mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-12 16:02:56 +00:00
feat: toggle to hide reads that don't trigger runs in the pipeline graph
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
a069f3c231
commit
7c840fb54e
@@ -25,6 +25,7 @@
|
||||
assetsOnlyView,
|
||||
upstreamDeletion,
|
||||
NO_ASSET_NODE_ID,
|
||||
withoutPassiveReads,
|
||||
type AssetUpstream,
|
||||
type AssetUpstreamDelete
|
||||
} from './assetsOnlyView'
|
||||
@@ -1359,7 +1360,21 @@
|
||||
}
|
||||
return { ...m, nodes, edges }
|
||||
}
|
||||
let view = $derived(assetsOnly ? assetsOnlyModel(model) : model)
|
||||
// Reads that start nothing (lookups, reference tables) are often most of a
|
||||
// graph's edges; hiding them leaves what makes the pipeline run. Remembered
|
||||
// across pipelines.
|
||||
const SHOW_PASSIVE_READS_KEY = 'pipeline-show-passive-reads'
|
||||
let showPassiveReads = $state(true)
|
||||
try {
|
||||
showPassiveReads = localStorage.getItem(SHOW_PASSIVE_READS_KEY) !== 'false'
|
||||
} catch {}
|
||||
let withoutPassive = $derived(withoutPassiveReads(model.nodes, model.edges))
|
||||
let shownModel = $derived(
|
||||
showPassiveReads || withoutPassive.dropped === 0
|
||||
? model
|
||||
: { ...model, nodes: withoutPassive.nodes, edges: withoutPassive.edges }
|
||||
)
|
||||
let view = $derived(assetsOnly ? assetsOnlyModel(shownModel) : shownModel)
|
||||
|
||||
// dbt association, surfaced by emphasis instead of edges. Hovering a model's
|
||||
// dbt badge lights up the project node that materializes it; hovering the
|
||||
@@ -1901,7 +1916,7 @@
|
||||
<PanToNode targetId={panToNodeId} {nodes} />
|
||||
<Controls position="top-right" orientation="horizontal" showLock={false} class="!mr-10" />
|
||||
{#if assetsOnlyToggle}
|
||||
<Panel position="top-left" class="!m-3">
|
||||
<Panel position="top-left" class="!m-3 flex flex-col gap-1.5">
|
||||
<Toggle
|
||||
checked={!assetsOnly}
|
||||
size="xs"
|
||||
@@ -1911,6 +1926,19 @@
|
||||
if (assetsOnlyFolder != undefined) setAssetsOnlyFolder(assetsOnlyFolder, assetsOnly)
|
||||
}}
|
||||
/>
|
||||
{#if withoutPassive.dropped > 0}
|
||||
<Toggle
|
||||
checked={showPassiveReads}
|
||||
size="xs"
|
||||
options={{ right: "Show reads that don't trigger runs" }}
|
||||
on:change={(e) => {
|
||||
showPassiveReads = e.detail
|
||||
try {
|
||||
localStorage.setItem(SHOW_PASSIVE_READS_KEY, String(e.detail))
|
||||
} catch {}
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</Panel>
|
||||
{/if}
|
||||
{#if showMinimap}
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
assetsOnlyView,
|
||||
upstreamDeletion,
|
||||
NO_ASSET_NODE_ID,
|
||||
withoutPassiveReads,
|
||||
type AssetUpstream
|
||||
} from './assetsOnlyView'
|
||||
|
||||
@@ -134,3 +135,28 @@ describe('upstreamDeletion', () => {
|
||||
expect(upstreamDeletion(u, script, all)).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('withoutPassiveReads', () => {
|
||||
it('drops reads that trigger nothing, and the assets only they drew', () => {
|
||||
const nodes = [
|
||||
node('asset:src', 'asset'),
|
||||
node('asset:lookup', 'asset'),
|
||||
node('asset:out', 'asset'),
|
||||
node('script:a', 'runnable')
|
||||
]
|
||||
const edges = [
|
||||
edge('asset:src', 'script:a', 'lineage-read'),
|
||||
edge('asset:src', 'script:a', 'trigger-asset'),
|
||||
edge('asset:lookup', 'script:a', 'lineage-read'),
|
||||
edge('asset:out', 'script:a', 'lineage-read'),
|
||||
edge('script:a', 'asset:out', 'lineage-write')
|
||||
]
|
||||
const r = withoutPassiveReads(nodes, edges)
|
||||
expect(r.nodes.map((n) => n.id)).toEqual(['asset:src', 'asset:out', 'script:a'])
|
||||
expect(r.edges.map((e) => e.id)).toEqual([
|
||||
'lineage-read:asset:src->script:a',
|
||||
'trigger-asset:asset:src->script:a',
|
||||
'lineage-write:script:a->asset:out'
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -186,3 +186,32 @@ export function upstreamDeletion(
|
||||
trigger: ownTrigger ? { kind, path: t.data.ref, draft: !!t.data.draft } : undefined
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The graph without its reads that start nothing: a read edge with no asset
|
||||
* trigger along it, and the assets only such reads drew.
|
||||
*/
|
||||
export function withoutPassiveReads<N extends ViewNode, E extends ViewEdge>(
|
||||
nodes: N[],
|
||||
edges: E[]
|
||||
): { nodes: N[]; edges: E[]; dropped: number } {
|
||||
const triggers = new Set(
|
||||
edges.filter((e) => e.kind === 'trigger-asset').map((e) => `${e.source}\n${e.target}`)
|
||||
)
|
||||
const passive = (e: E) =>
|
||||
e.kind === 'lineage-read' && !triggers.has(`${e.source}\n${e.target}`)
|
||||
const kept = edges.filter((e) => !passive(e))
|
||||
const dropped = edges.length - kept.length
|
||||
if (dropped === 0) return { nodes, edges, dropped }
|
||||
const linked = new Set(
|
||||
kept.filter((e) => e.kind !== 'add-anchor').flatMap((e) => [e.source, e.target])
|
||||
)
|
||||
const readOnly = new Set(
|
||||
edges.filter(passive).map((e) => e.source).filter((id) => !linked.has(id))
|
||||
)
|
||||
return {
|
||||
nodes: nodes.filter((n) => !readOnly.has(n.id)),
|
||||
edges: kept.filter((e) => !readOnly.has(e.source) && !readOnly.has(e.target)),
|
||||
dropped
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user