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 33a1656cb..02fd7729a 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 33b2508ad..96c27380b 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 630316ff8..74ec5e5ac 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 6b65a7b13..bd022e32d 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 0e5339b32..6165226bd 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 d6cc99f24..ab2c56c33 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 7d06bcd8c..10ed625b9 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 fdf0f07eb..7843f03fc 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 744b0a5fb..39849b724 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 c65bc05aa..5fb555b5b 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;