feat(frontend): dataflow

This commit is contained in:
Faton Ramadani
2024-08-12 11:54:29 +02:00
parent 4170db79f5
commit 76fea32da0
7 changed files with 189 additions and 29 deletions
@@ -30,6 +30,8 @@
import EmptyEdge from './renderers/edges/EmptyEdge.svelte'
import { sugiyama, dagStratify, decrossOpt, coordCenter } from 'd3-dag'
import { Expand } from 'lucide-svelte'
import Toggle from '../Toggle.svelte'
import DataflowEdge from './renderers/edges/DataflowEdge.svelte'
export let success: boolean | undefined = undefined
export let modules: FlowModule[] | undefined = []
@@ -54,10 +56,13 @@
undefined
)
let useDataflow: Writable<boolean | undefined> = writable<boolean | undefined>(false)
setContext<{
selectedId: Writable<string | undefined>
flowInputsStore: Writable<FlowInput | undefined>
}>('FlowGraphContext', { selectedId, flowInputsStore })
useDataflow: Writable<boolean | undefined>
}>('FlowGraphContext', { selectedId, flowInputsStore, useDataflow })
const dispatch = createEventDispatcher()
@@ -155,7 +160,9 @@
dispatch('selectIteration', { ...detail, moduleId: moduleId })
}
},
success
success,
$useDataflow,
$selectedId
)
const nodes = writable<Node[]>([])
@@ -182,7 +189,8 @@
const edgeTypes = {
edge: BaseEdge,
empty: EmptyEdge
empty: EmptyEdge,
dataflowedge: DataflowEdge
} as any
const proOptions = { hideAttribution: true }
@@ -232,6 +240,25 @@
</ControlButton>
{/if}
</Controls>
<Controls
position="top-left"
orientation="horizontal"
showLock={false}
showZoom={false}
showFitView={false}
>
<Toggle
value={$useDataflow}
on:change={() => {
$useDataflow = !$useDataflow
}}
size="xs"
options={{
right: 'Dataflow'
}}
/>
</Controls>
</SvelteFlow>
</div>
@@ -0,0 +1,11 @@
## Rendering
- Nodes [x]
- Edges [x]
- Insert button [x]
- AI button [x]
- Delete branch button [x]
- Insert branch button [x]
- Graph actions [x]
## Functionality
@@ -1,5 +1,7 @@
import type { FlowModule } from '$lib/gen'
import { type Node, type Edge } from '@xyflow/svelte'
import { getDependeeAndDependentComponents } from '../flows/flowExplorer'
import { dfsByModule } from '../flows/previousResults'
export type GraphEventHandlers = {
insert: (detail) => void
@@ -16,7 +18,9 @@ export default function graphBuilder(
extra: Record<string, any>,
failureModule: FlowModule | undefined,
eventHandlers: GraphEventHandlers,
success: boolean | undefined
success: boolean | undefined,
useDataflow: boolean | undefined,
selectedId: string | undefined
): {
nodes: Node[]
edges: Edge[]
@@ -49,7 +53,13 @@ export default function graphBuilder(
const parents: { [key: string]: string[] } = {}
function addEdge(sourceId: string, targetId: string, customId?: string, type?: string) {
function addEdge(
sourceId: string,
targetId: string,
customId?: string,
type?: string,
offset?: number
) {
parents[targetId] = [...(parents[targetId] ?? []), sourceId]
edges.push({
@@ -59,13 +69,16 @@ export default function graphBuilder(
type: type ?? 'edge',
data: {
insertable: extra.insertable,
modules
modules,
sourceId,
targetId,
offset
}
})
}
const inputNode: Node = {
id: 'input',
id: 'Input',
position: { x: -1, y: -1 },
type: 'input2',
data: {
@@ -280,5 +293,44 @@ export default function graphBuilder(
}
})
// DATAFLOW
if (useDataflow && selectedId) {
let deps = getDependeeAndDependentComponents(selectedId, modules ?? [], failureModule)
if (deps) {
Object.entries(deps.dependees).forEach((x, i) => {
const inputs = x[1]
inputs?.forEach((input, index) => {
let pid = x[0]
if (input?.startsWith('flow_input.iter')) {
const parent = dfsByModule(selectedId!, modules ?? [])?.pop()
if (parent?.id) {
pid = parent.id
}
}
addEdge(
pid,
selectedId!,
`dep-${pid}-${selectedId}-${input}-${index}`,
'dataflowedge',
i * 20
)
})
})
Object.entries(deps.dependents).forEach((x, i) => {
let pid = x[0]
console.log('offset', i * 10)
addEdge(selectedId!, pid, `dep-${selectedId}-${pid}-${i}`, 'dataflowedge', i * 10)
})
}
}
return { nodes, edges }
}
@@ -1,13 +1,9 @@
<script lang="ts">
import InsertModuleButton from '$lib/components/flows/map/InsertModuleButton.svelte'
import type { FlowModule } from '$lib/gen/models/FlowModule'
import {
getBezierPath,
BaseEdge,
type Position,
EdgeLabelRenderer
// @ts-ignore
} from '@xyflow/svelte'
import { getBezierPath, BaseEdge, type Position, EdgeLabelRenderer } from '@xyflow/svelte'
import { getContext } from 'svelte'
import type { Writable } from 'svelte/store'
export let sourceX: number
export let sourceY: number
@@ -16,7 +12,6 @@
export let targetY: number
export let targetPosition: Position
export let markerEnd: string | undefined = undefined
export let style: string | undefined = undefined
export let data: {
insertable: boolean
@@ -41,10 +36,14 @@
targetY - sourceY > 100
? `${edgePath} ${getStraightLinePath({ sourceX, sourceY, targetX, targetY })}`
: edgePath
const { useDataflow } = getContext<{
useDataflow: Writable<boolean | undefined>
}>('FlowGraphContext')
</script>
<EdgeLabelRenderer>
{#if data?.insertable}
{#if data?.insertable && !$useDataflow}
<div
class="edgeButtonContainer nodrag nopan"
style:transform="translate(-50%, -50%) translate({labelX}px,{labelY}px)"
@@ -53,7 +52,8 @@
</div>
{/if}
</EdgeLabelRenderer>
<BaseEdge path={completeEdge} {markerEnd} {style} />
<BaseEdge path={completeEdge} {markerEnd} class={$useDataflow ? 'hidden' : ''} />
<style>
.edgeButtonContainer {
@@ -0,0 +1,66 @@
<script lang="ts">
import type { FlowModule } from '$lib/gen/models/FlowModule'
import { getBezierPath, BaseEdge, type Position, EdgeLabelRenderer } from '@xyflow/svelte'
export let sourceX: number
export let sourceY: number
export let sourcePosition: Position
export let targetX: number
export let targetY: number
export let targetPosition: Position
export let markerEnd: string | undefined = undefined
export let data: {
insertable: boolean
modules: FlowModule[]
sourceId: string
targetId: string
offset: number
}
$: [edgePath, labelX, labelY] = getBezierPath({
sourceX,
sourceY: targetY - sourceY > 100 ? targetY - 100 : sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
curvature: 0.1
})
function getStraightLinePath({ sourceX, sourceY, targetX, targetY }) {
return `M${sourceX},${sourceY} L${sourceX},${targetY - 100}`
}
$: completeEdge =
targetY - sourceY > 100
? `${edgePath} ${getStraightLinePath({ sourceX, sourceY, targetX, targetY })}`
: edgePath
</script>
<EdgeLabelRenderer>
{#if data?.insertable}
<div
class="edgeButtonContainer nodrag nopan bg-surface-selected p-1 border text-xs"
style:transform="translate(-50%, -50%) translate({labelX}px,{labelY}px)"
>
{data.sourceId} -> {data.targetId}
</div>
{/if}
</EdgeLabelRenderer>
<BaseEdge
path={completeEdge}
{markerEnd}
style={`animation:dashdraw 0.5s linear infinite; stroke-dasharray: 5px;`}
/>
<style>
.edgeButtonContainer {
position: absolute;
font-size: 12pt;
/* everything inside EdgeLabelRenderer has no pointer events by default */
/* if you have an interactive element, set pointer-events: all */
pointer-events: all;
}
</style>
@@ -2,20 +2,23 @@
import {
getBezierPath,
BaseEdge,
type EdgeProps
type Position
// @ts-ignore
} from '@xyflow/svelte'
import { getContext } from 'svelte'
import type { Writable } from 'svelte/store'
type $$Props = EdgeProps
export let sourceX: number
export let sourceY: number
export let sourcePosition: Position
export let targetX: number
export let targetY: number
export let targetPosition: Position
export let markerEnd: string | undefined = undefined
export let sourceX: $$Props['sourceX']
export let sourceY: $$Props['sourceY']
export let sourcePosition: $$Props['sourcePosition']
export let targetX: $$Props['targetX']
export let targetY: $$Props['targetY']
export let targetPosition: $$Props['targetPosition']
export let markerEnd: $$Props['markerEnd'] = undefined
export let style: $$Props['style'] = undefined
const { useDataflow } = getContext<{
useDataflow: Writable<boolean | undefined>
}>('FlowGraphContext')
$: [edgePath] = getBezierPath({
sourceX,
@@ -27,4 +30,4 @@
})
</script>
<BaseEdge path={edgePath} {markerEnd} {style} />
<BaseEdge path={edgePath} {markerEnd} class={$useDataflow ? 'hidden' : ''} />
@@ -104,6 +104,7 @@
title="Add branch"
on:click={() => {
dispatch('insert', { modules: data.modules, index: idx, detail: 'move' })
//data?.eventHandlers?.insert()
}}
type="button"
disabled={data.wrapperId === data.moving}
@@ -121,7 +122,7 @@
<button
class="rounded-full border hover:bg-surface-hover bg-surface p-1"
on:click={() => {
dispatch('addBranch')
data?.eventHandlers?.newBranch(data.module)
}}
>
<GitBranchPlus size={16} />