Skip to content

Commit

Permalink
[7.x] [Index Management] Add Mappings Editor to Index Template Wizard (
Browse files Browse the repository at this point in the history
…#47562) (#54864)

* Skip flakey index template component integration tests.
  • Loading branch information
cjcenizal authored Jan 15, 2020
1 parent c131e8d commit c6af2b5
Show file tree
Hide file tree
Showing 188 changed files with 14,376 additions and 475 deletions.
22 changes: 22 additions & 0 deletions src/plugins/es_ui_shared/public/components/json_editor/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export * from './json_editor';

export { OnJsonEditorUpdateHandler } from './use_json';
111 changes: 111 additions & 0 deletions src/plugins/es_ui_shared/public/components/json_editor/json_editor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import React, { useCallback } from 'react';
import { EuiFormRow, EuiCodeEditor } from '@elastic/eui';
import { debounce } from 'lodash';

import { isJSON } from '../../../static/validators/string';
import { useJson, OnJsonEditorUpdateHandler } from './use_json';

interface Props {
onUpdate: OnJsonEditorUpdateHandler;
label?: string;
helpText?: React.ReactNode;
value?: string;
defaultValue?: { [key: string]: any };
euiCodeEditorProps?: { [key: string]: any };
error?: string | null;
}

export const JsonEditor = React.memo(
({
label,
helpText,
onUpdate,
value,
defaultValue,
euiCodeEditorProps,
error: propsError,
}: Props) => {
const isControlled = value !== undefined;

const { content, setContent, error: internalError } = useJson({
defaultValue,
onUpdate,
isControlled,
});

const debouncedSetContent = useCallback(debounce(setContent, 300), [setContent]);

// We let the consumer control the validation and the error message.
const error = isControlled ? propsError : internalError;

const onEuiCodeEditorChange = useCallback(
(updated: string) => {
if (isControlled) {
onUpdate({
data: {
raw: updated,
format() {
return JSON.parse(updated);
},
},
validate() {
return isJSON(updated);
},
isValid: undefined,
});
} else {
debouncedSetContent(updated);
}
},
[isControlled]
);

return (
<EuiFormRow
label={label}
helpText={helpText}
isInvalid={typeof error === 'string'}
error={error}
fullWidth
>
<EuiCodeEditor
mode="json"
theme="textmate"
width="100%"
height="500px"
setOptions={{
showLineNumbers: false,
tabSize: 2,
}}
editorProps={{
$blockScrolling: Infinity,
}}
showGutter={false}
minLines={6}
value={isControlled ? value : content}
onChange={onEuiCodeEditorChange}
{...euiCodeEditorProps}
/>
</EuiFormRow>
);
}
);
94 changes: 94 additions & 0 deletions src/plugins/es_ui_shared/public/components/json_editor/use_json.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { useEffect, useState, useRef } from 'react';
import { i18n } from '@kbn/i18n';

import { isJSON } from '../../../static/validators/string';

export type OnJsonEditorUpdateHandler<T = { [key: string]: any }> = (arg: {
data: {
raw: string;
format(): T;
};
validate(): boolean;
isValid: boolean | undefined;
}) => void;

interface Parameters<T extends object> {
onUpdate: OnJsonEditorUpdateHandler<T>;
defaultValue?: T;
isControlled?: boolean;
}

const stringifyJson = (json: { [key: string]: any }) =>
Object.keys(json).length ? JSON.stringify(json, null, 2) : '{\n\n}';

export const useJson = <T extends object = { [key: string]: any }>({
defaultValue = {} as T,
onUpdate,
isControlled = false,
}: Parameters<T>) => {
const didMount = useRef(false);
const [content, setContent] = useState<string>(stringifyJson(defaultValue));
const [error, setError] = useState<string | null>(null);

const validate = () => {
// We allow empty string as it will be converted to "{}""
const isValid = content.trim() === '' ? true : isJSON(content);
if (!isValid) {
setError(
i18n.translate('esUi.validation.string.invalidJSONError', {
defaultMessage: 'Invalid JSON',
})
);
} else {
setError(null);
}
return isValid;
};

const formatContent = () => {
const isValid = validate();
const data = isValid && content.trim() !== '' ? JSON.parse(content) : {};
return data as T;
};

useEffect(() => {
if (didMount.current) {
const isValid = isControlled ? undefined : validate();
onUpdate({
data: {
raw: content,
format: formatContent,
},
validate,
isValid,
});
} else {
didMount.current = true;
}
}, [content]);

return {
content,
setContent,
error,
};
};
20 changes: 20 additions & 0 deletions src/plugins/es_ui_shared/public/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export * from './components/json_editor';
6 changes: 3 additions & 3 deletions src/plugins/es_ui_shared/static/forms/components/field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
* under the License.
*/

import React from 'react';
import React, { ComponentType } from 'react';
import { FieldHook, FIELD_TYPES } from '../hook_form_lib';

interface Props {
field: FieldHook;
euiFieldProps?: Record<string, any>;
euiFieldProps?: { [key: string]: any };
idAria?: string;
[key: string]: any;
}
Expand All @@ -41,7 +41,7 @@ import {
ToggleField,
} from './fields';

const mapTypeToFieldComponent = {
const mapTypeToFieldComponent: { [key: string]: ComponentType<any> } = {
[FIELD_TYPES.TEXT]: TextField,
[FIELD_TYPES.TEXTAREA]: TextAreaField,
[FIELD_TYPES.NUMBER]: NumericField,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const CheckBoxField = ({ field, euiFieldProps = {}, ...rest }: Props) =>

return (
<EuiFormRow
helpText={field.helpText}
helpText={typeof field.helpText === 'function' ? field.helpText() : field.helpText}
error={errorMessage}
isInvalid={isInvalid}
fullWidth
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export const ComboBoxField = ({ field, euiFieldProps = {}, ...rest }: Props) =>
<EuiFormRow
label={field.label}
labelAppend={field.labelAppend}
helpText={field.helpText}
helpText={typeof field.helpText === 'function' ? field.helpText() : field.helpText}
error={errorMessage}
isInvalid={isInvalid}
fullWidth
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ export * from './select_field';
export * from './super_select_field';
export * from './toggle_field';
export * from './text_area_field';
export * from './json_editor_field';
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import React, { useCallback } from 'react';

import { JsonEditor, OnJsonEditorUpdateHandler } from '../../../../public';
import { FieldHook, getFieldValidityAndErrorMessage } from '../../hook_form_lib';

interface Props {
field: FieldHook;
euiCodeEditorProps?: { [key: string]: any };
[key: string]: any;
}

export const JsonEditorField = ({ field, ...rest }: Props) => {
const { errorMessage } = getFieldValidityAndErrorMessage(field);

const { label, helpText, value, setValue } = field;

const onJsonUpdate: OnJsonEditorUpdateHandler = useCallback<OnJsonEditorUpdateHandler>(
updatedJson => {
setValue(updatedJson.data.raw);
},
[setValue]
);

return (
<JsonEditor
label={label}
helpText={helpText}
value={value as string}
onUpdate={onJsonUpdate}
error={errorMessage}
{...rest}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const MultiSelectField = ({ field, euiFieldProps = {}, ...rest }: Props)
return (
<EuiFormRow
label={field.label}
helpText={field.helpText}
helpText={typeof field.helpText === 'function' ? field.helpText() : field.helpText}
error={errorMessage}
isInvalid={isInvalid}
fullWidth
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const NumericField = ({ field, euiFieldProps = {}, ...rest }: Props) => {
return (
<EuiFormRow
label={field.label}
helpText={field.helpText}
helpText={typeof field.helpText === 'function' ? field.helpText() : field.helpText}
error={errorMessage}
isInvalid={isInvalid}
fullWidth
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const RadioGroupField = ({ field, euiFieldProps = {}, ...rest }: Props) =
return (
<EuiFormRow
label={field.label}
helpText={field.helpText}
helpText={typeof field.helpText === 'function' ? field.helpText() : field.helpText}
error={errorMessage}
isInvalid={isInvalid}
fullWidth
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const RangeField = ({ field, euiFieldProps = {}, ...rest }: Props) => {
return (
<EuiFormRow
label={field.label}
helpText={field.helpText}
helpText={typeof field.helpText === 'function' ? field.helpText() : field.helpText}
error={errorMessage}
isInvalid={isInvalid}
fullWidth
Expand Down
Loading

0 comments on commit c6af2b5

Please sign in to comment.