diff --git a/frontend/src/lib/components/Path.svelte b/frontend/src/lib/components/Path.svelte index 85f9df1ec5..dafd4320af 100644 --- a/frontend/src/lib/components/Path.svelte +++ b/frontend/src/lib/components/Path.svelte @@ -138,7 +138,7 @@ } export async function reset() { - if (path == '' || path == 'u//') { + if (path == '' || path == 'u//' || path?.startsWith('tmp/')) { if ($lastMetaUsed == undefined || $lastMetaUsed.owner != $userStore?.username) { meta = { ownerKind: hideUser ? 'folder' : 'user', @@ -323,12 +323,12 @@ async function initPath() { await tick() - if (path != undefined && path != '') { + if (path != undefined && path != '' && !path?.startsWith('tmp/')) { meta = pathToMeta(path, hideUser) onMetaChange() return } - if (initialPath == undefined || initialPath == '') { + if (initialPath == undefined || initialPath == '' || initialPath?.startsWith('tmp/')) { reset() } else { meta = pathToMeta(initialPath, hideUser) diff --git a/frontend/src/lib/components/ScriptBuilder.svelte b/frontend/src/lib/components/ScriptBuilder.svelte index fa817b4058..4b386aa363 100644 --- a/frontend/src/lib/components/ScriptBuilder.svelte +++ b/frontend/src/lib/components/ScriptBuilder.svelte @@ -379,7 +379,7 @@ if (templateScript) { script.content += '\r\n' + templateScript } - scriptEditor?.inferSchema(script.content, language, true) + scriptEditor?.inferSchema(script.content, { nlang: language, resetArgs: true }) if (script.content != editor?.getCode()) { setCode(script.content) } @@ -567,7 +567,7 @@ if (!disableHistoryChange) { history.replaceState(history.state, '', `/scripts/edit/${script.path}`) } - if (stay || script.kind !== 'script' || script.no_main_func) { + if (stay || (script.no_main_func && script.kind !== 'preprocessor')) { script.parent_hash = newHash sendUserToast('Deployed') } else { diff --git a/frontend/src/lib/components/ScriptEditor.svelte b/frontend/src/lib/components/ScriptEditor.svelte index a9fcdc5cba..cd9356e34b 100644 --- a/frontend/src/lib/components/ScriptEditor.svelte +++ b/frontend/src/lib/components/ScriptEditor.svelte @@ -123,6 +123,8 @@ enablePreprocessorSnippet = false }: Props = $props() + let initialArgs = structuredClone($state.snapshot(args)) + $effect.pre(() => { if (schema == undefined) { schema = emptySchema() @@ -269,7 +271,18 @@ }) } - export async function inferSchema(code: string, nlang?: SupportedLanguage, resetArgs = false) { + export async function inferSchema( + code: string, + { + nlang, + resetArgs = false, + applyInitialArgs = false + }: { + nlang?: SupportedLanguage + resetArgs?: boolean + applyInitialArgs?: boolean + } = {} + ) { let nschema = schema ?? emptySchema() try { @@ -297,6 +310,10 @@ if (resetArgs) { args = {} } + if (applyInitialArgs) { + // we reapply initial args as the schema form might have cleared them between mount and the schema inference + args = initialArgs + } schema = nschema } catch (e) { validCode = false @@ -338,7 +355,7 @@ } onMount(() => { - inferSchema(code) + inferSchema(code, { applyInitialArgs: true }) loadPastTests() aiChatManager.saveAndClear() aiChatManager.changeMode(AIMode.SCRIPT) diff --git a/frontend/src/lib/components/ScriptEditorSkeleton.svelte b/frontend/src/lib/components/ScriptEditorSkeleton.svelte new file mode 100644 index 0000000000..031b8c9ee9 --- /dev/null +++ b/frontend/src/lib/components/ScriptEditorSkeleton.svelte @@ -0,0 +1,55 @@ +
+ +
+
+
+
+ + +
+
+
+
+
+
+
+ + +
+ +
+
+
+
+
+
+
+
+ + +
+ +
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/lib/components/TagsToListenTo.svelte b/frontend/src/lib/components/TagsToListenTo.svelte index 76c7fe15d6..e99c67223b 100644 --- a/frontend/src/lib/components/TagsToListenTo.svelte +++ b/frontend/src/lib/components/TagsToListenTo.svelte @@ -29,6 +29,9 @@ {disabled} class={disabled ? 'border-0' : ''} allowClear={!disabled} - onCreateItem={(c) => worker_tags.push(c)} + onCreateItem={(c) => { + worker_tags.push(c) + dispatch('dirty') + }} createText="Press Enter to use this tag" /> diff --git a/frontend/src/lib/components/common/table/ScriptRow.svelte b/frontend/src/lib/components/common/table/ScriptRow.svelte index 840bac9526..1fa78d86cd 100644 --- a/frontend/src/lib/components/common/table/ScriptRow.svelte +++ b/frontend/src/lib/components/common/table/ScriptRow.svelte @@ -112,7 +112,7 @@ - import { type NewScript, ScriptService, type Script } from '$lib/gen' + import { type NewScript, ScriptService, type ScriptLang } from '$lib/gen' import { page } from '$app/stores' import { defaultScripts, initialArgsStore, workspaceStore } from '$lib/stores' import ScriptBuilder from '$lib/components/ScriptBuilder.svelte' import type { Schema } from '$lib/common' - import { decodeState, emptySchema, emptyString } from '$lib/utils' + import { decodeState, emptySchema, emptyString, sendUserToast } from '$lib/utils' import { goto } from '$lib/navigation' import { replaceState } from '$app/navigation' import UnsavedConfirmationModal from '$lib/components/common/confirmationModal/UnsavedConfirmationModal.svelte' @@ -13,6 +13,13 @@ import type { Trigger } from '$lib/components/triggers/utils' import { get } from 'svelte/store' import { untrack } from 'svelte' + import ScriptEditorSkeleton from '$lib/components/ScriptEditorSkeleton.svelte' + + type Script = NewScript & { + draft_triggers?: Trigger[] + hash?: string + extra_perms?: Record + } // Default let schema: Schema = emptySchema() @@ -20,8 +27,9 @@ const templatePath = $page.url.searchParams.get('template') const hubPath = $page.url.searchParams.get('hub') const showMeta = /true|1/i.test($page.url.searchParams.get('show_meta') ?? '0') + const urlArgs = $page.url.searchParams.get('initial_args') - let initialArgs = get(initialArgsStore) ?? {} + let initialArgs = urlArgs ? decodeState(urlArgs) : (get(initialArgsStore) ?? {}) if (get(initialArgsStore)) $initialArgsStore = undefined const path = $page.url.searchParams.get('path') @@ -40,54 +48,74 @@ } } - function defaultScript() { + function defaultScript(): Script { return { hash: '', path: path ?? '', summary: '', content: '', + description: '', schema: schema, is_template: false, extra_perms: {}, - language: - $defaultScripts?.order?.filter( - (x) => $defaultScripts?.hidden == undefined || !$defaultScripts.hidden.includes(x) - )?.[0] ?? 'bun', + language: ($defaultScripts?.order?.filter( + (x) => $defaultScripts?.hidden == undefined || !$defaultScripts.hidden.includes(x) + )?.[0] ?? 'bun') as ScriptLang, kind: 'script' } } - let script: NewScript & { draft_triggers: Trigger[] } = $state( - !path && initialState != undefined ? decodeStateAndHandleError(initialState) : defaultScript() + let script: Script | undefined = $state( + templatePath || hubPath + ? undefined + : !path && initialState != undefined + ? decodeStateAndHandleError(initialState) + : defaultScript() ) async function loadTemplate(): Promise { if (templatePath) { - const template = await ScriptService.getScriptByPath({ - workspace: $workspaceStore!, - path: templatePath - }) - - // Only copy the summary if it's not empty - script.summary = !emptyString(template.summary) ? `Copy of ${template.summary}` : '' - script.description = template.description - script.content = template.content - script.schema = template.schema - script.language = template.language - scriptBuilder?.setCode(script.content) + try { + const template = await ScriptService.getScriptByPath({ + workspace: $workspaceStore!, + path: templatePath + }) + script = { + ...defaultScript(), + summary: !emptyString(template.summary) ? `Copy of ${template.summary}` : '', + description: template.description, + content: template.content, + schema: template.schema, + language: template.language, + path: template.path + '_fork' + } + } catch (err) { + script = defaultScript() + console.error('Error loading template', err) + sendUserToast('Error loading template: ' + err.message, true) + } } } async function loadHub(): Promise { if (hubPath) { - const { content, language, summary } = await ScriptService.getHubScriptByPath({ - path: hubPath - }) - script.description = `Fork of ${hubPath}` - script.content = replaceScriptPlaceholderWithItsValues(hubPath, content) - script.summary = summary ?? '' - script.language = language as Script['language'] - scriptBuilder?.setCode(script.content) + try { + const { content, language, summary } = await ScriptService.getHubScriptByPath({ + path: hubPath + }) + script = { + ...defaultScript(), + description: `Fork of ${hubPath}`, + content: replaceScriptPlaceholderWithItsValues(hubPath, content), + summary: summary ?? '', + language: language as Script['language'], + path: hubPath + '_fork' + } + } catch (err) { + script = defaultScript() + console.error('Error loading script from hub', err) + sendUserToast('Error loading script from hub: ' + err.message, true) + } } } @@ -100,22 +128,26 @@ }) - { - goto(`/scripts/get/${e.hash}?workspace=${$workspaceStore}`) - }} - onSaveInitial={(e) => { - goto(`/scripts/edit/${e.path}`) - }} - searchParams={$page.url.searchParams} - bind:script - {showMeta} - replaceStateFn={(path) => replaceState(path, $page.state)} -> - - +{#if script} + { + goto(`/scripts/get/${e.hash}?workspace=${$workspaceStore}`) + }} + onSaveInitial={(e) => { + goto(`/scripts/edit/${e.path}`) + }} + searchParams={$page.url.searchParams} + bind:script + {showMeta} + replaceStateFn={(path) => replaceState(path, $page.state)} + > + + +{:else} + +{/if}