diff --git a/frontend/src/app.css b/frontend/src/app.css index da4e0dc293..eaeec5064e 100644 --- a/frontend/src/app.css +++ b/frontend/src/app.css @@ -3,12 +3,6 @@ @tailwind components; @tailwind utilities; -html { - - /* Avoid content shifting */ - overflow-y: overlay; -} - @layer base { h1 { @apply text-2xl; diff --git a/frontend/src/lib/components/Drawer.svelte b/frontend/src/lib/components/Drawer.svelte new file mode 100644 index 0000000000..0616af3e2b --- /dev/null +++ b/frontend/src/lib/components/Drawer.svelte @@ -0,0 +1,118 @@ + + + + + diff --git a/frontend/src/lib/components/FlowBuilder.svelte b/frontend/src/lib/components/FlowBuilder.svelte index e07282c254..25c07dadd1 100644 --- a/frontend/src/lib/components/FlowBuilder.svelte +++ b/frontend/src/lib/components/FlowBuilder.svelte @@ -16,6 +16,7 @@ import { onDestroy, onMount } from 'svelte' import Icon from 'svelte-awesome' import { OFFSET } from './CronInput.svelte' + import Drawer from './Drawer.svelte' import FlowEditor from './FlowEditor.svelte' import FlowPreviewContent from './FlowPreviewContent.svelte' import { flowStateStore, flowStateToFlow, type FlowState } from './flows/flowState' @@ -27,13 +28,13 @@ export let initialPath: string = '' let pathError = '' + let previewOpen = false + let scheduleArgs: Record let previewArgs: Record let scheduleEnabled: boolean let scheduleCron: string - let previewOpen = false - $: step = Number($page.url.searchParams.get('step')) || 1 async function createSchedule(path: string) { @@ -121,9 +122,6 @@ } async function changeStep(step: number) { - if (step === 2 && previewOpen) { - previewOpen = false - } goto(`?step=${step}`) } @@ -157,9 +155,7 @@
-
+
@@ -244,17 +240,8 @@

Loading

{/if}
- -
-
- {#if $flowStore && step === 1} -
- (previewOpen = !previewOpen)} - /> -
- {/if} -
-
+ + + (previewOpen = !previewOpen)} /> + diff --git a/frontend/src/lib/components/FlowEditor.svelte b/frontend/src/lib/components/FlowEditor.svelte index 90eb75c149..450cca0be2 100644 --- a/frontend/src/lib/components/FlowEditor.svelte +++ b/frontend/src/lib/components/FlowEditor.svelte @@ -2,6 +2,7 @@ import { ScheduleService } from '$lib/gen' import { workspaceStore } from '$lib/stores' + import FlowSettings from './flows/FlowSettings.svelte' import { flowStateStore } from './flows/flowState' import { flowStore } from './flows/flowStore' diff --git a/frontend/src/lib/components/FlowJobResult.svelte b/frontend/src/lib/components/FlowJobResult.svelte index d9d376c569..7608d8b852 100644 --- a/frontend/src/lib/components/FlowJobResult.svelte +++ b/frontend/src/lib/components/FlowJobResult.svelte @@ -1,27 +1,28 @@ {#if job} -
-
- -
- -
-
-
-
- -
-
{job.logs}
-
-
-
+
+ + Results + Logs + + + + + +
+
{job.logs}
+
+
{/if} diff --git a/frontend/src/lib/components/FlowPreview.svelte b/frontend/src/lib/components/FlowPreview.svelte index 04694acfcb..feb2b88e10 100644 --- a/frontend/src/lib/components/FlowPreview.svelte +++ b/frontend/src/lib/components/FlowPreview.svelte @@ -1,12 +1,11 @@
- {#if `result` in job} - - {/if} {/if} {/if} diff --git a/frontend/src/lib/components/FlowPreviewContent.svelte b/frontend/src/lib/components/FlowPreviewContent.svelte index 338d2b0192..4acb34c201 100644 --- a/frontend/src/lib/components/FlowPreviewContent.svelte +++ b/frontend/src/lib/components/FlowPreviewContent.svelte @@ -2,16 +2,16 @@ import { Job, JobService } from '$lib/gen' import { workspaceStore } from '$lib/stores' import { sendUserToast, truncateRev } from '$lib/utils' - import { faClose } from '@fortawesome/free-solid-svg-icons' + import { faClose, faPlay } 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 { flowStateStore, flowStateToFlow } from './flows/flowState' import { mapJobResultsToFlowState } from './flows/flowStateUtils' import { flowStore } from './flows/flowStore' import { runFlowPreview } from './flows/utils' import FlowStatusViewer from './FlowStatusViewer.svelte' + import ProgressBar from './ProgressBar.svelte' import SchemaForm from './SchemaForm.svelte' export let args: Record = {} @@ -20,6 +20,7 @@ let job: Job | undefined let jobId: string let isValid: boolean = false + let intervalState: 'idle' | 'canceled' | 'done' | 'running' = 'idle' $: newFlow = flowStateToFlow($flowStateStore, $flowStore) $: steps = newFlow.value.modules.length @@ -27,18 +28,20 @@ const dispatch = createEventDispatcher() export async function runPreview(args: Record) { + job = undefined intervalId && clearInterval(intervalId) jobId = await runFlowPreview(args, newFlow) intervalId = setInterval(loadJob, 1000) + intervalState = 'running' sendUserToast(`started preview ${truncateRev(jobId, 10)}`) } - async function loadJob() { try { job = await JobService.getJob({ workspace: $workspaceStore!, id: jobId }) if (job?.type == 'CompletedJob') { clearInterval(intervalId) + intervalState = 'done' } } catch (err) { sendUserToast(err, true) @@ -47,34 +50,52 @@ onDestroy(() => { intervalId && clearInterval(intervalId) + intervalState = 'done' }) -
-
-
-

Flow Preview

+
+
+
+
+ +
- +

Flow preview

+ +
+
- + {#if intervalState === 'running'} + + {:else} + + {/if} +
{#if job} -
- mapJobResultsToFlowState(e.detail, 'upto', steps - 1)} - /> -
- {#if `result` in job} - - {/if} + mapJobResultsToFlowState(e.detail, 'upto', steps - 1)} + root={true} + /> {/if}
diff --git a/frontend/src/lib/components/FlowStatusViewer.svelte b/frontend/src/lib/components/FlowStatusViewer.svelte index b9c3d62f3d..a360d3bd45 100644 --- a/frontend/src/lib/components/FlowStatusViewer.svelte +++ b/frontend/src/lib/components/FlowStatusViewer.svelte @@ -1,243 +1,128 @@ -
-
- {#if job} - +{#if job} +
+

Preview results

+ + {#if `result` in job} + + {/if} + + {#if Array.isArray(forloopJobIds) && forloopJobIds?.length > 0 && Array.isArray(loopJobs)} +

+ Loop results ({forloopJobIds.length} items) +

+ {#each forloopJobIds as loopJobId, j} + +
+ +
+ {/each} + {:else if hasModules && 'result' in job && Array.isArray(innerJobs)} +
    +

    + Detailed results +

    + + {#each job?.flow_status?.modules ?? [] as module, i} +

    + Step + {i + 1} out of + {job?.raw_flow?.modules.length} +

    + +
  • + +
  • + {/each} +
{/if}
- - - -

- Step - - {Math.min((job?.flow_status?.step ?? 0) + 1, job?.raw_flow?.modules.length ?? 0)} - - out of {job?.raw_flow?.modules.length} - -

- -
    - {#each job?.raw_flow?.modules ?? [] as mod, i} -
  • -
    - {#if i < (job?.raw_flow?.modules ?? []).length - 1} -
    -
  • - {/each} -
-
+{:else} + Loading +{/if} diff --git a/frontend/src/lib/components/JobStatus.svelte b/frontend/src/lib/components/JobStatus.svelte index bd16a12a9f..fa9d70fc39 100644 --- a/frontend/src/lib/components/JobStatus.svelte +++ b/frontend/src/lib/components/JobStatus.svelte @@ -22,7 +22,7 @@ {#if job && 'success' in job && job.success} - Succeeded {job.is_skipped ? '(Skipped)' : ''} + Success {job.is_skipped ? '(Skipped)' : ''} diff --git a/frontend/src/lib/components/ModuleStep.svelte b/frontend/src/lib/components/ModuleStep.svelte index b760ce57b5..275fd08e8e 100644 --- a/frontend/src/lib/components/ModuleStep.svelte +++ b/frontend/src/lib/components/ModuleStep.svelte @@ -142,7 +142,7 @@ {#if !shouldPick}
-
+
{/if} diff --git a/frontend/src/lib/components/ProgressBar.svelte b/frontend/src/lib/components/ProgressBar.svelte new file mode 100644 index 0000000000..2518e22496 --- /dev/null +++ b/frontend/src/lib/components/ProgressBar.svelte @@ -0,0 +1,36 @@ + + +
+
+ {text} + + {series.slice(0, i).reduce((x, y) => y + x, 0)}% + +
+
+ {#each series as serie, index} + y + x, 0)} + length={serie} + shouldToggle={toggled[index]} + /> + {/each} +
+
diff --git a/frontend/src/lib/components/ProgressBarPart.svelte b/frontend/src/lib/components/ProgressBarPart.svelte new file mode 100644 index 0000000000..936d504c66 --- /dev/null +++ b/frontend/src/lib/components/ProgressBarPart.svelte @@ -0,0 +1,25 @@ + + +
diff --git a/frontend/src/lib/components/flows/flowStateUtils.ts b/frontend/src/lib/components/flows/flowStateUtils.ts index 84c4e579ad..519e4eabf2 100644 --- a/frontend/src/lib/components/flows/flowStateUtils.ts +++ b/frontend/src/lib/components/flows/flowStateUtils.ts @@ -1,5 +1,12 @@ import type { Schema } from '$lib/common' -import { CompletedJob, ScriptService, type Flow, type FlowModule, type RawScript } from '$lib/gen' +import { + CompletedJob, + Job, + ScriptService, + type Flow, + type FlowModule, + type RawScript +} from '$lib/gen' import { initialCode } from '$lib/script_helpers' import { userStore, workspaceStore } from '$lib/stores' import { @@ -15,7 +22,6 @@ import { get } from 'svelte/store' import { flowStateStore, type FlowModuleSchema, type FlowState } from './flowState' import { flowStore } from './flowStore' import { jobsToResults, loadSchemaFromModule } from './utils' - export function emptyFlowModuleSchema(): FlowModuleSchema { return { flowModule: emptyModule(), @@ -264,24 +270,42 @@ function extractPreviewResults(flowModuleSchemas: FlowModuleSchema[]) { return flowModuleSchemas.map((fms) => fms.previewResult) } +export type JobResult = { + job?: Job + innerJobs?: JobResult[] + loopJobs?: JobResult[] +} + export function mapJobResultsToFlowState( - jobs: CompletedJob[], + jobs: JobResult, config: 'upto' | 'justthis', configIndex: number ): void { - if (!Array.isArray(jobs) || jobs.length === 0) { + if (!Array.isArray(jobs.innerJobs) || jobs.innerJobs.length === 0) { return } if (config === 'justthis') { - const [result] = jobsToResults(jobs) + const job = jobs.job as CompletedJob flowStateStore.update((flowState: FlowState) => { - flowState[configIndex] = result + flowState[configIndex] = job.result return flowState }) } else { - const result = jobsToResults(jobs) + const results = jobs.innerJobs.map(({ job, loopJobs }) => { + if (Array.isArray(loopJobs) && loopJobs.length > 0) { + return loopJobs.map(({ job }) => { + if (job && 'result' in job) { + return job.result + } + }) + } else { + if (job && 'result' in job) { + return job.result + } + } + }) flowStateStore.update((flowState: FlowState) => { if (!Array.isArray(flowState)) { @@ -290,7 +314,7 @@ export function mapJobResultsToFlowState( return flowState.map((flowModuleSchema: FlowModuleSchema, index) => { if (index <= configIndex) { - flowModuleSchema.previewResult = result[index] + flowModuleSchema.previewResult = results[index] } return flowModuleSchema diff --git a/frontend/src/lib/components/preview/FlowPreviewStatus.svelte b/frontend/src/lib/components/preview/FlowPreviewStatus.svelte new file mode 100644 index 0000000000..7e67ca847f --- /dev/null +++ b/frontend/src/lib/components/preview/FlowPreviewStatus.svelte @@ -0,0 +1,31 @@ + + +
+ + + + + + + {#if job} + + + + + {/if} + +
+ Status +
+ Job Id + + + {job?.id} + +
+
diff --git a/frontend/src/lib/components/tabs/Tab.svelte b/frontend/src/lib/components/tabs/Tab.svelte new file mode 100644 index 0000000000..6528fb6a23 --- /dev/null +++ b/frontend/src/lib/components/tabs/Tab.svelte @@ -0,0 +1,13 @@ + + +
(value = index)} +> + +
diff --git a/frontend/src/lib/components/tabs/TabPanel.svelte b/frontend/src/lib/components/tabs/TabPanel.svelte new file mode 100644 index 0000000000..7ab27fb4c3 --- /dev/null +++ b/frontend/src/lib/components/tabs/TabPanel.svelte @@ -0,0 +1,12 @@ + + +{#if value === index} +
+ +
+{/if} diff --git a/frontend/src/lib/components/tabs/Tabs.svelte b/frontend/src/lib/components/tabs/Tabs.svelte new file mode 100644 index 0000000000..5fd29c35d1 --- /dev/null +++ b/frontend/src/lib/components/tabs/Tabs.svelte @@ -0,0 +1,3 @@ +
+ +
diff --git a/frontend/src/lib/stores.ts b/frontend/src/lib/stores.ts index cf77cd3f34..370c4a269d 100644 --- a/frontend/src/lib/stores.ts +++ b/frontend/src/lib/stores.ts @@ -51,3 +51,5 @@ export function clearStores(): void { usersWorkspaceStore.set(undefined) superadmin.set(undefined) } + +export const arePreviewsReady = writable([]) diff --git a/frontend/src/routes/run/[...run].svelte b/frontend/src/routes/run/[...run].svelte index ac0dc1e542..0edf22a523 100644 --- a/frontend/src/routes/run/[...run].svelte +++ b/frontend/src/routes/run/[...run].svelte @@ -330,7 +330,7 @@ {#if job?.job_kind == 'flow' || job?.job_kind == 'flowpreview'}
- +
{/if}