* Created common TSVB migrations. Registered them in serverside embeddable factory so that by value panels receive them Co-authored-by: Stratoula Kalafateli <efstratia.kalafateli@elastic.co> Co-authored-by: Devon Thomson <devon.thomson@elastic.co>
This commit is contained in:
parent
157e2cf140
commit
550d110244
|
@ -147,7 +147,10 @@ function createExtractPanelReferencesMigration(
|
|||
};
|
||||
}
|
||||
|
||||
type ValueOrReferenceInput = SavedObjectEmbeddableInput & { attributes?: SerializableValue };
|
||||
type ValueOrReferenceInput = SavedObjectEmbeddableInput & {
|
||||
attributes?: SerializableValue;
|
||||
savedVis?: SerializableValue;
|
||||
};
|
||||
|
||||
// Runs the embeddable migrations on each panel
|
||||
const migrateByValuePanels = (
|
||||
|
@ -158,19 +161,21 @@ const migrateByValuePanels = (
|
|||
// Skip if panelsJSON is missing otherwise this will cause saved object import to fail when
|
||||
// importing objects without panelsJSON. At development time of this, there is no guarantee each saved
|
||||
// object has panelsJSON in all previous versions of kibana.
|
||||
if (typeof attributes.panelsJSON !== 'string') {
|
||||
return attributes;
|
||||
if (typeof attributes?.panelsJSON !== 'string') {
|
||||
return doc;
|
||||
}
|
||||
const panels = JSON.parse(attributes.panelsJSON) as SavedDashboardPanel[];
|
||||
// Same here, prevent failing saved object import if ever panels aren't an array.
|
||||
if (!Array.isArray(panels)) {
|
||||
return attributes;
|
||||
return doc;
|
||||
}
|
||||
const newPanels: SavedDashboardPanel[] = [];
|
||||
panels.forEach((panel) => {
|
||||
// Convert each panel into a state that can be passed to EmbeddablesSetup.migrate
|
||||
const originalPanelState = convertSavedDashboardPanelToPanelState<ValueOrReferenceInput>(panel);
|
||||
if (originalPanelState.explicitInput.attributes) {
|
||||
|
||||
// saved vis is used to store by value input for Visualize. This should eventually be renamed to `attributes` to align with Lens and Maps
|
||||
if (originalPanelState.explicitInput.attributes || originalPanelState.explicitInput.savedVis) {
|
||||
// If this panel is by value, migrate the state using embeddable migrations
|
||||
const migratedInput = deps.embeddable.migrate(
|
||||
{
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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 { flow } from 'lodash';
|
||||
import { EmbeddableRegistryDefinition } from 'src/plugins/embeddable/server';
|
||||
import { SerializableState } from '../../../kibana_utils/common';
|
||||
import {
|
||||
commonAddSupportOfDualIndexSelectionModeInTSVB,
|
||||
commonHideTSVBLastValueIndicator,
|
||||
commonRemoveDefaultIndexPatternAndTimeFieldFromTSVBModel,
|
||||
} from '../migrations/visualization_common_migrations';
|
||||
|
||||
const byValueAddSupportOfDualIndexSelectionModeInTSVB = (state: SerializableState) => {
|
||||
return {
|
||||
...state,
|
||||
savedVis: commonAddSupportOfDualIndexSelectionModeInTSVB(state.savedVis),
|
||||
};
|
||||
};
|
||||
|
||||
const byValueHideTSVBLastValueIndicator = (state: SerializableState) => {
|
||||
return {
|
||||
...state,
|
||||
savedVis: commonHideTSVBLastValueIndicator(state.savedVis),
|
||||
};
|
||||
};
|
||||
|
||||
const byValueRemoveDefaultIndexPatternAndTimeFieldFromTSVBModel = (state: SerializableState) => {
|
||||
return {
|
||||
...state,
|
||||
savedVis: commonRemoveDefaultIndexPatternAndTimeFieldFromTSVBModel(state.savedVis),
|
||||
};
|
||||
};
|
||||
|
||||
export const visualizeEmbeddableFactory = (): EmbeddableRegistryDefinition => {
|
||||
return {
|
||||
id: 'visualization',
|
||||
migrations: {
|
||||
// These migrations are run in 7.13.1 for `by value` panels because the 7.13 release window was missed.
|
||||
'7.13.1': (state) =>
|
||||
flow(
|
||||
byValueAddSupportOfDualIndexSelectionModeInTSVB,
|
||||
byValueHideTSVBLastValueIndicator,
|
||||
byValueRemoveDefaultIndexPatternAndTimeFieldFromTSVBModel
|
||||
)(state),
|
||||
},
|
||||
};
|
||||
};
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export const commonAddSupportOfDualIndexSelectionModeInTSVB = (visState: any) => {
|
||||
if (visState && visState.type === 'metrics') {
|
||||
const { params } = visState;
|
||||
|
||||
if (typeof params?.index_pattern === 'string') {
|
||||
params.use_kibana_indexes = false;
|
||||
}
|
||||
}
|
||||
return visState;
|
||||
};
|
||||
|
||||
export const commonHideTSVBLastValueIndicator = (visState: any) => {
|
||||
if (visState && visState.type === 'metrics' && visState.params.type !== 'timeseries') {
|
||||
return {
|
||||
...visState,
|
||||
params: {
|
||||
...visState.params,
|
||||
hide_last_value_indicator: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
return visState;
|
||||
};
|
||||
|
||||
export const commonRemoveDefaultIndexPatternAndTimeFieldFromTSVBModel = (visState: any) => {
|
||||
if (visState && visState.type === 'metrics') {
|
||||
const { params } = visState;
|
||||
|
||||
delete params.default_index_pattern;
|
||||
delete params.default_timefield;
|
||||
|
||||
return visState;
|
||||
}
|
||||
|
||||
return visState;
|
||||
};
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { visualizationSavedObjectTypeMigrations } from './visualization_migrations';
|
||||
import { visualizationSavedObjectTypeMigrations } from './visualization_saved_object_migrations';
|
||||
import { SavedObjectMigrationContext, SavedObjectMigrationFn } from 'kibana/server';
|
||||
|
||||
const savedObjectMigrationContext = (null as unknown) as SavedObjectMigrationContext;
|
||||
|
@ -1977,4 +1977,44 @@ describe('migration visualization', () => {
|
|||
expect(params).not.toHaveProperty('default_timefield');
|
||||
});
|
||||
});
|
||||
|
||||
describe('7.13.0 and 7.13.1 tsvb migrations can run twice', () => {
|
||||
const migrate = (doc: any) =>
|
||||
visualizationSavedObjectTypeMigrations['7.13.0'](
|
||||
doc as Parameters<SavedObjectMigrationFn>[0],
|
||||
savedObjectMigrationContext
|
||||
);
|
||||
|
||||
const migrateAgain = (doc: any) =>
|
||||
visualizationSavedObjectTypeMigrations['7.13.1'](
|
||||
doc as Parameters<SavedObjectMigrationFn>[0],
|
||||
savedObjectMigrationContext
|
||||
);
|
||||
|
||||
const createTestDocWithType = (type: string) => ({
|
||||
attributes: {
|
||||
title: 'My Vis',
|
||||
description: 'This is my super cool vis.',
|
||||
visState: `{"type":"metrics","params":{"type":"${type}","default_index_pattern":"test", "default_timefield":"test", "index_pattern":"testme"}}`,
|
||||
},
|
||||
});
|
||||
|
||||
it('the migrations can be applied twice without breaking anything', () => {
|
||||
const migratedTestDoc = migrate(createTestDocWithType('markdown'));
|
||||
const { params } = JSON.parse(migratedTestDoc.attributes.visState);
|
||||
|
||||
expect(params.hide_last_value_indicator).toBeTruthy();
|
||||
expect(params).not.toHaveProperty('default_index_pattern');
|
||||
expect(params).not.toHaveProperty('default_timefield');
|
||||
expect(params.use_kibana_indexes).toBeFalsy();
|
||||
|
||||
const migratedTestDocNew = migrateAgain(migratedTestDoc);
|
||||
const visState = JSON.parse(migratedTestDocNew.attributes.visState);
|
||||
|
||||
expect(visState.params.hide_last_value_indicator).toBeTruthy();
|
||||
expect(visState.params).not.toHaveProperty('default_index_pattern');
|
||||
expect(visState.params).not.toHaveProperty('default_timefield');
|
||||
expect(params.use_kibana_indexes).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -11,6 +11,11 @@ import { cloneDeep, get, omit, has, flow, forOwn } from 'lodash';
|
|||
import { SavedObjectMigrationFn } from 'kibana/server';
|
||||
|
||||
import { DEFAULT_QUERY_LANGUAGE } from '../../../data/common';
|
||||
import {
|
||||
commonAddSupportOfDualIndexSelectionModeInTSVB,
|
||||
commonHideTSVBLastValueIndicator,
|
||||
commonRemoveDefaultIndexPatternAndTimeFieldFromTSVBModel,
|
||||
} from './visualization_common_migrations';
|
||||
|
||||
const migrateIndexPattern: SavedObjectMigrationFn<any, any> = (doc) => {
|
||||
const searchSourceJSON = get(doc, 'attributes.kibanaSavedObjectMeta.searchSourceJSON');
|
||||
|
@ -799,22 +804,16 @@ const addSupportOfDualIndexSelectionModeInTSVB: SavedObjectMigrationFn<any, any>
|
|||
visState = JSON.parse(visStateJSON);
|
||||
} catch (e) {
|
||||
// Let it go, the data is invalid and we'll leave it as is
|
||||
return doc;
|
||||
}
|
||||
if (visState && visState.type === 'metrics') {
|
||||
const { params } = visState;
|
||||
|
||||
if (typeof params?.index_pattern === 'string') {
|
||||
params.use_kibana_indexes = false;
|
||||
}
|
||||
|
||||
return {
|
||||
...doc,
|
||||
attributes: {
|
||||
...doc.attributes,
|
||||
visState: JSON.stringify(visState),
|
||||
},
|
||||
};
|
||||
}
|
||||
const newVisState = commonAddSupportOfDualIndexSelectionModeInTSVB(visState);
|
||||
return {
|
||||
...doc,
|
||||
attributes: {
|
||||
...doc.attributes,
|
||||
visState: JSON.stringify(newVisState),
|
||||
},
|
||||
};
|
||||
}
|
||||
return doc;
|
||||
};
|
||||
|
@ -929,25 +928,17 @@ const migrateVislibAreaLineBarTypes: SavedObjectMigrationFn<any, any> = (doc) =>
|
|||
const hideTSVBLastValueIndicator: SavedObjectMigrationFn<any, any> = (doc) => {
|
||||
try {
|
||||
const visState = JSON.parse(doc.attributes.visState);
|
||||
|
||||
if (visState && visState.type === 'metrics' && visState.params.type !== 'timeseries')
|
||||
return {
|
||||
...doc,
|
||||
attributes: {
|
||||
...doc.attributes,
|
||||
visState: JSON.stringify({
|
||||
...visState,
|
||||
params: {
|
||||
...visState.params,
|
||||
hide_last_value_indicator: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
};
|
||||
const newVisState = commonHideTSVBLastValueIndicator(visState);
|
||||
return {
|
||||
...doc,
|
||||
attributes: {
|
||||
...doc.attributes,
|
||||
visState: JSON.stringify(newVisState),
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
// Let it go, the data is invalid and we'll leave it as is
|
||||
}
|
||||
|
||||
return doc;
|
||||
};
|
||||
|
||||
|
@ -962,23 +953,17 @@ const removeDefaultIndexPatternAndTimeFieldFromTSVBModel: SavedObjectMigrationFn
|
|||
visState = JSON.parse(visStateJSON);
|
||||
} catch (e) {
|
||||
// Let it go, the data is invalid and we'll leave it as is
|
||||
}
|
||||
if (visState && visState.type === 'metrics') {
|
||||
const { params } = visState;
|
||||
|
||||
delete params.default_index_pattern;
|
||||
delete params.default_timefield;
|
||||
|
||||
return {
|
||||
...doc,
|
||||
attributes: {
|
||||
...doc.attributes,
|
||||
visState: JSON.stringify(visState),
|
||||
},
|
||||
};
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
return doc;
|
||||
const newVisState = commonRemoveDefaultIndexPatternAndTimeFieldFromTSVBModel(visState);
|
||||
return {
|
||||
...doc,
|
||||
attributes: {
|
||||
...doc.attributes,
|
||||
visState: JSON.stringify(newVisState),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const visualizationSavedObjectTypeMigrations = {
|
||||
|
@ -1021,4 +1006,10 @@ export const visualizationSavedObjectTypeMigrations = {
|
|||
hideTSVBLastValueIndicator,
|
||||
removeDefaultIndexPatternAndTimeFieldFromTSVBModel
|
||||
),
|
||||
'7.13.1': flow(
|
||||
// duplicate these migrations in case a broken by value panel is added to the library
|
||||
addSupportOfDualIndexSelectionModeInTSVB,
|
||||
hideTSVBLastValueIndicator,
|
||||
removeDefaultIndexPatternAndTimeFieldFromTSVBModel
|
||||
),
|
||||
};
|
|
@ -24,6 +24,8 @@ import { visualizationSavedObjectType } from './saved_objects';
|
|||
|
||||
import { VisualizationsPluginSetup, VisualizationsPluginStart } from './types';
|
||||
import { registerVisualizationsCollector } from './usage_collector';
|
||||
import { EmbeddableSetup } from '../../embeddable/server';
|
||||
import { visualizeEmbeddableFactory } from './embeddable/visualize_embeddable_factory';
|
||||
|
||||
export class VisualizationsPlugin
|
||||
implements Plugin<VisualizationsPluginSetup, VisualizationsPluginStart> {
|
||||
|
@ -35,7 +37,10 @@ export class VisualizationsPlugin
|
|||
this.config = initializerContext.config.legacy.globalConfig$;
|
||||
}
|
||||
|
||||
public setup(core: CoreSetup, plugins: { usageCollection?: UsageCollectionSetup }) {
|
||||
public setup(
|
||||
core: CoreSetup,
|
||||
plugins: { usageCollection?: UsageCollectionSetup; embeddable: EmbeddableSetup }
|
||||
) {
|
||||
this.logger.debug('visualizations: Setup');
|
||||
|
||||
core.savedObjects.registerType(visualizationSavedObjectType);
|
||||
|
@ -59,6 +64,8 @@ export class VisualizationsPlugin
|
|||
registerVisualizationsCollector(plugins.usageCollection, this.config);
|
||||
}
|
||||
|
||||
plugins.embeddable.registerEmbeddableFactory(visualizeEmbeddableFactory());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import { SavedObjectsType } from 'kibana/server';
|
||||
import { visualizationSavedObjectTypeMigrations } from './visualization_migrations';
|
||||
import { visualizationSavedObjectTypeMigrations } from '../migrations/visualization_saved_object_migrations';
|
||||
|
||||
export const visualizationSavedObjectType: SavedObjectsType = {
|
||||
name: 'visualization',
|
||||
|
|
Loading…
Reference in a new issue