fix(schema): preserve user-defined JSON schema for Python list[dict] parameters (#7496)
* fix(schema): preserve user-defined JSON schema for Python list[dict] Fixes issue where JSON schema properties manually defined in the UI are lost when saving Python scripts with list[dict] or untyped array parameters. Changes: - Preserve all items fields (properties, required, additionalProperties, etc.) - Preserve items.type instead of hardcoding "object" - Preserve type for untyped parameters using nullish coalescing - Add type safety check for items preservation The Python parser cannot infer object properties from list[dict] annotations. This fix preserves user-defined schema fields when parser cannot infer structure. Fixes #7209 * fix(schema): preserve all fields for untyped lists, not just properties Address bot feedback for consistency. The untyped list branch now preserves all user-defined fields (required, additionalProperties, enum, etc.) just like the record[] branch, instead of only preserving properties. This ensures users who define required fields or enum values for untyped list parameters don't lose that data on save. Related to #7209 * nits and publish --------- Co-authored-by: Devdatta Talele <devtalele0@gmail.com>
This commit is contained in:
3
cli/.gitignore
vendored
3
cli/.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
npm/
|
||||
gen/
|
||||
node_modules/
|
||||
node_modules/
|
||||
windmill-utils-internal/.npmrc
|
||||
4
cli/windmill-utils-internal/package-lock.json
generated
4
cli/windmill-utils-internal/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "windmill-utils-internal",
|
||||
"version": "1.3.0",
|
||||
"version": "1.3.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "windmill-utils-internal",
|
||||
"version": "1.3.0",
|
||||
"version": "1.3.2",
|
||||
"license": "Apache 2.0",
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.2.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "windmill-utils-internal",
|
||||
"version": "1.3.1",
|
||||
"version": "1.3.2",
|
||||
"description": "Internal utility functions for Windmill",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
@@ -21,4 +21,4 @@
|
||||
"files": [
|
||||
"dist/**/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
/**
|
||||
* Type alias for enum values - can be an array of strings or undefined
|
||||
*/
|
||||
export type EnumType = string[] | { label: string; value: string }[] | undefined;
|
||||
export type EnumType =
|
||||
| string[]
|
||||
| { label: string; value: string }[]
|
||||
| undefined;
|
||||
|
||||
/**
|
||||
* Represents a property in a JSON schema with various validation and display options
|
||||
@@ -40,6 +43,16 @@ export interface SchemaProperty {
|
||||
originalType?: string;
|
||||
}
|
||||
|
||||
const ITEMS_PRESERVED_FIELDS = [
|
||||
"properties",
|
||||
"required",
|
||||
"additionalProperties",
|
||||
"enum",
|
||||
"resourceType",
|
||||
"contentEncoding",
|
||||
"description",
|
||||
] as (keyof SchemaProperty["items"])[];
|
||||
|
||||
/**
|
||||
* Converts argument signature types to JSON schema properties.
|
||||
* This function handles various Windmill-specific types and converts them
|
||||
@@ -54,22 +67,22 @@ export function argSigToJsonSchemaType(
|
||||
| string
|
||||
| { resource: string | null }
|
||||
| {
|
||||
list:
|
||||
| (string | { name?: string; props?: { key: string; typ: any }[] })
|
||||
| { str: any }
|
||||
| { object: { name?: string; props?: { key: string; typ: any }[] } }
|
||||
| null;
|
||||
}
|
||||
list:
|
||||
| (string | { name?: string; props?: { key: string; typ: any }[] })
|
||||
| { str: any }
|
||||
| { object: { name?: string; props?: { key: string; typ: any }[] } }
|
||||
| null;
|
||||
}
|
||||
| { dynselect: string }
|
||||
| { dynmultiselect: string }
|
||||
| { str: string[] | null }
|
||||
| { object: { name?: string; props?: { key: string; typ: any }[] } }
|
||||
| {
|
||||
oneof: {
|
||||
label: string;
|
||||
properties: { key: string; typ: any }[];
|
||||
}[];
|
||||
},
|
||||
oneof: {
|
||||
label: string;
|
||||
properties: { key: string; typ: any }[];
|
||||
}[];
|
||||
},
|
||||
oldS: SchemaProperty
|
||||
): void {
|
||||
const newS: SchemaProperty = { type: "" };
|
||||
@@ -206,15 +219,34 @@ export function argSigToJsonSchemaType(
|
||||
}
|
||||
newS.items = { type: "object", properties: properties };
|
||||
} else {
|
||||
newS.items = { type: "object" };
|
||||
// Preserve ALL user-defined fields when parser cannot infer structure
|
||||
newS.items = { type: oldS.items?.type || "object" };
|
||||
|
||||
if (oldS.items && typeof oldS.items === "object") {
|
||||
ITEMS_PRESERVED_FIELDS.forEach((field) => {
|
||||
if (oldS.items && oldS.items[field] !== undefined) {
|
||||
newS.items![field] = oldS.items[field];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
newS.originalType = "record[]";
|
||||
} else {
|
||||
newS.items = { type: "object" };
|
||||
// Preserve ALL user-defined fields for untyped lists (same as record[] branch)
|
||||
newS.items = { type: oldS.items?.type || "object" };
|
||||
|
||||
if (oldS.items && typeof oldS.items === "object") {
|
||||
ITEMS_PRESERVED_FIELDS.forEach((field) => {
|
||||
if (oldS.items && oldS.items[field] !== undefined) {
|
||||
newS.items![field] = oldS.items[field];
|
||||
}
|
||||
});
|
||||
}
|
||||
newS.originalType = "object[]";
|
||||
}
|
||||
} else {
|
||||
newS.type = "object";
|
||||
// Preserve existing type when inference fails, default to "object" for undefined/null
|
||||
newS.type = oldS.type ?? "object";
|
||||
}
|
||||
|
||||
const preservedFields = [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "commonjs",
|
||||
"module": "ES2022",
|
||||
"lib": ["ES2022"],
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
@@ -11,7 +11,7 @@
|
||||
"noUnusedParameters": false,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"moduleResolution": "node",
|
||||
"moduleResolution": "bundler",
|
||||
"baseUrl": "./",
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
@@ -19,11 +19,6 @@
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
|
||||
8
frontend/package-lock.json
generated
8
frontend/package-lock.json
generated
@@ -86,7 +86,7 @@
|
||||
"windmill-parser-wasm-ts": "1.593.0",
|
||||
"windmill-parser-wasm-yaml": "1.593.0",
|
||||
"windmill-sql-datatype-parser-wasm": "1.512.0",
|
||||
"windmill-utils-internal": "^1.3.1",
|
||||
"windmill-utils-internal": "^1.3.2",
|
||||
"xterm": "^5.3.0",
|
||||
"xterm-readline": "^1.1.2",
|
||||
"y-monaco": "^0.1.4",
|
||||
@@ -15893,9 +15893,9 @@
|
||||
"integrity": "sha512-uHNL8F72/Tf96xF3hOHnPDjkEyqXw7fNjcPJiUhth9sTQkcwUIoJMOdwm8/cs+j9kKVRJ4tgNYMHEBLylazp6g=="
|
||||
},
|
||||
"node_modules/windmill-utils-internal": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/windmill-utils-internal/-/windmill-utils-internal-1.3.1.tgz",
|
||||
"integrity": "sha512-afRGUDcvaUfGu7FA6DD0xWECQiKnXADs0N4WyQQ+OvaloxZ4oQzdEpLnVab/m3T02hhs29ru4Ilrdxu3ozyT5Q==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/windmill-utils-internal/-/windmill-utils-internal-1.3.2.tgz",
|
||||
"integrity": "sha512-sLE7sfmN3vBwPReqKorBrusnn83Qnm8vVFqh/7+kz8mf98ojMVDMgBginjlh9KBtVfWu9NhyjGS+WXRcnWalzA==",
|
||||
"license": "Apache 2.0"
|
||||
},
|
||||
"node_modules/word-wrap": {
|
||||
|
||||
@@ -158,7 +158,7 @@
|
||||
"windmill-parser-wasm-ts": "1.593.0",
|
||||
"windmill-parser-wasm-yaml": "1.593.0",
|
||||
"windmill-sql-datatype-parser-wasm": "1.512.0",
|
||||
"windmill-utils-internal": "^1.3.1",
|
||||
"windmill-utils-internal": "^1.3.2",
|
||||
"xterm": "^5.3.0",
|
||||
"xterm-readline": "^1.1.2",
|
||||
"y-monaco": "^0.1.4",
|
||||
|
||||
Reference in New Issue
Block a user