Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions frontend/snapshots.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6363,9 +6363,9 @@ snapshots:
products-data-catalog-metric-lineage--load-failed--light:
hash: v1.k794b7964.1b9c3b1720e0444a2f33b4ba6dc972f6a56a114c94be10cc77fa455b8441fbca.LUvQPwM50s6A-ZDh32zDhqhWWm5KAPgEFK2qa8ffmWs
products-data-catalog-metric-lineage--loading--dark:
hash: v1.k794b7964.10e5f42c7d9feef174fbf84585f42b3c023795a750dbbea10febeec15966f0d9.WQdI3QUiM3MPqu2jUswGuIkHtAjQlM-XV8dAV1Qpbmg
hash: v1.k794b7964.d2e01904e4c1ba9e222e434c70d459e1d4354b7cf5ec05f8e54aa17844b91fa3.ldvpgC3VPt5yjE4qd-lwTNdm3tfAhpCoWAGhMun3YWk
products-data-catalog-metric-lineage--loading--light:
hash: v1.k794b7964.5290922c579080221a18b00e7855f14d4fd4bdba8158fcb2acb0dcc1fcd1fb6c.N5PeHfKZdzMTWuAgku68dGntKgBb3tE0dqZbO6orPrY
hash: v1.k794b7964.fa63fb4b9b33a6c2cc7a7c22e3968c9f015b0e63e82996ea559b87fdea7797a0.RpSFIW0xf3AwRBHwe-Auvg-qR7JQHSMrhro-qOUhAzo
products-data-catalog-metric-lineage--no-definition--dark:
hash: v1.k794b7964.0a67016ff06498b8f16e83dcbd01d03ced850f02935d9cfc555c5d321a6dc21e.SYouGVS4FM4aPQFE51xlJG_1LPN79L4zsp_xwt4mRJI
products-data-catalog-metric-lineage--no-definition--light:
Expand All @@ -6390,6 +6390,18 @@ snapshots:
hash: v1.k794b7964.112213e8e69bef1f6e8aab90994d6e0be0c7fcb922965b6834c1081d3d3805c0.CDKiRu_VCNR1dBVF3-l8EfsSBvtbYuQPHWFYHyXbIoI
products-data-modeling-lineage-graph--full--light:
hash: v1.k794b7964.3d2a0a0a6ff2a27f3f8d682857757695b61970b3bfdc3f50e7508c86257aa4ad.S_I2CjkAMi3HiNyo014ZRrZHZbcDaVTQwF4718lZNws
products-data-modeling-lineage-graph--loading--dark:
hash: v1.k794b7964.37e743bd1659c207ae6da2e71d236547305a9956ac742799d8de1016d6136129.v6YYaaPBVxDTr4p6vGmQxUR35EzxaX_KryIe6cPHeHI
products-data-modeling-lineage-graph--loading--light:
hash: v1.k794b7964.799b736f8dfed7d406019308f305b3ce63ff6da574ebdad87d991d3c7bdb654d.H1HIvMH-fmzpbbYKKK3eJ1QhnHzPFV1Rifb2eIqRKUA
products-data-modeling-lineage-graph--loading-dark-mode--dark:
hash: v1.k794b7964.b4b4e7958ad0e3a27afee43b9617d7885fd4e02bc2edff68bc05598297159ef2.0AecY87D9zDsi6MBje5iYOSAbVAGSIkcJ8QZRH6V21Y
products-data-modeling-lineage-graph--loading-dark-mode--light:
hash: v1.k794b7964.9db1ad5713b6cdd0b0410f1c7859bee92d885c48f3400611673b50d0cfbdbe43.kR2brmUL-KkueOC8D8pqWJ9bzuTAVJrhRTxuC4fncJ4
products-data-modeling-lineage-graph--loading-focused--dark:
hash: v1.k794b7964.5c5253d7f45ff64b2a7de267d7f216b5dfbc6cebf566c64bb2804a15d49f6877.jipTXPSFWSQEENdldM5M1jViiEaBSPmHfbpMf8M_nx8
products-data-modeling-lineage-graph--loading-focused--light:
hash: v1.k794b7964.fe8f51a186a08326e770d97862c7f3edf4fa0d3bc477a9082be1db3bf6a36d24.1sIg57c84D-amSb_6VRD1ySV2WN-HbaeEToOy-e9YuM
products-data-modeling-lineage-graph--search-focus--dark:
hash: v1.k794b7964.50fc53d09a95dbfa156c1bb0234cb4ae94f1edad3c531971a6d29fc6e644792b.CnYgYXb_RjjTDPN13751BGVZ03jgtmKYiwd6IWXzvoE
products-data-modeling-lineage-graph--search-focus--light:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
tabbed?: boolean
}

