From cfafb9d9bcf48a61fdfeabcfbe6ec493dd94cbb5 Mon Sep 17 00:00:00 2001 From: Eric Duong Date: Tue, 18 Jun 2024 09:46:27 -0400 Subject: [PATCH] chore(data-warehouse): split managed and self managed tables in settings page (#23034) split managed and self-managed --- .../data-warehouse/external/TableData.tsx | 2 +- .../data-warehouse/new/NewSourceWizard.tsx | 2 +- ...x => DataWarehouseManagedSourcesTable.tsx} | 2 +- .../DataWarehouseSelfManagedSourcesTable.tsx | 58 +++++++++++++++++++ .../settings/DataWarehouseSettingsScene.tsx | 32 ++++++++-- .../settings/dataWarehouseSettingsLogic.ts | 50 +++++++++++++++- frontend/src/scenes/pipeline/Pipeline.tsx | 4 +- frontend/src/scenes/scenes.ts | 2 +- frontend/src/scenes/urls.ts | 4 +- frontend/src/types.ts | 5 ++ 10 files changed, 148 insertions(+), 13 deletions(-) rename frontend/src/scenes/data-warehouse/settings/{DataWarehouseSourcesTable.tsx => DataWarehouseManagedSourcesTable.tsx} (99%) create mode 100644 frontend/src/scenes/data-warehouse/settings/DataWarehouseSelfManagedSourcesTable.tsx diff --git a/frontend/src/scenes/data-warehouse/external/TableData.tsx b/frontend/src/scenes/data-warehouse/external/TableData.tsx index cddabcc609ba3..3ec7cbe952e61 100644 --- a/frontend/src/scenes/data-warehouse/external/TableData.tsx +++ b/frontend/src/scenes/data-warehouse/external/TableData.tsx @@ -229,7 +229,7 @@ export function DeleteTableModal({ return ( setIsOpen(false)} footer={ <> diff --git a/frontend/src/scenes/data-warehouse/new/NewSourceWizard.tsx b/frontend/src/scenes/data-warehouse/new/NewSourceWizard.tsx index 7a6ba4a8b6a1d..db86dbe60eb32 100644 --- a/frontend/src/scenes/data-warehouse/new/NewSourceWizard.tsx +++ b/frontend/src/scenes/data-warehouse/new/NewSourceWizard.tsx @@ -11,7 +11,7 @@ import PostgresSchemaForm from '../external/forms/PostgresSchemaForm' import SourceForm from '../external/forms/SourceForm' import { SyncProgressStep } from '../external/forms/SyncProgressStep' import { DatawarehouseTableForm } from '../new/DataWarehouseTableForm' -import { RenderDataWarehouseSourceIcon } from '../settings/DataWarehouseSourcesTable' +import { RenderDataWarehouseSourceIcon } from '../settings/DataWarehouseManagedSourcesTable' import { dataWarehouseTableLogic } from './dataWarehouseTableLogic' import { sourceWizardLogic } from './sourceWizardLogic' diff --git a/frontend/src/scenes/data-warehouse/settings/DataWarehouseSourcesTable.tsx b/frontend/src/scenes/data-warehouse/settings/DataWarehouseManagedSourcesTable.tsx similarity index 99% rename from frontend/src/scenes/data-warehouse/settings/DataWarehouseSourcesTable.tsx rename to frontend/src/scenes/data-warehouse/settings/DataWarehouseManagedSourcesTable.tsx index 99f92ad4a543d..c4b797426c6dc 100644 --- a/frontend/src/scenes/data-warehouse/settings/DataWarehouseSourcesTable.tsx +++ b/frontend/src/scenes/data-warehouse/settings/DataWarehouseManagedSourcesTable.tsx @@ -42,7 +42,7 @@ const StatusTagSetting = { Failed: 'danger', } -export function DataWarehouseSourcesTable(): JSX.Element { +export function DataWarehouseManagedSourcesTable(): JSX.Element { const { dataWarehouseSources, dataWarehouseSourcesLoading, sourceReloadingById } = useValues(dataWarehouseSettingsLogic) const { deleteSource, reloadSource, updateSource } = useActions(dataWarehouseSettingsLogic) diff --git a/frontend/src/scenes/data-warehouse/settings/DataWarehouseSelfManagedSourcesTable.tsx b/frontend/src/scenes/data-warehouse/settings/DataWarehouseSelfManagedSourcesTable.tsx new file mode 100644 index 0000000000000..a067aff2bd2c9 --- /dev/null +++ b/frontend/src/scenes/data-warehouse/settings/DataWarehouseSelfManagedSourcesTable.tsx @@ -0,0 +1,58 @@ +import { LemonButton, LemonDialog, LemonTable } from '@posthog/lemon-ui' +import { useActions, useValues } from 'kea' + +import { DatabaseSchemaDataWarehouseTable } from '~/queries/schema' + +import { dataWarehouseSettingsLogic } from './dataWarehouseSettingsLogic' + +export function DataWarehouseSelfManagedSourcesTable(): JSX.Element { + const { selfManagedTables } = useValues(dataWarehouseSettingsLogic) + const { deleteSelfManagedTable } = useActions(dataWarehouseSettingsLogic) + + return ( + { + return ( +
+ { + LemonDialog.open({ + title: 'Delete table?', + description: + 'Table deletion cannot be undone. All views and joins related to this table will be deleted.', + + primaryButton: { + children: 'Delete', + status: 'danger', + onClick: () => { + deleteSelfManagedTable(item.id) + }, + }, + secondaryButton: { + children: 'Cancel', + }, + }) + }} + > + Delete + +
+ ) + }, + }, + ]} + /> + ) +} diff --git a/frontend/src/scenes/data-warehouse/settings/DataWarehouseSettingsScene.tsx b/frontend/src/scenes/data-warehouse/settings/DataWarehouseSettingsScene.tsx index 8ca757a11d9a5..2b75670c1101e 100644 --- a/frontend/src/scenes/data-warehouse/settings/DataWarehouseSettingsScene.tsx +++ b/frontend/src/scenes/data-warehouse/settings/DataWarehouseSettingsScene.tsx @@ -1,11 +1,16 @@ -import { LemonButton } from '@posthog/lemon-ui' +import { LemonButton, LemonTabs } from '@posthog/lemon-ui' +import { useValues } from 'kea' +import { router } from 'kea-router' import { PageHeader } from 'lib/components/PageHeader' import { SceneExport } from 'scenes/sceneTypes' import { urls } from 'scenes/urls' +import { DataWarehouseSettingsTab } from '~/types' + import { DataWarehouseBetaNotice } from '../DataWarehouseBetaNotice' -import { dataWarehouseSettingsLogic } from './dataWarehouseSettingsLogic' -import { DataWarehouseSourcesTable } from './DataWarehouseSourcesTable' +import { DataWarehouseManagedSourcesTable } from './DataWarehouseManagedSourcesTable' +import { DataWarehouseSelfManagedSourcesTable } from './DataWarehouseSelfManagedSourcesTable' +import { dataWarehouseSettingsLogic, humanFriendlyDataWarehouseSettingsTabName } from './dataWarehouseSettingsLogic' export const scene: SceneExport = { component: DataWarehouseSettingsScene, @@ -13,6 +18,13 @@ export const scene: SceneExport = { } export function DataWarehouseSettingsScene(): JSX.Element { + const { currentTab } = useValues(dataWarehouseSettingsLogic) + + const tabToContent: Partial> = { + [DataWarehouseSettingsTab.Managed]: , + [DataWarehouseSettingsTab.SelfManaged]: , + } + return (
- + router.actions.push(urls.dataWarehouseSettings(tab as DataWarehouseSettingsTab))} + tabs={Object.entries(tabToContent).map(([tab, content]) => ({ + label: ( + + {humanFriendlyDataWarehouseSettingsTabName(tab as DataWarehouseSettingsTab)}{' '} + + ), + key: tab, + content: content, + }))} + />
) } diff --git a/frontend/src/scenes/data-warehouse/settings/dataWarehouseSettingsLogic.ts b/frontend/src/scenes/data-warehouse/settings/dataWarehouseSettingsLogic.ts index 19795ffe3c37a..41423920778dc 100644 --- a/frontend/src/scenes/data-warehouse/settings/dataWarehouseSettingsLogic.ts +++ b/frontend/src/scenes/data-warehouse/settings/dataWarehouseSettingsLogic.ts @@ -1,11 +1,14 @@ -import { actions, afterMount, kea, listeners, path, reducers, selectors } from 'kea' +import { actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' import { loaders } from 'kea-loaders' +import { actionToUrl, urlToAction } from 'kea-router' import api, { ApiMethodOptions, PaginatedResponse } from 'lib/api' import { lemonToast } from 'lib/lemon-ui/LemonToast/LemonToast' +import { databaseTableListLogic } from 'scenes/data-management/database/databaseTableListLogic' import { Scene } from 'scenes/sceneTypes' import { urls } from 'scenes/urls' -import { Breadcrumb, ExternalDataSourceSchema, ExternalDataStripeSource } from '~/types' +import { DatabaseSchemaDataWarehouseTable } from '~/queries/schema' +import { Breadcrumb, DataWarehouseSettingsTab, ExternalDataSourceSchema, ExternalDataStripeSource } from '~/types' import type { dataWarehouseSettingsLogicType } from './dataWarehouseSettingsLogicType' @@ -13,8 +16,21 @@ const REFRESH_INTERVAL = 10000 export interface DataWarehouseSource {} +export const humanFriendlyDataWarehouseSettingsTabName = (tab: DataWarehouseSettingsTab): string => { + switch (tab) { + case DataWarehouseSettingsTab.Managed: + return 'Managed' + case DataWarehouseSettingsTab.SelfManaged: + return 'Self managed' + } +} + export const dataWarehouseSettingsLogic = kea([ path(['scenes', 'data-warehouse', 'settings', 'dataWarehouseSettingsLogic']), + connect(() => ({ + values: [databaseTableListLogic, ['dataWarehouseTables']], + actions: [databaseTableListLogic, ['loadDatabase']], + })), actions({ deleteSource: (source: ExternalDataStripeSource) => ({ source }), reloadSource: (source: ExternalDataStripeSource) => ({ source }), @@ -24,6 +40,8 @@ export const dataWarehouseSettingsLogic = kea([ schemaLoadingFinished: (schema: ExternalDataSourceSchema) => ({ schema }), updateSchema: (schema: ExternalDataSourceSchema) => ({ schema }), abortAnyRunningQuery: true, + setCurrentTab: (tab: DataWarehouseSettingsTab = DataWarehouseSettingsTab.Managed) => ({ tab }), + deleteSelfManagedTable: (tableId: string) => ({ tableId }), }), loaders(({ cache, actions, values }) => ({ dataWarehouseSources: [ @@ -100,6 +118,12 @@ export const dataWarehouseSettingsLogic = kea([ }), }, ], + currentTab: [ + DataWarehouseSettingsTab.Managed as DataWarehouseSettingsTab, + { + setCurrentTab: (_, { tab }) => tab, + }, + ], })), selectors({ breadcrumbs: [ @@ -117,8 +141,18 @@ export const dataWarehouseSettingsLogic = kea([ }, ], ], + selfManagedTables: [ + (s) => [s.dataWarehouseTables], + (dataWarehouseTables): DatabaseSchemaDataWarehouseTable[] => { + return dataWarehouseTables.filter((table) => !table.source) + }, + ], }), listeners(({ actions, values, cache }) => ({ + deleteSelfManagedTable: async ({ tableId }) => { + await api.dataWarehouseTables.delete(tableId) + actions.loadDatabase() + }, loadSourcesSuccess: () => { clearTimeout(cache.refreshTimeout) @@ -254,4 +288,16 @@ export const dataWarehouseSettingsLogic = kea([ afterMount(({ actions }) => { actions.loadSources(null) }), + actionToUrl(({ values }) => { + return { + setCurrentTab: () => [urls.dataWarehouseSettings(values.currentTab)], + } + }), + urlToAction(({ actions, values }) => ({ + '/data-warehouse/settings/:tab': ({ tab }) => { + if (tab !== values.currentTab) { + actions.setCurrentTab(tab as DataWarehouseSettingsTab) + } + }, + })), ]) diff --git a/frontend/src/scenes/pipeline/Pipeline.tsx b/frontend/src/scenes/pipeline/Pipeline.tsx index 177762ce2fb7a..3f57c5d64e731 100644 --- a/frontend/src/scenes/pipeline/Pipeline.tsx +++ b/frontend/src/scenes/pipeline/Pipeline.tsx @@ -5,7 +5,7 @@ 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 { DataWarehouseSourcesTable } from 'scenes/data-warehouse/settings/DataWarehouseSourcesTable' +import { DataWarehouseManagedSourcesTable } from 'scenes/data-warehouse/settings/DataWarehouseManagedSourcesTable' import { SceneExport } from 'scenes/sceneTypes' import { urls } from 'scenes/urls' @@ -39,7 +39,7 @@ export function Pipeline(): JSX.Element { 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 diff --git a/frontend/src/scenes/scenes.ts b/frontend/src/scenes/scenes.ts index fbb947c13d134..daedf852af18a 100644 --- a/frontend/src/scenes/scenes.ts +++ b/frontend/src/scenes/scenes.ts @@ -555,7 +555,7 @@ export const routes: Record = { [urls.surveyTemplates()]: Scene.SurveyTemplates, [urls.dataWarehouse()]: Scene.DataWarehouse, [urls.dataWarehouseTable()]: Scene.DataWarehouseTable, - [urls.dataWarehouseSettings()]: Scene.DataWarehouseSettings, + [urls.dataWarehouseSettings(':tab')]: Scene.DataWarehouseSettings, [urls.dataWarehouseRedirect(':kind')]: Scene.DataWarehouseRedirect, [urls.featureFlags()]: Scene.FeatureFlags, [urls.featureFlag(':id')]: Scene.FeatureFlag, diff --git a/frontend/src/scenes/urls.ts b/frontend/src/scenes/urls.ts index cb300d96749ad..4d99bb15b5d8c 100644 --- a/frontend/src/scenes/urls.ts +++ b/frontend/src/scenes/urls.ts @@ -11,6 +11,7 @@ import { AnyPartialFilterType, AppMetricsUrlParams, DashboardType, + DataWarehouseSettingsTab, FilterType, InsightShortId, PipelineNodeTab, @@ -159,7 +160,8 @@ export const urls = { combineUrl('/data-warehouse', {}, query ? { q: typeof query === 'string' ? query : JSON.stringify(query) } : {}) .url, dataWarehouseTable: (): string => `/data-warehouse/new`, - dataWarehouseSettings: (): string => '/data-warehouse/settings', + dataWarehouseSettings: (tab?: DataWarehouseSettingsTab | ':tab'): string => + `/data-warehouse/settings/${tab ? tab : DataWarehouseSettingsTab.Managed}`, dataWarehouseRedirect: (kind: string): string => `/data-warehouse/${kind}/redirect`, annotations: (): string => '/data-management/annotations', annotation: (id: AnnotationType['id'] | ':id'): string => `/data-management/annotations/${id}`, diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 23e84132c413d..677ec5522e094 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -3793,6 +3793,11 @@ export interface DataWarehouseViewLink { created_at?: string | null } +export enum DataWarehouseSettingsTab { + Managed = 'managed', + SelfManaged = 'self_managed', +} + export const externalDataSources = ['Stripe', 'Hubspot', 'Postgres', 'Zendesk', 'Snowflake'] as const export type ExternalDataSourceType = (typeof externalDataSources)[number]