Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(data-warehouse): cta update #17360

Merged
merged 11 commits into from
Sep 11, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export function DatabaseTablesContainer(): JSX.Element {
)
}}
/>
<ViewLinkModal />
<ViewLinkModal tableSelectable={false} />
</>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ export const databaseSceneLogic = kea<databaseSceneLogicType>([
.sort((a, b) => a.name.localeCompare(b.name))
},
],
tableOptions: [
(s) => [s.filteredTables],
(filteredTables: DatabaseSceneRow[]) =>
filteredTables.map((row) => ({
value: row,
label: row.name,
})),
],
}),
afterMount(({ actions }) => actions.loadDatabase()),
])
132 changes: 79 additions & 53 deletions frontend/src/scenes/data-warehouse/ViewLinkModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import { viewLinkLogic } from 'scenes/data-warehouse/viewLinkLogic'
import { Form, Field } from 'kea-forms'
import { useActions, useValues } from 'kea'
import { DatabaseSchemaQueryResponseField } from '~/queries/schema'
import { databaseSceneLogic } from 'scenes/data-management/database/databaseSceneLogic'

export function ViewLinkModal(): JSX.Element {
const { viewOptions, toJoinKeyOptions, selectedView, selectedTable, isFieldModalOpen, fromJoinKeyOptions } =
useValues(viewLinkLogic)
const { selectView, toggleFieldModal } = useActions(viewLinkLogic)
export function ViewLinkModal({ tableSelectable }: { tableSelectable: boolean }): JSX.Element {
const { isFieldModalOpen } = useValues(viewLinkLogic)
const { toggleFieldModal } = useActions(viewLinkLogic)

return (
<LemonModal
Expand All @@ -25,59 +25,85 @@ export function ViewLinkModal(): JSX.Element {
onClose={toggleFieldModal}
width={600}
>
<Form logic={viewLinkLogic} formKey="viewLink" enableFormOnSubmit>
<div className="flex flex-col w-full justify-between items-center">
<div className="flex flex-row w-full justify-between">
<div className="flex flex-col">
<span className="l4">Table</span>
{selectedTable ? selectedTable.name : ''}
</div>
<div className="w-50">
<span className="l4">View</span>
<Field name="saved_query_id">
<LemonSelect
fullWidth
options={viewOptions}
onSelect={selectView}
placeholder="Select a view"
/>
</Field>
</div>
<ViewLinkForm tableSelectable={tableSelectable} />
</LemonModal>
)
}

interface ViewLinkFormProps {
tableSelectable: boolean
}

export function ViewLinkForm({ tableSelectable }: ViewLinkFormProps): JSX.Element {
const { viewOptions, toJoinKeyOptions, selectedView, selectedTable, fromJoinKeyOptions } = useValues(viewLinkLogic)
const { selectView, toggleFieldModal, selectTable } = useActions(viewLinkLogic)
const { tableOptions } = useValues(databaseSceneLogic)

return (
<Form logic={viewLinkLogic} formKey="viewLink" enableFormOnSubmit>
<div className="flex flex-col w-full justify-between items-center">
<div className="flex flex-row w-full justify-between">
<div className="flex flex-col">
<span className="l4">Table</span>
{tableSelectable ? (
<LemonSelect
value={selectedTable}
fullWidth
options={tableOptions}
onSelect={selectTable}
placeholder="Select a table"
/>
) : selectedTable ? (
selectedTable.name
) : (
''
)}
</div>
<div className="mt-3 flex flex-row justify-between items-center w-full">
<div className="w-50">
<span className="l4">Table Key</span>
<Field name="from_join_key">
<LemonSelect fullWidth options={fromJoinKeyOptions} placeholder="Select a key" />
</Field>
</div>
<div className="mt-5">
<IconSwapHoriz />
</div>
<div className="w-50">
<span className="l4">View Key</span>
<Field name="to_join_key">
<LemonSelect
fullWidth
disabledReason={selectedView ? '' : 'Select a view to choose join key'}
options={toJoinKeyOptions}
placeholder="Select a key"
/>
</Field>
</div>
<div className="w-50">
<span className="l4">View</span>
<Field name="saved_query_id">
<LemonSelect
fullWidth
options={viewOptions}
onSelect={selectView}
placeholder="Select a view"
/>
</Field>
</div>
</div>
<LemonDivider className="mt-4 mb-4" />
<div className="flex flex-row justify-end w-full">
<LemonButton className="mr-3" type="secondary" onClick={toggleFieldModal}>
Close
</LemonButton>
<LemonButton type="primary" htmlType="submit">
Save
</LemonButton>
<div className="mt-3 flex flex-row justify-between items-center w-full">
<div className="w-50">
<span className="l4">Table Key</span>
<Field name="from_join_key">
<LemonSelect fullWidth options={fromJoinKeyOptions} placeholder="Select a key" />
</Field>
</div>
<div className="mt-5">
<IconSwapHoriz />
</div>
<div className="w-50">
<span className="l4">View Key</span>
<Field name="to_join_key">
<LemonSelect
fullWidth
disabledReason={selectedView ? '' : 'Select a view to choose join key'}
options={toJoinKeyOptions}
placeholder="Select a key"
/>
</Field>
</div>
</div>
</Form>
</LemonModal>
</div>
<LemonDivider className="mt-4 mb-4" />
<div className="flex flex-row justify-end w-full">
<LemonButton className="mr-3" type="secondary" onClick={toggleFieldModal}>
Close
</LemonButton>
<LemonButton type="primary" htmlType="submit">
Save
</LemonButton>
</div>
</Form>
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import { LemonTag } from '@posthog/lemon-ui'
import { LemonButton, LemonTag } from '@posthog/lemon-ui'
import { PageHeader } from 'lib/components/PageHeader'
import { SceneExport } from 'scenes/sceneTypes'
import { databaseSceneLogic } from 'scenes/data-management/database/databaseSceneLogic'
import { DataWarehousePageTabs, DataWarehouseTab } from '../DataWarehousePageTabs'
import { DatabaseTablesContainer } from 'scenes/data-management/database/DatabaseTables'
import { ViewLinkModal } from '../ViewLinkModal'
import { useActions, useValues } from 'kea'
import { viewLinkLogic } from '../viewLinkLogic'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { FEATURE_FLAGS } from 'lib/constants'

export const scene: SceneExport = {
component: DataWarehousePosthogScene,
logic: databaseSceneLogic,
}

export function DataWarehousePosthogScene(): JSX.Element {
const { toggleFieldModal } = useActions(viewLinkLogic)
const { featureFlags } = useValues(featureFlagLogic)
return (
<div>
<PageHeader
Expand All @@ -31,9 +38,17 @@ export function DataWarehousePosthogScene(): JSX.Element {
.
</div>
}
buttons={
featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE_VIEWS] ? (
<LemonButton type="primary" data-attr="new-data-warehouse-table" onClick={toggleFieldModal}>
Link table to view
</LemonButton>
) : undefined
}
/>
<DataWarehousePageTabs tab={DataWarehouseTab.Posthog} />
<DatabaseTablesContainer />
<ViewLinkModal tableSelectable={true} />
</div>
)
}
80 changes: 68 additions & 12 deletions frontend/src/scenes/data-warehouse/viewLinkLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { databaseSceneLogic } from 'scenes/data-management/database/databaseScen
import { loaders } from 'kea-loaders'
import { lemonToast } from 'lib/lemon-ui/lemonToast'
import type { viewLinkLogicType } from './viewLinkLogicType'
import { ViewLinkKeyLabel } from './ViewLinkModal'

const NEW_VIEW_LINK: DataWarehouseViewLink = {
id: 'new',
Expand All @@ -17,6 +18,11 @@ const NEW_VIEW_LINK: DataWarehouseViewLink = {
from_join_key: undefined,
}

export interface KeySelectOption {
value: string
label: JSX.Element
}

export const viewLinkLogic = kea<viewLinkLogicType>([
path(['scenes', 'data-warehouse', 'viewLinkLogic']),
connect({
Expand Down Expand Up @@ -63,11 +69,34 @@ export const viewLinkLogic = kea<viewLinkLogicType>([
forms(({ actions, values }) => ({
viewLink: {
defaults: NEW_VIEW_LINK,
errors: ({ saved_query_id, to_join_key, from_join_key }) => ({
saved_query_id: !saved_query_id ? 'Must select a view' : undefined,
to_join_key: !to_join_key ? 'Must select a join key' : undefined,
from_join_key: !from_join_key ? 'Must select a join key' : undefined,
}),
errors: ({ saved_query_id, to_join_key, from_join_key }) => {
let to_join_key_err: string | undefined = undefined
let from_join_key_err: string | undefined = undefined

if (!to_join_key) {
to_join_key_err = 'Must select a join key'
}

if (!from_join_key) {
from_join_key_err = 'Must select a join key'
}

if (
to_join_key &&
from_join_key &&
values.mappedToJoinKeyOptions[to_join_key]?.type !==
values.mappedFromJoinKeyOptions[from_join_key]?.type
) {
to_join_key_err = 'Join key types must match'
from_join_key_err = 'Join key types must match'
}

return {
saved_query_id: !saved_query_id ? 'Must select a view' : undefined,
to_join_key: to_join_key_err,
from_join_key: from_join_key_err,
}
},
submit: async ({ saved_query_id, to_join_key, from_join_key }) => {
if (values.selectedTable) {
await api.dataWarehouseViewLinks.create({
Expand All @@ -77,7 +106,8 @@ export const viewLinkLogic = kea<viewLinkLogicType>([
from_join_key,
})
actions.toggleFieldModal()
actions.loadDatabase()
// actions.loadDatabase()
// actions.loadViewLinks()
}
},
},
Expand Down Expand Up @@ -120,26 +150,52 @@ export const viewLinkLogic = kea<viewLinkLogicType>([
],
toJoinKeyOptions: [
(s) => [s.selectedView],
(selectedView: DataWarehouseSceneRow | null) => {
(selectedView: DataWarehouseSceneRow | null): KeySelectOption[] => {
if (!selectedView) {
return []
}
return selectedView.columns.map((column) => ({
value: column.key,
label: column.key,
label: <ViewLinkKeyLabel column={column} />,
}))
},
],
mappedToJoinKeyOptions: [
(s) => [s.selectedView],
(selectedView: DataWarehouseSceneRow | null) => {
if (!selectedView) {
return []
}
return selectedView.columns.reduce((acc, column) => {
acc[column.key] = column
return acc
}, {})
},
],
fromJoinKeyOptions: [
(s) => [s.selectedTable],
(selectedTable: DataWarehouseSceneRow | null): KeySelectOption[] => {
if (!selectedTable) {
return []
}
return selectedTable.columns
.filter((column) => column.type !== 'view')
.map((column) => ({
value: column.key,
label: <ViewLinkKeyLabel column={column} />,
}))
},
],
mappedFromJoinKeyOptions: [
(s) => [s.selectedTable],
(selectedTable: DataWarehouseSceneRow | null) => {
if (!selectedTable) {
return []
}
return selectedTable.columns.map((column) => ({
value: column.key,
label: column.key,
}))
return selectedTable.columns.reduce((acc, column) => {
acc[column.key] = column
return acc
}, {})
},
],
}),
Expand Down