Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Visualize] Allows editing broken visualizations caused by runtime fields changes #94798

Merged
merged 22 commits into from
Apr 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export declare enum KBN_FIELD_TYPES
| HISTOGRAM | <code>&quot;histogram&quot;</code> | |
| IP | <code>&quot;ip&quot;</code> | |
| IP\_RANGE | <code>&quot;ip_range&quot;</code> | |
| MISSING | <code>&quot;missing&quot;</code> | |
| MURMUR3 | <code>&quot;murmur3&quot;</code> | |
| NESTED | <code>&quot;nested&quot;</code> | |
| NUMBER | <code>&quot;number&quot;</code> | |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export declare enum KBN_FIELD_TYPES
| HISTOGRAM | <code>&quot;histogram&quot;</code> | |
| IP | <code>&quot;ip&quot;</code> | |
| IP\_RANGE | <code>&quot;ip_range&quot;</code> | |
| MISSING | <code>&quot;missing&quot;</code> | |
| MURMUR3 | <code>&quot;murmur3&quot;</code> | |
| NESTED | <code>&quot;nested&quot;</code> | |
| NUMBER | <code>&quot;number&quot;</code> | |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ Merges input$ and output$ streams and debounces emit till next macro-task. Could
<b>Signature:</b>

```typescript
getUpdated$(): Readonly<Rx.Observable<void>>;
getUpdated$(): Readonly<Rx.Observable<TEmbeddableInput | TEmbeddableOutput>>;
```
<b>Returns:</b>

`Readonly<Rx.Observable<void>>`
`Readonly<Rx.Observable<TEmbeddableInput | TEmbeddableOutput>>`

