From a23f09a4ffb1f03dc371beb311f47d9709663756 Mon Sep 17 00:00:00 2001 From: Arthur Moreira de Deus Date: Thu, 27 Nov 2025 15:30:44 -0300 Subject: [PATCH 1/4] feat(customers): Filter insight by person in PersonFeedCanvas --- .../notebooks/Nodes/NotebookNodeQuery.tsx | 57 +++++++++++++++---- .../scenes/notebooks/Notebook/Notebook.tsx | 5 +- .../notebooks/Notebook/notebookLogic.ts | 3 + .../src/scenes/persons/PersonFeedCanvas.tsx | 12 +++- 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx index 197b49ce9edb8..cfad6943e0965 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx @@ -9,11 +9,21 @@ import { insightDataLogic } from 'scenes/insights/insightDataLogic' import { insightLogic } from 'scenes/insights/insightLogic' import { useSummarizeInsight } from 'scenes/insights/summarizeInsight' import { createPostHogWidgetNode } from 'scenes/notebooks/Nodes/NodeWrapper' +import { notebookLogic } from 'scenes/notebooks/Notebook/notebookLogic' import { urls } from 'scenes/urls' import { Query } from '~/queries/Query/Query' import { DataTableNode, InsightQueryNode, InsightVizNode, NodeKind, QuerySchema } from '~/queries/schema/schema-general' -import { containsHogQLQuery, isHogQLQuery, isInsightVizNode, isNodeWithSource } from '~/queries/utils' +import { + containsHogQLQuery, + isActorsQuery, + isDataTableNode, + isEventsQuery, + isHogQLQuery, + isInsightVizNode, + isNodeWithSource, + isSavedInsightNode, +} from '~/queries/utils' import { InsightLogicProps, InsightShortId } from '~/types' import { NotebookNodeAttributeProperties, NotebookNodeProps, NotebookNodeType } from '../types' @@ -39,6 +49,7 @@ const Component = ({ const nodeLogic = useMountedLogic(notebookNodeLogic) const { expanded } = useValues(nodeLogic) const { setTitlePlaceholder } = useActions(nodeLogic) + const { canvasFiltersOverride } = useValues(notebookLogic) const summarizeInsight = useSummarizeInsight() const insightLogicProps = { @@ -77,9 +88,9 @@ const Component = ({ }, [query, insightName]) const modifiedQuery = useMemo(() => { - const modifiedQuery = { ...query, full: false } + let modifiedQuery = { ...query, full: false } - if (NodeKind.DataTableNode === modifiedQuery.kind || NodeKind.SavedInsightNode === modifiedQuery.kind) { + if (isDataTableNode(modifiedQuery) || isSavedInsightNode(modifiedQuery)) { modifiedQuery.showOpenEditorButton = false modifiedQuery.full = false modifiedQuery.showHogQLEditor = false @@ -87,7 +98,7 @@ const Component = ({ modifiedQuery.showTimings = false } - if (NodeKind.InsightVizNode === modifiedQuery.kind || NodeKind.SavedInsightNode === modifiedQuery.kind) { + if (isInsightVizNode(modifiedQuery) || isSavedInsightNode(modifiedQuery)) { modifiedQuery.showFilters = false modifiedQuery.showHeader = false modifiedQuery.showTable = false @@ -96,7 +107,7 @@ const Component = ({ } return modifiedQuery - }, [query]) + }, [query, canvasFiltersOverride]) if (!expanded) { return null @@ -129,18 +140,21 @@ const Component = ({ type NotebookNodeQueryAttributes = { query: QuerySchema + /* Wether canvasFiltersOverride is applied, as we should apply it only once */ + isDefaultFilterApplied: boolean } export const Settings = ({ attributes, updateAttributes, }: NotebookNodeAttributeProperties): JSX.Element => { - const { query } = attributes + const { query, isDefaultFilterApplied } = attributes + const { canvasFiltersOverride } = useValues(notebookLogic) const modifiedQuery = useMemo(() => { const modifiedQuery = { ...query, full: false } - if (NodeKind.DataTableNode === modifiedQuery.kind || NodeKind.SavedInsightNode === modifiedQuery.kind) { + if (isDataTableNode(modifiedQuery) || isSavedInsightNode(modifiedQuery)) { modifiedQuery.showOpenEditorButton = false modifiedQuery.showHogQLEditor = true modifiedQuery.showResultsTable = false @@ -160,18 +174,33 @@ export const Settings = ({ modifiedQuery.showColumnConfigurator = true } - if (NodeKind.InsightVizNode === modifiedQuery.kind || NodeKind.SavedInsightNode === modifiedQuery.kind) { + if (isInsightVizNode(modifiedQuery) || isSavedInsightNode(modifiedQuery)) { modifiedQuery.showFilters = true modifiedQuery.showHeader = true modifiedQuery.showResults = false modifiedQuery.embedded = true } + if ( + isInsightVizNode(modifiedQuery) && + !isHogQLQuery(modifiedQuery.source) && + !isActorsQuery(modifiedQuery.source) && + !isDefaultFilterApplied + ) { + modifiedQuery.source.properties = canvasFiltersOverride + updateAttributes({ ...attributes, isDefaultFilterApplied: true }) + } + + if (isDataTableNode(modifiedQuery) && isEventsQuery(modifiedQuery.source) && !isDefaultFilterApplied) { + modifiedQuery.source.fixedProperties = canvasFiltersOverride + updateAttributes({ ...attributes, isDefaultFilterApplied: true }) + } + return modifiedQuery - }, [query]) + }, [query, canvasFiltersOverride]) const detachSavedInsight = (): void => { - if (attributes.query.kind === NodeKind.SavedInsightNode) { + if (isSavedInsightNode(attributes.query)) { const insightProps: InsightLogicProps = { dashboardItemId: attributes.query.shortId } const dataLogic = insightDataLogic.findMounted(insightProps) @@ -181,7 +210,7 @@ export const Settings = ({ } } - return attributes.query.kind === NodeKind.SavedInsightNode ? ( + return isSavedInsightNode(attributes.query) ? (
Insight created outside of this notebook
@@ -241,9 +270,12 @@ export const NotebookNodeQuery = createPostHogWidgetNode - query.kind === NodeKind.SavedInsightNode + isSavedInsightNode(query) ? urls.insightView(query.shortId) : isInsightVizNode(query) ? urls.insightNew({ query }) @@ -257,6 +289,7 @@ export const NotebookNodeQuery = createPostHogWidgetNode boolean, fn: () => any): Promise { @@ -151,6 +153,7 @@ export const notebookLogic = kea([ setAccessDeniedToNotebook: true, }), reducers(({ props }) => ({ + canvasFiltersOverride: [props.canvasFiltersOverride ?? ([] as AnyPropertyFilter[])], isShareModalOpen: [ false, { diff --git a/frontend/src/scenes/persons/PersonFeedCanvas.tsx b/frontend/src/scenes/persons/PersonFeedCanvas.tsx index 43a7c975d34ad..ebf98634d22e1 100644 --- a/frontend/src/scenes/persons/PersonFeedCanvas.tsx +++ b/frontend/src/scenes/persons/PersonFeedCanvas.tsx @@ -4,7 +4,7 @@ import { uuid } from 'lib/utils' import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic' import { Notebook } from 'scenes/notebooks/Notebook/Notebook' -import { PersonType } from '~/types' +import { AnyPropertyFilter, PersonType, PropertyFilterType, PropertyOperator } from '~/types' type PersonFeedCanvasProps = { person: PersonType @@ -16,11 +16,21 @@ const PersonFeedCanvas = ({ person }: PersonFeedCanvasProps): JSX.Element => { const id = person.id const distinctId = person.distinct_ids[0] + const personFilter: AnyPropertyFilter[] = [ + { + type: PropertyFilterType.EventMetadata, + key: 'person_id', + value: id, + operator: PropertyOperator.Exact, + }, + ] + return ( Date: Thu, 27 Nov 2025 18:01:01 -0300 Subject: [PATCH 2/4] chore: Fix typo --- frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx index cfad6943e0965..54cf16f8a02c8 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx @@ -140,7 +140,7 @@ const Component = ({ type NotebookNodeQueryAttributes = { query: QuerySchema - /* Wether canvasFiltersOverride is applied, as we should apply it only once */ + /* Whether canvasFiltersOverride is applied, as we should apply it only once */ isDefaultFilterApplied: boolean } From 2e78bc8459fb4b8950f22585569c74c301297fea Mon Sep 17 00:00:00 2001 From: Arthur Moreira de Deus Date: Thu, 27 Nov 2025 18:01:56 -0300 Subject: [PATCH 3/4] chore: Remove unused dependency --- frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx index 54cf16f8a02c8..20a4812f40411 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx @@ -49,7 +49,6 @@ const Component = ({ const nodeLogic = useMountedLogic(notebookNodeLogic) const { expanded } = useValues(nodeLogic) const { setTitlePlaceholder } = useActions(nodeLogic) - const { canvasFiltersOverride } = useValues(notebookLogic) const summarizeInsight = useSummarizeInsight() const insightLogicProps = { @@ -107,7 +106,7 @@ const Component = ({ } return modifiedQuery - }, [query, canvasFiltersOverride]) + }, [query]) if (!expanded) { return null From f4403f6dbf83caf37429d43275eab5f0d1f0f0fb Mon Sep 17 00:00:00 2001 From: Arthur Moreira de Deus Date: Fri, 28 Nov 2025 10:49:56 -0300 Subject: [PATCH 4/4] refactor: Pass down filter overrides through notebookLogic with BindLogic --- .../scenes/notebooks/Notebook/Notebook.tsx | 5 +- .../src/scenes/persons/PersonFeedCanvas.tsx | 112 +++++++++--------- 2 files changed, 59 insertions(+), 58 deletions(-) diff --git a/frontend/src/scenes/notebooks/Notebook/Notebook.tsx b/frontend/src/scenes/notebooks/Notebook/Notebook.tsx index 3db84c97ccfa1..1520f6d8558bb 100644 --- a/frontend/src/scenes/notebooks/Notebook/Notebook.tsx +++ b/frontend/src/scenes/notebooks/Notebook/Notebook.tsx @@ -14,7 +14,6 @@ import { NotebookLogicProps, notebookLogic } from 'scenes/notebooks/Notebook/not import { ErrorBoundary } from '~/layout/ErrorBoundary' import { SCRATCHPAD_NOTEBOOK } from '~/models/notebooksModel' -import { AnyPropertyFilter } from '~/types' import { AddInsightsToNotebookModal } from '../AddInsightsToNotebookModal/AddInsightsToNotebookModal' import { Editor } from './Editor' @@ -29,7 +28,6 @@ export type NotebookProps = NotebookLogicProps & { initialAutofocus?: EditorFocusPosition initialContent?: JSONContent editable?: boolean - canvasFiltersOverride?: AnyPropertyFilter[] } export function Notebook({ @@ -38,9 +36,8 @@ export function Notebook({ editable = true, initialAutofocus = 'start', initialContent, - canvasFiltersOverride, }: NotebookProps): JSX.Element { - const logicProps: NotebookLogicProps = { shortId, mode, canvasFiltersOverride } + const logicProps: NotebookLogicProps = { shortId, mode } const logic = notebookLogic(logicProps) const { notebook, notebookLoading, editor, conflictWarningVisible, isEditable, isTemplate, notebookMissing } = useValues(logic) diff --git a/frontend/src/scenes/persons/PersonFeedCanvas.tsx b/frontend/src/scenes/persons/PersonFeedCanvas.tsx index ebf98634d22e1..6c0dc574c5fb8 100644 --- a/frontend/src/scenes/persons/PersonFeedCanvas.tsx +++ b/frontend/src/scenes/persons/PersonFeedCanvas.tsx @@ -1,8 +1,9 @@ -import { useValues } from 'kea' +import { BindLogic, useValues } from 'kea' import { uuid } from 'lib/utils' import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic' import { Notebook } from 'scenes/notebooks/Notebook/Notebook' +import { notebookLogic } from 'scenes/notebooks/Notebook/notebookLogic' import { AnyPropertyFilter, PersonType, PropertyFilterType, PropertyOperator } from '~/types' @@ -15,6 +16,8 @@ const PersonFeedCanvas = ({ person }: PersonFeedCanvasProps): JSX.Element => { const id = person.id const distinctId = person.distinct_ids[0] + const shortId = `canvas-${id}` + const mode = 'canvas' const personFilter: AnyPropertyFilter[] = [ { @@ -26,60 +29,61 @@ const PersonFeedCanvas = ({ person }: PersonFeedCanvasProps): JSX.Element => { ] return ( - + + { + type: 'ph-llm-trace', + attrs: { personId: id, nodeId: uuid() }, + }, + { + type: 'ph-zendesk-tickets', + attrs: { personId: id, nodeId: uuid() }, + }, + { + type: 'ph-issues', + attrs: { personId: id, nodeId: uuid() }, + }, + ], + }} + /> + ) }