Skip to content

Commit ae99ecb

Browse files
jloleysenscjcenizal
authored andcommitted
[Index Management] Add Mappings Editor to Index Template Wizard (#47562)
1 parent 5320fbb commit ae99ecb

188 files changed

Lines changed: 14375 additions & 475 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
export * from './json_editor';
21+
22+
export { OnJsonEditorUpdateHandler } from './use_json';
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
import React, { useCallback } from 'react';
21+
import { EuiFormRow, EuiCodeEditor } from '@elastic/eui';
22+
import { debounce } from 'lodash';
23+
24+
import { isJSON } from '../../../static/validators/string';
25+
import { useJson, OnJsonEditorUpdateHandler } from './use_json';
26+
27+
interface Props {
28+
onUpdate: OnJsonEditorUpdateHandler;
29+
label?: string;
30+
helpText?: React.ReactNode;
31+
value?: string;
32+
defaultValue?: { [key: string]: any };
33+
euiCodeEditorProps?: { [key: string]: any };
34+
error?: string | null;
35+
}
36+
37+
export const JsonEditor = React.memo(
38+
({
39+
label,
40+
helpText,
41+
onUpdate,
42+
value,
43+
defaultValue,
44+
euiCodeEditorProps,
45+
error: propsError,
46+
}: Props) => {
47+
const isControlled = value !== undefined;
48+
49+
const { content, setContent, error: internalError } = useJson({
50+
defaultValue,
51+
onUpdate,
52+
isControlled,
53+
});
54+
55+
const debouncedSetContent = useCallback(debounce(setContent, 300), [setContent]);
56+
57+
// We let the consumer control the validation and the error message.
58+
const error = isControlled ? propsError : internalError;
59+
60+
const onEuiCodeEditorChange = useCallback(
61+
(updated: string) => {
62+
if (isControlled) {
63+
onUpdate({
64+
data: {
65+
raw: updated,
66+
format() {
67+
return JSON.parse(updated);
68+
},
69+
},
70+
validate() {
71+
return isJSON(updated);
72+
},
73+
isValid: undefined,
74+
});
75+
} else {
76+
debouncedSetContent(updated);
77+
}
78+
},
79+
[isControlled]
80+
);
81+
82+
return (
83+
<EuiFormRow
84+
label={label}
85+
helpText={helpText}
86+
isInvalid={typeof error === 'string'}
87+
error={error}
88+
fullWidth
89+
>
90+
<EuiCodeEditor
91+
mode="json"
92+
theme="textmate"
93+
width="100%"
94+
height="500px"
95+
setOptions={{
96+
showLineNumbers: false,
97+
tabSize: 2,
98+
}}
99+
editorProps={{
100+
$blockScrolling: Infinity,
101+
}}
102+
showGutter={false}
103+
minLines={6}
104+
value={isControlled ? value : content}
105+
onChange={onEuiCodeEditorChange}
106+
{...euiCodeEditorProps}
107+
/>
108+
</EuiFormRow>
109+
);
110+
}
111+
);
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
import { useEffect, useState, useRef } from 'react';
21+
import { i18n } from '@kbn/i18n';
22+
23+
import { isJSON } from '../../../static/validators/string';
24+
25+
export type OnJsonEditorUpdateHandler<T = { [key: string]: any }> = (arg: {
26+
data: {
27+
raw: string;
28+
format(): T;
29+
};
30+
validate(): boolean;
31+
isValid: boolean | undefined;
32+
}) => void;
33+
34+
interface Parameters<T extends object> {
35+
onUpdate: OnJsonEditorUpdateHandler<T>;
36+
defaultValue?: T;
37+
isControlled?: boolean;
38+
}
39+
40+
const stringifyJson = (json: { [key: string]: any }) =>
41+
Object.keys(json).length ? JSON.stringify(json, null, 2) : '{\n\n}';
42+
43+
export const useJson = <T extends object = { [key: string]: any }>({
44+
defaultValue = {} as T,
45+
onUpdate,
46+
isControlled = false,
47+
}: Parameters<T>) => {
48+
const didMount = useRef(false);
49+
const [content, setContent] = useState<string>(stringifyJson(defaultValue));
50+
const [error, setError] = useState<string | null>(null);
51+
52+
const validate = () => {
53+
// We allow empty string as it will be converted to "{}""
54+
const isValid = content.trim() === '' ? true : isJSON(content);
55+
if (!isValid) {
56+
setError(
57+
i18n.translate('esUi.validation.string.invalidJSONError', {
58+
defaultMessage: 'Invalid JSON',
59+
})
60+
);
61+
} else {
62+
setError(null);
63+
}
64+
return isValid;
65+
};
66+
67+
const formatContent = () => {
68+
const isValid = validate();
69+
const data = isValid && content.trim() !== '' ? JSON.parse(content) : {};
70+
return data as T;
71+
};
72+
73+
useEffect(() => {
74+
if (didMount.current) {
75+
const isValid = isControlled ? undefined : validate();
76+
onUpdate({
77+
data: {
78+
raw: content,
79+
format: formatContent,
80+
},
81+
validate,
82+
isValid,
83+
});
84+
} else {
85+
didMount.current = true;
86+
}
87+
}, [content]);
88+
89+
return {
90+
content,
91+
setContent,
92+
error,
93+
};
94+
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
export * from './components/json_editor';

src/plugins/es_ui_shared/static/forms/components/field.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717
* under the License.
1818
*/
1919

20-
import React from 'react';
20+
import React, { ComponentType } from 'react';
2121
import { FieldHook, FIELD_TYPES } from '../hook_form_lib';
2222

2323
interface Props {
2424
field: FieldHook;
25-
euiFieldProps?: Record<string, any>;
25+
euiFieldProps?: { [key: string]: any };
2626
idAria?: string;
2727
[key: string]: any;
2828
}
@@ -41,7 +41,7 @@ import {
4141
ToggleField,
4242
} from './fields';
4343

44-
const mapTypeToFieldComponent = {
44+
const mapTypeToFieldComponent: { [key: string]: ComponentType<any> } = {
4545
[FIELD_TYPES.TEXT]: TextField,
4646
[FIELD_TYPES.TEXTAREA]: TextAreaField,
4747
[FIELD_TYPES.NUMBER]: NumericField,

src/plugins/es_ui_shared/static/forms/components/fields/checkbox_field.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const CheckBoxField = ({ field, euiFieldProps = {}, ...rest }: Props) =>
3535

3636
return (
3737
<EuiFormRow
38-
helpText={field.helpText}
38+
helpText={typeof field.helpText === 'function' ? field.helpText() : field.helpText}
3939
error={errorMessage}
4040
isInvalid={isInvalid}
4141
fullWidth

src/plugins/es_ui_shared/static/forms/components/fields/combobox_field.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export const ComboBoxField = ({ field, euiFieldProps = {}, ...rest }: Props) =>
8383
<EuiFormRow
8484
label={field.label}
8585
labelAppend={field.labelAppend}
86-
helpText={field.helpText}
86+
helpText={typeof field.helpText === 'function' ? field.helpText() : field.helpText}
8787
error={errorMessage}
8888
isInvalid={isInvalid}
8989
fullWidth

src/plugins/es_ui_shared/static/forms/components/fields/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ export * from './select_field';
2828
export * from './super_select_field';
2929
export * from './toggle_field';
3030
export * from './text_area_field';
31+
export * from './json_editor_field';
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
import React, { useCallback } from 'react';
21+
22+
import { JsonEditor, OnJsonEditorUpdateHandler } from '../../../../public';
23+
import { FieldHook, getFieldValidityAndErrorMessage } from '../../hook_form_lib';
24+
25+
interface Props {
26+
field: FieldHook;
27+
euiCodeEditorProps?: { [key: string]: any };
28+
[key: string]: any;
29+
}
30+
31+
export const JsonEditorField = ({ field, ...rest }: Props) => {
32+
const { errorMessage } = getFieldValidityAndErrorMessage(field);
33+
34+
const { label, helpText, value, setValue } = field;
35+
36+
const onJsonUpdate: OnJsonEditorUpdateHandler = useCallback<OnJsonEditorUpdateHandler>(
37+
updatedJson => {
38+
setValue(updatedJson.data.raw);
39+
},
40+
[setValue]
41+
);
42+
43+
return (
44+
<JsonEditor
45+
label={label}
46+
helpText={helpText}
47+
value={value as string}
48+
onUpdate={onJsonUpdate}
49+
error={errorMessage}
50+
{...rest}
51+
/>
52+
);
53+
};

src/plugins/es_ui_shared/static/forms/components/fields/multi_select_field.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const MultiSelectField = ({ field, euiFieldProps = {}, ...rest }: Props)
3535
return (
3636
<EuiFormRow
3737
label={field.label}
38-
helpText={field.helpText}
38+
helpText={typeof field.helpText === 'function' ? field.helpText() : field.helpText}
3939
error={errorMessage}
4040
isInvalid={isInvalid}
4141
fullWidth

0 commit comments

Comments
 (0)