Issue with rendering property in deeply nested json

im using the package jsonforms/vue-vanilla and i am currently trying to solve a rendering issue with my fetched schema from an api.
what im trying to do is fetch a deeply nested oneOf property called resourceKindSpec and trying to merge it with the rest of the properties:

const fetchSchema = async () => {
  try {
    const schemaKey = 'CreateResource';

    // Fetch and resolve schema
    schema.value = await SchemaService.getSchemaByKey(schemaKey);

    // Log the allOf arrays to see the structure
    console.log('allOf[1]', schema.value.allOf[1]); // Additional properties
    console.log('allOf[0]', schema.value.allOf[0]); // Base properties and oneOf schemas

    // Extract properties from both allOf[0] and allOf[1]
    const baseProperties = schema.value.allOf[0].properties || {};
    const additionalProperties = schema.value.allOf[1].properties || {};

    // Get the oneOf schemas from allOf[0]
    const oneOfSchemas = schema.value.allOf[0].oneOf || [];
    console.log('oneOfSchemas', oneOfSchemas);

    // Find the matching schema based on x-quandago-resource-kind
    const matchingSpec = oneOfSchemas.find(
      (spec) => spec.properties?.spec['x-quandago-resource-kind'] === activeResourceKind.value
    );

    if (!matchingSpec) {
      console.warn(`No matching spec found for ${activeResourceKind.value}`);
      return;
    }

    // Extract the properties of the matched spec
    const resourceKindSpec = matchingSpec.properties.spec.properties || {};
    console.log('spec to be merged:', resourceKindSpec);
    
    // Merge the base, additional, and resourceKindSpec properties
    const mergedSchema = {
      ...schema.value.allOf[1], // Additional properties from allOf[1]
      properties: {
        ...baseProperties, // Base properties from allOf[0]
        ...additionalProperties, // Additional properties from allOf[1]
        ...resourceKindSpec, // Matched spec properties
      },
    };

    console.log('Merged schema:', mergedSchema);

    // Generate the UI schema for the merged schema
    uischema.value = generateUISchema(mergedSchema);
   
    // Handle the api_version dynamically
    const handleApiVersionChange = (selectedVersion) => {
      const mapping = schema.value.allOf[0].discriminator.mapping;
      const refSchema = mapping[selectedVersion];
      const specSchemaKey = refSchema.split('/').pop();
      fetchSpecSchema(specSchemaKey);
    };

    // Listen to changes in api_version
    onMounted(() => {
      watch(() => data.value.api_version, (newValue) => {
        if (newValue) {
          handleApiVersionChange(newValue);
        }
      });
    });

    // Generate UI schema for the matching oneOf schema
    const oneOfUISchema = generateUISchema(matchingSpec);
    uischema.value.elements.push(oneOfUISchema);
    
    console.log('Final UI schema:', uischema.value);

  } catch (error) {
    console.error('Error fetching schema:', error);
  } finally {
    isLoading.value = false;
  }
};

the schema generator is as follows:

const generateUISchema = (schema) => {
  const uiElements = Object.keys(schema.properties).map((propertyKey) => {
    return {
      type: 'Control',
      scope: `#/properties/${propertyKey}`,
    };
  });

  // Add `api_version` if it's a required field and not in the properties
  if (schema.required && schema.required.includes('api_version')) {
    uiElements.unshift({
      type: 'Control',
      scope: '#/properties/api_version',
      options: {
        enum: [
          'interactions/v1',
          'sbc/v1',
          'trunk/v1',
          'transformationRules/v1',
          'inboundRoutingRule/v1',
          'outboundRoutingRule/v1',
        ],
      },
    });
  }

  // Debugging UI Elements
  console.log('Generated UI Elements:', uiElements);

  return {
    type: 'VerticalLayout',
    elements: uiElements,
  };
};

the ui schema after merging is as follows:

[
    {
        "type": "Control",
        "scope": "#/properties/display_name",
        "options": {
            "type": "text",
            "validation": {
                "minLength": 3
            }
        },
        "label": "display_name"
    },
    {
        "type": "Control",
        "scope": "#/properties/description",
        "options": {
            "type": "text",
            "validation": {
                "maxLength": 512
            }
        },
        "label": "description"
    },
    {
        "type": "Control",
        "scope": "#/properties/api_version",
        "options": {
            "type": "text"
        },
        "label": "api_version"
    },
    {
        "type": "Control",
        "scope": "#/properties/tags",
        "options": {},
        "label": "tags"
    },
    {
        "type": "Control",
        "scope": "#/properties/account_id",
        "options": {
            "type": "text"
        },
        "label": "account_id"
    },
    {
        "type": "Control",
        "scope": "#/properties/kind",
        "options": {
            "type": "text"
        },
        "label": "kind"
    },
    {
        "type": "Control",
        "scope": "#/properties/name",
        "options": {
            "type": "text",
            "validation": {
                "maxLength": 64,
                "minLength": 3,
                "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
            }
        },
        "label": "name"
    },
    {
        "type": "Control",
        "scope": "#/properties/environment",
        "options": {
            "type": "text",
            "validation": {
                "maxLength": 64,
                "minLength": 3,
                "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
            }
        },
        "label": "environment"
    },
    {
        "type": "Control",
        "scope": "#/properties/capacity",
        "options": {
            "type": "number"
        },
        "label": "capacity"
    },
    {
        "type": "Control",
        "scope": "#/properties/classic",
        "options": {
            "type": "checkbox"
        },
        "label": "classic"
    },
    {
        "type": "Control",
        "scope": "#/properties/domain",
        "options": {
            "type": "text",
            "validation": {
                "maxLength": 255,
                "minLength": 3,
                "pattern": "(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{1,63}(?<!-)\\.)+[a-zA-Z]{2,63}$)"
            }
        },
        "label": "domain"
    },
    {
        "type": "Control",
        "scope": "#/properties/tenant_guid",
        "options": {
            "type": "text",
            "validation": {
                "maxLength": 32,
                "minLength": 32,
                "pattern": "^[0-9a-f]+$"
            }
        },
        "label": "tenant_guid"
    },
    {
        "type": "Control",
        "scope": "#/properties/tenant_shortname",
        "options": {
            "type": "text",
            "validation": {
                "maxLength": 16,
                "minLength": 1,
                "pattern": "^[a-z]+$"
            }
        },
        "label": "tenant_shortname"
    }
]

somehow the labels ‘capacity’ until 'tenant_shortname' are not being rendered:

i only see this text in their place:

No applicable renderer found.
No applicable renderer found.
No applicable renderer found.
No applicable renderer found.
No applicable renderer found.

is there something wrong with how i generated the schema?

Hi @faridguzman91,

To determine what is going wrong, you need to post the full JSON Schema and UI Schema as handed over to JSON Forms. Only then it will be apparent why “No applicable renderer found” is returned.


Some things which caught my eye:

This looks like the same logic as in our default UI Schema generator. If all you want is a VerticalLayout with a control for each property, then there is no need to manage a UI Schema at all.

This seems weird. If a property is not listed in the properties, then you can’t add a UI Schema element for it. If a control points to a scope in the schema which does not exist, then “No applicable renderer” will be rendered by default. Only custom renderers could recover that.

In your UI schema generator you are returning a VerticalLayout, however you posted an array as your UI Schema. I guess that’s just a copy mistake?

  • Where are all these options coming from? In your UI Schema generator you did not have them.
  • The options listed here look like properties which should be in the JSON Schema, why are they replicated here?
  • Do you use custom renderers? The off-the-shelf renderers will ignore all these options as they don’t know them

Do the respective properties exist in the used JSON Schema?