dynamically reload schema if it changes

This commit is contained in:
Ruben Fiszel
2023-02-15 17:56:43 +01:00
parent 8445697e31
commit 06a8fcf666
5 changed files with 70 additions and 55 deletions
@@ -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 {
@@ -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">
@@ -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'