From 0f1fc788472b1a2f9fde7d6f9b64d9a84f25af64 Mon Sep 17 00:00:00 2001 From: Lukas Boll Date: Fri, 27 Oct 2023 19:33:52 +0200 Subject: [PATCH] fix: Resolve references for generated UI schemas Previously, UI schemas generated by JsonForms were incomplete in many instances because not all references were resolved. This commit addresses the issue by providing the root schema to all usages of the Generate.uischema function, ensuring the resolution of all references. Closes #2187 --- .../src/other/object.renderer.ts | 7 +++++- packages/core/src/reducers/reducers.ts | 2 +- .../src/complex/CombinatorProperties.tsx | 7 ++++-- .../src/complex/MaterialAnyOfRenderer.tsx | 1 + .../src/complex/MaterialObjectRenderer.tsx | 7 ++++-- .../src/complex/MaterialOneOfRenderer.tsx | 1 + packages/react/src/JsonForms.tsx | 4 +++- .../src/complex/ObjectRenderer.vue | 7 +++++- .../components/CombinatorProperties.vue | 9 +++++++- packages/vue/src/components/JsonForms.vue | 23 +++++++++++++++---- 10 files changed, 55 insertions(+), 13 deletions(-) diff --git a/packages/angular-material/src/other/object.renderer.ts b/packages/angular-material/src/other/object.renderer.ts index 33a1656cbb..02fd7729af 100644 --- a/packages/angular-material/src/other/object.renderer.ts +++ b/packages/angular-material/src/other/object.renderer.ts @@ -73,7 +73,12 @@ export class ObjectControlRenderer extends JsonFormsControlWithDetail { delete newSchema.oneOf; delete newSchema.anyOf; delete newSchema.allOf; - return Generate.uiSchema(newSchema, 'Group'); + return Generate.uiSchema( + newSchema, + 'Group', + undefined, + this.rootSchema + ); }, props.uischema, props.rootSchema diff --git a/packages/core/src/reducers/reducers.ts b/packages/core/src/reducers/reducers.ts index 33b2508ad5..96c27380b5 100644 --- a/packages/core/src/reducers/reducers.ts +++ b/packages/core/src/reducers/reducers.ts @@ -77,7 +77,7 @@ export const findUISchema = ( return fallback(); } // force generation of uischema - return Generate.uiSchema(schema, fallback); + return Generate.uiSchema(schema, fallback, undefined, rootSchema); } } else if (typeof control.options.detail === 'object') { // check if detail is a valid uischema diff --git a/packages/material-renderers/src/complex/CombinatorProperties.tsx b/packages/material-renderers/src/complex/CombinatorProperties.tsx index 630316ff84..74ec5e5aca 100644 --- a/packages/material-renderers/src/complex/CombinatorProperties.tsx +++ b/packages/material-renderers/src/complex/CombinatorProperties.tsx @@ -36,6 +36,7 @@ interface CombinatorPropertiesProps { schema: JsonSchema; combinatorKeyword: 'oneOf' | 'anyOf'; path: string; + rootSchema: JsonSchema; } export class CombinatorProperties extends React.Component< @@ -45,7 +46,7 @@ export class CombinatorProperties extends React.Component< {} > { render() { - const { schema, combinatorKeyword, path } = this.props; + const { schema, combinatorKeyword, path, rootSchema } = this.props; const otherProps: JsonSchema = omit( schema, @@ -53,7 +54,9 @@ export class CombinatorProperties extends React.Component< ) as JsonSchema; const foundUISchema: UISchemaElement = Generate.uiSchema( otherProps, - 'VerticalLayout' + 'VerticalLayout', + undefined, + rootSchema ); let isLayoutWithElements = false; if (foundUISchema !== null && isLayout(foundUISchema)) { diff --git a/packages/material-renderers/src/complex/MaterialAnyOfRenderer.tsx b/packages/material-renderers/src/complex/MaterialAnyOfRenderer.tsx index 6b65a7b13b..bd022e32db 100644 --- a/packages/material-renderers/src/complex/MaterialAnyOfRenderer.tsx +++ b/packages/material-renderers/src/complex/MaterialAnyOfRenderer.tsx @@ -104,6 +104,7 @@ export const MaterialAnyOfRenderer = ({ schema={schema} combinatorKeyword={anyOf} path={path} + rootSchema={rootSchema} /> {anyOfRenderInfos.map((anyOfRenderInfo) => ( diff --git a/packages/material-renderers/src/complex/MaterialObjectRenderer.tsx b/packages/material-renderers/src/complex/MaterialObjectRenderer.tsx index 0e5339b324..6165226bd7 100644 --- a/packages/material-renderers/src/complex/MaterialObjectRenderer.tsx +++ b/packages/material-renderers/src/complex/MaterialObjectRenderer.tsx @@ -56,8 +56,11 @@ export const MaterialObjectRenderer = ({ path, () => isEmpty(path) - ? Generate.uiSchema(schema, 'VerticalLayout') - : { ...Generate.uiSchema(schema, 'Group'), label }, + ? Generate.uiSchema(schema, 'VerticalLayout', undefined, rootSchema) + : { + ...Generate.uiSchema(schema, 'Group', undefined, rootSchema), + label, + }, uischema, rootSchema ), diff --git a/packages/material-renderers/src/complex/MaterialOneOfRenderer.tsx b/packages/material-renderers/src/complex/MaterialOneOfRenderer.tsx index d6cc99f243..ab2c56c33d 100644 --- a/packages/material-renderers/src/complex/MaterialOneOfRenderer.tsx +++ b/packages/material-renderers/src/complex/MaterialOneOfRenderer.tsx @@ -106,6 +106,7 @@ export const MaterialOneOfRenderer = ({ schema={schema} combinatorKeyword={'oneOf'} path={path} + rootSchema={rootSchema} /> {oneOfRenderInfos.map((oneOfRenderInfo) => ( diff --git a/packages/react/src/JsonForms.tsx b/packages/react/src/JsonForms.tsx index 7d06bcd8c1..10ed625b99 100644 --- a/packages/react/src/JsonForms.tsx +++ b/packages/react/src/JsonForms.tsx @@ -210,7 +210,9 @@ export const JsonForms = ( ); const uischemaToUse = useMemo( () => - typeof uischema === 'object' ? uischema : Generate.uiSchema(schemaToUse), + typeof uischema === 'object' + ? uischema + : Generate.uiSchema(schemaToUse, undefined, undefined, schemaToUse), [uischema, schemaToUse] ); diff --git a/packages/vue-vanilla/src/complex/ObjectRenderer.vue b/packages/vue-vanilla/src/complex/ObjectRenderer.vue index fdf0f07eb2..7843f03fc0 100644 --- a/packages/vue-vanilla/src/complex/ObjectRenderer.vue +++ b/packages/vue-vanilla/src/complex/ObjectRenderer.vue @@ -51,7 +51,12 @@ const controlRenderer = defineComponent({ computed: { detailUiSchema(): UISchemaElement { const uiSchemaGenerator = () => { - const uiSchema = Generate.uiSchema(this.control.schema, 'Group'); + const uiSchema = Generate.uiSchema( + this.control.schema, + 'Group', + undefined, + this.control.rootSchema + ); if (isEmpty(this.control.path)) { uiSchema.type = 'VerticalLayout'; } else { diff --git a/packages/vue-vanilla/src/complex/components/CombinatorProperties.vue b/packages/vue-vanilla/src/complex/components/CombinatorProperties.vue index 744b0a5fb1..39849b724e 100644 --- a/packages/vue-vanilla/src/complex/components/CombinatorProperties.vue +++ b/packages/vue-vanilla/src/complex/components/CombinatorProperties.vue @@ -18,6 +18,7 @@ interface CombinatorProps { schema: JsonSchema; combinatorKeyword: 'oneOf' | 'anyOf' | 'allOf'; path: string; + rootSchema: JsonSchema; } export default defineComponent({ @@ -38,6 +39,10 @@ export default defineComponent({ type: String, required: true, }, + rootSchema: { + type: Object as PropType, + required: true, + }, }, setup(props: CombinatorProps) { const otherProps: JsonSchema = omit( @@ -46,7 +51,9 @@ export default defineComponent({ ) as JsonSchema; const foundUISchema: UISchemaElement = Generate.uiSchema( otherProps, - 'VerticalLayout' + 'VerticalLayout', + undefined, + props.rootSchema ); const isLayout = (uischema: UISchemaElement): uischema is Layout => diff --git a/packages/vue/src/components/JsonForms.vue b/packages/vue/src/components/JsonForms.vue index c65bc05aaa..5fb555b5bb 100644 --- a/packages/vue/src/components/JsonForms.vue +++ b/packages/vue/src/components/JsonForms.vue @@ -114,8 +114,11 @@ export default defineComponent({ data() { const dataToUse = this.data; const generatorData = isObject(dataToUse) ? dataToUse : {}; - const schemaToUse = this.schema ?? Generate.jsonSchema(generatorData); - const uischemaToUse = this.uischema ?? Generate.uiSchema(schemaToUse); + const schemaToUse: JsonSchema = + this.schema ?? Generate.jsonSchema(generatorData); + const uischemaToUse = + this.uischema ?? + Generate.uiSchema(schemaToUse, undefined, undefined, schemaToUse); const initCore = (): JsonFormsCore => { const initialCore = { data: dataToUse, @@ -177,11 +180,23 @@ export default defineComponent({ const generatorData = isObject(this.data) ? this.data : {}; this.schemaToUse = newSchema ?? Generate.jsonSchema(generatorData); if (!this.uischema) { - this.uischemaToUse = Generate.uiSchema(this.schemaToUse); + this.uischemaToUse = Generate.uiSchema( + this.schemaToUse, + undefined, + undefined, + this.schemaToUse + ); } }, uischema(newUischema) { - this.uischemaToUse = newUischema ?? Generate.uiSchema(this.schemaToUse); + this.uischemaToUse = + newUischema ?? + Generate.uiSchema( + this.schemaToUse, + undefined, + undefined, + this.schemaToUse + ); }, data(newData) { this.dataToUse = newData;