mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-21 08:02:26 +00:00
feat(frontend): global flow preview (#329)
* Added flow preview * Fix blue * Disable preview button is not inputs are valid * Fix layout top margin
This commit is contained in:
@@ -77,6 +77,11 @@ html {
|
||||
@apply rounded-sm;
|
||||
}
|
||||
|
||||
.blue-button {
|
||||
@apply bg-blue-500 !important;
|
||||
@apply hover:bg-blue-700 !important;
|
||||
}
|
||||
|
||||
.default-button {
|
||||
/*this styling does not impact the Dropdown component */
|
||||
@apply bg-blue-500;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="max-w-screen-lg flex grow w-full h-full xl:-ml-20">
|
||||
<div class="grow w-full h-full">
|
||||
<div class="grow w-full h-full mt-4">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,10 +10,13 @@
|
||||
sendUserToast,
|
||||
setQueryWithoutLoad
|
||||
} from '$lib/utils'
|
||||
import { Breadcrumb, BreadcrumbItem } from 'flowbite-svelte'
|
||||
import { faPlay } from '@fortawesome/free-solid-svg-icons'
|
||||
import { Breadcrumb, BreadcrumbItem, Button } from 'flowbite-svelte'
|
||||
import { onMount } from 'svelte'
|
||||
import Icon from 'svelte-awesome'
|
||||
import { OFFSET } from './CronInput.svelte'
|
||||
import FlowEditor from './FlowEditor.svelte'
|
||||
import FlowPreviewContent from './FlowPreviewContent.svelte'
|
||||
import { flowStore, mode } from './flows/flowStore'
|
||||
import { flowToMode } from './flows/utils'
|
||||
|
||||
@@ -26,6 +29,8 @@
|
||||
let scheduleEnabled
|
||||
let scheduleCron: string
|
||||
|
||||
let previewOpen = false
|
||||
|
||||
$: step = Number($page.url.searchParams.get('step')) || 1
|
||||
|
||||
async function createSchedule(path: string) {
|
||||
@@ -127,69 +132,95 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col max-w-screen-lg w-full mb-96 px-8">
|
||||
<!-- Nav between steps-->
|
||||
<div class="justify-between flex flex-row w-full">
|
||||
<Breadcrumb>
|
||||
<BreadcrumbItem>
|
||||
<button on:click={() => changeStep(1)} class={step === 1 ? 'font-bold' : null}>
|
||||
Flow Editor
|
||||
</button>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbItem>
|
||||
<button on:click={() => changeStep(2)} class={step === 2 ? 'font-bold' : null}>
|
||||
UI customisation
|
||||
</button>
|
||||
</BreadcrumbItem>
|
||||
</Breadcrumb>
|
||||
<div class="flex flex-row-reverse ml-2">
|
||||
{#if step == 1}
|
||||
<button
|
||||
disabled={pathError != ''}
|
||||
class="default-button px-6 max-h-8"
|
||||
on:click={() => changeStep(2)}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
<button
|
||||
disabled={pathError != ''}
|
||||
class="default-button-secondary px-6 max-h-8 mr-2"
|
||||
on:click={saveFlow}
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
<div class="flex flex-row w-full h-full justify-between">
|
||||
<div class="flex flex-col max-w-screen-md mb-96 m-auto">
|
||||
<div class="mx-4">
|
||||
<!-- Nav between steps-->
|
||||
<div class="justify-between flex flex-row w-full my-4">
|
||||
<Breadcrumb>
|
||||
<BreadcrumbItem>
|
||||
<button on:click={() => changeStep(1)} class={step === 1 ? 'font-bold' : null}>
|
||||
Flow Editor
|
||||
</button>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbItem>
|
||||
<button on:click={() => changeStep(2)} class={step === 2 ? 'font-bold' : null}>
|
||||
UI customisation
|
||||
</button>
|
||||
</BreadcrumbItem>
|
||||
</Breadcrumb>
|
||||
<div class="flex flex-row-reverse ml-2">
|
||||
{#if step == 1}
|
||||
<button
|
||||
disabled={pathError != ''}
|
||||
class="default-button px-6 max-h-8"
|
||||
on:click={() => changeStep(2)}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
<button
|
||||
disabled={pathError != ''}
|
||||
class="default-button-secondary px-6 max-h-8 mr-2"
|
||||
on:click={saveFlow}
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
{:else}
|
||||
<button class="default-button px-6 self-end" on:click={saveFlow}>Save</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row-reverse">
|
||||
<span class="my-1 text-sm text-gray-500 italic">
|
||||
{#if initialPath && initialPath != $flowStore?.path} {initialPath} → {/if}
|
||||
{$flowStore?.path}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- metadata -->
|
||||
|
||||
{#if $flowStore}
|
||||
{#if step === 1}
|
||||
<FlowEditor
|
||||
bind:pathError
|
||||
bind:initialPath
|
||||
bind:scheduleEnabled
|
||||
bind:scheduleCron
|
||||
bind:scheduleArgs
|
||||
/>
|
||||
{:else if step === 2}
|
||||
<ScriptSchema
|
||||
synchronizedHeader={false}
|
||||
bind:summary={$flowStore.summary}
|
||||
bind:description={$flowStore.description}
|
||||
bind:schema={$flowStore.schema}
|
||||
/>
|
||||
{/if}
|
||||
{:else}
|
||||
<button class="default-button px-6 self-end" on:click={saveFlow}>Save</button>
|
||||
<p>Loading</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row-reverse">
|
||||
<span class="my-1 text-sm text-gray-500 italic">
|
||||
{#if initialPath && initialPath != $flowStore?.path} {initialPath} → {/if}
|
||||
{$flowStore?.path}
|
||||
</span>
|
||||
|
||||
<Button
|
||||
size="lg"
|
||||
pill
|
||||
on:click={() => (previewOpen = !previewOpen)}
|
||||
class={`blue-button fixed bottom-10 right-10 ${previewOpen ? 'hidden' : ''}`}
|
||||
>
|
||||
Preview flow
|
||||
<Icon data={faPlay} class="ml-2" />
|
||||
</Button>
|
||||
|
||||
<div class={`relative h-screen w-1/3 ${previewOpen ? '' : 'hidden'}`}>
|
||||
<div class="absolute top-0 h-full">
|
||||
<div class="fixed border-l-2 right-0 h-screen w-1/3">
|
||||
<FlowPreviewContent
|
||||
flow={$flowStore}
|
||||
bind:args={scheduleArgs}
|
||||
on:close={() => (previewOpen = !previewOpen)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- metadata -->
|
||||
|
||||
{#if $flowStore}
|
||||
{#if step === 1}
|
||||
<FlowEditor
|
||||
bind:pathError
|
||||
bind:initialPath
|
||||
bind:scheduleEnabled
|
||||
bind:scheduleCron
|
||||
bind:scheduleArgs
|
||||
/>
|
||||
{:else if step === 2}
|
||||
<ScriptSchema
|
||||
synchronizedHeader={false}
|
||||
bind:summary={$flowStore.summary}
|
||||
bind:description={$flowStore.description}
|
||||
bind:schema={$flowStore.schema}
|
||||
/>
|
||||
{/if}
|
||||
{:else}
|
||||
<p>Loading</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
{/each}
|
||||
<Button
|
||||
disabled={pathIsEmpty($flowStore.path)}
|
||||
color="blue"
|
||||
class="blue-button"
|
||||
on:click={() => {
|
||||
addModule()
|
||||
open = $flowStore?.value.modules.length - 1
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
<script lang="ts">
|
||||
import { Job, JobService, type Flow } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { sendUserToast, truncateRev } from '$lib/utils'
|
||||
import { faClose } from '@fortawesome/free-solid-svg-icons'
|
||||
import { Button } from 'flowbite-svelte'
|
||||
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||
import Icon from 'svelte-awesome'
|
||||
import FlowJobResult from './FlowJobResult.svelte'
|
||||
import FlowStatusViewer from './FlowStatusViewer.svelte'
|
||||
import SchemaForm from './SchemaForm.svelte'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
export let flow: Flow
|
||||
export let args: Record<string, any> = {}
|
||||
|
||||
let intervalId: NodeJS.Timer
|
||||
let job: Job | undefined
|
||||
let jobs = []
|
||||
let jobId: string
|
||||
let isValid: boolean = false
|
||||
|
||||
$: dispatch('change', jobs)
|
||||
|
||||
export async function runPreview(args: Record<string, any>) {
|
||||
intervalId && clearInterval(intervalId)
|
||||
|
||||
jobId = await JobService.runFlowPreview({
|
||||
workspace: $workspaceStore ?? '',
|
||||
requestBody: {
|
||||
args,
|
||||
value: flow.value,
|
||||
path: flow.path
|
||||
}
|
||||
})
|
||||
jobs = []
|
||||
intervalId = setInterval(loadJob, 1000)
|
||||
sendUserToast(`started preview ${truncateRev(jobId, 10)}`)
|
||||
}
|
||||
|
||||
async function loadJob() {
|
||||
try {
|
||||
job = await JobService.getJob({ workspace: $workspaceStore!, id: jobId })
|
||||
if (job?.type == 'CompletedJob') {
|
||||
clearInterval(intervalId)
|
||||
}
|
||||
} catch (err) {
|
||||
sendUserToast(err, true)
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
intervalId && clearInterval(intervalId)
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col space-y-4 h-screen bg-white ">
|
||||
<div class="flex flex-col space-y-4 p-6 border-b-2">
|
||||
<div class="flex justify-between">
|
||||
<h3 class="text-lg leading-6 font-bold text-gray-900">Flow Preview</h3>
|
||||
|
||||
<Button color="alternative" on:click={() => dispatch('close')}>
|
||||
<Icon data={faClose} />
|
||||
</Button>
|
||||
</div>
|
||||
<SchemaForm schema={flow.schema} bind:isValid bind:args />
|
||||
<Button disabled={!isValid} class="blue-button" on:click={() => runPreview(args)} size="md"
|
||||
>Preview
|
||||
</Button>
|
||||
</div>
|
||||
<div class="h-full overflow-y-auto mb-16">
|
||||
{#if job}
|
||||
<div class="w-full">
|
||||
<FlowStatusViewer {job} bind:jobs />
|
||||
</div>
|
||||
{#if `result` in job}
|
||||
<FlowJobResult {job} />
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,14 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { faHourglassHalf, faSpinner, faTimes } from '@fortawesome/free-solid-svg-icons'
|
||||
import { scriptPathToHref, truncateRev } from '$lib/utils'
|
||||
import { faHourglassHalf, faSpinner, faTimes } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
import Icon from 'svelte-awesome'
|
||||
import { check } from 'svelte-awesome/icons'
|
||||
|
||||
import { CompletedJob, FlowStatusModule, JobService, QueuedJob } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import JobStatus from './JobStatus.svelte'
|
||||
import FlowJobResult from './FlowJobResult.svelte'
|
||||
import JobStatus from './JobStatus.svelte'
|
||||
|
||||
export let job: QueuedJob | CompletedJob
|
||||
export let jobs: (CompletedJob | CompletedJob[] | undefined)[] = []
|
||||
@@ -74,29 +74,28 @@
|
||||
$: $workspaceStore && job && loadResults()
|
||||
</script>
|
||||
|
||||
<div class="flow-root w-full p-4">
|
||||
<div class="flex flex-row-reverse">
|
||||
<div class="flow-root w-full p-6">
|
||||
<div class="flex ">
|
||||
{#if job}
|
||||
<div class="flex-col">
|
||||
<a href="/run/{job?.id}" class="font-medium text-blue-600"
|
||||
>{truncateRev(job?.id ?? '', 10)}</a
|
||||
>
|
||||
<div>
|
||||
<JobStatus {job} />
|
||||
</div>
|
||||
<a href="/run/{job?.id}" class="font-medium text-blue-600">
|
||||
{truncateRev(job?.id ?? '', 10)}
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<JobStatus {job} />
|
||||
|
||||
<p class="text-gray-500 mb-6 w-full text-center">
|
||||
Step
|
||||
<span class="font-medium text-gray-900"
|
||||
>{Math.min((job?.flow_status?.step ?? 0) + 1, job?.raw_flow?.modules.length ?? 0)}</span
|
||||
>
|
||||
<span class="font-medium text-gray-900">
|
||||
{Math.min((job?.flow_status?.step ?? 0) + 1, job?.raw_flow?.modules.length ?? 0)}
|
||||
</span>
|
||||
out of <span class="font-medium text-gray-900">{job?.raw_flow?.modules.length}</span>
|
||||
<span class="mt-4" />
|
||||
</p>
|
||||
<ul class="-mb-8 w-full">
|
||||
|
||||
<ul class="w-full">
|
||||
{#each job?.raw_flow?.modules ?? [] as mod, i}
|
||||
<li class="w-full">
|
||||
<div class="relative pb-8 w-full">
|
||||
@@ -162,17 +161,18 @@
|
||||
{#if job.flow_status?.modules[i].forloop_jobs}
|
||||
{#each job.flow_status?.modules[i].forloop_jobs ?? [] as job}
|
||||
<div class="flex flex-col">
|
||||
<a href="/run/{job}" class="font-medium text-blue-600"
|
||||
>{truncateRev(job ?? '', 10)}</a
|
||||
>
|
||||
<a href="/run/{job}" class="font-medium text-blue-600">
|
||||
{truncateRev(job ?? '', 10)}
|
||||
</a>
|
||||
</div>
|
||||
{/each}
|
||||
{:else if job.flow_status?.modules[i].job}
|
||||
<a
|
||||
href="/run/{job.flow_status?.modules[i].job}"
|
||||
class="font-medium text-blue-600"
|
||||
>{truncateRev(job.flow_status?.modules[i].job ?? '', 10)}</a
|
||||
>
|
||||
{truncateRev(job.flow_status?.modules[i].job ?? '', 10)}
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
<div slot="actions">
|
||||
<div on:click={() => overlays[argName]?.focus('connect')}>
|
||||
<Tooltip placement="bottom" content="Input connect">
|
||||
<Button color="blue" size="sm" class="h-8">
|
||||
<Button size="sm" class="blue-button h-8">
|
||||
<Icon data={faChain} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
<script lang="ts">
|
||||
import { displayDate, forLater, msToSec } from '$lib/utils'
|
||||
import {
|
||||
faCalendar,
|
||||
faCheck,
|
||||
faCircle,
|
||||
faClock,
|
||||
faHourglassHalf,
|
||||
faTimes
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import { displayDate, forLater, msToSec } from '$lib/utils'
|
||||
|
||||
import Icon from 'svelte-awesome'
|
||||
import { check } from 'svelte-awesome/icons'
|
||||
|
||||
import type { CompletedJob, QueuedJob } from '$lib/gen'
|
||||
import { Badge } from 'flowbite-svelte'
|
||||
|
||||
const SMALL_ICON_SCALE = 0.7
|
||||
|
||||
@@ -19,32 +20,39 @@
|
||||
</script>
|
||||
|
||||
{#if job && 'success' in job && job.success}
|
||||
<Icon class="text-green-600" data={check} scale={SMALL_ICON_SCALE} />
|
||||
<span class="mx-2">Succeeded {job.is_skipped ? '(Skipped)' : ''}</span>
|
||||
<div>
|
||||
<Icon class="text-gray-700" data={faHourglassHalf} scale={SMALL_ICON_SCALE} /><span class="mx-2"
|
||||
>Job ran in {msToSec(job.duration_ms)}
|
||||
s</span
|
||||
>
|
||||
</div>
|
||||
<Badge large color="green">
|
||||
<Icon data={faCheck} scale={SMALL_ICON_SCALE} class="mr-2" />
|
||||
Succeeded {job.is_skipped ? '(Skipped)' : ''}
|
||||
</Badge>
|
||||
|
||||
<Badge large>
|
||||
<Icon data={faHourglassHalf} scale={SMALL_ICON_SCALE} class="mr-2" />
|
||||
Job ran in {msToSec(job.duration_ms)} s
|
||||
</Badge>
|
||||
{:else if job && 'success' in job}
|
||||
<Icon class="text-red-700" data={faTimes} scale={SMALL_ICON_SCALE} />
|
||||
<span class="mx-2">Failed</span>
|
||||
<div>
|
||||
<Icon class="text-gray-700" data={faHourglassHalf} scale={SMALL_ICON_SCALE} /><span class="mx-2"
|
||||
>Job ran in {msToSec(job.duration_ms)}
|
||||
s</span
|
||||
>
|
||||
</div>
|
||||
<Badge large color="red">
|
||||
<Icon data={faTimes} scale={SMALL_ICON_SCALE} class="mr-2" />
|
||||
Failed
|
||||
</Badge>
|
||||
<Badge large>
|
||||
<Icon data={faHourglassHalf} scale={SMALL_ICON_SCALE} class="mr-2" />
|
||||
Job ran in {msToSec(job.duration_ms)}s
|
||||
</Badge>
|
||||
{:else if job && 'running' in job && job.running}
|
||||
<Icon class="text-yellow-500" data={faCircle} scale={SMALL_ICON_SCALE} />
|
||||
<span class="mx-2">Running</span>
|
||||
<Badge large color="yellow">
|
||||
<Icon data={faCircle} scale={SMALL_ICON_SCALE} class="mr-2" />
|
||||
Running
|
||||
</Badge>
|
||||
{:else if job && 'running' in job && 'scheduled_for' in job && job.scheduled_for && forLater(job.scheduled_for)}
|
||||
<Icon class="text-gray-700" data={faCalendar} scale={SMALL_ICON_SCALE} />
|
||||
<span class="mx-2">Scheduled for {displayDate(job.scheduled_for)}</span>
|
||||
<Badge>
|
||||
<Icon data={faCalendar} scale={SMALL_ICON_SCALE} class="mr-2" />
|
||||
Scheduled for {displayDate(job.scheduled_for)}
|
||||
</Badge>
|
||||
{:else if job && 'running' in job}
|
||||
<Icon class="text-gray-700" data={faClock} scale={SMALL_ICON_SCALE} />
|
||||
<span class="mx-2">Queued</span>
|
||||
<Badge>
|
||||
<Icon data={faClock} scale={SMALL_ICON_SCALE} class="mr-2" />
|
||||
Queued
|
||||
</Badge>
|
||||
{:else}
|
||||
<Icon class="text-gray-200" data={faCircle} scale={SMALL_ICON_SCALE} />
|
||||
{/if}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { ResourceService } from '$lib/gen'
|
||||
|
||||
import ResourcePicker from './ResourcePicker.svelte'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import SchemaForm from './SchemaForm.svelte'
|
||||
import RadioButton from './RadioButton.svelte'
|
||||
import ResourcePicker from './ResourcePicker.svelte'
|
||||
import SchemaForm from './SchemaForm.svelte'
|
||||
|
||||
export let format: string
|
||||
export let value: any
|
||||
|
||||
@@ -144,7 +144,7 @@
|
||||
modalProperty = Object.assign({}, DEFAULT_PROPERTY)
|
||||
schemaModal.openModal()
|
||||
}}
|
||||
color="blue"
|
||||
class="blue-button"
|
||||
>
|
||||
<Icon data={faPlus} class="mr-1" />
|
||||
Add argument
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
<div class="flex flex-col h-screen max-w-screen-lg xl:-ml-20 xl:pl-4 w-full -mt-4 pt-4 md:mx-10 ">
|
||||
<!-- Nav between steps-->
|
||||
<div class="flex flex-col w-full">
|
||||
<div class="justify-between flex flex-row drop-shadow-sm w-full">
|
||||
<div class="justify-between flex flex-row drop-shadow-sm w-full mt-4">
|
||||
<div class="wizard-nav flex flex-row w-full">
|
||||
<button
|
||||
class="{step === 1
|
||||
@@ -279,7 +279,6 @@
|
||||
/* .wizard-nav {
|
||||
@apply w-1/2 sm:w-1/4;
|
||||
} */
|
||||
|
||||
.wizard-nav button {
|
||||
max-height: 30px;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
import { Dropdown, DropdownItem } from 'flowbite-svelte'
|
||||
import Icon from 'svelte-awesome'
|
||||
import Editor from '../Editor.svelte'
|
||||
import FlowPreview from '../FlowPreview.svelte'
|
||||
import FlowViewer from '../FlowViewer.svelte'
|
||||
import Modal from '../Modal.svelte'
|
||||
import RadioButton from '../RadioButton.svelte'
|
||||
@@ -129,31 +128,29 @@
|
||||
rows="1"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="mx-6">
|
||||
<RadioButton
|
||||
options={[
|
||||
[
|
||||
{
|
||||
title: 'UI or webhook triggered',
|
||||
desc: 'Trigger this flow through the generated UI, a manual schedule or by calling the associated webhook'
|
||||
},
|
||||
'push'
|
||||
],
|
||||
[
|
||||
{
|
||||
title: 'Watching changes regularly',
|
||||
desc: 'The first module of this flow is a trigger script whose purpose is to pull data from an external source and return all new items since last run. This flow is meant to be scheduled very regularly to reduce latency to react to new events. It will trigger the rest of the flow once per item. If no new items, the flow will be skipped.'
|
||||
},
|
||||
'pull'
|
||||
]
|
||||
]}
|
||||
bind:value={$mode}
|
||||
/>
|
||||
</div>
|
||||
{#if $mode == 'pull'}
|
||||
<div class="p-4">
|
||||
<div class="mt-4">
|
||||
<RadioButton
|
||||
options={[
|
||||
[
|
||||
{
|
||||
title: 'UI or webhook triggered',
|
||||
desc: 'Trigger this flow through the generated UI, a manual schedule or by calling the associated webhook'
|
||||
},
|
||||
'push'
|
||||
],
|
||||
[
|
||||
{
|
||||
title: 'Watching changes regularly',
|
||||
desc: 'The first module of this flow is a trigger script whose purpose is to pull data from an external source and return all new items since last run. This flow is meant to be scheduled very regularly to reduce latency to react to new events. It will trigger the rest of the flow once per item. If no new items, the flow will be skipped.'
|
||||
},
|
||||
'pull'
|
||||
]
|
||||
]}
|
||||
bind:value={$mode}
|
||||
/>
|
||||
</div>
|
||||
{#if $mode == 'pull'}
|
||||
<CollapseLink text="set primary schedule" open={true}>
|
||||
<Tooltip>
|
||||
The primary schedule of a flow is simply a schedule that has the same name as a flow. It
|
||||
@@ -177,15 +174,6 @@
|
||||
</div>
|
||||
<SchemaForm schema={$flowStore.schema} bind:args={scheduleArgs} />
|
||||
</CollapseLink>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="p-6">
|
||||
<FlowPreview
|
||||
mode={$mode}
|
||||
flow={$flowStore}
|
||||
i={$flowStore?.value.modules.length}
|
||||
bind:args={scheduleArgs}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</FlowBox>
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation'
|
||||
import { OpenAPI } from '$lib/gen'
|
||||
import { logout } from '$lib/logout'
|
||||
import { superadmin, userStore, usersWorkspaceStore, workspaceStore } from '$lib/stores'
|
||||
import { clickOutside } from '$lib/utils'
|
||||
import { faDiscord, faGithub } from '@fortawesome/free-brands-svg-icons'
|
||||
import {
|
||||
faBookOpen,
|
||||
@@ -21,11 +26,6 @@
|
||||
import { onMount } from 'svelte'
|
||||
import Icon from 'svelte-awesome'
|
||||
import '../app.css'
|
||||
import { OpenAPI } from '$lib/gen'
|
||||
import { superadmin, userStore, usersWorkspaceStore, workspaceStore } from '$lib/stores'
|
||||
import { clickOutside } from '$lib/utils'
|
||||
import { logout } from '$lib/logout'
|
||||
import { goto } from '$app/navigation'
|
||||
|
||||
OpenAPI.WITH_CREDENTIALS = true
|
||||
|
||||
@@ -342,9 +342,9 @@
|
||||
</ul>
|
||||
</nav>
|
||||
<div
|
||||
class="bg-white antialiased text-gray-900 pt-4 {isCollapsed
|
||||
? 'pl-12'
|
||||
: 'pl-44'} pr-8 flex h-full max-w-screen flex-col items-center"
|
||||
class="bg-white antialiased text-gray-900 {isCollapsed
|
||||
? 'pl-8'
|
||||
: 'pl-36'} flex h-full max-w-screen flex-col items-center"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user