From 52db0bb2f3ed379cf910f7d06874f7bc2871faaa Mon Sep 17 00:00:00 2001 From: ewandor Date: Sun, 26 Jan 2025 15:34:29 +0100 Subject: [PATCH] Implementing union enum when mutlifields are all enums --- gui/app/src/common/crud/crud-form.tsx | 13 +++- gui/app/src/common/crud/fields/union-enum.tsx | 78 +++++++++++++++++++ .../src/common/crud/widgets/union-enum.tsx | 40 ++++++++++ 3 files changed, 128 insertions(+), 3 deletions(-) create mode 100644 gui/app/src/common/crud/fields/union-enum.tsx create mode 100644 gui/app/src/common/crud/widgets/union-enum.tsx diff --git a/gui/app/src/common/crud/crud-form.tsx b/gui/app/src/common/crud/crud-form.tsx index b38b478..3c51596 100644 --- a/gui/app/src/common/crud/crud-form.tsx +++ b/gui/app/src/common/crud/crud-form.tsx @@ -1,11 +1,11 @@ import validator from "@rjsf/validator-ajv8"; import Form from "@rjsf/mui"; -import { RegistryWidgetsType } from "@rjsf/utils"; +import {RegistryFieldsType, RegistryWidgetsType} from "@rjsf/utils"; import { useEffect, useState } from "react"; import { jsonschemaProvider } from "../../providers/jsonschema-provider"; import { useForm } from "@refinedev/core"; -//import TextWidget from "@rjsf/core/src/components/widgets/TextWidget"; import CrudTextWidget from "./widgets/crud-text-widget"; +import UnionEnumField from "./fields/union-enum"; type Props = { schemaName: string, @@ -14,7 +14,13 @@ type Props = { //onSubmit: (data: IChangeEvent, event: FormEvent) => void } -const customWidgets: RegistryWidgetsType = { TextWidget: CrudTextWidget }; +const customWidgets: RegistryWidgetsType = { + TextWidget: CrudTextWidget +}; + +const customFields: RegistryFieldsType = { + AnyOfField: UnionEnumField +} export const CrudForm: React.FC = ({schemaName, resource, id}) => { const { onFinish, query, formLoading } = useForm({ @@ -53,6 +59,7 @@ export const CrudForm: React.FC = ({schemaName, resource, id}) => { validator={validator} omitExtraData={true} widgets={customWidgets} + fields={customFields} /> ) } \ No newline at end of file diff --git a/gui/app/src/common/crud/fields/union-enum.tsx b/gui/app/src/common/crud/fields/union-enum.tsx new file mode 100644 index 0000000..d0bf698 --- /dev/null +++ b/gui/app/src/common/crud/fields/union-enum.tsx @@ -0,0 +1,78 @@ +import { ERRORS_KEY, FieldProps, getUiOptions } from "@rjsf/utils"; +import AnyOfField from "@rjsf/core/lib/components/fields/MultiSchemaField"; +import { UnionEnumWidget } from "../widgets/union-enum"; +import get from 'lodash/get'; +import isEmpty from 'lodash/isEmpty'; +import omit from 'lodash/omit'; + +const UnionEnumField = (props: FieldProps) => { + const { + name, + disabled = false, + errorSchema = {}, + formContext, + formData, + onChange, + onBlur, + onFocus, + registry, + schema, + uiSchema, + options, + idSchema, + } = props; + + const enumOptions: any[] = [] + for (let opt of options) { + if (!opt.hasOwnProperty('enum')) { + return () + } + for (let val of opt.enum) { + enumOptions.push({ + title: val, + value: val, + type: opt.title + }) + } + } + + const { globalUiOptions, schemaUtils } = registry; + const { + placeholder, + autofocus, + autocomplete, + title = schema.title, + ...uiOptions + } = getUiOptions(uiSchema, globalUiOptions); + + const rawErrors = get(errorSchema, ERRORS_KEY, []); + const fieldErrorSchema = omit(errorSchema, [ERRORS_KEY]); + const displayLabel = schemaUtils.getDisplayLabel(schema, uiSchema, globalUiOptions); + + return ( + + ); +} + +export default UnionEnumField; diff --git a/gui/app/src/common/crud/widgets/union-enum.tsx b/gui/app/src/common/crud/widgets/union-enum.tsx new file mode 100644 index 0000000..d0ef7dc --- /dev/null +++ b/gui/app/src/common/crud/widgets/union-enum.tsx @@ -0,0 +1,40 @@ +import {FieldProps, WidgetProps} from "@rjsf/utils"; +import AnyOfField from "@rjsf/core/lib/components/fields/MultiSchemaField"; +import {ListSubheader, MenuItem, Select} from "@mui/material"; +import {useState} from "react"; +import Autocomplete from "@mui/material/Autocomplete"; +import TextField from "@mui/material/TextField"; + +export const UnionEnumWidget = (props: WidgetProps) => { + const { + options, + value, + } = props; + const [selectedValue, setSelectedValue] = useState(null); + + + if (! selectedValue && value && options.enumOptions) { + for (const opt of options.enumOptions){ + if (opt.value == value) { + setSelectedValue(opt); + break; + } + } + } + + return ( + { + setSelectedValue(newValue); + props.onChange(newValue.value); + }} + options={options.enumOptions} + groupBy={(option) => option.type} + getOptionLabel={(option) => option.title} + renderInput={(params) => ( + + )} + /> + ); +}