chore(data-warehouse): Use the same pipeline sources UI in warehouse source creation wizard (#38300)

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Tom Owers
2025-09-26 11:15:34 -07:00
committed by GitHub
parent c34f617148
commit d1072a9604
6 changed files with 32 additions and 176 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

@@ -1,23 +1,18 @@
import { BindLogic, useActions, useValues } from 'kea'
import posthog from 'posthog-js'
import { useCallback, useEffect } from 'react'
import { IconBell, IconCheck } from '@posthog/icons'
import { LemonButton, LemonDivider, LemonSkeleton, LemonTable, LemonTag, lemonToast } from '@posthog/lemon-ui'
import { LemonButton, LemonDivider, LemonSkeleton } from '@posthog/lemon-ui'
import { FEATURE_FLAGS } from 'lib/constants'
import { LemonMarkdown } from 'lib/lemon-ui/LemonMarkdown'
import { IconBlank } from 'lib/lemon-ui/icons'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { nonHogFunctionTemplatesLogic } from 'scenes/data-pipelines/utils/nonHogFunctionTemplatesLogic'
import { DataWarehouseSourceIcon } from 'scenes/data-warehouse/settings/DataWarehouseSourceIcon'
import { HogFunctionTemplateList } from 'scenes/hog-functions/list/HogFunctionTemplateList'
import { SceneExport } from 'scenes/sceneTypes'
import { SceneContent } from '~/layout/scenes/components/SceneContent'
import { SceneDivider } from '~/layout/scenes/components/SceneDivider'
import { SceneSection } from '~/layout/scenes/components/SceneSection'
import { SceneTitleSection } from '~/layout/scenes/components/SceneTitleSection'
import { ExternalDataSourceType, SourceConfig } from '~/queries/schema/schema-general'
import { ManualLinkSourceType, SurveyEventName, SurveyEventProperties } from '~/types'
import { DataWarehouseInitialBillingLimitNotice } from '../DataWarehouseInitialBillingLimitNotice'
import SchemaForm from '../external/forms/SchemaForm'
@@ -75,7 +70,6 @@ function InternalNewSourceWizardScene(): JSX.Element {
interface NewSourcesWizardProps {
onComplete?: () => void
disableConnectedSources?: boolean
allowedSources?: ExternalDataSourceType[] // Filter to only show these source types
initialSource?: ExternalDataSourceType // Pre-select this source and start on step 2
}
@@ -168,10 +162,7 @@ function InternalSourcesWizard(props: NewSourcesWizardProps): JSX.Element {
)}
{currentStep === 1 ? (
<FirstStep
disableConnectedSources={props.disableConnectedSources}
allowedSources={props.allowedSources}
/>
<FirstStep allowedSources={props.allowedSources} />
) : currentStep === 2 ? (
<SecondStep />
) : currentStep === 3 ? (
@@ -188,174 +179,38 @@ function InternalSourcesWizard(props: NewSourcesWizardProps): JSX.Element {
)
}
function FirstStep({ disableConnectedSources, allowedSources }: NewSourcesWizardProps): JSX.Element {
const { connectors, manualConnectors } = useValues(sourceWizardLogic)
const { selectConnector, toggleManualLinkFormVisible, onNext, setManualLinkingProvider } =
useActions(sourceWizardLogic)
const { featureFlags } = useValues(featureFlagLogic)
function FirstStep({ allowedSources }: NewSourcesWizardProps): JSX.Element {
const { availableSourcesLoading } = useValues(availableSourcesDataLogic)
const { connectors } = useValues(sourceWizardLogic)
const onClick = (sourceConfig: SourceConfig): void => {
selectConnector(sourceConfig)
onNext()
}
const onManualLinkClick = (manualLinkSource: ManualLinkSourceType): void => {
toggleManualLinkFormVisible(true)
setManualLinkingProvider(manualLinkSource)
}
const filteredConnectors = connectors
.filter((n) => {
if (n.name === 'MetaAds') {
return featureFlags[FEATURE_FLAGS.META_ADS_DWH]
// Filter out sources for onboarding flow
const sources = connectors.reduce(
(acc, cur) => {
if (allowedSources) {
if (allowedSources.indexOf(cur.name) !== -1) {
acc[cur.name] = cur
}
} else {
acc[cur.name] = cur
}
// Filter by allowed sources if specified
if (allowedSources && allowedSources.length > 0) {
return allowedSources.includes(n.name)
}
return acc
},
{} as Record<string, SourceConfig>
)
return true
const { hogFunctionTemplatesDataWarehouseSources } = useValues(
nonHogFunctionTemplatesLogic({
availableSources: sources ?? {},
})
.sort((a, b) => Number(a.unreleasedSource) - Number(b.unreleasedSource))
)
return (
<SceneSection
title="Managed data warehouse sources"
description="Data will be synced to PostHog and regularly refreshed."
>
<LemonTable
dataSource={filteredConnectors}
loading={false}
disableTableWhileLoading={false}
columns={[
{
title: 'Source',
width: 0,
render: function (_, sourceConfig) {
return sourceConfig.name ? (
<DataWarehouseSourceIcon type={sourceConfig.name} />
) : (
<IconBlank />
)
},
},
{
title: 'Name',
key: 'name',
render: (_, sourceConfig) => (
<div className="flex flex-col">
<span className="gap-1 text-sm font-semibold">
{sourceConfig.label ?? sourceConfig.name}
{sourceConfig.betaSource && (
<span>
{' '}
<LemonTag type="warning">BETA</LemonTag>
</span>
)}
</span>
{sourceConfig.unreleasedSource && (
<span>Get notified when {sourceConfig.label} is available to connect</span>
)}
</div>
),
},
{
key: 'actions',
render: (_, sourceConfig) => {
const isConnected = disableConnectedSources && sourceConfig.existingSource
return (
<div className="flex flex-row justify-end p-1">
{isConnected && (
<LemonTag type="success" className="my-4" size="medium">
<IconCheck />
Connected
</LemonTag>
)}
{!isConnected && sourceConfig.unreleasedSource === true && (
<LemonButton
className="my-2"
type="primary"
icon={<IconBell />}
onClick={() => {
// https://us.posthog.com/project/2/surveys/0190ff15-5032-0000-722a-e13933c140ac
posthog.capture(SurveyEventName.SENT, {
[SurveyEventProperties.SURVEY_ID]:
'0190ff15-5032-0000-722a-e13933c140ac',
[`${SurveyEventProperties.SURVEY_RESPONSE}_ad030277-3642-4abf-b6b0-7ecb449f07e8`]:
sourceConfig.label ?? sourceConfig.name,
})
posthog.capture('source_notify_me', {
source: sourceConfig.label ?? sourceConfig.name,
})
lemonToast.success('Notification registered successfully')
}}
>
Notify me
</LemonButton>
)}
{!isConnected && !sourceConfig.unreleasedSource && (
<LemonButton
onClick={() => onClick(sourceConfig)}
className="my-2"
type="primary"
disabledReason={
disableConnectedSources && sourceConfig.existingSource
? 'You have already connected this source'
: undefined
}
>
Link
</LemonButton>
)}
</div>
)
},
},
]}
/>
<SceneSection
title="Self-managed data warehouse sources"
description="Data will be queried directly from your data source that you manage."
>
<LemonTable
dataSource={manualConnectors}
loading={false}
disableTableWhileLoading={false}
columns={[
{
title: 'Source',
width: 0,
render: (_, sourceConfig) => <DataWarehouseSourceIcon type={sourceConfig.type} />,
},
{
title: 'Name',
key: 'name',
render: (_, sourceConfig) => (
<span className="gap-1 text-sm font-semibold">{sourceConfig.name}</span>
),
},
{
key: 'actions',
width: 0,
render: (_, sourceConfig) => (
<div className="flex flex-row justify-end p-1">
<LemonButton
onClick={() => onManualLinkClick(sourceConfig.type)}
className="my-2"
type="primary"
>
Link
</LemonButton>
</div>
),
},
]}
/>
</SceneSection>
</SceneSection>
<HogFunctionTemplateList
type="source_webhook"
manualTemplates={hogFunctionTemplatesDataWarehouseSources}
manualTemplatesLoading={availableSourcesLoading}
/>
)
}

View File

@@ -37,7 +37,7 @@ export function OnboardingDataWarehouseSourcesStep({
<LemonSkeleton />
) : (
<BindLogic logic={sourceWizardLogic} props={{ availableSources }}>
<NewSourcesWizard disableConnectedSources onComplete={() => goToNextStep()} />
<NewSourcesWizard onComplete={() => goToNextStep()} />
</BindLogic>
)}
</OnboardingStep>

View File

@@ -39,6 +39,7 @@ cargo test -- --ignored
You can verify MinIO is running by visiting: http://localhost:19001 (MinIO Console)
Login credentials:
- Username: `object_storage_root_user`
- Password: `object_storage_root_password`
@@ -48,4 +49,4 @@ Unit tests don't require MinIO and test the mock implementation:
```bash
cargo test --lib
```
```