[Mappings Editor] JSON Editor#47589
Conversation
|
Pinging @elastic/es-ui (Team:Elasticsearch UI) |
x-pack/legacy/plugins/index_management/public/components/mappings_editor/reducer.ts
Outdated
Show resolved
Hide resolved
💚 Build Succeeded |
- Updates overall form validity - Debounces updates to ace to prevent JSON worker parsing errors - Pulls data from current editor - Implements basic toggle controls with user feedback
💚 Build Succeeded |
💚 Build Succeeded |
💚 Build Succeeded |
sebelga
left a comment
There was a problem hiding this comment.
Thanks for this PR @jloleysens ! I made comments to ask some changes. But I realize that I have most of them done locally. If you don't mind I will push 1 commit with most of the changes that I made locally and then you can "soft" revert the commit if you don't agree with some things and work from there.
|
|
||
| return ( | ||
| <JsonEditor | ||
| onUpdate={({ data, isValid }) => |
There was a problem hiding this comment.
In order to have the react.memo work inside the JsonEditor, we need to have the callback wrapped inside a useCallback here I think.
|
|
||
| return ( | ||
| <JsonEditor | ||
| onUpdate={({ data, isValid }) => |
There was a problem hiding this comment.
I think we need to use a useCallback here in order for the react.memo to take effect in the <JsonEditor />.
There was a problem hiding this comment.
Also, instead of deconstructing and changing the contract, can we simply forward the updated json data?
Something along those lines:
<JsonEditor
onUpdate={updatedFields =>
dispatch({
type: 'fieldsJsonEditor.update',
value: updatedFields,
})
}
defaultValue={defaultValueRef.current}
/>And then use this type for the reducer value: Parameters<OnUpdateHandler>[0] (importing OnUpdateHandler from use_json)
It seems to me than like that it is easier later to update a contract if needed.
There was a problem hiding this comment.
To your second point, I'm not sure I see enough value in maintaining this particular contract. If this contract changes we will need to update all of it's uses in the reducer which seems like more work?
| @@ -0,0 +1,63 @@ | |||
| /* | |||
There was a problem hiding this comment.
Can we rename this file to utils.test.ts to link it to the utils file?
| fieldForm?: FormComponentValidity; | ||
| } | ||
|
|
||
| export const determineIfValid = (components: FormComponentsArgs): boolean | undefined => { |
There was a problem hiding this comment.
It would be clearer to me if the function was called isMappingsValid() and instead of components call it state and set the type to the State type as it is the state that we are providing to this function.
There was a problem hiding this comment.
This is what I came up with (and that makes the above test with undefined expected work)
const stateWithValidity: Array<keyof State> = ['configuration', 'fieldsJsonEditor', 'fieldForm'];
export const isMappingsValid = (state: State): boolean | undefined =>
Object.entries(state)
.filter(([key]) => stateWithValidity.includes(key as keyof State))
.reduce(
(isValid, { 1: value }) => {
if (value === undefined) {
return isValid;
}
// If one section validity of the state is "undefined", the mappings validity is also "undefined"
if (isValid === undefined || value.isValid === undefined) {
return undefined;
}
return isValid && value.isValid;
},
true as undefined | boolean
);| fieldForm: undefined, | ||
| }; | ||
|
|
||
| expect(determineIfValid(components)).toBe(false); |
There was a problem hiding this comment.
We should expect it to be undefined as one of the section (configuration) is undefined.
| if (switchingToDefault) { | ||
| nextState.fieldsJsonEditor.isValid = undefined; | ||
| } else { | ||
| if (nextState.fieldForm) nextState.fieldForm.isValid = undefined; |
There was a problem hiding this comment.
I think we can set the fieldForm to undefined when switching? And it'd be good to reset the ```
So the nextState would be something like
const nextState: State = {
...state,
fields,
fieldForm: undefined,
documentFields: {
...state.documentFields,
status: 'idle',
fieldToAddFieldTo: undefined,
fieldToEdit: undefined,
editor: action.value,
},
};And just return that.
| }; | ||
| } | ||
| case 'fieldsJsonEditor.update': | ||
| return { |
There was a problem hiding this comment.
Instead of making 2 copies of the state, can we create like in other places an intermediary nextState and provide it to the determineIfValid () ?
| }, | ||
| fieldsJsonEditor: { | ||
| format: () => ({}), | ||
| isValid: undefined, |
There was a problem hiding this comment.
The isValid should be true on init.
| /* TODO: Review toggle controls UI */ | ||
| export const EditorToggleControls = ({ editor }: Props) => { | ||
| const dispatch = useDispatch(); | ||
| const state = useState(); |
There was a problem hiding this comment.
Can we deconstruct the fieldsJsonEditor from the state as it is used in multiple places?
| Max depth for Mappings Editor exceeded | ||
| </EuiText> | ||
| ) : null} | ||
| {showValidityWarning ? ( |
There was a problem hiding this comment.
Here we would need to also check if the Json validity is still false
showValidityWarning && !fieldsJsonEditor.isValid ?| interface FormComponentValidity { | ||
| isValid?: boolean; | ||
| } | ||
| const stateWithValidity: Array<keyof State> = ['configuration', 'fieldsJsonEditor', 'fieldForm']; |
There was a problem hiding this comment.
Hmm, the one drawback I can see with this is that we now have two places that need to be kept in sync for validation to function correctly. I think if it's documented then it's totally fine to take this approach.
One alternative could be that these entries are placed under a key like formComponents that conform to the FormComponentValidity interface which we can call HasValidity? That may result in a bit less massaging of (picking values off) of the state object. What do you think? Totally fine to shelf this idea for now and go with what you have implemented because it would mean updating everywhere!
💔 Build Failed |
sebelga
left a comment
There was a problem hiding this comment.
LGTM! Thanks for making those changes!
💚 Build Succeeded |
Summary
Add a JSON editor to mappings editor component that can function as a fallback for the mappings editor.