From dbe180b1eeac6359f1f4bb3f6e73e779f8dd2e8e Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Tue, 8 Oct 2019 16:30:58 +0200 Subject: [PATCH 1/8] First pass at integration between JSON editor and mappings editor --- .../components/json_editor/json_editor.tsx | 80 +++++++++---------- .../components/mappings_editor/lib/utils.ts | 5 +- .../mappings_editor/mappings_editor.tsx | 67 +++++++++++----- .../mappings_editor/mappings_state.tsx | 15 ++-- .../components/mappings_editor/reducer.ts | 19 +++++ 5 files changed, 119 insertions(+), 67 deletions(-) diff --git a/x-pack/legacy/plugins/index_management/public/components/json_editor/json_editor.tsx b/x-pack/legacy/plugins/index_management/public/components/json_editor/json_editor.tsx index 7c9f0ea3e7c62..e9460780530ae 100644 --- a/x-pack/legacy/plugins/index_management/public/components/json_editor/json_editor.tsx +++ b/x-pack/legacy/plugins/index_management/public/components/json_editor/json_editor.tsx @@ -17,46 +17,42 @@ interface Props { euiCodeEditorProps?: { [key: string]: any }; } -export const JsonEditor = ({ - label, - helpText, - onUpdate, - defaultValue, - euiCodeEditorProps, -}: Props) => { - const { content, setContent, error } = useJson({ - defaultValue, - onUpdate, - }); +export const JsonEditor = React.memo( + ({ label, helpText, onUpdate, defaultValue, euiCodeEditorProps }: Props) => { + const { content, setContent, error } = useJson({ + defaultValue, + onUpdate, + }); - return ( - - { - setContent(udpated); - }} - {...euiCodeEditorProps} - /> - - ); -}; + return ( + + { + setContent(updated); + }} + {...euiCodeEditorProps} + /> + + ); + } +); diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/utils.ts b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/utils.ts index 8962cd25af74e..e135e8e189cf8 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/utils.ts +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/utils.ts @@ -15,7 +15,7 @@ import { SubType, ChildFieldName, } from '../types'; -import { DATA_TYPE_DEFINITION } from '../constants'; +import { DATA_TYPE_DEFINITION, MAX_DEPTH_DEFAULT_EDITOR } from '../constants'; export const getUniqueId = () => { return ( @@ -243,3 +243,6 @@ export const shouldDeleteChildFieldsAfterTypeChange = ( return false; }; + +export const canUseMappingsEditor = (maxNestedDepth: number) => + maxNestedDepth < MAX_DEPTH_DEFAULT_EDITOR; diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_editor.tsx b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_editor.tsx index a292703c8a0cc..60b5d5c3dea97 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_editor.tsx +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_editor.tsx @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { useCallback, useState } from 'react'; +import { EuiButton, EuiSpacer } from '@elastic/eui'; -import { JsonEditor } from '../json_editor'; import { ConfigurationForm, CONFIGURATION_FIELDS, @@ -14,6 +14,9 @@ import { DocumentFields, } from './components'; import { MappingsState, Props as MappingsStateProps, Types } from './mappings_state'; +import { OnUpdateHandler } from '../json_editor/use_json'; +import { canUseMappingsEditor } from './lib'; +import { JsonEditor } from '../json_editor'; interface Props { onUpdate: MappingsStateProps['onUpdate']; @@ -32,25 +35,51 @@ export const MappingsEditor = React.memo(({ onUpdate, defaultValue = {} }: Props ); const fieldsDefaultValue = defaultValue.properties || {}; - // Temporary logic - const onJsonEditorUpdate = (args: any) => { - // eslint-disable-next-line - console.log(args); - }; - return ( - {({ editor, getProperties }) => ( - <> - - - {editor === 'json' ? ( - - ) : ( - - )} - - )} + {({ editor, getProperties, dispatch, maxNestedDepth }) => { + const [jsonEditorDefault, setJsonEditorDefault] = useState({}); + const onJsonEditorUpdate = useCallback( + args => { + dispatch({ type: 'jsonEditor.update', value: { json: args.getData() } }); + }, + [dispatch] + ); + + const renderEditor = () => { + if (editor === 'json') { + return ; + } + return ; + }; + + return ( + <> + + + {renderEditor()} + {/* TODO: Review toggle controls below */} + + {editor === 'json' ? ( + dispatch({ type: 'changeEditor', value: 'default' })} + > + {'Use Mappings Editor'} + + ) : ( + { + setJsonEditorDefault(getProperties()); + dispatch({ type: 'changeEditor', value: 'json' }); + }} + > + {'Use JSON Editor'} + + )} + + ); + }} ); }); diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_state.tsx b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_state.tsx index e93f549ba59a5..95406d258844d 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_state.tsx +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_state.tsx @@ -4,12 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useReducer, useEffect, createContext, useContext } from 'react'; +import React, { useReducer, useEffect, createContext, useContext, useCallback } from 'react'; -import { reducer, MappingsConfiguration, MappingsFields, State, Dispatch } from './reducer'; -import { MAX_DEPTH_DEFAULT_EDITOR } from './constants'; +import { reducer, MappingsConfiguration, MappingsFields, State, Dispatch, Action } from './reducer'; import { Field, FieldsEditor } from './types'; -import { normalize, deNormalize } from './lib'; +import { normalize, deNormalize, canUseMappingsEditor } from './lib'; type Mappings = MappingsConfiguration & { properties: MappingsFields; @@ -36,6 +35,8 @@ export interface Props { children: (params: { editor: FieldsEditor; getProperties(): Mappings['properties']; + dispatch: React.Dispatch; + maxNestedDepth: number; }) => React.ReactNode; defaultValue: { fields: { [key: string]: Field } }; onUpdate: OnUpdateHandler; @@ -44,6 +45,7 @@ export interface Props { export const MappingsState = React.memo(({ children, onUpdate, defaultValue }: Props) => { const { byId, rootLevelFields, maxNestedDepth } = normalize(defaultValue.fields); + const canUseDefaultEditor = canUseMappingsEditor(maxNestedDepth); const initialState: State = { isValid: undefined, configuration: { @@ -60,7 +62,7 @@ export const MappingsState = React.memo(({ children, onUpdate, defaultValue }: P }, documentFields: { status: 'idle', - editor: maxNestedDepth >= MAX_DEPTH_DEFAULT_EDITOR ? 'json' : 'default', + editor: canUseDefaultEditor ? 'default' : 'json', }, }; @@ -86,12 +88,15 @@ export const MappingsState = React.memo(({ children, onUpdate, defaultValue }: P }); }, [state]); + const renderPropsDispatch = useCallback(dispatch, []); return ( {children({ editor: state.documentFields.editor, + maxNestedDepth: state.fields ? state.fields.maxNestedDepth : 0, getProperties: () => deNormalize(state.fields), + dispatch: renderPropsDispatch, })} diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/reducer.ts b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/reducer.ts index 8105f66a8cdf9..c75ce5a2e7d95 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/reducer.ts +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/reducer.ts @@ -11,6 +11,7 @@ import { shouldDeleteChildFieldsAfterTypeChange, getAllChildFields, getMaxNestedDepth, + normalize, } from './lib'; export interface MappingsConfiguration { @@ -50,6 +51,8 @@ export type Action = | { type: 'documentField.createField'; value?: string } | { type: 'documentField.editField'; value: string } | { type: 'documentField.changeStatus'; value: DocumentFieldsStatus } + | { type: 'jsonEditor.update'; value: { json: { [key: string]: any } } } + | { type: 'changeEditor'; value: FieldsEditor } | { type: 'documentField.changeEditor'; value: FieldsEditor }; export type Dispatch = (action: Action) => void; @@ -112,6 +115,7 @@ export const reducer = (state: State, action: Action): State => { fieldToEdit: undefined, }, }; + case 'changeEditor': case 'documentField.changeEditor': return { ...state, documentFields: { ...state.documentFields, editor: action.value } }; case 'field.add': { @@ -240,6 +244,21 @@ export const reducer = (state: State, action: Action): State => { }, }; } + case 'jsonEditor.update': + try { + const nextFields = normalize(action.value.json); + return { + ...state, + fields: nextFields, + }; + } catch (e) { + // This shouldn't happen because the source of the JSON should have + // sanity checking for valid JSON. + + // eslint-disable-next-line no-console + console.error(e); + return state; + } default: throw new Error(`Action "${action!.type}" not recognized.`); } From 21c8a724497a284083975b8fe2a11dd22568050e Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Wed, 9 Oct 2019 13:29:15 +0200 Subject: [PATCH 2/8] First iteration of more complete JSON Editor - 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 --- .../components/json_editor/json_editor.tsx | 7 +- .../public/components/json_editor/use_json.ts | 12 ++- .../document_fields_json_editor.tsx | 31 ++++++++ .../components/editor_toggle_controls.tsx | 76 ++++++++++++++++++ .../mappings_editor/components/index.ts | 4 + .../mappings_editor/lib/form_validity.test.ts | 71 +++++++++++++++++ .../components/mappings_editor/lib/utils.ts | 23 ++++++ .../mappings_editor/mappings_editor.tsx | 40 ++-------- .../mappings_editor/mappings_state.tsx | 19 +++-- .../components/mappings_editor/reducer.ts | 78 +++++++++++-------- 10 files changed, 281 insertions(+), 80 deletions(-) create mode 100644 x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields_json_editor.tsx create mode 100644 x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/editor_toggle_controls.tsx create mode 100644 x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/form_validity.test.ts diff --git a/x-pack/legacy/plugins/index_management/public/components/json_editor/json_editor.tsx b/x-pack/legacy/plugins/index_management/public/components/json_editor/json_editor.tsx index e9460780530ae..8292c93bb9df7 100644 --- a/x-pack/legacy/plugins/index_management/public/components/json_editor/json_editor.tsx +++ b/x-pack/legacy/plugins/index_management/public/components/json_editor/json_editor.tsx @@ -4,8 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { useCallback } from 'react'; import { EuiFormRow, EuiCodeEditor } from '@elastic/eui'; +import { debounce } from 'lodash'; import { useJson, OnUpdateHandler } from './use_json'; @@ -24,6 +25,8 @@ export const JsonEditor = React.memo( onUpdate, }); + const debouncedSetContent = useCallback(debounce(setContent, 300), [setContent]); + return ( { - setContent(updated); + debouncedSetContent(updated); }} {...euiCodeEditorProps} /> diff --git a/x-pack/legacy/plugins/index_management/public/components/json_editor/use_json.ts b/x-pack/legacy/plugins/index_management/public/components/json_editor/use_json.ts index 4e0bc8f5a2c66..4d8b455d4c26a 100644 --- a/x-pack/legacy/plugins/index_management/public/components/json_editor/use_json.ts +++ b/x-pack/legacy/plugins/index_management/public/components/json_editor/use_json.ts @@ -10,7 +10,10 @@ import { i18n } from '@kbn/i18n'; import { isJSON } from '../../../../../../../src/plugins/es_ui_shared/static/validators/string'; export type OnUpdateHandler = (arg: { - getData(): T; + data: { + raw: string; + format(): T; + }; validate(): boolean; isValid: boolean; }) => void; @@ -45,7 +48,7 @@ export const useJson = ({ return isValid; }; - const getData = () => { + const formatContent = () => { const isValid = validate(); const data = isValid && content.trim() !== '' ? JSON.parse(content) : {}; return data as T; @@ -54,7 +57,10 @@ export const useJson = ({ useEffect(() => { const isValid = validate(); onUpdate({ - getData, + data: { + raw: content, + format: formatContent, + }, validate, isValid, }); diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields_json_editor.tsx b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields_json_editor.tsx new file mode 100644 index 0000000000000..0005493f9a23e --- /dev/null +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields_json_editor.tsx @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useRef } from 'react'; + +import { useDispatch } from '../mappings_state'; +import { JsonEditor } from '../../json_editor'; + +export interface Props { + defaultValue: object; +} + +export const DocumentFieldsJsonEditor = ({ defaultValue }: Props) => { + const dispatch = useDispatch(); + const defaultValueRef = useRef(defaultValue); + + return ( + + dispatch({ + type: 'fieldsJsonEditor.update', + value: { json: data.format(), isValid }, + }) + } + defaultValue={defaultValueRef.current} + /> + ); +}; diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/editor_toggle_controls.tsx b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/editor_toggle_controls.tsx new file mode 100644 index 0000000000000..11312b2176218 --- /dev/null +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/editor_toggle_controls.tsx @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { EuiButton, EuiText, EuiSpacer } from '@elastic/eui'; + +import { useDispatch, useState } from '../mappings_state'; +import { FieldsEditor } from '../types'; +import { canUseMappingsEditor, normalize } from '../lib'; + +interface Props { + editor: FieldsEditor; +} + +/* TODO: Review toggle controls */ +export const EditorToggleControls = ({ editor }: Props) => { + const dispatch = useDispatch(); + const state = useState(); + + const [showMaxDepthWarning, setShowMaxDepthWarning] = React.useState(false); + const [showValidityWarning, setShowValidityWarning] = React.useState(false); + + const clearWarnings = () => { + if (showMaxDepthWarning) setShowMaxDepthWarning(false); + if (showValidityWarning) setShowValidityWarning(false); + }; + + if (editor === 'default') { + clearWarnings(); + return ( + { + dispatch({ type: 'documentField.changeEditor', value: 'json' }); + }} + > + Use JSON Editor + + ); + } + + return ( + <> + { + clearWarnings(); + const deNormalizedFields = state.fieldsJsonEditor.format(); + const normalizedFields = normalize(deNormalizedFields); + const maxDepthOk = canUseMappingsEditor(normalizedFields.maxNestedDepth); + const validJSON = state.fieldsJsonEditor.isValid; + + if (maxDepthOk && validJSON) { + dispatch({ type: 'documentField.changeEditor', value: 'default' }); + } else { + if (!maxDepthOk) setShowMaxDepthWarning(true); + if (!validJSON) setShowValidityWarning(true); + } + }} + > + Use Mappings Editor + + {showMaxDepthWarning ? ( + + Max depth for Mappings Editor exceeded + + ) : null} + {showValidityWarning ? ( + + JSON is invalid + + ) : null} + + ); +}; diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/index.ts b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/index.ts index 4110db5a39312..7a389431787f1 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/index.ts +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/index.ts @@ -7,3 +7,7 @@ export * from './configuration_form'; export * from './document_fields'; + +export * from './document_fields_json_editor'; + +export * from './editor_toggle_controls'; diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/form_validity.test.ts b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/form_validity.test.ts new file mode 100644 index 0000000000000..a1a0f0d8f3af5 --- /dev/null +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/form_validity.test.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +jest.mock('../constants', () => ({ DATA_TYPE_DEFINITION: {} })); + +import { determineIfValid, FormComponentsArgs } from '.'; + +describe('Mappings Editor form validity', () => { + let components: FormComponentsArgs; + it('handles base case', () => { + components = { + fieldsJsonEditor: { isValid: undefined }, + configuration: { isValid: undefined }, + fieldForm: undefined, + }; + expect(determineIfValid(components)).toBe(undefined); + }); + + it('handles combinations of true, false and undefined', () => { + components = { + fieldsJsonEditor: { isValid: false }, + configuration: { isValid: true }, + fieldForm: { isValid: true }, + }; + + expect(determineIfValid(components)).toBe(false); + + components = { + fieldsJsonEditor: { isValid: false }, + configuration: { isValid: true }, + fieldForm: undefined, + }; + + expect(determineIfValid(components)).toBe(false); + + components = { + fieldsJsonEditor: { isValid: false }, + configuration: { isValid: undefined }, + fieldForm: undefined, + }; + + expect(determineIfValid(components)).toBe(false); + + components = { + fieldsJsonEditor: { isValid: undefined }, + configuration: { isValid: undefined }, + fieldForm: undefined, + }; + + expect(determineIfValid(components)).toBe(undefined); + + components = { + fieldsJsonEditor: { isValid: true }, + configuration: { isValid: undefined }, + fieldForm: undefined, + }; + + expect(determineIfValid(components)).toBe(true); + + components = { + fieldsJsonEditor: { isValid: true }, + configuration: { isValid: false }, + fieldForm: undefined, + }; + + expect(determineIfValid(components)).toBe(false); + }); +}); diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/utils.ts b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/utils.ts index e135e8e189cf8..858454b201488 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/utils.ts +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/utils.ts @@ -246,3 +246,26 @@ export const shouldDeleteChildFieldsAfterTypeChange = ( export const canUseMappingsEditor = (maxNestedDepth: number) => maxNestedDepth < MAX_DEPTH_DEFAULT_EDITOR; + +interface FormComponentValidity { + isValid?: boolean; +} + +export interface FormComponentsArgs { + configuration: FormComponentValidity; + fieldsJsonEditor: FormComponentValidity; + fieldForm?: FormComponentValidity; +} + +export const determineIfValid = (components: FormComponentsArgs): boolean | undefined => { + return Object.values(components).reduce( + (valid, value) => { + // If one component is false, the form validity is false + if (valid === false) return valid; + // If even one component has a validity, that determines the validity of the form + if (value && value.isValid !== undefined) return value.isValid; + return valid; + }, + undefined as boolean | undefined + ); +}; diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_editor.tsx b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_editor.tsx index 60b5d5c3dea97..0a57ce3ae3d66 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_editor.tsx +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_editor.tsx @@ -4,19 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useCallback, useState } from 'react'; -import { EuiButton, EuiSpacer } from '@elastic/eui'; +import React from 'react'; +import { EuiSpacer } from '@elastic/eui'; import { ConfigurationForm, CONFIGURATION_FIELDS, DocumentFieldsHeaders, DocumentFields, + DocumentFieldsJsonEditor, + EditorToggleControls, } from './components'; import { MappingsState, Props as MappingsStateProps, Types } from './mappings_state'; -import { OnUpdateHandler } from '../json_editor/use_json'; -import { canUseMappingsEditor } from './lib'; -import { JsonEditor } from '../json_editor'; interface Props { onUpdate: MappingsStateProps['onUpdate']; @@ -37,18 +36,10 @@ export const MappingsEditor = React.memo(({ onUpdate, defaultValue = {} }: Props return ( - {({ editor, getProperties, dispatch, maxNestedDepth }) => { - const [jsonEditorDefault, setJsonEditorDefault] = useState({}); - const onJsonEditorUpdate = useCallback( - args => { - dispatch({ type: 'jsonEditor.update', value: { json: args.getData() } }); - }, - [dispatch] - ); - + {({ editor, getProperties }) => { const renderEditor = () => { if (editor === 'json') { - return ; + return ; } return ; }; @@ -58,25 +49,8 @@ export const MappingsEditor = React.memo(({ onUpdate, defaultValue = {} }: Props {renderEditor()} - {/* TODO: Review toggle controls below */} - {editor === 'json' ? ( - dispatch({ type: 'changeEditor', value: 'default' })} - > - {'Use Mappings Editor'} - - ) : ( - { - setJsonEditorDefault(getProperties()); - dispatch({ type: 'changeEditor', value: 'json' }); - }} - > - {'Use JSON Editor'} - - )} + ); }} diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_state.tsx b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_state.tsx index 95406d258844d..f9ab3e1a5b1ae 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_state.tsx +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_state.tsx @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useReducer, useEffect, createContext, useContext, useCallback } from 'react'; +import React, { useReducer, useEffect, createContext, useContext } from 'react'; -import { reducer, MappingsConfiguration, MappingsFields, State, Dispatch, Action } from './reducer'; +import { reducer, MappingsConfiguration, MappingsFields, State, Dispatch } from './reducer'; import { Field, FieldsEditor } from './types'; import { normalize, deNormalize, canUseMappingsEditor } from './lib'; @@ -35,8 +35,6 @@ export interface Props { children: (params: { editor: FieldsEditor; getProperties(): Mappings['properties']; - dispatch: React.Dispatch; - maxNestedDepth: number; }) => React.ReactNode; defaultValue: { fields: { [key: string]: Field } }; onUpdate: OnUpdateHandler; @@ -64,6 +62,10 @@ export const MappingsState = React.memo(({ children, onUpdate, defaultValue }: P status: 'idle', editor: canUseDefaultEditor ? 'default' : 'json', }, + fieldsJsonEditor: { + format: () => ({}), + isValid: undefined, + }, }; const [state, dispatch] = useReducer(reducer, initialState); @@ -73,7 +75,11 @@ export const MappingsState = React.memo(({ children, onUpdate, defaultValue }: P onUpdate({ getData: () => ({ ...state.configuration.data.format(), - properties: deNormalize(state.fields), + properties: + // Pull the mappings properties from the current editor + state.documentFields.editor === 'json' + ? state.fieldsJsonEditor.format() + : deNormalize(state.fields), }), validate: async () => { if (state.fieldForm === undefined) { @@ -88,15 +94,12 @@ export const MappingsState = React.memo(({ children, onUpdate, defaultValue }: P }); }, [state]); - const renderPropsDispatch = useCallback(dispatch, []); return ( {children({ editor: state.documentFields.editor, - maxNestedDepth: state.fields ? state.fields.maxNestedDepth : 0, getProperties: () => deNormalize(state.fields), - dispatch: renderPropsDispatch, })} diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/reducer.ts b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/reducer.ts index c75ce5a2e7d95..73ae2f1cd0d07 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/reducer.ts +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/reducer.ts @@ -11,6 +11,7 @@ import { shouldDeleteChildFieldsAfterTypeChange, getAllChildFields, getMaxNestedDepth, + determineIfValid, normalize, } from './lib'; @@ -40,6 +41,10 @@ export interface State { documentFields: DocumentFieldsState; fields: NormalizedFields; fieldForm?: OnFormUpdateArg; + fieldsJsonEditor: { + format(): MappingsFields; + isValid: boolean | undefined; + }; } export type Action = @@ -51,36 +56,30 @@ export type Action = | { type: 'documentField.createField'; value?: string } | { type: 'documentField.editField'; value: string } | { type: 'documentField.changeStatus'; value: DocumentFieldsStatus } - | { type: 'jsonEditor.update'; value: { json: { [key: string]: any } } } - | { type: 'changeEditor'; value: FieldsEditor } - | { type: 'documentField.changeEditor'; value: FieldsEditor }; + | { type: 'documentField.changeEditor'; value: FieldsEditor } + | { type: 'fieldsJsonEditor.update'; value: { json: { [key: string]: any }; isValid: boolean } }; export type Dispatch = (action: Action) => void; export const reducer = (state: State, action: Action): State => { switch (action.type) { case 'configuration.update': { - const fieldFormValidity = state.fieldForm === undefined ? true : state.fieldForm.isValid; - const isValid = - action.value.isValid === undefined || fieldFormValidity === undefined - ? undefined - : action.value.isValid && fieldFormValidity; - return { ...state, - isValid, + isValid: determineIfValid({ + ...state, + configuration: action.value, + }), configuration: action.value, }; } case 'fieldForm.update': { - const isValid = - action.value.isValid === undefined || state.configuration.isValid === undefined - ? undefined - : action.value.isValid && state.configuration.isValid; - return { ...state, - isValid, + isValid: determineIfValid({ + ...state, + fieldForm: action.value, + }), fieldForm: action.value, }; } @@ -115,9 +114,21 @@ export const reducer = (state: State, action: Action): State => { fieldToEdit: undefined, }, }; - case 'changeEditor': case 'documentField.changeEditor': - return { ...state, documentFields: { ...state.documentFields, editor: action.value } }; + const switchingToDefault = action.value === 'default'; + const fields = switchingToDefault ? normalize(state.fieldsJsonEditor.format()) : state.fields; + const nextState = { + ...state, + fields, + documentFields: { ...state.documentFields, editor: action.value }, + }; + + if (switchingToDefault) { + nextState.fieldsJsonEditor.isValid = undefined; + } else { + if (nextState.fieldForm) nextState.fieldForm.isValid = false; + } + return nextState; case 'field.add': { const id = getUniqueId(); const { fieldToAddFieldTo } = state.documentFields; @@ -152,7 +163,7 @@ export const reducer = (state: State, action: Action): State => { return { ...state, - isValid: state.configuration.isValid, + isValid: determineIfValid(state), fields: { ...state.fields, rootLevelFields, maxNestedDepth }, }; } @@ -228,7 +239,7 @@ export const reducer = (state: State, action: Action): State => { return { ...state, - isValid: state.configuration.isValid, + isValid: determineIfValid(state), fieldForm: undefined, documentFields: { ...state.documentFields, @@ -244,21 +255,20 @@ export const reducer = (state: State, action: Action): State => { }, }; } - case 'jsonEditor.update': - try { - const nextFields = normalize(action.value.json); - return { + case 'fieldsJsonEditor.update': + return { + ...state, + isValid: determineIfValid({ ...state, - fields: nextFields, - }; - } catch (e) { - // This shouldn't happen because the source of the JSON should have - // sanity checking for valid JSON. - - // eslint-disable-next-line no-console - console.error(e); - return state; - } + fieldsJsonEditor: action.value, + }), + fieldsJsonEditor: { + format() { + return action.value.json; + }, + isValid: action.value.isValid, + }, + }; default: throw new Error(`Action "${action!.type}" not recognized.`); } From c8f4774919ac3a7af5d6fe6c9b518d26bb315142 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Wed, 9 Oct 2019 14:05:35 +0200 Subject: [PATCH 3/8] Remove unused import --- .../mappings_editor/components/editor_toggle_controls.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/editor_toggle_controls.tsx b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/editor_toggle_controls.tsx index 11312b2176218..8b4c64e0c1832 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/editor_toggle_controls.tsx +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/editor_toggle_controls.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; -import { EuiButton, EuiText, EuiSpacer } from '@elastic/eui'; +import { EuiButton, EuiText } from '@elastic/eui'; import { useDispatch, useState } from '../mappings_state'; import { FieldsEditor } from '../types'; From 56ae16bc9f111f23764d7cca039bfc1cd81190bf Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Wed, 9 Oct 2019 15:56:38 +0200 Subject: [PATCH 4/8] Move files (document_fields_json_editor and editor_toggle_controls) --- .../{ => document_fields}/document_fields_json_editor.tsx | 4 ++-- .../{ => document_fields}/editor_toggle_controls.tsx | 8 ++++---- .../mappings_editor/components/document_fields/index.ts | 4 ++++ .../public/components/mappings_editor/components/index.ts | 4 ---- 4 files changed, 10 insertions(+), 10 deletions(-) rename x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/{ => document_fields}/document_fields_json_editor.tsx (87%) rename x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/{ => document_fields}/editor_toggle_controls.tsx (91%) diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields_json_editor.tsx b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/document_fields_json_editor.tsx similarity index 87% rename from x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields_json_editor.tsx rename to x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/document_fields_json_editor.tsx index 0005493f9a23e..650c6f85677c7 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields_json_editor.tsx +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/document_fields_json_editor.tsx @@ -6,8 +6,8 @@ import React, { useRef } from 'react'; -import { useDispatch } from '../mappings_state'; -import { JsonEditor } from '../../json_editor'; +import { useDispatch } from '../../mappings_state'; +import { JsonEditor } from '../../../json_editor'; export interface Props { defaultValue: object; diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/editor_toggle_controls.tsx b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/editor_toggle_controls.tsx similarity index 91% rename from x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/editor_toggle_controls.tsx rename to x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/editor_toggle_controls.tsx index 8b4c64e0c1832..4e52ee5e8dd48 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/editor_toggle_controls.tsx +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/editor_toggle_controls.tsx @@ -7,15 +7,15 @@ import React from 'react'; import { EuiButton, EuiText } from '@elastic/eui'; -import { useDispatch, useState } from '../mappings_state'; -import { FieldsEditor } from '../types'; -import { canUseMappingsEditor, normalize } from '../lib'; +import { useDispatch, useState } from '../../mappings_state'; +import { FieldsEditor } from '../../types'; +import { canUseMappingsEditor, normalize } from '../../lib'; interface Props { editor: FieldsEditor; } -/* TODO: Review toggle controls */ +/* TODO: Review toggle controls UI */ export const EditorToggleControls = ({ editor }: Props) => { const dispatch = useDispatch(); const state = useState(); diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/index.ts b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/index.ts index a9d1620c56921..0687bedcc3667 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/index.ts +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/index.ts @@ -7,3 +7,7 @@ export * from './document_fields'; export * from './document_fields_header'; + +export * from './document_fields_json_editor'; + +export * from './editor_toggle_controls'; diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/index.ts b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/index.ts index 7a389431787f1..4110db5a39312 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/index.ts +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/index.ts @@ -7,7 +7,3 @@ export * from './configuration_form'; export * from './document_fields'; - -export * from './document_fields_json_editor'; - -export * from './editor_toggle_controls'; From 2c92e557eb871149f6b810b725724f767006d1d5 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 10 Oct 2019 11:10:59 +0200 Subject: [PATCH 5/8] false -> undefined --- .../public/components/mappings_editor/reducer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/reducer.ts b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/reducer.ts index 73ae2f1cd0d07..5c804e391f2ad 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/reducer.ts +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/reducer.ts @@ -126,7 +126,7 @@ export const reducer = (state: State, action: Action): State => { if (switchingToDefault) { nextState.fieldsJsonEditor.isValid = undefined; } else { - if (nextState.fieldForm) nextState.fieldForm.isValid = false; + if (nextState.fieldForm) nextState.fieldForm.isValid = undefined; } return nextState; case 'field.add': { From fb4a423d65951ae9b3f5f4c4adf3eea73a107f39 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 10 Oct 2019 11:18:48 +0200 Subject: [PATCH 6/8] Reorder tests and remove duplicate test --- .../mappings_editor/lib/form_validity.test.ts | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/form_validity.test.ts b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/form_validity.test.ts index a1a0f0d8f3af5..4275ef411b6c8 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/form_validity.test.ts +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/form_validity.test.ts @@ -20,14 +20,6 @@ describe('Mappings Editor form validity', () => { }); it('handles combinations of true, false and undefined', () => { - components = { - fieldsJsonEditor: { isValid: false }, - configuration: { isValid: true }, - fieldForm: { isValid: true }, - }; - - expect(determineIfValid(components)).toBe(false); - components = { fieldsJsonEditor: { isValid: false }, configuration: { isValid: true }, @@ -45,25 +37,25 @@ describe('Mappings Editor form validity', () => { expect(determineIfValid(components)).toBe(false); components = { - fieldsJsonEditor: { isValid: undefined }, + fieldsJsonEditor: { isValid: true }, configuration: { isValid: undefined }, fieldForm: undefined, }; - expect(determineIfValid(components)).toBe(undefined); + expect(determineIfValid(components)).toBe(true); components = { fieldsJsonEditor: { isValid: true }, - configuration: { isValid: undefined }, + configuration: { isValid: false }, fieldForm: undefined, }; - expect(determineIfValid(components)).toBe(true); + expect(determineIfValid(components)).toBe(false); components = { - fieldsJsonEditor: { isValid: true }, - configuration: { isValid: false }, - fieldForm: undefined, + fieldsJsonEditor: { isValid: false }, + configuration: { isValid: true }, + fieldForm: { isValid: true }, }; expect(determineIfValid(components)).toBe(false); From 3c7e33e7f4f4d06a7e6e534d56d9361352a22023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien?= Date: Thu, 10 Oct 2019 15:57:17 +0200 Subject: [PATCH 7/8] Made some of the CR changes --- .../editor_toggle_controls.tsx | 25 ++++++------ .../mappings_editor/lib/form_validity.test.ts | 5 ++- .../components/mappings_editor/lib/utils.ts | 39 +++++++++---------- .../mappings_editor/mappings_state.tsx | 7 ++-- .../components/mappings_editor/reducer.ts | 36 +++++++++-------- 5 files changed, 59 insertions(+), 53 deletions(-) diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/editor_toggle_controls.tsx b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/editor_toggle_controls.tsx index 4e52ee5e8dd48..cf9eaf72ebd25 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/editor_toggle_controls.tsx +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/editor_toggle_controls.tsx @@ -18,7 +18,7 @@ interface Props { /* TODO: Review toggle controls UI */ export const EditorToggleControls = ({ editor }: Props) => { const dispatch = useDispatch(); - const state = useState(); + const { fieldsJsonEditor } = useState(); const [showMaxDepthWarning, setShowMaxDepthWarning] = React.useState(false); const [showValidityWarning, setShowValidityWarning] = React.useState(false); @@ -46,16 +46,19 @@ export const EditorToggleControls = ({ editor }: Props) => { { clearWarnings(); - const deNormalizedFields = state.fieldsJsonEditor.format(); - const normalizedFields = normalize(deNormalizedFields); - const maxDepthOk = canUseMappingsEditor(normalizedFields.maxNestedDepth); - const validJSON = state.fieldsJsonEditor.isValid; - - if (maxDepthOk && validJSON) { - dispatch({ type: 'documentField.changeEditor', value: 'default' }); + const { isValid } = fieldsJsonEditor; + if (!isValid) { + setShowValidityWarning(true); } else { - if (!maxDepthOk) setShowMaxDepthWarning(true); - if (!validJSON) setShowValidityWarning(true); + const deNormalizedFields = fieldsJsonEditor.format(); + const { maxNestedDepth } = normalize(deNormalizedFields); + const canUseDefaultEditor = canUseMappingsEditor(maxNestedDepth); + + if (canUseDefaultEditor) { + dispatch({ type: 'documentField.changeEditor', value: 'default' }); + } else { + setShowMaxDepthWarning(true); + } } }} > @@ -66,7 +69,7 @@ export const EditorToggleControls = ({ editor }: Props) => { Max depth for Mappings Editor exceeded ) : null} - {showValidityWarning ? ( + {showValidityWarning && !fieldsJsonEditor.isValid ? ( JSON is invalid diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/form_validity.test.ts b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/form_validity.test.ts index 4275ef411b6c8..31f404fff6dbb 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/form_validity.test.ts +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/form_validity.test.ts @@ -6,6 +6,7 @@ jest.mock('../constants', () => ({ DATA_TYPE_DEFINITION: {} })); +// FormComponentsArgs will have to be changed with "State" import { determineIfValid, FormComponentsArgs } from '.'; describe('Mappings Editor form validity', () => { @@ -34,7 +35,7 @@ describe('Mappings Editor form validity', () => { fieldForm: undefined, }; - expect(determineIfValid(components)).toBe(false); + expect(determineIfValid(components)).toBe(undefined); components = { fieldsJsonEditor: { isValid: true }, @@ -42,7 +43,7 @@ describe('Mappings Editor form validity', () => { fieldForm: undefined, }; - expect(determineIfValid(components)).toBe(true); + expect(determineIfValid(components)).toBe(undefined); components = { fieldsJsonEditor: { isValid: true }, diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/utils.ts b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/utils.ts index 858454b201488..6e426b686bff0 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/utils.ts +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/utils.ts @@ -16,6 +16,7 @@ import { ChildFieldName, } from '../types'; import { DATA_TYPE_DEFINITION, MAX_DEPTH_DEFAULT_EDITOR } from '../constants'; +import { State } from '../reducer'; export const getUniqueId = () => { return ( @@ -247,25 +248,23 @@ export const shouldDeleteChildFieldsAfterTypeChange = ( export const canUseMappingsEditor = (maxNestedDepth: number) => maxNestedDepth < MAX_DEPTH_DEFAULT_EDITOR; -interface FormComponentValidity { - isValid?: boolean; -} +const stateWithValidity: Array = ['configuration', 'fieldsJsonEditor', 'fieldForm']; -export interface FormComponentsArgs { - configuration: FormComponentValidity; - fieldsJsonEditor: FormComponentValidity; - fieldForm?: FormComponentValidity; -} +export const determineIfValid = (state: State): boolean | undefined => + Object.entries(state) + .filter(([key]) => stateWithValidity.includes(key as keyof State)) + .reduce( + (isValid, { 1: value }) => { + if (value === undefined) { + return isValid; + } -export const determineIfValid = (components: FormComponentsArgs): boolean | undefined => { - return Object.values(components).reduce( - (valid, value) => { - // If one component is false, the form validity is false - if (valid === false) return valid; - // If even one component has a validity, that determines the validity of the form - if (value && value.isValid !== undefined) return value.isValid; - return valid; - }, - undefined as boolean | undefined - ); -}; + // 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 + ); diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_state.tsx b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_state.tsx index f9ab3e1a5b1ae..9c5834c231da6 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_state.tsx +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/mappings_state.tsx @@ -64,7 +64,7 @@ export const MappingsState = React.memo(({ children, onUpdate, defaultValue }: P }, fieldsJsonEditor: { format: () => ({}), - isValid: undefined, + isValid: true, }, }; @@ -83,11 +83,12 @@ export const MappingsState = React.memo(({ children, onUpdate, defaultValue }: P }), validate: async () => { if (state.fieldForm === undefined) { - return await state.configuration.validate(); + return (await state.configuration.validate()) && state.fieldsJsonEditor.isValid; } return Promise.all([state.configuration.validate(), state.fieldForm.validate()]).then( - ([isConfigurationValid, isFormFieldValid]) => isConfigurationValid && isFormFieldValid + ([isConfigurationValid, isFormFieldValid]) => + isConfigurationValid && isFormFieldValid && state.fieldsJsonEditor.isValid ); }, isValid: state.isValid, diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/reducer.ts b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/reducer.ts index 5c804e391f2ad..e7623394390a5 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/reducer.ts +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/reducer.ts @@ -43,7 +43,7 @@ export interface State { fieldForm?: OnFormUpdateArg; fieldsJsonEditor: { format(): MappingsFields; - isValid: boolean | undefined; + isValid: boolean; }; } @@ -114,21 +114,22 @@ export const reducer = (state: State, action: Action): State => { fieldToEdit: undefined, }, }; - case 'documentField.changeEditor': + case 'documentField.changeEditor': { const switchingToDefault = action.value === 'default'; const fields = switchingToDefault ? normalize(state.fieldsJsonEditor.format()) : state.fields; - const nextState = { + return { ...state, fields, - documentFields: { ...state.documentFields, editor: action.value }, + fieldForm: undefined, + documentFields: { + ...state.documentFields, + status: 'idle', + fieldToAddFieldTo: undefined, + fieldToEdit: undefined, + editor: action.value, + }, }; - - if (switchingToDefault) { - nextState.fieldsJsonEditor.isValid = undefined; - } else { - if (nextState.fieldForm) nextState.fieldForm.isValid = undefined; - } - return nextState; + } case 'field.add': { const id = getUniqueId(); const { fieldToAddFieldTo } = state.documentFields; @@ -255,13 +256,9 @@ export const reducer = (state: State, action: Action): State => { }, }; } - case 'fieldsJsonEditor.update': - return { + case 'fieldsJsonEditor.update': { + const nextState = { ...state, - isValid: determineIfValid({ - ...state, - fieldsJsonEditor: action.value, - }), fieldsJsonEditor: { format() { return action.value.json; @@ -269,6 +266,11 @@ export const reducer = (state: State, action: Action): State => { isValid: action.value.isValid, }, }; + + nextState.isValid = determineIfValid(nextState); + + return nextState; + } default: throw new Error(`Action "${action!.type}" not recognized.`); } From 3beedf67202bdca01896499e36505fc3ddbb8b68 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 10 Oct 2019 17:07:28 +0200 Subject: [PATCH 8/8] Make changes after CR --- .../document_fields_json_editor.tsx | 21 ++++++++----------- .../editor_toggle_controls.tsx | 9 ++++++-- .../{form_validity.test.ts => utils.test.ts} | 5 ++--- 3 files changed, 18 insertions(+), 17 deletions(-) rename x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/{form_validity.test.ts => utils.test.ts} (91%) diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/document_fields_json_editor.tsx b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/document_fields_json_editor.tsx index 650c6f85677c7..f304ec455b73f 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/document_fields_json_editor.tsx +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/document_fields_json_editor.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useRef } from 'react'; +import React, { useRef, useCallback } from 'react'; import { useDispatch } from '../../mappings_state'; import { JsonEditor } from '../../../json_editor'; @@ -16,16 +16,13 @@ export interface Props { export const DocumentFieldsJsonEditor = ({ defaultValue }: Props) => { const dispatch = useDispatch(); const defaultValueRef = useRef(defaultValue); - - return ( - - dispatch({ - type: 'fieldsJsonEditor.update', - value: { json: data.format(), isValid }, - }) - } - defaultValue={defaultValueRef.current} - /> + const onUpdate = useCallback( + ({ data, isValid }) => + dispatch({ + type: 'fieldsJsonEditor.update', + value: { json: data.format(), isValid }, + }), + [dispatch] ); + return ; }; diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/editor_toggle_controls.tsx b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/editor_toggle_controls.tsx index cf9eaf72ebd25..d1e9738617105 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/editor_toggle_controls.tsx +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/editor_toggle_controls.tsx @@ -24,8 +24,13 @@ export const EditorToggleControls = ({ editor }: Props) => { const [showValidityWarning, setShowValidityWarning] = React.useState(false); const clearWarnings = () => { - if (showMaxDepthWarning) setShowMaxDepthWarning(false); - if (showValidityWarning) setShowValidityWarning(false); + if (showMaxDepthWarning) { + setShowMaxDepthWarning(false); + } + + if (showValidityWarning) { + setShowValidityWarning(false); + } }; if (editor === 'default') { diff --git a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/form_validity.test.ts b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/utils.test.ts similarity index 91% rename from x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/form_validity.test.ts rename to x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/utils.test.ts index 31f404fff6dbb..39912a0cf0c86 100644 --- a/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/form_validity.test.ts +++ b/x-pack/legacy/plugins/index_management/public/components/mappings_editor/lib/utils.test.ts @@ -6,11 +6,10 @@ jest.mock('../constants', () => ({ DATA_TYPE_DEFINITION: {} })); -// FormComponentsArgs will have to be changed with "State" -import { determineIfValid, FormComponentsArgs } from '.'; +import { determineIfValid } from '.'; describe('Mappings Editor form validity', () => { - let components: FormComponentsArgs; + let components: any; it('handles base case', () => { components = { fieldsJsonEditor: { isValid: undefined },