Compare commits

...

3 Commits

Author SHA1 Message Date
Ruben Fiszel
57b02e6103 update 2025-06-10 11:29:47 +02:00
Ruben Fiszel
a7ed1c83c5 merge updates 2025-06-10 01:45:48 +02:00
Ruben Fiszel
360a371d0e all 2025-05-28 23:58:57 +02:00
20 changed files with 670 additions and 381 deletions

View File

@@ -7,7 +7,6 @@
"": {
"name": "windmill-components",
"version": "1.496.3",
"hasInstallScript": true,
"license": "AGPL-3.0",
"dependencies": {
"@aws-crypto/sha256-js": "^4.0.0",
@@ -151,7 +150,7 @@
"fsevents": "^2.3.3"
},
"peerDependencies": {
"svelte": "^4.0.0"
"svelte": "^5.0.0"
}
},
"node_modules/@alloc/quick-lru": {

View File

@@ -5,7 +5,6 @@
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"postinstall": "node scripts/untar_ui_builder.js && node scripts/patch_files.js",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --threshold warning",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --ignore-path .gitignore --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .",
@@ -161,7 +160,7 @@
"zod-to-json-schema": "^3.24.5"
},
"peerDependencies": {
"svelte": "^4.0.0"
"svelte": "^5.0.0"
},
"exports": {
"./package.json": "./package.json",
@@ -381,11 +380,16 @@
"./tailwindUtils": {
"types": "./package/components/apps/editor/componentsPanel/tailwindUtils.d.ts",
"default": "./package/components/apps/editor/componentsPanel/tailwindUtils.js"
},
"./components/custom_ui": {
"types": "./package/components/custom_ui.d.ts",
"default": "./package/components/custom_ui.js"
}
},
"files": [
"dist",
"package"
"package",
"scripts"
],
"license": "AGPL-3.0",
"svelte": "./dist/index.js",
@@ -519,6 +523,9 @@
],
"tailwindUtils": [
"./package/components/apps/editor/componentsPanel/tailwindUtils.d.ts"
],
"components/custom_ui": [
"./package/components/custom_ui.d.ts"
]
}
},

View File

