{props.nodesDraggable && props.onResetNodePositions && (
)}
- {props.panels && {props.panels}}
+ {props.panels && {props.panels}}
)
}
diff --git a/products/data_modeling/frontend/lineage/ModelsLineageTab.tsx b/products/data_modeling/frontend/lineage/ModelsLineageTab.tsx
index afce2529f8ed..ca2de95e806e 100644
--- a/products/data_modeling/frontend/lineage/ModelsLineageTab.tsx
+++ b/products/data_modeling/frontend/lineage/ModelsLineageTab.tsx
@@ -169,7 +169,6 @@ export function ModelsLineageTab(): JSX.Element {
onResetNodePositions={nodesDraggable ? resetNodePositions : undefined}
showControls
showMinimap
- minimapPosition="top-right"
loading={nodesLoading || edgesLoading}
emptyMessage={
isFiltered ? 'No models match these filters.' : 'No models yet. Create a view to see it here.'
@@ -180,7 +179,6 @@ export function ModelsLineageTab(): JSX.Element {
isRunning: node.last_run_status === 'Running',
})}
onNodeClick={nodesDraggable ? undefined : (node) => router.actions.push(lineageNodeUrl(node))}
- panelPosition="bottom-left"
panels={}
/>
From c4a5073252b2912a70e7b0dcbe1f298ac4fc9468 Mon Sep 17 00:00:00 2001
From: Jovan Sakovic <49978945+sakce@users.noreply.github.com>
Date: Fri, 2 Oct 2026 17:17:08 +0200
Subject: [PATCH 3/6] feat(data-modeling): drag nodes in detail lineage
Generated-By: PostHog Desktop
Task-Id: e3bdd69b-e26b-4d2f-b324-fb57dc5226c2
---
.../frontend/lineage/LineageNode.tsx | 2 +-
.../frontend/nodeDetail/NodeDetailLineage.tsx | 40 +++++++++++++++----
.../nodeDetail/NodeDetailScene.stories.tsx | 2 +-
.../nodeDetail/nodeDetailSceneLogic.ts | 21 ++++++++++
4 files changed, 56 insertions(+), 9 deletions(-)
diff --git a/products/data_modeling/frontend/lineage/LineageNode.tsx b/products/data_modeling/frontend/lineage/LineageNode.tsx
index 6386c3138efe..afdc0ae768a0 100644
--- a/products/data_modeling/frontend/lineage/LineageNode.tsx
+++ b/products/data_modeling/frontend/lineage/LineageNode.tsx
@@ -372,7 +372,7 @@ export function LineageNode({ data }: { data: LineageNodeData }): JSX.Element {
to={data.openUrl}
targetBlank
stopPropagation
- tooltip={`Open ${node.name} in new tab`}
+ tooltip="Open in new tab"
aria-label={`Open ${node.name} in new tab`}
icon={}
data-attr="lineage-node-open"
diff --git a/products/data_modeling/frontend/nodeDetail/NodeDetailLineage.tsx b/products/data_modeling/frontend/nodeDetail/NodeDetailLineage.tsx
index 49bcee5d88c0..5dccb33de4d1 100644
--- a/products/data_modeling/frontend/nodeDetail/NodeDetailLineage.tsx
+++ b/products/data_modeling/frontend/nodeDetail/NodeDetailLineage.tsx
@@ -5,6 +5,7 @@ import { useMemo } from 'react'
import { IconExpand45, IconExternal } from '@posthog/icons'
import { LemonBanner, LemonButton } from '@posthog/lemon-ui'
+import { useFeatureFlag } from 'lib/hooks/useFeatureFlag'
import { LemonModal } from 'lib/lemon-ui/LemonModal/LemonModal'
import { urls } from 'scenes/urls'
@@ -14,7 +15,12 @@ import { LineageGraph } from '../lineage/LineageGraph'
import { lineageNodeUrl } from '../lineage/lineageNodeUrl'
import { nodeDetailSceneLogic } from './nodeDetailSceneLogic'
+function nodeLineageUrl(node: DataModelingNode): string {
+ return lineageNodeUrl(node, 'lineage')
+}
+
export function NodeDetailLineage({ id }: { id: string }): JSX.Element {
+ const nodesDraggable = useFeatureFlag('DATA_MODELING_LINEAGE_NODE_DRAGGING')
const {
lineageGraph,
lineageGraphLoading,
@@ -22,9 +28,11 @@ export function NodeDetailLineage({ id }: { id: string }): JSX.Element {
effectiveLastRunAt,
effectiveLastRunStatus,
lineageModalOpen,
+ lineageNodePositions,
node,
} = useValues(nodeDetailSceneLogic({ id }))
- const { openLineageModal, closeLineageModal, loadLineageGraph } = useActions(nodeDetailSceneLogic({ id }))
+ const { openLineageModal, closeLineageModal, loadLineageGraph, lineageNodeDragStopped, resetLineageNodePositions } =
+ useActions(nodeDetailSceneLogic({ id }))
// The current node's freshest status/run come from its materialization jobs, not the graph payload
const nodes = useMemo((): DataModelingNode[] => {
@@ -43,7 +51,7 @@ export function NodeDetailLineage({ id }: { id: string }): JSX.Element {
}, [lineageGraph, effectiveLastRunAt, effectiveLastRunStatus])
const openNode = (node: DataModelingNode): void => {
- router.actions.push(lineageNodeUrl(node, 'lineage'))
+ router.actions.push(nodeLineageUrl(node))
}
if (!lineageGraphLoading && lineageGraphError) {
@@ -82,9 +90,16 @@ export function NodeDetailLineage({ id }: { id: string }): JSX.Element {
loadingCenter={lineageGraphLoading && node ? { name: node.name, type: node.type } : undefined}
variant="full"
interactive
+ nodesDraggable={nodesDraggable}
+ nodePositions={nodesDraggable ? lineageNodePositions : undefined}
+ nodeOpenUrl={nodesDraggable ? nodeLineageUrl : undefined}
+ onNodeDragStop={
+ nodesDraggable ? (node, position) => lineageNodeDragStopped(node.id, position) : undefined
+ }
+ onResetNodePositions={nodesDraggable ? resetLineageNodePositions : undefined}
showControls
showMinimap
- onNodeClick={openNode}
+ onNodeClick={nodesDraggable ? undefined : openNode}
panels={
lineageNodeDragStopped(node.id, position) : undefined
+ }
+ onResetNodePositions={nodesDraggable ? resetLineageNodePositions : undefined}
showControls
- onNodeClick={(node) => {
- closeLineageModal()
- openNode(node)
- }}
+ onNodeClick={
+ nodesDraggable
+ ? undefined
+ : (node) => {
+ closeLineageModal()
+ openNode(node)
+ }
+ }
/>
diff --git a/products/data_modeling/frontend/nodeDetail/NodeDetailScene.stories.tsx b/products/data_modeling/frontend/nodeDetail/NodeDetailScene.stories.tsx
index d18be401eb3d..6ea5bf820333 100644
--- a/products/data_modeling/frontend/nodeDetail/NodeDetailScene.stories.tsx
+++ b/products/data_modeling/frontend/nodeDetail/NodeDetailScene.stories.tsx
@@ -201,7 +201,7 @@ export const View: Story = {}
export const WarehouseTable: Story = {
args: { id: tableNode.id },
parameters: {
- featureFlags: [FEATURE_FLAGS.DATA_QUALITY_CHECKS],
+ featureFlags: [FEATURE_FLAGS.DATA_QUALITY_CHECKS, FEATURE_FLAGS.DATA_MODELING_LINEAGE_NODE_DRAGGING],
pageUrl: urls.nodeDetail(tableNode.id, 'lineage'),
msw: {
mocks: {
diff --git a/products/data_modeling/frontend/nodeDetail/nodeDetailSceneLogic.ts b/products/data_modeling/frontend/nodeDetail/nodeDetailSceneLogic.ts
index b5c243362ffe..2fa404e0f23e 100644
--- a/products/data_modeling/frontend/nodeDetail/nodeDetailSceneLogic.ts
+++ b/products/data_modeling/frontend/nodeDetail/nodeDetailSceneLogic.ts
@@ -1,3 +1,4 @@
+import type { XYPosition } from '@xyflow/react'
import { MakeLogicType, actions, afterMount, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea'
import { loaders } from 'kea-loaders'
import { router, urlToAction } from 'kea-router'
@@ -75,6 +76,7 @@ export interface nodeDetailSceneLogicValues {
lineageGraphError: boolean
lineageGraphLoading: boolean
lineageModalOpen: boolean
+ lineageNodePositions: Record
node: DataModelingNode | null
nodeLoading: boolean
nodeType: NodeTypeEnumApi | null
@@ -125,6 +127,13 @@ export interface nodeDetailSceneLogicActions {
closeLineageModal: () => {
value: true
}
+ lineageNodeDragStopped: (
+ nodeId: string,
+ position: XYPosition
+ ) => {
+ nodeId: string
+ position: XYPosition
+ }
loadLineageGraph: () => any
loadLineageGraphFailure: (
error: string,
@@ -219,6 +228,9 @@ export interface nodeDetailSceneLogicActions {
openLineageModal: () => {
value: true
}
+ resetLineageNodePositions: () => {
+ value: true
+ }
setCurrentTab: (tab: NodeDetailSceneTab | null) => {
tab: 'data-quality' | 'history' | 'lineage' | 'materialization' | 'query' | null
}
@@ -302,6 +314,8 @@ export const nodeDetailSceneLogic = kea([
canonicalizeTab: true,
openLineageModal: true,
closeLineageModal: true,
+ lineageNodeDragStopped: (nodeId: string, position: XYPosition) => ({ nodeId, position }),
+ resetLineageNodePositions: true,
}),
reducers({
// What the address bar asks for. Tab links navigate, so nothing else may write this.
@@ -381,6 +395,13 @@ export const nodeDetailSceneLogic = kea([
closeLineageModal: () => false,
},
],
+ lineageNodePositions: [
+ {} as Record,
+ {
+ lineageNodeDragStopped: (positions, { nodeId, position }) => ({ ...positions, [nodeId]: position }),
+ resetLineageNodePositions: () => ({}),
+ },
+ ],
}),
loaders(({ props, values }) => ({
node: {
From 674c0a2f0a3d5f80b6e2e8206654e457b3d20f4a Mon Sep 17 00:00:00 2001
From: Jovan Sakovic <49978945+sakce@users.noreply.github.com>
Date: Fri, 2 Oct 2026 17:31:51 +0200
Subject: [PATCH 4/6] fix(data-modeling): focus node detail lineage
Generated-By: PostHog Desktop
Task-Id: e3bdd69b-e26b-4d2f-b324-fb57dc5226c2
---
.../data_modeling/frontend/lineage/LineageGraphLoading.tsx | 6 ++++--
.../data_modeling/frontend/nodeDetail/NodeDetailLineage.tsx | 6 ++++++
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/products/data_modeling/frontend/lineage/LineageGraphLoading.tsx b/products/data_modeling/frontend/lineage/LineageGraphLoading.tsx
index 0d2e697c1f66..84b36acb2abb 100644
--- a/products/data_modeling/frontend/lineage/LineageGraphLoading.tsx
+++ b/products/data_modeling/frontend/lineage/LineageGraphLoading.tsx
@@ -56,15 +56,17 @@ function loadingGraph(
}
}
+ const hasUpstream = center.type !== 'table'
+
return {
centerNodeId,
nodes: [
- node(upstreamId, 'Loading upstream...', 'table'),
+ ...(hasUpstream ? [node(upstreamId, 'Loading upstream...', 'table')] : []),
node(centerNodeId, center.name, center.type),
node(downstreamId, 'Loading downstream...', 'view'),
],
edges: [
- edge(`${idPrefix}-upstream-edge`, upstreamId, centerNodeId),
+ ...(hasUpstream ? [edge(`${idPrefix}-upstream-edge`, upstreamId, centerNodeId)] : []),
edge(`${idPrefix}-downstream-edge`, centerNodeId, downstreamId),
],
}
diff --git a/products/data_modeling/frontend/nodeDetail/NodeDetailLineage.tsx b/products/data_modeling/frontend/nodeDetail/NodeDetailLineage.tsx
index 5dccb33de4d1..f6aecad4f1df 100644
--- a/products/data_modeling/frontend/nodeDetail/NodeDetailLineage.tsx
+++ b/products/data_modeling/frontend/nodeDetail/NodeDetailLineage.tsx
@@ -49,6 +49,10 @@ export function NodeDetailLineage({ id }: { id: string }): JSX.Element {
: node
)
}, [lineageGraph, effectiveLastRunAt, effectiveLastRunStatus])
+ const focusNodeIds = useMemo(
+ () => (lineageGraph?.currentNodeId ? new Set([lineageGraph.currentNodeId]) : null),
+ [lineageGraph?.currentNodeId]
+ )
const openNode = (node: DataModelingNode): void => {
router.actions.push(nodeLineageUrl(node))
@@ -86,6 +90,7 @@ export function NodeDetailLineage({ id }: { id: string }): JSX.Element {
nodes={nodes}
edges={lineageGraph?.edges ?? []}
currentNodeId={lineageGraph?.currentNodeId}
+ focusNodeIds={focusNodeIds}
loading={lineageGraphLoading}
loadingCenter={lineageGraphLoading && node ? { name: node.name, type: node.type } : undefined}
variant="full"
@@ -132,6 +137,7 @@ export function NodeDetailLineage({ id }: { id: string }): JSX.Element {
nodes={nodes}
edges={lineageGraph?.edges ?? []}
currentNodeId={lineageGraph?.currentNodeId}
+ focusNodeIds={focusNodeIds}
variant="full"
interactive
nodesDraggable={nodesDraggable}
From 5cd5578f61254533252b12604ddb1218327e0561 Mon Sep 17 00:00:00 2001
From: Jovan Sakovic <49978945+sakce@users.noreply.github.com>
Date: Fri, 2 Oct 2026 18:04:44 +0200
Subject: [PATCH 5/6] chore(data-modeling): cover narrow lineage canvas in
storybook
The minimap is now gated on the canvas container instead of the viewport, and no lineage story
renders below the 48rem breakpoint, so a change back to a viewport breakpoint would put the minimap
over a cramped canvas without failing anything.
Co-Authored-By: Claude Opus 5
Generated-By: PostHog Desktop
Task-Id: 53f76885-d344-456d-a367-0ace8a2179e9
---
.../frontend/lineage/LineageGraph.stories.tsx | 24 +++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/products/data_modeling/frontend/lineage/LineageGraph.stories.tsx b/products/data_modeling/frontend/lineage/LineageGraph.stories.tsx
index da07ec87dd3d..2e60d81d23a1 100644
--- a/products/data_modeling/frontend/lineage/LineageGraph.stories.tsx
+++ b/products/data_modeling/frontend/lineage/LineageGraph.stories.tsx
@@ -209,6 +209,30 @@ export const Canvas: Story = {
),
}
+// The minimap is gated on the canvas container instead of the viewport, so a canvas that is narrow
+// inside a wide window must still hide it and leave the zoom controls room. The graph is cut to two
+// nodes because fit-view scales the whole graph into 480px, and nodes that small render text the
+// snapshot cannot compare reliably.
+export const NarrowCanvas: Story = {
+ render: () => (
+
+ ),
+ decorators: [
+ (StoryFn) => (
+
+
+
+ ),
+ ],
+}
+
export const DraggableNodes: Story = {
parameters: { featureFlags: [FEATURE_FLAGS.DATA_MODELING_LINEAGE_NODE_DRAGGING] },
render: () => ,
From cdb6faddb7f612f4916fd4b364fe05e5dcd9bfd8 Mon Sep 17 00:00:00 2001
From: "posthog[bot]" <206114724+posthog[bot]@users.noreply.github.com>
Date: Fri, 2 Oct 2026 22:16:08 +0000
Subject: [PATCH 6/6] chore(visual): update storybook baselines
14 updated
Run: 0ae07cf3-754f-4c61-a339-1098652d7c7d
Co-authored-by: sakce <49978945+sakce@users.noreply.github.com>
---
frontend/snapshots.yml | 28 ++++++++++++++++------------
1 file changed, 16 insertions(+), 12 deletions(-)
diff --git a/frontend/snapshots.yml b/frontend/snapshots.yml
index b03bc5748866..b9cd7a94e5e9 100644
--- a/frontend/snapshots.yml
+++ b/frontend/snapshots.yml
@@ -6655,17 +6655,17 @@ snapshots:
products-data-catalog-metric-lineage--no-warehouse-access--light:
hash: v1.k794b7964.d24fc4898fd69d316912802e328f3a6e2e94cee4cf106d8893597da97dbf73af.UOfef0QXupztuN6lJ1r5vYH5FiYFRHx_eqHRlY-34CQ
products-data-modeling-lineage-graph--canvas--dark:
- hash: v1.k794b7964.7a843fa31e6bee6160f6d308d5d8a1b26d8f110741f914c427150e6a6f53e555.2O-4iOAEMchOc6BaSDiC-Hvrhai-a2QMg1b0-yis9A4
+ hash: v1.k794b7964.dfc9cecd5fe04ca15b3030156b8a22b1e7e856ca02ba62a45acb9f18e8e4363f.OMoHNsARLj6RjX4bCuo2KF33IMbCanui8ZqWzGhIczk
products-data-modeling-lineage-graph--canvas--light:
- hash: v1.k794b7964.97977a4c30ab6a8fc5afdecb1ed6e9892d7fab579580cd250a0d3362fbbf6e87.R8w2a2xrAV5cL984OpFZzMY3zelheXpdTkoS2FPKeSs
+ hash: v1.k794b7964.abbc2578ede8d828962ca36072f7f3192b2f595879d2df310d2b8304da15c9dc.8xbTQ8AJrMZhoqk4vMGuUxKW1IBiljeLpuubCXYKCkM
products-data-modeling-lineage-graph--dark-mode--dark:
hash: v1.k794b7964.dbaa1992239d54c653a2132b63857ca77420a178b662c000fb93e7fded648a19.XVks3zJgtqjlm24-mHsgMx3boV8KNZNtXN5dcph4LWw
products-data-modeling-lineage-graph--dark-mode--light:
hash: v1.k794b7964.bc8a6b5f4e177299e6b7ca346135a43ecbd3048405692bb1e75a8747f695c12d.Cg73TPpnrS5uZDxIKIWiV4BhszAzKFH_dSHExM_kkJM
products-data-modeling-lineage-graph--draggable-nodes--dark:
- hash: v1.k794b7964.e7fa348d01185cb0caead49e88f43afcc2885992c4a4b79f59fc34da6f19bca5.WfK2u7q2UakJ496Kt9G7l76XIhBA-49hcrL2MlwGS4w
+ hash: v1.k794b7964.07a5ee7f200d2b6b0f19c1c2295c0351810959cb4782ffdf368616f76bcea019.pM9SXd5270zePRVh34lXqpalGz5Wz_WDdO_5uEi232g
products-data-modeling-lineage-graph--draggable-nodes--light:
- hash: v1.k794b7964.dfc5bc62d287ed88c8dfa9630052ea2f67037f2e3d7440d95560f7fc99824a3e.po-hGnD-1T6eHcFvVKT5ZmshWvlAiioiNIfH4z5Lw28
+ hash: v1.k794b7964.423039b18ad74e8b8a0f512bed923afebb082d520175c27a37852ae961d79f0f.nrCG91Mj_M54zDZb4ZL1DLh8Gedgm_DOmhPKh_zGEVQ
products-data-modeling-lineage-graph--empty-state--dark:
hash: v1.k794b7964.9870c50d45ee1583472d6a98917a350892a8c2d8e29c20d17138eb68b8b52d60.yi6jAXaHCs0dh9kUIVgf6aWiVa8Btlb2b9xUQw_q4VE
products-data-modeling-lineage-graph--empty-state--light:
@@ -6687,21 +6687,25 @@ snapshots:
products-data-modeling-lineage-graph--loading-focused--light:
hash: v1.k794b7964.ad5f3bb5a4c9a5193cf69e525d90f14a6593bcd863437ae10d7148c798720278.N7js9PPoiXJKVTgurWgbO00-kxtsO-gsKxcFaaZAhPo
products-data-modeling-lineage-graph--moved-node-focus--dark:
- hash: v1.k794b7964.104d9527724d974ab4b4d6482ff8e7c9ab7865bcd0598d160e3727fd94989c7c.IoqXmWo1wJlpwX22IL_FBQKV58RLpNmvOgIzxky6qaI
+ hash: v1.k794b7964.3c88300ce8234129cbe1809432f3545a596ea655166149faaf5fce6f23ce4c18.pyjkoADBv8Js6lTGxe2HYEa_N2j2cAiq0g9qbwTkH_4
products-data-modeling-lineage-graph--moved-node-focus--light:
- hash: v1.k794b7964.526c6f5cc22548b7fb466ed640a7add56aaa64ac0282ae60e01b38cfc50ca7f1.Nrl9rYDuPwqzmSMwBCLldb8SBiNn031dS_cIgevFJZA
+ hash: v1.k794b7964.cd86fa8aae566ba968e6f427aac7244c098b983627b71bbaa977ead163dea928.b99WA-4QaTu5AO5y2aOxScBgDW9s_DWoU0VXbJeEd8M
+ products-data-modeling-lineage-graph--narrow-canvas--dark:
+ hash: v1.k794b7964.1c8595f58c615df292fb49f20c6a5baa270fb748fa352e00b61a22f198bef927.RO7E7WU6C-rcB3X_ehW13eY8II9DroOk63RrtEUZCwQ
+ products-data-modeling-lineage-graph--narrow-canvas--light:
+ hash: v1.k794b7964.607c0429769d365d295ac605cdbadd234773b26cf48cb9e6349dea953baed856._YpaiX9ffz0Cx-r5WxQLV6PLKzNhsu34nbsXN3hVOIM
products-data-modeling-lineage-graph--reset-moved-nodes--dark:
- hash: v1.k794b7964.15e5e88b4178f0347d9ebae1f83d8a236fb988fbc621204f2ed568717c9b0b08.z7W9cDpbkr85TkgQHo9H6-fXSsVQ5irrpJUU3HhU2Lg
+ hash: v1.k794b7964.bf54d50c1f529389bb45a9d7d21aa6e735e73773952fea70f08b0ea6803396cc.oeEbgWmB_ekBNdk2Ng5-9L4blVGhsovaAPYrwUzI3K4
products-data-modeling-lineage-graph--reset-moved-nodes--light:
- hash: v1.k794b7964.b54ae28affd8c87b5762de3905c081e087a5d2c6ef78ab3335ffb55e12972130.W9m2cQGMi-7XuGKMEtcWkE9L5SQ8rM-UY0Ktgn7IWO8
+ hash: v1.k794b7964.58aa75c5200337a71da0b9e4eb6455df23e16c91592982406f1934d9fcab4173.uvZ46-W9atDhcT0R_h9rtD0s4Z4UItW3nnL-9DDi6Lg
products-data-modeling-lineage-graph--search-focus--dark:
- hash: v1.k794b7964.bb7fd2d6e2a32b2ae732793749f5c3378b9ddeed90115a169515e50611fc0558.hzBxXCNRLcqtZ_OV-8RcnASe8V2kyVEPHXqAlYkrmtY
+ hash: v1.k794b7964.c6bbd5662f44ae3c049af510a720695e8dc4e32fc3aa62a3e46c9721cf3c8cf4.5J3A6g_ZGj4lHduTNNFde5_FR6AJF1fpMfdLwdmp77U
products-data-modeling-lineage-graph--search-focus--light:
- hash: v1.k794b7964.3d11e7ae38507207bbe6cc4e4a2e836551851f548b320ba9e68434a7f28955e4.5xbCZPz04Wxs56vbST3OAyMzXApj7I5Mn-p1Iummm5s
+ hash: v1.k794b7964.01b0ba3eef46ca6062549746c987d16be44d29b49a359b9d50f61b6a493f1282.XYFsMELihoJxhKSk1w5Dir9tjglJ7cuc53lrnpVO5GU
products-data-modeling-lineage-graph--selector-focus--dark:
- hash: v1.k794b7964.d3226e0d54f2c6a0fb7cbc6780adbf9f7e4297ab739c291be627c3c3b648fe70.IDq0v9lnIZuiJNAJVtEUOXYJRZZvBdp-mtGrFRhahno
+ hash: v1.k794b7964.8a4d94fd9e9218ed6d6c51add35561489602b263b639b8d3037d94c9c6c38cc5.4KGmwfgzcseL11b9Wkt3uAQ7CYcvWUhDD1ahUEcqUS0
products-data-modeling-lineage-graph--selector-focus--light:
- hash: v1.k794b7964.3d864c004ba10e4965d2dd21416e56c24ed0920a1947558f1637b4a4188c7f2d.Bq_kGJNOot-IwoTiPYugFocCo6kP5f8szxMmW38B4RY
+ hash: v1.k794b7964.ea66ffeafce86f35e88b88278d614e73b67a987603cc0fbeecc4e2fea3e0b709.g5XUGqtsw1n6fL5bbbaz8FyztTggLARgUUKsDlQ9QiI
products-data-modeling-lineage-graph--single-node--dark:
hash: v1.k794b7964.3a7800242792b8dd49d06a252b0ccf609de5be3bf5b077e28904ca2ef46b9150.3jN6spC1a4TJhjq6LOuaDGym92gQz9Xw2KUfy0Br-D8
products-data-modeling-lineage-graph--single-node--light: