fix: make some eval onDemandOnly

This commit is contained in:
Ruben Fiszel
2024-01-18 08:22:18 +01:00
parent 772da1b50e
commit 36905daef6
19 changed files with 121 additions and 55 deletions
+2 -2
View File
@@ -96,9 +96,9 @@ impl IntoResponse for Error {
};
if matches!(status, axum::http::StatusCode::NOT_FOUND) {
tracing::warn!(not_found = e.to_string());
tracing::warn!(message = e.to_string());
} else {
tracing::error!(error = e.to_string());
tracing::error!(essage = e.to_string());
};
axum::response::Response::builder()
+5
View File
@@ -54,6 +54,7 @@ export async function pushApp(
} else {
console.log(colors.yellow.bold("Creating new app..."));
console.log(message);
await AppService.createApp({
workspace,
requestBody: {
@@ -101,12 +102,16 @@ async function push(opts: GlobalOptions, filePath: string) {
const workspace = await resolveWorkspace(opts);
await requireLogin(opts);
<<<<<<< Updated upstream
await pushApp(
workspace.workspaceId,
filePath,
undefined,
parseFromFile(filePath)
);
=======
await pushApp(workspace.workspaceId, filePath, parseFromFile(filePath));
>>>>>>> Stashed changes
console.log(colors.bold.underline.green("App pushed"));
}
@@ -165,6 +165,9 @@
// let widgets: HTMLElement | undefined =
// document.getElementById('monaco-widgets-root') ?? undefined
if (!divEl) {
return
}
editor = meditor.create(divEl as HTMLDivElement, {
...editorConfig(code, lang, automaticLayout, fixedOverflowWidgets),
model,
@@ -125,22 +125,20 @@
} else {
await runnableComponent?.runComponent()
}
if (rowContext && rowInputs) {
rowInputs.set(id, { result: outputs.result.peak(), loading: false })
}
}
let loading = false
let css = initCss($app.css?.buttoncomponent, customCss)
</script>
{#each Object.keys(components['buttoncomponent'].initialData.configuration) as key (key)}
{#each Object.entries(components['buttoncomponent'].initialData.configuration) as [key, initialConfig] (key)}
<ResolveConfig
{id}
{extraKey}
{key}
bind:resolvedConfig={resolvedConfig[key]}
configuration={configuration[key]}
{initialConfig}
/>
{/each}
@@ -172,6 +170,16 @@
{render}
{outputs}
{extraKey}
onSuccess={(r) => {
let inputOutput = { result: r, loading: false }
if (rowContext && rowInputs) {
rowInputs.set(id, inputOutput)
}
if (iterContext && listInputs) {
listInputs.set(id, inputOutput)
}
console.log('success', r)
}}
refreshOnStart={resolvedConfig.triggerOnAppLoad}
>
<AlignWrapper {noWFull} {horizontalAlignment} {verticalAlignment} class="wm-button-wrapper">
@@ -28,6 +28,7 @@
export let error: string = ''
export let key: string = ''
export let field: string = key
export let onDemandOnly: boolean = false
const { componentControl, runnableComponents } = getContext<AppViewerContext>('AppViewerContext')
@@ -47,6 +48,7 @@
}
$: lastInput?.type == 'evalv2' &&
!onDemandOnly &&
(fullContext.iter != undefined ||
fullContext.row != undefined ||
fullContext.group != undefined) &&
@@ -144,8 +146,9 @@
let lastExpr: any = undefined
const debounceEval = async () => {
let nvalue = await evalExpr(lastInput as EvalAppInput)
const debounceEval = async (s?: string) => {
let args = s == 'exprChanged' ? { file: { name: 'example.png' } } : undefined
let nvalue = await evalExpr(lastInput as EvalAppInput, args)
if (field) {
editorContext?.evalPreview.update((x) => {
@@ -173,7 +176,7 @@
$: lastInput && lastInput.type == 'eval' && $stateId && $state && debounce2(debounceEval)
$: lastInput?.type == 'evalv2' && lastInput.expr && debounceEval()
$: lastInput?.type == 'evalv2' && lastInput.expr && debounceEval('exprChanged')
$: lastInput?.type == 'templatev2' && lastInput.eval && debounceTemplate()
async function handleConnection() {
@@ -200,6 +203,12 @@
} else if (lastInput?.type == 'eval') {
value = await evalExpr(lastInput as EvalAppInput)
} else if (lastInput?.type == 'evalv2') {
if (onDemandOnly) {
value = (args?: any) => {
return evalExpr(lastInput as EvalV2AppInput, args)
}
return
}
const skey = `${id}-${key}-${rowContext ? $rowContext.index : 0}-${
iterContext ? $iterContext.index : 0
}`
@@ -257,9 +266,13 @@
): Promise<any> {
if (iterContext && $iterContext.disabled) return
try {
const context = computeGlobalContext(
$worldStore,
deepMergeWithPriority(fullContext, args ?? {})
)
const r = await eval_like(
input.expr,
computeGlobalContext($worldStore, deepMergeWithPriority(fullContext, args ?? {})),
context,
true,
$state,
$mode == 'dnd',
@@ -7,7 +7,7 @@
export let key: string
export let resolvedConfig: any | { type: 'oneOf'; configuration: any; selected: string }
export let configuration: RichConfiguration
export let initialConfig: RichConfiguration | undefined = undefined
$: configuration?.type == 'oneOf' && handleSelected(configuration.selected)
function handleSelected(selected: string) {
@@ -22,11 +22,13 @@
{#each Object.keys(configuration.configuration?.[choice] ?? {}) as nestedKey (nestedKey)}
{#if resolvedConfig.configuration?.[choice] != undefined}
<InputValue
field={key}
field={nestedKey}
key={key + choice + nestedKey + extraKey}
{id}
input={configuration?.configuration?.[choice]?.[nestedKey]}
bind:value={resolvedConfig.configuration[choice][nestedKey]}
onDemandOnly={initialConfig?.type == 'oneOf' &&
initialConfig?.configuration?.[choice]?.[nestedKey]?.onDemandOnly}
/>
{/if}
{/each}
@@ -36,6 +38,8 @@
key={key + extraKey}
{id}
input={configuration}
onDemandOnly={(initialConfig?.type == 'static' || initialConfig?.type == 'evalv2') &&
initialConfig?.onDemandOnly}
bind:value={resolvedConfig}
/>
{/if}
@@ -515,7 +515,7 @@
recordJob(jobId, result, undefined, transformerResult)
delete $errorByComponent[id]
dispatch('success')
dispatch('success', result)
donePromise?.(result)
}
@@ -530,7 +530,7 @@
onMount(() => {
cancellableRun = (inlineScript?: InlineScript, setRunnableJobEditorPanel?: boolean) => {
let rejectCb: (err: Error) => void
let p: Partial<CancelablePromise<any>> = new Promise<void>((resolve, reject) => {
let p: Partial<CancelablePromise<any>> = new Promise<any>((resolve, reject) => {
rejectCb = reject
donePromise = resolve
executeComponent(true, inlineScript, setRunnableJobEditorPanel).catch(reject)
@@ -27,15 +27,15 @@
| 'close'
| 'clearFiles'
configuration: {
gotoUrl: { url: string | undefined; newTab: boolean | undefined }
gotoUrl: { url: (() => string) | string | undefined; newTab: boolean | undefined }
setTab: {
setTab: { id: string; index: number }[] | undefined
}
sendToast?: {
message: string | undefined
message: (() => string) | string | undefined
}
sendErrorToast?: {
message: string | undefined
message: (() => string) | string | undefined
appendError: boolean | undefined
}
openModal?: {
@@ -82,6 +82,7 @@
export let errorHandledByComponent: boolean = false
export let hasChildrens: boolean = false
export let allowConcurentRequests = false
export let onSuccess: (result: any) => void = () => {}
export function setArgs(value: any) {
runnableComponent?.setArgs(value)
@@ -122,7 +123,7 @@
)
}
export function handleSideEffect(success: boolean, errorMessage?: string) {
export async function handleSideEffect(success: boolean, errorMessage?: string) {
const sideEffect = success ? doOnSuccess : doOnError
if (recomputeIds && success) {
@@ -146,33 +147,39 @@
}
break
case 'gotoUrl':
const url = sideEffect?.configuration?.gotoUrl?.url
if (!url) return
let gotoUrl = sideEffect?.configuration?.gotoUrl?.url
if (!gotoUrl) return
if (typeof gotoUrl === 'function') {
gotoUrl = await gotoUrl()
}
const newTab = sideEffect?.configuration?.gotoUrl?.newTab
if (newTab) {
window.open(url, '_blank')
window.open(gotoUrl, '_blank')
} else {
window.location.href = url
window.location.href = gotoUrl
}
break
case 'sendToast': {
const message = sideEffect?.configuration?.sendToast?.message
let message = sideEffect?.configuration?.sendToast?.message
if (!message) return
if (typeof message === 'function') {
message = await message()
}
sendUserToast(message, !success)
break
}
case 'sendErrorToast': {
const message = sideEffect?.configuration?.sendErrorToast?.message
let message = sideEffect?.configuration?.sendErrorToast?.message
const appendError = sideEffect?.configuration?.sendErrorToast?.appendError
if (!message) return
if (typeof message === 'function') {
message = await message()
}
sendUserToast(message, true, [], appendError ? errorMessage : undefined)
break
}
@@ -254,7 +261,10 @@
on:doneError
on:cancel
on:resultSet={() => (initializing = false)}
on:success={() => handleSideEffect(true)}
on:success={(e) => {
onSuccess(e.detail)
handleSideEffect(true)
}}
on:handleError={(e) => handleSideEffect(false, e.detail)}
{outputs}
{errorHandledByComponent}
@@ -16,7 +16,6 @@
import { HelpersService, type UploadFilePart } from '$lib/gen'
import { writable, type Writable } from 'svelte/store'
import { Ban, CheckCheck, FileWarning, Files, RefreshCcw, Trash } from 'lucide-svelte'
import InputValue from '../helpers/InputValue.svelte'
export let id: string
export let configuration: RichConfigurations
@@ -82,7 +81,14 @@
return
}
const path = (await inputValue?.computeExpr({ file: fileToUpload })) ?? fileToUploadKey
let pathTemplate = resolvedConfig?.type?.configuration?.s3?.pathTemplate as any
const path =
typeof pathTemplate == 'function'
? (await pathTemplate?.({
file: fileToUpload
})) ?? fileToUploadKey
: fileToUploadKey
$fileUploads = $fileUploads.filter((fileUpload) => fileUpload.name !== fileToUpload.name)
@@ -196,8 +202,6 @@
}
}
let inputValue: InputValue | undefined = undefined
async function deleteFile(fileKey: string) {
await HelpersService.deleteS3File({
workspace: $workspaceStore!,
@@ -245,25 +249,27 @@
/>
{/each}
{#each Object.keys(components['s3fileinputcomponent'].initialData.configuration) as key (key)}
{#each Object.entries(components['s3fileinputcomponent'].initialData.configuration) as [key, value] (key)}
<ResolveConfig
{id}
{extraKey}
{key}
bind:resolvedConfig={resolvedConfig[key]}
configuration={configuration[key]}
initialConfig={value}
/>
{/each}
{#if configuration.type?.['configuration']?.s3.pathTemplate}
<!-- {#if configuration.type?.['configuration']?.s3.pathTemplate}
<InputValue
input={configuration.type?.['configuration']?.s3.pathTemplate}
{id}
field="pathTemplate"
value=""
bind:this={inputValue}
onDemandOnly
/>
{/if}
{/if} -->
{#if render}
<div class="w-full h-full p-2 flex">
@@ -25,7 +25,8 @@ import type {
StaticAppInput,
EvalAppInput,
EvalV2AppInput,
InputConnectionEval
InputConnectionEval,
StaticAppInputOnDemand
} from '../inputType'
import { get, type Writable } from 'svelte/store'
import { deepMergeWithPriority } from '$lib/utils'
@@ -640,7 +641,9 @@ export type InitConfig<
configuration: {
[Choice in keyof T[Property]['configuration']]: {
[IT in keyof T[Property]['configuration'][Choice]]: T[Property]['configuration'][Choice][IT] extends StaticAppInput
? T[Property]['configuration'][Choice][IT]['value'] | undefined
? T[Property]['configuration'][Choice][IT] extends StaticAppInputOnDemand
? () => Promise<T[Property]['configuration'][Choice][IT]['value'] | undefined>
: T[Property]['configuration'][Choice][IT]['value'] | undefined
: undefined
}
}
@@ -58,12 +58,7 @@ import type {
} from '../../types'
import type { Size } from '../../svelte-grid/types'
import type {
AppInputSpec,
EvalV2AppInput,
ResultAppInput,
StaticAppInput
} from '../../inputType'
import type { AppInputSpec, EvalV2AppInput, ResultAppInput, StaticAppInput } from '../../inputType'
export type BaseComponent<T extends string> = {
type: T
@@ -404,7 +399,8 @@ const onSuccessClick = {
fieldType: 'text',
type: 'static',
value: '',
placeholder: '/apps/get/foo'
placeholder: '/apps/get/foo',
onDemandOnly: true
},
newTab: {
tooltip: 'Open the url in a new tab',
@@ -419,7 +415,8 @@ const onSuccessClick = {
value: [] as Array<{ id: string; index: number }>,
fieldType: 'array',
subFieldType: 'tab-select',
tooltip: 'Set the tabs id and index to go to on success'
tooltip: 'Set the tabs id and index to go to on success',
onDemandOnly: true
}
},
sendToast: {
@@ -428,7 +425,8 @@ const onSuccessClick = {
fieldType: 'text',
type: 'static',
value: '',
placeholder: 'Hello there'
placeholder: 'Hello there',
onDemandOnly: true
}
},
openModal: {
@@ -489,7 +487,8 @@ const onErrorClick = {
fieldType: 'text',
type: 'static',
value: '',
placeholder: '/apps/get/foo'
placeholder: '/apps/get/foo',
onDemandOnly: true
},
newTab: {
tooltip: 'Open the url in a new tab',
@@ -513,7 +512,8 @@ const onErrorClick = {
fieldType: 'text',
type: 'static',
value: '',
placeholder: 'Hello there'
placeholder: 'Hello there',
onDemandOnly: true
},
appendError: {
tooltip: 'Append the error message to the toast',
@@ -3051,10 +3051,12 @@ This is a paragraph.
},
*/
pathTemplate: {
type: 'eval',
type: 'evalv2',
expr: `\`\${file.name}\``,
fieldType: 'template',
}
connections: [],
onDemandOnly: true
} as EvalV2AppInput
}
}
} as const
@@ -12,7 +12,6 @@
export let componentInput: AppInput
export let disableStatic: boolean = false
export let evalV2editor: EvalV2InputEditor | undefined
export let id: string
const { onchange, connectingInput, app } = getContext<AppViewerContext>('AppViewerContext')
@@ -220,7 +220,6 @@
<ComponentInputTypeEditor
{evalV2editor}
bind:componentInput={componentSettings.item.data.componentInput}
id={component.id}
/>
<div class="flex flex-col w-full gap-2 mt-2">
@@ -371,6 +370,7 @@
inputSpecsConfiguration={initialConfiguration}
bind:inputSpecs={componentSettings.item.data.configuration}
userInputEnabled={false}
acceptSelf
/>
</PanelSection>
{:else if componentSettings.item.data.type != 'containercomponent'}
@@ -19,9 +19,10 @@
on:change={() => {
if (disablable) {
field = {
type: 'eval',
type: 'evalv2',
expr: 'false',
fieldType: 'boolean'
fieldType: 'boolean',
connections: []
}
} else {
field = {
@@ -36,6 +36,7 @@
export let shouldFormatExpression: boolean = false
export let fixedOverflowWidgets: boolean = true
export let loading: boolean = false
export let acceptSelf: boolean = false
const { connectingInput, app } = getContext<AppViewerContext>('AppViewerContext')
@@ -168,6 +169,7 @@
<EvalInputEditor {id} bind:componentInput />
{:else if componentInput?.type === 'evalv2'}
<EvalV2InputEditor
{acceptSelf}
field={key}
bind:this={evalV2editor}
{id}
@@ -14,6 +14,7 @@
export let resourceOnly = false
export let displayType = false
export let deletable = false
export let acceptSelf: boolean = false
$: finalInputSpecsConfiguration = inputSpecsConfiguration ?? inputSpecs
@@ -25,6 +26,7 @@
{#each Object.keys(finalInputSpecsConfiguration) as k}
{#if finalInputSpecsConfiguration[k]?.type == 'oneOf'}
<OneOfInputSpecsEditor
{acceptSelf}
key={k}
bind:oneOf={inputSpecs[k]}
{id}
@@ -37,6 +39,7 @@
{:else}
{@const meta = finalInputSpecsConfiguration?.[k]}
<InputsSpecEditor
{acceptSelf}
key={k}
bind:componentInput={inputSpecs[k]}
{id}
@@ -14,6 +14,7 @@
export let resourceOnly: boolean
export let tooltip: string | undefined
export let disabledOptions: string[] = []
export let acceptSelf: boolean = false
$: {
if (oneOf == undefined) {
@@ -84,6 +85,7 @@
key={nestedKey}
bind:componentInput={oneOf.configuration[oneOf.selected][nestedKey]}
{id}
{acceptSelf}
userInputEnabled={false}
{shouldCapitalize}
{resourceOnly}
@@ -14,6 +14,7 @@
export let id: string
export let field: string
export let fixedOverflowWidgets: boolean = true
export let acceptSelf: boolean = false
const { onchange, worldStore, state, app } = getContext<AppViewerContext>('AppViewerContext')
const { evalPreview } = getContext<AppEditorContext>('AppEditorContext')
@@ -25,7 +26,7 @@
$: extraLib =
componentInput?.expr && $worldStore
? buildExtraLib($worldStore?.outputsById ?? {}, id, $state, false)
? buildExtraLib($worldStore?.outputsById ?? {}, acceptSelf ? '' : id, $state, false)
: undefined
if (
@@ -74,6 +74,7 @@ export type EvalInputV2 = {
type: 'evalv2'
expr: string
connections: InputConnectionEval[]
onDemandOnly?: boolean
}
export type RowInput = {
@@ -162,6 +163,7 @@ type InputConfiguration<T extends InputType, V extends InputType> = {
convertTo?: ReadFileAs
}
noStatic?: boolean
onDemandOnly?: boolean
}
export type StaticOptions = {
@@ -216,6 +218,8 @@ export type UserAppInput = Extract<AppInput, { type: 'user' }>
export type ResultAppInput = Extract<AppInput, { type: 'runnable' }>
export type EvalAppInput = Extract<AppInput, { type: 'eval' }>
export type EvalV2AppInput = Extract<AppInput, { type: 'evalv2' }>
export type StaticAppInputOnDemand = Extract<StaticAppInput, { onDemandOnly: true }>
export type UploadAppInput = Extract<AppInput, { type: 'upload' }>
export type RichAppInput =