Skip to content

Commit

Permalink
Merge branch 'main' of github.com:elastic/kibana into cases-avatars
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathan-buttner committed Sep 12, 2022
2 parents aac7448 + b023912 commit 707c2f1
Show file tree
Hide file tree
Showing 205 changed files with 6,353 additions and 1,709 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ describe('<FieldEditor />', () => {
expect(lastState.submit).toBeDefined();

const { data: formData } = await submitFormAndGetData(lastState);
expect(formData).toEqual(field);
expect(formData).toEqual({ ...field, format: null });

// Make sure that both isValid and isSubmitted state are now "true"
lastState = getLastStateUpdate();
Expand All @@ -128,7 +128,10 @@ describe('<FieldEditor />', () => {
onChange,
},
{
namesNotAllowed: existingFields,
namesNotAllowed: {
fields: existingFields,
runtimeComposites: [],
},
existingConcreteFields: [],
fieldTypeToProcess: 'runtime',
}
Expand Down Expand Up @@ -165,7 +168,10 @@ describe('<FieldEditor />', () => {
onChange,
},
{
namesNotAllowed: existingRuntimeFieldNames,
namesNotAllowed: {
fields: existingRuntimeFieldNames,
runtimeComposites: [],
},
existingConcreteFields: [],
fieldTypeToProcess: 'runtime',
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ describe('<FieldEditorFlyoutContent />', () => {

expect(onSave).toHaveBeenCalled();
const fieldReturned = onSave.mock.calls[onSave.mock.calls.length - 1][0];
expect(fieldReturned).toEqual(field);
expect(fieldReturned).toEqual({ ...field, format: null });
});

test('should accept an onCancel prop', async () => {
Expand Down Expand Up @@ -149,6 +149,7 @@ describe('<FieldEditorFlyoutContent />', () => {
name: 'someName',
type: 'keyword', // default to keyword
script: { source: 'echo("hello")' },
format: null,
});

// Change the type and make sure it is forwarded
Expand All @@ -165,6 +166,7 @@ describe('<FieldEditorFlyoutContent />', () => {
name: 'someName',
type: 'date',
script: { source: 'echo("hello")' },
format: null,
});
});

Expand Down Expand Up @@ -202,6 +204,7 @@ describe('<FieldEditorFlyoutContent />', () => {
name: 'someName',
type: 'keyword',
script: { source: 'echo("hello")' },
format: null,
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -813,4 +813,48 @@ describe('Field editor Preview panel', () => {
expect(exists('previewNotAvailableCallout')).toBe(true);
});
});

describe('composite runtime field', () => {
test('should display composite editor when composite type is selected', async () => {
testBed = await setup();
const {
exists,
actions: { fields, waitForUpdates },
} = testBed;
fields.updateType('composite', 'Composite');
await waitForUpdates();
expect(exists('compositeEditor')).toBe(true);
});

test('should show composite field types and update appropriately', async () => {
httpRequestsMockHelpers.setFieldPreviewResponse({ values: { 'composite_field.a': [1] } });
testBed = await setup();
const {
exists,
actions: { fields, waitForUpdates },
} = testBed;
await fields.updateType('composite', 'Composite');
await fields.updateScript("emit('a',1)");
await waitForUpdates();
expect(exists('typeField_0')).toBe(true);

// increase the number of fields
httpRequestsMockHelpers.setFieldPreviewResponse({
values: { 'composite_field.a': [1], 'composite_field.b': [1] },
});
await fields.updateScript("emit('a',1); emit('b',1)");
await waitForUpdates();
expect(exists('typeField_0')).toBe(true);
expect(exists('typeField_1')).toBe(true);

// decrease the number of fields
httpRequestsMockHelpers.setFieldPreviewResponse({
values: { 'composite_field.a': [1] },
});
await fields.updateScript("emit('a',1)");
await waitForUpdates();
expect(exists('typeField_0')).toBe(true);
expect(exists('typeField_1')).toBe(false);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import './jest.mocks';
import React, { FunctionComponent } from 'react';
import { merge } from 'lodash';

import { defer } from 'rxjs';
import { defer, BehaviorSubject } from 'rxjs';
import { notificationServiceMock, uiSettingsServiceMock } from '@kbn/core/public/mocks';
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
import { fieldFormatsMock as fieldFormats } from '@kbn/field-formats-plugin/common/mocks';
Expand All @@ -21,6 +21,7 @@ import { FieldEditorProvider, Context } from '../../../public/components/field_e
import { FieldPreviewProvider } from '../../../public/components/preview';
import { initApi, ApiService } from '../../../public/lib';
import { init as initHttpRequests } from './http_requests';
import { RuntimeFieldSubFields } from '../../../public/shared_imports';

const dataStart = dataPluginMock.createStartContract();
const { search } = dataStart;
Expand Down Expand Up @@ -124,7 +125,7 @@ export const WithFieldEditorDependencies =
uiSettings: uiSettingsServiceMock.createStartContract(),
fieldTypeToProcess: 'runtime',
existingConcreteFields: [],
namesNotAllowed: [],
namesNotAllowed: { fields: [], runtimeComposites: [] },
links: {
runtimePainless: 'https://elastic.co',
},
Expand All @@ -138,6 +139,8 @@ export const WithFieldEditorDependencies =
getById: () => undefined,
},
fieldFormats,
fieldName$: new BehaviorSubject(''),
subfields$: new BehaviorSubject<RuntimeFieldSubFields | undefined>(undefined),
};

const mergedDependencies = merge({}, dependencies, overridingDependencies);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@ import { CloseEditor } from '../types';
type DeleteFieldFunc = (fieldName: string | string[]) => void;
export interface Props {
children: (deleteFieldHandler: DeleteFieldFunc) => React.ReactNode;
/**
* Data view of fields to be deleted
*/
dataView: DataView;
/**
* Callback fired when fields are deleted
* @param fieldNames - the names of the deleted fields
*/
onDelete?: (fieldNames: string[]) => void;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import React from 'react';
import {
EuiNotificationBadge,
EuiFlexGroup,
EuiFlexItem,
EuiSpacer,
EuiText,
EuiFieldText,
EuiComboBox,
EuiFormRow,
EuiButtonEmpty,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import useObservable from 'react-use/lib/useObservable';
import { FormattedMessage } from '@kbn/i18n-react';
import { ScriptField } from './form_fields';
import { useFieldEditorContext } from '../field_editor_context';
import { RUNTIME_FIELD_OPTIONS_PRIMITIVE } from './constants';
import { valueToComboBoxOption } from './lib';
import { RuntimePrimitiveTypes } from '../../shared_imports';

export interface CompositeEditorProps {
onReset: () => void;
}

export const CompositeEditor = ({ onReset }: CompositeEditorProps) => {
const { links, existingConcreteFields, subfields$ } = useFieldEditorContext();
const subfields = useObservable(subfields$) || {};

return (
<div data-test-subj="compositeEditor">
<ScriptField
existingConcreteFields={existingConcreteFields}
links={links}
placeholder={"emit('field_name', 'hello world');"}
/>
<EuiSpacer size="xl" />
<>
<EuiFlexGroup gutterSize="s" alignItems="center" justifyContent="spaceBetween">
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
<EuiText size="s">
<FormattedMessage
id="indexPatternFieldEditor.editor.compositeFieldsCount"
defaultMessage="Generated fields"
/>
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiNotificationBadge color="subdued">
{Object.entries(subfields).length}
</EuiNotificationBadge>
</EuiFlexItem>
</EuiFlexGroup>
<EuiFlexItem grow={false}>
<EuiButtonEmpty flush="right" iconType="refresh" onClick={onReset}>
<FormattedMessage
id="indexPatternFieldEditor.editor.compositeRefreshTypes"
defaultMessage="Reset"
/>
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
{Object.entries(subfields).map(([key, itemValue], idx) => {
return (
<div>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<EuiFieldText value={key} disabled={true} />
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow fullWidth>
<EuiComboBox
placeholder={i18n.translate(
'indexPatternFieldEditor.editor.form.runtimeType.placeholderLabel',
{
defaultMessage: 'Select a type',
}
)}
singleSelection={{ asPlainText: true }}
options={RUNTIME_FIELD_OPTIONS_PRIMITIVE}
selectedOptions={[valueToComboBoxOption(itemValue.type)!]}
onChange={(newValue) => {
if (newValue.length === 0) {
// Don't allow clearing the type. One must always be selected
return;
}
// update the type for the given field
subfields[key] = { type: newValue[0].value! as RuntimePrimitiveTypes };

subfields$.next({ ...subfields });
}}
isClearable={false}
data-test-subj={`typeField_${idx}`}
aria-label={i18n.translate(
'indexPatternFieldEditor.editor.form.typeSelectAriaLabel',
{
defaultMessage: 'Type select',
}
)}
fullWidth
/>
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGroup>
</div>
);
})}
</>
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import type { EuiComboBoxOptionOption } from '@elastic/eui';
import { RuntimeType } from '../../shared_imports';

export const RUNTIME_FIELD_OPTIONS: Array<EuiComboBoxOptionOption<RuntimeType>> = [
export const RUNTIME_FIELD_OPTIONS_PRIMITIVE: Array<EuiComboBoxOptionOption<RuntimeType>> = [
{
label: 'Keyword',
value: 'keyword',
Expand Down Expand Up @@ -39,3 +39,11 @@ export const RUNTIME_FIELD_OPTIONS: Array<EuiComboBoxOptionOption<RuntimeType>>
value: 'geo_point',
},
];

export const RUNTIME_FIELD_OPTIONS = [
...RUNTIME_FIELD_OPTIONS_PRIMITIVE,
{
label: 'Composite',
value: 'composite',
} as EuiComboBoxOptionOption<RuntimeType>,
];
Loading

0 comments on commit 707c2f1

Please sign in to comment.