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:
hugocasa
2026-01-07 01:42:48 +07:00
committed by GitHub
parent 6807fc6a3c
commit fecc8f2eff
7 changed files with 63 additions and 35 deletions

View File

@@ -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 = [