249 lines
6.5 KiB
Svelte
249 lines
6.5 KiB
Svelte
<script lang="ts">
|
|
import {
|
|
defaultIfEmptyString,
|
|
displayDaysAgo,
|
|
emptyString,
|
|
getToday,
|
|
truncateHash
|
|
} from '$lib/utils'
|
|
import { slide } from 'svelte/transition'
|
|
|
|
import type { Schema } from '$lib/common'
|
|
import { runFormStore, userStore } from '$lib/stores'
|
|
import { faChevronDown, faChevronUp } from '@fortawesome/free-solid-svg-icons'
|
|
import CliHelpBox from './CliHelpBox.svelte'
|
|
import { Badge, Button } from './common'
|
|
import InlineCodeCopy from './InlineCodeCopy.svelte'
|
|
import SchemaForm from './SchemaForm.svelte'
|
|
import SharedBadge from './SharedBadge.svelte'
|
|
import Toggle from './Toggle.svelte'
|
|
import Tooltip from './Tooltip.svelte'
|
|
import CollapseLink from './CollapseLink.svelte'
|
|
import { SCRIPT_VIEW_SHOW_RUN_FROM_CLI, SCRIPT_VIEW_SHOW_SCHEDULE_RUN_LATER } from '$lib/consts'
|
|
|
|
export let runnable:
|
|
| {
|
|
summary?: string
|
|
schema?: Schema
|
|
description?: string
|
|
path?: string
|
|
is_template?: boolean
|
|
hash?: string
|
|
kind?: string
|
|
can_write?: boolean
|
|
created_at?: string
|
|
created_by?: string
|
|
extra_perms?: Record<string, boolean>
|
|
}
|
|
| undefined
|
|
export let runAction: (
|
|
scheduledForStr: string | undefined,
|
|
args: Record<string, any>,
|
|
invisible_to_owner?: boolean
|
|
) => void
|
|
export let buttonText = 'Run'
|
|
export let schedulable = true
|
|
export let detailed = true
|
|
export let autofocus = false
|
|
export let topButton = false
|
|
export let loading = false
|
|
export let noVariablePicker = false
|
|
export let viewCliRun = false
|
|
export let isFlow: boolean
|
|
|
|
export let args: Record<string, any> = {}
|
|
|
|
if ($runFormStore) {
|
|
args = $runFormStore
|
|
$runFormStore = undefined
|
|
}
|
|
|
|
export function run() {
|
|
runAction(scheduledForStr, args, invisible_to_owner)
|
|
}
|
|
|
|
export let isValid = true
|
|
|
|
let viewOptions = false
|
|
let viewCliOptions = false
|
|
|
|
let scheduledForStr: string | undefined
|
|
let invisible_to_owner: false
|
|
|
|
$: cliCommand = `wmill ${isFlow ? 'flow' : 'script'} run ${runnable?.path} -d '${JSON.stringify(
|
|
args
|
|
)}'`
|
|
</script>
|
|
|
|
<div class="max-w-6xl">
|
|
{#if detailed}
|
|
{#if runnable}
|
|
<div class="flex flex-row flex-wrap justify-between gap-4">
|
|
<div>
|
|
<div class="flex flex-col mb-2">
|
|
<h1 class="break-words py-2 mr-2">
|
|
{defaultIfEmptyString(runnable.summary, runnable.path ?? '')}
|
|
</h1>
|
|
{#if !emptyString(runnable.summary)}
|
|
<h2 class="font-bold pb-4">{runnable.path}</h2>
|
|
{/if}
|
|
|
|
<div class="flex items-center gap-2">
|
|
<span class="text-sm text-gray-500">
|
|
{#if runnable}
|
|
Edited {displayDaysAgo(runnable.created_at || '')} by {runnable.created_by ||
|
|
'unknown'}
|
|
{/if}
|
|
</span>
|
|
<Badge color="dark-gray">
|
|
{truncateHash(runnable?.hash ?? '')}
|
|
</Badge>
|
|
{#if runnable?.is_template}
|
|
<Badge color="blue">Template</Badge>
|
|
{/if}
|
|
{#if runnable && runnable.kind !== 'runnable'}
|
|
<Badge color="blue">
|
|
{runnable?.kind}
|
|
</Badge>
|
|
{/if}
|
|
<SharedBadge
|
|
canWrite={runnable.can_write ?? true}
|
|
extraPerms={runnable?.extra_perms ?? {}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{:else}
|
|
<h1>Loading...</h1>
|
|
{/if}
|
|
{/if}
|
|
{#if topButton}
|
|
<Button
|
|
btnClasses="!px-6 !py-1 w-full"
|
|
disabled={!isValid}
|
|
on:click={() => runAction(undefined, args)}
|
|
>
|
|
{buttonText}
|
|
</Button>
|
|
{/if}
|
|
{#if runnable?.schema}
|
|
<div class="my-2" />
|
|
{#if !runnable.schema.properties || Object.keys(runnable.schema.properties).length === 0}
|
|
<div class="text-sm p-4">No arguments</div>
|
|
{:else}
|
|
<SchemaForm {noVariablePicker} {autofocus} schema={runnable.schema} bind:isValid bind:args />
|
|
{/if}
|
|
{:else}
|
|
<div class="text-xs text-gray-600">No schema</div>
|
|
{/if}
|
|
{#if schedulable}
|
|
<div class="mt-10" />
|
|
<CollapseLink text="Advanced">
|
|
<div class="flex flex-col gap-4 mt-2 border p-2">
|
|
<div class="flex flex-col gap-2">
|
|
{#if SCRIPT_VIEW_SHOW_SCHEDULE_RUN_LATER}
|
|
<div class="flex">
|
|
<Button
|
|
color="light"
|
|
size="sm"
|
|
endIcon={{ icon: viewOptions ? faChevronUp : faChevronDown }}
|
|
on:click={() => (viewOptions = !viewOptions)}
|
|
>
|
|
Schedule to run later
|
|
</Button>
|
|
</div>
|
|
{/if}
|
|
{#if viewOptions}
|
|
<div transition:slide|local class="mt-6">
|
|
<div class="border rounded-md p-3 pt-4">
|
|
<div class="flex flex-row items-end">
|
|
<div class="w-max md:w-2/3 mt-2 mb-1">
|
|
<label for="run-time" />
|
|
<input
|
|
class="inline-block"
|
|
type="datetime-local"
|
|
id="run-time"
|
|
name="run-scheduled-time"
|
|
bind:value={scheduledForStr}
|
|
min={getToday().toISOString().slice(0, 16)}
|
|
/>
|
|
</div>
|
|
<Button
|
|
variant="border"
|
|
color="blue"
|
|
size="sm"
|
|
btnClasses="mx-2 mb-1"
|
|
on:click={() => {
|
|
scheduledForStr = undefined
|
|
}}
|
|
>
|
|
Clear
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
{#if runnable?.path?.startsWith(`u/${$userStore?.username}`) != true && (runnable?.path?.split('/')?.length ?? 0) > 2}
|
|
<div class="flex items-center gap-1">
|
|
<Toggle
|
|
options={{
|
|
right: `make run invisible to others`
|
|
}}
|
|
bind:checked={invisible_to_owner}
|
|
/>
|
|
<Tooltip
|
|
>By default, runs are visible to the owner(s) of the script or flow being triggered</Tooltip
|
|
>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
</CollapseLink>
|
|
<div class="flex gap-2 items-start flex-wrap justify-between mt-2 md:mt-6 mb-6">
|
|
<div class="flex-row-reverse flex grow">
|
|
<Button
|
|
{loading}
|
|
btnClasses="!px-6 !py-1"
|
|
disabled={!isValid}
|
|
on:click={() => runAction(scheduledForStr, args, invisible_to_owner)}
|
|
>
|
|
{scheduledForStr ? 'Schedule to run later' : buttonText}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
{:else if !topButton}
|
|
<Button
|
|
btnClasses="!px-6 !py-1 w-full"
|
|
disabled={!isValid}
|
|
on:click={() => runAction(undefined, args, invisible_to_owner)}
|
|
>
|
|
{buttonText}
|
|
</Button>
|
|
{/if}
|
|
|
|
{#if viewCliRun}
|
|
<div>
|
|
<div class="my-20" />
|
|
{#if SCRIPT_VIEW_SHOW_RUN_FROM_CLI}
|
|
<div class="flex">
|
|
<Button
|
|
color="light"
|
|
size="xs"
|
|
endIcon={{ icon: viewCliOptions ? faChevronUp : faChevronDown }}
|
|
on:click={() => (viewCliOptions = !viewCliOptions)}
|
|
>
|
|
Run it from the CLI
|
|
</Button>
|
|
</div>
|
|
{/if}
|
|
{#if viewCliOptions}
|
|
<div transition:slide|local class="mt-2 px-4 pt-2">
|
|
<InlineCodeCopy content={cliCommand} />
|
|
<CliHelpBox />
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
{/if}
|
|
</div>
|