diff --git a/backend/parsers/windmill-parser-ts/src/lib.rs b/backend/parsers/windmill-parser-ts/src/lib.rs index 1ef525599a..8cdd5ac45e 100644 --- a/backend/parsers/windmill-parser-ts/src/lib.rs +++ b/backend/parsers/windmill-parser-ts/src/lib.rs @@ -11,7 +11,7 @@ use regex::Regex; use serde_json::Value; use std::collections::HashSet; use swc_ecma_visit::{noop_visit_type, Visit, VisitWith}; -use windmill_parser::{json_to_typ, Arg, MainArgSignature, ObjectProperty, Typ}; +use windmill_parser::{json_to_typ, Arg, MainArgSignature, ObjectProperty, OneOfVariant, Typ}; use swc_common::{sync::Lrc, FileName, SourceMap, SourceMapper, Span, Spanned}; use swc_ecma_ast::{ @@ -401,6 +401,79 @@ fn tstype_to_typ(ts_type: &TsType) -> (Typ, bool) { }; (tstype_to_typ(&types[other_p]).0, true) } else { + if types.len() > 1 { + let one_of_values: Vec = types + .into_iter() + .map_while(|x| match &**x { + TsType::TsTypeLit(TsTypeLit { members, .. }) => { + let label = members + .iter() + .find_map(|y| match y { + TsTypeElement::TsPropertySignature( + TsPropertySignature { key, type_ann, .. }, + ) => match (&**key, type_ann) { + (Expr::Ident(Ident { sym, .. }), type_ann) => { + if sym.to_string() == "label" { + type_ann.as_ref().map(|z| match &*z.type_ann { + TsType::TsLitType(TsLitType { + lit: TsLit::Str(Str { value, .. }), + .. + }) => Some(value.to_string()), + _ => None, + }) + } else { + None + } + } + _ => None, + }, + _ => None, + }) + .flatten(); + + match label { + Some(label) => { + let properties: Vec = members + .into_iter() + .filter_map(|x| match x { + TsTypeElement::TsPropertySignature( + TsPropertySignature { key, type_ann, .. }, + ) => match (*key.to_owned(), type_ann) { + (Expr::Ident(Ident { sym, .. }), type_ann) => { + Some(ObjectProperty { + key: sym.to_string(), + typ: type_ann + .as_ref() + .map(|typ| { + Box::new( + tstype_to_typ( + &*typ.type_ann, + ) + .0, + ) + }) + .unwrap_or(Box::new(Typ::Unknown)), + }) + } + _ => None, + }, + _ => None, + }) + .collect(); + Some(OneOfVariant { label, properties }) + } + _ => None, + } + } + _ => None, + }) + .collect(); + + if one_of_values.len() == types.len() { + return (Typ::OneOf(one_of_values), false); + } + } + let literals = types .into_iter() .filter(|x| match ***x { diff --git a/backend/parsers/windmill-parser-wasm/pkg/package.json b/backend/parsers/windmill-parser-wasm/pkg/package.json index a4306c79cf..c5737ed914 100644 --- a/backend/parsers/windmill-parser-wasm/pkg/package.json +++ b/backend/parsers/windmill-parser-wasm/pkg/package.json @@ -3,7 +3,7 @@ "collaborators": [ "Ruben Fiszel " ], - "version": "1.335.0", + "version": "1.345.2", "files": [ "windmill_parser_wasm_bg.wasm", "windmill_parser_wasm.js", diff --git a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.js b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.js index 3cd9d90260..f33f2c15d0 100644 --- a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.js +++ b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.js @@ -97,6 +97,15 @@ function getInt32Memory0() { return cachedInt32Memory0; } +let cachedFloat64Memory0 = null; + +function getFloat64Memory0() { + if (cachedFloat64Memory0 === null || cachedFloat64Memory0.byteLength === 0) { + cachedFloat64Memory0 = new Float64Array(wasm.memory.buffer); + } + return cachedFloat64Memory0; +} + function addHeapObject(obj) { if (heap_next === heap.length) heap.push(heap.length + 1); const idx = heap_next; @@ -115,15 +124,6 @@ function getStringFromWasm0(ptr, len) { return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); } -let cachedFloat64Memory0 = null; - -function getFloat64Memory0() { - if (cachedFloat64Memory0 === null || cachedFloat64Memory0.byteLength === 0) { - cachedFloat64Memory0 = new Float64Array(wasm.memory.buffer); - } - return cachedFloat64Memory0; -} - let cachedBigInt64Memory0 = null; function getBigInt64Memory0() { @@ -584,6 +584,10 @@ async function __wbg_load(module, imports) { function __wbg_get_imports() { const imports = {}; imports.wbg = {}; + imports.wbg.__wbg_eval_75d97e58e74fc19b = function(arg0, arg1) { + const ret = eval(getStringFromWasm0(arg0, arg1)); + return addHeapObject(ret); + }; imports.wbg.__wbindgen_object_drop_ref = function(arg0) { takeObject(arg0); }; @@ -604,22 +608,6 @@ function __wbg_get_imports() { const ret = typeof(getObject(arg0)) === 'bigint'; return ret; }; - imports.wbg.__wbindgen_bigint_from_i64 = function(arg0) { - const ret = arg0; - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_jsval_eq = function(arg0, arg1) { - const ret = getObject(arg0) === getObject(arg1); - return ret; - }; - imports.wbg.__wbindgen_bigint_from_u64 = function(arg0) { - const ret = BigInt.asUintN(64, arg0); - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_error_new = function(arg0, arg1) { - const ret = new Error(getStringFromWasm0(arg0, arg1)); - return addHeapObject(ret); - }; imports.wbg.__wbindgen_number_get = function(arg0, arg1) { const obj = getObject(arg1); const ret = typeof(obj) === 'number' ? obj : undefined; @@ -635,8 +623,20 @@ function __wbg_get_imports() { const ret = getObject(arg0) in getObject(arg1); return ret; }; - imports.wbg.__wbg_eval_4ecb84501b3abc94 = function(arg0, arg1) { - const ret = eval(getStringFromWasm0(arg0, arg1)); + imports.wbg.__wbindgen_bigint_from_i64 = function(arg0) { + const ret = arg0; + return addHeapObject(ret); + }; + imports.wbg.__wbindgen_jsval_eq = function(arg0, arg1) { + const ret = getObject(arg0) === getObject(arg1); + return ret; + }; + imports.wbg.__wbindgen_bigint_from_u64 = function(arg0) { + const ret = BigInt.asUintN(64, arg0); + return addHeapObject(ret); + }; + imports.wbg.__wbindgen_error_new = function(arg0, arg1) { + const ret = new Error(getStringFromWasm0(arg0, arg1)); return addHeapObject(ret); }; imports.wbg.__wbindgen_jsval_loose_eq = function(arg0, arg1) { diff --git a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm index 9fa475d73b..f4e0fef1a5 100644 Binary files a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm and b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm differ diff --git a/backend/parsers/windmill-parser/src/lib.rs b/backend/parsers/windmill-parser/src/lib.rs index 98edfef3c6..71e41b24f7 100644 --- a/backend/parsers/windmill-parser/src/lib.rs +++ b/backend/parsers/windmill-parser/src/lib.rs @@ -24,6 +24,13 @@ pub struct ObjectProperty { pub typ: Box, } +#[derive(Serialize, Clone, Debug, PartialEq)] +#[serde(rename_all(serialize = "lowercase"))] +pub struct OneOfVariant { + pub label: String, + pub properties: Vec, +} + #[derive(Serialize, Clone, Debug, PartialEq)] #[serde(rename_all(serialize = "lowercase"))] pub enum Typ { @@ -38,6 +45,7 @@ pub enum Typ { Email, Sql, Object(Vec), + OneOf(Vec), Unknown, } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index cae113590f..2242aa9c03 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -52,7 +52,7 @@ "vscode-languageclient": "~9.0.1", "vscode-uri": "~3.0.8", "vscode-ws-jsonrpc": "~3.1.0", - "windmill-parser-wasm": "^1.335.0", + "windmill-parser-wasm": "^1.345.2", "windmill-sql-datatype-parser-wasm": "^1.318.0", "y-monaco": "^0.1.4", "y-websocket": "^1.5.0", @@ -10261,9 +10261,9 @@ } }, "node_modules/windmill-parser-wasm": { - "version": "1.335.0", - "resolved": "https://registry.npmjs.org/windmill-parser-wasm/-/windmill-parser-wasm-1.335.0.tgz", - "integrity": "sha512-a6UzDKRt1InP0FgZHZ/ZhkoEI+AgCXirZ4yq9hTgL4o9PGRId9pl8Nk18R3CEJ9XaCd1LX6+GbRppnBtThyrvA==" + "version": "1.345.2", + "resolved": "https://registry.npmjs.org/windmill-parser-wasm/-/windmill-parser-wasm-1.345.2.tgz", + "integrity": "sha512-JTAx5zOZgJG/anZ+YZAD7MtWKcr29don0SOrsAHRUenmAtysUqxFYx1dHXJIilU0SxaSeeGblaTTiPHypAIJVw==" }, "node_modules/windmill-sql-datatype-parser-wasm": { "version": "1.318.0", diff --git a/frontend/package.json b/frontend/package.json index ebad69874f..ed0aab4e0c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -95,6 +95,7 @@ "@popperjs/core": "^2.11.6", "@redocly/json-to-json-schema": "^0.0.1", "@tanstack/svelte-table": "^8.9.9", + "@windmill-labs/svelte-dnd-action": "latest", "ag-charts-community": "^9.0.1", "ag-charts-enterprise": "^9.0.1", "ag-grid-community": "^31.0.0", @@ -122,7 +123,6 @@ "quill": "^1.3.7", "svelte-carousel": "^1.0.25", "svelte-chartjs": "^3.1.5", - "@windmill-labs/svelte-dnd-action": "latest", "svelte-exmarkdown": "^3.0.3", "svelte-infinite-loading": "^1.3.8", "svelte-portal": "^2.2.1", @@ -132,7 +132,7 @@ "vscode-languageclient": "~9.0.1", "vscode-uri": "~3.0.8", "vscode-ws-jsonrpc": "~3.1.0", - "windmill-parser-wasm": "^1.335.0", + "windmill-parser-wasm": "^1.345.2", "windmill-sql-datatype-parser-wasm": "^1.318.0", "y-monaco": "^0.1.4", "y-websocket": "^1.5.0", diff --git a/frontend/src/lib/common.ts b/frontend/src/lib/common.ts index 0daa000b50..7540b4aec5 100644 --- a/frontend/src/lib/common.ts +++ b/frontend/src/lib/common.ts @@ -43,6 +43,7 @@ export interface SchemaProperty { dateFormat?: string title?: string placeholder?: string + oneOf?: SchemaProperty[] } export interface ModalSchemaProperty { @@ -69,6 +70,7 @@ export interface ModalSchemaProperty { dateFormat?: string title?: string placeholder?: string + oneOf?: SchemaProperty[] } export function modalToSchema(schema: ModalSchemaProperty): SchemaProperty { @@ -94,7 +96,8 @@ export function modalToSchema(schema: ModalSchemaProperty): SchemaProperty { nullable: schema.nullable, dateFormat: schema.dateFormat, title: schema.title, - placeholder: schema.placeholder + placeholder: schema.placeholder, + oneOf: schema.oneOf } } export type Schema = { diff --git a/frontend/src/lib/components/ArgInput.svelte b/frontend/src/lib/components/ArgInput.svelte index e06c62355e..27e55312fb 100644 --- a/frontend/src/lib/components/ArgInput.svelte +++ b/frontend/src/lib/components/ArgInput.svelte @@ -25,6 +25,8 @@ import autosize from '$lib/autosize' import PasswordArgInput from './PasswordArgInput.svelte' import Password from './Password.svelte' + import ToggleButtonGroup from './common/toggleButton-v2/ToggleButtonGroup.svelte' + import ToggleButton from './common/toggleButton-v2/ToggleButton.svelte' import SchemaFormDnd from './schema/SchemaFormDND.svelte' import SchemaForm from './SchemaForm.svelte' @@ -36,6 +38,7 @@ export let format: string = '' export let contentEncoding: 'base64' | 'binary' | undefined = undefined export let type: string | undefined = undefined + export let oneOf: SchemaProperty[] | undefined = undefined export let required = false export let pattern: undefined | string = undefined export let valid = true @@ -75,6 +78,20 @@ export let editor: SimpleEditor | undefined = undefined export let orderEditable = false + let oneOfSelected: string | undefined = undefined + function updateOneOfSelected(oneOf: SchemaProperty[] | undefined) { + if (oneOf && oneOf.length >= 2 && !oneOfSelected) { + oneOfSelected = oneOf[0]['title'] + } + } + $: updateOneOfSelected(oneOf) + function updateOneOfSelectedValue(oneOfSelected: string | undefined) { + if (oneOfSelected) { + value = { label: oneOfSelected } + } + } + $: updateOneOfSelectedValue(oneOfSelected) + const dispatch = createEventDispatcher() let ignoreValueUndefined = false @@ -480,7 +497,96 @@ {/if} {:else if inputCat == 'object' || inputCat == 'resource-object' || isListJson} - {#if properties && Object.keys(properties).length > 0} + {#if oneOf && oneOf.length >= 2} +
+ {#if oneOf && oneOf.length >= 2} + + {#each oneOf as obj} + + {/each} + + + {#if oneOfSelected} + {@const objIdx = oneOf.findIndex((o) => o.title === oneOfSelected)} + {@const obj = oneOf[objIdx]} + {#if obj && obj.properties && Object.keys(obj.properties).length > 0} +
+ {#if orderEditable} + k !== 'label') + ), + order: obj.order?.filter((k) => k !== 'label') ?? undefined, + $schema: '', + required: obj.required ?? [], + type: 'object' + }} + args={value} + dndType={`nested-${title}`} + on:reorder={(e) => { + if (oneOf && oneOf[objIdx]) { + const keys = e.detail + oneOf[objIdx].order = keys + } + }} + on:change + /> + {:else} + k !== 'label') + ), + order: obj.order?.filter((k) => k !== 'label') ?? undefined, + $schema: '', + required: obj.required ?? [], + type: 'object' + }} + bind:args={value} + /> + {/if} +
+ {:else if disabled} +