mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-07 00:01:49 +00:00
approvers are available to the step right after approval
This commit is contained in:
@@ -656,6 +656,7 @@ async fn transform_input(
|
||||
token: &str,
|
||||
steps: Vec<Uuid>,
|
||||
resumes: &[Value],
|
||||
approvers: Vec<String>,
|
||||
by_id: &IdContext,
|
||||
base_internal_url: &str,
|
||||
) -> anyhow::Result<Map<String, serde_json::Value>> {
|
||||
@@ -682,6 +683,7 @@ async fn transform_input(
|
||||
resumes.last().map(|v| json!(v)).unwrap_or_default(),
|
||||
),
|
||||
("resumes".to_string(), resumes.clone().into()),
|
||||
("approvers".to_string(), json!(approvers.clone())),
|
||||
];
|
||||
|
||||
let v = eval_timeout(
|
||||
@@ -854,6 +856,7 @@ async fn push_next_flow_job(
|
||||
};
|
||||
|
||||
let mut resume_messages: Vec<Value> = vec![];
|
||||
let mut approvers: Vec<String> = vec![];
|
||||
|
||||
/* (suspend / resume), when starting a module, if previous module has a
|
||||
* non-zero `suspend` value, collect `resume_job`s for the previous module job.
|
||||
@@ -886,6 +889,12 @@ async fn push_next_flow_job(
|
||||
.await?;
|
||||
|
||||
resume_messages.extend(resumes.iter().map(|r| r.value.clone()));
|
||||
approvers.extend(resumes.iter().map(|r| {
|
||||
r.approver
|
||||
.as_deref()
|
||||
.unwrap_or_else(|| "anonymous")
|
||||
.to_string()
|
||||
}));
|
||||
|
||||
let required_events = suspend.required_events.unwrap() as u16;
|
||||
if resume_messages.len() >= required_events as usize {
|
||||
@@ -1087,6 +1096,7 @@ async fn push_next_flow_job(
|
||||
&token,
|
||||
steps.to_vec(),
|
||||
resume_messages.as_slice(),
|
||||
approvers,
|
||||
by_id,
|
||||
base_internal_url,
|
||||
)
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
class="text-xs text-blue-500"
|
||||
on:click={async () => {
|
||||
await getResource(value.substring('$res:'.length))
|
||||
jsonViewer.openModal()
|
||||
jsonViewer.toggleDrawer()
|
||||
}}>{value}</button
|
||||
>{:else if asJson.length > 40}
|
||||
{truncate(asJson, 40)}<a
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
<Badge large>
|
||||
<Icon data={faHourglassHalf} scale={SMALL_ICON_SCALE} class="mr-2" />
|
||||
Job ran in {msToSec(job.duration_ms)} s
|
||||
Ran in {msToSec(job.duration_ms)} s
|
||||
</Badge>
|
||||
</div>
|
||||
{:else if job && 'success' in job}
|
||||
@@ -39,7 +39,7 @@
|
||||
</Badge>
|
||||
<Badge large>
|
||||
<Icon data={faHourglassHalf} scale={SMALL_ICON_SCALE} class="mr-2" />
|
||||
Job ran in {msToSec(job.duration_ms)}s
|
||||
Ran in {msToSec(job.duration_ms)}s
|
||||
</Badge>
|
||||
</div>
|
||||
{:else if job && 'running' in job && job.running}
|
||||
|
||||
@@ -200,16 +200,18 @@
|
||||
/>
|
||||
</div>
|
||||
<h2 class="border-b pb-1 mt-4"> Metadata </h2>
|
||||
<Button
|
||||
color="light"
|
||||
size="sm"
|
||||
endIcon={{ icon: viewScriptKind ? faChevronUp : faChevronDown }}
|
||||
on:click={() => (viewScriptKind = !viewScriptKind)}
|
||||
>
|
||||
Specialize the script as a specific module kind for flows
|
||||
</Button>
|
||||
<div>
|
||||
<Button
|
||||
color="light"
|
||||
size="sm"
|
||||
endIcon={{ icon: viewScriptKind ? faChevronUp : faChevronDown }}
|
||||
on:click={() => (viewScriptKind = !viewScriptKind)}
|
||||
>
|
||||
Specialize the script as a specific module kind for flows
|
||||
</Button>
|
||||
</div>
|
||||
{#if viewScriptKind}
|
||||
<div class="max-w-lg" transition:slide>
|
||||
<div class="max-w-lg">
|
||||
<RadioButton
|
||||
label="Script Type"
|
||||
options={[
|
||||
@@ -249,17 +251,18 @@
|
||||
</div>
|
||||
{/if}
|
||||
{#if script.language == 'deno' && script.kind == Script.kind.SCRIPT}
|
||||
<Button
|
||||
color="light"
|
||||
size="sm"
|
||||
endIcon={{ icon: viewTemplate ? faChevronUp : faChevronDown }}
|
||||
on:click={() => (viewTemplate = !viewTemplate)}
|
||||
>
|
||||
Use a predefined template specific to this language and script kind
|
||||
</Button>
|
||||
|
||||
<div
|
||||
><Button
|
||||
color="light"
|
||||
size="sm"
|
||||
endIcon={{ icon: viewTemplate ? faChevronUp : faChevronDown }}
|
||||
on:click={() => (viewTemplate = !viewTemplate)}
|
||||
>
|
||||
Use a predefined template specific to this language and script kind
|
||||
</Button>
|
||||
</div>
|
||||
{#if viewTemplate}
|
||||
<div class="max-w-lg" transition:slide>
|
||||
<div class="max-w-lg">
|
||||
<RadioButton
|
||||
label="Template"
|
||||
options={[
|
||||
|
||||
@@ -45,8 +45,9 @@
|
||||
},
|
||||
light: {
|
||||
border:
|
||||
'border bg-white hover:bg-gray-100 focus:bg-gray-100 text-gray-700 hover:text-gray-800 focus:text-gray-800 focus:ring-gray-300',
|
||||
contained: 'bg-white hover:bg-gray-100 focus:bg-gray-100 text-gray-700 focus:ring-gray-300'
|
||||
'border border-gray-300 bg-white hover:bg-gray-100 focus:bg-gray-100 text-gray-700 hover:text-gray-800 focus:text-gray-800 focus:ring-gray-300',
|
||||
contained:
|
||||
'bg-white border-gray-300 hover:bg-gray-100 focus:bg-gray-100 text-gray-700 focus:ring-gray-300'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
modules: Array<FlowModule>
|
||||
}
|
||||
export let parentModule: FlowModule | undefined
|
||||
export let previousModuleId: string | undefined
|
||||
export let previousModule: FlowModule | undefined
|
||||
|
||||
const { previewArgs } = getContext<FlowEditorContext>('FlowEditorContext')
|
||||
let editor: SimpleEditor | undefined = undefined
|
||||
@@ -25,9 +25,10 @@
|
||||
$: pickableProperties = getStepPropPicker(
|
||||
$flowStateStore,
|
||||
parentModule,
|
||||
previousModuleId,
|
||||
previousModule,
|
||||
$flowStore,
|
||||
previewArgs
|
||||
previewArgs,
|
||||
true
|
||||
).pickableProperties
|
||||
</script>
|
||||
|
||||
@@ -43,7 +44,7 @@
|
||||
<span class="mb-2 text-sm font-bold">Branch predicate</span>
|
||||
<div class="border w-full">
|
||||
<PropPickerWrapper
|
||||
priorId={previousModuleId}
|
||||
priorId={previousModule?.id}
|
||||
{pickableProperties}
|
||||
on:select={({ detail }) => {
|
||||
editor?.insertAtCursor(detail)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
export let flowModule: FlowModule
|
||||
export let parentModule: FlowModule | undefined
|
||||
export let previousModuleId: string | undefined
|
||||
export let previousModule: FlowModule | undefined
|
||||
|
||||
let selected: string = 'early-stop'
|
||||
</script>
|
||||
@@ -77,13 +77,17 @@
|
||||
|
||||
<TabContent value="early-stop" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleEarlyStop {previousModuleId} bind:flowModule {parentModule} />
|
||||
<FlowModuleEarlyStop
|
||||
previousModuleId={previousModule?.id}
|
||||
bind:flowModule
|
||||
{parentModule}
|
||||
/>
|
||||
</div>
|
||||
</TabContent>
|
||||
|
||||
<TabContent value="suspend" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleSuspend {previousModuleId} bind:flowModule />
|
||||
<FlowModuleSuspend previousModuleId={previousModule?.id} bind:flowModule />
|
||||
</div>
|
||||
</TabContent>
|
||||
</div>
|
||||
|
||||
@@ -24,10 +24,7 @@
|
||||
<FlowFailureModule />
|
||||
{:else}
|
||||
{#each $flowStore.value.modules as flowModule, index (flowModule.id ?? index)}
|
||||
<FlowModuleWrapper
|
||||
bind:flowModule
|
||||
previousModuleId={$flowStore.value.modules[index - 1]?.id}
|
||||
/>
|
||||
<FlowModuleWrapper bind:flowModule previousModule={$flowStore.value.modules[index - 1]} />
|
||||
{/each}
|
||||
{/if}
|
||||
{/key}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
</script>
|
||||
|
||||
<div class="space-y-4 p-4">
|
||||
<div class="text-sm font-bold">Common script</div>
|
||||
<div class="text-sm font-bold">{failureModule ? 'Error handler' : 'Common script'}</div>
|
||||
<div class="grid sm:grid-col-2 lg:grid-cols-3 gap-4">
|
||||
<FlowScriptPicker
|
||||
label="Inline Python (3.10)"
|
||||
@@ -23,8 +23,8 @@
|
||||
on:click={() => {
|
||||
dispatch('new', {
|
||||
language: RawScript.language.PYTHON3,
|
||||
kind: 'script',
|
||||
subkind: failureModule ? 'failure' : 'flow'
|
||||
kind: failureModule ? 'failure' : 'script',
|
||||
subkind: 'flow'
|
||||
})
|
||||
}}
|
||||
/>
|
||||
@@ -36,8 +36,8 @@
|
||||
on:click={() => {
|
||||
dispatch('new', {
|
||||
language: RawScript.language.DENO,
|
||||
kind: 'script',
|
||||
subkind: failureModule ? 'failure' : 'flow'
|
||||
kind: failureModule ? 'failure' : 'script',
|
||||
subkind: 'flow'
|
||||
})
|
||||
}}
|
||||
/>
|
||||
@@ -49,8 +49,8 @@
|
||||
on:click={() => {
|
||||
dispatch('new', {
|
||||
language: RawScript.language.GO,
|
||||
kind: 'script',
|
||||
subkind: failureModule ? 'failure' : 'flow'
|
||||
kind: failureModule ? 'failure' : 'script',
|
||||
subkind: 'flow'
|
||||
})
|
||||
}}
|
||||
/>
|
||||
@@ -81,9 +81,9 @@
|
||||
<div class="text-sm font-bold pt-8">
|
||||
Trigger script
|
||||
<Tooltip>
|
||||
Used as a first step most commonly with an internal state and a schedule to watch for changes
|
||||
on an external system, compute the diff since last time, set the new state. The diffs are
|
||||
then treated one by one with a for-loop.
|
||||
Used as a first step most commonly with an internal state and a schedule to watch for
|
||||
changes on an external system, compute the diff since last time, set the new state. The
|
||||
diffs are then treated one by one with a for-loop.
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
export let mod: FlowModule
|
||||
export let parentModule: FlowModule | undefined
|
||||
export let previousModuleId: string | undefined
|
||||
export let previousModule: FlowModule | undefined
|
||||
|
||||
let editor: SimpleEditor | undefined = undefined
|
||||
let selected: string = 'early-stop'
|
||||
@@ -28,9 +28,10 @@
|
||||
$: pickableProperties = getStepPropPicker(
|
||||
$flowStateStore,
|
||||
parentModule,
|
||||
previousModuleId,
|
||||
previousModule,
|
||||
$flowStore,
|
||||
previewArgs
|
||||
previewArgs,
|
||||
true
|
||||
).pickableProperties
|
||||
</script>
|
||||
|
||||
@@ -52,7 +53,7 @@
|
||||
{#if mod.value.iterator.type == 'javascript'}
|
||||
<div class="border w-full">
|
||||
<PropPickerWrapper
|
||||
priorId={previousModuleId}
|
||||
priorId={previousModule?.id}
|
||||
{pickableProperties}
|
||||
on:select={({ detail }) => {
|
||||
editor?.insertAtCursor(detail)
|
||||
@@ -106,13 +107,17 @@
|
||||
|
||||
<TabContent value="early-stop" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleEarlyStop {previousModuleId} bind:flowModule={mod} {parentModule} />
|
||||
<FlowModuleEarlyStop
|
||||
previousModuleId={previousModule?.id}
|
||||
bind:flowModule={mod}
|
||||
{parentModule}
|
||||
/>
|
||||
</div>
|
||||
</TabContent>
|
||||
|
||||
<TabContent value="suspend" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleSuspend {previousModuleId} bind:flowModule={mod} />
|
||||
<FlowModuleSuspend previousModuleId={previousModule?.id} bind:flowModule={mod} />
|
||||
</div>
|
||||
</TabContent>
|
||||
</div>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
export let failureModule: boolean = false
|
||||
|
||||
export let parentModule: FlowModule | undefined = undefined
|
||||
export let previousModuleId: string | undefined = undefined
|
||||
export let previousModule: FlowModule | undefined
|
||||
|
||||
let editor: Editor
|
||||
let modulePreview: ModulePreview
|
||||
@@ -54,7 +54,14 @@
|
||||
|
||||
$: stepPropPicker = failureModule
|
||||
? { pickableProperties: { previous_result: { error: 'the error message' } }, extraLib: '' }
|
||||
: getStepPropPicker($flowStateStore, parentModule, previousModuleId, $flowStore, previewArgs)
|
||||
: getStepPropPicker(
|
||||
$flowStateStore,
|
||||
parentModule,
|
||||
previousModule,
|
||||
$flowStore,
|
||||
previewArgs,
|
||||
true
|
||||
)
|
||||
|
||||
function onKeyDown(event: KeyboardEvent) {
|
||||
if ((event.ctrlKey || event.metaKey) && event.key == 'Enter') {
|
||||
@@ -178,7 +185,7 @@
|
||||
{#if selected === 'inputs'}
|
||||
<div class="h-full overflow-auto">
|
||||
<PropPickerWrapper
|
||||
priorId={previousModuleId}
|
||||
priorId={previousModule?.id}
|
||||
pickableProperties={stepPropPicker.pickableProperties}
|
||||
>
|
||||
<SchemaForm
|
||||
@@ -200,14 +207,14 @@
|
||||
<FlowRetries bind:flowModule class="px-4 pb-4 h-full overflow-auto" />
|
||||
{:else if selected === 'early-stop'}
|
||||
<FlowModuleEarlyStop
|
||||
{previousModuleId}
|
||||
previousModuleId={previousModule?.id}
|
||||
bind:flowModule
|
||||
class="px-4 pb-4 h-full overflow-auto"
|
||||
{parentModule}
|
||||
/>
|
||||
{:else if selected === 'suspend'}
|
||||
<div class="px-4 pb-4 h-full overflow-auto">
|
||||
<FlowModuleSuspend {previousModuleId} bind:flowModule />
|
||||
<FlowModuleSuspend previousModuleId={previousModule?.id} bind:flowModule />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
|
||||
const { previewArgs } = getContext<FlowEditorContext>('FlowEditorContext')
|
||||
|
||||
export let previousModuleId: string | undefined
|
||||
export let flowModule: FlowModule
|
||||
export let parentModule: FlowModule | undefined
|
||||
export let previousModuleId: string | undefined
|
||||
|
||||
let editor: SimpleEditor | undefined = undefined
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
const propPicker = getStepPropPicker(
|
||||
$flowStateStore,
|
||||
parentModule,
|
||||
flowModule.id,
|
||||
flowModule,
|
||||
$flowStore,
|
||||
previewArgs
|
||||
).pickableProperties
|
||||
|
||||
@@ -28,14 +28,14 @@
|
||||
// Pointer to parent module, only defined within Branches or Loops.
|
||||
export let parentModule: FlowModule | undefined = undefined
|
||||
// Pointer to previous module, for easy access to testing results
|
||||
export let previousModuleId: string | undefined = undefined
|
||||
export let previousModule: FlowModule | undefined = undefined
|
||||
</script>
|
||||
|
||||
{#if flowModule.id === $selectedId}
|
||||
{#if flowModule.value.type === 'forloopflow'}
|
||||
<FlowLoop bind:mod={flowModule} {parentModule} {previousModuleId} />
|
||||
<FlowLoop bind:mod={flowModule} {parentModule} {previousModule} />
|
||||
{:else if flowModule.value.type === 'branchone' || flowModule.value.type === 'branchall'}
|
||||
<FlowBranchesWrapper {previousModuleId} bind:flowModule {parentModule} />
|
||||
<FlowBranchesWrapper {previousModule} bind:flowModule {parentModule} />
|
||||
{:else if flowModule.value.type === 'identity'}
|
||||
{#if $selectedId == 'failure'}
|
||||
<Alert type="info" title="Error handlers are triggered upon non recovered errors">
|
||||
@@ -46,15 +46,19 @@
|
||||
Steps are retried until they succeed, or until the maximum number of retries defined for that
|
||||
spec is reached, at which point the error handler is called.
|
||||
</Alert>
|
||||
{:else}
|
||||
<h1 class="p-4"
|
||||
>Select a step kind <Tooltip
|
||||
>Until being defined, this step acts as an identify function, returning as result its
|
||||
input and assigning it a key 'previous_result' if the input is not a json object</Tooltip
|
||||
></h1
|
||||
>
|
||||
{/if}
|
||||
<h1 class="p-4"
|
||||
>Select a step kind <Tooltip
|
||||
>Until being defined, this step acts as an identify function, returning as result its input
|
||||
and assigning it a key 'previous_result' if the input is not a json object</Tooltip
|
||||
></h1
|
||||
>
|
||||
|
||||
<FlowInputs
|
||||
shouldDisableTriggerScripts={parentModule !== undefined || previousModuleId !== undefined}
|
||||
shouldDisableTriggerScripts={parentModule !== undefined ||
|
||||
previousModule !== undefined ||
|
||||
$selectedId == 'failure'}
|
||||
on:loop={async () => {
|
||||
const [module, state] = await createLoop(flowModule.id)
|
||||
flowModule = module
|
||||
@@ -101,7 +105,7 @@
|
||||
failureModule={$selectedId === 'failure'}
|
||||
/>
|
||||
{:else if flowModule.value.type === 'rawscript' || flowModule.value.type === 'script'}
|
||||
<FlowModuleComponent bind:flowModule {parentModule} {previousModuleId} />
|
||||
<FlowModuleComponent bind:flowModule {parentModule} {previousModule} />
|
||||
{/if}
|
||||
{:else if flowModule.value.type === 'forloopflow'}
|
||||
{#each flowModule.value.modules as submodule, index (index)}
|
||||
@@ -125,7 +129,7 @@
|
||||
{/if}
|
||||
{#each flowModule.value.branches as branch, branchIndex (branchIndex)}
|
||||
{#if $selectedId === `${flowModule?.id}-branch-${branchIndex}`}
|
||||
<FlowBranchOneWrapper bind:branch parentModule={flowModule} {previousModuleId} />
|
||||
<FlowBranchOneWrapper bind:branch parentModule={flowModule} {previousModule} />
|
||||
{:else}
|
||||
{#each branch.modules as submodule, index}
|
||||
<svelte:self
|
||||
|
||||
@@ -123,21 +123,27 @@ function getFlowInput(
|
||||
export function getStepPropPicker(
|
||||
flowState: FlowState,
|
||||
parentModule: FlowModule | undefined,
|
||||
previousModuleId: string | undefined,
|
||||
previousModule: FlowModule | undefined,
|
||||
flow: Flow,
|
||||
args: any
|
||||
args: any,
|
||||
approvers: boolean = false
|
||||
): StepPropPicker {
|
||||
const flowInput = getFlowInput(dfs(parentModule?.id, flow), flowState, args, flow.schema)
|
||||
|
||||
const previousResults = previousModuleId
|
||||
? flowState[previousModuleId].previewResult
|
||||
const previousResults = previousModule
|
||||
? flowState[previousModule.id].previewResult
|
||||
: flattenPreviousResult(flowInput)
|
||||
|
||||
const pickableProperties = {
|
||||
flow_input: flowInput,
|
||||
previous_result: previousResults
|
||||
}
|
||||
|
||||
if (approvers && ((previousModule?.suspend?.required_events ?? 0) > 0)) {
|
||||
pickableProperties["approvers"] = "The list of approvers"
|
||||
}
|
||||
return {
|
||||
extraLib: buildExtraLib(objectToTsType(flowInput), objectToTsType(previousResults)),
|
||||
pickableProperties: {
|
||||
flow_input: flowInput,
|
||||
previous_result: previousResults
|
||||
}
|
||||
pickableProperties
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ export async function main(approver?: string) {
|
||||
return wmill.getResumeEndpoints(approver)
|
||||
}`
|
||||
|
||||
const ALL_INITIAL_CODE = [PYTHON_INIT_CODE, DENO_INIT_CODE, POSTGRES_INIT_CODE, DENO_INIT_CODE_TRIGGER, DENO_INIT_CODE_CLEAR, PYTHON_INIT_CODE_CLEAR, DENO_INIT_CODE_APPROVAL]
|
||||
const ALL_INITIAL_CODE = [PYTHON_INIT_CODE, DENO_INIT_CODE, POSTGRES_INIT_CODE, DENO_INIT_CODE_TRIGGER, DENO_INIT_CODE_CLEAR, PYTHON_INIT_CODE_CLEAR, DENO_INIT_CODE_APPROVAL, DENO_FAILURE_MODULE_CODE]
|
||||
|
||||
export function isInitialCode(content: string): boolean {
|
||||
for (const code of ALL_INITIAL_CODE) {
|
||||
@@ -177,36 +177,37 @@ export function isInitialCode(content: string): boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
export function initialCode(language: 'deno' | 'python3' | 'go', kind: Script.kind, subkind: 'pgsql' | 'flow' | 'script' | 'failure' | 'approval' | undefined): string {
|
||||
export function initialCode(language: 'deno' | 'python3' | 'go', kind: Script.kind, subkind: 'pgsql' | 'flow' | 'script' | undefined): string {
|
||||
if (language === 'deno') {
|
||||
if (kind === 'trigger') {
|
||||
return DENO_INIT_CODE_TRIGGER
|
||||
} else if (kind === 'script') {
|
||||
if (subkind === 'flow') {
|
||||
return DENO_INIT_CODE_CLEAR
|
||||
} else if (subkind === 'failure') {
|
||||
return DENO_FAILURE_MODULE_CODE
|
||||
} else if (subkind === 'approval') {
|
||||
return DENO_INIT_CODE_APPROVAL
|
||||
}
|
||||
else if (subkind === 'pgsql') {
|
||||
return POSTGRES_INIT_CODE
|
||||
} else {
|
||||
return DENO_INIT_CODE
|
||||
}
|
||||
} else {
|
||||
} else if (kind === 'failure') {
|
||||
return DENO_FAILURE_MODULE_CODE
|
||||
} else if (kind === 'approval') {
|
||||
return DENO_INIT_CODE_APPROVAL
|
||||
}
|
||||
else {
|
||||
return DENO_INIT_CODE
|
||||
}
|
||||
} else if (language === 'python3') {
|
||||
if (subkind === 'flow') {
|
||||
return PYTHON_INIT_CODE_CLEAR
|
||||
} else if (subkind === 'failure') {
|
||||
} else if (kind === 'failure') {
|
||||
return PYTHON_FAILURE_MODULE_CODE
|
||||
} else {
|
||||
return PYTHON_INIT_CODE
|
||||
}
|
||||
} else {
|
||||
if (subkind === 'failure') {
|
||||
if (kind === 'failure') {
|
||||
return GO_FAILURE_MODULE_CODE
|
||||
} else {
|
||||
return GO_INIT_CODE
|
||||
|
||||
@@ -276,7 +276,7 @@ export function groupBy<T>(
|
||||
|
||||
export function truncate(s: string, n: number, suffix: string = '...'): string {
|
||||
if (!s) {
|
||||
return suffix
|
||||
return ''
|
||||
}
|
||||
if (s.length <= n) {
|
||||
return s
|
||||
|
||||
@@ -45,15 +45,19 @@
|
||||
})
|
||||
|
||||
async function getJob() {
|
||||
const suspendedJobFlow = await JobService.getSuspendedJobFlow({
|
||||
workspace: $page.params.workspace,
|
||||
id: $page.params.job,
|
||||
resumeId: new Number($page.params.resume).valueOf(),
|
||||
signature: $page.params.hmac,
|
||||
approver
|
||||
})
|
||||
job = suspendedJobFlow.job
|
||||
currentApprovers = suspendedJobFlow.approvers
|
||||
try {
|
||||
const suspendedJobFlow = await JobService.getSuspendedJobFlow({
|
||||
workspace: $page.params.workspace,
|
||||
id: $page.params.job,
|
||||
resumeId: new Number($page.params.resume).valueOf(),
|
||||
signature: $page.params.hmac,
|
||||
approver
|
||||
})
|
||||
job = suspendedJobFlow.job
|
||||
currentApprovers = suspendedJobFlow.approvers
|
||||
} catch (e) {
|
||||
sendUserToast(e.message, true)
|
||||
}
|
||||
}
|
||||
|
||||
async function resume() {
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
faScroll,
|
||||
faFastForward
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import DisplayResult from '$lib/components/DisplayResult.svelte'
|
||||
import { userStore, workspaceStore } from '$lib/stores'
|
||||
import CenteredPage from '$lib/components/CenteredPage.svelte'
|
||||
@@ -33,10 +32,11 @@
|
||||
import HighlightCode from '$lib/components/HighlightCode.svelte'
|
||||
import TestJobLoader from '$lib/components/TestJobLoader.svelte'
|
||||
import LogViewer from '$lib/components/LogViewer.svelte'
|
||||
import { Button, ActionRow, Skeleton } from '$lib/components/common'
|
||||
import { Button, ActionRow, Skeleton, Tab } from '$lib/components/common'
|
||||
import FlowMetadata from '$lib/components/FlowMetadata.svelte'
|
||||
import JobArgs from '$lib/components/JobArgs.svelte'
|
||||
import FlowProgressBar from '$lib/components/flows/FlowProgressBar.svelte'
|
||||
import Tabs from '$lib/components/common/tabs/Tabs.svelte'
|
||||
|
||||
let workspace_id_query: string | undefined = $page.url.searchParams.get('workspace') ?? undefined
|
||||
let workspace_id: string | undefined
|
||||
@@ -252,40 +252,14 @@
|
||||
{#if job?.job_kind !== 'flow' && job?.job_kind !== 'flowpreview'}
|
||||
<!-- Logs and outputs-->
|
||||
<div class="mr-2 sm:mr-0 mt-12">
|
||||
<div class="flex flex-col sm:flex-row text-base">
|
||||
<button
|
||||
class=" py-1 px-6 block border-gray-200 hover:bg-gray-50 {viewTab !== 'result'
|
||||
? 'text-gray-500'
|
||||
: 'text-gray-700 font-semibold '}"
|
||||
on:click={() => (viewTab = 'result')}
|
||||
<Tabs bind:selected={viewTab}>
|
||||
<Tab value="result">Result</Tab>
|
||||
<Tab value="logs">Logs</Tab>
|
||||
<Tab value="code"
|
||||
>{job?.job_kind == 'dependencies' ? 'Input Dependencies' : 'Code previewed'}</Tab
|
||||
>
|
||||
Result <Tooltip
|
||||
>What is returned by the <span class="font-mono">main</span> function of the script,
|
||||
stringified to JSON. Then for some specific cases, like having "png", "jpeg" or "file"
|
||||
as sole key, they are displayed more richly. See
|
||||
<a href="https://docs.windmill.dev/docs/reference#rich-display-rendering">here</a> for more
|
||||
details.</Tooltip
|
||||
>
|
||||
</button>
|
||||
<button
|
||||
class="py-1 px-6 block border-gray-200 hover:bg-gray-50 {viewTab !== 'logs'
|
||||
? 'text-gray-500'
|
||||
: 'text-gray-700 font-semibold '}"
|
||||
on:click={() => (viewTab = 'logs')}
|
||||
>
|
||||
Logs
|
||||
</button>
|
||||
{#if job && 'raw_code' in job && job.raw_code}
|
||||
<button
|
||||
class="py-1 px-6 block border-gray-200 hover:bg-gray-50 {viewTab !== 'code'
|
||||
? 'text-gray-500'
|
||||
: 'text-gray-700 font-semibold '}"
|
||||
on:click={() => (viewTab = 'code')}
|
||||
>
|
||||
{job.job_kind == 'dependencies' ? 'Input Dependencies' : 'Code previewed'}
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</Tabs>
|
||||
|
||||
<Skeleton loading={!job} layout={[[5]]} />
|
||||
{#if job}
|
||||
<div class="flex flex-row border rounded-md p-3 max-h-1/2 overflow-auto">
|
||||
|
||||
Reference in New Issue
Block a user