Skip to content

Commit 183ed1e

Browse files
author
Sébastien Loix
authored
[Mappings editor] Add json editor to edit field settings (#47674)
1 parent c9ffd0f commit 183ed1e

12 files changed

Lines changed: 295 additions & 168 deletions

File tree

src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export function useForm<T extends object = FormData>(
5252
const [isValid, setIsValid] = useState<boolean | undefined>(undefined);
5353
const fieldsRefs = useRef<FieldsMap>({});
5454
const formUpdateSubscribers = useRef<Subscription[]>([]);
55+
const isUnmounted = useRef<boolean>(false);
5556

5657
// formData$ is an observable we can subscribe to in order to receive live
5758
// update of the raw form data. As an observable it does not trigger any React
@@ -64,6 +65,7 @@ export function useForm<T extends object = FormData>(
6465
return () => {
6566
formUpdateSubscribers.current.forEach(subscription => subscription.unsubscribe());
6667
formUpdateSubscribers.current = [];
68+
isUnmounted.current = true;
6769
};
6870
}, []);
6971

@@ -225,7 +227,9 @@ export function useForm<T extends object = FormData>(
225227
const validate = async () => await validateAllFields();
226228

227229
const subscription = formData$.current.subscribe(raw => {
228-
handler({ isValid, data: { raw, format }, validate });
230+
if (!isUnmounted.current) {
231+
handler({ isValid, data: { raw, format }, validate });
232+
}
229233
});
230234

231235
formUpdateSubscribers.current.push(subscription);

x-pack/legacy/plugins/index_management/public/components/json_editor/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@
55
*/
66

77
export * from './json_editor';
8+
9+
export { OnUpdateHandler } from './use_json';

x-pack/legacy/plugins/index_management/public/components/json_editor/use_json.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ import { i18n } from '@kbn/i18n';
1010
import { isJSON } from '../../../../../../../src/plugins/es_ui_shared/static/validators/string';
1111

1212
export type OnUpdateHandler<T = { [key: string]: any }> = (arg: {
13-
getData(): T;
13+
data: {
14+
raw: string;
15+
format(): T;
16+
};
1417
validate(): boolean;
1518
isValid: boolean;
1619
}) => void;
@@ -45,7 +48,7 @@ export const useJson = <T extends object = { [key: string]: any }>({
4548
return isValid;
4649
};
4750

48-
const getData = () => {
51+
const formatContent = () => {
4952
const isValid = validate();
5053
const data = isValid && content.trim() !== '' ? JSON.parse(content) : {};
5154
return data as T;
@@ -54,7 +57,10 @@ export const useJson = <T extends object = { [key: string]: any }>({
5457
useEffect(() => {
5558
const isValid = validate();
5659
onUpdate({
57-
getData,
60+
data: {
61+
raw: content,
62+
format: formatContent,
63+
},
5864
validate,
5965
isValid,
6066
});

x-pack/legacy/plugins/index_management/public/components/mappings_editor/components/document_fields/fields/edit_field.tsx

Lines changed: 0 additions & 139 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
import React, { useRef, useEffect } from 'react';
7+
import {
8+
EuiFlyout,
9+
EuiFlyoutHeader,
10+
EuiFlyoutBody,
11+
EuiFlyoutFooter,
12+
EuiTitle,
13+
EuiButton,
14+
EuiFlexGroup,
15+
EuiFlexItem,
16+
} from '@elastic/eui';
17+
18+
import { useForm, Form, ValidationFunc, OnFormUpdateArg } from '../../../../shared_imports';
19+
import { OnUpdateHandler } from '../../../../../json_editor';
20+
import { useDispatch } from '../../../../mappings_state';
21+
import { Field, NormalizedField } from '../../../../types';
22+
import { UpdateFieldProvider, UpdateFieldFunc } from './update_field_provider';
23+
import { EditFieldHeaderForm } from './edit_field_header_form';
24+
import { FieldSettingsJsonEditor } from './field_settings_json_editor';
25+
26+
const formWrapper = (props: any) => <form {...props} />;
27+
28+
interface Props {
29+
field: NormalizedField;
30+
uniqueNameValidator: ValidationFunc;
31+
}
32+
33+
export const EditField = React.memo(({ field, uniqueNameValidator }: Props) => {
34+
const { form } = useForm<Field>({ defaultValue: field.source });
35+
const dispatch = useDispatch();
36+
37+
const fieldsSettings = useRef<Parameters<OnUpdateHandler>[0] | undefined>(undefined);
38+
const fieldFormUpdate = useRef<OnFormUpdateArg<Field> | undefined>(undefined);
39+
40+
const getSubmitForm = (updateField: UpdateFieldFunc) => async (e?: React.FormEvent) => {
41+
if (e) {
42+
e.preventDefault();
43+
}
44+
45+
const { isValid: isFormValid, data: formData } = await form.submit();
46+
47+
const {
48+
isValid: isFieldsSettingsValid,
49+
data: { format: getFieldsSettingsData },
50+
} = fieldsSettings.current!;
51+
52+
if (isFormValid && isFieldsSettingsValid) {
53+
const fieldsSettingsData = getFieldsSettingsData();
54+
updateField({ ...field, source: { ...formData, ...fieldsSettingsData } });
55+
}
56+
};
57+
58+
const getUpdatedField = (): OnFormUpdateArg<Field> | void => {
59+
if (fieldFormUpdate.current === undefined || fieldsSettings.current === undefined) {
60+
return;
61+
}
62+
63+
const isFormValid = fieldFormUpdate.current.isValid;
64+
const isFieldsSettingsValid = fieldsSettings.current.isValid;
65+
66+
return {
67+
isValid: isFormValid === undefined ? undefined : isFormValid && isFieldsSettingsValid,
68+
data: {
69+
raw: { ...fieldFormUpdate.current.data.raw, settings: fieldsSettings.current.data.raw },
70+
format() {
71+
return {
72+
...fieldFormUpdate.current!.data.format(),
73+
...fieldsSettings.current!.data.format(),
74+
};
75+
},
76+
},
77+
validate: async () => {
78+
const isFieldFormValid = await fieldFormUpdate.current!.validate();
79+
return isFieldFormValid && fieldsSettings.current!.isValid;
80+
},
81+
};
82+
};
83+
84+
useEffect(() => {
85+
const subscription = form.subscribe(updatedFieldForm => {
86+
fieldFormUpdate.current = updatedFieldForm;
87+
88+
const updatedField = getUpdatedField();
89+
if (updatedField) {
90+
dispatch({ type: 'fieldForm.update', value: updatedField });
91+
}
92+
});
93+
94+
return subscription.unsubscribe;
95+
}, [form]);
96+
97+
const onFieldsSettingsUpdate: OnUpdateHandler = fieldsSettingsUpdate => {
98+
fieldsSettings.current = fieldsSettingsUpdate;
99+
100+
const updatedField = getUpdatedField();
101+
if (updatedField) {
102+
dispatch({ type: 'fieldForm.update', value: updatedField });
103+
}
104+
};
105+
106+
const exitEdit = () => {
107+
dispatch({ type: 'documentField.changeStatus', value: 'idle' });
108+
};
109+
110+
const cancel = () => {
111+
exitEdit();
112+
};
113+
114+
const {
115+
source: { name, type, ...fieldsSettingsDefault },
116+
} = field;
117+
118+
return (
119+
<UpdateFieldProvider>
120+
{updateField => (
121+
<EuiFlyout
122+
data-test-subj="mappingsEditorFieldEdit"
123+
onClose={exitEdit}
124+
aria-labelledby="mappingsEditorFieldEditTitle"
125+
size="m"
126+
maxWidth={400}
127+
>
128+
<EuiFlyoutHeader>
129+
<EuiTitle size="m">
130+
<h2>Edit field '{field.source.name}'</h2>
131+
</EuiTitle>
132+
</EuiFlyoutHeader>
133+
134+
<EuiFlyoutBody>
135+
<Form
136+
form={form}
137+
style={{ padding: '20px 0' }}
138+
FormWrapper={formWrapper}
139+
onSubmit={getSubmitForm(updateField)}
140+
>
141+
<EditFieldHeaderForm uniqueNameValidator={uniqueNameValidator} />
142+
</Form>
143+
<FieldSettingsJsonEditor
144+
onUpdate={onFieldsSettingsUpdate}
145+
defaultValue={fieldsSettingsDefault}
146+
/>
147+
</EuiFlyoutBody>
148+
149+
<EuiFlyoutFooter>
150+
<EuiFlexGroup>
151+
<EuiFlexItem>
152+
<EuiButton onClick={getSubmitForm(updateField)} type="submit">
153+
Update
154+
</EuiButton>
155+
</EuiFlexItem>
156+
<EuiFlexItem>
157+
<EuiButton onClick={cancel}>Cancel</EuiButton>
158+
</EuiFlexItem>
159+
</EuiFlexGroup>
160+
</EuiFlyoutFooter>
161+
</EuiFlyout>
162+
)}
163+
</UpdateFieldProvider>
164+
);
165+
});

0 commit comments

Comments
 (0)