1 change: 1 addition & 0 deletions src/plugins/data/common/kbn_field_types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,5 @@ export enum KBN_FIELD_TYPES {
OBJECT = 'object',
NESTED = 'nested',
HISTOGRAM = 'histogram',
MISSING = 'missing',
}
2 changes: 1 addition & 1 deletion src/plugins/data/common/search/aggs/agg_configs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ describe('AggConfigs', () => {
describe('#toDsl', () => {
beforeEach(() => {
indexPattern = stubIndexPattern as IndexPattern;
indexPattern.fields.getByName = (name) => (name as unknown) as IndexPatternField;
indexPattern.fields.getByName = (name) => (({ name } as unknown) as IndexPatternField);
});

it('uses the sorted aggs', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,33 @@ import { AggConfigs, CreateAggConfigParams } from '../agg_configs';
import { BUCKET_TYPES } from './bucket_agg_types';
import { IBucketAggConfig } from './bucket_agg_type';
import { mockAggTypesRegistry } from '../test_helpers';
import type { IndexPatternField } from '../../../index_patterns';
import { IndexPattern } from '../../../index_patterns/index_patterns/index_pattern';

const indexPattern = {
id: '1234',
title: 'logstash-*',
fields: [
{
name: 'field',
name: 'machine.os.raw',
type: 'string',
esTypes: ['string'],
aggregatable: true,
filterable: true,
searchable: true,
},
{
name: 'geo.src',
type: 'string',
esTypes: ['string'],
aggregatable: true,
filterable: true,
searchable: true,
},
],
} as any;
} as IndexPattern;

indexPattern.fields.getByName = (name) => (({ name } as unknown) as IndexPatternField);

const singleTerm = {
aggs: [
Expand Down
78 changes: 60 additions & 18 deletions src/plugins/data/common/search/aggs/buckets/terms.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,53 @@ import { AggConfigs } from '../agg_configs';
import { METRIC_TYPES } from '../metrics';
import { mockAggTypesRegistry } from '../test_helpers';
import { BUCKET_TYPES } from './bucket_agg_types';
import type { IndexPatternField } from '../../../index_patterns';
import { IndexPattern } from '../../../index_patterns/index_patterns/index_pattern';

describe('Terms Agg', () => {
describe('order agg editor UI', () => {
const getAggConfigs = (params: Record<string, any> = {}) => {
const indexPattern = {
id: '1234',
title: 'logstash-*',
fields: {
getByName: () => field,
filter: () => [field],
},
} as any;
fields: [
{
name: 'field',
type: 'string',
esTypes: ['string'],
aggregatable: true,
filterable: true,
searchable: true,
},
{
name: 'string_field',
type: 'string',
esTypes: ['string'],
aggregatable: true,
filterable: true,
searchable: true,
},
{
name: 'empty_number_field',
type: 'number',
esTypes: ['number'],
aggregatable: true,
filterable: true,
searchable: true,
},
{
name: 'number_field',
type: 'number',
esTypes: ['number'],
aggregatable: true,
filterable: true,
searchable: true,
},
],
} as IndexPattern;

const field = {
name: 'field',
indexPattern,
};
indexPattern.fields.getByName = (name) => (({ name } as unknown) as IndexPatternField);
indexPattern.fields.filter = () => indexPattern.fields;

return new AggConfigs(
indexPattern,
Expand Down Expand Up @@ -207,16 +237,28 @@ describe('Terms Agg', () => {
const indexPattern = {
id: '1234',
title: 'logstash-*',
fields: {
getByName: () => field,
filter: () => [field],
},
} as any;
fields: [
{
name: 'string_field',
type: 'string',
esTypes: ['string'],
aggregatable: true,
filterable: true,
searchable: true,
},
{
name: 'number_field',
type: 'number',
esTypes: ['number'],
aggregatable: true,
filterable: true,
searchable: true,
},
],
} as IndexPattern;

const field = {
name: 'field',
indexPattern,
};
indexPattern.fields.getByName = (name) => (({ name } as unknown) as IndexPatternField);
indexPattern.fields.filter = () => indexPattern.fields;

const aggConfigs = new AggConfigs(
indexPattern,
Expand Down
76 changes: 51 additions & 25 deletions src/plugins/data/common/search/aggs/param_types/field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@

import { i18n } from '@kbn/i18n';
import { IAggConfig } from '../agg_config';
import { SavedObjectNotFound } from '../../../../../../plugins/kibana_utils/common';
import {
SavedFieldNotFound,
SavedFieldTypeInvalidForAgg,
} from '../../../../../../plugins/kibana_utils/common';
import { BaseParamType } from './base';
import { propFilter } from '../utils';
import { KBN_FIELD_TYPES } from '../../../kbn_field_types/types';
Expand Down Expand Up @@ -47,13 +50,49 @@ export class FieldParamType extends BaseParamType {
);
}

if (field.scripted) {
if (field.type === KBN_FIELD_TYPES.MISSING) {
throw new SavedFieldNotFound(
i18n.translate(
'data.search.aggs.paramTypes.field.notFoundSavedFieldParameterErrorMessage',
{
defaultMessage:
'The field "{fieldParameter}" associated with this object no longer exists in the index pattern. Please use another field.',
values: {
fieldParameter: field.name,
},
}
)
);
}

const validField = this.getAvailableFields(aggConfig).find(
(f: any) => f.name === field.name
);

if (!validField) {
throw new SavedFieldTypeInvalidForAgg(
i18n.translate(
'data.search.aggs.paramTypes.field.invalidSavedFieldParameterErrorMessage',
{
defaultMessage:
'Saved field "{fieldParameter}" of index pattern "{indexPatternTitle}" is invalid for use with the "{aggType}" aggregation. Please select a new field.',
values: {
fieldParameter: field.name,
aggType: aggConfig?.type?.title,
indexPatternTitle: aggConfig.getIndexPattern().title,
},
}
)
);
}

if (validField.scripted) {
output.params.script = {
source: field.script,
lang: field.lang,
source: validField.script,
lang: validField.lang,
};
} else {
output.params.field = field.name;
output.params.field = validField.name;
}
};
}
Expand All @@ -69,28 +108,15 @@ export class FieldParamType extends BaseParamType {
const field = aggConfig.getIndexPattern().fields.getByName(fieldName);

if (!field) {
throw new SavedObjectNotFound('index-pattern-field', fieldName);
}

const validField = this.getAvailableFields(aggConfig).find((f: any) => f.name === fieldName);
if (!validField) {
throw new Error(
i18n.translate(
'data.search.aggs.paramTypes.field.invalidSavedFieldParameterErrorMessage',
{
defaultMessage:
'Saved field "{fieldParameter}" of index pattern "{indexPatternTitle}" is invalid for use with the "{aggType}" aggregation. Please select a new field.',
values: {
fieldParameter: fieldName,
aggType: aggConfig?.type?.title,
indexPatternTitle: aggConfig.getIndexPattern().title,
},
}
)
);
return new IndexPatternField({
type: KBN_FIELD_TYPES.MISSING,
name: fieldName,
searchable: false,
aggregatable: false,
});
}

return validField;
return field;
};
}

Expand Down
2 changes: 2 additions & 0 deletions src/plugins/data/public/public.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1781,6 +1781,8 @@ export enum KBN_FIELD_TYPES {
// (undocumented)
IP_RANGE = "ip_range",
// (undocumented)
MISSING = "missing",
// (undocumented)
MURMUR3 = "murmur3",
// (undocumented)
NESTED = "nested",
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/data/server/server.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1082,6 +1082,8 @@ export enum KBN_FIELD_TYPES {
// (undocumented)
IP_RANGE = "ip_range",
// (undocumented)
MISSING = "missing",
// (undocumented)
MURMUR3 = "murmur3",
// (undocumented)
NESTED = "nested",
Expand Down
7 changes: 3 additions & 4 deletions src/plugins/embeddable/public/lib/embeddables/embeddable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import { cloneDeep, isEqual } from 'lodash';
import * as Rx from 'rxjs';
import { merge } from 'rxjs';
import { debounceTime, distinctUntilChanged, map, mapTo, skip } from 'rxjs/operators';
import { debounceTime, distinctUntilChanged, map, skip } from 'rxjs/operators';
import { RenderCompleteDispatcher } from '../../../../kibana_utils/public';
import { Adapters } from '../types';
import { IContainer } from '../containers';
Expand Down Expand Up @@ -111,10 +111,9 @@ export abstract class Embeddable<
* In case corresponding state change triggered `reload` this stream is guarantied to emit later,
* which allows to skip any state handling in case `reload` already handled it.
*/
public getUpdated$(): Readonly<Rx.Observable<void>> {
public getUpdated$(): Readonly<Rx.Observable<TEmbeddableInput | TEmbeddableOutput>> {
return merge(this.getInput$().pipe(skip(1)), this.getOutput$().pipe(skip(1))).pipe(
debounceTime(0),
mapTo(undefined)
debounceTime(0)
);
}

Expand Down
2 changes: 1 addition & 1 deletion src/plugins/embeddable/public/public.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ export abstract class Embeddable<TEmbeddableInput extends EmbeddableInput = Embe
getRoot(): IEmbeddable | IContainer;
// (undocumented)
getTitle(): string;
getUpdated$(): Readonly<Rx.Observable<void>>;
getUpdated$(): Readonly<Rx.Observable<TEmbeddableInput | TEmbeddableOutput>>;
// (undocumented)
readonly id: string;
// (undocumented)
Expand Down
22 changes: 20 additions & 2 deletions src/plugins/kibana_utils/common/errors/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,39 @@ export class DuplicateField extends KbnError {
export class SavedObjectNotFound extends KbnError {
public savedObjectType: string;
public savedObjectId?: string;
constructor(type: string, id?: string, link?: string) {
constructor(type: string, id?: string, link?: string, customMessage?: string) {
const idMsg = id ? ` (id: ${id})` : '';
let message = `Could not locate that ${type}${idMsg}`;

if (link) {
message += `, [click here to re-create it](${link})`;
}

super(message);
super(customMessage || message);

this.savedObjectType = type;
this.savedObjectId = id;
}
}

/**
* A saved field doesn't exist anymore
*/
export class SavedFieldNotFound extends KbnError {
constructor(message: string) {
super(message);
}
}

/**
* A saved field type isn't compatible with aggregation
*/
export class SavedFieldTypeInvalidForAgg extends KbnError {
constructor(message: string) {
super(message);
}
}

/**
* This error is for scenarios where a saved object is detected that has invalid JSON properties.
* There was a scenario where we were importing objects with double-encoded JSON, and the system
Expand Down
Loading