mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-04 16:03:06 +00:00
Add graph logic to simplify display
This commit is contained in:
@@ -139,7 +139,7 @@
|
||||
style="width: 275px; height: 34px; background-color: {bgColor};"
|
||||
on:mouseenter={() => (hover = true)}
|
||||
on:mouseleave={() => (hover = false)}
|
||||
on:click
|
||||
on:click|preventDefault|stopPropagation
|
||||
>
|
||||
<div class="absolute text-sm right-12 -bottom-3 flex flex-row gap-1 z-10">
|
||||
{#if retry}
|
||||
|
||||
@@ -256,6 +256,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
$: console.log('has schedule poll', hasSchedulePoll)
|
||||
</script>
|
||||
|
||||
<Portal name="flow-module">
|
||||
@@ -458,6 +459,9 @@
|
||||
on:addSchedulePoll={() => {
|
||||
hasSchedulePoll = true
|
||||
}}
|
||||
on:removeSchedulePoll={() => {
|
||||
hasSchedulePoll = false
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
import Button from '../common/button/Button.svelte'
|
||||
import FlowYamlEditor from '../flows/header/FlowYamlEditor.svelte'
|
||||
import SchedulePollNode from './renderers/nodes/ShedulePollNode.svelte'
|
||||
import tr from 'date-fns/locale/tr'
|
||||
export let success: boolean | undefined = undefined
|
||||
export let modules: FlowModule[] | undefined = []
|
||||
export let failureModule: FlowModule | undefined = undefined
|
||||
@@ -177,6 +178,9 @@
|
||||
},
|
||||
addSchedulePoll: () => {
|
||||
dispatch('addSchedulePoll')
|
||||
},
|
||||
removeSchedulePoll: () => {
|
||||
dispatch('removeSchedulePoll')
|
||||
}
|
||||
},
|
||||
success,
|
||||
@@ -201,12 +205,139 @@
|
||||
|
||||
let height = 0
|
||||
|
||||
function removeInputNode(nodes, edges, id) {
|
||||
const inputNode = nodes.find((node) => node.id === id)
|
||||
if (!inputNode) return { nodes, edges }
|
||||
|
||||
// Find edges connected to the input node
|
||||
const connectedEdges = edges.filter((edge) => edge.source === id || edge.target === id)
|
||||
|
||||
// Remove the input node
|
||||
let updatedNodes = nodes.filter((node) => node.id !== id)
|
||||
|
||||
// Remove edges connected to the input node
|
||||
let updatedEdges = edges.filter((edge) => edge.source !== id && edge.target !== id)
|
||||
|
||||
// Create new edges from the input node's parent to its children
|
||||
const inputEdges = connectedEdges.filter((edge) => edge.target === id)
|
||||
const outputEdges = connectedEdges.filter((edge) => edge.source === id)
|
||||
|
||||
inputEdges.forEach((inputEdge) => {
|
||||
outputEdges.forEach((outputEdge) => {
|
||||
const newEdge = {
|
||||
id: `edge:${inputEdge.source}->${outputEdge.target}`,
|
||||
source: inputEdge.source,
|
||||
target: outputEdge.target,
|
||||
type: 'empty',
|
||||
data: {
|
||||
...outputEdge.data,
|
||||
sourceId: inputEdge.source,
|
||||
targetId: outputEdge.target
|
||||
}
|
||||
}
|
||||
updatedEdges.push(newEdge)
|
||||
})
|
||||
})
|
||||
|
||||
// Update parent ids of the nodes
|
||||
updatedNodes = updatedNodes.map((node) => {
|
||||
if (node.data && node.data.parentIds && node.data.parentIds.includes(id)) {
|
||||
const updatedParentIds = node.data.parentIds.filter((parentId) => parentId !== id)
|
||||
if (inputNode.data && inputNode.data.parentIds) {
|
||||
updatedParentIds.push(...inputNode.data.parentIds)
|
||||
}
|
||||
return {
|
||||
...node,
|
||||
data: {
|
||||
...node.data,
|
||||
parentIds: [...new Set(updatedParentIds)] // Remove duplicates
|
||||
}
|
||||
}
|
||||
}
|
||||
return node
|
||||
})
|
||||
|
||||
return { nodes: updatedNodes, edges: updatedEdges }
|
||||
}
|
||||
|
||||
function removeTriggerForLoopNodes(nodes, edges) {
|
||||
let updatedGraph = {
|
||||
nodes: [...nodes],
|
||||
edges: [...edges]
|
||||
}
|
||||
let forloopNode = updatedGraph.nodes.find((node) => node?.data?.value?.type === 'forloopflow')
|
||||
|
||||
if (!forloopNode) {
|
||||
return updatedGraph
|
||||
}
|
||||
|
||||
if (forloopNode?.data?.value?.parentsIds?.length > 0) {
|
||||
console.log('triggerScript', forloopNode?.data?.value?.parentsIds[0])
|
||||
}
|
||||
|
||||
let forloopModules = forloopNode?.data?.value?.modules
|
||||
if (!forloopModules) {
|
||||
return updatedGraph
|
||||
}
|
||||
|
||||
for (let i = 0; i < forloopModules.length; i++) {
|
||||
const module = forloopModules[i]
|
||||
console.log(`Processing module ${i}:`, module)
|
||||
updatedGraph = removeInputNode(updatedGraph.nodes, updatedGraph.edges, module.id)
|
||||
}
|
||||
|
||||
updatedGraph = removeInputNode(updatedGraph.nodes, updatedGraph.edges, forloopNode.id)
|
||||
|
||||
return updatedGraph
|
||||
}
|
||||
|
||||
function removeForLoopStartNodes(nodes, edges) {
|
||||
let updatedGraph = {
|
||||
nodes: [...nodes],
|
||||
edges: [...edges]
|
||||
}
|
||||
let forloopNode = updatedGraph.nodes.find((node) => node?.type === 'forLoopStart')
|
||||
if (!forloopNode) {
|
||||
return updatedGraph
|
||||
}
|
||||
return removeInputNode(updatedGraph.nodes, updatedGraph.edges, forloopNode.id)
|
||||
}
|
||||
|
||||
function removeForLoopEndNodes(nodes, edges) {
|
||||
let updatedGraph = {
|
||||
nodes: [...nodes],
|
||||
edges: [...edges]
|
||||
}
|
||||
let forloopNode = updatedGraph.nodes.find((node) => node?.type === 'forLoopEnd')
|
||||
if (!forloopNode) {
|
||||
return updatedGraph
|
||||
}
|
||||
return removeInputNode(updatedGraph.nodes, updatedGraph.edges, forloopNode.id)
|
||||
}
|
||||
|
||||
function processGraph(graph) {
|
||||
let newGraph = { nodes: graph.nodes, edges: graph.edges }
|
||||
newGraph = removeInputNode(newGraph.nodes, newGraph.edges, 'Input')
|
||||
newGraph = removeTriggerForLoopNodes(newGraph.nodes, newGraph.edges)
|
||||
newGraph = removeForLoopStartNodes(newGraph.nodes, newGraph.edges)
|
||||
newGraph = removeForLoopEndNodes(newGraph.nodes, newGraph.edges)
|
||||
return newGraph
|
||||
}
|
||||
|
||||
function updateStores() {
|
||||
if (graph.error) {
|
||||
return
|
||||
}
|
||||
|
||||
$nodes = layoutNodes(graph?.nodes)
|
||||
if (hasSchedulePoll) {
|
||||
graph = processGraph(graph)
|
||||
}
|
||||
|
||||
console.log('graph nodes after removal', graph.nodes)
|
||||
console.log('graph edges after removal', graph.edges)
|
||||
console.log('graph nodes', graph.nodes)
|
||||
console.log('graph edges', graph.edges)
|
||||
$nodes = layoutNodes(graph.nodes)
|
||||
$edges = graph.edges
|
||||
|
||||
console.log('nodes', $nodes)
|
||||
|
||||
@@ -15,6 +15,7 @@ export type GraphEventHandlers = {
|
||||
selectedIteration: (detail, moduleId: string) => void
|
||||
changeId: (newId: string) => void
|
||||
addSchedulePoll: () => void
|
||||
removeSchedulePoll: () => void
|
||||
}
|
||||
|
||||
export default function graphBuilder(
|
||||
@@ -168,7 +169,8 @@ export default function graphBuilder(
|
||||
type: 'schedulePoll',
|
||||
data: {
|
||||
eventHandlers: eventHandlers,
|
||||
modules: modules
|
||||
modules: modules,
|
||||
...extra
|
||||
}
|
||||
}
|
||||
nodes.push(schedulePollNode)
|
||||
|
||||
@@ -1,77 +1,149 @@
|
||||
<script lang="ts">
|
||||
import NodeWrapper from './NodeWrapper.svelte'
|
||||
import FlowModuleSchemaItem from '../../../flows/map/FlowModuleSchemaItem.svelte'
|
||||
import { Repeat } from 'lucide-svelte'
|
||||
import { getContext, createEventDispatcher } from 'svelte'
|
||||
import { Repeat, X } from 'lucide-svelte'
|
||||
import { getContext } from 'svelte'
|
||||
import type { Writable } from 'svelte/store'
|
||||
import type { GraphEventHandlers } from '../../graphBuilder'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { NODE } from '../../util'
|
||||
import InsertModuleButton from '../../../flows/map/InsertModuleButton.svelte'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
import type { FlowModule } from '$lib/gen'
|
||||
import MapItem from '../../../flows/map/MapItem.svelte'
|
||||
|
||||
export let data: {
|
||||
bgColor: string
|
||||
eventHandlers: GraphEventHandlers
|
||||
modules: FlowModule[]
|
||||
}
|
||||
|
||||
const { selectedId } = getContext<{ selectedId: Writable<string> }>('FlowGraphContext')
|
||||
$: itemProps = {
|
||||
selected: $selectedId === 'stepid'
|
||||
}
|
||||
|
||||
/* async function deleteSchedulePoll(e) {
|
||||
data.eventHandlers.delete(e.detail, '')
|
||||
} */
|
||||
let componentHeight = 0
|
||||
let componentHeight = NODE.height
|
||||
let hover = false
|
||||
|
||||
console.log('Modules', data.modules)
|
||||
|
||||
let forloopModules: FlowModule[] = []
|
||||
let triggerModule: FlowModule | undefined = undefined
|
||||
|
||||
function getSchedulePollModules() {
|
||||
let forloopModule = data.modules.find((mod) => mod.value.type === 'forloopflow')
|
||||
if (forloopModule) {
|
||||
forloopModules = forloopModule.value.modules
|
||||
}
|
||||
console.log('Forloop Modules', forloopModules)
|
||||
if (data.modules.length > 0) {
|
||||
triggerModule = data.modules[0]
|
||||
}
|
||||
console.log('Trigger Module', triggerModule)
|
||||
}
|
||||
|
||||
$: getSchedulePollModules()
|
||||
</script>
|
||||
|
||||
<NodeWrapper>
|
||||
<button
|
||||
class={twMerge(
|
||||
'flex flex-col gap-2 rounded-sm p-1 z-10 border absolute',
|
||||
$selectedId === 'schedulePoll'
|
||||
? 'outline outline-offset-0 outline-2 outline-slate-500 dark:outline-gray-400'
|
||||
: ''
|
||||
)}
|
||||
<NodeWrapper wrapperClass="!shadow-none">
|
||||
<div
|
||||
style="width: {NODE.width}px; min-height: {NODE.height}px; transform: translate(0, calc({NODE.height}px - {componentHeight}px));"
|
||||
on:click={() => data.eventHandlers.select('schedulePoll')}
|
||||
bind:clientHeight={componentHeight}
|
||||
>
|
||||
<div
|
||||
class="text-2xs text-secondary font-normal text-center rounded-sm w-[80%] border bg-surface"
|
||||
<button
|
||||
class={twMerge(
|
||||
'flex flex-col gap-2 rounded-sm p-1 border absolute grow w-full',
|
||||
$selectedId === 'schedulePoll'
|
||||
? 'outline outline-offset-0 outline-2 outline-slate-500 dark:outline-gray-400'
|
||||
: ''
|
||||
)}
|
||||
on:click={() => ($selectedId = 'schedulePoll')}
|
||||
bind:clientHeight={componentHeight}
|
||||
on:mouseenter={() => (hover = true)}
|
||||
on:mouseleave={() => (hover = false)}
|
||||
>
|
||||
<div class="flex flex-row gap-2 p-2">
|
||||
<div>
|
||||
<Repeat size={16} />
|
||||
{#if triggerModule}
|
||||
<div
|
||||
class="text-2xs text-secondary font-normal text-center rounded-sm shadow-md w-[80%] border bg-surface"
|
||||
>
|
||||
<MapItem
|
||||
mod={triggerModule}
|
||||
insertable={true}
|
||||
bgColor={'#ffffff'}
|
||||
modules={data.modules ?? []}
|
||||
moving={''}
|
||||
flowJobs={undefined}
|
||||
on:delete={(e) => {
|
||||
data.eventHandlers.delete(e.detail, '')
|
||||
}}
|
||||
on:insert={(e) => {
|
||||
data.eventHandlers.insert(e.detail)
|
||||
}}
|
||||
on:changeId={(e) => {
|
||||
data.eventHandlers.changeId(e.detail)
|
||||
}}
|
||||
on:move={(e) => {
|
||||
if (triggerModule) {
|
||||
data.eventHandlers.move(triggerModule, data.modules)
|
||||
}
|
||||
}}
|
||||
on:newBranch={(e) => {
|
||||
if (triggerModule) {
|
||||
data.eventHandlers.newBranch(triggerModule)
|
||||
}
|
||||
}}
|
||||
on:select={(e) => {
|
||||
data.eventHandlers.select(e.detail)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#each forloopModules as mod}
|
||||
<div class="text-2xs text-secondary font-normal w-[80%] ml-auto shadow-sm">
|
||||
<MapItem
|
||||
{mod}
|
||||
insertable={true}
|
||||
bgColor={'#ffffff'}
|
||||
modules={data.modules ?? []}
|
||||
moving={''}
|
||||
flowJobs={undefined}
|
||||
on:delete={(e) => {
|
||||
data.eventHandlers.delete(e.detail, '')
|
||||
}}
|
||||
on:insert={(e) => {
|
||||
data.eventHandlers.insert(e.detail)
|
||||
}}
|
||||
on:changeId={(e) => {
|
||||
data.eventHandlers.changeId(e.detail)
|
||||
}}
|
||||
on:move={(e) => {
|
||||
data.eventHandlers.move(mod, data.modules)
|
||||
}}
|
||||
on:newBranch={(e) => {
|
||||
data.eventHandlers.newBranch(mod)
|
||||
}}
|
||||
on:select={(e) => {
|
||||
data.eventHandlers.select(e.detail)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<div class="flex grow justify-center items-center">
|
||||
<span class="text-center">Schedule Poll</span>
|
||||
<div class="text-2xs text-secondary font-normal w-[80%] ml-auto">
|
||||
<div class="flex justify-center items-center w-full">
|
||||
<InsertModuleButton />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="text-2xs text-secondary font-normal text-center rounded-sm w-[80%] ml-auto border bg-surface"
|
||||
>
|
||||
<FlowModuleSchemaItem
|
||||
deletable={true}
|
||||
label={`Step`}
|
||||
id="step id"
|
||||
on:changeId
|
||||
on:move={() => dispatch('move')}
|
||||
on:delete
|
||||
on:click={() => ($selectedId = 'stepid')}
|
||||
{...itemProps}
|
||||
bgColor={'#ffffff'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="text-2xs text-secondary font-normal rounded-sm w-[80%] ml-auto">
|
||||
<div class="flex justify-center items-center w-full">
|
||||
<InsertModuleButton />
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
class="absolute -top-[10px] -right-[10px] rounded-full h-[20px] w-[20px] trash center-center text-secondary
|
||||
outline-[1px] outline dark:outline-gray-500 outline-gray-300 bg-surface duration-150 hover:bg-red-400 hover:text-white
|
||||
{hover || $selectedId === 'schedulePoll' ? '' : '!hidden'}"
|
||||
title="Delete"
|
||||
on:click|preventDefault|stopPropagation={() => {
|
||||
data.eventHandlers.removeSchedulePoll()
|
||||
console.log('remove schedule Poll')
|
||||
}}
|
||||
>
|
||||
<X class="mx-[3px]" size={12} strokeWidth={2} />
|
||||
</button>
|
||||
</button>
|
||||
</div>
|
||||
</NodeWrapper>
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
<TriggersWrapper
|
||||
path={data.path}
|
||||
on:new={(e) => {
|
||||
console.log('Yes New script at index', data.index, e)
|
||||
console.log('Event Handlers', data?.eventHandlers)
|
||||
data?.eventHandlers.insert({
|
||||
modules: data.modules,
|
||||
index: 0,
|
||||
|
||||
Reference in New Issue
Block a user