From 955a980703362b78bf24a47ec348878d7aac94e3 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Tue, 13 Aug 2024 15:14:26 +0200 Subject: [PATCH] feat(frontend): group fields are mutable --- .../apps/components/GroupWrapper.svelte | 5 +- .../apps/components/helpers/InputValue.svelte | 10 ++- .../helpers/RunnableComponent.svelte | 9 ++- .../apps/components/helpers/eval.ts | 66 +++++++++++++++---- .../components/layout/AppContainer.svelte | 17 ++++- .../ComponentInputTypeEditor.svelte | 6 +- .../editor/settingsPanel/GridGroup.svelte | 14 +++- frontend/src/lib/components/apps/types.ts | 3 +- 8 files changed, 102 insertions(+), 28 deletions(-) diff --git a/frontend/src/lib/components/apps/components/GroupWrapper.svelte b/frontend/src/lib/components/apps/components/GroupWrapper.svelte index ad8624e743..b41d20e654 100644 --- a/frontend/src/lib/components/apps/components/GroupWrapper.svelte +++ b/frontend/src/lib/components/apps/components/GroupWrapper.svelte @@ -3,9 +3,10 @@ import type { Writable } from 'svelte/store' import type { GroupContext } from '../types' - export let groupContext: Writable> + export let context: Writable> + export let id: string - setContext('GroupContext', groupContext) + setContext('GroupContext', { id, context }) diff --git a/frontend/src/lib/components/apps/components/helpers/InputValue.svelte b/frontend/src/lib/components/apps/components/helpers/InputValue.svelte index cda976a396..996fcbea72 100644 --- a/frontend/src/lib/components/apps/components/helpers/InputValue.svelte +++ b/frontend/src/lib/components/apps/components/helpers/InputValue.svelte @@ -43,10 +43,12 @@ let previousConnectedValues: Record = {} + let groupStore = groupContext?.context + $: fullContext = { iter: iterContext ? $iterContext : undefined, row: rowContext ? $rowContext : undefined, - group: groupContext ? $groupContext : undefined + group: groupStore ? $groupStore : undefined } $: lastInput?.type == 'evalv2' && @@ -272,7 +274,8 @@ $componentControl, $worldStore, $runnableComponents, - false + false, + groupContext?.id ) error = '' return r @@ -297,7 +300,8 @@ $componentControl, $worldStore, $runnableComponents, - false + false, + groupContext?.id ) error = '' return r diff --git a/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte b/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte index e38b469c84..971a603c1a 100644 --- a/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte +++ b/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte @@ -279,14 +279,15 @@ computeGlobalContext($worldStore, { iter: iterContext ? $iterContext : undefined, row: rowContext ? $rowContext : undefined, - group: groupContext ? $groupContext : undefined + group: groupContext ? get(groupContext.context) : undefined }), $state, isEditor, $componentControl, $worldStore, $runnableComponents, - true + true, + groupContext?.id ) await setResult(r, job) @@ -504,6 +505,7 @@ computeGlobalContext($worldStore, { iter: iterContext ? $iterContext : undefined, row: rowContext ? $rowContext : undefined, + group: groupContext ? get(groupContext.context) : undefined, result: res }), $state, @@ -511,7 +513,8 @@ $componentControl, $worldStore, $runnableComponents, - true + true, + groupContext?.id ) return transformerResult } catch (err) { diff --git a/frontend/src/lib/components/apps/components/helpers/eval.ts b/frontend/src/lib/components/apps/components/helpers/eval.ts index a27b8ff3c2..4e48087b72 100644 --- a/frontend/src/lib/components/apps/components/helpers/eval.ts +++ b/frontend/src/lib/components/apps/components/helpers/eval.ts @@ -25,11 +25,11 @@ function create_context_function_template( ) { let hasReturnAsLastLine = noReturn || eval_string.split('\n').some((x) => x.startsWith('return ')) return ` -return async function (context, state, goto, setTab, recompute, getAgGrid, setValue, setSelectedIndex, openModal, closeModal, open, close, validate, invalidate, validateAll, clearFiles, showToast, waitJob, askNewResource) { +return async function (context, state, createProxy, goto, setTab, recompute, getAgGrid, setValue, setSelectedIndex, openModal, closeModal, open, close, validate, invalidate, validateAll, clearFiles, showToast, waitJob, askNewResource) { "use strict"; ${ contextKeys && contextKeys.length > 0 - ? `let ${contextKeys.map((key) => ` ${key} = context['${key}']`)};` + ? `let ${contextKeys.map((key) => ` ${key} = createProxy('${key}', context['${key}'] ?? {})`)};` : `` } ${ @@ -46,6 +46,7 @@ return ${eval_string.startsWith('return ') ? eval_string.substring(7) : eval_str type WmFunctor = ( context, state, + createProxy, goto, setTab, recompute, @@ -113,30 +114,67 @@ export async function eval_like( showToast?: (message: string, error?: boolean) => void waitJob?: (jobId: string) => void askNewResource?: () => void + setGroupValue?: (key: string, value: any) => void } >, worldStore: World | undefined, runnableComponents: Record void)[] }>, - noReturn: boolean + noReturn: boolean, + groupContextId: string | undefined ) { - const proxiedState = new Proxy(state, { - set(target, key, value) { - if (typeof key !== 'string') { - throw new Error('Invalid key') - } - target[key] = value - let o = worldStore?.newOutput('state', key, value) - o?.set(value, true) - - return true + const createProxy = (name: string, obj: any) => { + if (name == 'group' && groupContextId) { + return createGroupProxy(groupContextId, obj) } - }) + return new Proxy(obj, { + set(target, key, value) { + if (name != 'state') { + throw new Error( + 'Cannot set value on objects that are neither the global state or a container group field' + ) + } + if (typeof key !== 'string') { + throw new Error('Invalid key') + } + target[key] = value + let o = worldStore?.newOutput(name, key, value) + o?.set(value, true) + + return true + }, + get(obj, prop) { + if (name != 'state' && prop == 'group') { + return createGroupProxy(name, obj[prop]) + } else { + return obj[prop] + } + } + }) + } + + const createGroupProxy = (name: string, obj: any) => { + return new Proxy(obj, { + set(target, key, value) { + target[key] = value + let o = worldStore?.newOutput(name, 'group', target) + o?.set(target, true) + if (typeof key !== 'string') { + throw new Error('Invalid key') + } + controlComponents[name]?.setGroupValue?.(key, value) + return true + } + }) + } + + const proxiedState = createProxy('state', state) let evaluator = make_context_evaluator(text, Object.keys(context ?? {}), noReturn) // console.log(i, j) return await evaluator( context, proxiedState, + createProxy, async (x, newTab) => { if (newTab || editor) { if (!newTab) { diff --git a/frontend/src/lib/components/apps/components/layout/AppContainer.svelte b/frontend/src/lib/components/apps/components/layout/AppContainer.svelte index dcf932fcb2..a8b5e29c2c 100644 --- a/frontend/src/lib/components/apps/components/layout/AppContainer.svelte +++ b/frontend/src/lib/components/apps/components/layout/AppContainer.svelte @@ -1,5 +1,5 @@ @@ -57,7 +68,7 @@
{#if $app.subgrids?.[`${id}-0`]} - + \` where x is the group field name` + using \`group.x\` where x is the group field name. + + Group fields are mutable by frontend scripts, so \`group.x = 42\` can be used to set the value inside the group and + \`a.group.x = 42\` outside of it.` }} />
@@ -111,6 +115,14 @@ /> + +
+ + You may set the value of a group field in a frontend script within the group using: group.x = 42 + and externally using {item.id}.group.x = 42 + {/if} diff --git a/frontend/src/lib/components/apps/types.ts b/frontend/src/lib/components/apps/types.ts index d0640f0e0e..4ce6979aa5 100644 --- a/frontend/src/lib/components/apps/types.ts +++ b/frontend/src/lib/components/apps/types.ts @@ -186,7 +186,7 @@ export type ListInputs = { remove: (id: string) => void } -export type GroupContext = Writable> +export type GroupContext = { id: string; context: Writable> } export type AppViewerContext = { worldStore: Writable @@ -263,6 +263,7 @@ export type AppViewerContext = { showToast?: (message: string, error?: boolean) => void recompute?: () => void askNewResource?: () => void + setGroupValue?: (key: string, value: any) => void } > >