diff --git a/frontend/__snapshots__/lemon-ui-icons--shelf-p.png b/frontend/__snapshots__/lemon-ui-icons--shelf-p.png
index ed1853f8297e6..4c18318a5a42a 100644
Binary files a/frontend/__snapshots__/lemon-ui-icons--shelf-p.png and b/frontend/__snapshots__/lemon-ui-icons--shelf-p.png differ
diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page.png
new file mode 100644
index 0000000000000..f71305149b638
Binary files /dev/null and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page.png differ
diff --git a/frontend/src/layout/navigation/SideBar/SideBar.tsx b/frontend/src/layout/navigation/SideBar/SideBar.tsx
index c37c2f0284631..b7e4b38ad165c 100644
--- a/frontend/src/layout/navigation/SideBar/SideBar.tsx
+++ b/frontend/src/layout/navigation/SideBar/SideBar.tsx
@@ -18,6 +18,7 @@ import {
IconOpenInApp,
IconPerson,
IconPinOutline,
+ IconPipeline,
IconPlus,
IconRecording,
IconRocketLaunch,
@@ -226,6 +227,9 @@ function Pages(): JSX.Element {
to={urls.persons()}
title={`Persons${showGroupsOptions ? ' & Groups' : ''}`}
/>
+
+ } identifier={Scene.Pipeline} to={urls.pipeline()} />
+
}
diff --git a/frontend/src/lib/constants.tsx b/frontend/src/lib/constants.tsx
index 6343b341614ef..9cfcf1ba136c7 100644
--- a/frontend/src/lib/constants.tsx
+++ b/frontend/src/lib/constants.tsx
@@ -165,6 +165,7 @@ export const FEATURE_FLAGS = {
SURVEYS_PAYGATES: 'surveys-paygates',
CONSOLE_RECORDING_SEARCH: 'console-recording-search', // owner: #team-monitoring
PERSONS_HOGQL_QUERY: 'persons-hogql-query', // owner: @mariusandra
+ PIPELINE_UI: 'pipeline-ui', // owner: #team-pipeline
NOTEBOOK_CANVASES: 'notebook-canvases', // owner: #team-monitoring
SESSION_RECORDING_SAMPLING: 'session-recording-sampling', // owner: #team-monitoring
PERSON_FEED_CANVAS: 'person-feed-canvas', // owner: #project-canvas
diff --git a/frontend/src/lib/lemon-ui/icons/icons.tsx b/frontend/src/lib/lemon-ui/icons/icons.tsx
index 8d5048e4aad10..429bd17c3c6eb 100644
--- a/frontend/src/lib/lemon-ui/icons/icons.tsx
+++ b/frontend/src/lib/lemon-ui/icons/icons.tsx
@@ -2383,6 +2383,17 @@ export function IconDatabase(props: LemonIconProps): JSX.Element {
)
}
+export function IconPipeline(props: LemonIconProps): JSX.Element {
+ return (
+
+
+
+ )
+}
+
export function IconDragHandle(props: LemonIconProps): JSX.Element {
return (
diff --git a/frontend/src/scenes/appScenes.ts b/frontend/src/scenes/appScenes.ts
index 494f7668f4bfe..7955d08dc045a 100644
--- a/frontend/src/scenes/appScenes.ts
+++ b/frontend/src/scenes/appScenes.ts
@@ -28,6 +28,7 @@ export const appScenes: Record any> = {
[Scene.ReplayPlaylist]: () => import('./session-recordings/playlist/SessionRecordingsPlaylistScene'),
[Scene.Person]: () => import('./persons/PersonScene'),
[Scene.Persons]: () => import('./persons/PersonsScene'),
+ [Scene.Pipeline]: () => import('./pipeline/Pipeline'),
[Scene.Groups]: () => import('./groups/Groups'),
[Scene.Group]: () => import('./groups/Group'),
[Scene.Action]: () => import('./actions/Action'),
diff --git a/frontend/src/scenes/pipeline/Pipeline.stories.tsx b/frontend/src/scenes/pipeline/Pipeline.stories.tsx
new file mode 100644
index 0000000000000..dd0b1641b9e72
--- /dev/null
+++ b/frontend/src/scenes/pipeline/Pipeline.stories.tsx
@@ -0,0 +1,18 @@
+import { useEffect } from 'react'
+import { Meta } from '@storybook/react'
+import { App } from 'scenes/App'
+import { router } from 'kea-router'
+import { urls } from 'scenes/urls'
+
+export default {
+ title: 'Scenes-App/Pipeline',
+ decorators: [],
+ parameters: { layout: 'fullscreen', options: { showPanel: false }, viewMode: 'story' }, // scene mode
+} as Meta
+
+export function PipelineLandingPage(): JSX.Element {
+ useEffect(() => {
+ router.actions.push(urls.pipeline())
+ }, [])
+ return
+}
diff --git a/frontend/src/scenes/pipeline/Pipeline.tsx b/frontend/src/scenes/pipeline/Pipeline.tsx
new file mode 100644
index 0000000000000..42ee27cc7c66b
--- /dev/null
+++ b/frontend/src/scenes/pipeline/Pipeline.tsx
@@ -0,0 +1,19 @@
+import { SceneExport } from 'scenes/sceneTypes'
+import { pipelineLogic } from './pipelineLogic'
+import { PageHeader } from 'lib/components/PageHeader'
+
+export function Pipeline(): JSX.Element {
+ return (
+
+ )
+}
+
+export const scene: SceneExport = {
+ component: Pipeline,
+ logic: pipelineLogic,
+}
+
+// TODO: error from import ./pipeline/PipelineScene
+// TODO: update https://storybook.posthog.net/?path=/docs/how-to-build-a-scene--docs <- about kea stuff to exclude and have run pnpm ... for type creation
diff --git a/frontend/src/scenes/pipeline/pipelineLogic.tsx b/frontend/src/scenes/pipeline/pipelineLogic.tsx
new file mode 100644
index 0000000000000..9d74a469558e0
--- /dev/null
+++ b/frontend/src/scenes/pipeline/pipelineLogic.tsx
@@ -0,0 +1,6 @@
+import { kea } from 'kea'
+import type { pipelineLogicType } from './pipelineLogicType'
+
+export const pipelineLogic = kea({
+ path: ['scenes', 'pipeline', 'pipelineLogic'],
+})
diff --git a/frontend/src/scenes/sceneTypes.ts b/frontend/src/scenes/sceneTypes.ts
index 0e35998cd8887..3ff7072ca8404 100644
--- a/frontend/src/scenes/sceneTypes.ts
+++ b/frontend/src/scenes/sceneTypes.ts
@@ -27,6 +27,7 @@ export enum Scene {
ReplayPlaylist = 'ReplayPlaylist',
Person = 'Person',
Persons = 'Persons',
+ Pipeline = 'Pipeline',
Groups = 'Groups',
Group = 'Group',
Action = 'Action',
diff --git a/frontend/src/scenes/scenes.ts b/frontend/src/scenes/scenes.ts
index d8f43290d737f..311a72f6f5c34 100644
--- a/frontend/src/scenes/scenes.ts
+++ b/frontend/src/scenes/scenes.ts
@@ -140,6 +140,10 @@ export const sceneConfigurations: Partial> = {
projectBased: true,
name: 'Persons & Groups',
},
+ [Scene.Pipeline]: {
+ projectBased: true,
+ name: 'Pipeline',
+ },
[Scene.Experiments]: {
projectBased: true,
name: 'Experiments',
@@ -432,6 +436,7 @@ export const routes: Record = {
[urls.personByDistinctId('*', false)]: Scene.Person,
[urls.personByUUID('*', false)]: Scene.Person,
[urls.persons()]: Scene.Persons,
+ [urls.pipeline()]: Scene.Pipeline,
[urls.groups(':groupTypeIndex')]: Scene.Groups,
[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 930aa0c14d6a1..9e454a67f9f81 100644
--- a/frontend/src/scenes/urls.ts
+++ b/frontend/src/scenes/urls.ts
@@ -93,6 +93,7 @@ export const urls = {
personByUUID: (uuid: string, encode: boolean = true): string =>
encode ? `/persons/${encodeURIComponent(uuid)}` : `/persons/${uuid}`,
persons: (): string => '/persons',
+ pipeline: (): string => '/pipeline',
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 =>