Skip to content

Commit

Permalink
feat(dw-edit-managed-sources): Edit Self Managed Sources for DW (#28111)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
phixMe and github-actions[bot] authored Feb 7, 2025
1 parent d6d0d15 commit 3418674
Show file tree
Hide file tree
Showing 15 changed files with 468 additions and 288 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
131 changes: 81 additions & 50 deletions frontend/src/scenes/data-warehouse/new/DataWarehouseTableForm.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LemonInput, LemonSelect, Link } from '@posthog/lemon-ui'
import { LemonButton, LemonInput, LemonSelect, Link } from '@posthog/lemon-ui'
import { useValues } from 'kea'
import { Form } from 'kea-forms'
import { LemonField } from 'lib/lemon-ui/LemonField'
Expand Down Expand Up @@ -44,7 +44,11 @@ const ProviderMappings: Record<
},
}

export function DatawarehouseTableForm(): JSX.Element {
interface Props {
onUpdate?: () => void
}

export function DatawarehouseTableForm({ onUpdate }: Props): JSX.Element {
const { manualLinkingProvider } = useValues(sourceWizardLogic)

const provider = manualLinkingProvider ?? 'aws'
Expand All @@ -57,67 +61,87 @@ export function DatawarehouseTableForm(): JSX.Element {
enableFormOnSubmit
autoComplete="off"
>
<div className="flex flex-col gap-2 max-w-160">
<div className="flex flex-col gap-2">
<LemonField name="name" label="Table name">
<LemonInput
data-attr="table-name"
className="ph-ignore-input"
placeholder="Examples: stripe_invoice, hubspot_contacts, users"
autoComplete="off"
autoCapitalize="off"
autoCorrect="off"
spellCheck={false}
/>
{({ value = '', onChange }) => (
<LemonInput
data-attr="table-name"
className="ph-ignore-input"
placeholder="Examples: stripe_invoice, hubspot_contacts, users"
autoComplete="off"
autoCapitalize="off"
autoCorrect="off"
spellCheck={false}
value={value}
onChange={onChange}
/>
)}
</LemonField>
<div className="text-secondary text-xs mb-4">This will be the table name used when writing queries</div>
<LemonField name="url_pattern" label="Files URL pattern">
<LemonInput
data-attr="table-name"
className="ph-ignore-input"
placeholder={ProviderMappings[provider].fileUrlPatternPlaceholder}
autoComplete="off"
autoCapitalize="off"
autoCorrect="off"
spellCheck={false}
/>
{({ value = '', onChange }) => (
<LemonInput
data-attr="table-url-pattern"
className="ph-ignore-input"
placeholder={ProviderMappings[provider].fileUrlPatternPlaceholder}
autoComplete="off"
autoCapitalize="off"
autoCorrect="off"
spellCheck={false}
value={value}
onChange={onChange}
/>
)}
</LemonField>
<div className="text-secondary text-xs mb-4">
You can use <strong>*</strong> to select multiple files.
</div>
<LemonField name="format" label="File format" className="w-max mb-4">
<LemonSelect
data-attr="table-format"
options={[
{ label: 'Parquet (recommended)', value: 'Parquet' },
{ label: 'CSV', value: 'CSV' },
{ label: 'CSV with headers', value: 'CSVWithNames' },
{ label: 'JSON', value: 'JSONEachRow' },
{ label: 'Delta', value: 'Delta' },
]}
/>
{({ value = '', onChange }) => (
<LemonSelect
data-attr="table-format"
options={[
{ label: 'Parquet (recommended)', value: 'Parquet' },
{ label: 'CSV', value: 'CSV' },
{ label: 'CSV with headers', value: 'CSVWithNames' },
{ label: 'JSON', value: 'JSONEachRow' },
{ label: 'Delta', value: 'Delta' },
]}
value={value}
onChange={onChange}
/>
)}
</LemonField>
<LemonField name={['credential', 'access_key']} label={ProviderMappings[provider].accessKeyLabel}>
<LemonInput
data-attr="access-key"
className="ph-ignore-input"
placeholder={ProviderMappings[provider].accessKeyPlaceholder}
autoComplete="off"
autoCapitalize="off"
autoCorrect="off"
spellCheck={false}
/>
{({ value = '', onChange }) => (
<LemonInput
data-attr="access-key"
className="ph-ignore-input"
placeholder={ProviderMappings[provider].accessKeyPlaceholder}
autoComplete="off"
autoCapitalize="off"
autoCorrect="off"
spellCheck={false}
value={value}
onChange={onChange}
/>
)}
</LemonField>
<LemonField name={['credential', 'access_secret']} label={ProviderMappings[provider].accessSecretLabel}>
<LemonInput
data-attr="access-secret"
className="ph-ignore-input"
type="password"
placeholder="eg: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
autoComplete="off"
autoCapitalize="off"
autoCorrect="off"
spellCheck={false}
/>
{({ value = '', onChange }) => (
<LemonInput
data-attr="access-secret"
className="ph-ignore-input"
type="password"
placeholder="eg: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
autoComplete="off"
autoCapitalize="off"
autoCorrect="off"
spellCheck={false}
value={value}
onChange={onChange}
/>
)}
</LemonField>
{provider === 'google-cloud' && (
<div className="text-secondary text-xs">
Expand All @@ -128,6 +152,13 @@ export function DatawarehouseTableForm(): JSX.Element {
</div>
)}
</div>
{!!onUpdate && (
<div className="flex justify-end">
<LemonButton type="primary" onClick={onUpdate}>
Save
</LemonButton>
</div>
)}
</Form>
)
}
78 changes: 38 additions & 40 deletions frontend/src/scenes/data-warehouse/new/NewSourceWizard.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { LemonButton, LemonTable, Link } from '@posthog/lemon-ui'
import { useActions, useValues } from 'kea'
import { BindLogic, useActions, useValues } from 'kea'
import { PageHeader } from 'lib/components/PageHeader'
import { FEATURE_FLAGS } from 'lib/constants'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { useCallback, useEffect } from 'react'
import { DataWarehouseSourceIcon } from 'scenes/data-warehouse/settings/DataWarehouseSourceIcon'
import { SceneExport } from 'scenes/sceneTypes'

import { ManualLinkSourceType, SourceConfig } from '~/types'
Expand All @@ -13,7 +14,6 @@ import SchemaForm from '../external/forms/SchemaForm'
import SourceForm from '../external/forms/SourceForm'
import { SyncProgressStep } from '../external/forms/SyncProgressStep'
import { DatawarehouseTableForm } from '../new/DataWarehouseTableForm'
import { RenderDataWarehouseSourceIcon } from '../settings/DataWarehouseManagedSourcesTable'
import { dataWarehouseTableLogic } from './dataWarehouseTableLogic'
import { sourceWizardLogic } from './sourceWizardLogic'

Expand Down Expand Up @@ -160,33 +160,29 @@ function FirstStep(): JSX.Element {
{
title: 'Source',
width: 0,
render: function RenderAppInfo(_, sourceConfig) {
return <RenderDataWarehouseSourceIcon type={sourceConfig.name} />
render: function (_, sourceConfig) {
return <DataWarehouseSourceIcon type={sourceConfig.name} />
},
},
{
title: 'Name',
key: 'name',
render: function RenderName(_, sourceConfig) {
return (
<span className="font-semibold text-sm gap-1">
{sourceConfig.label ?? sourceConfig.name}
</span>
)
},
render: (_, sourceConfig) => (
<span className="font-semibold text-sm gap-1">
{sourceConfig.label ?? sourceConfig.name}
</span>
),
},
{
key: 'actions',
width: 0,
render: function RenderActions(_, sourceConfig) {
return (
<div className="flex flex-row justify-end">
<LemonButton onClick={() => onClick(sourceConfig)} className="my-2" type="primary">
Link
</LemonButton>
</div>
)
},
render: (_, sourceConfig) => (
<div className="flex flex-row justify-end">
<LemonButton onClick={() => onClick(sourceConfig)} className="my-2" type="primary">
Link
</LemonButton>
</div>
),
},
]}
/>
Expand All @@ -205,33 +201,29 @@ function FirstStep(): JSX.Element {
{
title: 'Source',
width: 0,
render: function RenderAppInfo(_, sourceConfig) {
return <RenderDataWarehouseSourceIcon type={sourceConfig.type} />
},
render: (_, sourceConfig) => <DataWarehouseSourceIcon type={sourceConfig.type} />,
},
{
title: 'Name',
key: 'name',
render: function RenderName(_, sourceConfig) {
return <span className="font-semibold text-sm gap-1">{sourceConfig.name}</span>
},
render: (_, sourceConfig) => (
<span className="font-semibold text-sm gap-1">{sourceConfig.name}</span>
),
},
{
key: 'actions',
width: 0,
render: function RenderActions(_, sourceConfig) {
return (
<div className="flex flex-row justify-end">
<LemonButton
onClick={() => onManualLinkClick(sourceConfig.type)}
className="my-2"
type="primary"
>
Link
</LemonButton>
</div>
)
},
render: (_, sourceConfig) => (
<div className="flex flex-row justify-end">
<LemonButton
onClick={() => onManualLinkClick(sourceConfig.type)}
className="my-2"
type="primary"
>
Link
</LemonButton>
</div>
),
},
]}
/>
Expand All @@ -242,7 +234,13 @@ function FirstStep(): JSX.Element {
function SecondStep(): JSX.Element {
const { selectedConnector } = useValues(sourceWizardLogic)

return selectedConnector ? <SourceForm sourceConfig={selectedConnector} /> : <DatawarehouseTableForm />
return selectedConnector ? (
<SourceForm sourceConfig={selectedConnector} />
) : (
<BindLogic logic={dataWarehouseTableLogic} props={{ id: 'new' }}>
<DatawarehouseTableForm />
</BindLogic>
)
}

function ThirdStep(): JSX.Element {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { lemonToast } from '@posthog/lemon-ui'
import { actions, connect, kea, listeners, path, props, reducers } from 'kea'
import { actions, connect, events, kea, listeners, path, props, reducers } from 'kea'
import { forms } from 'kea-forms'
import { loaders } from 'kea-loaders'
import { router } from 'kea-router'
Expand Down Expand Up @@ -71,6 +71,7 @@ export const dataWarehouseTableLogic = kea<dataWarehouseTableLogicType>([
updateTableSuccess: async ({ table }) => {
lemonToast.success(<>Table {table.name} updated</>)
actions.editingTable(false)
actions.loadDatabase()
router.actions.replace(urls.dataWarehouse())
},
})),
Expand All @@ -92,6 +93,13 @@ export const dataWarehouseTableLogic = kea<dataWarehouseTableLogicType>([
table: {
defaults: { ...NEW_WAREHOUSE_TABLE } as DataWarehouseTable,
errors: ({ name, url_pattern, credential, format }) => {
const HOGQL_TABLE_NAME_REGEX = /^[a-zA-Z_][a-zA-Z0-9_]*$/
if (!HOGQL_TABLE_NAME_REGEX.test(name)) {
return {
name: 'Invalid table name. Table names must start with a letter or underscore and contain only alphanumeric characters or underscores.',
}
}

if (url_pattern?.startsWith('s3://')) {
return {
url_pattern:
Expand Down Expand Up @@ -125,4 +133,9 @@ export const dataWarehouseTableLogic = kea<dataWarehouseTableLogicType>([
},
},
})),
events(({ actions }) => ({
propsChanged: () => {
actions.loadTable()
},
})),
])
Loading

0 comments on commit 3418674

Please sign in to comment.