Custom renderer for oneOf - inside array items [react]

I have:

const schema = {
  type: "object",
  title: "Auth.js Settings",
  properties: {
    providers: {
      type: "array",
      title: "Providers",
      items: {
        type: "object",
        oneOf: [
          {
            properties: {
              type: { const: "google" },
              clientId: { type: "string" },
              clientSecret: { type: "string" },
            },
            required: ["type", "clientId", "clientSecret"],
            additionalProperties: false,
          },
          {
            properties: {
              type: { const: "github" },
              clientId: { type: "string" },
              clientSecret: { type: "string" },
            },
            required: ["type", "clientId", "clientSecret"],
            additionalProperties: false,
          },
          {
            properties: {
              type: { const: "credentials" },
              authorize: { type: "string", format: "uri" },
            },
            required: ["type", "authorize"],
            additionalProperties: false,
          },
        ],
      },
    },
  },
};

Normally oneOf, material appears as tab. But I want to show it as select instead of tabs with a custom renderer with an option. How can I write a tester for this? And how can the UI Schema be?

const uiSchema = {
  type: "VerticalLayout",
  elements: [
    {
      type: "Control",
      scope: "#/properties/providers",
      options: { format: "select" },
    },
  ],
};

I did it this way but the format option here is valid for array. I can’t get this option in tester. Is there a ui schema for Items? Are there any examples?

After much effort:

export const uiSchema = {
  type: "VerticalLayout",
  elements: [
    {
      type: "Control",
      scope: "#/properties/providers",
      options: {
        detail: {
          type: "Control",
          scope: "#",
          options: { format: "x:select" },
        },
      },
    },
  ],
};

and the tester:

export const selectOneOfControlTester: RankedTester = rankWith(
  4,
  and(isOneOfControl, optionIs("format", "x:select"))
);

but there is still a problem. const values are not included in the data. I think this is because of createDefaultValue and extractDefaults.

Hi @cihad ,
Looking at the code of createDefaultValue and extractDefaults, I think you could get the const values to be initialized by also defining their value via a default property. See here in the code: https://github.com/eclipsesource/jsonforms/blob/fcef896c8927269d3f3ed609a7255651085b193d/packages/core/src/mappers/renderer.ts#L174-L176

ALthough this might not strictly be necessary, I think it makes sense to specify the type also for the const properties because JSON Forms uses the type property quite often.

For instance, do something like this:

type: { const: "github", "default": "github", "type": "string" },

Arguably it could make sense to extend createDefaultValue to set the const value automatically. If you like you can open an issue for that.

Best regards,
Lucas

I will open an issue for that. I’m not sure if it should be a feature request or a bug report.

Personally I would prefer to not do that. If we always generate const values, we remove the option to not generate them.

I don’t see a strong reason to treat const values as a special case here. If they should be auto-generated, a default should be specified just like with all other values.

1 Like

That makes sense. I haven’t considered that but I agree that it is beneficial to leave the option open to not generate these const values.

It seems strange that values like "" for string, 0 for number, false for boolean, null for null, etc., which are not given a default value, are generated, but const, which has a stronger expression than these (because it indicates exactly what it should be), is not given a default value.

Can you give an example of what are the negative situations that this would cause?

Actually, I think what I want to talk about and what @sdirix is talking about are different things. Mine is about oneOf tab transitions and filling new values in oneOf controller component with createDefaultValue. I am sure @sdrix is talking about another situation. This function is already used in 3 places:

1st when adding a new item to the array,
2nd in oneOf tab transitions,
3rd in anyOf tab transitions if the data types are different.

@cihad, you’re right I was mainly thinking about use case 1 (adding new item to array) in the object case in which we check the default of all properties.

I agree, in case we’re not in the object case and need to create a value from somewhere, then there is no reason to not be a bit smarter and use the const if the property has it.

So I’m fine with adding that logic to the createDefaultValue here :+1:

1 Like