feat(apps): add setValue to frontend script's SDK

This commit is contained in:
Ruben Fiszel
2023-05-28 18:02:42 +02:00
parent 1cb3686e8d
commit 77e7e49372
22 changed files with 185 additions and 54 deletions
@@ -20,7 +20,7 @@
import { createEventDispatcher, onDestroy, onMount } from 'svelte'
import libStdContent from '$lib/es5.d.ts.txt?raw'
import { buildWorkerDefinition } from 'monaco-editor-workers'
import { buildWorkerDefinition } from './build_workers'
meditor.defineTheme('myTheme', {
base: 'vs',
@@ -390,6 +390,7 @@
if ($selectedComponent) {
$componentControl[$selectedComponent[0]] = {
...$componentControl[$selectedComponent[0]],
setCode: (value: string) => {
code = value
setCode(value)
@@ -18,7 +18,7 @@
export let configuration: RichConfigurations
export let customCss: ComponentCustomCSS<'schemaformcomponent'> | undefined = undefined
const { worldStore, connectingInput, app, selectedComponent } =
const { worldStore, connectingInput, app, selectedComponent, componentControl } =
getContext<AppViewerContext>('AppViewerContext')
const outputs = initOutput($worldStore, id, {
@@ -43,6 +43,12 @@
outputs.values.set(newArgs, true)
}
$componentControl[id] = {
setValue(nvalue: any) {
args = nvalue
}
}
$: args && handleArgsChange()
$: outputs.valid.set(valid)
@@ -19,9 +19,15 @@
export let render: boolean
const requireHtmlApproval = getContext<boolean | undefined>(IS_APP_PUBLIC_CONTEXT_KEY)
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
const { app, worldStore, componentControl } = getContext<AppViewerContext>('AppViewerContext')
let result: any = undefined
$componentControl[id] = {
setValue(value: string) {
result = value
}
}
const outputs = initOutput($worldStore, id, {
result: undefined,
loading: false
@@ -48,6 +48,13 @@
initializing = false
}
$componentControl[id] = {
...$componentControl[id],
setValue(value: string) {
result = value
}
}
const outputs = initOutput($worldStore, id, {
result,
loading: initializing
@@ -119,7 +126,7 @@
$: resolvedConfig.style && (component = getComponent())
$: resolvedConfig.style && (classes = getClasses())
$: initialValue = componentInput?.type == 'template' ? componentInput.eval : ''
$: editableValue = initialValue ? JSON.parse(JSON.stringify(initialValue)) : ''
$: editableValue = initialValue ?? ''
let rows = 1
@@ -128,7 +135,6 @@
if (target.value) {
$componentControl[id]?.setCode?.(target.value)
editableValue
autosize()
}
}
@@ -72,28 +72,29 @@
$: lastInput && $worldStore && debounce(handleConnection)
$: lastInput &&
lastInput.type == 'template' &&
$stateId &&
$state &&
debounce(async () => {
let nvalue = await getValue(lastInput)
if (!deepEqual(nvalue, value)) {
value = nvalue
}
dispatch('done')
})
const debounceTemplate = async () => {
console.log('template')
let nvalue = await getValue(lastInput)
if (!deepEqual(nvalue, value)) {
value = nvalue
}
}
$: lastInput &&
lastInput.type == 'eval' &&
lastInput.type == 'template' &&
isCodeInjection(lastInput.eval) &&
$stateId &&
$state &&
debounce2(async () => {
let nvalue = await evalExpr(lastInput)
if (!deepEqual(nvalue, value)) {
value = nvalue
}
})
debounce(debounceTemplate)
const debounceEval = async () => {
let nvalue = await evalExpr(lastInput)
if (!deepEqual(nvalue, value)) {
value = nvalue
}
}
$: lastInput && lastInput.type == 'eval' && $stateId && $state && debounce2(debounceEval)
async function handleConnection() {
if (lastInput?.type === 'connected') {
@@ -20,7 +20,7 @@ export function computeGlobalContext(world: World | undefined, extraContext: any
function create_context_function_template(eval_string, context, noReturn: boolean) {
return `
return async function (context, state, goto, setTab, recompute, getAgGrid) {
return async function (context, state, goto, setTab, recompute, getAgGrid, setValue) {
"use strict";
${
Object.keys(context).length > 0
@@ -36,7 +36,7 @@ function make_context_evaluator(
eval_string,
context,
noReturn: boolean
): (context, state, goto, setTab, recompute, getAgGrid) => Promise<any> {
): (context, state, goto, setTab, recompute, getAgGrid, setValue) => Promise<any> {
let template = create_context_function_template(eval_string, context, noReturn)
let functor = Function(template)
return functor()
@@ -82,7 +82,11 @@ export async function eval_like(
editor: boolean,
controlComponents: Record<
string,
{ setTab?: (index: number) => void; agGrid?: { api: any; columnApi: any } }
{
setTab?: (index: number) => void
agGrid?: { api: any; columnApi: any }
setValue?: (value: any) => void
}
>,
worldStore: World | undefined,
runnableComponents: Record<string, { cb?: () => void }>
@@ -126,6 +130,9 @@ export async function eval_like(
},
(id) => {
return controlComponents[id]?.agGrid
},
(id, value) => {
controlComponents[id]?.setValue?.(value)
}
)
}
@@ -30,8 +30,16 @@
configuration
)
let value: boolean = (resolvedConfig.defaultValue as boolean | undefined) ?? false
$componentControl[id] = {
setValue(nvalue: boolean) {
value = nvalue
}
}
if (controls) {
$componentControl[id] = controls
$componentControl[id] = { ...$componentControl[id], ...controls }
}
// As the checkbox is a special case and has no input
@@ -41,7 +49,21 @@
result: false
})
$: resolvedConfig.defaultValue != undefined && outputs?.result.set(resolvedConfig.defaultValue)
function handleInput() {
outputs.result.set(value)
if (recomputeIds) {
recomputeIds.forEach((id) => $runnableComponents?.[id]?.cb())
}
}
function handleDefault() {
value = resolvedConfig.defaultValue ?? false
handleInput()
}
$: value != undefined && handleInput()
$: resolvedConfig.defaultValue != undefined && handleDefault()
$: css = concatCustomCss($app.css?.checkboxcomponent, customCss)
</script>
@@ -60,16 +82,13 @@
<AlignWrapper {render} {horizontalAlignment} {verticalAlignment}>
<Toggle
size="sm"
bind:checked={resolvedConfig.defaultValue}
bind:checked={value}
options={{ right: resolvedConfig.label }}
textClass={css?.text?.class ?? ''}
textStyle={css?.text?.style ?? ''}
on:change={(e) => {
preclickAction?.()
outputs.result.set(e.detail)
if (recomputeIds) {
recomputeIds.forEach((id) => $runnableComponents?.[id]?.cb())
}
value = e.detail
}}
/>
</AlignWrapper>
@@ -15,7 +15,8 @@
export let customCss: ComponentCustomCSS<'dateinputcomponent'> | undefined = undefined
export let render: boolean
const { app, worldStore, selectedComponent } = getContext<AppViewerContext>('AppViewerContext')
const { app, worldStore, selectedComponent, componentControl } =
getContext<AppViewerContext>('AppViewerContext')
let labelValue: string = 'Title'
let minValue: string = ''
let maxValue: string = ''
@@ -23,6 +24,12 @@
let value: string | undefined = undefined
$componentControl[id] = {
setValue(nvalue: string) {
value = nvalue
}
}
let outputs = initOutput($worldStore, id, {
result: undefined as string | undefined
})
@@ -16,7 +16,8 @@
export let customCss: ComponentCustomCSS<'multiselectcomponent'> | undefined = undefined
export let render: boolean
const { app, worldStore, selectedComponent } = getContext<AppViewerContext>('AppViewerContext')
const { app, worldStore, selectedComponent, componentControl } =
getContext<AppViewerContext>('AppViewerContext')
let items: string[]
const resolvedConfig = initConfig(
@@ -30,6 +31,13 @@
let value: string[] | undefined = outputs?.result.peak()
$componentControl[id] = {
setValue(nvalue: string[]) {
value = nvalue
outputs?.result.set([...(value ?? [])])
}
}
$: resolvedConfig.items && handleItems()
function handleItems() {
@@ -14,12 +14,19 @@
export let customCss: ComponentCustomCSS<'numberinputcomponent'> | undefined = undefined
export let render: boolean
const { app, worldStore, selectedComponent } = getContext<AppViewerContext>('AppViewerContext')
const { app, worldStore, selectedComponent, componentControl } =
getContext<AppViewerContext>('AppViewerContext')
let defaultValue: number | undefined = undefined
let placeholder: string | undefined = undefined
let value: number | undefined = undefined
$componentControl[id] = {
setValue(nvalue: number) {
value = nvalue
}
}
let min: number | undefined = undefined
let max: number | undefined = undefined
let step = 1
@@ -15,7 +15,7 @@
export let customCss: ComponentCustomCSS<'rangecomponent'> | undefined = undefined
export let render: boolean
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
const { app, worldStore, componentControl } = getContext<AppViewerContext>('AppViewerContext')
let min = 0
let max = 42
let step = 1
@@ -27,6 +27,12 @@
result: null as [number, number] | null
})
$componentControl[id] = {
setValue(nvalue: [number, number]) {
values = nvalue
}
}
$: outputs?.result.set(values)
$: css = concatCustomCss($app.css?.rangecomponent, customCss)
@@ -31,8 +31,14 @@
componentControl
} = getContext<AppViewerContext>('AppViewerContext')
$componentControl[id] = {
setValue(nvalue: string) {
setValue(JSON.stringify(nvalue))
}
}
if (controls) {
$componentControl[id] = controls
$componentControl[id] = { ...$componentControl[id], ...controls }
}
let resolvedConfig = initConfig(
@@ -80,13 +86,16 @@
return i
})
}
preclickAction?.()
setValue(e.detail?.['value'])
}
function setValue(nvalue: any) {
let result: any = undefined
try {
result = JSON.parse(e.detail?.['value'])
result = JSON.parse(nvalue)
} catch (_) {}
value = e.detail?.['value']
value = nvalue
outputs?.result.set(result)
if (recomputeIds) {
recomputeIds.forEach((id) => $runnableComponents?.[id]?.cb())
@@ -15,7 +15,7 @@
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export let render: boolean
const { worldStore } = getContext<AppViewerContext>('AppViewerContext')
const { worldStore, componentControl } = getContext<AppViewerContext>('AppViewerContext')
const resolvedConfig = initConfig(
components['selectstepcomponent'].initialData.configuration,
@@ -26,13 +26,31 @@
})
let selected: string = ''
$: selected === '' && resolvedConfig && setDefaultValue()
let selectedIndex: number = 0
$: resolvedConfig.defaultValue != undefined && setDefaultValue()
$componentControl[id] = {
setValue(nvalue: string) {
selected = nvalue
selectedIndex = resolvedConfig.items.findIndex((item) => item.value === nvalue)
},
setTab(index) {
selected = resolvedConfig.items?.[index]?.value
selectedIndex = index
}
}
function setDefaultValue() {
if (resolvedConfig.defaultValue === undefined) {
if (resolvedConfig.defaultValue != undefined) {
selectedIndex = resolvedConfig.items.findIndex(
(item) => item.value === resolvedConfig.defaultValue
)
}
if (selectedIndex === -1 || resolvedConfig.defaultValue == undefined) {
selected = resolvedConfig.items[0].value
} else if (resolvedConfig.defaultValue?.value) {
selected = resolvedConfig.defaultValue?.value
} else if (resolvedConfig.defaultValue) {
selected = resolvedConfig.items[selectedIndex].value
}
}
@@ -51,8 +69,6 @@
}
$: selected && handleSelection(selected)
let selectedIndex: number = 0
</script>
{#each Object.keys(components['selectstepcomponent'].initialData.configuration) as key (key)}
@@ -17,7 +17,7 @@
export let customCss: ComponentCustomCSS<'selecttabcomponent'> | undefined = undefined
export let render: boolean
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
const { app, worldStore, componentControl } = getContext<AppViewerContext>('AppViewerContext')
const resolvedConfig = initConfig(
components['selecttabcomponent'].initialData.configuration,
@@ -30,6 +30,15 @@
let selected: string = ''
$: selected === '' && resolvedConfig && setDefaultValue()
$componentControl[id] = {
setValue(nvalue: string) {
selected = nvalue
},
setTab(index) {
selected = resolvedConfig.items?.[index]?.value
}
}
function setDefaultValue() {
if (resolvedConfig.defaultValue === undefined) {
selected = resolvedConfig.items[0].value
@@ -15,7 +15,8 @@
export let customCss: ComponentCustomCSS<'slidercomponent'> | undefined = undefined
export let render: boolean
const { app, worldStore, selectedComponent } = getContext<AppViewerContext>('AppViewerContext')
const { app, worldStore, selectedComponent, componentControl } =
getContext<AppViewerContext>('AppViewerContext')
let min = 0
let max = 42
let step = 1
@@ -28,6 +29,12 @@
let values: [number] = [outputs?.result.peak() ?? 0]
$componentControl[id] = {
setValue(nvalue: number) {
values[0] = nvalue
}
}
$: values && handleValues()
function handleValues() {
@@ -20,7 +20,7 @@
| 'textareainputcomponent' = 'textinputcomponent'
export let render: boolean
const { app, worldStore, selectedComponent, connectingInput } =
const { app, worldStore, selectedComponent, connectingInput, componentControl } =
getContext<AppViewerContext>('AppViewerContext')
let placeholder: string | undefined = undefined
@@ -31,6 +31,12 @@
result: ''
})
$componentControl[id] = {
setValue(nvalue: string) {
value = nvalue
}
}
$: handleDefault(defaultValue)
$: outputs?.result.set(value ?? '')
@@ -15,7 +15,8 @@
export let customCss: ComponentCustomCSS<'currencycomponent'> | undefined = undefined
export let render: boolean
const { app, worldStore, selectedComponent } = getContext<AppViewerContext>('AppViewerContext')
const { app, worldStore, selectedComponent, componentControl } =
getContext<AppViewerContext>('AppViewerContext')
const outputs = initOutput($worldStore, id, {
result: null as number | null
@@ -28,6 +29,12 @@
let locale: string | undefined = undefined
let value: number | undefined = undefined
$componentControl[id] = {
setValue(nvalue: number) {
value = nvalue
}
}
function handleInput() {
outputs?.result.set(value ?? null)
}
@@ -237,6 +237,7 @@ state.foo += 1
// you may also just reassign as next statement 'state.foo = state.foo'
// you can also navigate (goto), recompute a script (recompute), or set a tab (setTab)
// Inputs and display components support settings their value directly (setValue)
return state.foo`,
language: 'frontend',
@@ -161,8 +161,8 @@
class="mb-0.5"
documentationLink="https://docs.windmill.dev/docs/apps/app-runnable#background-runnable"
>
Background runnables are triggered upon global refresh or when their input changes. The
result of a background runnable can be shared among many components.
Background runnables can be triggered on app refresh or when their input changes. The
result can be shared among many components.
</Tooltip>
</div>
<Button
@@ -195,6 +195,7 @@ export type AppViewerContext = {
agGrid?: { api: any; columnApi: any }
setCode?: (value: string) => void
onDelete?: () => void
setValue?: (value: any) => void
}
>
>
@@ -216,6 +216,7 @@ ${
declare function setTab(id: string, index: string): void;
declare function recompute(id: string): void;
declare function getAgGrid(id: string): {api: any, columnApi: any} | undefined;
declare function setValue(id: string, value: any): void;
`
: ''
}