feat(frontend): cancellable inline script editor run

This commit is contained in:
Ruben Fiszel
2023-04-14 00:59:52 +02:00
parent b986ccc0fb
commit 1476f559b7
5 changed files with 85 additions and 33 deletions
@@ -146,7 +146,7 @@
if (previewJobUpdates.new_logs) {
job.logs = (job?.logs ?? '').concat(previewJobUpdates.new_logs)
}
if (previewJobUpdates.mem_peak) {
if (previewJobUpdates.mem_peak && job) {
job.mem_peak = previewJobUpdates.mem_peak
}
if ((previewJobUpdates.running ?? false) || (previewJobUpdates.completed ?? false)) {
@@ -11,7 +11,7 @@
import { createEventDispatcher, getContext, onDestroy } from 'svelte'
import type { AppInputs, Runnable } from '../../inputType'
import type { Output } from '../../rx'
import type { AppViewerContext, InlineScript } from '../../types'
import type { AppViewerContext, CancelablePromise, InlineScript } from '../../types'
import { computeGlobalContext, eval_like } from './eval'
import InputValue from './InputValue.svelte'
import RefreshButton from './RefreshButton.svelte'
@@ -58,12 +58,29 @@
const dispatch = createEventDispatcher()
let donePromise: (() => void) | undefined = undefined
const cancellableRun: (inlineScript?: InlineScript) => CancelablePromise<void> = (
inlineScript?: InlineScript
) => {
let rejectCb: (err: Error) => void
let p: Partial<CancelablePromise<void>> = new Promise<void>((resolve, reject) => {
rejectCb = reject
donePromise = resolve
executeComponent(true, inlineScript).catch(reject)
})
p.cancel = () => {
testJobLoader?.cancelJob()
loading = false
rejectCb(new Error('Canceled'))
}
return p as CancelablePromise<void>
}
$runnableComponents[id] = {
autoRefresh: autoRefresh && recomputableByRefreshButton,
refreshOnStart,
cb: async (inlineScript?: InlineScript) => {
await executeComponent(true, inlineScript)
}
cb: cancellableRun
}
if (!$initialized.initializedComponents.includes(id)) {
@@ -372,6 +389,7 @@
if (startedAt > lastStartedAt) {
lastStartedAt = startedAt
setResult(e.detail.result)
donePromise?.()
}
}
loading = false
@@ -396,7 +396,7 @@
<Skeleton layout={[[40]]} />
{/if}
{:else}
<div class="flex flex-col h-full w-full gap-4 mb-4">
<div class="flex flex-col h-full w-full gap-4 p-2 mb-4">
{#if job?.['running']}
<div class="flex flex-row-reverse w-full">
<Button
@@ -404,6 +404,8 @@
variant="border"
on:click={() => testJobLoader?.cancelJob()}
>
<Loader2 size={14} class="animate-spin mr-2" />
Cancel
</Button>
</div>
@@ -633,7 +635,12 @@
</span>
<span class="hidden md:inline">
<Button
on:click={() => (jobsDrawerOpen = true)}
on:click={() => {
if (selectedJobId == undefined && $jobs.length > 0) {
selectedJobId = $jobs[0].job
}
jobsDrawerOpen = true
}}
color={hasErrors ? 'red' : 'light'}
size="xs"
variant="border"
@@ -2,8 +2,8 @@
import Button from '$lib/components/common/button/Button.svelte'
import type { Preview } from '$lib/gen'
import { createEventDispatcher, getContext, onMount } from 'svelte'
import type { AppViewerContext, InlineScript } from '../../types'
import { CornerDownLeft, Maximize2, Trash2 } from 'lucide-svelte'
import type { AppViewerContext, CancelablePromise, InlineScript } from '../../types'
import { CornerDownLeft, Loader2, Maximize2, Trash2 } from 'lucide-svelte'
import InlineScriptEditorDrawer from './InlineScriptEditorDrawer.svelte'
import { inferArgs } from '$lib/infer'
import type { Schema } from '$lib/common'
@@ -87,6 +87,8 @@
inlineScript?.language == 'frontend' && worldStore
? buildExtraLib($worldStore?.outputsById ?? {}, id, false, $state, true)
: undefined
let cancelable: CancelablePromise<void> | undefined = undefined
</script>
{#if inlineScript}
@@ -166,31 +168,52 @@
</div>
</Button>
{#if $runnableComponents[id] != undefined}
<Button
loading={runLoading}
size="xs"
color="dark"
variant="border"
btnClasses="!px-2 !py-1 !bg-gray-700 !text-white hover:!bg-gray-900"
on:click={async () => {
runLoading = true
await $runnableComponents[id]?.cb?.(!transformer ? inlineScript : undefined)
runLoading = false
}}
>
<div class="flex flex-row gap-1 items-center">
Run
{#if !runLoading}
<Button
loading={runLoading}
size="xs"
color="dark"
variant="border"
btnClasses="!px-2 !py-1 !bg-gray-700 !text-white hover:!bg-gray-900"
on:click={async () => {
runLoading = true
try {
cancelable = $runnableComponents[id]?.cb?.(
!transformer ? inlineScript : undefined
)
await cancelable
} catch {}
runLoading = false
}}
>
<div class="flex flex-row gap-1 items-center">
Run
<div class="flex flex-row items-center gap-1">
<Kbd>{getModifierKey()}</Kbd>
<Kbd>
<div class="h-4 flex items-center justify-center">
<CornerDownLeft size={10} />
</div>
</Kbd>
<div class="flex flex-row items-center gap-1">
<Kbd>{getModifierKey()}</Kbd>
<Kbd>
<div class="h-4 flex items-center justify-center">
<CornerDownLeft size={10} />
</div>
</Kbd>
</div>
</div>
</div>
</Button>
</Button>
{:else}
<Button
size="xs"
color="red"
variant="border"
btnClasses="!px-2 !py-1.5"
on:click={async () => {
cancelable?.cancel()
runLoading = false
}}
>
<Loader2 size={14} class="animate-spin mr-2" />
Cancel
</Button>
{/if}
{/if}
</div>
</div>
+5 -1
View File
@@ -130,6 +130,10 @@ export type ConnectingInput = {
hoveredComponent: string | undefined
}
export interface CancelablePromise<T> extends Promise<T> {
cancel: () => void
}
export type AppViewerContext = {
worldStore: Writable<World>
app: Writable<App>
@@ -148,7 +152,7 @@ export type AppViewerContext = {
{
autoRefresh: boolean
refreshOnStart?: boolean
cb: (inlineScript?: InlineScript) => Promise<void>
cb: (inlineScript?: InlineScript) => CancelablePromise<void>
}
>
>