Skip to content

[Mappings Editor] JSON Editor#47589

Merged
sebelga merged 9 commits intoelastic:feature/mappings-editorfrom
jloleysens:feature/mappings-editor-json-editor
Oct 10, 2019
Merged

[Mappings Editor] JSON Editor#47589
sebelga merged 9 commits intoelastic:feature/mappings-editorfrom
jloleysens:feature/mappings-editor-json-editor

Conversation

@jloleysens
Copy link
Copy Markdown
Contributor

Summary

Add a JSON editor to mappings editor component that can function as a fallback for the mappings editor.

@jloleysens jloleysens added Feature:Index Management Index and index templates UI Team:Kibana Management Dev Tools, Index Management, Upgrade Assistant, ILM, Ingest Node Pipelines, and more t// labels Oct 8, 2019
@jloleysens jloleysens requested a review from sebelga October 8, 2019 14:33
@elasticmachine
Copy link
Copy Markdown
Contributor

Pinging @elastic/es-ui (Team:Elasticsearch UI)

@elasticmachine
Copy link
Copy Markdown
Contributor

💚 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
@elasticmachine
Copy link
Copy Markdown
Contributor

💚 Build Succeeded

@elasticmachine
Copy link
Copy Markdown
Contributor

💚 Build Succeeded

@elasticmachine
Copy link
Copy Markdown
Contributor

💚 Build Succeeded

Copy link
Copy Markdown
Contributor

@sebelga sebelga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 }) =>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 }) =>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to use a useCallback here in order for the react.memo to take effect in the <JsonEditor />.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 @@
/*
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The isValid should be true on init.

/* TODO: Review toggle controls UI */
export const EditorToggleControls = ({ editor }: Props) => {
const dispatch = useDispatch();
const state = useState();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we deconstruct the fieldsJsonEditor from the state as it is used in multiple places?

Max depth for Mappings Editor exceeded
</EuiText>
) : null}
{showValidityWarning ? (
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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'];
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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!

@elasticmachine
Copy link
Copy Markdown
Contributor

💔 Build Failed

@sebelga sebelga self-requested a review October 10, 2019 15:41
Copy link
Copy Markdown
Contributor

@sebelga sebelga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks for making those changes!

@sebelga sebelga merged commit b72e6d1 into elastic:feature/mappings-editor Oct 10, 2019
@elasticmachine
Copy link
Copy Markdown
Contributor

💚 Build Succeeded

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature:Index Management Index and index templates UI Team:Kibana Management Dev Tools, Index Management, Upgrade Assistant, ILM, Ingest Node Pipelines, and more t//

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants