From 786d748033caeaa0a9e975f8b97ab15f8505644c Mon Sep 17 00:00:00 2001 From: Ben White Date: Tue, 17 Oct 2023 09:41:51 +0200 Subject: [PATCH] feat: Create Notebook from dashboard (#17968) --- frontend/src/models/notebooksModel.ts | 52 ++++++++++++++++++- .../src/scenes/dashboard/DashboardHeader.tsx | 12 +++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/frontend/src/models/notebooksModel.ts b/frontend/src/models/notebooksModel.ts index c70d4a2a674de..249b6055b6847 100644 --- a/frontend/src/models/notebooksModel.ts +++ b/frontend/src/models/notebooksModel.ts @@ -1,7 +1,7 @@ -import { actions, BuiltLogic, connect, kea, path, reducers } from 'kea' +import { actions, BuiltLogic, connect, kea, listeners, path, reducers } from 'kea' import { loaders } from 'kea-loaders' -import { NotebookListItemType, NotebookTarget, NotebookType } from '~/types' +import { DashboardType, NotebookListItemType, NotebookNodeType, NotebookTarget, NotebookType } from '~/types' import api from 'lib/api' import posthog from 'posthog-js' @@ -16,6 +16,8 @@ import { notebookLogicType } from 'scenes/notebooks/Notebook/notebookLogicType' import { urls } from 'scenes/urls' import { notebookLogic } from 'scenes/notebooks/Notebook/notebookLogic' import { router } from 'kea-router' +import { filtersToQueryNode } from '~/queries/nodes/InsightQuery/utils/filtersToQueryNode' +import { InsightVizNode, Node, NodeKind } from '~/queries/schema' export const SCRATCHPAD_NOTEBOOK: NotebookListItemType = { short_id: 'scratchpad', @@ -74,6 +76,7 @@ export const notebooksModel = kea([ receiveNotebookUpdate: (notebook: NotebookListItemType) => ({ notebook }), loadNotebooks: true, deleteNotebook: (shortId: NotebookListItemType['short_id'], title?: string) => ({ shortId, title }), + createNotebookFromDashboard: (dashboard: DashboardType) => ({ dashboard }), }), connect({ values: [teamLogic, ['currentTeamId']], @@ -144,4 +147,49 @@ export const notebooksModel = kea([ }, ], })), + + listeners(({ actions }) => ({ + createNotebookFromDashboard: async ({ dashboard }) => { + const queries = dashboard.tiles.reduce((acc, tile) => { + if (!tile.insight) { + return acc + } + if (tile.insight.query) { + return [ + ...acc, + { + title: tile.insight.name, + query: tile.insight.query, + }, + ] + } + const node = filtersToQueryNode(tile.insight.filters) + + if (!node) { + return acc + } + + return [ + ...acc, + { + title: tile.insight.name, + query: { + kind: NodeKind.InsightVizNode, + source: node, + }, + }, + ] + }, [] as { title: string; query: InsightVizNode | Node }[]) + + const resources = queries.map((x) => ({ + type: NotebookNodeType.Query, + attrs: { + title: x.title, + query: x.query, + }, + })) + + await actions.createNotebook(dashboard.name + ' (copied)', NotebookTarget.Auto, resources) + }, + })), ]) diff --git a/frontend/src/scenes/dashboard/DashboardHeader.tsx b/frontend/src/scenes/dashboard/DashboardHeader.tsx index f7cb04f9e5e68..806b6a3ada25d 100644 --- a/frontend/src/scenes/dashboard/DashboardHeader.tsx +++ b/frontend/src/scenes/dashboard/DashboardHeader.tsx @@ -31,6 +31,8 @@ import { duplicateDashboardLogic } from 'scenes/dashboard/duplicateDashboardLogi import { tagsModel } from '~/models/tagsModel' import { DashboardTemplateEditor } from './DashboardTemplateEditor' import { dashboardTemplateEditorLogic } from './dashboardTemplateEditorLogic' +import { notebooksModel } from '~/models/notebooksModel' +import { FlaggedFeature } from 'lib/components/FlaggedFeature' export const DASHBOARD_CANNOT_EDIT_MESSAGE = "You don't have edit permissions for this dashboard. Ask a dashboard collaborator with edit access to add you." @@ -50,6 +52,7 @@ export function DashboardHeader(): JSX.Element | null { const { setDashboardMode, triggerDashboardUpdate } = useActions(dashboardLogic) const { asDashboardTemplate } = useValues(dashboardLogic) const { updateDashboard, pinDashboard, unpinDashboard } = useActions(dashboardsModel) + const { createNotebookFromDashboard } = useActions(notebooksModel) const { setDashboardTemplate, openDashboardTemplateEditor } = useActions(dashboardTemplateEditorLogic) @@ -261,6 +264,15 @@ export function DashboardHeader(): JSX.Element | null { > Duplicate dashboard + + createNotebookFromDashboard(dashboard)} + status="stealth" + fullWidth + > + Create notebook from dashboard + + {canEditDashboard && ( {