mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[data views / runtime fields] Fix runtime fields with dots in the name (#160458)
## Summary Composite runtime fields with dots in the name were broken, now fixed. To verify - 1. Create runtime field with dot in the name 2. Make a composite runtime field with subfields with dot in the name 3. Go back and edit those fields Closes: https://github.com/elastic/kibana/issues/159648 ### Release note Fixes creation and editing of composite runtime fields with dots in the names.
This commit is contained in:
parent
a91535202a
commit
b2200e4d33
7 changed files with 44 additions and 31 deletions
|
@ -71,7 +71,7 @@ export const CompositeEditor = ({ onReset }: CompositeEditorProps) => {
|
|||
</EuiFlexGroup>
|
||||
{Object.entries(subfields).map(([key, itemValue], idx) => {
|
||||
return (
|
||||
<div>
|
||||
<div key={key}>
|
||||
<EuiFlexGroup gutterSize="s">
|
||||
<EuiFlexItem>
|
||||
<EuiFieldText value={key} disabled={true} />
|
||||
|
|
|
@ -168,7 +168,7 @@ const FieldEditorComponent = ({ field, onChange, onFormModifiedChange }: Props)
|
|||
useEffect(() => {
|
||||
const existingCompositeField = !!Object.keys(subfields$.getValue() || {}).length;
|
||||
|
||||
const changes$ = getFieldPreviewChanges(fieldPreview$);
|
||||
const changes$ = getFieldPreviewChanges(fieldPreview$, updatedName);
|
||||
|
||||
const subChanges = changes$.subscribe((previewFields) => {
|
||||
const fields = subfields$.getValue();
|
||||
|
@ -199,7 +199,7 @@ const FieldEditorComponent = ({ field, onChange, onFormModifiedChange }: Props)
|
|||
return () => {
|
||||
subChanges.unsubscribe();
|
||||
};
|
||||
}, [form, fieldPreview$, subfields$]);
|
||||
}, [form, fieldPreview$, subfields$, updatedName]);
|
||||
|
||||
useEffect(() => {
|
||||
if (onChange) {
|
||||
|
|
|
@ -10,58 +10,68 @@ import { getFieldPreviewChanges } from './lib';
|
|||
import { BehaviorSubject } from 'rxjs';
|
||||
import { ChangeType, FieldPreview } from '../preview/types';
|
||||
|
||||
// note that periods and overlap in parent and subfield names are to test for corner cases
|
||||
const parentName = 'composite.field';
|
||||
const subfieldName = 'composite.field.a';
|
||||
|
||||
const appendParentName = (key: string) => `${parentName}.${key}`;
|
||||
|
||||
describe('getFieldPreviewChanges', () => {
|
||||
it('should return new keys', (done) => {
|
||||
const subj = new BehaviorSubject<FieldPreview[] | undefined>(undefined);
|
||||
const changes = getFieldPreviewChanges(subj);
|
||||
const changes = getFieldPreviewChanges(subj, parentName);
|
||||
changes.subscribe((change) => {
|
||||
expect(change).toStrictEqual({ hello: { changeType: ChangeType.UPSERT, type: 'keyword' } });
|
||||
expect(change).toStrictEqual({
|
||||
[subfieldName]: { changeType: ChangeType.UPSERT, type: 'keyword' },
|
||||
});
|
||||
done();
|
||||
});
|
||||
subj.next([]);
|
||||
subj.next([{ key: 'hello', value: 'world', type: 'keyword' }]);
|
||||
subj.next([{ key: appendParentName(subfieldName), value: 'world', type: 'keyword' }]);
|
||||
});
|
||||
|
||||
it('should return updated type', (done) => {
|
||||
const subj = new BehaviorSubject<FieldPreview[] | undefined>(undefined);
|
||||
const changes = getFieldPreviewChanges(subj);
|
||||
const changes = getFieldPreviewChanges(subj, parentName);
|
||||
changes.subscribe((change) => {
|
||||
expect(change).toStrictEqual({ hello: { changeType: ChangeType.UPSERT, type: 'long' } });
|
||||
expect(change).toStrictEqual({
|
||||
[subfieldName]: { changeType: ChangeType.UPSERT, type: 'long' },
|
||||
});
|
||||
done();
|
||||
});
|
||||
subj.next([{ key: 'hello', value: 'world', type: 'keyword' }]);
|
||||
subj.next([{ key: 'hello', value: 1, type: 'long' }]);
|
||||
subj.next([{ key: appendParentName(subfieldName), value: 'world', type: 'keyword' }]);
|
||||
subj.next([{ key: appendParentName(subfieldName), value: 1, type: 'long' }]);
|
||||
});
|
||||
|
||||
it('should remove keys', (done) => {
|
||||
const subj = new BehaviorSubject<FieldPreview[] | undefined>(undefined);
|
||||
const changes = getFieldPreviewChanges(subj);
|
||||
const changes = getFieldPreviewChanges(subj, parentName);
|
||||
changes.subscribe((change) => {
|
||||
expect(change).toStrictEqual({ hello: { changeType: ChangeType.DELETE } });
|
||||
expect(change).toStrictEqual({ [subfieldName]: { changeType: ChangeType.DELETE } });
|
||||
done();
|
||||
});
|
||||
subj.next([{ key: 'hello', value: 'world', type: 'keyword' }]);
|
||||
subj.next([{ key: appendParentName(subfieldName), value: 'world', type: 'keyword' }]);
|
||||
subj.next([]);
|
||||
});
|
||||
|
||||
it('should add, update, and remove keys in a single change', (done) => {
|
||||
const subj = new BehaviorSubject<FieldPreview[] | undefined>(undefined);
|
||||
const changes = getFieldPreviewChanges(subj);
|
||||
const changes = getFieldPreviewChanges(subj, parentName);
|
||||
changes.subscribe((change) => {
|
||||
expect(change).toStrictEqual({
|
||||
hello: { changeType: ChangeType.UPSERT, type: 'long' },
|
||||
[subfieldName]: { changeType: ChangeType.UPSERT, type: 'long' },
|
||||
hello2: { changeType: ChangeType.DELETE },
|
||||
hello3: { changeType: ChangeType.UPSERT, type: 'keyword' },
|
||||
});
|
||||
done();
|
||||
});
|
||||
subj.next([
|
||||
{ key: 'hello', value: 'world', type: 'keyword' },
|
||||
{ key: 'hello2', value: 'world', type: 'keyword' },
|
||||
{ key: appendParentName(subfieldName), value: 'world', type: 'keyword' },
|
||||
{ key: appendParentName('hello2'), value: 'world', type: 'keyword' },
|
||||
]);
|
||||
subj.next([
|
||||
{ key: 'hello', value: 1, type: 'long' },
|
||||
{ key: 'hello3', value: 'world', type: 'keyword' },
|
||||
{ key: appendParentName(subfieldName), value: 1, type: 'long' },
|
||||
{ key: appendParentName('hello3'), value: 'world', type: 'keyword' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -88,13 +88,16 @@ export const getNameFieldConfig = (
|
|||
export const valueToComboBoxOption = (value: string) =>
|
||||
RUNTIME_FIELD_OPTIONS_PRIMITIVE.find(({ value: optionValue }) => optionValue === value);
|
||||
|
||||
export const getFieldPreviewChanges = (subject: BehaviorSubject<FieldPreview[] | undefined>) =>
|
||||
export const getFieldPreviewChanges = (
|
||||
subject: BehaviorSubject<FieldPreview[] | undefined>,
|
||||
parentName: string
|
||||
) =>
|
||||
subject.pipe(
|
||||
filter((preview) => preview !== undefined),
|
||||
map((items) =>
|
||||
// reduce the fields to make diffing easier
|
||||
items!.map((item) => {
|
||||
const key = item.key.slice(item.key.search('\\.') + 1);
|
||||
const key = item.key.substring(`${parentName}.`.length);
|
||||
return { name: key, type: item.type! };
|
||||
})
|
||||
),
|
||||
|
|
|
@ -115,6 +115,13 @@ export const FieldPreviewProvider: FunctionComponent<{ controller: PreviewContro
|
|||
return;
|
||||
}
|
||||
|
||||
// Not sure why this is getting called without currentDocIndex
|
||||
// would be much better to prevent this function from being called at all
|
||||
if (!currentDocIndex) {
|
||||
controller.setIsLoadingPreview(false);
|
||||
return;
|
||||
}
|
||||
|
||||
controller.setLastExecutePainlessRequestParams({
|
||||
type,
|
||||
script: script?.source,
|
||||
|
|
|
@ -153,14 +153,7 @@ export const getFieldEditorOpener =
|
|||
|
||||
let field: Field | undefined;
|
||||
if (dataViewField) {
|
||||
if (isExistingRuntimeField && dataViewField.runtimeField!.type === 'composite') {
|
||||
// Composite runtime subfield
|
||||
const [compositeName] = fieldNameToEdit!.split('.');
|
||||
field = {
|
||||
name: compositeName,
|
||||
...dataView.getRuntimeField(compositeName)!,
|
||||
};
|
||||
} else if (isExistingRuntimeField) {
|
||||
if (isExistingRuntimeField) {
|
||||
// Runtime field
|
||||
field = {
|
||||
name: fieldNameToEdit!,
|
||||
|
|
|
@ -32,7 +32,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
|
||||
describe('create composite runtime field', function describeIndexTests() {
|
||||
// Starting with '@' to sort toward start of field list
|
||||
const fieldName = '@composite_test';
|
||||
const fieldName = '@composite.test';
|
||||
|
||||
it('should create runtime field', async function () {
|
||||
await PageObjects.settings.navigateTo();
|
||||
|
@ -42,7 +42,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await log.debug('add runtime field');
|
||||
await PageObjects.settings.addCompositeRuntimeField(
|
||||
fieldName,
|
||||
"emit('a','hello world')",
|
||||
"emit('a.a','hello world')",
|
||||
false,
|
||||
1
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue