mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-24 08:01:38 +00:00
af9e1f4479
* feat: add ids to modules + inputTransforms from module to module value * all * delete obsolete input transforms
204 lines
6.1 KiB
Svelte
204 lines
6.1 KiB
Svelte
<script lang="ts">
|
|
import type { FlowEditorContext } from '../types'
|
|
import { getContext } from 'svelte'
|
|
import FlowModuleSchemaItem from './FlowModuleSchemaItem.svelte'
|
|
import Icon from 'svelte-awesome'
|
|
import { faCalendarAlt, faPen, faPlus, faSliders } from '@fortawesome/free-solid-svg-icons'
|
|
import {
|
|
emptyFlowModuleState,
|
|
emptyModule,
|
|
isEmptyFlowModule
|
|
} from '$lib/components/flows/flowStateUtils'
|
|
import { classNames } from '$lib/utils'
|
|
import type { FlowModuleState } from '../flowState'
|
|
import type { FlowModule } from '$lib/gen'
|
|
|
|
import FlowErrorHandlerItem from './FlowErrorHandlerItem.svelte'
|
|
import RemoveStepConfirmationModal from '../content/RemoveStepConfirmationModal.svelte'
|
|
|
|
export let prefix: string | undefined = undefined
|
|
export let modules: FlowModule[]
|
|
export let moduleStates: FlowModuleState[]
|
|
|
|
const { select, selectedId, schedule } = getContext<FlowEditorContext>('FlowEditorContext')
|
|
|
|
function insertAtIndex(index: number): void {
|
|
moduleStates.splice(index, 0, emptyFlowModuleState())
|
|
modules.splice(index, 0, emptyModule())
|
|
moduleStates = moduleStates
|
|
modules = modules
|
|
select([prefix, String(index)].filter(Boolean).join('-'))
|
|
}
|
|
|
|
function removeAtIndex(index: number): void {
|
|
select('settings')
|
|
|
|
modules.splice(index, 1)
|
|
moduleStates.splice(index, 1)
|
|
moduleStates = moduleStates
|
|
modules = modules
|
|
}
|
|
let indexToRemove: number | undefined = undefined
|
|
$: confirmationModalOpen = indexToRemove !== undefined
|
|
</script>
|
|
|
|
<div class="flex flex-col justify-between h-full">
|
|
<ul class="w-full">
|
|
{#if prefix === undefined}
|
|
<div
|
|
on:click={() => select('settings')}
|
|
class={classNames(
|
|
'border w-full rounded-md p-2 bg-white text-sm cursor-pointer flex items-center mb-4',
|
|
$selectedId.includes('settings')
|
|
? 'outline outline-offset-1 outline-2 outline-slate-900'
|
|
: ''
|
|
)}
|
|
>
|
|
<Icon data={faSliders} class="mr-2" />
|
|
<span class="font-bold flex flex-row justify-between w-full flex-wrap gap-2 items-center"
|
|
>Settings <span
|
|
class={classNames('badge', $schedule?.enabled ? 'badge-on' : 'badge-off')}
|
|
on:click|stopPropagation={() => select('settings-schedule')}
|
|
>
|
|
{$schedule.cron}
|
|
<Icon class={$schedule.cron ? 'ml-2' : ''} data={faCalendarAlt} scale={0.8} />
|
|
</span></span
|
|
>
|
|
</div>
|
|
|
|
<FlowModuleSchemaItem
|
|
on:click={() => select('inputs')}
|
|
isFirst
|
|
hasLine
|
|
selected={$selectedId === 'inputs'}
|
|
>
|
|
<div slot="icon">
|
|
<Icon data={faPen} scale={0.8} />
|
|
</div>
|
|
<div slot="content" class="flex flex-row">
|
|
<span>Inputs</span>
|
|
</div>
|
|
</FlowModuleSchemaItem>
|
|
{/if}
|
|
|
|
{#each modules as mod, index (index)}
|
|
<button
|
|
on:click={() => insertAtIndex(index)}
|
|
type="button"
|
|
class="text-gray-900 m-0.5 my-0.5 bg-white border border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-200 font-medium rounded-full text-sm w-6 h-6 flex items-center justify-center"
|
|
>
|
|
<Icon data={faPlus} scale={0.8} />
|
|
</button>
|
|
{#if mod.value.type === 'forloopflow'}
|
|
<li>
|
|
<FlowModuleSchemaItem
|
|
deletable
|
|
on:delete={() => removeAtIndex(index)}
|
|
on:click={() => select(['loop', String(index)].join('-'))}
|
|
selected={$selectedId === ['loop', String(index)].join('-')}
|
|
retry={mod.retry?.constant != undefined || mod.retry?.exponential != undefined}
|
|
earlyStop={mod.stop_after_if != undefined}
|
|
suspend={Boolean(mod.suspend)}
|
|
>
|
|
<div slot="icon">
|
|
<span>{index + 1}</span>
|
|
</div>
|
|
<div slot="content" class="truncate block w-full">
|
|
<span>{mod.summary || 'For loop'}</span>
|
|
</div>
|
|
</FlowModuleSchemaItem>
|
|
|
|
<div class="flex text-xs">
|
|
<div class="line mr-2 w-8" />
|
|
|
|
<div class="w-full mb-2">
|
|
{#if moduleStates[index]?.childFlowModules}
|
|
<svelte:self
|
|
prefix={String(index)}
|
|
moduleStates={moduleStates[index].childFlowModules}
|
|
modules={mod.value.modules}
|
|
/>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="italic text-xs pl-10 text-gray-600">
|
|
The loop's result is the list of every iteration's result.
|
|
</div>
|
|
</li>
|
|
{:else}
|
|
<li>
|
|
<FlowModuleSchemaItem
|
|
on:click={() => select([prefix, String(index)].filter(Boolean).join('-'))}
|
|
color={prefix ? 'orange' : 'blue'}
|
|
isLast={index === modules.length - 1}
|
|
selected={$selectedId === [prefix, String(index)].filter(Boolean).join('-')}
|
|
deletable
|
|
on:delete={(event) => {
|
|
if (event.detail.event.shiftKey || isEmptyFlowModule(mod)) {
|
|
removeAtIndex(index)
|
|
} else {
|
|
indexToRemove = index
|
|
}
|
|
}}
|
|
retry={mod.retry?.constant != undefined || mod.retry?.exponential != undefined}
|
|
earlyStop={mod.stop_after_if != undefined}
|
|
suspend={Boolean(mod.suspend)}
|
|
>
|
|
<div slot="icon">
|
|
<span>{index + 1}</span>
|
|
</div>
|
|
<div slot="content" class="w-full truncate block">
|
|
<span
|
|
>{mod.summary ||
|
|
(`path` in mod.value ? mod.value.path : undefined) ||
|
|
(mod.value.type === 'rawscript'
|
|
? `Inline ${mod.value.language}`
|
|
: 'Select a script')}</span
|
|
>
|
|
</div>
|
|
</FlowModuleSchemaItem>
|
|
</li>
|
|
{/if}
|
|
{/each}
|
|
|
|
<button
|
|
on:click={() => insertAtIndex(modules.length)}
|
|
type="button"
|
|
class="text-gray-900 bg-white border m-0.5 border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-200 font-medium rounded-full text-sm w-6 h-6 flex items-center justify-center"
|
|
>
|
|
<Icon data={faPlus} scale={0.8} />
|
|
</button>
|
|
</ul>
|
|
{#if prefix === undefined}
|
|
<FlowErrorHandlerItem />
|
|
{/if}
|
|
</div>
|
|
|
|
<RemoveStepConfirmationModal
|
|
bind:open={confirmationModalOpen}
|
|
on:canceled={() => {
|
|
indexToRemove = undefined
|
|
}}
|
|
on:confirmed={() => {
|
|
if (indexToRemove !== undefined) {
|
|
removeAtIndex(indexToRemove)
|
|
indexToRemove = undefined
|
|
}
|
|
}}
|
|
/>
|
|
|
|
<style>
|
|
.badge {
|
|
@apply whitespace-nowrap text-sm font-medium border px-2.5 py-0.5 rounded cursor-pointer flex items-center;
|
|
}
|
|
|
|
.badge-on {
|
|
@apply bg-blue-100 text-blue-800 hover:bg-blue-200;
|
|
}
|
|
|
|
.badge-off {
|
|
@apply bg-gray-100 text-gray-800 hover:bg-gray-200;
|
|
}
|
|
</style>
|