diff --git a/frontend/src/lib/components/apps/components/TableComponent.svelte b/frontend/src/lib/components/apps/components/TableComponent.svelte index 31df45cf07..7b77e61264 100644 --- a/frontend/src/lib/components/apps/components/TableComponent.svelte +++ b/frontend/src/lib/components/apps/components/TableComponent.svelte @@ -17,16 +17,10 @@ const { worldStore } = getContext('AppEditorContext') - // ComponentInput: Static/dynamic - // ScriptInput: Run form: Static/Dynamic/User - // paramInput: Search : configurable only at component level (toggle) - export const staticOutputs: string[] = ['selectedRow', 'loading', 'result'] $: outputs = $worldStore?.outputsById[id] as { selectedRow: Output - result: Output> - loading: Output } let selectedRowIndex = -1 @@ -49,6 +43,10 @@ let result: Array> = [] $: headers = Object.keys(result[0] || {}) || [] + + const extraQueryParams = { search, page } + + export const reservedKeys: string[] = Object.keys(extraQueryParams) diff --git a/frontend/src/lib/components/apps/components/charts/PieChartComponent.svelte b/frontend/src/lib/components/apps/components/charts/PieChartComponent.svelte index ff98625c12..70aa3699af 100644 --- a/frontend/src/lib/components/apps/components/charts/PieChartComponent.svelte +++ b/frontend/src/lib/components/apps/components/charts/PieChartComponent.svelte @@ -42,10 +42,8 @@ let result: ChartData<'pie', number[], unknown> | undefined = undefined - + {#if result} - {:else} - No dataset {/if} diff --git a/frontend/src/lib/components/apps/components/common/ButtonComponent.svelte b/frontend/src/lib/components/apps/components/common/ButtonComponent.svelte index 6fae003a75..4b36e473cb 100644 --- a/frontend/src/lib/components/apps/components/common/ButtonComponent.svelte +++ b/frontend/src/lib/components/apps/components/common/ButtonComponent.svelte @@ -18,17 +18,26 @@ let labelValue: string = 'Default label' - let tick = 0 + let runnableComponent: RunnableComponent - + diff --git a/frontend/src/lib/components/apps/components/helpers/ComponentInputValue.svelte b/frontend/src/lib/components/apps/components/helpers/ComponentInputValue.svelte index fb51a823fb..4c2b088452 100644 --- a/frontend/src/lib/components/apps/components/helpers/ComponentInputValue.svelte +++ b/frontend/src/lib/components/apps/components/helpers/ComponentInputValue.svelte @@ -2,26 +2,17 @@ import { getContext } from 'svelte' import type { StaticInput, DynamicInput, AppEditorContext } from '../../types' + type T = $$Generic + export let input: DynamicInput | StaticInput - export let value: any + export let value: T const { worldStore } = getContext('AppEditorContext') - $: hasConnection = input.type === 'output' && input.id && input.name + $: input.type === 'static' && (value = input.value) + $: input.type === 'output' && $worldStore?.connect(input, onValueChange) - $: inputResult = hasConnection - ? $worldStore?.connect(input, () => updateValue()) - : { - peak: () => { - if (input.type === 'static') { - return input.value - } - } - } - - function updateValue() { - value = inputResult?.peak() + function onValueChange(newValue: T): void { + value = newValue } - - $: !hasConnection && input && updateValue() diff --git a/frontend/src/lib/components/apps/components/helpers/DebouncedInput.svelte b/frontend/src/lib/components/apps/components/helpers/DebouncedInput.svelte index 5f251e509e..9b22e16286 100644 --- a/frontend/src/lib/components/apps/components/helpers/DebouncedInput.svelte +++ b/frontend/src/lib/components/apps/components/helpers/DebouncedInput.svelte @@ -5,8 +5,9 @@ let timer: NodeJS.Timeout - function debounce(event: KeyboardEvent) { + function debounce(event: KeyboardEvent): void { clearTimeout(timer) + timer = setTimeout(() => { const target = event.target as HTMLInputElement value = target.value diff --git a/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte b/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte index c433449976..f312f783a0 100644 --- a/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte +++ b/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte @@ -22,13 +22,12 @@ export let runType: 'script' | 'flow' | undefined = undefined export let inlineScriptName: string | undefined = undefined export let extraQueryParams: Record = {} - export let shouldTick: number | undefined = undefined + export let autoRefresh: boolean = true export let result: any = undefined const { app, worldStore } = getContext('AppEditorContext') - let pagePath = $page.params.path - // Local state + let pagePath = $page.params.path let args: Record = {} let schema: Schema | undefined = undefined let testIsLoading = false @@ -36,8 +35,24 @@ $: mergedArgs = { ...args, ...extraQueryParams, ...runnableInputValues } - function isMergedArgsValid(mergedArgs: Record) { - if (Object.keys(inputs).length !== Object.keys(runnableInputValues).length) { + // TODO: Review + function setStaticInputsToArgs() { + Object.entries(inputs).forEach(([key, value]) => { + if (value.type === 'static') { + args[key] = value.value + } + }) + + args = args + } + + $: inputs && setStaticInputsToArgs() + + function argMergedArgsValid(mergedArgs: Record) { + if ( + Object.keys(inputs).filter((k) => inputs[k].type !== 'user').length !== + Object.keys(runnableInputValues).length + ) { return false } @@ -45,16 +60,14 @@ (arg) => arg !== undefined && arg !== null ) - debugger - - if (areAllArgsValid) { + if (areAllArgsValid && autoRefresh) { executeComponent() } return areAllArgsValid } - $: isValid = isMergedArgsValid(mergedArgs) + $: isValid = argMergedArgsValid(mergedArgs) // Test job internal state let testJob: CompletedJob | undefined = undefined @@ -65,13 +78,6 @@ loading: Output } - /** - * Args are built from 3 sources: - * 1. The inputs spec ( ) - * 2. The schema input transform with user submitted values§ - * 3. The extra query params - */ - async function loadSchemaFromTriggerable( workspace: string, path: string, @@ -91,8 +97,15 @@ // When the schema is loaded, we need to update the inputs spec // in order to render the inputs the component panel - $: if (schema && Object.keys(schema.properties ?? {}).length !== Object.keys(inputs).length) { - inputs = schemaToInputsSpec(schema) + $: if (schema && Object.keys(schema.properties).length !== Object.keys(inputs).length) { + let schemaWithoutExtraQueries: Schema = JSON.parse(JSON.stringify(schema)) + + // Remove extra query params from the schema, which are not directly configurable by the user + Object.keys(extraQueryParams).forEach((key) => { + delete schemaWithoutExtraQueries.properties[key] + }) + + inputs = schemaToInputsSpec(schemaWithoutExtraQueries) } let schemaStripped: Schema | undefined = undefined @@ -123,14 +136,19 @@ $: schema && stripSchema(schema) - $: disabledArgs = Object.keys(inputs).reduce((a: string[], c: string) => { - if (inputs[c].type === 'static') { - a = [...a, c] - } - return a - }, []) + $: disabledArgs = Object.keys(inputs).reduce( + (disabledArgsAccumulator: string[], inputName: string) => { + if (inputs[inputName].type === 'static') { + disabledArgsAccumulator = [...disabledArgsAccumulator, inputName] + } + return disabledArgsAccumulator + }, + [] + ) async function executeComponent() { + outputs?.loading.set(true) + await testJobLoader?.abstractRun(() => { const requestBody = { args: mergedArgs, @@ -154,6 +172,10 @@ }) }) } + + export function runComponent() { + executeComponent() + } {#each Object.keys(inputs) as key} @@ -164,6 +186,8 @@ on:done={() => { if (testJob) { outputs.result.set(testJob?.result) + outputs?.loading.set(false) + result = testJob?.result } }} @@ -176,7 +200,7 @@ {/if} -{#if shouldTick === undefined} +{#if autoRefresh === true} {#if isValid} - {#if component.runnable && component['path'] === undefined && component['inlineScriptName'] === undefined} - Select a script or a flow to continue - { - if (component && component.type === 'runformcomponent') { - component.path = detail.path - component.runType = 'script' - } - }} - /> - { - if (component && component.type === 'runformcomponent') { - component.path = detail.path - component.runType = 'flow' - } - }} - /> - {/if} + + + {/if} - {#if component.runnable && component['path'] === undefined && component['inlineScriptName'] === undefined} - {#each Object.keys($app.inlineScripts ?? {}) as inlineScriptName} - - {/each} - {/if} + /> + { + if (component && component.type === 'runformcomponent') { + component.path = detail.path + component.runType = 'flow' + } + }} + /> + {/if} - {#if component.componentInputs} + {#if component.runnable && component['path'] === undefined && component['inlineScriptName'] === undefined} + {#each Object.keys($app.inlineScripts ?? {}) as inlineScriptName} + + {/each} + {/if} + + {/if} + {#if Object.values(component.inputs).length > 0} + + + + {/if} + + {#if Object.values(component.componentInputs).length > 0} + - {/if} - + + {/if} {#if component.verticalAlignement !== undefined} diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/InputsSpecsEditor.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/InputsSpecsEditor.svelte index d7e597d508..f5acd41cd1 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/InputsSpecsEditor.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/InputsSpecsEditor.svelte @@ -7,6 +7,38 @@ export let inputSpecs: InputsSpec + const userTypeKeys = ['schemaProperty', 'defaultValue', 'value'] + const staticTypeKeys = ['visible', 'value', 'fieldType'] + const dynamicTypeKeys = ['id', 'name', 'defaultValue'] + + function sanitizeInputSpec(type: 'user' | 'static' | 'output', inputSpecKey: string) { + const inputSpec = inputSpecs[inputSpecKey] + if (type === 'user') { + for (const key of staticTypeKeys) { + delete inputSpec[key] + } + for (const key of dynamicTypeKeys) { + delete inputSpec[key] + } + } else if (type === 'static') { + for (const key of userTypeKeys) { + delete inputSpec[key] + } + for (const key of dynamicTypeKeys) { + delete inputSpec[key] + } + } else if (type === 'output') { + for (const key of userTypeKeys) { + delete inputSpec[key] + } + for (const key of staticTypeKeys) { + delete inputSpec[key] + } + } + + inputSpecs[inputSpecKey] = inputSpec + } + let openedProp = Object.keys(inputSpecs)[0] @@ -26,7 +58,10 @@ {#if inputSpecKey === openedProp}
- + sanitizeInputSpec(x.detail, inputSpecKey)} + > Static diff --git a/frontend/src/lib/components/apps/types.ts b/frontend/src/lib/components/apps/types.ts index 6ec1c5cc01..ac2c986cde 100644 --- a/frontend/src/lib/components/apps/types.ts +++ b/frontend/src/lib/components/apps/types.ts @@ -24,7 +24,16 @@ export type StaticInput = { type: 'static' value: any visible?: boolean - fieldType: 'text' | 'textarea' | 'number' | 'boolean' | 'select' | 'date' | 'time' | 'datetime' + fieldType: + | 'text' + | 'textarea' + | 'number' + | 'boolean' + | 'select' + | 'date' + | 'time' + | 'datetime' + | 'object' } export type AppInputTransform = DynamicInput | StaticInput | UserInput @@ -92,6 +101,7 @@ export type AppComponent = // Only dynamic inputs (Result of display) componentInputs: ComponentInputsSpec runnable?: boolean | undefined + card?: boolean | undefined // TODO: add min/max width/height } diff --git a/frontend/src/lib/components/apps/utils.ts b/frontend/src/lib/components/apps/utils.ts index 70411cae1d..9e347d2db1 100644 --- a/frontend/src/lib/components/apps/utils.ts +++ b/frontend/src/lib/components/apps/utils.ts @@ -77,11 +77,13 @@ export async function loadSchema( export function schemaToInputsSpec(schema: Schema): InputsSpec { return Object.keys(schema.properties).reduce((accu, key) => { const property = schema.properties[key] + accu[key] = { type: 'static', defaultValue: property.default, value: undefined, - visible: true + visible: true, + fieldType: property.type } return accu }, {})