@@ -1,3 +1,14 @@
// Check if this script is being run from the package root
const isTopLevel = !process.env.npm_config_global && process.env.INIT_CWD === process.cwd()
if (isTopLevel) {
console.log('Running postinstall: direct install')
// Your postinstall logic here
} else {
console.log('Skipping postinstall: installed as dependency')
process.exit(0)
}
import path from 'path'
import fs from 'fs'
@@ -18,17 +29,6 @@ const response = await fetch(tarUrl)
const buffer = await response.arrayBuffer()
await fs.promises.writeFile(outputTarPath, Buffer.from(buffer))
// Check if this script is being run from the package root
const isRootInstall = process.cwd() + '/scripts' === __dirname
if (isRootInstall) {
console.log('Running postinstall: direct install')
// Your postinstall logic here
} else {
console.log('Skipping postinstall: installed as dependency')
process.exit(0)
}
// Create extract directory if it doesn't exist
try {
await fs.promises.mkdir(extractTo, { recursive: true })

View File

@@ -1,8 +1,10 @@
<script context="module" lang="ts">
<script module lang="ts">
export const EDITOR_BAR_WIDTH_THRESHOLD = 1044
</script>
<script lang="ts">
import { run } from 'svelte/legacy'
import { ResourceService, VariableService, type Script } from '$lib/gen'
import { workspaceStore } from '$lib/stores'
@@ -47,110 +49,145 @@
import type { EditorBarUi } from './custom_ui'
import EditorSettings from './EditorSettings.svelte'
export let lang: SupportedLanguage | 'bunnative' | undefined
export let editor: Editor | undefined
export let websocketAlive: {
pyright: boolean
ruff: boolean
deno: boolean
go: boolean
shellcheck: boolean
interface Props {
lang: SupportedLanguage | 'bunnative' | undefined
editor: Editor | undefined
websocketAlive: {
pyright: boolean
ruff: boolean
deno: boolean
go: boolean
shellcheck: boolean
}
iconOnly?: boolean
validCode?: boolean
kind?: 'script' | 'trigger' | 'approval'
template?: 'pgsql' | 'mysql' | 'script' | 'docker' | 'powershell' | 'bunnative'
collabMode?: boolean
collabLive?: boolean
collabUsers?: { name: string }[]
scriptPath?: string | undefined
diffEditor?: DiffEditor | undefined
args: Record<string, any>
noHistory?: boolean
saveToWorkspace?: boolean
customUi?: EditorBarUi
lastDeployedCode?: string | undefined
diffMode?: boolean
showHistoryDrawer?: boolean
right?: import('svelte').Snippet
}
export let iconOnly: boolean = false
export let validCode: boolean = true
export let kind: 'script' | 'trigger' | 'approval' = 'script'
export let template: 'pgsql' | 'mysql' | 'script' | 'docker' | 'powershell' | 'bunnative' =
'script'
export let collabMode = false
export let collabLive = false
export let collabUsers: { name: string }[] = []
export let scriptPath: string | undefined = undefined
export let diffEditor: DiffEditor | undefined = undefined
export let args: Record<string, any>
export let noHistory = false
export let saveToWorkspace = false
export let customUi: EditorBarUi = {}
export let lastDeployedCode: string | undefined = undefined
export let diffMode: boolean = false
export let showHistoryDrawer: boolean = false
let contextualVariablePicker: ItemPicker
let variablePicker: ItemPicker
let resourcePicker: ItemPicker
let resourceTypePicker: ItemPicker
let variableEditor: VariableEditor
let resourceEditor: ResourceEditorDrawer
let showContextVarPicker = false
let showVarPicker = false
let showResourcePicker = false
let showResourceTypePicker = false
let {
lang,
editor,
websocketAlive,
iconOnly = false,
validCode = true,
kind = 'script',
template = 'script',
collabMode = false,
collabLive = false,
collabUsers = [],
scriptPath = undefined,
diffEditor = undefined,
args,
noHistory = false,
saveToWorkspace = false,
customUi = {},
lastDeployedCode = undefined,
diffMode = false,
showHistoryDrawer = $bindable(false),
right
}: Props = $props()
$: showContextVarPicker = [
'python3',
'bash',
'powershell',
'go',
'deno',
'bun',
'bunnative',
'nativets',
'php',
'rust',
'csharp',
'nu',
'java'
// for related places search: ADD_NEW_LANG
].includes(lang ?? '')
$: showVarPicker = [
'python3',
'bash',
'powershell',
'go',
'deno',
'bun',
'bunnative',
'nativets',
'php',
'rust',
'csharp',
'nu',
'java'
// for related places search: ADD_NEW_LANG
].includes(lang ?? '')
$: showResourcePicker = [
'python3',
'bash',
'powershell',
'go',
'deno',
'bun',
'bunnative',
'nativets',
'php',
'rust',
'csharp',
'nu',
'java'
// for related places search: ADD_NEW_LANG
].includes(lang ?? '')
$: showResourceTypePicker =
['typescript', 'javascript'].includes(scriptLangToEditorLang(lang)) ||
lang === 'python3' ||
lang === 'php'
let contextualVariablePicker: ItemPicker | undefined = $state()
let variablePicker: ItemPicker | undefined = $state()
let resourcePicker: ItemPicker | undefined = $state()
let resourceTypePicker: ItemPicker | undefined = $state()
let variableEditor: VariableEditor | undefined = $state()
let resourceEditor: ResourceEditorDrawer | undefined = $state()
let showContextVarPicker = $state(false)
let showVarPicker = $state(false)
let showResourcePicker = $state(false)
let showResourceTypePicker = $state(false)
let codeViewer: Drawer
let codeObj: { language: SupportedLanguage; content: string } | undefined = undefined
run(() => {
showContextVarPicker = [
'python3',
'bash',
'powershell',
'go',
'deno',
'bun',
'bunnative',
'nativets',
'php',
'rust',
'csharp',
'nu',
'java'
// for related places search: ADD_NEW_LANG
].includes(lang ?? '')
})
run(() => {
showVarPicker = [
'python3',
'bash',
'powershell',
'go',
'deno',
'bun',
'bunnative',
'nativets',
'php',
'rust',
'csharp',
'nu',
'java'
// for related places search: ADD_NEW_LANG
].includes(lang ?? '')
})
run(() => {
showResourcePicker = [
'python3',
'bash',
'powershell',
'go',
'deno',
'bun',
'bunnative',
'nativets',
'php',
'rust',
'csharp',
'nu',
'java'
// for related places search: ADD_NEW_LANG
].includes(lang ?? '')
})
run(() => {
showResourceTypePicker =
['typescript', 'javascript'].includes(scriptLangToEditorLang(lang)) ||
lang === 'python3' ||
lang === 'php'
})
let codeViewer: Drawer | undefined = $state()
let codeObj: { language: SupportedLanguage; content: string } | undefined = $state(undefined)
function addEditorActions() {
editor?.addAction('insert-variable', 'Windmill: Insert variable', () => {
variablePicker.openDrawer()
variablePicker?.openDrawer()
})
editor?.addAction('insert-resource', 'Windmill: Insert resource', () => {
resourcePicker.openDrawer()
resourcePicker?.openDrawer()
})
}
$: editor && addEditorActions()
run(() => {
editor && addEditorActions()
})
async function loadVariables() {
return await VariableService.listVariable({ workspace: $workspaceStore ?? '' })
@@ -162,9 +199,9 @@
})
}
let scriptPicker: Drawer
let pick_existing: 'hub' | 'workspace' = 'hub'
let filter = ''
let scriptPicker: Drawer | undefined = $state()
let pick_existing: 'hub' | 'workspace' = $state('hub')
let filter = $state('')
async function onScriptPick(e: { detail: { path: string } }) {
codeObj = undefined
@@ -462,21 +499,23 @@ string ${windmillPathToCamelCaseName(path)} = await client.GetStringAsync(uri);
itemName="Variable"
extraField="path"
loadItems={loadVariables}
buttons={{ 'Edit/View': (x) => variableEditor.editVariable(x) }}
buttons={{ 'Edit/View': (x) => variableEditor?.editVariable(x) }}
>
<div slot="submission" class="flex flex-row">
<Button
variant="border"
color="blue"
size="sm"
startIcon={{ icon: Plus }}
on:click={() => {
variableEditor.initNew()
}}
>
New variable
</Button>
</div>
{#snippet submission()}
<div class="flex flex-row">
<Button
variant="border"
color="blue"
size="sm"
startIcon={{ icon: Plus }}
on:click={() => {
variableEditor?.initNew()
}}
>
New variable
</Button>
</div>
{/snippet}
</ItemPicker>
<ItemPicker
@@ -548,24 +587,26 @@ JsonNode ${windmillPathToCamelCaseName(path)} = JsonNode.Parse(await client.GetS
tooltip="Resources represent connections to third party systems. Resources are a good way to define a connection to a frequently used third party system such as a database."
documentationLink="https://www.windmill.dev/docs/core_concepts/resources_and_types"
itemName="Resource"
buttons={{ 'Edit/View': (x) => resourceEditor.initEdit(x) }}
buttons={{ 'Edit/View': (x) => resourceEditor?.initEdit(x) }}
extraField="description"
extraField2="resource_type"
loadItems={async () =>
await ResourceService.listResource({ workspace: $workspaceStore ?? 'NO_W' })}
>
<div slot="submission" class="flex flex-row gap-x-1 mr-2">
<Button
startIcon={{ icon: Plus }}
target="_blank"
variant="border"
color="blue"
size="sm"
href="{base}/resources?connect_app=undefined"
>
Add resource
</Button>
</div>
{#snippet submission()}
<div class="flex flex-row gap-x-1 mr-2">
<Button
startIcon={{ icon: Plus }}
target="_blank"
variant="border"
color="blue"
size="sm"
href="{base}/resources?connect_app=undefined"
>
Add resource
</Button>
</div>
{/snippet}
</ItemPicker>
{#if showResourceTypePicker}
@@ -650,7 +691,7 @@ JsonNode ${windmillPathToCamelCaseName(path)} = JsonNode.Parse(await client.GetS
size="xs"
spacingSize="md"
color="light"
on:click={resourceTypePicker.openDrawer}
on:click={() => resourceTypePicker?.openDrawer}
{iconOnly}
startIcon={{ icon: Package }}
>
@@ -724,7 +765,9 @@ JsonNode ${windmillPathToCamelCaseName(path)} = JsonNode.Parse(await client.GetS
}}
/>
<Popover>
<svelte:fragment slot="text">Toggle diff mode</svelte:fragment>
{#snippet text()}
Toggle diff mode
{/snippet}
<DiffIcon class="ml-1 text-tertiary" size={14} />
</Popover>
</div>
@@ -739,14 +782,16 @@ JsonNode ${windmillPathToCamelCaseName(path)} = JsonNode.Parse(await client.GetS
on:change={() => dispatch('toggleCollabMode')}
/>
<Popover>
<svelte:fragment slot="text">Multiplayer</svelte:fragment>
{#snippet text()}
Multiplayer
{/snippet}
<Users class="ml-1 text-tertiary" size={14} />
</Popover>
{#if collabLive}
<button
title="Show invite link"
class="p-1 rounded hover:bg-gray-400 mx-1 border"
on:click={() => dispatch('collabPopup')}><Link size={14} /></button
onclick={() => dispatch('collabPopup')}><Link size={14} /></button
>
<div class="isolate flex -space-x-2 pl-2">
{#each collabUsers as user}
@@ -773,7 +818,7 @@ JsonNode ${windmillPathToCamelCaseName(path)} = JsonNode.Parse(await client.GetS
</div>
<div class="flex flex-row items-center gap-2">
<slot name="right" />
{@render right?.()}
{#if scriptPath && !noHistory}
<Button
btnClasses="!font-medium text-tertiary"

View File

@@ -43,7 +43,6 @@
import type { FlowEditorContext, FlowInput, FlowInputEditorState } from './flows/types'
import { cleanInputs } from './flows/utils'
import { Calendar, Pen, Save, DiffIcon, HistoryIcon, FileJson, type Icon } from 'lucide-svelte'
import { createEventDispatcher } from 'svelte'
import Awareness from './Awareness.svelte'
import { getAllModules } from './flows/flowExplorer'
import { type FlowCopilotContext } from './copilot/flow'
@@ -89,6 +88,24 @@
export let setSavedraftCb: ((cb: () => void) => void) | undefined = undefined
export let draftTriggersFromUrl: Trigger[] | undefined = undefined
export let selectedTriggerIndexFromUrl: number | undefined = undefined
export let onevent: {
deploy?: (path: string) => void
deployError?: (error: Error) => void
saveInitial?: (path: string) => void
saveDraft?: ({
path,
savedAtNewPath,
newFlow
}: {
path: string
savedAtNewPath: boolean
newFlow: boolean
}) => void
saveDraftError?: (error: Error) => void
saveDraftOnlyAtNewPath?: ({ path, selectedId }: { path: string; selectedId: string }) => void
seeDetails?: (path: string) => void
historyRestore?: () => void
} = {}
let initialPathStore = writable(initialPath)
$: initialPathStore.set(initialPath)
@@ -152,8 +169,6 @@
}
}
const dispatch = createEventDispatcher()
const primaryScheduleStore = writable<ScheduleTrigger | undefined | false>(savedPrimarySchedule) // kept for legacy reasons
const triggersCount = writable<TriggersCount | undefined>(undefined)
const simplifiedPoll = writable(false)
@@ -275,18 +290,19 @@
let savedAtNewPath = false
if (newFlow) {
dispatch('saveInitial', $pathStore)
onevent.saveInitial?.($pathStore)
} else if (savedFlow?.draft_only && $pathStore !== initialPath) {
savedAtNewPath = true
initialPath = $pathStore
// this is so we can use the flow builder outside of sveltekit
dispatch('saveDraftOnlyAtNewPath', { path: $pathStore, selectedId: getSelectedId() })
onevent.saveDraftOnlyAtNewPath?.({ path: $pathStore, selectedId: getSelectedId() })
}
dispatch('saveDraft', { path: $pathStore, savedAtNewPath, newFlow })
onevent.saveDraft?.({ path: $pathStore, savedAtNewPath, newFlow })
sendUserToast('Saved as draft')
} catch (error) {
sendUserToast(`Error while saving the flow as a draft: ${error.body || error.message}`, true)
dispatch('saveDraftError', error)
onevent.saveDraftError?.(error)
}
loadingDraft = false
}
@@ -450,9 +466,9 @@
} as Flow
setDraftTriggers([])
loadingSave = false
dispatch('deploy', $pathStore)
onevent.deploy?.($pathStore)
} catch (err) {
dispatch('deployError', err)
onevent.deployError?.(err)
sendUserToast(`The flow could not be saved: ${err.body}`, true)
loadingSave = false
}
@@ -651,7 +667,7 @@
if (savedFlow?.draft_only === false || savedFlow?.draft_only === undefined) {
dropdownItems.push({
label: 'Exit & see details',
onClick: () => dispatch('details', $pathStore)
onClick: () => onevent.seeDetails?.($pathStore)
})
}
@@ -777,7 +793,11 @@
{#key renderCount}
{#if !$userStore?.operator}
{#if $pathStore}
<FlowHistory bind:this={flowHistory} path={$pathStore} on:historyRestore />
<FlowHistory
bind:this={flowHistory}
path={$pathStore}
onHistoryRestore={() => onevent.historyRestore?.()}
/>
{/if}
<FlowYamlEditor bind:drawer={yamlEditorDrawer} />
<FlowImportExportMenu bind:drawer={jsonViewerDrawer} />

View File

@@ -7,23 +7,41 @@
import SearchItems from './SearchItems.svelte'
type Item = Record<string, any>
export let pickCallback: (path: string, f: string) => void
export let loadItems: () => Promise<Item[] | undefined>
export let extraField: string = 'path'
export let extraField2: string | undefined = undefined
export let itemName: string
export let closeOnClick = true
/** Displayed if the load function returns no items. */
export let noItemMessage = 'There are no items in the list'
/** Displayed if the search returns no items. */
export let buttons: Record<string, (x: string) => void> = {}
export let tooltip: string = ''
export let documentationLink: string | undefined = undefined
let loading = false
let items: Item[] | undefined = []
let filteredItems: Item[] | undefined = []
let filter = ''
interface Props {
pickCallback: (path: string, f: string) => void
loadItems: () => Promise<Item[] | undefined>
extraField?: string
extraField2?: string | undefined
itemName: string
closeOnClick?: boolean
/** Displayed if the load function returns no items. */
noItemMessage?: string
/** Displayed if the search returns no items. */
buttons?: Record<string, (x: string) => void>
tooltip?: string
documentationLink?: string | undefined
submission?: import('svelte').Snippet
}
let {
pickCallback,
loadItems,
extraField = 'path',
extraField2 = undefined,
itemName,
closeOnClick = true,
noItemMessage = 'There are no items in the list',
buttons = {},
tooltip = '',
documentationLink = undefined,
submission
}: Props = $props()
let loading = $state(false)
let items: Item[] | undefined = $state([])
let filteredItems: Item[] | undefined = $state([])
let filter = $state('')
export function openDrawer() {
loading = true
@@ -34,12 +52,12 @@
.finally(() => {
loading = false
})
drawer.openDrawer?.()
drawer?.openDrawer?.()
}
let drawer: Drawer
let drawer: Drawer | undefined = $state()
let refreshing = false
let refreshing = $state(false)
</script>
<SearchItems
@@ -65,7 +83,7 @@
>
<div class="w-full h-full flex flex-col">
<div class="flex flex-row gap-2 pb-4">
<!-- svelte-ignore a11y-autofocus -->
<!-- svelte-ignore a11y_autofocus -->
<input
type="text"
placeholder="Search {itemName}s"
@@ -110,9 +128,9 @@
<button
class="py-2 px-1 gap-1 flex grow border-gray-300 border-opacity-0
text-primary"
on:click={() => {
onclick={() => {
if (closeOnClick) {
drawer.closeDrawer()
drawer?.closeDrawer()
}
pickCallback(obj['path'], obj[extraField])
}}
@@ -174,8 +192,8 @@
<NoItemFound />
{/if}
</div>
<svelte:fragment slot="actions">
<slot name="submission" />
</svelte:fragment>
{#snippet actions()}
{@render submission?.()}
{/snippet}
</DrawerContent>
</Drawer>

View File

@@ -68,7 +68,7 @@
import { writable } from 'svelte/store'
import { defaultScriptLanguages, processLangs } from '$lib/scripts'
import DefaultScripts from './DefaultScripts.svelte'
import { createEventDispatcher, onMount, setContext } from 'svelte'
import { onMount, setContext } from 'svelte'
import Summary from './Summary.svelte'
import type { ScriptBuilderWhitelabelCustomUi } from './custom_ui'
import DeployOverrideConfirmationModal from '$lib/components/common/confirmationModal/DeployOverrideConfirmationModal.svelte'
@@ -112,6 +112,22 @@
export let savedPrimarySchedule: ScheduleTrigger | undefined = undefined
export let functionExports: ((exports: ScriptBuilderFunctionExports) => void) | undefined =
undefined
export let onevent: {
deploy?: (newHash: string) => void
deployError?: (error: Error) => void
saveInitial?: (path: string) => void
saveDraft?: ({
path,
savedAtNewPath,
script
}: {
path: string
savedAtNewPath: boolean
script: NewScript
}) => void
saveDraftError?: (error: Error) => void
seeDetails?: (path: string) => void
} = {}
export function getInitialAndModifiedValues(): SavedAndModifiedValue {
return {
@@ -183,8 +199,6 @@
loadTriggers()
}
const dispatch = createEventDispatcher()
$: initialPath != '' && loadTriggers()
onMount(() => {
@@ -566,10 +580,10 @@
script.parent_hash = newHash
sendUserToast('Deployed')
} else {
dispatch('deploy', newHash)
onevent.deploy?.(newHash)
}
} catch (error) {
dispatch('deployError', error)
onevent.deployError?.(error)
sendUserToast(`Error while saving the script: ${error.body || error.message}`, true)
}
loadingSave = false
@@ -701,9 +715,9 @@
if (initialPath == '' || (savedScript?.draft_only && script.path !== initialPath)) {
savedAtNewPath = true
initialPath = script.path
dispatch('saveInitial', script.path)
onevent.saveInitial?.(script.path)
}
dispatch('saveDraft', { path: script.path, savedAtNewPath, script })
onevent.saveDraft?.({ path: script.path, savedAtNewPath, script })
sendUserToast('Saved as draft')
} catch (error) {
@@ -711,7 +725,7 @@
`Error while saving the script as a draft: ${error.body || error.message}`,
true
)
dispatch('saveDraftError', error)
onevent.saveDraftError?.(error)
}
loadingDraft = false
}
@@ -769,7 +783,7 @@
{
label: 'Exit & See details',
onClick: () => {
dispatch('seeDetails', initialPath)
onevent.seeDetails?.(initialPath)
}
}
]
@@ -1686,12 +1700,8 @@
{customUi}
collabMode
edit={initialPath != ''}
on:format={() => {
saveDraft()
}}
on:saveDraft={() => {
saveDraft()
}}
onFormat={() => saveDraft()}
onSaveDraft={() => saveDraft()}
on:openTriggers={openTriggers}
on:applyArgs={applyArgs}
on:addPreprocessor={addPreprocessor}

View File

@@ -13,7 +13,7 @@
import EditorBar, { EDITOR_BAR_WIDTH_THRESHOLD } from './EditorBar.svelte'
import TestJobLoader from './TestJobLoader.svelte'
import JobProgressBar from '$lib/components/jobs/JobProgressBar.svelte'
import { createEventDispatcher, onDestroy, onMount } from 'svelte'
import { onDestroy, onMount } from 'svelte'
import { Button } from './common'
import SplitPanesWrapper from './splitPanes/SplitPanesWrapper.svelte'
import WindmillIcon from './icons/WindmillIcon.svelte'
@@ -42,78 +42,114 @@
import HideButton from './apps/editor/settingsPanel/HideButton.svelte'
import { base } from '$lib/base'
import { SUPPORTED_CHAT_SCRIPT_LANGUAGES } from './copilot/chat/script/core'
import { createDispatcherIfMounted } from '$lib/createDispatcherIfMounted'
import { getStringError } from './copilot/chat/utils'
import type { ScriptOptions } from './copilot/chat/ContextManager.svelte'
import { aiChatManager, AIMode } from './copilot/chat/AIChatManager.svelte'
import TriggerableByAI from './TriggerableByAI.svelte'
// Exported
export let schema: Schema | any = emptySchema()
export let code: string
export let path: string | undefined
export let lang: Preview['language']
export let kind: string | undefined = undefined
export let template: 'pgsql' | 'mysql' | 'script' | 'docker' | 'powershell' | 'bunnative' =
'script'
export let tag: string | undefined
export let initialArgs: Record<string, any> = {}
export let fixedOverflowWidgets = true
export let noSyncFromGithub = false
export let editor: Editor | undefined = undefined
export let diffEditor: DiffEditor | undefined = undefined
export let collabMode = false
export let edit = true
export let noHistory = false
export let saveToWorkspace = false
export let watchChanges = false
export let customUi: ScriptEditorWhitelabelCustomUi | undefined = undefined
export let args: Record<string, any> = initialArgs
export let selectedTab: 'main' | 'preprocessor' = 'main'
export let hasPreprocessor = false
export let captureTable: CaptureTable | undefined = undefined
export let showCaptures: boolean = true
export let stablePathForCaptures: string = ''
export let lastSavedCode: string | undefined = undefined
export let lastDeployedCode: string | undefined = undefined
interface Props {
// Exported
schema?: Schema | any
code: string
path: string | undefined
lang: Preview['language']
kind?: string | undefined
template?: 'pgsql' | 'mysql' | 'script' | 'docker' | 'powershell' | 'bunnative'
tag: string | undefined
initialArgs?: Record<string, any>
fixedOverflowWidgets?: boolean
noSyncFromGithub?: boolean
editor?: Editor | undefined
diffEditor?: DiffEditor | undefined
collabMode?: boolean
edit?: boolean
noHistory?: boolean
saveToWorkspace?: boolean
watchChanges?: boolean
customUi?: ScriptEditorWhitelabelCustomUi | undefined
args?: Record<string, any>
selectedTab?: 'main' | 'preprocessor'
hasPreprocessor?: boolean
captureTable?: CaptureTable | undefined
showCaptures?: boolean
stablePathForCaptures?: string
lastSavedCode?: string | undefined
lastDeployedCode?: string | undefined
editor_bar_right?: import('svelte').Snippet
onChange?: (code: string, schema: Schema) => void
onFormat?: () => void
onSaveDraft?: () => void
}
let showHistoryDrawer = false
let {
schema = $bindable(emptySchema()),
code = $bindable(),
path,
lang,
kind = undefined,
template = 'script',
tag,
initialArgs = {},
fixedOverflowWidgets = true,
noSyncFromGithub = false,
editor = $bindable(undefined),
diffEditor = $bindable(undefined),
collabMode = false,
edit = true,
noHistory = false,
saveToWorkspace = false,
watchChanges = false,
customUi = undefined,
args = $bindable(initialArgs),
selectedTab = $bindable('main'),
hasPreprocessor = $bindable(false),
captureTable = $bindable(undefined),
showCaptures = true,
stablePathForCaptures = '',
lastSavedCode = undefined,
lastDeployedCode = undefined,
editor_bar_right,
onChange,
onFormat,
onSaveDraft
}: Props = $props()
// export let onC
let jobProgressReset: () => void
let diffMode = false
let showHistoryDrawer = $state(false)
let websocketAlive = {
let jobProgressReset: (() => void) | undefined = $state()
let diffMode = $state(false)
let websocketAlive = $state({
pyright: false,
deno: false,
go: false,
ruff: false,
shellcheck: false
}
})
const dispatch = createEventDispatcher()
const dispatchIfMounted = createDispatcherIfMounted(dispatch)
$effect(() => {
watchChanges && (code != undefined || schema != undefined) && onChange?.(code, schema)
})
$: watchChanges &&
(code != undefined || schema != undefined) &&
dispatchIfMounted('change', { code, schema })
let width = $state(1200)
let width = 1200
let testJobLoader: TestJobLoader | undefined = $state()
let testJobLoader: TestJobLoader
let isValid: boolean = true
let scriptProgress = undefined
let isValid: boolean = $state(true)
let scriptProgress = $state(undefined)
// Test
let testIsLoading = false
let testJob: Job | undefined
let pastPreviews: CompletedJob[] = []
let validCode = true
let testIsLoading = $state(false)
let testJob: Job | undefined = $state()
let pastPreviews: CompletedJob[] = $state([])
let validCode = $state(true)
let logPanel: LogPanel | undefined = $state()
let wsProvider: WebsocketProvider | undefined = undefined
let yContent: Y.Text | undefined = undefined
let peers: { name: string }[] = []
let showCollabPopup = false
let wsProvider: WebsocketProvider | undefined = $state(undefined)
let yContent: Y.Text | undefined = $state(undefined)
let peers: { name: string }[] = $state([])
let showCollabPopup = $state(false)
const url = new URL(window.location.toString())
let initialCollab = /true|1/i.test(url.searchParams.get('collab') ?? '0')
@@ -292,11 +328,15 @@
return `${url}?collab=1` + (edit ? '' : `&path=${path}`)
}
$: showTabs = hasPreprocessor
$: !hasPreprocessor && (selectedTab = 'main')
$: selectedTab && inferSchema(code)
let showTabs = $derived(hasPreprocessor)
$effect(() => {
!hasPreprocessor && (selectedTab = 'main')
})
$effect(() => {
selectedTab && inferSchema(code)
})
let argsRender = 0
let argsRender = $state(0)
export async function updateArgs(newArgs: Record<string, any>) {
if (Object.keys(newArgs).length > 0) {
args = { ...newArgs }
@@ -304,17 +344,21 @@
}
}
let setFocusToLogs = () => {}
function setFocusToLogs() {
logPanel?.setFocusToLogs()
}
setContext('disableTooltips', customUi?.disableTooltips === true)
let codePanelSize = 70
let testPanelSize = 30
let codePanelSize = $state(70)
let testPanelSize = $state(30)
let storedTestPanelSize = testPanelSize
$: !SUPPORTED_CHAT_SCRIPT_LANGUAGES.includes(lang ?? '') &&
!aiChatManager.open &&
aiChatManager.toggleOpen()
$effect(() => {
!SUPPORTED_CHAT_SCRIPT_LANGUAGES.includes(lang ?? '') &&
!aiChatManager.open &&
aiChatManager.toggleOpen()
})
function toggleTestPanel() {
if (testPanelSize > 0) {
@@ -348,9 +392,9 @@
editor?.show()
}
$: error = getError(testJob)
let error = $derived(getError(testJob))
$: {
$effect(() => {
const options: ScriptOptions = {
code,
lang: lang as ScriptLang,
@@ -367,7 +411,7 @@
editor?.reviewAndApplyCode(code)
}
aiChatManager.scriptEditorShowDiffMode = showDiffMode
}
})
</script>
<TestJobLoader
@@ -378,7 +422,7 @@
bind:job={testJob}
/>
<svelte:window on:keydown={onKeyDown} />
<svelte:window onkeydown={onKeyDown} />
<TriggerableByAI id="script-editor" description="Component to edit a script" />
@@ -431,7 +475,9 @@
{diffMode}
bind:showHistoryDrawer
>
<slot name="editor-bar-right" slot="right" />
{#snippet right()}
{@render editor_bar_right?.()}
{/snippet}
</EditorBar>
{#if !noSyncFromGithub && customUi?.editorBar?.useVsCode != false}
<div class="py-1">
@@ -490,7 +536,7 @@
aiChatManager.toggleOpen()
}}
>
<svelte:fragment slot="popoverOverride">
{#snippet popoverOverride()}
<div class="text-sm">
Enable Windmill AI in the <a
href="{base}/workspace_settings?tab=ai"
@@ -500,7 +546,7 @@
workspace settings <ExternalLink size={16} />
</a>
</div>
</svelte:fragment>
{/snippet}
</HideButton>
{/if}
{/if}
@@ -518,7 +564,7 @@
on:change={(e) => {
inferSchema(e.detail)
}}
on:saveDraft
on:saveDraft={() => onSaveDraft?.()}
on:toggleAiPanel={() => aiChatManager.toggleOpen()}
on:addSelectedLinesToAiChat={(e) => {
const { lines, startLine, endLine } = e.detail
@@ -536,7 +582,7 @@
} catch (e) {
console.error('Could not save last_save to local storage', e)
}
dispatch('format')
onFormat?.()
}}
class="flex flex-1 h-full !overflow-visible"
scriptLang={lang}
@@ -670,7 +716,7 @@
</Pane>
<Pane size={67} class="relative">
<LogPanel
bind:setFocusToLogs
bind:this={logPanel}
{lang}
previewJob={testJob}
{pastPreviews}
@@ -690,7 +736,7 @@
compact={true}
/>
{/if}
<svelte:fragment slot="capturesTab">
{#snippet capturesTab()}
<div class="h-full p-2">
<CaptureTable
bind:this={captureTable}
@@ -704,7 +750,7 @@
on:addPreprocessor
/>
</div>
</svelte:fragment>
{/snippet}
</LogPanel>
</Pane>
</Splitpanes>

View File

@@ -79,6 +79,10 @@
path: string,
opt?: Record<string, any>
) => window.history.pushState(null, '', path)
export let onevent: {
savedNewAppPath?: (path: string) => void
restore?: (app: App) => void
} = {}
migrateApp(app)
@@ -805,7 +809,7 @@
<AppEditorHeader
{newPath}
{newApp}
on:restore
on:restore={(e) => onevent.restore?.(e.detail)}
{policy}
{fromHub}
bind:this={appEditorHeader}
@@ -815,7 +819,7 @@
leftPanelHidden={leftPanelSize === 0}
rightPanelHidden={rightPanelSize === 0}
bottomPanelHidden={runnablePanelSize === 0}
on:savedNewAppPath
on:savedNewAppPath={(e) => onevent.savedNewAppPath?.(e.detail)}
on:showLeftPanel={() => showLeftPanel()}
on:showRightPanel={() => showRightPanel()}
on:hideLeftPanel={() => hideLeftPanel()}

View File

@@ -13,17 +13,33 @@
} from 'lucide-svelte'
import { twMerge } from 'tailwind-merge'
export let btnClasses: string | undefined = undefined
export let size: ButtonType.Size = 'xs'
interface Props {
btnClasses?: string | undefined
size?: ButtonType.Size
variant?: ButtonType.Variant
color?: ButtonType.Color
direction?: 'left' | 'right' | 'bottom'
hidden?: boolean
shortcut?: string | undefined
panelName?: string | undefined
customHiddenIcon?: ButtonType.Icon | undefined
usePopoverOverride?: boolean
popoverOverride?: import('svelte').Snippet
}
export let variant: ButtonType.Variant = 'contained'
export let color: ButtonType.Color = 'light'
export let direction: 'left' | 'right' | 'bottom' = 'right'
export let hidden: boolean = false
export let shortcut: string | undefined = undefined
export let panelName: string | undefined = undefined
export let customHiddenIcon: ButtonType.Icon | undefined = undefined
export let usePopoverOverride: boolean = false
let {
btnClasses = undefined,
size = 'xs',
variant = 'contained',
color = 'light',
direction = 'right',
hidden = false,
shortcut = undefined,
panelName = undefined,
customHiddenIcon = undefined,
usePopoverOverride = false,
popoverOverride
}: Props = $props()
const OpenIconMap = {
left: PanelLeftOpen,
@@ -45,9 +61,9 @@
</script>
<Popover>
<svelte:fragment slot="text">
{#if usePopoverOverride && $$slots.popoverOverride}
<slot name="popoverOverride" />
{#snippet text()}
{#if usePopoverOverride && popoverOverride}
{@render popoverOverride?.()}
{:else}
<div class="flex flex-row gap-1">
{hidden ? 'Show' : 'Hide '} the {panelName ?? direction} panel.
@@ -57,7 +73,7 @@
</div>
</div>
{/if}
</svelte:fragment>
{/snippet}
<Button
iconOnly
startIcon={hidden

View File

@@ -5,17 +5,35 @@
import TriggerableByAI from '$lib/components/TriggerableByAI.svelte'
import { createEventDispatcher } from 'svelte'
export let aiId: string | undefined = undefined
export let aiDescription: string | undefined = undefined
export let title: string | undefined = undefined
export let overflow_y = true
export let noPadding = false
export let forceOverflowVisible = false
export let tooltip: string = ''
export let documentationLink: string | undefined = undefined
export let CloseIcon: any | undefined = undefined
interface Props {
aiId?: string | undefined
aiDescription?: string | undefined
title?: string | undefined
overflow_y?: boolean
noPadding?: boolean
forceOverflowVisible?: boolean
tooltip?: string
documentationLink?: string | undefined
CloseIcon?: any | undefined
fullScreen?: boolean
actions?: import('svelte').Snippet
children?: import('svelte').Snippet
}
export let fullScreen: boolean = true
let {
aiId = undefined,
aiDescription = undefined,
title = undefined,
overflow_y = true,
noPadding = false,
forceOverflowVisible = false,
tooltip = '',
documentationLink = undefined,
CloseIcon = undefined,
fullScreen = true,
actions,
children
}: Props = $props()
const dispatch = createEventDispatcher()
</script>
@@ -39,9 +57,9 @@
{/if}</span
>
</div>
{#if $$slots.actions}
{#if actions}
<div class="flex gap-2 items-center justify-end">
<slot name="actions" />
{@render actions?.()}
</div>
{/if}
</div>
@@ -54,6 +72,6 @@
)}
class:overflow-y-auto={overflow_y}
>
<slot />
{@render children?.()}
</div>
</div>

View File

@@ -0,0 +1,76 @@
<script lang="ts">
import { setContext } from 'svelte'
import { writable } from 'svelte/store'
import { twMerge } from 'tailwind-merge'
import type { TabsContext } from './tabs.svelte'
interface Props {
selected: string
hideTabs?: boolean
class?: string
wrapperClass?: string
style?: string
hashNavigation?: boolean
values?: string[] | undefined
children?: import('svelte').Snippet<[any]>
content?: import('svelte').Snippet
onSelectedChange?: (value: string) => void
}
let {
selected = $bindable(),
hideTabs = false,
class: c = '',
wrapperClass = '',
style = '',
hashNavigation = false,
values = undefined,
children,
content,
onSelectedChange
}: Props = $props()
const selectedStore = writable(selected)
setContext<TabsContext>('Tabs', {
selected: selectedStore,
update: (value: string) => {
selectedStore.set(value)
selected = value
},
hashNavigation
})
function updateSelected() {
selectedStore.set(selected)
}
function hashChange() {
if (hashNavigation) {
const hash = window.location.hash
if (hash && hashValues?.includes(hash)) {
const id = hash.replace('#', '')
selectedStore.set(id)
selected = id
}
}
}
$effect(() => {
selected && updateSelected()
})
$effect(() => {
$selectedStore && onSelectedChange?.($selectedStore)
})
let hashValues = $derived(values ? values.map((x) => '#' + x) : undefined)
</script>
<svelte:window onhashchange={hashChange} />
{#if !hideTabs}
<div class="overflow-x-auto {wrapperClass}">
<div class={twMerge('border-b flex flex-row whitespace-nowrap scrollbar-hidden', c)} {style}>
{@render children?.({ selected })}
</div>
</div>
{/if}
{@render content?.()}

View File

@@ -0,0 +1,7 @@
import type { Writable } from 'svelte/store'
export type TabsContext = {
selected: Writable<string>
update: (value: string) => void
hashNavigation: boolean
}

View File

@@ -1,18 +1,20 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import Drawer from '../common/drawer/Drawer.svelte'
import DrawerContent from '../common/drawer/DrawerContent.svelte'
import FlowHistoryInner from './FlowHistoryInner.svelte'
export let path: string
let drawer: Drawer
export function open() {
drawer.openDrawer()
interface Props {
path: string
onHistoryRestore: () => void
}
const dispatch = createEventDispatcher()
let { path, onHistoryRestore }: Props = $props()
let drawer: Drawer | undefined = undefined
export function open() {
drawer?.openDrawer()
}
</script>
<Drawer bind:this={drawer} size="1200px">
@@ -26,8 +28,8 @@
<FlowHistoryInner
allowFork
on:historyRestore={() => {
drawer.closeDrawer()
dispatch('historyRestore')
drawer?.closeDrawer()
onHistoryRestore()
}}
{path}
/>

View File

@@ -198,9 +198,7 @@
{#key script.hash}
<ScriptEditor
showCaptures={false}
on:saveDraft={() => {
saveScript()
}}
onSaveDraft={() => saveScript()}
noSyncFromGithub
lang={script.language}
path={script.path}
@@ -209,7 +207,7 @@
bind:code={script.content}
bind:schema={script.schema}
>
<div slot="editor-bar-right">
<div slot="editor_bar_right">
<WorkerTagSelect bind:tag={script.tag} />
</div>
</ScriptEditor>

View File

@@ -1,4 +1,6 @@
<script lang="ts">
import { preventDefault } from 'svelte/legacy'
import {
type CompletedJob,
type Job,
@@ -10,11 +12,9 @@
import { workspaceStore } from '$lib/stores'
import { base } from '$lib/base'
import { displayDate } from '$lib/utils'
import Tabs from '../common/tabs/Tabs.svelte'
import Tab from '../common/tabs/Tab.svelte'
import DisplayResult from '../DisplayResult.svelte'
import Drawer from '../common/drawer/Drawer.svelte'
import DrawerContent from '../common/drawer/DrawerContent.svelte'
import HighlightCode from '../HighlightCode.svelte'
import LogViewer from '../LogViewer.svelte'
import { Pane, Splitpanes } from 'svelte-splitpanes'
@@ -30,33 +30,54 @@
import Tooltip from '$lib/components/Tooltip.svelte'
import type { PreviewPanelUi } from '../custom_ui'
import { getStringError } from '../copilot/chat/utils'
import { DrawerContent } from '../common'
import TabsV2 from '../common/tabs/TabsV2.svelte'
export let lang: Preview['language'] | undefined
export let previewIsLoading = false
export let previewJob: Job | undefined
export let pastPreviews: CompletedJob[] = []
export let editor: Editor | undefined = undefined
export let diffEditor: DiffEditor | undefined = undefined
export let args: Record<string, any> | undefined = undefined
export let workspace: string | undefined = undefined
export let showCaptures: boolean = false
export let customUi: PreviewPanelUi | undefined = undefined
interface Props {
lang: Preview['language'] | undefined
previewIsLoading?: boolean
previewJob: Job | undefined
pastPreviews?: CompletedJob[]
editor?: Editor | undefined
diffEditor?: DiffEditor | undefined
args?: Record<string, any> | undefined
workspace?: string | undefined
showCaptures?: boolean
customUi?: PreviewPanelUi | undefined
children?: import('svelte').Snippet
capturesTab?: import('svelte').Snippet
}
type DrawerContent = {
let {
lang,
previewIsLoading = false,
previewJob,
pastPreviews = [],
editor = undefined,
diffEditor = undefined,
args = undefined,
workspace = undefined,
showCaptures = false,
customUi = undefined,
children,
capturesTab
}: Props = $props()
type DContent = {
mode: 'json' | Preview['language'] | 'plain'
title: string
content: any
}
let selectedTab = 'logs'
let drawerOpen: boolean = false
let drawerContent: DrawerContent | undefined = undefined
let selectedTab = $state('logs')
let drawerOpen: boolean = $state(false)
let drawerContent: DContent | undefined = $state(undefined)
export function setFocusToLogs() {
selectedTab = 'logs'
}
function openDrawer(newContent: DrawerContent) {
function openDrawer(newContent: DContent) {
drawerContent = newContent
drawerOpen = true
}
@@ -69,7 +90,7 @@
return x as Record<string, WorkflowStatus>
}
let forceJson = false
let forceJson = $state(false)
</script>
<Drawer bind:open={drawerOpen} size="800px">
@@ -94,7 +115,7 @@
</Drawer>
<div class="h-full flex flex-col">
<Tabs bind:selected={selectedTab} class="pt-1" wrapperClass="flex-none">
<TabsV2 bind:selected={selectedTab} class="pt-1" wrapperClass="flex-none">
<Tab value="logs" size="xs">Logs & Result</Tab>
{#if customUi?.disableHistory !== true}
<Tab value="history" size="xs">History</Tab>
@@ -103,7 +124,7 @@
<Tab value="captures" size="xs">Trigger captures</Tab>
{/if}
<svelte:fragment slot="content">
{#snippet content()}
<div class="grow min-h-0">
{#if selectedTab === 'logs'}
<SplitPanesWrapper>
@@ -128,7 +149,7 @@
/>
</Pane>
<Pane>
<slot />
{@render children?.()}
{#if previewJob != undefined && 'result' in previewJob}
<div class="relative w-full h-full p-2">
<div class="relative">
@@ -140,6 +161,7 @@
customUi={customUi?.displayResult}
language={lang}
>
<!-- @migration-task: migrate this slot by hand, `copilot-fix` is an invalid identifier -->
<svelte:fragment slot="copilot-fix">
{#if lang && editor && diffEditor && args && previewJob && !previewJob.success && getStringError(previewJob.result)}
<ScriptFix {lang} />
@@ -203,7 +225,7 @@
<Cell>
<button
class="text-xs"
on:click|preventDefault={() => {
onclick={preventDefault(() => {
openDrawer({ mode: 'json', content: undefined, title: 'Result' })
JobService.getCompletedJobResult({
workspace: workspace ?? $workspaceStore ?? 'NO_W',
@@ -211,7 +233,7 @@
}).then((res) => {
drawerContent && (drawerContent.content = res)
})
}}
})}
>
See Result
</button>
@@ -219,7 +241,7 @@
<Cell>
<button
class="text-xs"
on:click|preventDefault={async () => {
onclick={preventDefault(async () => {
const code = (
await JobService.getCompletedJob({
workspace: workspace ?? $workspaceStore ?? 'NO_W',
@@ -231,7 +253,7 @@
content: String(code),
title: `Code ${lang}`
})
}}
})}
>
View code
</button>
@@ -239,7 +261,7 @@
<Cell last>
<button
class="text-xs"
on:click|preventDefault={async () => {
onclick={preventDefault(async () => {
const logs = await (
await fetch(
OpenAPI.BASE +
@@ -252,7 +274,7 @@
content: String(logs),
title: `Logs for ${id}`
})
}}
})}
>
View logs
</button>
@@ -264,9 +286,9 @@
</div>
{/if}
{#if selectedTab === 'captures'}
<slot name="capturesTab" />
{@render capturesTab?.()}
{/if}
</div>
</svelte:fragment>
</Tabs>
{/snippet}
</TabsV2>
</div>

View File

@@ -165,14 +165,16 @@
<!-- <div id="monaco-widgets-root" class="monaco-editor" style="z-index: 1200;" /> -->
<FlowBuilder
on:saveInitial={(e) => {
goto(`/flows/edit/${e.detail}?selected=${getSelectedId?.()}`)
}}
on:deploy={(e) => {
goto(`/flows/get/${e.detail}?workspace=${$workspaceStore}`)
}}
on:details={(e) => {
goto(`/flows/get/${e.detail}?workspace=${$workspaceStore}`)
onevent={{
saveInitial: (path) => {
goto(`/flows/edit/${path}?selected=${getSelectedId?.()}`)
},
deploy: (path) => {
goto(`/flows/get/${path}?workspace=${$workspaceStore}`)
},
seeDetails: (path) => {
goto(`/flows/get/${path}?workspace=${$workspaceStore}`)
}
}}
{initialPath}
{pathStoreInit}

View File

@@ -244,18 +244,19 @@
<DiffDrawer bind:this={diffDrawer} {restoreDeployed} {restoreDraft} />
<FlowBuilder
on:deploy={(e) => {
goto(`/flows/get/${e.detail}?workspace=${$workspaceStore}`)
}}
on:details={(e) => {
goto(`/flows/get/${e.detail}?workspace=${$workspaceStore}`)
}}
on:saveDraftOnlyAtNewPath={(e) => {
const { path, selectedId } = e.detail
goto(`/flows/edit/${path}?selected=${selectedId}`)
}}
on:historyRestore={() => {
loadFlow()
onevent={{
deploy: (path) => {
goto(`/flows/get/${path}?workspace=${$workspaceStore}`)
},
seeDetails: (path) => {
goto(`/flows/get/${path}?workspace=${$workspaceStore}`)
},
saveDraftOnlyAtNewPath: ({ path, selectedId }) => {
goto(`/flows/edit/${path}?selected=${selectedId}`)
},
historyRestore: () => {
loadFlow()
}
}}
{flowStore}
{flowStateStore}

View File

@@ -108,13 +108,13 @@
{initialArgs}
bind:this={scriptBuilder}
lockedLanguage={templatePath != null || hubPath != null}
on:deploy={(e) => {
let newHash = e.detail
goto(`/scripts/get/${newHash}?workspace=${$workspaceStore}`)
}}
on:saveInitial={(e) => {
let path = e.detail
goto(`/scripts/edit/${path}`)
onevent={{
deploy: (newHash) => {
goto(`/scripts/get/${newHash}?workspace=${$workspaceStore}`)
},
saveInitial: (path) => {
goto(`/scripts/edit/${path}`)
}
}}
bind:getInitialAndModifiedValues
searchParams={$page.url.searchParams}

View File

@@ -27,7 +27,6 @@
let scriptLoadedFromUrl = initialState != undefined ? decodeState(initialState) : undefined
let script: (NewScript & { draft_triggers?: Trigger[] }) | undefined = undefined
let initialPath: string = ''
@@ -218,19 +217,18 @@
{diffDrawer}
{savedPrimarySchedule}
searchParams={$page.url.searchParams}
on:deploy={(e) => {
let newHash = e.detail
goto(`/scripts/get/${newHash}?workspace=${$workspaceStore}`)
onevent={{
deploy: (newHash) => {
goto(`/scripts/get/${newHash}?workspace=${$workspaceStore}`)
},
saveInitial: (path) => {
goto(`/scripts/edit/${path}`)
},
saveDraft: ({ path, savedAtNewPath, script }) => {
goto(`/scripts/edit/${path}`)
}
}}
bind:getInitialAndModifiedValues
on:saveInitial={(e) => {
let path = e.detail
goto(`/scripts/edit/${path}`)
}}
on:seeDetails={(e) => {
let path = e.detail
goto(`/scripts/get/${path}?workspace=${$workspaceStore}`)
}}
replaceStateFn={(path) => {
replaceState(path, $page.state)
}}