mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
Integrate painless autocomplete in runtime fields editor (#84943)
This commit is contained in:
parent
d19b558c88
commit
079a7e82ba
11 changed files with 82 additions and 24 deletions
|
@ -90,8 +90,12 @@ interface Context {
|
|||
* An array of existing concrete fields. If the user gives a name to the runtime
|
||||
* field that matches one of the concrete fields, a callout will be displayed
|
||||
* to indicate that this runtime field will shadow the concrete field.
|
||||
* This array is also used to provide the list of field autocomplete suggestions to the code editor
|
||||
*/
|
||||
existingConcreteFields?: string[];
|
||||
existingConcreteFields?: Array<{
|
||||
name: string;
|
||||
type: string;
|
||||
}>;
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ describe('Runtime field editor', () => {
|
|||
});
|
||||
|
||||
test('should accept a list of existing concrete fields and display a callout when shadowing one of the fields', async () => {
|
||||
const existingConcreteFields = ['myConcreteField'];
|
||||
const existingConcreteFields = [{ name: 'myConcreteField', type: 'keyword' }];
|
||||
|
||||
testBed = setup({ onChange, docLinks, ctx: { existingConcreteFields } });
|
||||
|
||||
|
@ -87,7 +87,7 @@ describe('Runtime field editor', () => {
|
|||
expect(exists('shadowingFieldCallout')).toBe(false);
|
||||
|
||||
await act(async () => {
|
||||
form.setInputValue('nameField.input', existingConcreteFields[0]);
|
||||
form.setInputValue('nameField.input', existingConcreteFields[0].name);
|
||||
});
|
||||
component.update();
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
* 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, { useEffect } from 'react';
|
||||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { PainlessLang } from '@kbn/monaco';
|
||||
import { PainlessLang, PainlessContext } from '@kbn/monaco';
|
||||
import {
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
|
@ -28,7 +28,7 @@ import {
|
|||
ValidationFunc,
|
||||
FieldConfig,
|
||||
} from '../../shared_imports';
|
||||
import { RuntimeField } from '../../types';
|
||||
import { RuntimeField, RuntimeType } from '../../types';
|
||||
import { RUNTIME_FIELD_OPTIONS } from '../../constants';
|
||||
import { schema } from './schema';
|
||||
|
||||
|
@ -38,6 +38,11 @@ export interface FormState {
|
|||
submit: FormHook<RuntimeField>['submit'];
|
||||
}
|
||||
|
||||
interface Field {
|
||||
name: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface Props {
|
||||
links: {
|
||||
runtimePainless: string;
|
||||
|
@ -54,8 +59,9 @@ export interface Props {
|
|||
* An array of existing concrete fields. If the user gives a name to the runtime
|
||||
* field that matches one of the concrete fields, a callout will be displayed
|
||||
* to indicate that this runtime field will shadow the concrete field.
|
||||
* It is also used to provide the list of field autocomplete suggestions to the code editor.
|
||||
*/
|
||||
existingConcreteFields?: string[];
|
||||
existingConcreteFields?: Field[];
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -105,18 +111,51 @@ const getNameFieldConfig = (
|
|||
};
|
||||
};
|
||||
|
||||
const mapReturnTypeToPainlessContext = (runtimeType: RuntimeType): PainlessContext => {
|
||||
switch (runtimeType) {
|
||||
case 'keyword':
|
||||
return 'string_script_field_script_field';
|
||||
case 'long':
|
||||
return 'long_script_field_script_field';
|
||||
case 'double':
|
||||
return 'double_script_field_script_field';
|
||||
case 'date':
|
||||
return 'date_script_field';
|
||||
case 'ip':
|
||||
return 'ip_script_field_script_field';
|
||||
case 'boolean':
|
||||
return 'boolean_script_field_script_field';
|
||||
default:
|
||||
return 'string_script_field_script_field';
|
||||
}
|
||||
};
|
||||
|
||||
const RuntimeFieldFormComp = ({
|
||||
defaultValue,
|
||||
onChange,
|
||||
links,
|
||||
ctx: { namesNotAllowed, existingConcreteFields = [] } = {},
|
||||
}: Props) => {
|
||||
const typeFieldConfig = schema.type as FieldConfig<RuntimeType, RuntimeField>;
|
||||
|
||||
const [painlessContext, setPainlessContext] = useState<PainlessContext>(
|
||||
mapReturnTypeToPainlessContext(typeFieldConfig!.defaultValue!)
|
||||
);
|
||||
const { form } = useForm<RuntimeField>({ defaultValue, schema });
|
||||
const { submit, isValid: isFormValid, isSubmitted } = form;
|
||||
const [{ name }] = useFormData<RuntimeField>({ form, watch: 'name' });
|
||||
|
||||
const nameFieldConfig = getNameFieldConfig(namesNotAllowed, defaultValue);
|
||||
|
||||
const onTypeChange = useCallback((newType: Array<EuiComboBoxOptionOption<RuntimeType>>) => {
|
||||
setPainlessContext(mapReturnTypeToPainlessContext(newType[0]!.value!));
|
||||
}, []);
|
||||
|
||||
const suggestionProvider = PainlessLang.getSuggestionProvider(
|
||||
painlessContext,
|
||||
existingConcreteFields
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (onChange) {
|
||||
onChange({ isValid: isFormValid, isSubmitted, submit });
|
||||
|
@ -145,7 +184,10 @@ const RuntimeFieldFormComp = ({
|
|||
|
||||
{/* Return type */}
|
||||
<EuiFlexItem>
|
||||
<UseField<EuiComboBoxOptionOption[]> path="type">
|
||||
<UseField<Array<EuiComboBoxOptionOption<RuntimeType>>>
|
||||
path="type"
|
||||
onChange={onTypeChange}
|
||||
>
|
||||
{({ label, value, setValue }) => {
|
||||
if (value === undefined) {
|
||||
return null;
|
||||
|
@ -185,7 +227,7 @@ const RuntimeFieldFormComp = ({
|
|||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
{existingConcreteFields.includes(name) && (
|
||||
{existingConcreteFields.find((field) => field.name === name) && (
|
||||
<>
|
||||
<EuiSpacer />
|
||||
<EuiCallOut
|
||||
|
@ -237,6 +279,7 @@ const RuntimeFieldFormComp = ({
|
|||
>
|
||||
<CodeEditor
|
||||
languageId={PainlessLang.ID}
|
||||
suggestionProvider={suggestionProvider}
|
||||
width="100%"
|
||||
height="300px"
|
||||
value={value}
|
||||
|
@ -250,6 +293,9 @@ const RuntimeFieldFormComp = ({
|
|||
wordWrap: 'on',
|
||||
wrappingIndent: 'indent',
|
||||
automaticLayout: true,
|
||||
suggest: {
|
||||
snippetsPreventQuickSuggestions: false,
|
||||
},
|
||||
}}
|
||||
data-test-subj="scriptField"
|
||||
aria-label={i18n.translate('xpack.runtimeFields.form.scriptEditorAriaLabel', {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue