mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-20 08:01:35 +00:00
0d0557fc9d
* feat: add wac ai context * fix: limit wac context languages * fix: pass wac auto kind in flow script drawer
285 lines
7.1 KiB
Svelte
285 lines
7.1 KiB
Svelte
<script lang="ts">
|
|
import { Button, Drawer, DrawerContent } from '$lib/components/common'
|
|
import ConfirmationModal from '$lib/components/common/confirmationModal/ConfirmationModal.svelte'
|
|
import DiffDrawer from '$lib/components/DiffDrawer.svelte'
|
|
import ScriptEditor from '$lib/components/ScriptEditor.svelte'
|
|
import { ScriptService, type Preview, type Script } from '$lib/gen'
|
|
import { inferArgs } from '$lib/infer'
|
|
import { workspaceStore } from '$lib/stores'
|
|
import { Loader2, Save, DiffIcon } from 'lucide-svelte'
|
|
import {
|
|
cleanValueProperties,
|
|
emptySchema,
|
|
orderedJsonStringify,
|
|
sendUserToast
|
|
} from '$lib/utils'
|
|
import { createEventDispatcher } from 'svelte'
|
|
import { fade } from 'svelte/transition'
|
|
import WorkerTagSelect from '$lib/components/WorkerTagSelect.svelte'
|
|
|
|
let scriptEditorDrawer: Drawer | undefined = $state()
|
|
|
|
const dispatch = createEventDispatcher()
|
|
|
|
export async function openDrawer(hash: string, cb: () => void): Promise<void> {
|
|
script = undefined
|
|
closeAnyway = false
|
|
scriptEditorDrawer?.openDrawer?.()
|
|
script = await ScriptService.getScriptByHash({
|
|
workspace: $workspaceStore!,
|
|
hash
|
|
})
|
|
savedScript = structuredClone($state.snapshot(script))
|
|
callback = cb
|
|
}
|
|
|
|
let callback: (() => void) | undefined = undefined
|
|
let script:
|
|
| {
|
|
path: string
|
|
description: string
|
|
summary: string
|
|
hash: string
|
|
language: Preview['language']
|
|
content: string
|
|
schema?: any
|
|
tag?: string
|
|
kind: 'script' | 'failure' | 'trigger' | 'command' | 'approval' | 'preprocessor' | undefined
|
|
envs?: string[]
|
|
ws_error_handler_muted?: boolean
|
|
dedicated_worker?: boolean
|
|
visible_to_runner_only?: boolean
|
|
on_behalf_of_email?: string
|
|
auto_kind?: string
|
|
has_preprocessor?: boolean
|
|
}
|
|
| undefined = $state(undefined)
|
|
|
|
let savedScript:
|
|
| {
|
|
path: string
|
|
description: string
|
|
summary: string
|
|
hash: string
|
|
language: Preview['language']
|
|
content: string
|
|
schema?: any
|
|
tag?: string
|
|
kind: 'script' | 'failure' | 'trigger' | 'command' | 'approval' | 'preprocessor' | undefined
|
|
envs?: string[]
|
|
ws_error_handler_muted?: boolean
|
|
dedicated_worker?: boolean
|
|
visible_to_runner_only?: boolean
|
|
on_behalf_of_email?: string
|
|
auto_kind?: string
|
|
has_preprocessor?: boolean
|
|
}
|
|
| undefined = $state(undefined)
|
|
|
|
async function saveScript(): Promise<void> {
|
|
if (script) {
|
|
try {
|
|
script.schema = script.schema ?? emptySchema()
|
|
try {
|
|
const result = await inferArgs(script.language, script.content, script.schema)
|
|
script.auto_kind = result?.auto_kind || undefined
|
|
script.has_preprocessor = result?.has_preprocessor || undefined
|
|
} catch (error) {
|
|
sendUserToast(`Could not parse code, are you sure it is valid?`, true)
|
|
}
|
|
|
|
await ScriptService.createScript({
|
|
workspace: $workspaceStore!,
|
|
requestBody: {
|
|
...script,
|
|
language: script.language!,
|
|
description: script.description ?? '',
|
|
parent_hash: script.hash != '' ? script.hash : undefined,
|
|
is_template: false,
|
|
tag: script.tag,
|
|
kind: script.kind as Script['kind'] | undefined,
|
|
lock: undefined
|
|
}
|
|
})
|
|
savedScript = structuredClone($state.snapshot(script))
|
|
callback?.()
|
|
} catch (error) {
|
|
sendUserToast(`Impossible to save the script: ${error.body}`, true)
|
|
}
|
|
}
|
|
}
|
|
|
|
let closeAnyway = $state(false)
|
|
let diffDrawer: DiffDrawer | undefined = $state()
|
|
let unsavedModalOpen = $state(false)
|
|
async function checkForUnsavedChanges() {
|
|
if (closeAnyway) {
|
|
scriptEditorDrawer?.closeDrawer()
|
|
return
|
|
}
|
|
if (savedScript && script) {
|
|
const saved = cleanValueProperties(savedScript)
|
|
const current = cleanValueProperties(script)
|
|
if (orderedJsonStringify(saved) !== orderedJsonStringify(current)) {
|
|
unsavedModalOpen = true
|
|
scriptEditorDrawer?.openDrawer()
|
|
} else {
|
|
scriptEditorDrawer?.closeDrawer()
|
|
}
|
|
}
|
|
}
|
|
let args = $state({})
|
|
|
|
let displayEditor = $state(true)
|
|
</script>
|
|
|
|
<ConfirmationModal
|
|
open={unsavedModalOpen}
|
|
title="Unsaved changes detected"
|
|
confirmationText="Discard changes"
|
|
on:canceled={() => {
|
|
unsavedModalOpen = false
|
|
}}
|
|
on:confirmed={() => {
|
|
console.log('confirmed')
|
|
closeAnyway = true
|
|
unsavedModalOpen = false
|
|
scriptEditorDrawer?.closeDrawer()
|
|
}}
|
|
>
|
|
<div class="flex flex-col w-full space-y-4">
|
|
<span>Are you sure you want to discard the changes you have made? </span>
|
|
<Button
|
|
wrapperClasses="self-start"
|
|
variant="default"
|
|
size="xs"
|
|
on:click={() => {
|
|
if (!savedScript || !script) {
|
|
return
|
|
}
|
|
unsavedModalOpen = false
|
|
closeAnyway = true
|
|
displayEditor = false
|
|
diffDrawer?.openDrawer()
|
|
diffDrawer?.setDiff({
|
|
title: 'Saved <> Current',
|
|
mode: 'simple',
|
|
original: savedScript,
|
|
current: script,
|
|
button: {
|
|
text: 'Close anyway',
|
|
onClick: () => {
|
|
closeAnyway = true
|
|
diffDrawer?.closeDrawer()
|
|
}
|
|
}
|
|
})
|
|
}}
|
|
>Show diff
|
|
</Button>
|
|
</div>
|
|
</ConfirmationModal>
|
|
<!-- <div id="monaco-widgets-root" class="monaco-editor" style="z-index: 1200;" /> -->
|
|
|
|
<Drawer
|
|
bind:this={scriptEditorDrawer}
|
|
size="1200px"
|
|
on:close={() => {
|
|
checkForUnsavedChanges()
|
|
}}
|
|
>
|
|
<DrawerContent
|
|
title="Script Editor"
|
|
noPadding
|
|
forceOverflowVisible
|
|
fullScreen
|
|
on:close={() => {
|
|
scriptEditorDrawer?.closeDrawer()
|
|
}}
|
|
>
|
|
{#if script && displayEditor}
|
|
{#key script.hash}
|
|
<ScriptEditor
|
|
showCaptures={false}
|
|
on:saveDraft={() => {
|
|
saveScript()
|
|
}}
|
|
noSyncFromGithub
|
|
lang={script.language}
|
|
path={script.path}
|
|
autoKind={script.auto_kind}
|
|
tag={script.tag}
|
|
fixedOverflowWidgets={false}
|
|
bind:code={script.content}
|
|
bind:schema={script.schema}
|
|
{args}
|
|
>
|
|
{#snippet editorBarRight()}
|
|
<div>
|
|
<WorkerTagSelect bind:tag={() => script?.tag, (v) => script && (script.tag = v)} />
|
|
</div>
|
|
{/snippet}
|
|
</ScriptEditor>
|
|
{/key}
|
|
{:else}
|
|
<div
|
|
out:fade={{ duration: 200 }}
|
|
class="absolute inset-0 center-center flex-col bg-surface text-primary border"
|
|
>
|
|
<Loader2 class="animate-spin" size={16} />
|
|
<span class="text-xs mt-1">Loading</span>
|
|
</div>
|
|
{/if}
|
|
{#snippet actions()}
|
|
<Button
|
|
disabled={!savedScript || !script}
|
|
variant="default"
|
|
on:click={async () => {
|
|
if (!savedScript || !script) {
|
|
return
|
|
}
|
|
closeAnyway = true
|
|
displayEditor = false
|
|
diffDrawer?.openDrawer()
|
|
diffDrawer?.setDiff({
|
|
mode: 'simple',
|
|
original: savedScript,
|
|
current: script,
|
|
title: 'Saved <> Current',
|
|
button: {
|
|
text: 'Restore to saved',
|
|
onClick: () => {
|
|
script = structuredClone($state.snapshot(savedScript))
|
|
diffDrawer?.closeDrawer()
|
|
}
|
|
}
|
|
})
|
|
}}
|
|
>
|
|
<div class="flex flex-row gap-2 items-center">
|
|
<DiffIcon size={14} />
|
|
Diff
|
|
</div>
|
|
</Button>
|
|
<Button
|
|
on:click={async () => {
|
|
await saveScript()
|
|
dispatch('save')
|
|
scriptEditorDrawer?.closeDrawer()
|
|
}}
|
|
disabled={!script}
|
|
startIcon={{ icon: Save }}
|
|
>
|
|
Save
|
|
</Button>
|
|
{/snippet}
|
|
</DrawerContent>
|
|
</Drawer>
|
|
|
|
<DiffDrawer
|
|
bind:this={diffDrawer}
|
|
on:close={() => {
|
|
displayEditor = true
|
|
}}
|
|
/>
|