mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-08 00:03:07 +00:00
dynamically reload schema if it changes
This commit is contained in:
@@ -7,10 +7,10 @@
|
||||
import { AppService, type CompletedJob } from '$lib/gen'
|
||||
import { defaultIfEmptyString, emptySchema, sendUserToast } from '$lib/utils'
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import { computeFields } from '../../editor/inlineScriptsPanel/utils'
|
||||
import type { AppInputs, Runnable } from '../../inputType'
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import { fieldTypeToTsType, schemaToInputsSpec } from '../../utils'
|
||||
import InputValue from './InputValue.svelte'
|
||||
import RefreshButton from './RefreshButton.svelte'
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
if (inlineScript) {
|
||||
const newSchema = inlineScript.schema
|
||||
|
||||
const newFields = reloadInputs(newSchema)
|
||||
const newFields = computeFields(newSchema, defaultUserInput, fields)
|
||||
|
||||
if (JSON.stringify(newFields) !== JSON.stringify(fields)) {
|
||||
setTimeout(() => {
|
||||
@@ -124,39 +124,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// When the schema is loaded, we need to update the inputs spec
|
||||
// in order to render the inputs the component panel
|
||||
function reloadInputs(schema: Schema) {
|
||||
let schemaCopy: Schema = JSON.parse(JSON.stringify(schema))
|
||||
|
||||
const result = {}
|
||||
const newInputs = schemaToInputsSpec(schemaCopy, defaultUserInput)
|
||||
if (!fields) {
|
||||
return newInputs
|
||||
}
|
||||
Object.keys(newInputs).forEach((key) => {
|
||||
const newInput = newInputs[key]
|
||||
const oldInput = fields[key]
|
||||
|
||||
// If the input is not present in the old inputs, add it
|
||||
if (oldInput === undefined) {
|
||||
result[key] = newInput
|
||||
} else {
|
||||
if (
|
||||
fieldTypeToTsType(newInput.fieldType) !== fieldTypeToTsType(oldInput.fieldType) ||
|
||||
newInput.format !== oldInput.format ||
|
||||
newInput.subFieldType !== oldInput.subFieldType
|
||||
) {
|
||||
result[key] = newInput
|
||||
} else {
|
||||
result[key] = oldInput
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
$: schemaStripped = runnable && stripSchema(fields)
|
||||
|
||||
function stripSchema(inputs: AppInputs): Schema {
|
||||
|
||||
+24
-2
@@ -7,10 +7,12 @@
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { emptySchema, getScriptByPath } from '$lib/utils'
|
||||
import { faCodeBranch, faExternalLinkAlt, faEye, faPen } from '@fortawesome/free-solid-svg-icons'
|
||||
import type { AppInput, ResultAppInput } from '../../inputType'
|
||||
import { clearResultAppInput } from '../../utils'
|
||||
import { onMount } from 'svelte'
|
||||
import type { AppInput, RunnableByPath } from '../../inputType'
|
||||
import { clearResultAppInput, schemaToInputsSpec } from '../../utils'
|
||||
import EmptyInlineScript from './EmptyInlineScript.svelte'
|
||||
import InlineScriptEditor from './InlineScriptEditor.svelte'
|
||||
import { computeFields } from './utils'
|
||||
|
||||
export let componentInput: AppInput | undefined
|
||||
export let id: string
|
||||
@@ -39,6 +41,26 @@
|
||||
|
||||
let drawerFlowViewer: Drawer
|
||||
let flowPath: string = ''
|
||||
|
||||
async function refreshScript(x: RunnableByPath) {
|
||||
let { schema } = await getScriptByPath(x.path)
|
||||
if (JSON.stringify(x.schema) != JSON.stringify(schema)) {
|
||||
x.schema = schema
|
||||
if (componentInput?.type == 'runnable') {
|
||||
componentInput.fields = computeFields(schema, false, componentInput.fields)
|
||||
}
|
||||
componentInput = componentInput
|
||||
}
|
||||
}
|
||||
|
||||
$: if (
|
||||
componentInput &&
|
||||
componentInput.type == 'runnable' &&
|
||||
componentInput?.runnable?.type === 'runnableByPath' &&
|
||||
componentInput.runnable.runType == 'script'
|
||||
) {
|
||||
refreshScript(componentInput.runnable)
|
||||
}
|
||||
</script>
|
||||
|
||||
<Drawer bind:this={drawerFlowViewer} size="1200px">
|
||||
|
||||
+7
-16
@@ -14,7 +14,7 @@
|
||||
const { app, selectedComponent, lazyGrid } = getContext<AppEditorContext>('AppEditorContext')
|
||||
let list: HTMLElement
|
||||
|
||||
function selectInlineScript(id: string) {
|
||||
function selectScript(id: string) {
|
||||
selectedScriptComponentId = id
|
||||
if (!id.startsWith('unused-') || !id.startsWith('bg_')) {
|
||||
$selectedComponent = selectedScriptComponentId
|
||||
@@ -24,19 +24,10 @@
|
||||
$: runnables = getAppScripts($lazyGrid)
|
||||
|
||||
// When selected component changes, update selectedScriptComponentId
|
||||
$: if (selectedComponent) {
|
||||
$: if ($selectedComponent != selectedScriptComponentId) {
|
||||
selectedScriptComponentId = $selectedComponent
|
||||
}
|
||||
|
||||
// Doesn't work for some reason
|
||||
// $: if (selectedScriptComponentId) {
|
||||
// const selected = document.getElementById(PREFIX + selectedScriptComponentId)
|
||||
// if(selected) {
|
||||
// const top = selected.getBoundingClientRect().top - list.getBoundingClientRect().top + list.scrollTop
|
||||
// list.scrollTo({ top, behavior: 'smooth' })
|
||||
// }
|
||||
// }
|
||||
|
||||
function createBackgroundScript() {
|
||||
let index = 0
|
||||
let newScriptPath = `Background Script ${index}`
|
||||
@@ -58,7 +49,7 @@
|
||||
fields: {}
|
||||
})
|
||||
$app.hiddenInlineScripts = $app.hiddenInlineScripts
|
||||
selectInlineScript(`bg_${$app.hiddenInlineScripts.length - 1}`)
|
||||
selectScript(`bg_${$app.hiddenInlineScripts.length - 1}`)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -73,7 +64,7 @@
|
||||
id={PREFIX + id}
|
||||
class="border flex gap-1 truncate font-normal justify-between w-full items-center py-1 px-2 rounded-sm duration-200
|
||||
{selectedScriptComponentId === id ? 'border-blue-500 bg-blue-100' : 'hover:bg-blue-50'}"
|
||||
on:click={() => selectInlineScript(id)}
|
||||
on:click={() => selectScript(id)}
|
||||
>
|
||||
<span class="text-2xs truncate">{name}</span>
|
||||
<div>
|
||||
@@ -92,7 +83,7 @@
|
||||
id={PREFIX + id}
|
||||
class="border flex gap-1 truncate font-normal justify-between w-full items-center py-1 px-2 rounded-sm duration-200
|
||||
{selectedScriptComponentId === id ? 'border-blue-500 bg-blue-100' : 'hover:bg-blue-50'}"
|
||||
on:click={() => selectInlineScript(id)}
|
||||
on:click={() => selectScript(id)}
|
||||
>
|
||||
<span class="text-2xs truncate">{unusedInlineScript.name}</span>
|
||||
<Badge color="red">Detached</Badge>
|
||||
@@ -115,7 +106,7 @@
|
||||
id={PREFIX + id}
|
||||
class="border flex gap-1 truncate font-normal justify-between w-full items-center py-1 px-2 rounded-sm duration-200
|
||||
{selectedScriptComponentId === id ? 'border-blue-500 bg-blue-100' : 'hover:bg-blue-50'}"
|
||||
on:click={() => selectInlineScript(id)}
|
||||
on:click={() => selectScript(id)}
|
||||
>
|
||||
<span class="text-2xs truncate">{name}</span>
|
||||
<Badge color="dark-indigo">{id}</Badge>
|
||||
@@ -146,7 +137,7 @@
|
||||
id={PREFIX + id}
|
||||
class="border flex gap-1 truncate font-normal justify-between w-full items-center py-1 px-2 rounded-sm duration-200
|
||||
{selectedScriptComponentId === id ? 'border-blue-500 bg-blue-100' : 'hover:bg-blue-50'}"
|
||||
on:click={() => selectInlineScript(id)}
|
||||
on:click={() => selectScript(id)}
|
||||
>
|
||||
<span class="text-2xs truncate">{name}</span>
|
||||
<Badge color="dark-indigo">{id}</Badge>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { Runnable } from "../../inputType"
|
||||
import type { Schema } from "$lib/common";
|
||||
import type { AppInputs, Runnable } from "../../inputType"
|
||||
import type { GridItem } from "../../types"
|
||||
import { fieldTypeToTsType, schemaToInputsSpec } from "../../utils";
|
||||
import type { AppComponent } from "../Component.svelte";
|
||||
|
||||
export interface AppScriptsList {
|
||||
@@ -7,6 +9,39 @@ export interface AppScriptsList {
|
||||
imported: { name: string; id: string }[]
|
||||
}
|
||||
|
||||
// When the schema is loaded, we need to update the inputs spec
|
||||
// in order to render the inputs the component panel
|
||||
export function computeFields(schema: Schema, defaultUserInput: boolean, fields: AppInputs) {
|
||||
let schemaCopy: Schema = JSON.parse(JSON.stringify(schema))
|
||||
|
||||
const result = {}
|
||||
const newInputs = schemaToInputsSpec(schemaCopy, defaultUserInput)
|
||||
if (!fields) {
|
||||
return newInputs
|
||||
}
|
||||
Object.keys(newInputs).forEach((key) => {
|
||||
const newInput = newInputs[key]
|
||||
const oldInput = fields[key]
|
||||
|
||||
// If the input is not present in the old inputs, add it
|
||||
if (oldInput === undefined) {
|
||||
result[key] = newInput
|
||||
} else {
|
||||
if (
|
||||
fieldTypeToTsType(newInput.fieldType) !== fieldTypeToTsType(oldInput.fieldType) ||
|
||||
newInput.format !== oldInput.format ||
|
||||
newInput.subFieldType !== oldInput.subFieldType
|
||||
) {
|
||||
result[key] = newInput
|
||||
} else {
|
||||
result[key] = oldInput
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
export function getAppScripts(grid: GridItem[]) {
|
||||
return grid.reduce((acc, gridComponent) => {
|
||||
const component: AppComponent = gridComponent.data
|
||||
|
||||
@@ -58,7 +58,7 @@ export type TemplateInput = {
|
||||
type: 'template'
|
||||
}
|
||||
|
||||
type RunnableByPath = {
|
||||
export type RunnableByPath = {
|
||||
path: string
|
||||
schema: any
|
||||
runType: 'script' | 'flow' | 'hubscript'
|
||||
|
||||
Reference in New Issue
Block a user