diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page--dark.png index cbaafb7f34565..b97e0df63a7b8 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page--dark.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page--light.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page--light.png index 011c702ddcb41..750fd6e4e7bba 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page--light.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page--light.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page-iff-legacy-sources--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page-iff-legacy-sources--dark.png index 9ab2e60fe4566..80670feb8d8ce 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page-iff-legacy-sources--dark.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page-iff-legacy-sources--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page-iff-legacy-sources--light.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page-iff-legacy-sources--light.png index c3adfbba0722f..11bb9e86988fc 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page-iff-legacy-sources--light.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page-iff-legacy-sources--light.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-legacy-sources-page--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-legacy-sources-page--dark.png index cc2d0c1caf71a..7e11dc420c9e8 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-legacy-sources-page--dark.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-legacy-sources-page--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-legacy-sources-page--light.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-legacy-sources-page--light.png index 9b47b2d3f7674..10483f33eda80 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-legacy-sources-page--light.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-legacy-sources-page--light.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-overview-page--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-overview-page--dark.png index cbaafb7f34565..b97e0df63a7b8 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-overview-page--dark.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-overview-page--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-overview-page--light.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-overview-page--light.png index 011c702ddcb41..750fd6e4e7bba 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-overview-page--light.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-overview-page--light.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-site-apps-page--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-site-apps-page--dark.png index b60ebbf533446..f544bc2231949 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-site-apps-page--dark.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-site-apps-page--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-site-apps-page--light.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-site-apps-page--light.png index 42acc0d8a353e..f50b0e5089f6d 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-site-apps-page--light.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-site-apps-page--light.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page--dark.png index ecda5f6e39277..1d0c558ef4eae 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page--dark.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page--light.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page--light.png index 7ae95c48ae976..930bcb1a6fba1 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page--light.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page--light.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page-empty--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page-empty--dark.png index aea37bfbe3c7c..89f24f08f4faa 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page-empty--dark.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page-empty--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page-empty--light.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page-empty--light.png index 77a9e7e78c060..a7c13f9812edf 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page-empty--light.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page-empty--light.png differ diff --git a/frontend/__snapshots__/scenes-other-products--products--dark.png b/frontend/__snapshots__/scenes-other-products--products--dark.png index 0945526ed477d..18a32d7415f75 100644 Binary files a/frontend/__snapshots__/scenes-other-products--products--dark.png and b/frontend/__snapshots__/scenes-other-products--products--dark.png differ diff --git a/frontend/__snapshots__/scenes-other-products--products--light.png b/frontend/__snapshots__/scenes-other-products--products--light.png index b00e6e0840322..d044edeca1790 100644 Binary files a/frontend/__snapshots__/scenes-other-products--products--light.png and b/frontend/__snapshots__/scenes-other-products--products--light.png differ diff --git a/frontend/src/layout/navigation-3000/navigationLogic.tsx b/frontend/src/layout/navigation-3000/navigationLogic.tsx index 16f91c3ecfd4c..b31e8fb7f8794 100644 --- a/frontend/src/layout/navigation-3000/navigationLogic.tsx +++ b/frontend/src/layout/navigation-3000/navigationLogic.tsx @@ -486,6 +486,12 @@ export const navigation3000Logic = kea([ icon: , to: urls.surveys(), }, + { + identifier: Scene.DataWarehouse, + label: 'Data warehouse', + icon: , + to: isUsingSidebar ? undefined : urls.dataWarehouse(), + }, featureFlags[FEATURE_FLAGS.PRODUCT_INTRO_PAGES] !== 'test' || hasOnboardedFeatureFlags ? { identifier: Scene.EarlyAccessFeatures, @@ -494,16 +500,6 @@ export const navigation3000Logic = kea([ to: urls.earlyAccessFeatures(), } : null, - hasOnboardedAnyProduct - ? { - identifier: Scene.DataWarehouse, - label: 'Data warehouse', - icon: , - to: urls.dataWarehouse(), - featureFlag: FEATURE_FLAGS.DATA_WAREHOUSE, - tag: 'beta' as const, - } - : null, hasOnboardedAnyProduct ? featureFlags[FEATURE_FLAGS.PIPELINE_UI] ? { diff --git a/frontend/src/lib/components/CommandPalette/commandPaletteLogic.tsx b/frontend/src/lib/components/CommandPalette/commandPaletteLogic.tsx index 47b957a0787ce..ab0b11aecdbcd 100644 --- a/frontend/src/lib/components/CommandPalette/commandPaletteLogic.tsx +++ b/frontend/src/lib/components/CommandPalette/commandPaletteLogic.tsx @@ -567,17 +567,13 @@ export const commandPaletteLogic = kea([ push(urls.webAnalytics()) }, }, - ...(values.featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE] - ? [ - { - icon: IconServer, - display: 'Go to Data warehouse', - executor: () => { - push(urls.dataWarehouse()) - }, - }, - ] - : []), + { + icon: IconServer, + display: 'Go to Data warehouse', + executor: () => { + push(urls.dataWarehouse()) + }, + }, ...(values.featureFlags[FEATURE_FLAGS.ERROR_TRACKING] ? [ { diff --git a/frontend/src/lib/constants.tsx b/frontend/src/lib/constants.tsx index 0eed8c93e3a6c..4a03e5398a119 100644 --- a/frontend/src/lib/constants.tsx +++ b/frontend/src/lib/constants.tsx @@ -157,7 +157,6 @@ export const FEATURE_FLAGS = { // owner: #team-replay, only to be enabled for PostHog team testing EXCEPTION_AUTOCAPTURE: 'exception-autocapture', WEB_VITALS_AUTOCAPTURE: 'web-vitals-autocapture', // owner: @team-replay - DATA_WAREHOUSE: 'data-warehouse', // owner: @EDsCODE FF_DASHBOARD_TEMPLATES: 'ff-dashboard-templates', // owner: @EDsCODE ARTIFICIAL_HOG: 'artificial-hog', // owner: @Twixes CS_DASHBOARDS: 'cs-dashboards', // owner: @pauldambra diff --git a/frontend/src/mocks/handlers.ts b/frontend/src/mocks/handlers.ts index f1c8f9bfc93f5..4e33ba264729a 100644 --- a/frontend/src/mocks/handlers.ts +++ b/frontend/src/mocks/handlers.ts @@ -50,6 +50,7 @@ export const defaultMocks: Mocks = { '/api/projects/:team_id/dashboards/': EMPTY_PAGINATED_RESPONSE, '/api/projects/:team_id/dashboard_templates': EMPTY_PAGINATED_RESPONSE, '/api/projects/:team_id/dashboard_templates/repository/': [], + '/api/projects/:team_id/external_data_sources/': EMPTY_PAGINATED_RESPONSE, '/api/projects/:team_id/notebooks': () => { // this was matching on `?contains=query` but that made MSW unhappy and seems unnecessary return [ diff --git a/frontend/src/queries/nodes/HogQLQuery/HogQLQueryEditor.tsx b/frontend/src/queries/nodes/HogQLQuery/HogQLQueryEditor.tsx index ad7174d52325a..774db705ccdf5 100644 --- a/frontend/src/queries/nodes/HogQLQuery/HogQLQueryEditor.tsx +++ b/frontend/src/queries/nodes/HogQLQuery/HogQLQueryEditor.tsx @@ -83,12 +83,10 @@ export function HogQLQueryEditor(props: HogQLQueryEditorProps): JSX.Element { return (
- - {/* eslint-disable-next-line react/forbid-dom-props */} -
- -
-
+ {/* eslint-disable-next-line react/forbid-dom-props */} +
+ +
- {featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE] ? ( - - Save as view - - ) : null} - {featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE] && ( - } - type="secondary" - size="small" - dropdown={{ - overlay: ( -
- Save a query as a view that can be referenced in another query. This is - useful for modeling data and organizing large queries into readable - chunks.{' '} - More Info{' '} -
- ), - placement: 'right-start', - fallbackPlacements: ['left-start'], - actionable: true, - closeParentPopoverOnClickInside: true, - }} - /> - )} + + Save as view + + } + type="secondary" + size="small" + dropdown={{ + overlay: ( +
+ Save a query as a view that can be referenced in another query. This is + useful for modeling data and organizing large queries into readable chunks.{' '} + More Info{' '} +
+ ), + placement: 'right-start', + fallbackPlacements: ['left-start'], + actionable: true, + closeParentPopoverOnClickInside: true, + }} + /> )}
diff --git a/frontend/src/queries/nodes/InsightViz/GlobalAndOrFilters.tsx b/frontend/src/queries/nodes/InsightViz/GlobalAndOrFilters.tsx index 05a26792fd6b3..60b63667bce3c 100644 --- a/frontend/src/queries/nodes/InsightViz/GlobalAndOrFilters.tsx +++ b/frontend/src/queries/nodes/InsightViz/GlobalAndOrFilters.tsx @@ -1,7 +1,5 @@ import { useActions, useValues } from 'kea' import { TaxonomicFilterGroupType } from 'lib/components/TaxonomicFilter/types' -import { FEATURE_FLAGS } from 'lib/constants' -import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { insightVizDataLogic } from 'scenes/insights/insightVizDataLogic' import { keyForInsightLogicProps } from 'scenes/insights/sharedUtils' @@ -18,7 +16,6 @@ export function GlobalAndOrFilters({ insightProps }: EditorFilterProps): JSX.Ele const { groupsTaxonomicTypes } = useValues(groupsModel) const { isTrends, querySource, isDataWarehouseSeries } = useValues(insightVizDataLogic(insightProps)) const { updateQuerySource } = useActions(insightVizDataLogic(insightProps)) - const { featureFlags } = useValues(featureFlagLogic) const taxonomicGroupTypes = [ TaxonomicFilterGroupType.EventProperties, @@ -29,7 +26,7 @@ export function GlobalAndOrFilters({ insightProps }: EditorFilterProps): JSX.Ele TaxonomicFilterGroupType.Elements, ...(isTrends ? [TaxonomicFilterGroupType.SessionProperties] : []), TaxonomicFilterGroupType.HogQLExpression, - ...(featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE] ? [TaxonomicFilterGroupType.DataWarehousePersonProperties] : []), + TaxonomicFilterGroupType.DataWarehousePersonProperties, ] return ( diff --git a/frontend/src/queries/nodes/InsightViz/TrendsSeries.tsx b/frontend/src/queries/nodes/InsightViz/TrendsSeries.tsx index 85a348e21ccbc..2b152c1745d13 100644 --- a/frontend/src/queries/nodes/InsightViz/TrendsSeries.tsx +++ b/frontend/src/queries/nodes/InsightViz/TrendsSeries.tsx @@ -1,7 +1,6 @@ import { useActions, useValues } from 'kea' import { TaxonomicFilterGroupType } from 'lib/components/TaxonomicFilter/types' -import { FEATURE_FLAGS, SINGLE_SERIES_DISPLAY_TYPES } from 'lib/constants' -import { featureFlagLogic } from 'lib/logic/featureFlagLogic' +import { SINGLE_SERIES_DISPLAY_TYPES } from 'lib/constants' import { alphabet } from 'lib/utils' import { ActionFilter } from 'scenes/insights/filters/ActionFilter/ActionFilter' import { MathAvailability } from 'scenes/insights/filters/ActionFilter/ActionFilterRow/ActionFilterRow' @@ -24,7 +23,6 @@ export function TrendsSeries(): JSX.Element | null { insightVizDataLogic(insightProps) ) const { updateQuerySource } = useActions(insightVizDataLogic(insightProps)) - const { featureFlags } = useValues(featureFlagLogic) const { showGroupsOptions, groupsTaxonomicTypes } = useValues(groupsModel) @@ -38,7 +36,7 @@ export function TrendsSeries(): JSX.Element | null { ...(isTrends ? [TaxonomicFilterGroupType.SessionProperties] : []), TaxonomicFilterGroupType.HogQLExpression, TaxonomicFilterGroupType.DataWarehouseProperties, - ...(featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE] ? [TaxonomicFilterGroupType.DataWarehousePersonProperties] : []), + TaxonomicFilterGroupType.DataWarehousePersonProperties, ] if (!isInsightQueryNode(querySource)) { @@ -87,15 +85,11 @@ export function TrendsSeries(): JSX.Element | null { } mathAvailability={mathAvailability} propertiesTaxonomicGroupTypes={propertiesTaxonomicGroupTypes} - actionsTaxonomicGroupTypes={ - featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE] - ? [ - TaxonomicFilterGroupType.Events, - TaxonomicFilterGroupType.Actions, - TaxonomicFilterGroupType.DataWarehouse, - ] - : [TaxonomicFilterGroupType.Events, TaxonomicFilterGroupType.Actions] - } + actionsTaxonomicGroupTypes={[ + TaxonomicFilterGroupType.Events, + TaxonomicFilterGroupType.Actions, + TaxonomicFilterGroupType.DataWarehouse, + ]} /> ) diff --git a/frontend/src/scenes/data-management/DataManagementScene.stories.tsx b/frontend/src/scenes/data-management/DataManagementScene.stories.tsx index e99bde91c529a..248ca1a85bf2b 100644 --- a/frontend/src/scenes/data-management/DataManagementScene.stories.tsx +++ b/frontend/src/scenes/data-management/DataManagementScene.stories.tsx @@ -249,7 +249,6 @@ const meta: Meta = { } export default meta export function Database(): JSX.Element { - setFeatureFlags([FEATURE_FLAGS.DATA_WAREHOUSE]) useEffect(() => { router.actions.push(urls.database()) }, []) diff --git a/frontend/src/scenes/data-management/database/DatabaseTables.tsx b/frontend/src/scenes/data-management/database/DatabaseTables.tsx index 99c712b6ff3ad..da69f2ff923b0 100644 --- a/frontend/src/scenes/data-management/database/DatabaseTables.tsx +++ b/frontend/src/scenes/data-management/database/DatabaseTables.tsx @@ -1,22 +1,20 @@ import { LemonButton, LemonDropdown, Link } from '@posthog/lemon-ui' import { useActions, useValues } from 'kea' -import { FEATURE_FLAGS } from 'lib/constants' import { LemonTable, LemonTableColumns } from 'lib/lemon-ui/LemonTable' import { LemonTag } from 'lib/lemon-ui/LemonTag/LemonTag' -import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { humanFriendlyDetailedTime } from 'lib/utils' import { databaseTableListLogic } from 'scenes/data-management/database/databaseTableListLogic' +import { defaultQuery } from 'scenes/data-warehouse/utils' import { viewLinkLogic } from 'scenes/data-warehouse/viewLinkLogic' import { urls } from 'scenes/urls' -import { DatabaseSchemaTable, DataTableNode, NodeKind } from '~/queries/schema' +import { DatabaseSchemaTable } from '~/queries/schema' import { DatabaseTable } from './DatabaseTable' export function DatabaseTablesContainer(): JSX.Element { const { filteredTables, databaseLoading } = useValues(databaseTableListLogic) const { toggleJoinTableModal, selectSourceTable } = useActions(viewLinkLogic) - const { featureFlags } = useValues(featureFlagLogic) return ( <> @@ -29,20 +27,18 @@ export function DatabaseTablesContainer(): JSX.Element {
Columns - {featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE] && ( -
- { - selectSourceTable(row.name) - toggleJoinTableModal() - }} - > - Add link to view - -
- )} +
+ { + selectSourceTable(row.name) + toggleJoinTableModal() + }} + > + Add link to view + +
) @@ -81,22 +77,7 @@ export function DatabaseTables({ key: 'name', dataIndex: 'name', render: function RenderTable(table, obj: T) { - const query: DataTableNode = { - kind: NodeKind.DataTableNode, - full: true, - source: { - kind: NodeKind.HogQLQuery, - // TODO: Use `hogql` tag? - query: `SELECT ${Object.values(obj.fields) - .filter( - ({ table, fields, chain, schema_valid }) => - !table && !fields && !chain && schema_valid - ) - .map(({ name }) => name)} FROM ${ - table === 'numbers' ? 'numbers(0, 10)' : table - } LIMIT 100`, - }, - } + const query = defaultQuery(table as string, Object.values(obj.fields)) return (
diff --git a/frontend/src/scenes/data-warehouse/DataWarehouseBetaNotice.tsx b/frontend/src/scenes/data-warehouse/DataWarehouseBetaNotice.tsx deleted file mode 100644 index fb38bd83e08ff..0000000000000 --- a/frontend/src/scenes/data-warehouse/DataWarehouseBetaNotice.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { IconBug } from '@posthog/icons' -import { LemonButton } from '@posthog/lemon-ui' -import { useActions, useValues } from 'kea' -import { supportLogic } from 'lib/components/Support/supportLogic' -import { IconFeedback } from 'lib/lemon-ui/icons' -import { LemonBanner } from 'lib/lemon-ui/LemonBanner' -import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic' - -export const DataWarehouseBetaNotice = (): JSX.Element => { - const { openSupportForm } = useActions(supportLogic) - const { preflight } = useValues(preflightLogic) - - const showSupportOptions = preflight?.cloud - - return ( - -
-
- PostHog Data Warehouse is in Beta. Thanks for taking part! We'd love to hear what you think. -
- {showSupportOptions ? ( - - } - onClick={() => openSupportForm({ kind: 'bug' })} - > - Report a bug - - } - onClick={() => openSupportForm({ kind: 'feedback' })} - > - Give feedback - - - ) : null} -
-
- ) -} diff --git a/frontend/src/scenes/data-warehouse/external/DataWarehouseExternalScene.tsx b/frontend/src/scenes/data-warehouse/external/DataWarehouseExternalScene.tsx index 8f2c11076329d..6ea7faf48dfea 100644 --- a/frontend/src/scenes/data-warehouse/external/DataWarehouseExternalScene.tsx +++ b/frontend/src/scenes/data-warehouse/external/DataWarehouseExternalScene.tsx @@ -10,7 +10,6 @@ import { insightSceneLogic } from 'scenes/insights/insightSceneLogic' import { SceneExport } from 'scenes/sceneTypes' import { urls } from 'scenes/urls' -import { DataWarehouseBetaNotice } from '../DataWarehouseBetaNotice' import { DataWarehouseInitialBillingLimitNotice } from '../DataWarehouseInitialBillingLimitNotice' import { dataWarehouseSceneLogic } from './dataWarehouseSceneLogic' import { DataWarehouseTables } from './DataWarehouseTables' @@ -73,7 +72,6 @@ export function DataWarehouseExternalScene(): JSX.Element {
} /> - diff --git a/frontend/src/scenes/data-warehouse/external/DataWarehouseTables.tsx b/frontend/src/scenes/data-warehouse/external/DataWarehouseTables.tsx index f5b61e31951e4..277927c0434e2 100644 --- a/frontend/src/scenes/data-warehouse/external/DataWarehouseTables.tsx +++ b/frontend/src/scenes/data-warehouse/external/DataWarehouseTables.tsx @@ -4,8 +4,6 @@ import { clsx } from 'clsx' import { BindLogic, useActions, useValues } from 'kea' import { router } from 'kea-router' import { DatabaseTableTree, TreeItem } from 'lib/components/DatabaseTableTree/DatabaseTableTree' -import { FEATURE_FLAGS } from 'lib/constants' -import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { useState } from 'react' import { insightDataLogic } from 'scenes/insights/insightDataLogic' import { insightLogic } from 'scenes/insights/insightLogic' @@ -65,7 +63,6 @@ export const DatabaseTableTreeWithItems = ({ inline }: DatabaseTableTreeProps): useValues(dataWarehouseSceneLogic) const { selectRow, deleteDataWarehouseSavedQuery, deleteDataWarehouseTable, toggleSchemaModal } = useActions(dataWarehouseSceneLogic) - const { featureFlags } = useValues(featureFlagLogic) const [collapsed, setCollapsed] = useState(false) const { toggleJoinTableModal, selectSourceTable } = useActions(viewLinkLogic) const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false) @@ -159,10 +156,7 @@ export const DatabaseTableTreeWithItems = ({ inline }: DatabaseTableTreeProps): })), isLoading: databaseLoading, }, - ] - - if (featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE]) { - items.push({ + { name: 'Views', items: views.map((table) => ({ name: table.name, @@ -176,8 +170,8 @@ export const DatabaseTableTreeWithItems = ({ inline }: DatabaseTableTreeProps): })), emptyLabel: No views found, isLoading: databaseLoading, - }) - } + }, + ] return items } @@ -203,10 +197,7 @@ export const DatabaseTableTreeWithItems = ({ inline }: DatabaseTableTreeProps): })), isLoading: databaseLoading, }, - ] - - if (featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE]) { - items.push({ + { name: 'Views', items: views.map((table) => ({ table: table, @@ -214,8 +205,8 @@ export const DatabaseTableTreeWithItems = ({ inline }: DatabaseTableTreeProps): })), emptyLabel: No views found, isLoading: databaseLoading, - }) - } + }, + ] return items } diff --git a/frontend/src/scenes/data-warehouse/external/forms/SyncProgressStep.tsx b/frontend/src/scenes/data-warehouse/external/forms/SyncProgressStep.tsx index c0612fa20a20b..e38cad0634274 100644 --- a/frontend/src/scenes/data-warehouse/external/forms/SyncProgressStep.tsx +++ b/frontend/src/scenes/data-warehouse/external/forms/SyncProgressStep.tsx @@ -1,14 +1,14 @@ -import { LemonButton, LemonTable, LemonTag, LemonTagType } from '@posthog/lemon-ui' +import { LemonButton, LemonTable, LemonTableColumns, LemonTag, LemonTagType } from '@posthog/lemon-ui' import { useActions, useValues } from 'kea' import { sourceWizardLogic } from 'scenes/data-warehouse/new/sourceWizardLogic' import { dataWarehouseSettingsLogic } from 'scenes/data-warehouse/settings/dataWarehouseSettingsLogic' +import { defaultQuery } from 'scenes/data-warehouse/utils' import { urls } from 'scenes/urls' -import { DataTableNode, NodeKind } from '~/queries/schema' import { ExternalDataSourceSchema } from '~/types' export const SyncProgressStep = (): JSX.Element => { - const { sourceId } = useValues(sourceWizardLogic) + const { sourceId, isWrapped } = useValues(sourceWizardLogic) const { cancelWizard } = useActions(sourceWizardLogic) const { dataWarehouseSources, dataWarehouseSourcesLoading } = useValues(dataWarehouseSettingsLogic) @@ -43,6 +43,49 @@ export const SyncProgressStep = (): JSX.Element => { } } + const columns: LemonTableColumns = [ + { + title: 'Table', + key: 'table', + render: function RenderTable(_, schema) { + return schema.name + }, + }, + { + title: 'Status', + key: 'status', + render: function RenderStatus(_, schema) { + const { status, tagType } = getSyncStatus(schema) + + return {status} + }, + }, + ] + + if (!isWrapped) { + columns.push({ + key: 'actions', + width: 0, + render: function RenderStatus(_, schema) { + if (schema.table && schema.status === 'Completed') { + const query = defaultQuery(schema.table.name, schema.table.columns) + return ( + cancelWizard()} + to={urls.insightNew(undefined, undefined, JSON.stringify(query))} + > + Query + + ) + } + + return '' + }, + }) + } + return (
@@ -51,59 +94,7 @@ export const SyncProgressStep = (): JSX.Element => { dataSource={schemas} loading={dataWarehouseSourcesLoading} disableTableWhileLoading={false} - columns={[ - { - title: 'Table', - key: 'table', - render: function RenderTable(_, schema) { - return schema.name - }, - }, - { - title: 'Status', - key: 'status', - render: function RenderStatus(_, schema) { - const { status, tagType } = getSyncStatus(schema) - - return {status} - }, - }, - { - key: 'actions', - width: 0, - render: function RenderStatus(_, schema) { - if (schema.table && schema.status === 'Completed') { - const query: DataTableNode = { - kind: NodeKind.DataTableNode, - full: true, - source: { - kind: NodeKind.HogQLQuery, - query: `SELECT ${schema.table.columns - .filter( - ({ table, fields, chain, schema_valid }) => - !table && !fields && !chain && schema_valid - ) - .map(({ name }) => name)} FROM ${ - schema.table.name === 'numbers' ? 'numbers(0, 10)' : schema.table.name - } LIMIT 100`, - }, - } - return ( - cancelWizard()} - to={urls.insightNew(undefined, undefined, JSON.stringify(query))} - > - Query - - ) - } - - return '' - }, - }, - ]} + columns={columns} />
diff --git a/frontend/src/scenes/data-warehouse/new/NewSourceWizard.tsx b/frontend/src/scenes/data-warehouse/new/NewSourceWizard.tsx index 231109f991a56..099648a51822e 100644 --- a/frontend/src/scenes/data-warehouse/new/NewSourceWizard.tsx +++ b/frontend/src/scenes/data-warehouse/new/NewSourceWizard.tsx @@ -6,7 +6,6 @@ import { SceneExport } from 'scenes/sceneTypes' import { ManualLinkSourceType, SourceConfig } from '~/types' -import { DataWarehouseBetaNotice } from '../DataWarehouseBetaNotice' import { DataWarehouseInitialBillingLimitNotice } from '../DataWarehouseInitialBillingLimitNotice' import PostgresSchemaForm from '../external/forms/PostgresSchemaForm' import SourceForm from '../external/forms/SourceForm' @@ -17,14 +16,43 @@ import { dataWarehouseTableLogic } from './dataWarehouseTableLogic' import { sourceWizardLogic } from './sourceWizardLogic' export const scene: SceneExport = { - component: NewSourceWizard, + component: NewSourceWizardScene, logic: sourceWizardLogic, } -export function NewSourceWizard(): JSX.Element { - const { modalTitle, modalCaption } = useValues(sourceWizardLogic) - const { onBack, onSubmit, closeWizard } = useActions(sourceWizardLogic) - const { currentStep, isLoading, canGoBack, canGoNext, nextButtonText, showSkipButton } = - useValues(sourceWizardLogic) +export function NewSourceWizardScene(): JSX.Element { + const { closeWizard } = useActions(sourceWizardLogic) + + return ( + <> + + + Cancel + + + } + /> + + + ) +} + +interface NewSourcesWizardProps { + onComplete?: () => void +} + +export function NewSourcesWizard({ onComplete }: NewSourcesWizardProps): JSX.Element { + const wizardLogic = sourceWizardLogic({ onComplete }) + + const { modalTitle, modalCaption, isWrapped } = useValues(wizardLogic) + const { onBack, onSubmit } = useActions(wizardLogic) + const { currentStep, isLoading, canGoBack, canGoNext, nextButtonText, showSkipButton } = useValues(wizardLogic) const { tableLoading: manualLinkIsLoading } = useValues(dataWarehouseTableLogic) const footer = useCallback(() => { @@ -33,7 +61,7 @@ export function NewSourceWizard(): JSX.Element { } return ( -
+
- - - Cancel - - - } - /> - - + {!isWrapped && } <>

{modalTitle}

{modalCaption}

diff --git a/frontend/src/scenes/data-warehouse/new/sourceWizardLogic.tsx b/frontend/src/scenes/data-warehouse/new/sourceWizardLogic.tsx index 2354faf4cdb18..7908f494ad541 100644 --- a/frontend/src/scenes/data-warehouse/new/sourceWizardLogic.tsx +++ b/frontend/src/scenes/data-warehouse/new/sourceWizardLogic.tsx @@ -1,5 +1,5 @@ import { lemonToast, Link } from '@posthog/lemon-ui' -import { actions, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { actions, connect, kea, listeners, path, props, reducers, selectors } from 'kea' import { forms } from 'kea-forms' import { router, urlToAction } from 'kea-router' import api from 'lib/api' @@ -338,8 +338,13 @@ const manualLinkSourceMap: Record = { 'cloudflare-r2': 'Cloudflare R2', } +export interface SourceWizardLogicProps { + onComplete?: () => void +} + export const sourceWizardLogic = kea([ path(['scenes', 'data-warehouse', 'external', 'sourceWizardLogic']), + props({} as SourceWizardLogicProps), actions({ selectConnector: (connector: SourceConfig | null) => ({ connector }), toggleManualLinkFormVisible: (visible: boolean) => ({ visible }), @@ -526,8 +531,8 @@ export const sourceWizardLogic = kea([ }, ], nextButtonText: [ - (s) => [s.currentStep, s.isManualLinkingSelected], - (currentStep, isManualLinkingSelected): string => { + (s) => [s.currentStep, s.isManualLinkingSelected, (_, props) => props.onComplete], + (currentStep, isManualLinkingSelected, onComplete): string => { if (currentStep === 3 && isManualLinkingSelected) { return 'Link' } @@ -537,6 +542,9 @@ export const sourceWizardLogic = kea([ } if (currentStep === 4) { + if (onComplete) { + return 'Next' + } return 'Return to settings' } @@ -641,8 +649,10 @@ export const sourceWizardLogic = kea([ return '' }, ], + // determines if the wizard is wrapped in another component + isWrapped: [() => [(_, props) => props.onComplete], (onComplete) => !!onComplete], }), - listeners(({ actions, values }) => ({ + listeners(({ actions, values, props }) => ({ onBack: () => { if (values.currentStep <= 1) { actions.onClear() @@ -688,7 +698,11 @@ export const sourceWizardLogic = kea([ } if (values.currentStep === 4) { - actions.closeWizard() + if (props.onComplete) { + props.onComplete() + } else { + actions.closeWizard() + } } }, createTableSuccess: () => { diff --git a/frontend/src/scenes/data-warehouse/settings/DataWarehouseManagedSourcesTable.tsx b/frontend/src/scenes/data-warehouse/settings/DataWarehouseManagedSourcesTable.tsx index 5101d5a048599..489c61a360e77 100644 --- a/frontend/src/scenes/data-warehouse/settings/DataWarehouseManagedSourcesTable.tsx +++ b/frontend/src/scenes/data-warehouse/settings/DataWarehouseManagedSourcesTable.tsx @@ -27,7 +27,6 @@ import zendeskLogo from 'public/zendesk-logo.svg' import { useEffect } from 'react' import { urls } from 'scenes/urls' -import { DataTableNode, NodeKind } from '~/queries/schema' import { DataWarehouseSyncInterval, ExternalDataSourceSchema, @@ -37,6 +36,7 @@ import { } from '~/types' import { SyncMethodForm } from '../external/forms/SyncMethodForm' +import { defaultQuery } from '../utils' import { dataWarehouseSettingsLogic } from './dataWarehouseSettingsLogic' import { dataWarehouseSourcesTableSyncMethodModalLogic } from './dataWarehouseSourcesTableSyncMethodModalLogic' @@ -350,22 +350,7 @@ const SchemaTable = ({ schemas }: SchemaTableProps): JSX.Element => { key: 'table', render: function RenderTable(_, schema) { if (schema.table) { - const query: DataTableNode = { - kind: NodeKind.DataTableNode, - full: true, - source: { - kind: NodeKind.HogQLQuery, - // TODO: Use `hogql` tag? - query: `SELECT ${schema.table.columns - .filter( - ({ table, fields, chain, schema_valid }) => - !table && !fields && !chain && schema_valid - ) - .map(({ name }) => name)} FROM ${ - schema.table.name === 'numbers' ? 'numbers(0, 10)' : schema.table.name - } LIMIT 100`, - }, - } + const query = defaultQuery(schema.table.name, schema.table.columns) return ( {schema.table.name} diff --git a/frontend/src/scenes/data-warehouse/settings/DataWarehouseSettingsScene.tsx b/frontend/src/scenes/data-warehouse/settings/DataWarehouseSettingsScene.tsx index 85337b829b756..26534c71edcb7 100644 --- a/frontend/src/scenes/data-warehouse/settings/DataWarehouseSettingsScene.tsx +++ b/frontend/src/scenes/data-warehouse/settings/DataWarehouseSettingsScene.tsx @@ -7,7 +7,6 @@ import { urls } from 'scenes/urls' import { DataWarehouseSettingsTab } from '~/types' -import { DataWarehouseBetaNotice } from '../DataWarehouseBetaNotice' import { DataWarehouseInitialBillingLimitNotice } from '../DataWarehouseInitialBillingLimitNotice' import { DataWarehouseManagedSourcesTable } from './DataWarehouseManagedSourcesTable' import { DataWarehouseSelfManagedSourcesTable } from './DataWarehouseSelfManagedSourcesTable' @@ -46,7 +45,6 @@ export function DataWarehouseSettingsScene(): JSX.Element {
} /> - { + return { + kind: NodeKind.DataTableNode, + full: true, + source: { + kind: NodeKind.HogQLQuery, + // TODO: Use `hogql` tag? + query: `SELECT ${columns + .filter(({ table, fields, chain, schema_valid }) => !table && !fields && !chain && schema_valid) + .map(({ name }) => name)} FROM ${table === 'numbers' ? 'numbers(0, 10)' : table} LIMIT 100`, + }, + } +} diff --git a/frontend/src/scenes/onboarding/Onboarding.tsx b/frontend/src/scenes/onboarding/Onboarding.tsx index c5fdd54c2e890..a2ba4d97bac32 100644 --- a/frontend/src/scenes/onboarding/Onboarding.tsx +++ b/frontend/src/scenes/onboarding/Onboarding.tsx @@ -10,6 +10,7 @@ import { userLogic } from 'scenes/userLogic' import { AvailableFeature, ProductKey, SDKKey } from '~/types' +import { DataWarehouseSources } from './data-warehouse/sources' import { OnboardingBillingStep } from './OnboardingBillingStep' import { OnboardingInviteTeammates } from './OnboardingInviteTeammates' import { onboardingLogic, OnboardingStepKey } from './onboardingLogic' @@ -241,11 +242,20 @@ const SurveysOnboarding = (): JSX.Element => { ) } +const DataWarehouseOnboarding = (): JSX.Element => { + return ( + + + + ) +} + export const onboardingViews = { [ProductKey.PRODUCT_ANALYTICS]: ProductAnalyticsOnboarding, [ProductKey.SESSION_REPLAY]: SessionReplayOnboarding, [ProductKey.FEATURE_FLAGS]: FeatureFlagsOnboarding, [ProductKey.SURVEYS]: SurveysOnboarding, + [ProductKey.DATA_WAREHOUSE]: DataWarehouseOnboarding, } export function Onboarding(): JSX.Element | null { diff --git a/frontend/src/scenes/onboarding/data-warehouse/sources.tsx b/frontend/src/scenes/onboarding/data-warehouse/sources.tsx new file mode 100644 index 0000000000000..84752fb631d37 --- /dev/null +++ b/frontend/src/scenes/onboarding/data-warehouse/sources.tsx @@ -0,0 +1,34 @@ +import { useActions, useValues } from 'kea' +import { NewSourcesWizard } from 'scenes/data-warehouse/new/NewSourceWizard' +import { sourceWizardLogic } from 'scenes/data-warehouse/new/sourceWizardLogic' + +import { onboardingLogic, OnboardingStepKey } from '../onboardingLogic' +import { OnboardingStep } from '../OnboardingStep' + +export function DataWarehouseSources({ + stepKey = OnboardingStepKey.INSTALL, +}: { + usersAction?: string + subtitle?: string + stepKey?: OnboardingStepKey +}): JSX.Element { + const { goToNextStep } = useActions(onboardingLogic) + const { currentStep } = useValues(sourceWizardLogic) + + return ( + } + showSkip={currentStep == 1} + subtitle={ + currentStep == 1 + ? `Link all your important data from your CRM, payment processor, + or database and query across them seamlessly.` + : undefined + } + > + goToNextStep()} /> + + ) +} diff --git a/frontend/src/scenes/onboarding/onboardingLogic.tsx b/frontend/src/scenes/onboarding/onboardingLogic.tsx index e24198ea4c090..1cf174801d78c 100644 --- a/frontend/src/scenes/onboarding/onboardingLogic.tsx +++ b/frontend/src/scenes/onboarding/onboardingLogic.tsx @@ -26,6 +26,7 @@ export interface OnboardingLogicProps { export enum OnboardingStepKey { PRODUCT_INTRO = 'product_intro', INSTALL = 'install', + LINK_DATA = 'link_data', PLANS = 'plans', VERIFY = 'verify', PRODUCT_CONFIGURATION = 'configure', @@ -41,6 +42,14 @@ export const availableOnboardingProducts: AvailableOnboardingProducts = { url: urls.insights(), scene: Scene.SavedInsights, }, + [ProductKey.DATA_WAREHOUSE]: { + name: 'Data Warehouse', + icon: 'IconDatabase', + iconColor: 'salmon', + breadcrumbsName: 'Data Warehouse', + url: urls.dataWarehouse(), + scene: Scene.DataWarehouse, + }, [ProductKey.SESSION_REPLAY]: { name: 'Session Replay', icon: 'IconRewindPlay', diff --git a/frontend/src/scenes/pipeline/Pipeline.tsx b/frontend/src/scenes/pipeline/Pipeline.tsx index 3f57c5d64e731..d832084e73066 100644 --- a/frontend/src/scenes/pipeline/Pipeline.tsx +++ b/frontend/src/scenes/pipeline/Pipeline.tsx @@ -2,9 +2,7 @@ import { LemonTag } from '@posthog/lemon-ui' import { useValues } from 'kea' import { router } from 'kea-router' import { PageHeader } from 'lib/components/PageHeader' -import { FEATURE_FLAGS } from 'lib/constants' import { LemonTabs } from 'lib/lemon-ui/LemonTabs' -import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { DataWarehouseManagedSourcesTable } from 'scenes/data-warehouse/settings/DataWarehouseManagedSourcesTable' import { SceneExport } from 'scenes/sceneTypes' import { urls } from 'scenes/urls' @@ -27,20 +25,13 @@ export function Pipeline(): JSX.Element { const { canGloballyManagePlugins } = useValues(pipelineAccessLogic) const { currentTab } = useValues(pipelineLogic) const { hasEnabledImportApps } = useValues(importAppsLogic) - const { featureFlags } = useValues(featureFlagLogic) let tabToContent: Partial> = { [PipelineTab.Overview]: , [PipelineTab.Transformations]: , [PipelineTab.Destinations]: , [PipelineTab.SiteApps]: , - } - - if (featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE]) { - tabToContent = { - ...tabToContent, - [PipelineTab.DataImport]: , - } + [PipelineTab.DataImport]: , } // Import apps are deprecated, we only show the tab if there are some still enabled if (hasEnabledImportApps) { diff --git a/frontend/src/scenes/products/Products.tsx b/frontend/src/scenes/products/Products.tsx index ed3ef4d1f63f9..12a1800c2419d 100644 --- a/frontend/src/scenes/products/Products.tsx +++ b/frontend/src/scenes/products/Products.tsx @@ -98,7 +98,7 @@ export function Products(): JSX.Element { {isFirstProductOnboarding &&

You can set up additional products later.

}
<> -
+
{Object.keys(availableOnboardingProducts).map((productKey) => ( > = { [ProductKey.FEATURE_FLAGS]: [urls.featureFlags(), urls.earlyAccessFeatures(), urls.experiments()], [ProductKey.SURVEYS]: [urls.surveys()], [ProductKey.PRODUCT_ANALYTICS]: [urls.insights(), urls.webAnalytics()], + [ProductKey.DATA_WAREHOUSE]: [urls.dataWarehouse()], } export const sceneLogic = kea([ @@ -39,7 +41,16 @@ export const sceneLogic = kea([ path(['scenes', 'sceneLogic']), connect(() => ({ logic: [router, userLogic, preflightLogic], - actions: [router, ['locationChanged'], commandBarLogic, ['setCommandBar'], inviteLogic, ['hideInviteModal']], + actions: [ + router, + ['locationChanged'], + commandBarLogic, + ['setCommandBar'], + inviteLogic, + ['hideInviteModal'], + sourceWizardLogic, + ['selectConnector', 'handleRedirect', 'setStep'], + ], values: [ featureFlagLogic, ['featureFlags'], @@ -262,9 +273,25 @@ export const sceneLogic = kea([ onboardingLogic.mount() onboardingLogic.actions.setIncludeIntro(!!values.billing) onboardingLogic.unmount() - router.actions.replace( - urls.onboarding(productKeyFromUrl, OnboardingStepKey.PRODUCT_INTRO) - ) + + if ( + scene === Scene.DataWarehouseTable && + params.searchParams.kind == 'hubspot' && + params.searchParams.code + ) { + actions.selectConnector(SOURCE_DETAILS['Hubspot']) + actions.handleRedirect(params.searchParams.kind, { + code: params.searchParams.code, + }) + actions.setStep(2) + router.actions.replace( + urls.onboarding(productKeyFromUrl, OnboardingStepKey.LINK_DATA) + ) + } else { + router.actions.replace( + urls.onboarding(productKeyFromUrl, OnboardingStepKey.PRODUCT_INTRO) + ) + } return } } diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 2496d04da4d61..a6a02a518ac21 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -4184,7 +4184,11 @@ export type AvailableOnboardingProducts = Pick< { [key in ProductKey]: OnboardingProduct }, - ProductKey.PRODUCT_ANALYTICS | ProductKey.SESSION_REPLAY | ProductKey.FEATURE_FLAGS | ProductKey.SURVEYS + | ProductKey.PRODUCT_ANALYTICS + | ProductKey.SESSION_REPLAY + | ProductKey.FEATURE_FLAGS + | ProductKey.SURVEYS + | ProductKey.DATA_WAREHOUSE > export type OnboardingProduct = {