-
Notifications
You must be signed in to change notification settings - Fork 373
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add MultiEnum renderer for enums and oneOf #1709
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general I like it very much. However there are some things I would like to see differently.
Currently the schema tested for looks like this
"property": {
"type": "array",
"items": {
"anyOf": [
{ },
]
},
},
which doesn't really fit to the use case:
- The schema allows the same entry multiple times, but our control only handles them uniquely (the control therefore misbehaves if the same entry is there multiple times)
anyOf
stands for that at least one item matches. However we're handling it like "enums", which are unique. So it should beoneOf
.- To be consistent with our other
oneOfEnum
controls we should check whether theitems
areoneOf
and contain aconst
in each entry. - Ideally we should also be able to handle
enum
content
I would prefer to support the following schemas:
"property": {
"type": "array",
"items": {
"oneOf": [
{
"const": <any>,
"title": "mylabel"
},
{
"const": <any>,
"title": "otherLabel"
},
]
},
"uniqueItems": true
},
and
"property": {
"type": "array",
"items": {
"type": "string",
"enum": ["a", "b", "c"]
},
"uniqueItems": true
},
So we check for
- type array with unique items
- the items are either
enum
oroneOf
containingconst
Please also add an example to the example app.
) | ||
); | ||
|
||
export default MaterialEnumArrayControl; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be consistent with other controls we should default export the wrapped version
packages/material/src/index.ts
Outdated
}, | ||
{ | ||
tester: materialEnumArrayControlTester, | ||
renderer: withJsonFormsControlProps(MaterialEnumArrayControl) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't wrap here, but use the already wrapped imported version
const optionPath = Paths.compose(path, `${index}`); | ||
return ( | ||
<FormControlLabel | ||
id={option.const} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Careful: The value of const
can be anything! It doesn't need to be a string, but could for example be an object
, array
, etc. Please see mapStateToOneOfEnumProps
where we already had to handle the case.
const onChange = (option: string, value: any) => { | ||
const newData = data ? [...data] : []; | ||
if (value) { | ||
// option was added | ||
newData.push(option); | ||
} else { | ||
// option was removed | ||
const indexInData = newData.indexOf(option); | ||
newData.splice(indexInData, 1); | ||
} | ||
|
||
handleChange(path, newData); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you would use Actually that doesn't make so much sense as these functions are index based, which is not really the use case here.withJsonFormsArrayControlProps
you would get functions to add and remove items to the array for free, i.e. addItem
, removeItems
, moveUp
and moveDown
would get injected. schema
would also already point to the items
object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additionally it would be great to extract all the logic from the renderer. I would prefer a new mapStateToMultiEnumProps
and mapDispatchToMultiEnumProps
combined into a React withJsonFormsMultiEnumProps
.
mapStateToMultiEnumProps
: extracting theitems
options fromoneOf
orenum
, similar tomapStateToEnumPros
andmapStateToOneOfEnumProps
mapDispatchToMultiEnumProps
: providing aaddItem
andremoveItem
function which can be used for toggling. Using this we can also remove theuseRef
workaround
By extracting the logic from the renderer we can easily write a multi-select enum with a different renderer (e.g. Material UI's multi select dropdown) as well as more easily add the same renderer in the other renderer sets too.
c42726c
to
167de36
Compare
I updated the commit to include you comments, Stefan. The renderer now supports both |
Render an enum array or anyOf array of consts as a list of checkboxes. The checkbox is checked if the array item it represents is present in the data.
167de36
to
0a3c3c3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
packages/core/src/util/renderer.ts
Outdated
export const oneOfToEnumOptionMapper = (e: any): EnumOption => ({ | ||
value: e.const, | ||
label: | ||
e.title || (typeof e.const === 'string' ? e.const : JSON.stringify(e.const)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should respect empty titles ;)
e.title || (typeof e.const === 'string' ? e.const : JSON.stringify(e.const)) | |
e.title ?? (typeof e.const === 'string' ? e.const : JSON.stringify(e.const)) |
Render an anyOf array of consts as a list of checkboxes. The checkbox is
checked if the array item it represents is present in the data.