{/if}
{#if hoveredEdge && hoveredEdgeText}
diff --git a/frontend/src/lib/components/assets/AssetGraph/AssetNode.svelte b/frontend/src/lib/components/assets/AssetGraph/AssetNode.svelte
index ede2f3815e..2163398372 100644
--- a/frontend/src/lib/components/assets/AssetGraph/AssetNode.svelte
+++ b/frontend/src/lib/components/assets/AssetGraph/AssetNode.svelte
@@ -7,7 +7,8 @@
import NodeActionsMenu from './NodeActionsMenu.svelte'
import NodeFixButton, { type NodeFix } from './NodeFixButton.svelte'
import NodeOnDot from './NodeOnDot.svelte'
- import PipelineInsertMenu, { type PipelineInsertPick } from './PipelineInsertMenu.svelte'
+ import AddDownstreamMenu from './AddDownstreamMenu.svelte'
+ import AddDownstreamPill from './AddDownstreamPill.svelte'
import {
ArrowUpRight,
Code2,
@@ -15,7 +16,6 @@
History,
Play,
Loader2,
- Plus,
ShieldCheck,
ShieldAlert,
CheckCircle2,
@@ -26,7 +26,6 @@
import type { ScriptLang } from '$lib/gen'
import { enterpriseLicense } from '$lib/stores'
import { sendUserToast, type Item } from '$lib/utils'
- import { PIPELINE_LANGUAGES } from './pipelineLanguages'
import type { PipelineOutputKind } from './pipelineTemplates'
import type { DbtAssetProvenance } from './types'
import DbtIcon from '$lib/components/icons/DbtIcon.svelte'
@@ -116,6 +115,9 @@
) => void
pathPrefix?: string
defaultPathSuffix?: string
+ /** Starts dragging the "+" onto a script (subscribing it to this asset)
+ * or onto the blank canvas (opening the add menu there). */
+ onStartFeedDrag?: (e: PointerEvent) => void
// Producer scripts/flows that write to this asset, supplied by
// the canvas from the graph's write/rw edges. Drives the on-hover
// "Run" button. Includes unsaved/draft producers so the button
@@ -212,18 +214,7 @@
}
}
- function handlePick(pick: PipelineInsertPick) {
- if (pick.kindId === 'pipeline_script' && pick.language && pick.path) {
- data.onAddScript?.(
- { kind: data.asset_kind, path: data.path },
- pick.language as ScriptLang,
- pick.path,
- (pick.outputKind ?? 'none') as PipelineOutputKind,
- pick.aiPrompt,
- { outputAsset: pick.outputAsset }
- )
- }
- }
+
// A red asset needs fixing where its error comes from, not a downstream step;
// and a step downstream of what nothing writes would never run on its writes.
@@ -669,41 +660,33 @@
script creation, half-overlapping it like the flow editor's
between-step inserter. -->
-
{#snippet trigger({ open })}
-
+
{/snippet}
-
+
{/if}
diff --git a/frontend/src/lib/components/assets/AssetGraph/assetsOnlyView.ts b/frontend/src/lib/components/assets/AssetGraph/assetsOnlyView.ts
index d9c102018c..ae1882243d 100644
--- a/frontend/src/lib/components/assets/AssetGraph/assetsOnlyView.ts
+++ b/frontend/src/lib/components/assets/AssetGraph/assetsOnlyView.ts
@@ -10,6 +10,8 @@ export type ViewEdge = {
unsaved?: boolean
/** Assets-only edges: the folded runnables the data goes through. */
via?: string[]
+ /** Assets-only edges: a write to the source reruns one of `via`. */
+ reactive?: boolean
}
/** The assets-only node standing for the scripts that build no asset. */
@@ -63,6 +65,9 @@ export function assetsOnlyView(
} else if (e.kind === 'trigger-native') push(triggersOf, e.target, e)
}
+ const triggered = new Set(
+ edges.filter((e) => e.kind === 'trigger-asset').map((e) => `${e.source}\n${e.target}`)
+ )
const out = new Map()
for (const [assetId, writes] of producersOf) {
for (const w of writes) {
@@ -72,8 +77,10 @@ export function assetsOnlyView(
const id = `flow:${r.source}->${assetId}`
const prev = out.get(id)
const unsaved = !!(w.unsaved || r.unsaved)
+ const reactive = triggered.has(`${r.source}\n${w.source}`)
if (prev) {
prev.unsaved = prev.unsaved && unsaved
+ prev.reactive ||= reactive
if (!prev.via?.includes(w.source)) prev.via = [...(prev.via ?? []), w.source]
} else {
out.set(id, {
@@ -82,6 +89,7 @@ export function assetsOnlyView(
target: assetId,
kind: 'asset-flow',
unsaved,
+ reactive,
via: [w.source]
})
}
@@ -136,8 +144,10 @@ export function assetsOnlyView(
for (const r of inputsOf.get(id) ?? []) {
const eid = `flow:${r.source}->${NO_ASSET_NODE_ID}`
const prev = out.get(eid)
+ const reactive = triggered.has(`${r.source}\n${id}`)
if (prev) {
prev.unsaved = prev.unsaved && !!r.unsaved
+ prev.reactive ||= reactive
if (!prev.via?.includes(id)) prev.via = [...(prev.via ?? []), id]
} else {
out.set(eid, {
@@ -146,6 +156,7 @@ export function assetsOnlyView(
target: NO_ASSET_NODE_ID,
kind: 'asset-flow',
unsaved: !!r.unsaved,
+ reactive,
via: [id]
})
}
diff --git a/frontend/src/lib/components/assets/AssetGraph/edgeDescription.test.ts b/frontend/src/lib/components/assets/AssetGraph/edgeDescription.test.ts
index a0dea60700..2aff7a0e81 100644
--- a/frontend/src/lib/components/assets/AssetGraph/edgeDescription.test.ts
+++ b/frontend/src/lib/components/assets/AssetGraph/edgeDescription.test.ts
@@ -46,6 +46,6 @@ describe('describeEdge', () => {
nameOf,
dataOf
)
- ).toEqual({ subject: 'clean', phrase: 'is built from', object: 'raw', note: 'By Clean.' })
+ ).toEqual({ subject: 'clean', phrase: 'is built from', object: 'raw', note: 'By Clean. A write to raw does not rerun it.' })
})
})
diff --git a/frontend/src/lib/components/assets/AssetGraph/edgeDescription.ts b/frontend/src/lib/components/assets/AssetGraph/edgeDescription.ts
index 486bd3dab5..4267dde92c 100644
--- a/frontend/src/lib/components/assets/AssetGraph/edgeDescription.ts
+++ b/frontend/src/lib/components/assets/AssetGraph/edgeDescription.ts
@@ -13,6 +13,7 @@ export type DescribedEdge = {
muted?: boolean
missing?: boolean
via?: string[]
+ reactive?: boolean
macro_names?: string[]
via_use?: boolean
}
@@ -71,15 +72,18 @@ export function describeEdge(
}
case 'asset-flow': {
const via = (e.via ?? []).map(nameOf).join(', ')
+ const rerun = e.reactive
+ ? `Each write to ${src} reruns it.`
+ : `A write to ${src} does not rerun it.`
// The scripts that build nothing only read: name them, not the node.
if (e.target === NO_ASSET_NODE_ID) {
- return { subject: src, phrase: 'is read by', object: via || tgt }
+ return { subject: src, phrase: 'is read by', object: via || tgt, note: rerun }
}
return {
subject: tgt,
phrase: 'is built from',
object: src,
- note: via ? `By ${via}.` : undefined
+ note: via ? `By ${via}. ${rerun}` : rerun
}
}
case 'dbt-ref':