diff --git a/cypress/e2e/notebooks-creation-and-deletion.cy.ts b/cypress/e2e/notebooks-creation-and-deletion.cy.ts index 6206880118a81..4f73a7676b513 100644 --- a/cypress/e2e/notebooks-creation-and-deletion.cy.ts +++ b/cypress/e2e/notebooks-creation-and-deletion.cy.ts @@ -1,9 +1,9 @@ import { randomString } from '../support/random' function visitNotebooksList(): void { - cy.clickNavMenu('dashboards') - cy.location('pathname').should('include', '/dashboard') - cy.get('h1').should('contain', 'Dashboards & Notebooks') + cy.clickNavMenu('notebooks') + cy.location('pathname').should('include', '/notebooks') + cy.get('h1').should('contain', 'Notebooks') cy.get('li').contains('Notebooks').should('exist').click() } diff --git a/cypress/e2e/notebooks.cy.ts b/cypress/e2e/notebooks.cy.ts index a178b49afdbf6..d3d2945a3f245 100644 --- a/cypress/e2e/notebooks.cy.ts +++ b/cypress/e2e/notebooks.cy.ts @@ -27,12 +27,12 @@ describe('Notebooks', () => { }).as('patchNotebook') }) - cy.clickNavMenu('dashboards') - cy.location('pathname').should('include', '/dashboard') + cy.clickNavMenu('notebooks') + cy.location('pathname').should('include', '/notebooks') }) it('Notebooks are enabled', () => { - cy.get('h1').should('contain', 'Dashboards & Notebooks') + cy.get('h1').should('contain', 'Notebooks') cy.get('li').contains('Notebooks').should('exist').click() }) diff --git a/frontend/__snapshots__/lemon-ui-icons--shelf-j.png b/frontend/__snapshots__/lemon-ui-icons--shelf-j.png index d20b56618c56e..9812781502e35 100644 Binary files a/frontend/__snapshots__/lemon-ui-icons--shelf-j.png and b/frontend/__snapshots__/lemon-ui-icons--shelf-j.png differ diff --git a/frontend/__snapshots__/lemon-ui-icons--shelf-n.png b/frontend/__snapshots__/lemon-ui-icons--shelf-n.png index ee7f32ed29cef..9a82995334fba 100644 Binary files a/frontend/__snapshots__/lemon-ui-icons--shelf-n.png and b/frontend/__snapshots__/lemon-ui-icons--shelf-n.png differ diff --git a/frontend/__snapshots__/scenes-app-experiments--experiments-list-pay-gate.png b/frontend/__snapshots__/scenes-app-experiments--experiments-list-pay-gate.png index bafae37113a1b..7e96b5125fdab 100644 Binary files a/frontend/__snapshots__/scenes-app-experiments--experiments-list-pay-gate.png and b/frontend/__snapshots__/scenes-app-experiments--experiments-list-pay-gate.png differ diff --git a/frontend/__snapshots__/scenes-app-experiments--experiments-list.png b/frontend/__snapshots__/scenes-app-experiments--experiments-list.png index 28a9ce47379e4..5a3d3dd285231 100644 Binary files a/frontend/__snapshots__/scenes-app-experiments--experiments-list.png and b/frontend/__snapshots__/scenes-app-experiments--experiments-list.png differ diff --git a/frontend/__snapshots__/scenes-app-feature-flags--feature-flags-list.png b/frontend/__snapshots__/scenes-app-feature-flags--feature-flags-list.png index c0e66d04fb20d..a30dc1ed64cb0 100644 Binary files a/frontend/__snapshots__/scenes-app-feature-flags--feature-flags-list.png and b/frontend/__snapshots__/scenes-app-feature-flags--feature-flags-list.png differ diff --git a/frontend/__snapshots__/scenes-app-insights--lifecycle.png b/frontend/__snapshots__/scenes-app-insights--lifecycle.png index 2ab70086dee61..0f5f19aac9013 100644 Binary files a/frontend/__snapshots__/scenes-app-insights--lifecycle.png and b/frontend/__snapshots__/scenes-app-insights--lifecycle.png differ diff --git a/frontend/__snapshots__/scenes-app-insights--stickiness.png b/frontend/__snapshots__/scenes-app-insights--stickiness.png index 885c792dbff15..1f58fbc9b518b 100644 Binary files a/frontend/__snapshots__/scenes-app-insights--stickiness.png and b/frontend/__snapshots__/scenes-app-insights--stickiness.png differ diff --git a/frontend/__snapshots__/scenes-app-insights--trends-number.png b/frontend/__snapshots__/scenes-app-insights--trends-number.png index c4b27d87904c5..5e11ddb074351 100644 Binary files a/frontend/__snapshots__/scenes-app-insights--trends-number.png and b/frontend/__snapshots__/scenes-app-insights--trends-number.png differ diff --git a/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown.png b/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown.png index 1d66d872793ef..60eb90e01d46e 100644 Binary files a/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown.png and b/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown.png differ diff --git a/frontend/__snapshots__/scenes-app-insights--trends-table.png b/frontend/__snapshots__/scenes-app-insights--trends-table.png index 83727bad0e64a..1e44c590b7ab1 100644 Binary files a/frontend/__snapshots__/scenes-app-insights--trends-table.png and b/frontend/__snapshots__/scenes-app-insights--trends-table.png differ diff --git a/frontend/__snapshots__/scenes-app-notebooks--headings.png b/frontend/__snapshots__/scenes-app-notebooks--headings.png index 0a118977b5422..eb890f7ef2025 100644 Binary files a/frontend/__snapshots__/scenes-app-notebooks--headings.png and b/frontend/__snapshots__/scenes-app-notebooks--headings.png differ diff --git a/frontend/__snapshots__/scenes-app-notebooks--notebook-not-found.png b/frontend/__snapshots__/scenes-app-notebooks--notebook-not-found.png index da370b037075e..41cd092223d0b 100644 Binary files a/frontend/__snapshots__/scenes-app-notebooks--notebook-not-found.png and b/frontend/__snapshots__/scenes-app-notebooks--notebook-not-found.png differ diff --git a/frontend/__snapshots__/scenes-app-notebooks--notebooks-list.png b/frontend/__snapshots__/scenes-app-notebooks--notebooks-list.png index 1d3a565259700..29840a3cd8ae5 100644 Binary files a/frontend/__snapshots__/scenes-app-notebooks--notebooks-list.png and b/frontend/__snapshots__/scenes-app-notebooks--notebooks-list.png differ diff --git a/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist.png b/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist.png index 326a46e19d3ad..7d63a60ab61a0 100644 Binary files a/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist.png and b/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist.png differ diff --git a/frontend/src/layout/navigation/SideBar/SideBar.tsx b/frontend/src/layout/navigation/SideBar/SideBar.tsx index 1c345e6c652b6..7594457385193 100644 --- a/frontend/src/layout/navigation/SideBar/SideBar.tsx +++ b/frontend/src/layout/navigation/SideBar/SideBar.tsx @@ -14,6 +14,7 @@ import { IconGauge, IconLive, IconMessages, + IconNotebook, IconOpenInApp, IconPerson, IconPinOutline, @@ -38,7 +39,6 @@ import { AvailableFeature } from '~/types' import './SideBar.scss' import { navigationLogic } from '../navigationLogic' import { FEATURE_FLAGS } from 'lib/constants' -import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { groupsModel } from '~/models/groupsModel' import { userLogic } from 'scenes/userLogic' import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic' @@ -52,13 +52,13 @@ import { Spinner } from 'lib/lemon-ui/Spinner/Spinner' import { DebugNotice } from 'lib/components/DebugNotice' import ActivationSidebar from 'lib/components/ActivationSidebar/ActivationSidebar' import { NotebookPopover } from 'scenes/notebooks/Notebook/NotebookPopover' +import { FlaggedFeature } from 'lib/components/FlaggedFeature' function Pages(): JSX.Element { const { currentOrganization } = useValues(organizationLogic) const { hideSideBarMobile, toggleProjectSwitcher, hideProjectSwitcher } = useActions(navigationLogic) const { isProjectSwitcherShown } = useValues(navigationLogic) const { pinnedDashboards } = useValues(dashboardsModel) - const { featureFlags } = useValues(featureFlagLogic) const { showGroupsOptions } = useValues(groupsModel) const { hasAvailableFeature } = useValues(userLogic) const { preflight } = useValues(preflightLogic) @@ -150,6 +150,20 @@ function Pages(): JSX.Element { }, }} /> + + } + identifier={Scene.Notebooks} + to={urls.notebooks()} + sideAction={{ + icon: , + to: urls.notebook('new'), + tooltip: 'New notebook', + identifier: Scene.Notebook, + onClick: hideSideBarMobile, + }} + /> + } identifier={Scene.SavedInsights} @@ -167,6 +181,7 @@ function Pages(): JSX.Element {
Feature Management
} identifier={Scene.FeatureFlags} to={urls.featureFlags()} /> + {(hasAvailableFeature(AvailableFeature.EXPERIMENTATION) || !preflight?.instance_preferences?.disable_paid_fs) && ( } identifier={Scene.Experiments} to={urls.experiments()} /> @@ -186,15 +201,14 @@ function Pages(): JSX.Element { highlight="beta" /> - {featureFlags[FEATURE_FLAGS.WEB_ANALYTICS] && ( + } identifier={Scene.WebAnalytics} to={urls.webAnalytics()} highlight="alpha" /> - )} - +
Data
- {featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE] && ( + } identifier={Scene.DataWarehouse} @@ -222,7 +236,7 @@ function Pages(): JSX.Element { to={urls.dataWarehouse()} highlight="beta" /> - )} + } identifier={Scene.Cohorts} to={urls.cohorts()} /> } identifier={Scene.Annotations} to={urls.annotations()} /> {canViewPlugins(currentOrganization) || Object.keys(frontendApps).length > 0 ? ( @@ -240,9 +254,9 @@ function Pages(): JSX.Element { {Object.keys(frontendApps).length > 0 && } ) : null} - {featureFlags[FEATURE_FLAGS.FEEDBACK_SCENE] && ( + } identifier={Scene.Feedback} to={urls.feedback()} /> - )} +
Configuration
} + icon={} type={visibility === 'visible' ? 'primary' : 'tertiary'} onClick={() => setVisibility(visibility === 'visible' ? 'hidden' : 'visible')} status="primary-alt" diff --git a/frontend/src/lib/lemon-ui/icons/icons.tsx b/frontend/src/lib/lemon-ui/icons/icons.tsx index 3ef6f11d75e1e..b90b81c10bbfa 100644 --- a/frontend/src/lib/lemon-ui/icons/icons.tsx +++ b/frontend/src/lib/lemon-ui/icons/icons.tsx @@ -2383,28 +2383,6 @@ export function IconDatabase(props: LemonIconProps): JSX.Element { ) } -export function IconJournal(props: LemonIconProps): JSX.Element { - return ( - - - - ) -} - -export function IconJournalPlus(props: LemonIconProps): JSX.Element { - return ( - - - - ) -} - export function IconDragHandle(props: LemonIconProps): JSX.Element { return ( @@ -2483,3 +2461,17 @@ export function IconTarget(props: LemonIconProps): JSX.Element { ) } + +export function IconNotebook(props: LemonIconProps): JSX.Element { + return ( + + + + ) +} diff --git a/frontend/src/models/notebooksModel.ts b/frontend/src/models/notebooksModel.ts index 2c7ec1eb9efd4..c70d4a2a674de 100644 --- a/frontend/src/models/notebooksModel.ts +++ b/frontend/src/models/notebooksModel.ts @@ -40,7 +40,11 @@ export const openNotebook = async ( if (popoverLogic?.values.visibility === 'visible') { popoverLogic?.actions.selectNotebook(notebookId, focus) } else { - router.actions.push(urls.notebook(notebookId)) + if (router.values.location.pathname === urls.notebook('new')) { + router.actions.replace(urls.notebook(notebookId)) + } else { + router.actions.push(urls.notebook(notebookId)) + } } const theNotebookLogic = notebookLogic({ shortId: notebookId }) diff --git a/frontend/src/scenes/appScenes.ts b/frontend/src/scenes/appScenes.ts index c72cdcf50a97f..21eb1fa403df5 100644 --- a/frontend/src/scenes/appScenes.ts +++ b/frontend/src/scenes/appScenes.ts @@ -76,6 +76,7 @@ export const appScenes: Record any> = { [Scene.DebugQuery]: () => import('./debug/DebugScene'), [Scene.VerifyEmail]: () => import('./authentication/signup/verify-email/VerifyEmail'), [Scene.Feedback]: () => import('./feedback/Feedback'), + [Scene.Notebooks]: () => import('./notebooks/NotebooksScene'), [Scene.Notebook]: () => import('./notebooks/NotebookScene'), [Scene.Products]: () => import('./products/Products'), [Scene.Onboarding]: () => import('./onboarding/Onboarding'), diff --git a/frontend/src/scenes/dashboard/dashboards/Dashboards.tsx b/frontend/src/scenes/dashboard/dashboards/Dashboards.tsx index d2dad15ee317a..6c70731560a5a 100644 --- a/frontend/src/scenes/dashboard/dashboards/Dashboards.tsx +++ b/frontend/src/scenes/dashboard/dashboards/Dashboards.tsx @@ -13,11 +13,6 @@ import { NoDashboards } from 'scenes/dashboard/dashboards/NoDashboards' import { DashboardsTableContainer } from 'scenes/dashboard/dashboards/DashboardsTable' import { DashboardTemplatesTable } from 'scenes/dashboard/dashboards/templates/DashboardTemplatesTable' import { LemonTab, LemonTabs } from 'lib/lemon-ui/LemonTabs' -import { featureFlagLogic } from 'lib/logic/featureFlagLogic' -import { FEATURE_FLAGS } from 'lib/constants' -import { NotebooksTable } from 'scenes/notebooks/NotebooksTable/NotebooksTable' -import { notebooksModel } from '~/models/notebooksModel' -import { LemonTag } from '@posthog/lemon-ui' export const scene: SceneExport = { component: Dashboards, @@ -30,11 +25,6 @@ export function Dashboards(): JSX.Element { const { dashboards, currentTab, isFiltering } = useValues(dashboardsLogic) const { showNewDashboardModal } = useActions(newDashboardLogic) const { closePrompts } = useActions(inAppPromptLogic) - const { featureFlags } = useValues(featureFlagLogic) - const { notebooksLoading } = useValues(notebooksModel) - const { createNotebook } = useActions(notebooksModel) - - const notebooksEnabled = featureFlags[FEATURE_FLAGS.NOTEBOOKS] const enabledTabs: LemonTab[] = [ { @@ -46,19 +36,6 @@ export function Dashboards(): JSX.Element { label: 'Templates', }, ] - if (notebooksEnabled) { - enabledTabs.splice(1, 0, { - key: DashboardsTab.Notebooks, - label: ( - <> - Notebooks - - Beta - - - ), - }) - } return (
@@ -66,38 +43,23 @@ export function Dashboards(): JSX.Element { { - createNotebook() - }} - type="primary" - disabledReason={notebooksLoading ? 'Loading...' : undefined} - > - New notebook - - ) : ( - { - closePrompts() - showNewDashboardModal() - }} - type="primary" - > - New dashboard - - ) + { + closePrompts() + showNewDashboardModal() + }} + type="primary" + > + New dashboard + } /> setCurrentTab(newKey)} tabs={enabledTabs} /> {currentTab === DashboardsTab.Templates ? ( - ) : currentTab === DashboardsTab.Notebooks ? ( - ) : dashboardsLoading || dashboards.length > 0 || isFiltering ? ( ) : ( diff --git a/frontend/src/scenes/dashboard/dashboards/dashboardsLogic.ts b/frontend/src/scenes/dashboard/dashboards/dashboardsLogic.ts index 065220e5b48b7..015a792e1b3af 100644 --- a/frontend/src/scenes/dashboard/dashboards/dashboardsLogic.ts +++ b/frontend/src/scenes/dashboard/dashboards/dashboardsLogic.ts @@ -10,7 +10,6 @@ import { DashboardBasicType } from '~/types' export enum DashboardsTab { Dashboards = 'dashboards', - Notebooks = 'notebooks', Templates = 'templates', } diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeBacklink.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeBacklink.tsx index fa8a0b818484c..0345103e983b9 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeBacklink.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeBacklink.tsx @@ -10,7 +10,7 @@ import { IconLive, IconPerson, IconCohort, - IconJournal, + IconNotebook, } from 'lib/lemon-ui/icons' import { TaxonomicFilterGroupType } from 'lib/components/TaxonomicFilter/types' import { urls } from 'scenes/urls' @@ -31,7 +31,7 @@ const ICON_MAP = { events: , persons: , cohorts: , - notebooks: , + notebooks: , } const Component = (props: NodeViewProps): JSX.Element => { diff --git a/frontend/src/scenes/notebooks/Notebook/NotebookListMini.tsx b/frontend/src/scenes/notebooks/Notebook/NotebookListMini.tsx index e3e525a8cda9d..e573eecd30c3f 100644 --- a/frontend/src/scenes/notebooks/Notebook/NotebookListMini.tsx +++ b/frontend/src/scenes/notebooks/Notebook/NotebookListMini.tsx @@ -1,6 +1,6 @@ import { LemonButton } from '@posthog/lemon-ui' import { useValues } from 'kea' -import { IconJournal } from 'lib/lemon-ui/icons' +import { IconNotebook } from 'lib/lemon-ui/icons' import { notebooksModel } from '~/models/notebooksModel' import { NotebookListItemType } from '~/types' import { NotebookSelectPopover } from '../NotebookSelectButton/NotebookSelectButton' @@ -23,7 +23,7 @@ export function NotebookListMini({ selectedNotebookId }: NotebookListMiniProps): return ( - } status="primary-alt" sideIcon={null}> + } status="primary-alt" sideIcon={null}> {selectedTitle || 'Notebooks'} diff --git a/frontend/src/scenes/notebooks/NotebookScene.tsx b/frontend/src/scenes/notebooks/NotebookScene.tsx index 39caa1dd0589a..a69e66f2ce483 100644 --- a/frontend/src/scenes/notebooks/NotebookScene.tsx +++ b/frontend/src/scenes/notebooks/NotebookScene.tsx @@ -24,6 +24,7 @@ import { LOCAL_NOTEBOOK_TEMPLATES } from './NotebookTemplates/notebookTemplates' import './NotebookScene.scss' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { FEATURE_FLAGS } from 'lib/constants' +import { NotebookLoadingState } from './Notebook/NotebookLoadingState' interface NotebookSceneProps { shortId?: string @@ -38,10 +39,8 @@ export const scene: SceneExport = { } export function NotebookScene(): JSX.Element { - const { notebookId } = useValues(notebookSceneLogic) - const { notebook, notebookLoading, conflictWarningVisible, showHistory } = useValues( - notebookLogic({ shortId: notebookId }) - ) + const { notebookId, loading } = useValues(notebookSceneLogic) + const { notebook, conflictWarningVisible, showHistory } = useValues(notebookLogic({ shortId: notebookId })) const { exportJSON, setShowHistory } = useActions(notebookLogic({ shortId: notebookId })) const { selectNotebook, setVisibility } = useActions(notebookPopoverLogic) const { selectedNotebook, visibility } = useValues(notebookPopoverLogic) @@ -49,7 +48,7 @@ export function NotebookScene(): JSX.Element { const { featureFlags } = useValues(featureFlagLogic) const buttonSize = featureFlags[FEATURE_FLAGS.POSTHOG_3000] ? 'small' : 'medium' - if (!notebook && !notebookLoading && !conflictWarningVisible) { + if (!notebook && !loading && !conflictWarningVisible) { return } @@ -74,6 +73,10 @@ export function NotebookScene(): JSX.Element { const isTemplate = notebook?.is_template + if (notebookId === 'new') { + return + } + return (
diff --git a/frontend/src/scenes/notebooks/NotebookSelectButton/NotebookSelectButton.tsx b/frontend/src/scenes/notebooks/NotebookSelectButton/NotebookSelectButton.tsx index b04e2a4fe4e2c..edc4a3a3173b7 100644 --- a/frontend/src/scenes/notebooks/NotebookSelectButton/NotebookSelectButton.tsx +++ b/frontend/src/scenes/notebooks/NotebookSelectButton/NotebookSelectButton.tsx @@ -1,6 +1,6 @@ import { LemonButton, LemonButtonProps } from 'lib/lemon-ui/LemonButton' -import { IconJournalPlus, IconPlus, IconWithCount } from 'lib/lemon-ui/icons' +import { IconNotebook, IconPlus, IconWithCount } from 'lib/lemon-ui/icons' import { NotebookSelectButtonLogicProps, notebookSelectButtonLogic, @@ -206,7 +206,7 @@ export function NotebookSelectButton({ children, ...props }: NotebookSelectButto - + } data-attr={nodeLogic ? 'notebooks-add-button-in-a-notebook' : 'notebooks-add-button'} diff --git a/frontend/src/scenes/notebooks/NotebooksScene.tsx b/frontend/src/scenes/notebooks/NotebooksScene.tsx new file mode 100644 index 0000000000000..7caede1f116db --- /dev/null +++ b/frontend/src/scenes/notebooks/NotebooksScene.tsx @@ -0,0 +1,34 @@ +import { SceneExport } from 'scenes/sceneTypes' +import './NotebookScene.scss' +import { NotebooksTable } from './NotebooksTable/NotebooksTable' +import { LemonButton, LemonTag } from '@posthog/lemon-ui' +import { PageHeader } from 'lib/components/PageHeader' +import { urls } from 'scenes/urls' + +export const scene: SceneExport = { + component: NotebooksScene, +} + +export function NotebooksScene(): JSX.Element { + return ( +
+ + Notebooks + + Beta + +
+ } + buttons={ + + New notebook + + } + /> + + +
+ ) +} diff --git a/frontend/src/scenes/notebooks/notebookSceneLogic.ts b/frontend/src/scenes/notebooks/notebookSceneLogic.ts index 3129323a931fe..e7659c203c5d0 100644 --- a/frontend/src/scenes/notebooks/notebookSceneLogic.ts +++ b/frontend/src/scenes/notebooks/notebookSceneLogic.ts @@ -4,6 +4,7 @@ import { Breadcrumb } from '~/types' import type { notebookSceneLogicType } from './notebookSceneLogicType' import { notebookLogic } from './Notebook/notebookLogic' import { urls } from 'scenes/urls' +import { notebooksModel } from '~/models/notebooksModel' export type NotebookSceneLogicProps = { shortId: string @@ -13,31 +14,36 @@ export const notebookSceneLogic = kea([ props({} as NotebookSceneLogicProps), key(({ shortId }) => shortId), connect((props: NotebookSceneLogicProps) => ({ - values: [notebookLogic(props), ['notebook', 'notebookLoading']], - actions: [notebookLogic(props), ['loadNotebook']], + values: [notebookLogic(props), ['notebook', 'notebookLoading'], notebooksModel, ['notebooksLoading']], + actions: [notebookLogic(props), ['loadNotebook'], notebooksModel, ['createNotebook']], })), selectors(() => ({ notebookId: [() => [(_, props) => props], (props): string => props.shortId], + loading: [ + (s) => [s.notebookLoading, s.notebooksLoading], + (notebookLoading, notebooksLoading) => notebookLoading || notebooksLoading, + ], + breadcrumbs: [ - (s) => [s.notebook, s.notebookLoading], - (notebook, notebookLoading): Breadcrumb[] => [ + (s) => [s.notebook, s.loading], + (notebook, loading): Breadcrumb[] => [ { name: 'Notebooks', - path: urls.dashboards() + '?tab=notebooks', + path: urls.notebooks(), }, { - name: notebook - ? notebook?.title || 'Unnamed' - : notebookLoading - ? 'Loading...' - : 'Notebook not found', + name: notebook ? notebook?.title || 'Unnamed' : loading ? 'Loading...' : 'Notebook not found', }, ], ], })), - afterMount(({ actions }) => { - actions.loadNotebook() + afterMount(({ actions, props }) => { + if (props.shortId === 'new') { + actions.createNotebook() + } else { + actions.loadNotebook() + } }), ]) diff --git a/frontend/src/scenes/sceneTypes.ts b/frontend/src/scenes/sceneTypes.ts index 60ab9f17c9f01..370665987fa95 100644 --- a/frontend/src/scenes/sceneTypes.ts +++ b/frontend/src/scenes/sceneTypes.ts @@ -79,6 +79,7 @@ export enum Scene { DebugQuery = 'DebugQuery', VerifyEmail = 'VerifyEmail', Feedback = 'Feedback', + Notebooks = 'Notebooks', Notebook = 'Notebook', Products = 'Products', Onboarding = 'Onboarding', diff --git a/frontend/src/scenes/scenes.ts b/frontend/src/scenes/scenes.ts index 647b369ff8798..eec5a2c0dacca 100644 --- a/frontend/src/scenes/scenes.ts +++ b/frontend/src/scenes/scenes.ts @@ -318,6 +318,10 @@ export const sceneConfigurations: Partial> = { name: 'Notebook', layout: 'app-raw', }, + [Scene.Notebooks]: { + projectBased: true, + name: 'Notebooks', + }, } const preserveParams = (url: string) => (_params: Params, searchParams: Params, hashParams: Params) => { @@ -487,4 +491,5 @@ export const routes: Record = { [urls.feedback()]: Scene.Feedback, [urls.feedback() + '/*']: Scene.Feedback, [urls.notebook(':shortId')]: Scene.Notebook, + [urls.notebooks()]: Scene.Notebooks, } diff --git a/frontend/src/scenes/session-recordings/player/PlayerMetaLinks.tsx b/frontend/src/scenes/session-recordings/player/PlayerMetaLinks.tsx index b93793c4783b5..c6e511e0ccf7a 100644 --- a/frontend/src/scenes/session-recordings/player/PlayerMetaLinks.tsx +++ b/frontend/src/scenes/session-recordings/player/PlayerMetaLinks.tsx @@ -4,7 +4,7 @@ import { } from 'scenes/session-recordings/player/sessionRecordingPlayerLogic' import { useActions, useValues } from 'kea' import { LemonButton, LemonButtonProps } from 'lib/lemon-ui/LemonButton' -import { IconComment, IconDelete, IconJournalPlus, IconLink, IconPinFilled, IconPinOutline } from 'lib/lemon-ui/icons' +import { IconComment, IconDelete, IconNotebook, IconLink, IconPinFilled, IconPinOutline } from 'lib/lemon-ui/icons' import { openPlayerShareDialog } from 'scenes/session-recordings/player/share/PlayerShare' import { PlaylistPopoverButton } from './playlist-popover/PlaylistPopover' import { LemonDialog } from 'lib/lemon-ui/LemonDialog' @@ -85,7 +85,7 @@ export function PlayerMetaLinks(): JSX.Element { {nodeLogic?.props.nodeType === NotebookNodeType.RecordingPlaylist ? ( } + icon={} size="small" onClick={() => { nodeLogic.actions.insertAfter({ diff --git a/frontend/src/scenes/urls.ts b/frontend/src/scenes/urls.ts index dfccee2129218..239e16cbda9a6 100644 --- a/frontend/src/scenes/urls.ts +++ b/frontend/src/scenes/urls.ts @@ -183,9 +183,6 @@ export const urls = { combineUrl('/debug', {}, query ? { q: typeof query === 'string' ? query : JSON.stringify(query) } : {}).url, feedback: (): string => '/feedback', issues: (): string => '/issues', - notebooks: (): string => - combineUrl(urls.dashboards(), { - tab: 'notebooks', - }).url, + notebooks: (): string => '/notebooks', notebook: (shortId: string): string => `/notebooks/${shortId}`, }