diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration--dark.png index 6fb0998c99218..03ed3be76614d 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration--dark.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration--light.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration--light.png index 170cfeafbe203..e606a27b97dc7 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration--light.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration--light.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration-404--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration-404--dark.png new file mode 100644 index 0000000000000..f5331e45a4b4b Binary files /dev/null and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration-404--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration-404--light.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration-404--light.png new file mode 100644 index 0000000000000..025a455dae129 Binary files /dev/null and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration-404--light.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration-empty--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration-empty--dark.png new file mode 100644 index 0000000000000..917984d79bca1 Binary files /dev/null and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration-empty--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration-empty--light.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration-empty--light.png new file mode 100644 index 0000000000000..f91ed280d5bb8 Binary files /dev/null and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration-empty--light.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-logs--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-logs--dark.png index 390ebdc86a68d..e093a5f53abdd 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-logs--dark.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-logs--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-logs--light.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-logs--light.png index 20a60e7bd0174..ed4913123192c 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-logs--light.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-logs--light.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-logs-batch-export--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-logs-batch-export--dark.png new file mode 100644 index 0000000000000..f5331e45a4b4b Binary files /dev/null and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-logs-batch-export--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-logs-batch-export--light.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-logs-batch-export--light.png new file mode 100644 index 0000000000000..025a455dae129 Binary files /dev/null and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-logs-batch-export--light.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics--dark.png index 300b2202e6b49..4be88bd92af87 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics--dark.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics--light.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics--light.png index f286d78c11853..5b608fc07d6f2 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics--light.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics--light.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics-error-modal--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics-error-modal--dark.png index d234c5e9afb3a..8d0040451649e 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics-error-modal--dark.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics-error-modal--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics-error-modal--light.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics-error-modal--light.png index 892f0ca235736..d703740037ac5 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics-error-modal--light.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics-error-modal--light.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-apps-management-page--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-apps-management-page--dark.png index 103c966f5be29..5ef8980069537 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-apps-management-page--dark.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-apps-management-page--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-apps-management-page--light.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-apps-management-page--light.png index a79aa17f0b6a1..9f93174665f39 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-apps-management-page--light.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-apps-management-page--light.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-destinations-page--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-destinations-page--dark.png index 25e261411d22d..0c1edf3844993 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-destinations-page--dark.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-destinations-page--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-destinations-page--light.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-destinations-page--light.png index a2de99ec830f4..4502aa48db727 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-destinations-page--light.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-destinations-page--light.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-filtering-page--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-filtering-page--dark.png index 76f321a927289..0e6e16ae259fa 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-filtering-page--dark.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-filtering-page--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-filtering-page--light.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-filtering-page--light.png index a6b29cd3f9fc4..8eb0f0246b3e6 100644 Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-filtering-page--light.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-filtering-page--light.png differ 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 cfe55695fadf3..0c1edf3844993 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 52358ae7c9283..4502aa48db727 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-transformations-page-empty--dark.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page-empty--dark.png index d4aa288b61e3c..70cabae57dbdf 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 5e1f9164c4104..28cda46ec0211 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-billing-v2--billing-unsubscribe-modal-data-pipelines--dark.png b/frontend/__snapshots__/scenes-other-billing-v2--billing-unsubscribe-modal-data-pipelines--dark.png index 39d5318ba7312..389112f3e2c7f 100644 Binary files a/frontend/__snapshots__/scenes-other-billing-v2--billing-unsubscribe-modal-data-pipelines--dark.png and b/frontend/__snapshots__/scenes-other-billing-v2--billing-unsubscribe-modal-data-pipelines--dark.png differ diff --git a/frontend/src/mocks/handlers.ts b/frontend/src/mocks/handlers.ts index d039c449c402c..5255a2015116e 100644 --- a/frontend/src/mocks/handlers.ts +++ b/frontend/src/mocks/handlers.ts @@ -9,7 +9,6 @@ import { MOCK_DEFAULT_USER, MOCK_PERSON_PROPERTIES, MOCK_SECOND_ORGANIZATION_MEMBER, - MOCK_TEAM_ID, } from 'lib/api.mock' import { getAvailableFeatures } from '~/mocks/features' @@ -73,8 +72,7 @@ export const defaultMocks: Mocks = { '/api/organizations/@current/plugins/repository/': [], '/api/organizations/@current/plugins/unused/': [], '/api/plugin_config/': toPaginatedResponse([MOCK_DEFAULT_PLUGIN_CONFIG]), - [`/api/projects/${MOCK_TEAM_ID}/plugin_configs/${MOCK_DEFAULT_PLUGIN_CONFIG.id}/`]: MOCK_DEFAULT_PLUGIN_CONFIG, - '/api/projects/@current/persons/properties/': toPaginatedResponse(MOCK_PERSON_PROPERTIES), + [`/api/projects/:team_id/plugin_configs/${MOCK_DEFAULT_PLUGIN_CONFIG.id}/`]: MOCK_DEFAULT_PLUGIN_CONFIG, '/api/projects/:team_id/persons': EMPTY_PAGINATED_RESPONSE, '/api/projects/:team_id/persons/properties/': toPaginatedResponse(MOCK_PERSON_PROPERTIES), '/api/personal_api_keys/': [], diff --git a/frontend/src/scenes/apps/AppLogsTab.tsx b/frontend/src/scenes/apps/AppLogsTab.tsx index 1f400babb273b..34234e3f8dfcf 100644 --- a/frontend/src/scenes/apps/AppLogsTab.tsx +++ b/frontend/src/scenes/apps/AppLogsTab.tsx @@ -2,7 +2,7 @@ import { useValues } from 'kea' import { LemonSkeleton } from 'lib/lemon-ui/LemonSkeleton' import { PipelineAppLogs } from 'scenes/pipeline/PipelineAppLogs' -import { PipelineTabs } from '~/types' +import { PipelineAppKind } from '~/types' import { appMetricsSceneLogic } from './appMetricsSceneLogic' @@ -15,7 +15,7 @@ export function AppLogsTab(): JSX.Element { return (
- +
) } diff --git a/frontend/src/scenes/pipeline/AppMetrics.tsx b/frontend/src/scenes/pipeline/AppMetrics.tsx index 9b5686c0ed0a0..f8b52cea9640d 100644 --- a/frontend/src/scenes/pipeline/AppMetrics.tsx +++ b/frontend/src/scenes/pipeline/AppMetrics.tsx @@ -298,7 +298,8 @@ function ErrorDetailsModal({ pluginConfigId }: { pluginConfigId: number }): JSX. // eslint-disable-next-line react/forbid-dom-props
- When: + When:{' '} +
{activeErrorDetails.error_details.eventCount && ( diff --git a/frontend/src/scenes/pipeline/Destinations.tsx b/frontend/src/scenes/pipeline/Destinations.tsx index 804402d0ef180..0243d37047884 100644 --- a/frontend/src/scenes/pipeline/Destinations.tsx +++ b/frontend/src/scenes/pipeline/Destinations.tsx @@ -17,7 +17,7 @@ import { updatedAtColumn } from 'lib/lemon-ui/LemonTable/columnUtils' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { deleteWithUndo } from 'lib/utils/deleteWithUndo' -import { PipelineTabs, ProductKey } from '~/types' +import { PipelineAppKind, ProductKey } from '~/types' import { DestinationType, pipelineDestinationsLogic } from './destinationsLogic' import { NewButton } from './NewButton' @@ -42,7 +42,7 @@ export function Destinations(): JSX.Element { productKey={ProductKey.PIPELINE_DESTINATIONS} description="Pipeline destinations allow you to export data outside of PostHog, such as webhooks to Slack." docsURL="https://posthog.com/docs/cdp" - actionElementOverride={} + actionElementOverride={} isEmpty={true} /> )} @@ -85,7 +85,7 @@ function DestinationsTable(): JSX.Element { { title: 'App', render: function RenderAppInfo(_, destination) { - if (destination.type === 'webhook') { + if (destination.backend === 'plugin') { return } return <> // TODO: batch export @@ -100,7 +100,7 @@ function DestinationsTable(): JSX.Element { { title: '24h', // TODO: two options 24h or 7d selected render: function Render24hDeliveryRate(_, destination) { - if (destination.type === 'webhook') { + if (destination.backend === 'plugin') { let tooltip = 'No events exported in the past 24 hours' let value = '-' let tagType: LemonTagType = 'muted' @@ -206,7 +206,7 @@ function DestinationsTable(): JSX.Element { )} - {destination.type === 'webhook' && ( + {destination.backend === 'plugin' && ( { diff --git a/frontend/src/scenes/pipeline/NewButton.tsx b/frontend/src/scenes/pipeline/NewButton.tsx index 67b491360d32f..4b0a65e8dcb22 100644 --- a/frontend/src/scenes/pipeline/NewButton.tsx +++ b/frontend/src/scenes/pipeline/NewButton.tsx @@ -1,23 +1,20 @@ import { LemonButton } from 'lib/lemon-ui/LemonButton' import { urls } from 'scenes/urls' -import { PipelineAppTabs, PipelineTabs } from '~/types' - -import { singularName } from './pipelineLogic' +import { PipelineAppKind, PipelineAppTab } from '~/types' type NewButtonProps = { - tab: PipelineTabs + kind: PipelineAppKind } -export function NewButton({ tab }: NewButtonProps): JSX.Element { - const singular = singularName(tab) +export function NewButton({ kind }: NewButtonProps): JSX.Element { return ( - New {singular} + New {kind} ) } diff --git a/frontend/src/scenes/pipeline/Pipeline.stories.tsx b/frontend/src/scenes/pipeline/Pipeline.stories.tsx index 32b933a1b677d..05be1e9a0d534 100644 --- a/frontend/src/scenes/pipeline/Pipeline.stories.tsx +++ b/frontend/src/scenes/pipeline/Pipeline.stories.tsx @@ -6,8 +6,11 @@ import { App } from 'scenes/App' import { urls } from 'scenes/urls' import { mswDecorator, useStorybookMocks } from '~/mocks/browser' -import { PipelineAppTabs, PipelineTabs } from '~/types' +import { PipelineAppKind, PipelineAppTab, PipelineTab } from '~/types' +import batchExports from './__mocks__/batchExports.json' +import pluginConfigs from './__mocks__/pluginConfigs.json' +import plugins from './__mocks__/plugins.json' import { appMetricsLogic } from './appMetricsLogic' import { appsManagementLogic } from './appsManagementLogic' import { pipelineLogic } from './pipelineLogic' @@ -18,9 +21,14 @@ export default { // mocks used by all stories in this file mswDecorator({ get: { - 'api/organizations/@current/pipeline_transformations/': {}, - 'api/organizations/@current/plugins/': {}, - 'api/projects/:team_id/pipeline_transformation_configs/': {}, + '/api/projects/:team_id/batch_exports/': batchExports, + '/api/organizations/:organization_id/batch_exports/': batchExports, + '/api/organizations/@current/plugins/': plugins, + '/api/organizations/@current/pipeline_transformations/': plugins, + '/api/projects/:team_id/pipeline_transformation_configs/': pluginConfigs, + // TODO: Differentiate between transformation and destination mocks for nicer mocks + '/api/organizations/@current/pipeline_destinations/': plugins, + '/api/projects/:team_id/pipeline_destination_configs/': pluginConfigs, }, }), ], @@ -33,6 +41,13 @@ export default { }, // scene mode } as Meta +const eventSequenceTimerPluginConfigId = pluginConfigs.results.find( + (conf) => conf.plugin === plugins.results.find((plugin) => plugin.name === 'Event Sequence Timer Plugin')!.id +)!.id +const geoIpConfigId = pluginConfigs.results.find( + (conf) => conf.plugin === plugins.results.find((plugin) => plugin.name === 'GeoIP')!.id +)!.id + export function PipelineLandingPage(): JSX.Element { // also Destinations page useEffect(() => { @@ -41,9 +56,10 @@ export function PipelineLandingPage(): JSX.Element { }, []) return } + export function PipelineFilteringPage(): JSX.Element { useEffect(() => { - router.actions.push(urls.pipeline(PipelineTabs.Filters)) + router.actions.push(urls.pipeline(PipelineTab.Filters)) pipelineLogic.mount() }, []) return @@ -51,34 +67,23 @@ export function PipelineFilteringPage(): JSX.Element { export function PipelineTransformationsPageEmpty(): JSX.Element { useEffect(() => { - router.actions.push(urls.pipeline(PipelineTabs.Transformations)) + router.actions.push(urls.pipeline(PipelineTab.Transformations)) pipelineLogic.mount() }, []) return } export function PipelineTransformationsPage(): JSX.Element { - useStorybookMocks({ - get: { - 'api/organizations/@current/pipeline_transformations/': require('./__mocks__/plugins.json'), - 'api/projects/:team_id/pipeline_transformation_configs/': require('./__mocks__/transformationPluginConfigs.json'), - }, - }) useEffect(() => { - router.actions.push(urls.pipeline(PipelineTabs.Transformations)) + router.actions.push(urls.pipeline(PipelineTab.Transformations)) pipelineLogic.mount() }, []) return } + export function PipelineDestinationsPage(): JSX.Element { - useStorybookMocks({ - get: { - 'api/organizations/@current/pipeline_destinations/': require('./__mocks__/plugins.json'), - 'api/projects/:team_id/pipeline_destination_configs/': require('./__mocks__/transformationPluginConfigs.json'), - }, - }) useEffect(() => { - router.actions.push(urls.pipeline(PipelineTabs.Destinations)) + router.actions.push(urls.pipeline(PipelineTab.Destinations)) pipelineLogic.mount() }, []) return @@ -86,7 +91,27 @@ export function PipelineDestinationsPage(): JSX.Element { export function PipelineAppConfiguration(): JSX.Element { useEffect(() => { - router.actions.push(urls.pipelineApp(PipelineTabs.Destinations, 1, PipelineAppTabs.Configuration)) + router.actions.push( + urls.pipelineApp( + PipelineAppKind.Destination, + eventSequenceTimerPluginConfigId, + PipelineAppTab.Configuration + ) + ) + }, []) + return +} + +export function PipelineAppConfigurationEmpty(): JSX.Element { + useEffect(() => { + router.actions.push(urls.pipelineApp(PipelineAppKind.Destination, geoIpConfigId, PipelineAppTab.Configuration)) + }, []) + return +} + +export function PipelineAppConfiguration404(): JSX.Element { + useEffect(() => { + router.actions.push(urls.pipelineApp(PipelineAppKind.Destination, 4239084923809, PipelineAppTab.Configuration)) }, []) return } @@ -94,13 +119,13 @@ export function PipelineAppConfiguration(): JSX.Element { export function PipelineAppMetrics(): JSX.Element { useStorybookMocks({ get: { - 'api/projects/:team_id/app_metrics/4?date_from=-7d': require('./__mocks__/pluginMetrics.json'), - 'api/projects/:team_id/app_metrics/4/error_details?error_type=Error': require('./__mocks__/pluginErrorDetails.json'), + '/api/projects/:team_id/app_metrics/:plugin_config_id?date_from=-7d': require('./__mocks__/pluginMetrics.json'), + '/api/projects/:team_id/app_metrics/:plugin_config_id/error_details?error_type=Error': require('./__mocks__/pluginErrorDetails.json'), }, }) useEffect(() => { - router.actions.push(urls.pipelineApp(PipelineTabs.Destinations, 4, PipelineAppTabs.Metrics)) - appMetricsLogic({ pluginConfigId: 4 }).mount() + router.actions.push(urls.pipelineApp(PipelineAppKind.Destination, geoIpConfigId, PipelineAppTab.Metrics)) + appMetricsLogic({ pluginConfigId: geoIpConfigId }).mount() }, []) return } @@ -108,13 +133,13 @@ export function PipelineAppMetrics(): JSX.Element { export function PipelineAppMetricsErrorModal(): JSX.Element { useStorybookMocks({ get: { - 'api/projects/:team_id/app_metrics/4?date_from=-7d': require('./__mocks__/pluginMetrics.json'), - 'api/projects/:team_id/app_metrics/4/error_details?error_type=Error': require('./__mocks__/pluginErrorDetails.json'), + '/api/projects/:team_id/app_metrics/:plugin_config_id?date_from=-7d': require('./__mocks__/pluginMetrics.json'), + '/api/projects/:team_id/app_metrics/:plugin_config_id/error_details?error_type=Error': require('./__mocks__/pluginErrorDetails.json'), }, }) useEffect(() => { - router.actions.push(urls.pipelineApp(PipelineTabs.Destinations, 4, PipelineAppTabs.Metrics)) - const logic = appMetricsLogic({ pluginConfigId: 4 }) + router.actions.push(urls.pipelineApp(PipelineAppKind.Destination, geoIpConfigId, PipelineAppTab.Metrics)) + const logic = appMetricsLogic({ pluginConfigId: geoIpConfigId }) logic.mount() logic.actions.openErrorDetailsModal('Error') }, []) @@ -124,11 +149,11 @@ export function PipelineAppMetricsErrorModal(): JSX.Element { export function PipelineAppLogs(): JSX.Element { useStorybookMocks({ get: { - 'api/projects/:team_id/plugin_configs/1/logs': require('./__mocks__/pluginLogs.json'), + '/api/projects/:team_id/plugin_configs/:plugin_config_id/logs': require('./__mocks__/pluginLogs.json'), }, }) useEffect(() => { - router.actions.push(urls.pipelineApp(PipelineTabs.Destinations, 1, PipelineAppTabs.Logs)) + router.actions.push(urls.pipelineApp(PipelineAppKind.Destination, geoIpConfigId, PipelineAppTab.Logs)) }, []) return } @@ -136,26 +161,20 @@ export function PipelineAppLogs(): JSX.Element { export function PipelineAppLogsBatchExport(): JSX.Element { useStorybookMocks({ get: { - 'api/projects/:team_id/batch_exports/018cf79f-a9e5-0001-cd6a-edc4886d939d/logs': require('./__mocks__/batchExportLogs.json'), + '/api/projects/:team_id/batch_exports/:export_id/logs': require('./__mocks__/batchExportLogs.json'), }, }) useEffect(() => { router.actions.push( - urls.pipelineApp(PipelineTabs.Destinations, '018cf79f-a9e5-0001-cd6a-edc4886d939d', PipelineAppTabs.Logs) + urls.pipelineApp(PipelineAppKind.Destination, batchExports.results[0].id, PipelineAppTab.Logs) ) }, []) return } export function PipelineAppsManagementPage(): JSX.Element { - useStorybookMocks({ - get: { - 'api/organizations/@current/plugins/': require('./__mocks__/plugins.json'), - }, - }) - useEffect(() => { - router.actions.push(urls.pipeline(PipelineTabs.AppsManagement)) + router.actions.push(urls.pipeline(PipelineTab.AppsManagement)) appsManagementLogic.mount() }, []) return diff --git a/frontend/src/scenes/pipeline/Pipeline.tsx b/frontend/src/scenes/pipeline/Pipeline.tsx index 2fdf2c18f0b02..f131df44923d3 100644 --- a/frontend/src/scenes/pipeline/Pipeline.tsx +++ b/frontend/src/scenes/pipeline/Pipeline.tsx @@ -5,34 +5,37 @@ import { LemonTabs } from 'lib/lemon-ui/LemonTabs' import { SceneExport } from 'scenes/sceneTypes' import { urls } from 'scenes/urls' -import { PipelineTabs } from '~/types' +import { PipelineTab } from '~/types' import { AppsManagement } from './AppsManagement' import { Destinations } from './Destinations' import { NewButton } from './NewButton' +import { PIPELINE_TAB_TO_APP_KIND } from './PipelineApp' import { humanFriendlyTabName, pipelineLogic } from './pipelineLogic' import { Transformations } from './Transformations' export function Pipeline(): JSX.Element { const { currentTab } = useValues(pipelineLogic) - const tabToContent: Record = { - [PipelineTabs.Filters]:
Coming soon
, - [PipelineTabs.Transformations]: , - [PipelineTabs.Destinations]: , - [PipelineTabs.AppsManagement]: , + const tabToContent: Record = { + [PipelineTab.Filters]:
Coming soon
, + [PipelineTab.Transformations]: , + [PipelineTab.Destinations]: , + [PipelineTab.AppsManagement]: , } + const maybeKind = PIPELINE_TAB_TO_APP_KIND[currentTab] + return (
} + buttons={maybeKind ? : undefined} /> router.actions.push(urls.pipeline(tab as PipelineTabs))} - tabs={Object.values(PipelineTabs).map((tab) => ({ + onChange={(tab) => router.actions.push(urls.pipeline(tab as PipelineTab))} + tabs={Object.values(PipelineTab).map((tab) => ({ // TODO: Hide admin management based on `canGloballyManagePlugins` permission label: humanFriendlyTabName(tab), key: tab, diff --git a/frontend/src/scenes/pipeline/PipelineApp.tsx b/frontend/src/scenes/pipeline/PipelineApp.tsx index f049349ca3332..932b48f44ccd7 100644 --- a/frontend/src/scenes/pipeline/PipelineApp.tsx +++ b/frontend/src/scenes/pipeline/PipelineApp.tsx @@ -1,27 +1,39 @@ -import { Spinner } from '@posthog/lemon-ui' import { useValues } from 'kea' -import { router } from 'kea-router' import { NotFound } from 'lib/components/NotFound' import { PageHeader } from 'lib/components/PageHeader' import { FEATURE_FLAGS } from 'lib/constants' -import { LemonTabs } from 'lib/lemon-ui/LemonTabs/LemonTabs' +import { LemonTab, LemonTabs } from 'lib/lemon-ui/LemonTabs/LemonTabs' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { capitalizeFirstLetter } from 'lib/utils' import { PipelineAppLogs } from 'scenes/pipeline/PipelineAppLogs' import { SceneExport } from 'scenes/sceneTypes' import { urls } from 'scenes/urls' -import { PipelineAppTabs, PipelineTabs } from '~/types' +import { PipelineAppKind, PipelineAppTab, PipelineTab } from '~/types' import { AppMetrics } from './AppMetrics' import { PipelineAppConfiguration } from './PipelineAppConfiguration' import { pipelineAppLogic, PipelineAppLogicProps } from './pipelineAppLogic' -const paramsToProps = ({ params: { kind, id } }: { params: { kind?: string; id?: string } }): PipelineAppLogicProps => { +export const PIPELINE_TAB_TO_APP_KIND: Partial> = { + [PipelineTab.Filters]: PipelineAppKind.Filter, + [PipelineTab.Transformations]: PipelineAppKind.Transformation, + [PipelineTab.Destinations]: PipelineAppKind.Destination, +} + +const paramsToProps = ({ + params: { kindTab, id }, +}: { + params: { kindTab?: string; id?: string } +}): PipelineAppLogicProps => { const numericId = id && /^\d+$/.test(id) ? parseInt(id) : undefined + if (!kindTab || !id) { + throw new Error('Loaded the PipelineApp without either `kindTab` or `id` passed in') + } + return { - kind: (kind as PipelineTabs) || PipelineTabs.Destinations, - id: (numericId && !isNaN(numericId) ? numericId : id) || 'missing', + kind: PIPELINE_TAB_TO_APP_KIND[kindTab] || null, + id: numericId && !isNaN(numericId) ? numericId : id, } } @@ -31,25 +43,28 @@ export const scene: SceneExport = { paramsToProps, } -export function PipelineApp(params: { kind?: string; id?: string } = {}): JSX.Element { +export function PipelineApp(params: { kindTab?: string; id?: string } = {}): JSX.Element { const { kind, id } = paramsToProps({ params }) + + const { currentTab, loading, maybePlugin } = useValues(pipelineAppLogic) const { featureFlags } = useValues(featureFlagLogic) + if (!featureFlags[FEATURE_FLAGS.PIPELINE_UI]) { return

Pipeline 3000 not available yet

} - if (!Object.values(PipelineTabs).includes(kind)) { - return + + if (!kind) { + return } - const { currentTab } = useValues(pipelineAppLogic) - if (!id) { - return + if (!loading && !maybePlugin) { + return } - const tabToContent: Record = { - [PipelineAppTabs.Configuration]: , - [PipelineAppTabs.Metrics]: , - [PipelineAppTabs.Logs]: , + const tabToContent: Record = { + [PipelineAppTab.Configuration]: , + [PipelineAppTab.Metrics]: , + [PipelineAppTab.Logs]: , } return ( @@ -57,12 +72,15 @@ export function PipelineApp(params: { kind?: string; id?: string } = {}): JSX.El router.actions.push(urls.pipelineApp(kind, id, tab as PipelineAppTabs))} - tabs={Object.values(PipelineAppTabs).map((tab) => ({ - label: capitalizeFirstLetter(tab), - key: tab, - content: tabToContent[tab], - }))} + tabs={Object.values(PipelineAppTab).map( + (tab) => + ({ + label: capitalizeFirstLetter(tab), + key: tab, + content: tabToContent[tab], + link: params.kindTab ? urls.pipelineApp(kind, id, tab as PipelineAppTab) : undefined, + } as LemonTab) + )} />
) diff --git a/frontend/src/scenes/pipeline/PipelineAppConfiguration.tsx b/frontend/src/scenes/pipeline/PipelineAppConfiguration.tsx index e68dad87324ca..830390ee2fc6f 100644 --- a/frontend/src/scenes/pipeline/PipelineAppConfiguration.tsx +++ b/frontend/src/scenes/pipeline/PipelineAppConfiguration.tsx @@ -17,9 +17,9 @@ import { PluginField } from 'scenes/plugins/edit/PluginField' import { pipelineAppLogic } from './pipelineAppLogic' export function PipelineAppConfiguration(): JSX.Element { - const { appType } = useValues(pipelineAppLogic) + const { appBackend } = useValues(pipelineAppLogic) - if (appType === 'webhook') { + if (appBackend === 'plugin') { return ( @@ -31,7 +31,7 @@ export function PipelineAppConfiguration(): JSX.Element { } function WebhookAppConfiguration(): JSX.Element { - const { maybePlugin, maybePluginConfig, configuration } = useValues(pipelineAppLogic) + const { maybePlugin, maybePluginConfig, configuration, kind } = useValues(pipelineAppLogic) const { resetConfiguration, setConfigurationValues } = useActions(pipelineAppLogic) const [invisibleFields, setInvisibleFields] = useState([]) @@ -62,7 +62,7 @@ function WebhookAppConfiguration(): JSX.Element { // This will never show up when we realize that the plugin doesn't exist, since then the whole scene is NotFound return (
- {Array(3) + {Array(2) .fill(null) .map((_, index) => (
@@ -74,7 +74,13 @@ function WebhookAppConfiguration(): JSX.Element { ) } - const fields = getConfigSchemaArray(maybePlugin.config_schema).map((fieldConfig, index) => ( + const configSchemaArray = getConfigSchemaArray(maybePlugin.config_schema) + + if (configSchemaArray.length === 0) { + return

This {kind} isn't configurable.

+ } + + const fields = configSchemaArray.map((fieldConfig, index) => ( {fieldConfig.key && fieldConfig.type && diff --git a/frontend/src/scenes/pipeline/PipelineAppLogs.tsx b/frontend/src/scenes/pipeline/PipelineAppLogs.tsx index 5a4094b38eb0c..a8149694ae204 100644 --- a/frontend/src/scenes/pipeline/PipelineAppLogs.tsx +++ b/frontend/src/scenes/pipeline/PipelineAppLogs.tsx @@ -3,9 +3,10 @@ import { useActions, useValues } from 'kea' import { LOGS_PORTION_LIMIT } from 'lib/constants' import { pluralize } from 'lib/utils' -import { PipelineAppLogLevel, pipelineAppLogsLogic, PipelineAppLogsProps } from './pipelineAppLogsLogic' +import { PipelineAppLogicProps } from './pipelineAppLogic' +import { PipelineAppLogLevel, pipelineAppLogsLogic } from './pipelineAppLogsLogic' -export function PipelineAppLogs({ id, kind }: PipelineAppLogsProps): JSX.Element { +export function PipelineAppLogs({ id, kind }: PipelineAppLogicProps): JSX.Element { const logic = pipelineAppLogsLogic({ id, kind }) const { logs, logsLoading, backgroundLogs, columns, isThereMoreToLoad, selectedLogLevels } = useValues(logic) diff --git a/frontend/src/scenes/pipeline/Transformations.tsx b/frontend/src/scenes/pipeline/Transformations.tsx index d171d640ac6f6..ce1cdcc0b5eec 100644 --- a/frontend/src/scenes/pipeline/Transformations.tsx +++ b/frontend/src/scenes/pipeline/Transformations.tsx @@ -24,7 +24,13 @@ import { deleteWithUndo } from 'lib/utils/deleteWithUndo' import { PluginImage } from 'scenes/plugins/plugin/PluginImage' import { urls } from 'scenes/urls' -import { PipelineAppTabs, PipelineTabs, PluginConfigTypeNew, PluginConfigWithPluginInfoNew, ProductKey } from '~/types' +import { + PipelineAppKind, + PipelineAppTab, + PluginConfigTypeNew, + PluginConfigWithPluginInfoNew, + ProductKey, +} from '~/types' import { NewButton } from './NewButton' import { pipelineTransformationsLogic } from './transformationsLogic' @@ -56,7 +62,7 @@ export function Transformations(): JSX.Element { productKey={ProductKey.PIPELINE_TRANSFORMATIONS} description="Pipeline transformations allow you to enrich your data with additional information, such as geolocation." docsURL="https://posthog.com/docs/cdp" - actionElementOverride={} + actionElementOverride={} isEmpty={true} /> )} @@ -109,9 +115,9 @@ export function Transformations(): JSX.Element { {pluginConfig.name} @@ -191,9 +197,9 @@ export function Transformations(): JSX.Element { )} ([ (s) => [s.pluginConfigs, s.plugins, s.batchExportConfigs], (pluginConfigs, plugins, batchExportConfigs): DestinationType[] => { const appDests = Object.values(pluginConfigs).map((pluginConfig) => ({ - type: DestinationTypeKind.Webhook, + backend: PipelineAppBackend.Plugin, frequency: 'realtime', id: pluginConfig.id, name: pluginConfig.name, description: pluginConfig.description, enabled: pluginConfig.enabled, config_url: urls.pipelineApp( - PipelineTabs.Destinations, + PipelineAppKind.Destination, pluginConfig.id, - PipelineAppTabs.Configuration + PipelineAppTab.Configuration ), - metrics_url: urls.pipelineApp(PipelineTabs.Destinations, pluginConfig.id, PipelineAppTabs.Metrics), - logs_url: urls.pipelineApp(PipelineTabs.Destinations, pluginConfig.id, PipelineAppTabs.Logs), + metrics_url: urls.pipelineApp(PipelineAppKind.Destination, pluginConfig.id, PipelineAppTab.Metrics), + logs_url: urls.pipelineApp(PipelineAppKind.Destination, pluginConfig.id, PipelineAppTab.Logs), app_source_code_url: '', plugin: plugins[pluginConfig.plugin], success_rates: { @@ -196,19 +196,19 @@ export const pipelineDestinationsLogic = kea([ updated_at: pluginConfig.updated_at, })) const batchDests = Object.values(batchExportConfigs).map((batchExport) => ({ - type: DestinationTypeKind.BatchExport, + backend: PipelineAppBackend.BatchExport, frequency: batchExport.interval, id: batchExport.id, name: batchExport.name, description: `${batchExport.destination.type} batch export`, // TODO: add to backend enabled: !batchExport.paused, config_url: urls.pipelineApp( - PipelineTabs.Destinations, + PipelineAppKind.Destination, batchExport.id, - PipelineAppTabs.Configuration + PipelineAppTab.Configuration ), - metrics_url: urls.pipelineApp(PipelineTabs.Destinations, batchExport.id, PipelineAppTabs.Metrics), - logs_url: urls.pipelineApp(PipelineTabs.Destinations, batchExport.id, PipelineAppTabs.Logs), + metrics_url: urls.pipelineApp(PipelineAppKind.Destination, batchExport.id, PipelineAppTab.Metrics), + logs_url: urls.pipelineApp(PipelineAppKind.Destination, batchExport.id, PipelineAppTab.Logs), success_rates: { '24h': [5, 17], '7d': [12, 100043], @@ -235,7 +235,7 @@ export const pipelineDestinationsLogic = kea([ lemonToast.error("You don't have permission to enable or disable destinations") return } - if (destination.type === 'webhook') { + if (destination.backend === 'plugin') { actions.toggleEnabledWebhook({ destination: destination, enabled: enabled }) } else { actions.toggleEnabledBatchExport({ destination: destination, enabled: enabled }) diff --git a/frontend/src/scenes/pipeline/pipelineAppLogic.tsx b/frontend/src/scenes/pipeline/pipelineAppLogic.tsx index f117a412d5ebd..fa635fb146f8e 100644 --- a/frontend/src/scenes/pipeline/pipelineAppLogic.tsx +++ b/frontend/src/scenes/pipeline/pipelineAppLogic.tsx @@ -5,29 +5,30 @@ import { capitalizeFirstLetter } from 'lib/utils' import { Scene } from 'scenes/sceneTypes' import { urls } from 'scenes/urls' -import { Breadcrumb, PipelineAppTabs, PipelineTabs, PluginConfigTypeNew, PluginType } from '~/types' +import { Breadcrumb, PipelineAppKind, PipelineAppTab, PluginConfigTypeNew, PluginType } from '~/types' -import { DestinationTypeKind, pipelineDestinationsLogic } from './destinationsLogic' +import { PipelineAppBackend, pipelineDestinationsLogic } from './destinationsLogic' import type { pipelineAppLogicType } from './pipelineAppLogicType' export interface PipelineAppLogicProps { id: number | string - kind: PipelineTabs + /** Might be null if a non-existent kind is set in th URL. */ + kind: PipelineAppKind | null } export const pipelineAppLogic = kea([ props({} as PipelineAppLogicProps), - key(({ id }) => id), + key(({ kind, id }) => `${kind}:${id}`), path((id) => ['scenes', 'pipeline', 'pipelineAppLogic', id]), connect(() => ({ - values: [pipelineDestinationsLogic, ['plugins', 'pluginConfigs']], + values: [pipelineDestinationsLogic, ['plugins', 'pluginsLoading', 'pluginConfigs', 'pluginConfigsLoading']], })), actions({ - setCurrentTab: (tab: PipelineAppTabs = PipelineAppTabs.Configuration) => ({ tab }), + setCurrentTab: (tab: PipelineAppTab = PipelineAppTab.Configuration) => ({ tab }), }), reducers({ currentTab: [ - PipelineAppTabs.Configuration as PipelineAppTabs, + PipelineAppTab.Configuration as PipelineAppTab, { setCurrentTab: (_, { tab }) => tab, }, @@ -43,25 +44,34 @@ export const pipelineAppLogic = kea([ path: urls.pipeline(), }, { - key: kind, - name: capitalizeFirstLetter(kind), - path: urls.pipeline(kind), + key: kind || 'unknown', + name: kind ? capitalizeFirstLetter(kind) : 'Unknown', + path: urls.pipeline(), }, { key: [Scene.PipelineApp, id], - name: maybePluginConfig?.name || 'Unknown', + name: maybePluginConfig ? maybePluginConfig.name || 'Unnamed' : 'Unknown', }, ], ], - appType: [ + appBackend: [ (_, p) => [p.id], - (id): DestinationTypeKind => - typeof id === 'string' ? DestinationTypeKind.BatchExport : DestinationTypeKind.Webhook, + (id): PipelineAppBackend => + typeof id === 'string' ? PipelineAppBackend.BatchExport : PipelineAppBackend.Plugin, + ], + loading: [ + (s) => [s.appBackend, s.pluginConfigsLoading, s.pluginsLoading], + (appBackend, pluginConfigsLoading, pluginsLoading): boolean => { + if (appBackend === PipelineAppBackend.BatchExport) { + return false // TODO: Support loading state for batch exports + } + return pluginConfigsLoading || pluginsLoading + }, ], maybePluginConfig: [ - (s, p) => [s.pluginConfigs, s.appType, p.id], - (pluginConfigs, appType, maybePluginConfigId): PluginConfigTypeNew | null => { - if (appType !== 'webhook') { + (s, p) => [s.pluginConfigs, s.appBackend, p.id], + (pluginConfigs, appBackend, maybePluginConfigId): PluginConfigTypeNew | null => { + if (appBackend !== 'plugin') { return null } return pluginConfigs[maybePluginConfigId] || null @@ -76,6 +86,7 @@ export const pipelineAppLogic = kea([ return plugins[maybePluginConfig.plugin] || null }, ], + kind: [(_, p) => [p.kind], (kind) => kind], })), forms({ configuration: { @@ -87,13 +98,13 @@ export const pipelineAppLogic = kea([ }), actionToUrl(({ values, props }) => { return { - setCurrentTab: () => [urls.pipelineApp(props.kind, props.id, values.currentTab)], + setCurrentTab: () => [urls.pipelineApp(props.kind as PipelineAppKind, props.id, values.currentTab)], } }), urlToAction(({ actions, values }) => ({ - '/pipeline/:kind/:id/:tab': ({ tab }) => { - if (tab !== values.currentTab && Object.values(PipelineAppTabs).includes(tab as PipelineAppTabs)) { - actions.setCurrentTab(tab as PipelineAppTabs) + '/pipeline/:kindTab/:id/:appTab': ({ appTab }) => { + if (appTab !== values.currentTab && Object.values(PipelineAppTab).includes(appTab as PipelineAppTab)) { + actions.setCurrentTab(appTab as PipelineAppTab) } }, })), diff --git a/frontend/src/scenes/pipeline/pipelineAppLogsLogic.tsx b/frontend/src/scenes/pipeline/pipelineAppLogsLogic.tsx index 7f83bd2680a2d..78d3a28fad30f 100644 --- a/frontend/src/scenes/pipeline/pipelineAppLogsLogic.tsx +++ b/frontend/src/scenes/pipeline/pipelineAppLogsLogic.tsx @@ -3,11 +3,11 @@ import { actions, connect, events, kea, key, listeners, path, props, reducers, s import { loaders } from 'kea-loaders' import { LOGS_PORTION_LIMIT } from 'lib/constants' import { dayjs } from 'lib/dayjs' -import { DestinationTypeKind } from 'scenes/pipeline/destinationsLogic' -import { pipelineAppLogic } from 'scenes/pipeline/pipelineAppLogic' +import { PipelineAppBackend } from 'scenes/pipeline/destinationsLogic' +import { pipelineAppLogic, PipelineAppLogicProps } from 'scenes/pipeline/pipelineAppLogic' import api from '~/lib/api' -import { BatchExportLogEntry, PipelineTabs, PluginLogEntry } from '~/types' +import { BatchExportLogEntry, PluginLogEntry } from '~/types' import { teamLogic } from '../teamLogic' import type { pipelineAppLogsLogicType } from './pipelineAppLogsLogicType' @@ -23,17 +23,12 @@ export enum PipelineAppLogLevel { Error = 'ERROR', } -export interface PipelineAppLogsProps { - id: number | string - kind: PipelineTabs // This needs to be props passed for connecting to pipelineAppLogic -} - export const pipelineAppLogsLogic = kea([ - props({} as PipelineAppLogsProps), - key(({ id }: PipelineAppLogsProps) => id), + props({} as PipelineAppLogicProps), + key(({ id }: PipelineAppLogicProps) => id), path((key) => ['scenes', 'pipeline', 'pipelineAppLogsLogic', key]), - connect((props: PipelineAppLogsProps) => ({ - values: [teamLogic, ['currentTeamId'], pipelineAppLogic(props), ['appType']], + connect((props: PipelineAppLogicProps) => ({ + values: [teamLogic(), ['currentTeamId'], pipelineAppLogic(props), ['appBackend']], })), actions({ setSelectedLogLevels: (levels: PipelineAppLogLevel[]) => ({ @@ -48,7 +43,7 @@ export const pipelineAppLogsLogic = kea([ __default: [] as PluginLogEntry[] | BatchExportLogEntry[], loadLogs: async () => { let results: LogEntry[] - if (values.appType === DestinationTypeKind.BatchExport) { + if (values.appBackend === PipelineAppBackend.BatchExport) { results = await api.batchExportLogs.search( id as string, values.currentTeamId, @@ -72,7 +67,7 @@ export const pipelineAppLogsLogic = kea([ }, loadMoreLogs: async () => { let results: LogEntry[] - if (values.appType === DestinationTypeKind.BatchExport) { + if (values.appBackend === PipelineAppBackend.BatchExport) { results = await api.batchExportLogs.search( id as string, values.currentTeamId, @@ -111,7 +106,7 @@ export const pipelineAppLogsLogic = kea([ } let results: LogEntry[] - if (values.appType === DestinationTypeKind.BatchExport) { + if (values.appBackend === PipelineAppBackend.BatchExport) { results = await api.batchExportLogs.search( id as string, values.currentTeamId, @@ -188,8 +183,8 @@ export const pipelineAppLogsLogic = kea([ }, ], columns: [ - (s) => [s.appType], - (appType): LemonTableColumns => { + (s) => [s.appBackend], + (appBackend): LemonTableColumns => { return [ { title: 'Timestamp', @@ -198,15 +193,15 @@ export const pipelineAppLogsLogic = kea([ render: (timestamp: string) => dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss.SSS UTC'), }, { - title: appType === DestinationTypeKind.BatchExport ? 'Run Id' : 'Source', - dataIndex: appType === DestinationTypeKind.BatchExport ? 'run_id' : 'source', - key: appType === DestinationTypeKind.BatchExport ? 'run_id' : 'source', + title: appBackend === PipelineAppBackend.BatchExport ? 'Run Id' : 'Source', + dataIndex: appBackend === PipelineAppBackend.BatchExport ? 'run_id' : 'source', + key: appBackend === PipelineAppBackend.BatchExport ? 'run_id' : 'source', }, { title: 'Level', - key: appType === DestinationTypeKind.BatchExport ? 'level' : 'type', - dataIndex: appType === DestinationTypeKind.BatchExport ? 'level' : 'type', - render: appType === DestinationTypeKind.BatchExport ? LogLevelDisplay : LogTypeDisplay, + key: appBackend === PipelineAppBackend.BatchExport ? 'level' : 'type', + dataIndex: appBackend === PipelineAppBackend.BatchExport ? 'level' : 'type', + render: appBackend === PipelineAppBackend.BatchExport ? LogLevelDisplay : LogTypeDisplay, }, { title: 'Message', diff --git a/frontend/src/scenes/pipeline/pipelineLogic.tsx b/frontend/src/scenes/pipeline/pipelineLogic.tsx index 28e5124c44179..3fbb4506afe6e 100644 --- a/frontend/src/scenes/pipeline/pipelineLogic.tsx +++ b/frontend/src/scenes/pipeline/pipelineLogic.tsx @@ -3,32 +3,19 @@ import { actionToUrl, urlToAction } from 'kea-router' import { Scene } from 'scenes/sceneTypes' import { urls } from 'scenes/urls' -import { Breadcrumb, PipelineTabs } from '~/types' +import { Breadcrumb, PipelineTab } from '~/types' import type { pipelineLogicType } from './pipelineLogicType' -export const singularName = (tab: PipelineTabs): string => { +export const humanFriendlyTabName = (tab: PipelineTab): string => { switch (tab) { - case PipelineTabs.Filters: - return 'filter' - case PipelineTabs.Transformations: - return 'transformation' - case PipelineTabs.Destinations: - return 'destination' - default: - return '' - } -} - -export const humanFriendlyTabName = (tab: PipelineTabs): string => { - switch (tab) { - case PipelineTabs.Filters: + case PipelineTab.Filters: return 'Filters' - case PipelineTabs.Transformations: + case PipelineTab.Transformations: return 'Transformations' - case PipelineTabs.Destinations: + case PipelineTab.Destinations: return 'Destinations' - case PipelineTabs.AppsManagement: + case PipelineTab.AppsManagement: return 'Apps management' } } @@ -36,11 +23,11 @@ export const humanFriendlyTabName = (tab: PipelineTabs): string => { export const pipelineLogic = kea([ path(['scenes', 'pipeline', 'pipelineLogic']), actions({ - setCurrentTab: (tab: PipelineTabs = PipelineTabs.Destinations) => ({ tab }), + setCurrentTab: (tab: PipelineTab = PipelineTab.Destinations) => ({ tab }), }), reducers({ currentTab: [ - PipelineTabs.Destinations as PipelineTabs, + PipelineTab.Destinations as PipelineTab, { setCurrentTab: (_, { tab }) => tab, }, @@ -68,7 +55,7 @@ export const pipelineLogic = kea([ urlToAction(({ actions, values }) => ({ '/pipeline/:tab': ({ tab }) => { if (tab !== values.currentTab) { - actions.setCurrentTab(tab as PipelineTabs) + actions.setCurrentTab(tab as PipelineTab) } }, })), diff --git a/frontend/src/scenes/scenes.ts b/frontend/src/scenes/scenes.ts index fee1e2083f075..5e7de9b544a04 100644 --- a/frontend/src/scenes/scenes.ts +++ b/frontend/src/scenes/scenes.ts @@ -477,7 +477,7 @@ export const routes: Record = { [urls.personByUUID('*', false)]: Scene.Person, [urls.persons()]: Scene.PersonsManagement, [urls.pipeline(':tab')]: Scene.Pipeline, - [urls.pipelineApp(':kind', ':id', ':tab')]: Scene.PipelineApp, + [urls.pipelineApp(':kindTab', ':id', ':appTab')]: Scene.PipelineApp, [urls.groups(':groupTypeIndex')]: Scene.PersonsManagement, [urls.group(':groupTypeIndex', ':groupKey', false)]: Scene.Group, [urls.group(':groupTypeIndex', ':groupKey', false, ':groupTab')]: Scene.Group, diff --git a/frontend/src/scenes/urls.ts b/frontend/src/scenes/urls.ts index 94bae8697e213..ee99664a7e55a 100644 --- a/frontend/src/scenes/urls.ts +++ b/frontend/src/scenes/urls.ts @@ -10,8 +10,9 @@ import { DashboardType, FilterType, InsightShortId, - PipelineAppTabs, - PipelineTabs, + PipelineAppKind, + PipelineAppTab, + PipelineTab, ReplayTabs, } from '~/types' @@ -101,10 +102,14 @@ export const urls = { encode ? `/persons/${encodeURIComponent(uuid)}` : `/persons/${uuid}`, persons: (): string => '/persons', // TODO: Default to the landing page, once it's ready - pipeline: (tab?: PipelineTabs | ':tab'): string => `/pipeline/${tab ? tab : PipelineTabs.Destinations}`, + pipeline: (tab?: PipelineTab | ':tab'): string => `/pipeline/${tab ? tab : PipelineTab.Destinations}`, /** @param id 'new' for new, uuid for batch exports and numbers for plugins */ - pipelineApp: (kind: PipelineTabs | ':kind', id: string | number, tab?: PipelineAppTabs | ':tab'): string => - `/pipeline/${kind}/${id}/${tab ? tab : PipelineAppTabs.Configuration}`, + pipelineApp: ( + kind: PipelineAppKind | ':kindTab', + id: string | number, + appTab?: PipelineAppTab | ':appTab' + ): string => + `/pipeline/${!kind.startsWith(':') ? `${kind}s` : kind}/${id}/${appTab ?? PipelineAppTab.Configuration}`, groups: (groupTypeIndex: string | number): string => `/groups/${groupTypeIndex}`, // :TRICKY: Note that groupKey is provided by user. We need to override urlPatternOptions for kea-router. group: (groupTypeIndex: string | number, groupKey: string, encode: boolean = true, tab?: string | null): string => diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 87044f2153657..2062f3278a4b0 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -524,14 +524,20 @@ export enum ExperimentsTabs { Archived = 'archived', } -export enum PipelineTabs { +export enum PipelineTab { Filters = 'filters', Transformations = 'transformations', Destinations = 'destinations', AppsManagement = 'apps-management', } -export enum PipelineAppTabs { +export enum PipelineAppKind { + Filter = 'filter', + Transformation = 'transformation', + Destination = 'destination', +} + +export enum PipelineAppTab { Configuration = 'configuration', Logs = 'logs', Metrics = 'metrics',