diff --git a/frontend/src/lib/components/assets/AssetGraph/AssetGraphCanvas.svelte b/frontend/src/lib/components/assets/AssetGraph/AssetGraphCanvas.svelte
index 2a5988122e..dac7d93d98 100644
--- a/frontend/src/lib/components/assets/AssetGraph/AssetGraphCanvas.svelte
+++ b/frontend/src/lib/components/assets/AssetGraph/AssetGraphCanvas.svelte
@@ -1021,7 +1021,21 @@
? undefined
: { none: true as const }
: u.multiple || !r
- ? { multiple: true as const }
+ ? {
+ multiple: true as const,
+ scripts: (u.multiple ? u.runnableIds : [])
+ .map((id) => runnables.get(id)?.data)
+ .filter((d) => d != undefined)
+ .map((d) => ({
+ runnableId: `${d.runnable_kind}:${d.path}`,
+ path: d.path as string,
+ summary: d.summary as string | undefined,
+ language: d.language,
+ unsaved: d.unsaved as boolean | undefined,
+ onOpen: () =>
+ onselect?.({ kind: 'runnable', runnable_kind: d.runnable_kind, path: d.path })
+ }))
+ }
: {
runnableId: u.runnableId,
path: r.path,
@@ -1059,7 +1073,8 @@
? 'Multiple upstream nodes'
: `${upstream.trigger.label}${upstream.trigger.draft ? ' · draft' : ''}`,
runState: 'runState' in upstream && !!upstream.runState,
- scriptChip: 'runnableId' in upstream
+ scriptChips:
+ 'runnableId' in upstream ? 1 : 'scripts' in upstream ? (upstream.scripts?.length ?? 0) : 0
})
: undefined
return {
@@ -1218,7 +1233,15 @@
// never re-runs the layout.
const up = n.type === 'asset' ? n.data.upstream : undefined
const data =
- up?.runnableId !== undefined
+ up?.scripts
+ ? {
+ ...n.data,
+ upstream: {
+ ...up,
+ selected: up.scripts.some((sc: { runnableId: string }) => sc.runnableId === selectedId)
+ }
+ }
+ : up?.runnableId !== undefined
? {
...n.data,
upstream: {
diff --git a/frontend/src/lib/components/assets/AssetGraph/AssetGraphDetailsPane.svelte b/frontend/src/lib/components/assets/AssetGraph/AssetGraphDetailsPane.svelte
index 00c14ad4e8..af6f30a0bc 100644
--- a/frontend/src/lib/components/assets/AssetGraph/AssetGraphDetailsPane.svelte
+++ b/frontend/src/lib/components/assets/AssetGraph/AssetGraphDetailsPane.svelte
@@ -20,8 +20,11 @@
SquareFunction,
Trash2,
X,
- Pencil
+ Pencil,
+ ChevronDown
} from 'lucide-svelte'
+ import DropdownV2 from '$lib/components/DropdownV2.svelte'
+ import { upstreamScriptItems, type UpstreamScript } from './upstreamScriptItems'
import { inferArgs } from '$lib/infer'
import { emptySchema, sendUserToast } from '$lib/utils'
import type { Schema } from '$lib/common'
@@ -157,6 +160,10 @@
path: string
unsaved?: boolean
}>
+ /** The selected asset's producing scripts, for its "Edit script" action,
+ * which calls `onEditScript` with the one picked. */
+ producerScripts?: UpstreamScript[]
+ onEditScript?: (path: string) => void
// Pipeline-wide column-lineage graph (built by the parent page from the
// resolved graph). Drives the transitive column-lineage trace shown for a
// selected materialized asset.
@@ -305,6 +312,8 @@
onScriptRenamed,
onScriptRemoved,
selectionProducers = [],
+ producerScripts = [],
+ onEditScript,
selectionColumnGraph,
selectionColumnLoading = false,
selectionColumnTruncated = false,
@@ -1018,6 +1027,36 @@
{/if}
+ {#if selection?.kind === 'asset' && onEditScript && producerScripts.length === 1}
+
+ {:else if selection?.kind === 'asset' && onEditScript && producerScripts.length > 1}
+
+ {#snippet buttonReplacement()}
+
+ {/snippet}
+
+ {/if}
{#if readOnly && onRequestEdit}