feat(frontend): allow running eval in every field

This commit is contained in:
Ruben Fiszel
2023-05-02 09:59:11 +02:00
parent e2ab10d697
commit 3900908f50
12 changed files with 86 additions and 62 deletions
@@ -160,7 +160,9 @@
editor.onDidBlurEditorText(() => {
code = getCode()
})
}
function loadExtraLib() {
if (lang == 'javascript') {
const stdLib = { content: libStdContent, filePath: 'es5.d.ts' }
if (extraLib != '') {
@@ -177,12 +179,16 @@
}
}
onMount(() => {
let mounted = false
onMount(async () => {
if (browser) {
loadMonaco()
mounted = true
await loadMonaco()
}
})
$: mounted && extraLib && loadExtraLib()
onDestroy(() => {
try {
model && model.dispose()
@@ -459,19 +459,6 @@
editor.addCommand(KeyMod.CtrlCmd | KeyCode.KeyS, function () {})
})
const stdLib = { content: libStdContent, filePath: 'es5.d.ts' }
if (extraLib != '') {
languages.typescript.javascriptDefaults.setExtraLibs([
{
content: extraLib,
filePath: 'windmill.d.ts'
},
stdLib
])
} else {
languages.typescript.javascriptDefaults.setExtraLibs([stdLib])
}
extraModel = meditor.createModel('`' + model.getValue() + '`', 'javascript')
const worker = await languages.typescript.getJavaScriptWorker()
const client = await worker(extraModel.uri)
@@ -589,12 +576,31 @@
editor?.focus()
}
onMount(() => {
let mounted = false
onMount(async () => {
if (browser) {
loadMonaco()
await loadMonaco()
mounted = true
}
})
$: mounted && extraLib && loadExtraLib()
function loadExtraLib() {
const stdLib = { content: libStdContent, filePath: 'es5.d.ts' }
if (extraLib != '') {
languages.typescript.javascriptDefaults.setExtraLibs([
{
content: extraLib,
filePath: 'windmill.d.ts'
},
stdLib
])
} else {
languages.typescript.javascriptDefaults.setExtraLibs([stdLib])
}
}
onDestroy(() => {
try {
model && model.dispose()
@@ -56,6 +56,18 @@
timeout = setTimeout(cb, debounce_ms)
}
function debounce2(cb: () => Promise<void>) {
if (firstDebounce) {
firstDebounce = false
cb()
return
}
if (timeout) {
clearTimeout(timeout)
}
timeout = setTimeout(cb, 1000)
}
$: lastInput && $worldStore && debounce(handleConnection)
$: lastInput &&
@@ -63,7 +75,10 @@
$stateId &&
$state &&
debounce(async () => {
value = await getValue(lastInput)
let nvalue = await getValue(lastInput)
if (!deepEqual(nvalue, value)) {
value = nvalue
}
dispatch('done')
})
@@ -71,7 +86,12 @@
lastInput.type == 'eval' &&
$stateId &&
$state &&
debounce(async () => (value = await evalExpr(lastInput)))
debounce2(async () => {
let nvalue = await evalExpr(lastInput)
if (!deepEqual(nvalue, value)) {
value = nvalue
}
})
async function handleConnection() {
if (lastInput?.type === 'connected') {
@@ -88,7 +108,7 @@
dispatch('done')
}
async function evalExpr(input: EvalAppInput) {
async function evalExpr(input: EvalAppInput): Promise<any> {
try {
const r = await eval_like(
input.expr,
@@ -135,11 +135,7 @@
Object.keys(inputs ?? {}).forEach((key: string) => {
const input = inputs[key]
if (input.type === 'static' && schemaStripped !== undefined) {
delete schemaStripped.properties[key]
}
if (input.type === 'connected' && schemaStripped !== undefined) {
if (['static', 'eval', 'connected'].includes(input.type) && schemaStripped !== undefined) {
delete schemaStripped.properties[key]
}
})
@@ -270,7 +270,7 @@
</Splitpanes>
</SplitPanesWrapper>
</Pane>
<Pane size={22} minSize={5} maxSize={33}>
<Pane size={22} minSize={15} maxSize={33}>
<div class="relative flex flex-col h-full">
<Tabs bind:selected={selectedTab} wrapperClass="!min-h-[42px]" class="!h-full">
<Popover disappearTimeout={0} notClickable placement="bottom">
@@ -55,15 +55,7 @@ export function selectId(
selectedComponent: Writable<string[] | undefined>,
app: App
) {
// this ensure handleClickOutside are triggered
let event = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true,
relatedTarget: e.target
})
window.dispatchEvent(event)
;(document?.activeElement as HTMLElement)?.blur()
if (e.shiftKey) {
selectedComponent.update((old) => {
if (old && old?.[0]) {
@@ -410,8 +410,8 @@ export const components = {
},
disabled: {
fieldType: 'boolean',
type: 'eval',
expr: 'false'
type: 'static',
value: false
},
beforeIcon: {
type: 'static',
@@ -517,8 +517,8 @@ export const components = {
onSuccess: onSuccessClick,
disabled: {
fieldType: 'boolean',
type: 'eval',
expr: 'false'
type: 'static',
value: false
}
}
}
@@ -1536,8 +1536,8 @@ Hello \${ctx.username}
},
disabled: {
fieldType: 'boolean',
type: 'eval',
expr: 'false'
type: 'static',
value: false
}
},
componentInput: undefined,
@@ -97,9 +97,9 @@ export async function main(db: Resource<"postgresql"> = "$res:f/examples/demodb"
}`
},
displaycomponent: {
deno: `export async function main() {
deno: `export async function main(x = 42) {
return {
"foo": 42
foo: x
}
}`,
python3: `def main():
@@ -132,20 +132,16 @@
</Popover>
{/if}
{#if inlineScript.language != 'frontend'}
<Popover notClickable placement="bottom">
<Button
size="xs"
color="light"
btnClasses="!px-2 !bg-gray-100 hover:!bg-gray-200"
aria-label="Open full editor"
on:click={() => {
inlineScriptEditorDrawer?.openDrawer()
}}
>
Full Editor&nbsp;<Maximize2 size={14} />
</Button>
<svelte:fragment slot="text">Open full editor</svelte:fragment>
</Popover>
<Button
size="xs"
color="light"
btnClasses="!px-2 !bg-gray-100 hover:!bg-gray-200"
on:click={() => {
inlineScriptEditorDrawer?.openDrawer()
}}
>
Full Editor&nbsp;<Maximize2 size={14} />
</Button>
{/if}
<Button
@@ -12,7 +12,7 @@
import type { InputConnection, InputType, UploadAppInput } from '../../inputType'
import ToggleButtonGroup from '$lib/components/common/toggleButton-v2/ToggleButtonGroup.svelte'
import ToggleButton from '$lib/components/common/toggleButton-v2/ToggleButton.svelte'
import { Pen, Plug2, Upload, User } from 'lucide-svelte'
import { FunctionSquare, Pen, Plug2, Upload, User } from 'lucide-svelte'
import { fieldTypeToTsType } from '../../utils'
export let id: string
@@ -82,7 +82,7 @@
</div>
<div class={classNames('flex gap-x-2 gap-y-1 flex-wrap justify-end items-center')}>
{#if !onlyStatic && componentInput?.type && componentInput.type != 'eval'}
{#if !onlyStatic && componentInput?.type}
<ToggleButtonGroup
class="h-7"
bind:selected={componentInput.type}
@@ -94,6 +94,12 @@
hoveredComponent: undefined,
onConnect: applyConnection
}
} else if (
e.detail == 'eval' &&
componentInput['value'] != undefined &&
(componentInput['expr'] == '' || componentInput['expr'] == undefined)
) {
componentInput['expr'] = JSON.stringify(componentInput['value'])
}
}}
>
@@ -105,6 +111,7 @@
<ToggleButton value="upload" icon={Upload} iconOnly tooltip="Upload" />
{/if}
<ToggleButton value="connected" icon={Plug2} iconOnly tooltip="Connect" />
<ToggleButton value="eval" icon={FunctionSquare} iconOnly tooltip="Eval" />
</ToggleButtonGroup>
{/if}
</div>
@@ -115,7 +122,7 @@
{:else if componentInput?.type === 'row'}
<RowInputEditor bind:componentInput />
{:else if componentInput?.type === 'static'}
<div class={onlyStatic ? 'w-2/3 flex justify-end' : 'w-full'}>
<div class={onlyStatic ? 'w-2/3 flex justify-end' : 'w-full flex flex-row-reverse'}>
<StaticInputEditor
{fieldType}
{subFieldType}
@@ -19,7 +19,7 @@
</script>
{#if componentInput?.type === 'eval'}
<div class="border border-gray-300 ">
<div class="border border-gray-300">
<SimpleEditor
lang="javascript"
bind:code={componentInput.expr}
@@ -10,6 +10,7 @@
import TabSelectInput from './TabSelectInput.svelte'
import { DollarSign } from 'lucide-svelte'
import Popover from '$lib/components/Popover.svelte'
import Toggle from '$lib/components/Toggle.svelte'
export let componentInput: StaticInput<any> | undefined
export let fieldType: InputType | undefined = undefined
@@ -34,7 +35,7 @@
{:else if fieldType === 'date'}
<input on:keydown|stopPropagation type="date" bind:value={componentInput.value} />
{:else if fieldType === 'boolean'}
<input type="checkbox" class="!w-4 !h-4 !rounded-sm" bind:checked={componentInput.value} />
<Toggle bind:checked={componentInput.value} size="xs" />
{:else if fieldType === 'select' && selectOptions}
<select on:keydown|stopPropagation on:keydown|stopPropagation bind:value={componentInput.value}>
{#each selectOptions ?? [] as option}