mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-12 00:06:14 +00:00
Asset nodes
This commit is contained in:
@@ -143,7 +143,6 @@
|
||||
let flowStateStore = $derived(flowEditorContext?.flowStateStore)
|
||||
|
||||
let assets = $derived(id ? $flowStateStore?.[id]?.assetsCache : undefined)
|
||||
let containsSelectedAsset = $derived(assets?.some((a) => assetEq(a, selectedAssetStore?.val)))
|
||||
|
||||
let stepHistoryLoader = getStepHistoryLoaderContext()
|
||||
|
||||
@@ -276,8 +275,7 @@
|
||||
class={classNames(
|
||||
'w-full module flex rounded-sm cursor-pointer max-w-full ',
|
||||
'flex relative',
|
||||
deletable ? aiModuleActionToBgColor(action) : '',
|
||||
containsSelectedAsset ? '!bg-surface-hover' : ''
|
||||
deletable ? aiModuleActionToBgColor(action) : ''
|
||||
)}
|
||||
style="width: 275px; height: 34px; background-color: {hover && bgHoverColor
|
||||
? bgHoverColor
|
||||
@@ -292,8 +290,7 @@
|
||||
<div
|
||||
class={classNames(
|
||||
'absolute rounded-sm outline-offset-0 outline-slate-500 dark:outline-gray-400',
|
||||
selected || containsSelectedAsset ? 'outline outline-2' : 'active:outline active:outline-2',
|
||||
containsSelectedAsset ? 'outline-slate-600 dark:outline-gray-300' : ''
|
||||
selected ? 'outline outline-2' : 'active:outline active:outline-2'
|
||||
)}
|
||||
style={`width: 275px; height: ${outputPickerVisible ? (outputPickerBarOpen ? '51px' : '35px') : '34px'};`}
|
||||
></div>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
import {
|
||||
graphBuilder,
|
||||
isTriggerStep,
|
||||
type AssetN,
|
||||
type InlineScript,
|
||||
type InsertKind,
|
||||
type NodeLayout,
|
||||
@@ -50,11 +51,18 @@
|
||||
import SubflowBound from './renderers/nodes/SubflowBound.svelte'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import ViewportResizer from './ViewportResizer.svelte'
|
||||
import type { FlowEditorContext } from '../flows/types'
|
||||
import AssetNode from './renderers/nodes/AssetNode.svelte'
|
||||
import { formatAsset } from '../assets/lib'
|
||||
|
||||
let useDataflow: Writable<boolean | undefined> = writable<boolean | undefined>(false)
|
||||
|
||||
const triggerContext = getContext<TriggerContext>('TriggerContext')
|
||||
|
||||
const flowEditorContextOpt: FlowEditorContext | undefined =
|
||||
getContext<FlowEditorContext>('FlowEditorContext')
|
||||
const flowStateStoreOpt = flowEditorContextOpt.flowStateStore
|
||||
|
||||
let fullWidth = 0
|
||||
let width = $state(0)
|
||||
|
||||
@@ -220,9 +228,11 @@
|
||||
.decross(nodes.length > 20 ? decrossTwoLayer() : decrossOpt())
|
||||
.coord(coordCenter())
|
||||
.nodeSize((d) => {
|
||||
const id: string | undefined = d?.data?.['id'] ?? ''
|
||||
const assetOffset = $flowStateStoreOpt?.[id]?.assetsCache?.length ? 100 : 0
|
||||
return [
|
||||
(nodeWidths[d?.data?.['id'] ?? ''] ?? 1) * (NODE.width + NODE.gap.horizontal * 1),
|
||||
NODE.height + NODE.gap.vertical
|
||||
(nodeWidths[id] ?? 1) * (NODE.width + NODE.gap.horizontal * 1),
|
||||
NODE.height + NODE.gap.vertical + assetOffset
|
||||
] as readonly [number, number]
|
||||
})
|
||||
boxSize = layout(dag as any)
|
||||
@@ -256,6 +266,55 @@
|
||||
return newNodes
|
||||
}
|
||||
|
||||
function computeAssetNodes(nodes: Node[]) {
|
||||
const ASSET_X_GAP = 20
|
||||
const ASSET_WIDTH = 180
|
||||
const ASSET_Y_OFFSET = 55
|
||||
return nodes.flatMap((node) => {
|
||||
const assets = $flowStateStoreOpt?.[node.id]?.assetsCache
|
||||
const assetNodes = assets?.map(
|
||||
(asset, assetIdx) =>
|
||||
({
|
||||
id: `${node.id}-asset-${formatAsset(asset)}`,
|
||||
type: 'asset',
|
||||
data: { asset },
|
||||
position: {
|
||||
x:
|
||||
(ASSET_WIDTH + ASSET_X_GAP) * (assetIdx - assets.length / 2) +
|
||||
(NODE.width + ASSET_X_GAP) / 2,
|
||||
y: ASSET_Y_OFFSET
|
||||
},
|
||||
parentId: node.id,
|
||||
width: ASSET_WIDTH
|
||||
}) satisfies Node & AssetN
|
||||
)
|
||||
return assetNodes ?? []
|
||||
})
|
||||
}
|
||||
|
||||
function computeAssetEdges(edges: Edge[], assetNodes: (Node & AssetN)[]): Edge[] {
|
||||
return assetNodes.map(
|
||||
(n) =>
|
||||
({
|
||||
id: `${n.id}-edge`,
|
||||
source: n.parentId ?? '',
|
||||
target: n.id,
|
||||
type: 'empty',
|
||||
data: {
|
||||
insertable: false,
|
||||
sourceId: n.id,
|
||||
targetId: n.parentId,
|
||||
moving: moving,
|
||||
eventHandlers: eventHandler,
|
||||
index: 0,
|
||||
enableTrigger: false,
|
||||
disableAi: disableAi,
|
||||
disableMoveIds: []
|
||||
}
|
||||
}) satisfies Edge
|
||||
)
|
||||
}
|
||||
|
||||
let eventHandler = {
|
||||
deleteBranch: (detail, label) => {
|
||||
$selectedId = label
|
||||
@@ -344,7 +403,9 @@
|
||||
let newGraph = graph
|
||||
|
||||
nodes = layoutNodes(newGraph.nodes)
|
||||
edges = newGraph.edges
|
||||
const assetNodes = computeAssetNodes(nodes)
|
||||
nodes = [...nodes, ...assetNodes]
|
||||
edges = [...newGraph.edges, ...computeAssetEdges(newGraph.edges, assetNodes)]
|
||||
await tick()
|
||||
height = Math.max(...nodes.map((n) => n.position.y + NODE.height + 100), minHeight)
|
||||
}
|
||||
@@ -363,7 +424,8 @@
|
||||
branchOneEnd: BranchOneEndNode,
|
||||
subflowBound: SubflowBound,
|
||||
noBranch: NoBranchNode,
|
||||
trigger: TriggersNode
|
||||
trigger: TriggersNode,
|
||||
asset: AssetNode
|
||||
} as any
|
||||
|
||||
const edgeTypes = {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { getDependeeAndDependentComponents } from '../flows/flowExplorer'
|
||||
import { dfsByModule } from '../flows/previousResults'
|
||||
import { defaultIfEmptyString } from '$lib/utils'
|
||||
import type { GraphModuleState } from './model'
|
||||
import type { Asset } from '../assets/lib'
|
||||
|
||||
export type InsertKind =
|
||||
| 'script'
|
||||
@@ -90,6 +91,7 @@ export type FlowNode =
|
||||
| SubflowBoundN
|
||||
| NoBranchN
|
||||
| TriggerN
|
||||
| AssetN
|
||||
|
||||
export type InputN = {
|
||||
type: 'input2'
|
||||
@@ -256,6 +258,13 @@ export type TriggerN = {
|
||||
}
|
||||
}
|
||||
|
||||
export type AssetN = {
|
||||
type: 'asset'
|
||||
data: {
|
||||
asset: Asset
|
||||
}
|
||||
}
|
||||
|
||||
// input2: InputNode,
|
||||
// module: ModuleNode,
|
||||
// branchAllStart: BranchAllStart,
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<script lang="ts">
|
||||
import NodeWrapper from './NodeWrapper.svelte'
|
||||
import type { AssetN } from '../../graphBuilder.svelte'
|
||||
import { Pyramid } from 'lucide-svelte'
|
||||
import { assetEq, formatAsset } from '$lib/components/assets/lib'
|
||||
import { getContext } from 'svelte'
|
||||
import type { FlowEditorContext } from '$lib/components/flows/types'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
interface Props {
|
||||
data: AssetN['data']
|
||||
}
|
||||
|
||||
const { selectedAssetStore } = getContext<FlowEditorContext>('FlowEditorContext') ?? {}
|
||||
let { data }: Props = $props()
|
||||
const isSelected = $derived(assetEq(selectedAssetStore.val, data.asset))
|
||||
</script>
|
||||
|
||||
<NodeWrapper>
|
||||
{#snippet children({ darkMode })}
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
class={twMerge(
|
||||
'bg-surface py-1 px-1.5 flex gap-1.5 rounded-sm text-tertiary border',
|
||||
isSelected ? 'bg-surface-hover border-surface-inverse' : 'border-transparent'
|
||||
)}
|
||||
onmouseenter={() => (selectedAssetStore.val = data.asset)}
|
||||
onmouseleave={() => (selectedAssetStore.val = undefined)}
|
||||
>
|
||||
<Pyramid size={16} class="shrink-0" />
|
||||
<span class="text-3xs truncate">
|
||||
{formatAsset(data.asset)}
|
||||
</span>
|
||||
</div>
|
||||
{/snippet}
|
||||
</NodeWrapper>
|
||||
Reference in New Issue
Block a user