export function QueryInfo({ tabId, view, tabbed = false }: QueryInfoProps): JSX.Element {

Check warning on line 38 in frontend/src/scenes/data-warehouse/editor/output-pane-tabs/QueryInfo.tsx

View workflow job for this annotation

GitHub Actions / Frontend formatting

lint:complexity

`QueryInfo` has cyclomatic complexity 40 (warn >10)
const {
editingView,
upstream: loadedUpstream,
Expand Down Expand Up @@ -150,7 +150,27 @@
upstream?.edges.length === 0 && (
<p className="text-secondary py-8 text-center">No connected models yet.</p>
)}
{targetView && upstreamLoading && <Spinner />}
{targetView && upstreamLoading && !upstream && (
<div
className={
tabbed
? 'h-[min(45vh,500px)] border border-border rounded-md overflow-hidden'
: 'h-[500px] border border-border rounded-md overflow-hidden'
}
>
<LineageGraph
nodes={[]}
edges={[]}
loading
loadingCenter={{
name: targetView.name,
type: targetView.is_materialized ? 'matview' : 'view',
}}
variant="full"
fitViewOptions={tabbed ? { maxZoom: 1 } : undefined}
/>
</div>
)}
{targetView && upstreamLoadFailed && !upstreamLoading && (
<LemonBanner
type="warning"
Expand Down
20 changes: 19 additions & 1 deletion products/data_catalog/frontend/MetricLineagePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
onEditDefinition: () => void
}

export function MetricLineagePanel({

Check warning on line 74 in products/data_catalog/frontend/MetricLineagePanel.tsx

View workflow job for this annotation

GitHub Actions / Frontend formatting

lint:complexity

`MetricLineagePanel` has cyclomatic complexity 12 (warn >10)
metric,
lineage,
lineageLoading,
Expand All @@ -92,7 +92,25 @@
}

if (lineageLoading && !lineage) {
return <LemonSkeleton className="h-64 w-full" />
return (
<div className="@container">
<span className="sr-only @[40rem]:hidden" role="status">
Loading lineage
</span>
<div className="@[40rem]:hidden" aria-hidden="true">
<LemonSkeleton className="h-64 w-full" />
</div>
<div className="hidden @[40rem]:block h-[min(45vh,500px)] border border-border rounded-md overflow-hidden">
<LineageGraph
nodes={[]}
edges={[]}
loading
loadingCenter={{ name: metric.name, type: 'metric' }}
variant="full"
/>
</div>
</div>
)
}

if (lineageProblem === 'not_ready') {
Expand Down
41 changes: 41 additions & 0 deletions products/data_modeling/frontend/lineage/LineageGraph.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ const meta: Meta<typeof LineageGraph> = {

export default meta

// The loading graph keeps its skeleton nodes on screen, so the test runner must not wait for them to go.
const LOADING_PARAMETERS = {
testOptions: { waitForLoadersToDisappear: false, waitForSelector: '.react-flow__node' },
}

export const Full: Story = {
render: () => (
<LineageGraph nodes={GRAPH_NODES} edges={GRAPH_EDGES} currentNodeId="4" variant="full" showControls />
Expand All @@ -121,6 +126,42 @@ export const Canvas: Story = {
),
}

export const Loading: Story = {
parameters: LOADING_PARAMETERS,
render: () => (
<LineageGraph
nodes={GRAPH_NODES}
edges={GRAPH_EDGES}
loading
variant="canvas"
showControls
showMinimap
panels={<span>Graph tools</span>}
/>
),
}

export const LoadingFocused: Story = {
parameters: LOADING_PARAMETERS,
render: () => (
<LineageGraph
nodes={GRAPH_NODES}
edges={GRAPH_EDGES}
loading
loadingCenter={{ name: 'revenue_summary', type: 'matview' }}
variant="full"
showControls
showMinimap
panels={<span>Graph tools</span>}
/>
),
}

export const LoadingDarkMode: Story = {
...LoadingFocused,
globals: { theme: 'dark' },
}

export const SingleNode: Story = {
render: () => <LineageGraph nodes={[mockNode({ id: '1', name: 'raw_events', type: 'table' })]} edges={[]} />,
}
Expand Down
24 changes: 17 additions & 7 deletions products/data_modeling/frontend/lineage/LineageGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
import { ReactNode, useEffect } from 'react'

import { IconArchive } from '@posthog/icons'
import { Spinner } from '@posthog/lemon-ui'

import { themeLogic } from '~/layout/navigation-3000/themeLogic'
import { DataModelingEdge, DataModelingNode } from '~/types'

import { ElkDirection } from './autolayout'
import { LineageGraphLoading } from './LineageGraphLoading'
import { lineageGraphLogic } from './lineageGraphLogic'
import { LINEAGE_NODE_TYPES, LineageNodeCallbacks, LineageNodeState, LineageVariant } from './LineageNode'

Expand All @@ -44,6 +44,7 @@
showControls?: boolean
className?: string
loading?: boolean
loadingCenter?: Pick<DataModelingNode, 'name' | 'type'>
emptyMessage?: string
/** Per-node visual state (running, dimmed, highlighted), computed by the caller */
nodeState?: (node: DataModelingNode) => LineageNodeState
Expand All @@ -56,7 +57,7 @@
panelPosition?: PanelPosition
}

function LineageGraphContent(props: LineageGraphProps): JSX.Element {

Check warning on line 60 in products/data_modeling/frontend/lineage/LineageGraph.tsx

View workflow job for this annotation

GitHub Actions / Frontend formatting

lint:complexity

`LineageGraphContent` has cyclomatic complexity 17 (warn >10)
const { fitView, viewportInitialized } = useReactFlow()
const { isDarkModeOn } = useValues(themeLogic)
const { currentNodeId, nodeState, nodeCallbacks, onNodeClick, focusNodeIds, searchFocusRequest } = props
Expand Down Expand Up @@ -97,10 +98,14 @@
}, [fitView, viewportInitialized, searchFocusRequest, layout])

if (!layout) {
const center = props.loadingCenter ?? props.nodes.find((node) => node.id === currentNodeId)
return (
<div className="flex items-center justify-center w-full h-full">
<Spinner />
</div>
<LineageGraphLoading
center={center}
direction={props.direction ?? 'RIGHT'}
fitViewOptions={props.fitViewOptions}
variant={props.variant ?? 'full'}
/>
)
}

Expand Down Expand Up @@ -159,9 +164,14 @@
export function LineageGraph(props: LineageGraphProps): JSX.Element {
if (props.loading) {
return (
<div className="flex items-center justify-center w-full h-full">
<Spinner />
</div>
<ReactFlowProvider>
<LineageGraphLoading
center={props.loadingCenter}
direction={props.direction ?? 'RIGHT'}
fitViewOptions={props.fitViewOptions}
variant={props.variant ?? 'full'}
/>
</ReactFlowProvider>
)
}
if (props.nodes.length === 0) {
Expand Down
160 changes: 160 additions & 0 deletions products/data_modeling/frontend/lineage/LineageGraphLoading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import { Background, BackgroundVariant, FitViewOptions, ReactFlow, useReactFlow } from '@xyflow/react'
import { useValues } from 'kea'
import { useEffect, useId, useMemo } from 'react'

import { themeLogic } from '~/layout/navigation-3000/themeLogic'
import { DataModelingEdge, DataModelingNode } from '~/types'

import { ElkDirection } from './autolayout'
import { initialLineageGraphLayout, lineageGraphLogic } from './lineageGraphLogic'
import { LINEAGE_NODE_TYPES, LineageVariant } from './LineageNode'

export interface LineageGraphLoadingProps {
center?: Pick<DataModelingNode, 'name' | 'type'>
direction: ElkDirection
fitViewOptions?: FitViewOptions
variant: LineageVariant
}

function loadingGraph(
idPrefix: string,
center?: Pick<DataModelingNode, 'name' | 'type'>
): {
nodes: DataModelingNode[]
edges: DataModelingEdge[]
centerNodeId?: string
} {
const dag = 'lineage-loading'
const node = (id: string, name: string, type: DataModelingNode['type']): DataModelingNode => ({
id,
name,
type,
dag,
created_at: '',
updated_at: '',
upstream_count: 0,
downstream_count: 0,
})
const edge = (id: string, source_id: string, target_id: string): DataModelingEdge => ({
id,
source_id,
target_id,
dag,
properties: {},
created_at: '',
updated_at: '',
})
const upstreamId = `${idPrefix}-upstream`
const centerNodeId = `${idPrefix}-center`
const downstreamId = `${idPrefix}-downstream`

if (!center) {
return {
nodes: [node(upstreamId, '', 'view'), node(downstreamId, '', 'view')],
edges: [edge(`${idPrefix}-edge`, upstreamId, downstreamId)],
}
}

return {
centerNodeId,
nodes: [
node(upstreamId, 'Loading upstream...', 'table'),
node(centerNodeId, center.name, center.type),
node(downstreamId, 'Loading downstream...', 'view'),
],
edges: [
edge(`${idPrefix}-upstream-edge`, upstreamId, centerNodeId),
edge(`${idPrefix}-downstream-edge`, centerNodeId, downstreamId),
],
}
}

export function LineageGraphLoading({
center,
direction,
fitViewOptions,
variant,
}: LineageGraphLoadingProps): JSX.Element {
const { fitView, viewportInitialized } = useReactFlow()
const { isDarkModeOn } = useValues(themeLogic)
const reactId = useId()
const idPrefix = useMemo(() => `lineage-loading-${reactId.replaceAll(':', '')}`, [reactId])
const graph = useMemo(() => loadingGraph(idPrefix, center), [center?.name, center?.type, idPrefix])
const { layout } = useValues(
lineageGraphLogic({
nodes: graph.nodes,
edges: graph.edges,
variant,
direction,
})
)
const initialLayout = useMemo(
() => initialLineageGraphLayout(graph.nodes, graph.edges, variant, direction),
[graph, variant, direction]
)
const displayedLayout = layout ?? initialLayout
const loadingFitViewOptions = useMemo(
() => ({
...fitViewOptions,
maxZoom: Math.min(fitViewOptions?.maxZoom ?? 1, 1),
}),
[fitViewOptions]
)

useEffect(() => {
if (viewportInitialized) {
void fitView({
...loadingFitViewOptions,
nodes: displayedLayout.nodes,
padding: loadingFitViewOptions.padding ?? 0.2,
duration: 0,
})
}
}, [displayedLayout, fitView, loadingFitViewOptions, viewportInitialized])

const nodes = displayedLayout.nodes.map((node) => ({
...node,
data: {
...node.data,
state: {
loading: node.id === graph.centerNodeId && center ? ('focus' as const) : ('placeholder' as const),
},
callbacks: {},
},
}))
const edges = displayedLayout.edges.map((edge) => ({
...edge,
className: 'opacity-50',
}))

return (
<>
<span className="sr-only" role="status">
Loading lineage
</span>
<ReactFlow
aria-hidden="true"
colorMode={isDarkModeOn ? 'dark' : 'light'}
nodes={nodes}
edges={edges}
nodeTypes={LINEAGE_NODE_TYPES}
nodesDraggable={false}
nodesConnectable={false}
nodesFocusable={false}
elementsSelectable={false}
fitView
fitViewOptions={loadingFitViewOptions}
minZoom={0.1}
maxZoom={1}
zoomOnScroll={false}
panOnScroll={false}
panOnDrag={false}
zoomOnPinch={false}
zoomOnDoubleClick={false}
proOptions={{ hideAttribution: true }}
>
<Background variant={BackgroundVariant.Dots} gap={20} size={1} />
</ReactFlow>
</>
)
}
Loading
Loading