From 82831aa7190bb444a35222469122fa368202b020 Mon Sep 17 00:00:00 2001 From: David Newell Date: Thu, 31 Aug 2023 17:27:35 +0100 Subject: [PATCH 1/6] support insight viz nodes in notebooks --- .../nodes/InsightViz/EditorFilters.scss | 17 +++- .../nodes/InsightViz/EditorFilters.tsx | 4 +- .../nodes/InsightViz/InsightContainer.tsx | 3 + .../queries/nodes/InsightViz/InsightViz.tsx | 43 ++++---- frontend/src/queries/schema.ts | 4 + .../ActionFilterRow/ActionFilterRow.tsx | 7 +- .../notebooks/Nodes/NotebookNodePlaylist.tsx | 9 +- .../notebooks/Nodes/NotebookNodeQuery.tsx | 98 ++++++++++++++++--- .../notebooks/Nodes/NotebookNodeRecording.tsx | 9 +- .../src/scenes/notebooks/Notebook/utils.ts | 29 ++++-- frontend/src/styles/vars.scss | 2 +- frontend/src/types.ts | 5 - 12 files changed, 167 insertions(+), 63 deletions(-) diff --git a/frontend/src/queries/nodes/InsightViz/EditorFilters.scss b/frontend/src/queries/nodes/InsightViz/EditorFilters.scss index 3cc99c2935936..26a94508b9444 100644 --- a/frontend/src/queries/nodes/InsightViz/EditorFilters.scss +++ b/frontend/src/queries/nodes/InsightViz/EditorFilters.scss @@ -4,19 +4,25 @@ .EditorFiltersWrapper { flex-shrink: 0; - border: 1px solid var(--border); - border-radius: var(--radius); - padding: 1rem; - margin-bottom: 1rem; background: var(--bg-light); + container-type: inline-size; + + &:not(.EditorFiltersWrapper--embedded) { + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 1rem; + margin-bottom: 1rem; + } .EditorFilters { > * + * { margin-top: 1rem; } - @include screen($md) { + + @container (min-width: 768px) { display: flex; gap: 2rem; + .EditorFilterGroup { flex: 1; width: 50%; @@ -33,6 +39,7 @@ background: none; padding: 0px; margin-right: 1rem; + container-type: normal; @include screen($xl) { --editor-panel-width: max(25vw, 28rem); diff --git a/frontend/src/queries/nodes/InsightViz/EditorFilters.tsx b/frontend/src/queries/nodes/InsightViz/EditorFilters.tsx index d370659fe2f63..1c5e57a015572 100644 --- a/frontend/src/queries/nodes/InsightViz/EditorFilters.tsx +++ b/frontend/src/queries/nodes/InsightViz/EditorFilters.tsx @@ -44,9 +44,10 @@ export interface EditorFiltersProps { query: InsightQueryNode setQuery: (node: InsightQueryNode) => void showing: boolean + embedded: boolean } -export function EditorFilters({ query, setQuery, showing }: EditorFiltersProps): JSX.Element { +export function EditorFilters({ query, setQuery, showing, embedded }: EditorFiltersProps): JSX.Element { const { user } = useValues(userLogic) const availableFeatures = user?.organization?.available_features || [] @@ -268,6 +269,7 @@ export function EditorFilters({ query, setQuery, showing }: EditorFiltersProps):
diff --git a/frontend/src/queries/nodes/InsightViz/InsightContainer.tsx b/frontend/src/queries/nodes/InsightViz/InsightContainer.tsx index 3204eef170560..b9ed3ab50983b 100644 --- a/frontend/src/queries/nodes/InsightViz/InsightContainer.tsx +++ b/frontend/src/queries/nodes/InsightViz/InsightContainer.tsx @@ -52,6 +52,7 @@ export function InsightContainer({ disableLastComputationRefresh, insightMode, context, + embedded, }: { disableHeader?: boolean disableTable?: boolean @@ -60,6 +61,7 @@ export function InsightContainer({ disableLastComputationRefresh?: boolean insightMode?: ItemMode context?: QueryContext + embedded: boolean }): JSX.Element { const { insightProps, canEditInsight } = useValues(insightLogic) @@ -206,6 +208,7 @@ export function InsightContainer({ title={disableHeader ? null : } data-attr="insights-graph" className="insights-graph-container" + bordered={!embedded} >
{isFunnels && ( diff --git a/frontend/src/queries/nodes/InsightViz/InsightViz.tsx b/frontend/src/queries/nodes/InsightViz/InsightViz.tsx index 70b909c82f5ab..4520df356a298 100644 --- a/frontend/src/queries/nodes/InsightViz/InsightViz.tsx +++ b/frontend/src/queries/nodes/InsightViz/InsightViz.tsx @@ -51,13 +51,14 @@ export function InsightViz({ uniqueKey, query, setQuery, context, readOnly }: In } const showIfFull = !!query.full - const disableHeader = query.showHeader ? !query.showHeader : !showIfFull - const disableTable = query.showTable ? !query.showTable : !showIfFull - const disableCorrelationTable = query.showCorrelationTable ? !query.showCorrelationTable : !showIfFull - const disableLastComputation = query.showLastComputation ? !query.showLastComputation : !showIfFull - const disableLastComputationRefresh = query.showLastComputationRefresh - ? !query.showLastComputationRefresh - : !showIfFull + const disableHeader = !(query.showHeader ?? showIfFull) + const disableTable = !(query.showTable ?? showIfFull) + const disableCorrelationTable = !(query.showCorrelationTable ?? showIfFull) + const disableLastComputation = !(query.showLastComputation ?? showIfFull) + const disableLastComputationRefresh = !(query.showLastComputationRefresh ?? showIfFull) + const showingFilters = query.showFilters ?? insightMode === ItemMode.Edit + const showingResults = query.showResults ?? true + const embedded = query.embedded ?? false return ( @@ -71,21 +72,25 @@ export function InsightViz({ uniqueKey, query, setQuery, context, readOnly }: In )} -
- -
+ {showingResults && ( +
+ +
+ )}
diff --git a/frontend/src/queries/schema.ts b/frontend/src/queries/schema.ts index a8cbecf7d2d51..00b70e8eb15ff 100644 --- a/frontend/src/queries/schema.ts +++ b/frontend/src/queries/schema.ts @@ -327,6 +327,10 @@ export interface InsightVizNode extends Node { showCorrelationTable?: boolean showLastComputation?: boolean showLastComputationRefresh?: boolean + showFilters?: boolean + showResults?: boolean + /** Query is embedded inside another bordered component */ + embedded?: boolean } /** Base class for insight query nodes. Should not be used directly. */ diff --git a/frontend/src/scenes/insights/filters/ActionFilter/ActionFilterRow/ActionFilterRow.tsx b/frontend/src/scenes/insights/filters/ActionFilter/ActionFilterRow/ActionFilterRow.tsx index e19467fb969fd..66b0380403cd1 100644 --- a/frontend/src/scenes/insights/filters/ActionFilter/ActionFilterRow/ActionFilterRow.tsx +++ b/frontend/src/scenes/insights/filters/ActionFilter/ActionFilterRow/ActionFilterRow.tsx @@ -243,7 +243,7 @@ export function ActionFilterRow({ const suffix = typeof customRowSuffix === 'function' ? customRowSuffix({ filter, index, onClose }) : customRowSuffix const propertyFiltersButton = ( - + : } // TODO: Get new IconFilterStriked icon status="primary-alt" @@ -262,6 +262,7 @@ export function ActionFilterRow({ const renameRowButton = ( } status="primary-alt" title="Rename graph series" @@ -276,6 +277,7 @@ export function ActionFilterRow({ const duplicateRowButton = ( } status="primary-alt" title="Duplicate graph series" @@ -289,6 +291,7 @@ export function ActionFilterRow({ const deleteButton = ( } status="primary-alt" title="Delete graph series" @@ -300,7 +303,7 @@ export function ActionFilterRow({ const rowStartElements = [ sortable && filterCount > 1 ? : null, - showSeriesIndicator &&
{seriesIndicator}
, + showSeriesIndicator &&
{seriesIndicator}
, ].filter(Boolean) const rowEndElements = !readOnly diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodePlaylist.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodePlaylist.tsx index e90da87286266..62cd9e2505657 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodePlaylist.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodePlaylist.tsx @@ -1,5 +1,5 @@ import { createPostHogWidgetNode } from 'scenes/notebooks/Nodes/NodeWrapper' -import { FilterType, NotebookNodeType, NotebookNodeWidgetSettings, RecordingFilters } from '~/types' +import { FilterType, NotebookNodeType, RecordingFilters } from '~/types' import { RecordingsLists, SessionRecordingsPlaylistProps, @@ -18,7 +18,7 @@ import { LemonButton } from '@posthog/lemon-ui' import { IconChevronLeft, IconSettings } from 'lib/lemon-ui/icons' import { urls } from 'scenes/urls' import { notebookNodeLogic } from './notebookNodeLogic' -import { JSONContent, NotebookNodeViewProps } from '../Notebook/utils' +import { JSONContent, NotebookNodeViewProps, NotebookNodeWidgetSettings } from '../Notebook/utils' import { SessionRecordingsFilters } from 'scenes/session-recordings/filters/SessionRecordingsFilters' import { ErrorBoundary } from '@sentry/react' @@ -72,7 +72,10 @@ const Component = (props: NotebookNodeViewProps) return
{content}
} -export const Settings = ({ attributes, updateAttributes }: NotebookNodeWidgetSettings): JSX.Element => { +export const Settings = ({ + attributes, + updateAttributes, +}: NotebookNodeWidgetSettings): JSX.Element => { const [filters, setFilters] = useJsonNodeState( attributes, updateAttributes, diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx index 9933867edd31b..a20673e9d5223 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx @@ -1,17 +1,18 @@ import { Query } from '~/queries/Query/Query' -import { NodeKind, QuerySchema } from '~/queries/schema' +import { DataTableNode, InsightVizNode, NodeKind, QuerySchema } from '~/queries/schema' import { createPostHogWidgetNode } from 'scenes/notebooks/Nodes/NodeWrapper' -import { NotebookNodeType } from '~/types' -import { BindLogic, useValues } from 'kea' -import { insightLogic } from 'scenes/insights/insightLogic' +import { InsightShortId, NotebookNodeType } from '~/types' +import { useValues } from 'kea' import { useJsonNodeState } from './utils' import { useMemo } from 'react' import { notebookNodeLogic } from './notebookNodeLogic' -import { NotebookNodeViewProps } from '../Notebook/utils' +import { NotebookNodeViewProps, NotebookNodeWidgetSettings } from '../Notebook/utils' +import clsx from 'clsx' +import { IconSettings } from 'lib/lemon-ui/icons' +import { urls } from 'scenes/urls' const DEFAULT_QUERY: QuerySchema = { kind: NodeKind.DataTableNode, - full: false, source: { kind: NodeKind.EventsQuery, select: ['*', 'event', 'person', 'timestamp'], @@ -19,13 +20,10 @@ const DEFAULT_QUERY: QuerySchema = { after: '-24h', limit: 100, }, - expandable: false, } const Component = (props: NotebookNodeViewProps): JSX.Element | null => { - const [query, setQuery] = useJsonNodeState(props.node.attrs, props.updateAttributes, 'query') - const logic = insightLogic({ dashboardItemId: 'new' }) - const { insightProps } = useValues(logic) + const [query] = useJsonNodeState(props.node.attrs, props.updateAttributes, 'query') const { expanded } = useValues(notebookNodeLogic) const modifiedQuery = useMemo(() => { @@ -35,18 +33,32 @@ const Component = (props: NotebookNodeViewProps): J // We don't want to show the insights button for now modifiedQuery.showOpenEditorButton = false modifiedQuery.full = false + modifiedQuery.showHogQLEditor = false + modifiedQuery.embedded = true + } else if (NodeKind.InsightVizNode === modifiedQuery.kind) { + modifiedQuery.showFilters = false + modifiedQuery.showHeader = false + modifiedQuery.showTable = false + modifiedQuery.showCorrelationTable = false + modifiedQuery.embedded = true } return modifiedQuery - }, [query, expanded]) + }, [query]) if (!expanded) { return null } return ( - - setQuery(t as any)} /> - +
+ +
) } @@ -54,6 +66,44 @@ type NotebookNodeQueryAttributes = { query: QuerySchema } +export const Settings = ({ + attributes, + updateAttributes, +}: NotebookNodeWidgetSettings): JSX.Element => { + const [query, setQuery] = useJsonNodeState(attributes, updateAttributes, 'query') + + const modifiedQuery = useMemo(() => { + const modifiedQuery = { ...query } + + if (NodeKind.DataTableNode === modifiedQuery.kind) { + // We don't want to show the insights button for now + modifiedQuery.showOpenEditorButton = false + modifiedQuery.showHogQLEditor = true + modifiedQuery.showResultsTable = false + modifiedQuery.showReload = true + } else if (NodeKind.InsightVizNode === modifiedQuery.kind) { + modifiedQuery.showFilters = true + modifiedQuery.showResults = false + modifiedQuery.embedded = true + } + + return modifiedQuery + }, [query]) + + return ( +
+ { + setQuery({ ...query, source: (t as DataTableNode | InsightVizNode).source } as QuerySchema) + }} + readOnly={false} + uniqueKey={attributes.nodeId} + /> +
+ ) +} + export const NotebookNodeQuery = createPostHogWidgetNode({ nodeType: NotebookNodeType.Query, title: (attributes) => { @@ -70,6 +120,7 @@ export const NotebookNodeQuery = createPostHogWidgetNode, + Component: Settings, + }, + ], + pasteOptions: { + find: urls.insightView('(.+)' as InsightShortId), + getAttributes: async (match) => { + return { + query: { + kind: NodeKind.SavedInsightNode, + shortId: match[1] as InsightShortId, + }, + } + }, + }, }) diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeRecording.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeRecording.tsx index fb4624a044456..245ab769c8a7b 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeRecording.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeRecording.tsx @@ -3,7 +3,7 @@ import { SessionRecordingPlayerProps, } from 'scenes/session-recordings/player/SessionRecordingPlayer' import { createPostHogWidgetNode } from 'scenes/notebooks/Nodes/NodeWrapper' -import { NotebookNodeType, NotebookNodeWidgetSettings, SessionRecordingId } from '~/types' +import { NotebookNodeType, SessionRecordingId } from '~/types' import { urls } from 'scenes/urls' import { SessionRecordingPlayerMode } from 'scenes/session-recordings/player/sessionRecordingPlayerLogic' import { useActions, useValues } from 'kea' @@ -16,7 +16,7 @@ import { import { notebookNodeLogic } from './notebookNodeLogic' import { LemonSwitch } from '@posthog/lemon-ui' import { IconSettings } from 'lib/lemon-ui/icons' -import { JSONContent, NotebookNodeViewProps } from '../Notebook/utils' +import { JSONContent, NotebookNodeViewProps, NotebookNodeWidgetSettings } from '../Notebook/utils' const HEIGHT = 500 const MIN_HEIGHT = 400 @@ -55,7 +55,10 @@ const Component = (props: NotebookNodeViewProps ) } -export const Settings = ({ attributes, updateAttributes }: NotebookNodeWidgetSettings): JSX.Element => { +export const Settings = ({ + attributes, + updateAttributes, +}: NotebookNodeWidgetSettings): JSX.Element => { return ( updateAttributes({ noInspector: !attributes.noInspector })} diff --git a/frontend/src/scenes/notebooks/Notebook/utils.ts b/frontend/src/scenes/notebooks/Notebook/utils.ts index 185b14ec1c74d..27e6e166eb5a4 100644 --- a/frontend/src/scenes/notebooks/Notebook/utils.ts +++ b/frontend/src/scenes/notebooks/Notebook/utils.ts @@ -9,7 +9,7 @@ import { } from '@tiptap/core' import { Node as PMNode } from '@tiptap/pm/model' import { NodeViewProps } from '@tiptap/react' -import { NotebookNodeType, NotebookNodeWidgetSettings } from '~/types' +import { NotebookNodeType } from '~/types' export interface Node extends PMNode {} export interface JSONContent extends TTJSONContent {} @@ -20,16 +20,24 @@ export { FocusPosition as EditorFocusPosition, } from '@tiptap/core' -export type NotebookNodeAttributes = Record -export type NotebookNode = Omit & { - attrs: T & { - nodeId: string - height?: string | number - title?: string | ((attributes: T) => Promise) - } +export type CustomNotebookNodeAttributes = Record + +export type NotebookNodeAttributes = T & { + nodeId: string + title: string | ((attributes: T) => Promise) + height?: string | number +} + +type NotebookNode = Omit & { + attrs: NotebookNodeAttributes +} + +export type NotebookNodeWidgetSettings = { + attributes: NotebookNodeAttributes + updateAttributes: (attributes: Partial) => void } -export type NotebookNodeViewProps = Omit & { +export type NotebookNodeViewProps = Omit & { node: NotebookNode } @@ -37,7 +45,8 @@ export type NotebookNodeWidget = { key: string label: string icon: JSX.Element - Component: ({ attributes, updateAttributes }: NotebookNodeWidgetSettings) => JSX.Element + // using 'any' here shouldn't be necessary but I couldn't figure out how to set a generic on the notebookNodeLogic props + Component: ({ attributes, updateAttributes }: NotebookNodeWidgetSettings) => JSX.Element } export interface NotebookEditor { diff --git a/frontend/src/styles/vars.scss b/frontend/src/styles/vars.scss index c12994413fae1..f369ddf4a3890 100644 --- a/frontend/src/styles/vars.scss +++ b/frontend/src/styles/vars.scss @@ -321,5 +321,5 @@ $_lifecycle_dormant: $_danger; // Notebooks --notebook-popover-transition-properties: 150ms cubic-bezier(0, 0.5, 0.5, 1); - --notebook-sidebar-width: 20rem; + --notebook-sidebar-width: 27rem; } diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 81d3ca9857906..c4c3c6a0679aa 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -3040,11 +3040,6 @@ export enum NotebookNodeType { Image = 'ph-image', } -export type NotebookNodeWidgetSettings = { - attributes: Record - updateAttributes: (attributes: Record) => void -} - export enum NotebookTarget { Popover = 'popover', Auto = 'auto', From 47ba603105c60b80e30f938cefb081ef20433000 Mon Sep 17 00:00:00 2001 From: David Newell Date: Fri, 1 Sep 2023 16:05:43 +0100 Subject: [PATCH 2/6] remove space --- frontend/src/queries/nodes/InsightViz/EditorFilters.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/queries/nodes/InsightViz/EditorFilters.scss b/frontend/src/queries/nodes/InsightViz/EditorFilters.scss index 26a94508b9444..5642f184dcfbc 100644 --- a/frontend/src/queries/nodes/InsightViz/EditorFilters.scss +++ b/frontend/src/queries/nodes/InsightViz/EditorFilters.scss @@ -3,7 +3,6 @@ .EditorFiltersWrapper { flex-shrink: 0; - background: var(--bg-light); container-type: inline-size; From 5325a7f0af60620dae005d8df62a44090f707b5a Mon Sep 17 00:00:00 2001 From: David Newell Date: Mon, 4 Sep 2023 12:20:59 +0100 Subject: [PATCH 3/6] feat: saved insight query props --- .../queries/nodes/SavedInsight/SavedInsight.tsx | 2 +- frontend/src/queries/schema.ts | 6 ++++-- .../scenes/notebooks/Nodes/NotebookNodeInsight.tsx | 2 +- .../scenes/notebooks/Nodes/NotebookNodeQuery.scss | 14 ++++++++++++++ .../scenes/notebooks/Nodes/NotebookNodeQuery.tsx | 4 +++- 5 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.scss diff --git a/frontend/src/queries/nodes/SavedInsight/SavedInsight.tsx b/frontend/src/queries/nodes/SavedInsight/SavedInsight.tsx index b2f85a52703eb..947541fdb4e27 100644 --- a/frontend/src/queries/nodes/SavedInsight/SavedInsight.tsx +++ b/frontend/src/queries/nodes/SavedInsight/SavedInsight.tsx @@ -32,7 +32,7 @@ export function SavedInsight({ query, context, cachedResults }: InsightProps): J return ( ) diff --git a/frontend/src/queries/schema.ts b/frontend/src/queries/schema.ts index 00b70e8eb15ff..d45994809c812 100644 --- a/frontend/src/queries/schema.ts +++ b/frontend/src/queries/schema.ts @@ -309,17 +309,19 @@ export interface DataTableNode extends Node { // Saved insight node -export interface SavedInsightNode extends Node { +export interface SavedInsightNode extends Node, InsightVizNodeViewProperties { kind: NodeKind.SavedInsightNode shortId: InsightShortId } // Insight viz node -export interface InsightVizNode extends Node { +export interface InsightVizNode extends Node, InsightVizNodeViewProperties { kind: NodeKind.InsightVizNode source: InsightQueryNode +} +export interface InsightVizNodeViewProperties { /** Show with most visual options enabled. Used in insight scene. */ full?: boolean showHeader?: boolean diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeInsight.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeInsight.tsx index dd8bd1e1c39cb..dcb172c64a424 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeInsight.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeInsight.tsx @@ -15,7 +15,7 @@ const Component = (props: NotebookNodeViewProps): if (!expanded) { return null } - return + return } type NotebookNodeInsightAttributes = { diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.scss b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.scss new file mode 100644 index 0000000000000..2817d972626fb --- /dev/null +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.scss @@ -0,0 +1,14 @@ +// Here we override based on retention-container the graph-container styling, so +// as to not change the global styling. We need the extra nesting to ensure we +// are more specific than the other insights css +.insights-graph-container { + .ant-card-body { + padding: 0; + } + + .RetentionContainer { + .LineGraph { + position: relative; + } + } +} diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx index 0e98064b2fd17..10c2fd790c170 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx @@ -10,6 +10,8 @@ import { NotebookNodeViewProps, NotebookNodeWidgetSettings } from '../Notebook/u import clsx from 'clsx' import { IconSettings } from 'lib/lemon-ui/icons' +import './NotebookNodeQuery.scss' + const DEFAULT_QUERY: QuerySchema = { kind: NodeKind.DataTableNode, source: { @@ -34,7 +36,7 @@ const Component = (props: NotebookNodeViewProps): J modifiedQuery.full = false modifiedQuery.showHogQLEditor = false modifiedQuery.embedded = true - } else if (NodeKind.InsightVizNode === modifiedQuery.kind) { + } else if (NodeKind.InsightVizNode === modifiedQuery.kind || NodeKind.SavedInsightNode === modifiedQuery.kind) { modifiedQuery.showFilters = false modifiedQuery.showHeader = false modifiedQuery.showTable = false From fc67c995002da42060bd515df899c040d9e0c792 Mon Sep 17 00:00:00 2001 From: David Newell Date: Thu, 7 Sep 2023 09:32:07 +0100 Subject: [PATCH 4/6] remove file --- .../notebooks/Nodes/NotebookNodeInsight.tsx | 56 ------------------- 1 file changed, 56 deletions(-) delete mode 100644 frontend/src/scenes/notebooks/Nodes/NotebookNodeInsight.tsx diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeInsight.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeInsight.tsx deleted file mode 100644 index dcb172c64a424..0000000000000 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeInsight.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { InsightShortId, NotebookNodeType } from '~/types' -import { createPostHogWidgetNode } from 'scenes/notebooks/Nodes/NodeWrapper' -import { urls } from 'scenes/urls' -import { Query } from '~/queries/Query/Query' -import { NodeKind } from '~/queries/schema' -import { useValues } from 'kea' -import { notebookNodeLogic } from './notebookNodeLogic' -import { NotebookNodeViewProps } from '../Notebook/utils' -import { insightLogic } from 'scenes/insights/insightLogic' -import api from 'lib/api' - -const Component = (props: NotebookNodeViewProps): JSX.Element | null => { - const { expanded } = useValues(notebookNodeLogic) - - if (!expanded) { - return null - } - return -} - -type NotebookNodeInsightAttributes = { - id: InsightShortId -} - -export const NotebookNodeInsight = createPostHogWidgetNode({ - nodeType: NotebookNodeType.Insight, - title: async (attributes) => { - const mountedInsightLogic = insightLogic.findMounted({ dashboardItemId: attributes.id }) - let title = mountedInsightLogic?.values.insightName || null - - if (title === null) { - const response = await api.insights.loadInsight(attributes.id, true) - if (response.results?.[0]) { - title = response.results[0].name?.length - ? response.results[0].name - : response.results[0].derived_name || null - } - } - - return title ? `Insight: ${title}` : 'Insight' - }, - Component, - heightEstimate: '16rem', - href: (attrs) => urls.insightView(attrs.id), - resizeable: false, - startExpanded: true, - attributes: { - id: {}, - }, - pasteOptions: { - find: urls.insightView('(.+)' as InsightShortId), - getAttributes: async (match) => { - return { id: match[1] as InsightShortId } - }, - }, -}) From a3b5765e4f72f0657a5adacae9565bcfe753a95f Mon Sep 17 00:00:00 2001 From: David Newell Date: Mon, 11 Sep 2023 14:20:39 +0100 Subject: [PATCH 5/6] insight viz styling --- .../src/queries/nodes/DataTable/DataTable.tsx | 8 ++-- .../nodes/InsightViz/EditorFilters.scss | 44 +++++-------------- .../notebooks/Nodes/NotebookNodeQuery.scss | 25 ++++++++--- .../notebooks/Nodes/NotebookNodeQuery.tsx | 5 ++- .../scenes/notebooks/Notebook/Notebook.scss | 5 +++ .../notebooks/Notebook/NotebookSidebar.tsx | 4 +- 6 files changed, 44 insertions(+), 47 deletions(-) diff --git a/frontend/src/queries/nodes/DataTable/DataTable.tsx b/frontend/src/queries/nodes/DataTable/DataTable.tsx index fc71b627e76e2..d81b615a5adde 100644 --- a/frontend/src/queries/nodes/DataTable/DataTable.tsx +++ b/frontend/src/queries/nodes/DataTable/DataTable.tsx @@ -65,8 +65,8 @@ let uniqueNode = 0 export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }: DataTableProps): JSX.Element { const uniqueNodeKey = useState(() => uniqueNode++) - const [vizKey] = useState(() => `DataTable.${uniqueKey || uniqueNodeKey}`) const [dataKey] = useState(() => `DataNode.${uniqueKey || uniqueNodeKey}`) + const [vizKey] = useState(() => `DataTable.${uniqueNodeKey}`) const dataNodeLogicProps: DataNodeLogicProps = { query: query.source, @@ -374,9 +374,9 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults } ) : null} {showFirstRow && ( -
+
{firstRowLeft} -
+ {firstRowLeft.length > 0 && firstRowRight.length > 0 ?
: null} {firstRowRight} {showOpenEditorButton && inlineEditorButtonOnRow === 1 && !isReadOnly ? ( @@ -387,7 +387,7 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults } {showSecondRow && (
{secondRowLeft} -
+ {secondRowLeft.length > 0 && secondRowRight.length > 0 ?
: null} {secondRowRight} {showOpenEditorButton && inlineEditorButtonOnRow === 2 && !isReadOnly ? ( diff --git a/frontend/src/queries/nodes/InsightViz/EditorFilters.scss b/frontend/src/queries/nodes/InsightViz/EditorFilters.scss index 5642f184dcfbc..de26425709f08 100644 --- a/frontend/src/queries/nodes/InsightViz/EditorFilters.scss +++ b/frontend/src/queries/nodes/InsightViz/EditorFilters.scss @@ -1,5 +1,4 @@ @import '../../../styles/mixins'; -@import '../../../styles/mixins'; .EditorFiltersWrapper { flex-shrink: 0; @@ -48,38 +47,6 @@ display: block; padding-right: 1rem; } - &.anim--enter { - width: 0px; - - .EditorFilters { - transform: translateX(calc(-1 * var(--editor-panel-width))); - } - } - - &.anim--enter-active { - width: var(--editor-panel-width); - transition: width 250ms; - .EditorFilters { - transform: translateX(0px); - transition: transform 250ms; - } - } - - &.anim--exit { - width: var(--editor-panel-width); - .EditorFilters { - transform: translateX(0px); - } - } - - &.anim--exit-active { - width: 0px; - transition: width 250ms; - .EditorFilters { - transform: translateX(calc(-1 * var(--editor-panel-width))); - transition: transform 250ms; - } - } } .EditorFilters { @@ -95,4 +62,15 @@ } } } + + &.EditorFiltersWrapper--embedded { + margin-right: 0rem; + + @include screen($xl) { + .EditorFilters { + width: 100%; + padding-right: 0rem; + } + } + } } diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.scss b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.scss index 2817d972626fb..d9f57009fa37b 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.scss +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.scss @@ -1,14 +1,25 @@ -// Here we override based on retention-container the graph-container styling, so +@import '../../../styles/mixins'; + +// Here we override based on NotebookNode the ph-query styling, so // as to not change the global styling. We need the extra nesting to ensure we // are more specific than the other insights css -.insights-graph-container { - .ant-card-body { - padding: 0; + +.NotebookNode.ph-query { + .insights-graph-container { + .ant-card-body { + padding: 0; + } + + .RetentionContainer { + .LineGraph { + position: relative; + } + } } - .RetentionContainer { - .LineGraph { - position: relative; + .funnel-insights-container { + &.non-empty-state { + min-height: initial; } } } diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx index 119eb074dd451..0be30e9cc69ed 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx @@ -80,8 +80,9 @@ export const Settings = ({ modifiedQuery.showOpenEditorButton = false modifiedQuery.showHogQLEditor = true modifiedQuery.showResultsTable = false - modifiedQuery.showReload = true - } else if (NodeKind.InsightVizNode === modifiedQuery.kind) { + modifiedQuery.showReload = false + modifiedQuery.showElapsedTime = false + } else if (NodeKind.InsightVizNode === modifiedQuery.kind || NodeKind.SavedInsightNode === modifiedQuery.kind) { modifiedQuery.showFilters = true modifiedQuery.showResults = false modifiedQuery.embedded = true diff --git a/frontend/src/scenes/notebooks/Notebook/Notebook.scss b/frontend/src/scenes/notebooks/Notebook/Notebook.scss index 9b257616c581a..4774eb742b8bd 100644 --- a/frontend/src/scenes/notebooks/Notebook/Notebook.scss +++ b/frontend/src/scenes/notebooks/Notebook/Notebook.scss @@ -137,6 +137,11 @@ position: sticky; align-self: flex-start; top: 65px; + + &__content { + max-height: calc(100vh - 220px); + overflow: scroll; + } } .LemonTable__content > table > thead { diff --git a/frontend/src/scenes/notebooks/Notebook/NotebookSidebar.tsx b/frontend/src/scenes/notebooks/Notebook/NotebookSidebar.tsx index bdef0cbe9507f..a8dff38c32c28 100644 --- a/frontend/src/scenes/notebooks/Notebook/NotebookSidebar.tsx +++ b/frontend/src/scenes/notebooks/Notebook/NotebookSidebar.tsx @@ -34,7 +34,9 @@ export const Widgets = ({ logic }: { logic: BuiltLogic })
{widgets.map(({ key, label, Component }) => ( setWidgetsVisible(false)}> - +
+ +
))}
From ab1e45acbdc55de65286b4a3d0567091eeedd9d0 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 13:39:55 +0000 Subject: [PATCH 6/6] Update UI snapshots for `chromium` (2) --- .../scenes-app-surveys--survey-view.png | Bin 49200 -> 49233 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/frontend/__snapshots__/scenes-app-surveys--survey-view.png b/frontend/__snapshots__/scenes-app-surveys--survey-view.png index 418de31110ebfcd4d53531a8bb52582b3781448f..4fd6630f9ddd5ca34e0b127a72caba9627335cfa 100644 GIT binary patch delta 25230 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 delta 25227 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�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 DN`X{%