feat: make row information available from table rows' evals

This commit is contained in:
Ruben Fiszel
2023-07-19 12:42:02 +02:00
parent e9d3e2c08b
commit 7c0e840da3
20 changed files with 192 additions and 145 deletions
@@ -391,16 +391,11 @@
<div class="flex gap-x-4 shrink">
<label class="block shrink min-w-0">
<span class="text-gray-700 text-sm">Maximum number of runs</span>
<input class="!w-55" type="number" bind:value={script.concurrent_limit} placeholder="5" />
<input class="!w-55" type="number" bind:value={script.concurrent_limit} />
</label>
<label class="block shrink min-w-0">
<span class="text-gray-700 text-sm">Per time window (seconds)</span>
<input
class="!w-18"
type="number"
bind:value={script.concurrency_time_window_s}
placeholder="60"
/>
<input class="!w-18" type="number" bind:value={script.concurrency_time_window_s} />
</label>
</div>
@@ -625,7 +620,8 @@
</div>
{/if}
<h2 class="border-b pb-1 mt-10 mb-4"
>Arguments &nbsp;<Tooltip documentationLink="https://www.windmill.dev/docs/core_concepts/json_schema_and_parsing"
>Arguments &nbsp;<Tooltip
documentationLink="https://www.windmill.dev/docs/core_concepts/json_schema_and_parsing"
>The arguments are synced with the main signature but you may refine the parts that
cannot be inferred from the type directly.</Tooltip
></h2
@@ -106,7 +106,6 @@
{/each}
<!-- gotoNewTab={resolvedConfig.onSuccess.selected == 'goto'} -->
<RunnableWrapper
bind:this={runnableWrapper}
{recomputeIds}
@@ -32,6 +32,7 @@
import ResolveConfig from '../../helpers/ResolveConfig.svelte'
import AppCheckbox from '../../inputs/AppCheckbox.svelte'
import AppSelect from '../../inputs/AppSelect.svelte'
import RowWrapper from '../../layout/RowWrapper.svelte'
export let id: string
export let componentInput: AppInput | undefined
@@ -58,10 +59,13 @@
selectedRow: undefined,
loading: false,
result: [],
inputs: {},
search: '',
page: 1
})
let inputs = {}
$: setSearch(searchValue)
function setSearch(srch: string) {
@@ -347,82 +351,134 @@
>
<div class="center-center h-full w-full flex-wrap gap-1.5">
{#each actionButtons as actionButton, actionIndex (actionButton?.id)}
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<div
on:mouseover|stopPropagation={() => {
if (actionButton.id !== $hoverStore) {
$hoverStore = actionButton.id
}
<RowWrapper
on:inputsChange={() => {
outputs?.inputs.set(inputs, true)
}}
on:mouseout|stopPropagation={() => {
if ($hoverStore !== undefined) {
$hoverStore = undefined
}
}}
class={classNames(
($selectedComponent?.includes(actionButton.id) ||
$hoverStore === actionButton.id) &&
$mode !== 'preview'
? 'outline outline-indigo-500 outline-1 outline-offset-1 relative'
: ''
)}
bind:inputs
value={row}
index={rowIndex}
>
{#if $mode !== 'preview'}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<span
title={`Id: ${actionButton.id}`}
class={classNames(
'px-2 text-2xs font-bold w-fit absolute shadow -top-2 -left-2 border z-50 rounded-sm',
'bg-indigo-500/90 border-indigo-600 text-white',
$selectedComponent?.includes(actionButton.id) ||
$hoverStore === actionButton.id
? 'opacity-100'
: 'opacity-0'
)}
on:click|stopPropagation={() => {
$selectedComponent = [actionButton.id]
}}
>
{actionButton.id}
</span>
{/if}
{#if rowIndex == 0}
{@const controls = {
left: () => {
if (actionIndex === 0) {
$selectedComponent = [id]
return true
} else if (actionIndex > 0) {
$selectedComponent = [actionButtons[actionIndex - 1].id]
return true
}
return false
},
right: () => {
if (actionIndex === actionButtons.length - 1) {
return id
} else if (actionIndex < actionButtons.length - 1) {
$selectedComponent = [actionButtons[actionIndex + 1].id]
return true
}
return false
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<div
on:mouseover|stopPropagation={() => {
if (actionButton.id !== $hoverStore) {
$hoverStore = actionButton.id
}
}}
{#if actionButton.type == 'buttoncomponent'}
on:mouseout|stopPropagation={() => {
if ($hoverStore !== undefined) {
$hoverStore = undefined
}
}}
class={classNames(
($selectedComponent?.includes(actionButton.id) ||
$hoverStore === actionButton.id) &&
$mode !== 'preview'
? 'outline outline-indigo-500 outline-1 outline-offset-1 relative'
: ''
)}
>
{#if $mode !== 'preview'}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<span
title={`Id: ${actionButton.id}`}
class={classNames(
'px-2 text-2xs font-bold w-fit absolute shadow -top-2 -left-2 border z-50 rounded-sm',
'bg-indigo-500/90 border-indigo-600 text-white',
$selectedComponent?.includes(actionButton.id) ||
$hoverStore === actionButton.id
? 'opacity-100'
: 'opacity-0'
)}
on:click|stopPropagation={() => {
$selectedComponent = [actionButton.id]
}}
>
{actionButton.id}
</span>
{/if}
{#if rowIndex == 0}
{@const controls = {
left: () => {
if (actionIndex === 0) {
$selectedComponent = [id]
return true
} else if (actionIndex > 0) {
$selectedComponent = [actionButtons[actionIndex - 1].id]
return true
}
return false
},
right: () => {
if (actionIndex === actionButtons.length - 1) {
return id
} else if (actionIndex < actionButtons.length - 1) {
$selectedComponent = [actionButtons[actionIndex + 1].id]
return true
}
return false
}
}}
{#if actionButton.type == 'buttoncomponent'}
<AppButton
extraKey={'idx' + rowIndex}
{render}
noWFull
preclickAction={async () => {
toggleRow(row, rowIndex)
}}
id={actionButton.id}
customCss={actionButton.customCss}
configuration={actionButton.configuration}
recomputeIds={actionButton.recomputeIds}
extraQueryParams={{ row: row.original }}
componentInput={actionButton.componentInput}
{controls}
/>
{:else if actionButton.type == 'checkboxcomponent'}
<AppCheckbox
extraKey={'idx' + rowIndex}
{render}
id={actionButton.id}
customCss={actionButton.customCss}
configuration={actionButton.configuration}
recomputeIds={actionButton.recomputeIds}
preclickAction={async () => {
toggleRow(row, rowIndex)
}}
{controls}
/>
{:else if actionButton.type == 'selectcomponent'}
<div class="w-40">
<AppSelect
extraKey={'idx' + rowIndex}
{render}
id={actionButton.id}
customCss={actionButton.customCss}
configuration={actionButton.configuration}
recomputeIds={actionButton.recomputeIds}
preclickAction={async () => {
toggleRow(row, rowIndex)
}}
{controls}
/>
</div>
{/if}
{:else if actionButton.type == 'buttoncomponent'}
<AppButton
extraKey={'idx' + rowIndex}
{render}
noWFull
preclickAction={async () => {
toggleRow(row, rowIndex)
}}
id={actionButton.id}
customCss={actionButton.customCss}
configuration={actionButton.configuration}
recomputeIds={actionButton.recomputeIds}
preclickAction={async () => {
toggleRow(row, rowIndex)
}}
extraQueryParams={{ row: row.original }}
componentInput={actionButton.componentInput}
{controls}
/>
{:else if actionButton.type == 'checkboxcomponent'}
<AppCheckbox
@@ -435,11 +491,11 @@
preclickAction={async () => {
toggleRow(row, rowIndex)
}}
{controls}
/>
{:else if actionButton.type == 'selectcomponent'}
<div class="w-40">
<AppSelect
--font-size="10px"
extraKey={'idx' + rowIndex}
{render}
id={actionButton.id}
@@ -449,54 +505,11 @@
preclickAction={async () => {
toggleRow(row, rowIndex)
}}
{controls}
/>
</div>
{/if}
{:else if actionButton.type == 'buttoncomponent'}
<AppButton
extraKey={'idx' + rowIndex}
{render}
noWFull
id={actionButton.id}
customCss={actionButton.customCss}
configuration={actionButton.configuration}
recomputeIds={actionButton.recomputeIds}
preclickAction={async () => {
toggleRow(row, rowIndex)
}}
extraQueryParams={{ row: row.original }}
componentInput={actionButton.componentInput}
/>
{:else if actionButton.type == 'checkboxcomponent'}
<AppCheckbox
extraKey={'idx' + rowIndex}
{render}
id={actionButton.id}
customCss={actionButton.customCss}
configuration={actionButton.configuration}
recomputeIds={actionButton.recomputeIds}
preclickAction={async () => {
toggleRow(row, rowIndex)
}}
/>
{:else if actionButton.type == 'selectcomponent'}
<div class="w-40">
<AppSelect
--font-size="10px"
extraKey={'idx' + rowIndex}
{render}
id={actionButton.id}
customCss={actionButton.customCss}
configuration={actionButton.configuration}
recomputeIds={actionButton.recomputeIds}
preclickAction={async () => {
toggleRow(row, rowIndex)
}}
/>
</div>
{/if}
</div>
</div>
</RowWrapper>
{/each}
</div>
</td>
@@ -20,8 +20,13 @@
const { componentControl, runnableComponents } = getContext<AppViewerContext>('AppViewerContext')
const iterContext = getContext<ListContext>('ListWrapperContext')
const rowContext = getContext<ListContext>('RowWrapperContext')
$: fullContext = iterContext ? { ...extraContext, iter: $iterContext } : extraContext
$: fullContext = {
...extraContext,
iter: iterContext ? $iterContext : undefined,
row: rowContext ? $rowContext : undefined
}
const dispatch = createEventDispatcher()
if (input == undefined) {
@@ -110,6 +115,7 @@
value = nvalue as T
}
} else {
lastExpr = nvalue
value = nvalue
}
}
@@ -58,6 +58,7 @@
connectingInput
} = getContext<AppViewerContext>('AppViewerContext')
const iterContext = getContext<ListContext>('ListWrapperContext')
const rowContext = getContext<ListContext>('RowWrapperContext')
const dispatch = createEventDispatcher()
@@ -170,7 +171,10 @@
try {
const r = await eval_like(
runnable.inlineScript?.content,
computeGlobalContext($worldStore, iterContext ? { iter: $iterContext } : {}),
computeGlobalContext($worldStore, {
iter: iterContext ? $iterContext : undefined,
row: rowContext ? $rowContext : undefined
}),
false,
$state,
$mode == 'dnd',
@@ -302,10 +306,11 @@
let raw = $worldStore.newOutput(id, 'raw', res)
res = await eval_like(
transformer.content,
computeGlobalContext(
$worldStore,
iterContext ? { iter: $iterContext, result: res } : { result: res }
),
computeGlobalContext($worldStore, {
iter: iterContext ? $iterContext : undefined,
row: rowContext ? $rowContext : undefined,
result: res
}),
false,
$state,
$mode == 'dnd',
@@ -31,6 +31,8 @@
getContext<AppViewerContext>('AppViewerContext')
const iterContext = getContext<ListContext>('ListWrapperContext')
const listInputs: ListInputs | undefined = getContext<ListInputs>('ListInputs')
const rowContext = getContext<ListContext>('RowWrapperContext')
const rowInputs: ListInputs | undefined = getContext<ListInputs>('RowInputs')
let value: boolean = false
@@ -58,6 +60,9 @@
if (iterContext && listInputs) {
listInputs(id, value)
}
if (rowContext && rowInputs) {
rowInputs(id, value)
}
if (recomputeIds) {
recomputeIds.forEach((id) => $runnableComponents?.[id]?.cb?.forEach((cb) => cb()))
}
@@ -39,6 +39,8 @@
const iterContext = getContext<ListContext>('ListWrapperContext')
const listInputs: ListInputs | undefined = getContext<ListInputs>('ListInputs')
const rowContext = getContext<ListContext>('RowWrapperContext')
const rowInputs: ListInputs | undefined = getContext<ListInputs>('RowInputs')
$componentControl[id] = {
setValue(nvalue: string) {
@@ -87,6 +89,9 @@
if (iterContext && listInputs) {
listInputs(id, rawValue)
}
if (rowContext && rowInputs) {
rowInputs(id, rawValue)
}
}
function onChange(e: CustomEvent) {
@@ -112,6 +117,9 @@
if (iterContext && listInputs) {
listInputs(id, result)
}
if (rowContext && rowInputs) {
rowInputs(id, result)
}
if (recomputeIds) {
recomputeIds.forEach((id) => $runnableComponents?.[id]?.cb?.forEach((f) => f()))
}
@@ -19,7 +19,6 @@
} else {
inputs[id][index] = value
}
console.log('foo')
dispatch('inputsChange')
})
</script>
@@ -0,0 +1,26 @@
<script lang="ts">
import { createEventDispatcher, setContext } from 'svelte'
import type { ListInputs, ListContext } from '../../types'
import { writable } from 'svelte/store'
export let index: number
export let value: any
export let disabled = false
export let inputs: Record<string, Record<number, any>> = {}
const dispatch = createEventDispatcher()
const ctx = writable({ index, value, disabled })
$: $ctx = { index, value, disabled }
setContext<ListContext>('RowWrapperContext', ctx)
setContext<ListInputs>('RowInputs', (id: string, value: any) => {
if (!inputs[id]) {
inputs[id] = { [index]: value }
} else {
inputs[id][index] = value
}
dispatch('inputsChange')
})
</script>
<slot />
@@ -63,7 +63,6 @@
{#key tableActionSettings?.item?.data?.id}
<ComponentPanel
noGrid
rowColumns
bind:componentSettings={tableActionSettings}
duplicateMoveAllowed={false}
onDelete={() => {
@@ -118,7 +118,7 @@
$: extraLib =
inlineScript?.language == 'frontend' && worldStore
? buildExtraLib($worldStore?.outputsById ?? {}, id, false, $state, true)
? buildExtraLib($worldStore?.outputsById ?? {}, id, $state, true)
: undefined
let drawerIsOpen: boolean | undefined = undefined
@@ -32,7 +32,6 @@
export let componentSettings: { item: GridItem; parent: string | undefined } | undefined =
undefined
export let rowColumns = false
export let onDelete: (() => void) | undefined = undefined
export let noGrid = false
export let duplicateMoveAllowed = true
@@ -99,7 +98,6 @@
? buildExtraLib(
$worldStore?.outputsById ?? {},
componentSettings?.item?.data?.id,
false,
$state,
false
)
@@ -227,7 +225,6 @@
bind:inputSpecs={componentSettings.item.data.componentInput.fields}
userInputEnabled={component.type === 'formcomponent' ||
component.type === 'formbuttoncomponent'}
{rowColumns}
/>
</PanelSection>
</div>
@@ -239,7 +236,6 @@
{#if Object.values(initialConfiguration).length > 0}
<PanelSection title={`Configuration (${Object.values(initialConfiguration).length})`}>
<InputsSpecsEditor
{rowColumns}
id={component.id}
inputSpecsConfiguration={initialConfiguration}
bind:inputSpecs={componentSettings.item.data.configuration}
@@ -157,7 +157,6 @@
userInputEnabled={false}
shouldCapitalize={true}
resourceOnly={false}
hasRows={false}
fieldType={condition?.['fieldType']}
subFieldType={condition?.['subFieldType']}
format={condition?.['format']}
@@ -42,7 +42,6 @@
userInputEnabled={false}
shouldCapitalize={true}
resourceOnly={false}
hasRows={false}
fieldType={field?.['fieldType']}
subFieldType={field?.['subFieldType']}
format={field?.['format']}
@@ -18,7 +18,6 @@
export let id: string
export let componentInput: RichConfiguration
export let key: string
export let hasRows: boolean = false
export let userInputEnabled: boolean = false
export let shouldCapitalize: boolean = true
export let resourceOnly = false
@@ -139,7 +138,7 @@
/>
</div>
{:else if componentInput?.type === 'eval'}
<EvalInputEditor {hasRows} {id} bind:componentInput />
<EvalInputEditor {id} bind:componentInput />
{:else if componentInput?.type === 'upload'}
<UploadInputEditor bind:componentInput {fileUpload} />
{:else if componentInput?.type === 'user'}
@@ -9,7 +9,6 @@
export let inputSpecsConfiguration: RichConfigurations | undefined = undefined
export let userInputEnabled: boolean = false
export let shouldCapitalize: boolean = true
export let rowColumns = false
export let resourceOnly = false
export let displayType = false
@@ -26,7 +25,6 @@
{id}
{shouldCapitalize}
{resourceOnly}
{rowColumns}
inputSpecsConfiguration={finalInputSpecsConfiguration?.[k]?.['configuration']}
labels={finalInputSpecsConfiguration?.[k]?.['labels']}
tooltip={finalInputSpecsConfiguration?.[k]?.['tooltip']}
@@ -40,7 +38,6 @@
{userInputEnabled}
{shouldCapitalize}
{resourceOnly}
hasRows={rowColumns}
fieldType={meta?.['fieldType']}
subFieldType={meta?.['subFieldType']}
format={meta?.['format']}
@@ -11,7 +11,6 @@
export let shouldCapitalize: boolean
export let id: string
export let resourceOnly: boolean
export let rowColumns: boolean
export let tooltip: string | undefined
$: {
@@ -62,7 +61,6 @@
userInputEnabled={false}
{shouldCapitalize}
{resourceOnly}
hasRows={rowColumns}
fieldType={config?.['fieldType']}
subFieldType={config?.['subFieldType']}
format={config?.['format']}
@@ -14,7 +14,6 @@
} from '../appUtils'
import type { ButtonComponent, CheckboxComponent, SelectComponent } from '../component'
import PanelSection from './common/PanelSection.svelte'
import TableActionLabel from './TableActionLabel.svelte'
import { Inspect, List, ToggleRightIcon } from 'lucide-svelte'
export let components: (BaseAppComponent &
@@ -67,7 +66,13 @@
</Badge>
<div>
<TableActionLabel componentInput={component.configuration.label} />
{#if component.type == 'buttoncomponent'}
Button
{:else if component.type == 'selectcomponent'}
Select
{:else if component.type == 'checkboxcomponent'}
Toggle
{/if}
</div>
<div>
<Button variant="border" color="red" on:click={() => deleteComponent(component.id)}>
@@ -8,13 +8,12 @@
export let componentInput: EvalAppInput | undefined
export let id: string
export let hasRows: boolean = false
const { onchange, worldStore, state } = getContext<AppViewerContext>('AppViewerContext')
$: extraLib =
componentInput?.expr && $worldStore
? buildExtraLib($worldStore?.outputsById ?? {}, id, hasRows, $state, false)
? buildExtraLib($worldStore?.outputsById ?? {}, id, $state, false)
: undefined
</script>
+1 -2
View File
@@ -195,7 +195,6 @@ export function toStatic(
export function buildExtraLib(
components: Record<string, Record<string, Output<any>>>,
idToExclude: string,
hasRows: boolean,
state: Record<string, any>,
goto: boolean
): string {
@@ -209,7 +208,6 @@ export function buildExtraLib(
.join('\n')
return `${cs}
${hasRows ? 'declare const row: Record<string, any>;' : ''}
${
goto
? `declare async function goto(path: string, newTab?: boolean): Promise<void>;
@@ -225,6 +223,7 @@ declare function closeModal(id: string): void;
}
declare const state: ${JSON.stringify(state)};
declare const iter: {index: number, value: any};
declare const row: {index: number, value: any};
`
}