diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.kbn_field_types.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.kbn_field_types.md
index 4d75dda61d5c9..521ceeb1e37f2 100644
--- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.kbn_field_types.md
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.kbn_field_types.md
@@ -27,6 +27,7 @@ export declare enum KBN_FIELD_TYPES
| HISTOGRAM | "histogram"
| |
| IP | "ip"
| |
| IP\_RANGE | "ip_range"
| |
+| MISSING | "missing"
| |
| MURMUR3 | "murmur3"
| |
| NESTED | "nested"
| |
| NUMBER | "number"
| |
diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.kbn_field_types.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.kbn_field_types.md
index be4c3705bd8de..40fa872ff0fc6 100644
--- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.kbn_field_types.md
+++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.kbn_field_types.md
@@ -27,6 +27,7 @@ export declare enum KBN_FIELD_TYPES
| HISTOGRAM | "histogram"
| |
| IP | "ip"
| |
| IP\_RANGE | "ip_range"
| |
+| MISSING | "missing"
| |
| MURMUR3 | "murmur3"
| |
| NESTED | "nested"
| |
| NUMBER | "number"
| |
diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddable.getupdated_.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddable.getupdated_.md
index 5201444e69867..290dc10662569 100644
--- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddable.getupdated_.md
+++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddable.getupdated_.md
@@ -9,9 +9,9 @@ Merges input$ and output$ streams and debounces emit till next macro-task. Could
Signature:
```typescript
-getUpdated$(): Readonly>;
+getUpdated$(): Readonly>;
```
Returns:
-`Readonly>`
+`Readonly>`
diff --git a/src/plugins/data/common/kbn_field_types/types.ts b/src/plugins/data/common/kbn_field_types/types.ts
index c46e5c5266f55..e6f815e058ce3 100644
--- a/src/plugins/data/common/kbn_field_types/types.ts
+++ b/src/plugins/data/common/kbn_field_types/types.ts
@@ -80,4 +80,5 @@ export enum KBN_FIELD_TYPES {
OBJECT = 'object',
NESTED = 'nested',
HISTOGRAM = 'histogram',
+ MISSING = 'missing',
}
diff --git a/src/plugins/data/common/search/aggs/agg_configs.test.ts b/src/plugins/data/common/search/aggs/agg_configs.test.ts
index 297af560081b1..3ce528e6ed893 100644
--- a/src/plugins/data/common/search/aggs/agg_configs.test.ts
+++ b/src/plugins/data/common/search/aggs/agg_configs.test.ts
@@ -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', () => {
diff --git a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts
index 4e278d5872a3e..56e720d237c45 100644
--- a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts
+++ b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts
@@ -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: [
diff --git a/src/plugins/data/common/search/aggs/buckets/terms.test.ts b/src/plugins/data/common/search/aggs/buckets/terms.test.ts
index bb34d7ede453c..09dfbb28a4e53 100644
--- a/src/plugins/data/common/search/aggs/buckets/terms.test.ts
+++ b/src/plugins/data/common/search/aggs/buckets/terms.test.ts
@@ -10,6 +10,8 @@ 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', () => {
@@ -17,16 +19,44 @@ describe('Terms Agg', () => {
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,
@@ -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,
diff --git a/src/plugins/data/common/search/aggs/param_types/field.ts b/src/plugins/data/common/search/aggs/param_types/field.ts
index 2d3ff8f5fdba8..62dac9831211a 100644
--- a/src/plugins/data/common/search/aggs/param_types/field.ts
+++ b/src/plugins/data/common/search/aggs/param_types/field.ts
@@ -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';
@@ -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;
}
};
}
@@ -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;
};
}
diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md
index ec24a9296674d..5cc4dc6302a1e 100644
--- a/src/plugins/data/public/public.api.md
+++ b/src/plugins/data/public/public.api.md
@@ -1781,6 +1781,8 @@ export enum KBN_FIELD_TYPES {
// (undocumented)
IP_RANGE = "ip_range",
// (undocumented)
+ MISSING = "missing",
+ // (undocumented)
MURMUR3 = "murmur3",
// (undocumented)
NESTED = "nested",
diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md
index 9fff4ac95c87e..053b60956fa92 100644
--- a/src/plugins/data/server/server.api.md
+++ b/src/plugins/data/server/server.api.md
@@ -1082,6 +1082,8 @@ export enum KBN_FIELD_TYPES {
// (undocumented)
IP_RANGE = "ip_range",
// (undocumented)
+ MISSING = "missing",
+ // (undocumented)
MURMUR3 = "murmur3",
// (undocumented)
NESTED = "nested",
diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx b/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx
index e8418970d83f7..a0cd213b7bf24 100644
--- a/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx
+++ b/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx
@@ -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';
@@ -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> {
+ public getUpdated$(): Readonly> {
return merge(this.getInput$().pipe(skip(1)), this.getOutput$().pipe(skip(1))).pipe(
- debounceTime(0),
- mapTo(undefined)
+ debounceTime(0)
);
}
diff --git a/src/plugins/embeddable/public/public.api.md b/src/plugins/embeddable/public/public.api.md
index b9719542adc81..3f0907acabdfa 100644
--- a/src/plugins/embeddable/public/public.api.md
+++ b/src/plugins/embeddable/public/public.api.md
@@ -282,7 +282,7 @@ export abstract class Embeddable>;
+ getUpdated$(): Readonly>;
// (undocumented)
readonly id: string;
// (undocumented)
diff --git a/src/plugins/kibana_utils/common/errors/errors.ts b/src/plugins/kibana_utils/common/errors/errors.ts
index 7a9495cc8f413..7f3efc6d9571f 100644
--- a/src/plugins/kibana_utils/common/errors/errors.ts
+++ b/src/plugins/kibana_utils/common/errors/errors.ts
@@ -32,7 +32,7 @@ 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}`;
@@ -40,13 +40,31 @@ export class SavedObjectNotFound extends KbnError {
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
diff --git a/src/plugins/vis_default_editor/public/components/controls/field.test.tsx b/src/plugins/vis_default_editor/public/components/controls/field.test.tsx
index 94f767510c4bd..277804567c2b7 100644
--- a/src/plugins/vis_default_editor/public/components/controls/field.test.tsx
+++ b/src/plugins/vis_default_editor/public/components/controls/field.test.tsx
@@ -11,7 +11,7 @@ import { act } from 'react-dom/test-utils';
import { mount, shallow, ReactWrapper } from 'enzyme';
import { EuiComboBoxProps, EuiComboBox } from '@elastic/eui';
-import { IAggConfig, IndexPatternField } from 'src/plugins/data/public';
+import { IAggConfig, IndexPatternField, AggParam } from 'src/plugins/data/public';
import { ComboBoxGroupedOptions } from '../../utils';
import { FieldParamEditor, FieldParamEditorProps } from './field';
import { EditorVisState } from '../sidebar/state/reducers';
@@ -42,7 +42,7 @@ describe('FieldParamEditor component', () => {
setTouched = jest.fn();
onChange = jest.fn();
- field = { displayName: 'bytes' } as IndexPatternField;
+ field = { displayName: 'bytes', type: 'bytes' } as IndexPatternField;
option = { label: 'bytes', target: field };
indexedFields = [
{
@@ -52,7 +52,16 @@ describe('FieldParamEditor component', () => {
];
defaultProps = {
- agg: {} as IAggConfig,
+ agg: {
+ type: {
+ params: [
+ ({
+ name: 'field',
+ filterFieldTypes: ['bytes'],
+ } as unknown) as AggParam,
+ ],
+ },
+ } as IAggConfig,
aggParam: {
name: 'field',
type: 'field',
diff --git a/src/plugins/vis_default_editor/public/components/controls/field.tsx b/src/plugins/vis_default_editor/public/components/controls/field.tsx
index 95843dc6ae3a8..f8db2d89888a2 100644
--- a/src/plugins/vis_default_editor/public/components/controls/field.tsx
+++ b/src/plugins/vis_default_editor/public/components/controls/field.tsx
@@ -13,7 +13,13 @@ import useMount from 'react-use/lib/useMount';
import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import { AggParam, IAggConfig, IFieldParamType, IndexPatternField } from 'src/plugins/data/public';
+import {
+ AggParam,
+ IAggConfig,
+ IFieldParamType,
+ IndexPatternField,
+ KBN_FIELD_TYPES,
+} from '../../../../../plugins/data/public';
import { formatListAsProse, parseCommaSeparatedList, useValidation } from './utils';
import { AggParamEditorProps } from '../agg_param_props';
import { ComboBoxGroupedOptions } from '../../utils';
@@ -55,6 +61,7 @@ function FieldParamEditor({
}
};
const errors = customError ? [customError] : [];
+ let showErrorMessageImmediately = false;
if (!indexedFields.length) {
errors.push(
@@ -69,9 +76,38 @@ function FieldParamEditor({
);
}
+ if (value && value.type === KBN_FIELD_TYPES.MISSING) {
+ errors.push(
+ i18n.translate('visDefaultEditor.controls.field.fieldIsNotExists', {
+ defaultMessage:
+ 'The field "{fieldParameter}" associated with this object no longer exists in the index pattern. Please use another field.',
+ values: {
+ fieldParameter: value.name,
+ },
+ })
+ );
+ showErrorMessageImmediately = true;
+ } else if (
+ value &&
+ !getFieldTypes(agg).find((type: string) => type === value.type || type === '*')
+ ) {
+ errors.push(
+ i18n.translate('visDefaultEditor.controls.field.invalidFieldForAggregation', {
+ defaultMessage:
+ 'Saved field "{fieldParameter}" of index pattern "{indexPatternTitle}" is invalid for use with this aggregation. Please select a new field.',
+ values: {
+ fieldParameter: value?.name,
+ indexPatternTitle: agg.getIndexPattern && agg.getIndexPattern().title,
+ },
+ })
+ );
+ showErrorMessageImmediately = true;
+ }
+
const isValid = !!value && !errors.length && !isDirty;
// we show an error message right away if there is no compatible fields
- const showErrorMessage = (showValidation || !indexedFields.length) && !isValid;
+ const showErrorMessage =
+ (showValidation || !indexedFields.length || showErrorMessageImmediately) && !isValid;
useValidation(setValidity, isValid);
useMount(() => {
@@ -122,10 +158,14 @@ function FieldParamEditor({
}
function getFieldTypesString(agg: IAggConfig) {
+ return formatListAsProse(getFieldTypes(agg), { inclusive: false });
+}
+
+function getFieldTypes(agg: IAggConfig) {
const param =
get(agg, 'type.params', []).find((p: AggParam) => p.name === 'field') ||
({} as IFieldParamType);
- return formatListAsProse(parseCommaSeparatedList(param.filterFieldTypes), { inclusive: false });
+ return parseCommaSeparatedList(param.filterFieldTypes || []);
}
export { FieldParamEditor };
diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts
index 429dabeeef042..907a2b95a037b 100644
--- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts
+++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts
@@ -149,8 +149,9 @@ export class VisualizeEmbeddable
}
this.subscriptions.push(
- this.getUpdated$().subscribe(() => {
+ this.getUpdated$().subscribe((value) => {
const isDirty = this.handleChanges();
+
if (isDirty && this.handler) {
this.updateHandler();
}
diff --git a/src/plugins/visualize/public/application/utils/get_visualization_instance.ts b/src/plugins/visualize/public/application/utils/get_visualization_instance.ts
index cc0f3ce2afae5..9eda709e58c3e 100644
--- a/src/plugins/visualize/public/application/utils/get_visualization_instance.ts
+++ b/src/plugins/visualize/public/application/utils/get_visualization_instance.ts
@@ -18,8 +18,17 @@ import { SavedObject } from 'src/plugins/saved_objects/public';
import { cloneDeep } from 'lodash';
import { ExpressionValueError } from 'src/plugins/expressions/public';
import { createSavedSearchesLoader } from '../../../../discover/public';
+import { SavedFieldNotFound, SavedFieldTypeInvalidForAgg } from '../../../../kibana_utils/common';
import { VisualizeServices } from '../types';
+function isErrorRelatedToRuntimeFields(error: ExpressionValueError['error']) {
+ const originalError = error.original || error;
+ return (
+ originalError instanceof SavedFieldNotFound ||
+ originalError instanceof SavedFieldTypeInvalidForAgg
+ );
+}
+
const createVisualizeEmbeddableAndLinkSavedSearch = async (
vis: Vis,
visualizeServices: VisualizeServices
@@ -37,7 +46,7 @@ const createVisualizeEmbeddableAndLinkSavedSearch = async (
})) as VisualizeEmbeddableContract;
embeddableHandler.getOutput$().subscribe((output) => {
- if (output.error) {
+ if (output.error && !isErrorRelatedToRuntimeFields(output.error)) {
data.search.showError(
((output.error as unknown) as ExpressionValueError['error']).original || output.error
);
diff --git a/src/plugins/visualize/public/application/utils/use/use_saved_vis_instance.ts b/src/plugins/visualize/public/application/utils/use/use_saved_vis_instance.ts
index 64d61996495d7..965951bfbd88d 100644
--- a/src/plugins/visualize/public/application/utils/use/use_saved_vis_instance.ts
+++ b/src/plugins/visualize/public/application/utils/use/use_saved_vis_instance.ts
@@ -11,13 +11,12 @@ import { EventEmitter } from 'events';
import { parse } from 'query-string';
import { i18n } from '@kbn/i18n';
-import { redirectWhenMissing } from '../../../../../kibana_utils/public';
-
import { getVisualizationInstance } from '../get_visualization_instance';
import { getEditBreadcrumbs, getCreateBreadcrumbs } from '../breadcrumbs';
import { SavedVisInstance, VisualizeServices, IEditorController } from '../../types';
import { VisualizeConstants } from '../../visualize_constants';
import { getVisEditorsRegistry } from '../../../services';
+import { redirectToSavedObjectPage } from '../utils';
/**
* This effect is responsible for instantiating a saved vis or creating a new one
@@ -43,9 +42,7 @@ export const useSavedVisInstance = (
chrome,
history,
dashboard,
- setActiveUrl,
toastNotifications,
- http: { basePath },
stateTransferService,
application: { navigateToApp },
} = services;
@@ -131,27 +128,8 @@ export const useSavedVisInstance = (
visEditorController,
});
} catch (error) {
- const managementRedirectTarget = {
- app: 'management',
- path: `kibana/objects/savedVisualizations/${visualizationIdFromUrl}`,
- };
-
try {
- redirectWhenMissing({
- history,
- navigateToApp,
- toastNotifications,
- basePath,
- mapping: {
- visualization: VisualizeConstants.LANDING_PAGE_PATH,
- search: managementRedirectTarget,
- 'index-pattern': managementRedirectTarget,
- 'index-pattern-field': managementRedirectTarget,
- },
- onBeforeRedirect() {
- setActiveUrl(VisualizeConstants.LANDING_PAGE_PATH);
- },
- })(error);
+ redirectToSavedObjectPage(services, error, visualizationIdFromUrl);
} catch (e) {
toastNotifications.addWarning({
title: i18n.translate('visualize.createVisualization.failedToLoadErrorMessage', {
diff --git a/src/plugins/visualize/public/application/utils/utils.ts b/src/plugins/visualize/public/application/utils/utils.ts
index 0e529507f97e3..c906ff5304c90 100644
--- a/src/plugins/visualize/public/application/utils/utils.ts
+++ b/src/plugins/visualize/public/application/utils/utils.ts
@@ -10,6 +10,8 @@ import { i18n } from '@kbn/i18n';
import { ChromeStart, DocLinksStart } from 'kibana/public';
import { Filter } from '../../../../data/public';
+import { redirectWhenMissing } from '../../../../kibana_utils/public';
+import { VisualizeConstants } from '../visualize_constants';
import { VisualizeServices, VisualizeEditorVisInstance } from '../types';
export const addHelpMenuToAppChrome = (chrome: ChromeStart, docLinks: DocLinksStart) => {
@@ -58,3 +60,36 @@ export const visStateToEditorState = (
linked: savedVis && savedVis.id ? !!savedVis.savedSearchId : !!savedVisState.savedSearchId,
};
};
+
+export const redirectToSavedObjectPage = (
+ services: VisualizeServices,
+ error: any,
+ savedVisualizationsId?: string
+) => {
+ const {
+ history,
+ setActiveUrl,
+ toastNotifications,
+ http: { basePath },
+ application: { navigateToApp },
+ } = services;
+ const managementRedirectTarget = {
+ app: 'management',
+ path: `kibana/objects/savedVisualizations/${savedVisualizationsId}`,
+ };
+ redirectWhenMissing({
+ history,
+ navigateToApp,
+ toastNotifications,
+ basePath,
+ mapping: {
+ visualization: VisualizeConstants.LANDING_PAGE_PATH,
+ search: managementRedirectTarget,
+ 'index-pattern': managementRedirectTarget,
+ 'index-pattern-field': managementRedirectTarget,
+ },
+ onBeforeRedirect() {
+ setActiveUrl(VisualizeConstants.LANDING_PAGE_PATH);
+ },
+ })(error);
+};