django-jsonform icon indicating copy to clipboard operation
django-jsonform copied to clipboard

Title is not populated for `oneOf` when referenced through `$ref`

Open sshishov opened this issue 1 year ago • 2 comments

In the processing of oneOf options we rely that the title should be inside the components, but sometimes the oneOf is the array of just references, therefore title can be unavailable there.

We can replace the current implementation

    getOptions = () => {
        return this.props.args.schema[this.schemaName].map((option, index) => {
            return {label: option.title || 'Option ' + (index + 1), value: index};
        });
    }

with this one

    getOptions = () => {
        return Array.from(this.props.args.schema[this.schemaName].keys(), (index) => ({label: this.getSchema(index).title || 'Option ' + (index + 1), value: index}));
    }

or similar. The main point - we should receive the full schema first to make sure that we properly retrieve options.

I would recommend to store the schemas of objects in the internal state of the Container (same list with index acces). In this case we should not retrieve and parse it every time.

Example of the broken schema
{
    "$defs": {
        "ChoiceModel": {
            "additionalProperties": false,
            "properties": {
                "value": {
                    "title": "Value",
                    "type": "string"
                },
                "label": {
                    "title": "Label",
                    "type": "string"
                },
            },
            "required": [
                "label"
            ],
            "title": "ChoiceModel",
            "type": "object"
        },
        "CustomFieldNumberMetadataModel": {
            "additionalProperties": false,
            "properties": {},
            "title": "Metadata",
            "type": "object"
        },
        "CustomFieldNumberModel": {
            "additionalProperties": false,
            "properties": {
                "field_type": {
                    "const": "NUMBER",
                    "title": "Field Type"
                },
                "metadata": {
                    "$ref": "#/$defs/CustomFieldNumberMetadataModel"
                }
            },
            "required": [
                "field_type"
            ],
            "title": "Number",
            "type": "object"
        },
        "CustomFieldSelectMetadataModel": {
            "additionalProperties": false,
            "properties": {
                "choices": {
                    "items": {
                        "$ref": "#/$defs/ChoiceModel"
                    },
                    "title": "Choices",
                    "type": "array"
                }
            },
            "required": [
                "choices"
            ],
            "title": "Metadata",
            "type": "object"
        },
        "CustomFieldSelectModel": {
            "additionalProperties": false,
            "properties": {
                "field_type": {
                    "const": "SELECT",
                    "title": "Field Type"
                },
                "metadata": {
                    "$ref": "#/$defs/CustomFieldSelectMetadataModel"
                }
            },
            "required": [
                "field_type",
                "metadata"
            ],
            "title": "Select",
            "type": "object"
        },
        "CustomFieldTextMetadataModel": {
            "additionalProperties": false,
            "properties": {},
            "title": "Metadata",
            "type": "object"
        },
        "CustomFieldTextModel": {
            "additionalProperties": false,
            "properties": {
                "field_type": {
                    "const": "TEXT",
                    "title": "Field Type"
                },
                "metadata": {
                    "$ref": "#/$defs/CustomFieldTextMetadataModel"
                }
            },
            "required": [
                "field_type"
            ],
            "title": "Text",
            "type": "object"
        }
    },
    "discriminator": {
        "mapping": {
            "NUMBER": "#/$defs/CustomFieldNumberModel",
            "SELECT": "#/$defs/CustomFieldSelectModel",
            "TEXT": "#/$defs/CustomFieldTextModel"
        },
        "propertyName": "field_type"
    },
    "final": true,
    "oneOf": [
        {
            "$ref": "#/$defs/CustomFieldSelectModel"
        },
        {
            "$ref": "#/$defs/CustomFieldNumberModel"
        },
        {
            "$ref": "#/$defs/CustomFieldTextModel"
        }
    ],
    "title": "Discriminator"
}
Actual and Expected screenshots on playground

Screenshot 2024-03-28 at 00 04 13Screenshot 2024-03-28 at 00 04 27

NOTE: tested locally, working like a charm.

sshishov avatar Mar 27 '24 20:03 sshishov

Thanks for taking the time to go through the source code and providing a fix.

I'll ship it in the next release.

bhch avatar Mar 28 '24 02:03 bhch

Hi @sshishov, would you like to contribute and open a Pull Request at bhch/react-json-form?

If not, it's still okay and I can make these changes myself. Let me know.

Thanks again.

bhch avatar Apr 01 '24 06:04 bhch

Any Update? I'd really appreciate this enhancment

abe-101 avatar May 15 '24 16:05 abe-101

@abe-101 and @bhch thanks for taking care, guys! Lately was slightly busy and missed this opportunity!

Change looks good, I guess. Need to test more myself to make sure that all cases are covered...

sshishov avatar Jul 07 '24 11:07 sshishov

Released in v2.23.0.

bhch avatar Sep 20 '24 15:09 bhch

Thanks!

abe-101 avatar Sep 25 '24 20:09 abe-101