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

[7.12] Fix importing dashboards created before ~6.1.0 (#94332) #94566

Merged
merged 1 commit into from
Mar 15, 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
81 changes: 79 additions & 2 deletions src/plugins/dashboard/common/saved_dashboard_references.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ describe('extractReferences', () => {
type: 'visualization',
id: '1',
title: 'Title 1',
version: '7.9.1',
},
{
type: 'visualization',
id: '2',
title: 'Title 2',
version: '7.9.1',
},
]),
},
Expand All @@ -46,7 +48,7 @@ describe('extractReferences', () => {
Object {
"attributes": Object {
"foo": true,
"panelsJSON": "[{\\"embeddableConfig\\":{},\\"title\\":\\"Title 1\\",\\"panelRefName\\":\\"panel_0\\"},{\\"embeddableConfig\\":{},\\"title\\":\\"Title 2\\",\\"panelRefName\\":\\"panel_1\\"}]",
"panelsJSON": "[{\\"version\\":\\"7.9.1\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 1\\",\\"panelRefName\\":\\"panel_0\\"},{\\"version\\":\\"7.9.1\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 2\\",\\"panelRefName\\":\\"panel_1\\"}]",
},
"references": Array [
Object {
Expand All @@ -73,6 +75,7 @@ describe('extractReferences', () => {
{
id: '1',
title: 'Title 1',
version: '7.9.1',
},
]),
},
Expand All @@ -92,6 +95,7 @@ describe('extractReferences', () => {
{
type: 'visualization',
title: 'Title 1',
version: '7.9.1',
},
]),
},
Expand All @@ -101,12 +105,85 @@ describe('extractReferences', () => {
Object {
"attributes": Object {
"foo": true,
"panelsJSON": "[{\\"type\\":\\"visualization\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 1\\"}]",
"panelsJSON": "[{\\"version\\":\\"7.9.1\\",\\"type\\":\\"visualization\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 1\\"}]",
},
"references": Array [],
}
`);
});

// https://github.com/elastic/kibana/issues/93772
test('passes when received older RAW SO with older panels', () => {
const doc = {
id: '1',
attributes: {
hits: 0,
timeFrom: 'now-16h/h',
timeTo: 'now',
refreshInterval: {
display: '1 minute',
section: 2,
value: 60000,
pause: false,
},
description: '',
uiStateJSON: '{"P-1":{"vis":{"legendOpen":false}}}',
title: 'Errors/Fatals/Warnings dashboard',
timeRestore: true,
version: 1,
panelsJSON:
'[{"col":1,"id":"544891f0-2cf2-11e8-9735-93e95b055f48","panelIndex":1,"row":1,"size_x":12,"size_y":8,"type":"visualization"}]',
optionsJSON: '{"darkTheme":true}',
kibanaSavedObjectMeta: {
searchSourceJSON:
'{"highlightAll":true,"filter":[{"query":{"query_string":{"analyze_wildcard":true,"query":"*"}}}]}',
},
},
references: [],
};
const updatedDoc = extractReferences(doc, deps);

expect(updatedDoc).toMatchInlineSnapshot(`
Object {
"attributes": Object {
"description": "",
"hits": 0,
"kibanaSavedObjectMeta": Object {
"searchSourceJSON": "{\\"highlightAll\\":true,\\"filter\\":[{\\"query\\":{\\"query_string\\":{\\"analyze_wildcard\\":true,\\"query\\":\\"*\\"}}}]}",
},
"optionsJSON": "{\\"darkTheme\\":true}",
"panelsJSON": "[{\\"col\\":1,\\"panelIndex\\":1,\\"row\\":1,\\"size_x\\":12,\\"size_y\\":8,\\"panelRefName\\":\\"panel_0\\"}]",
"refreshInterval": Object {
"display": "1 minute",
"pause": false,
"section": 2,
"value": 60000,
},
"timeFrom": "now-16h/h",
"timeRestore": true,
"timeTo": "now",
"title": "Errors/Fatals/Warnings dashboard",
"uiStateJSON": "{\\"P-1\\":{\\"vis\\":{\\"legendOpen\\":false}}}",
"version": 1,
},
"references": Array [
Object {
"id": "544891f0-2cf2-11e8-9735-93e95b055f48",
"name": "panel_0",
"type": "visualization",
},
],
}
`);

const panel = JSON.parse(updatedDoc.attributes.panelsJSON as string)[0];

// unknown older panel keys are left untouched
expect(panel).toHaveProperty('col');
expect(panel).toHaveProperty('row');
expect(panel).toHaveProperty('size_x');
expect(panel).toHaveProperty('size_y');
});
});

describe('injectReferences', () => {
Expand Down
39 changes: 29 additions & 10 deletions src/plugins/dashboard/common/saved_dashboard_references.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* Side Public License, v 1.
*/

import semverSatisfies from 'semver/functions/satisfies';
import { SavedObjectAttributes, SavedObjectReference } from '../../../core/types';
import {
extractPanelsReferences,
Expand Down Expand Up @@ -33,17 +34,35 @@ export function extractReferences(
const panelReferences: SavedObjectReference[] = [];
let panels: Array<Record<string, string>> = JSON.parse(String(attributes.panelsJSON));

const extractedReferencesResult = extractPanelsReferences(
(panels as unknown) as SavedDashboardPanel730ToLatest[],
deps
);
const isPre730Panel = (panel: Record<string, string>): boolean => {
return 'version' in panel ? semverSatisfies(panel.version, '<7.3') : true;
};

panels = (extractedReferencesResult.map((res) => res.panel) as unknown) as Array<
Record<string, string>
>;
extractedReferencesResult.forEach((res) => {
panelReferences.push(...res.references);
});
const hasPre730Panel = panels.some(isPre730Panel);

/**
* `extractPanelsReferences` only knows how to reliably handle "latest" panels
* It is possible that `extractReferences` is run on older dashboard SO with older panels,
* for example, when importing a saved object using saved object UI `extractReferences` is called BEFORE any server side migrations are run.
*
* In this case we skip running `extractPanelsReferences` on such object.
* We also know that there is nothing to extract
* (First possible entity to be extracted by this mechanism is a dashboard drilldown since 7.11)
*/
if (!hasPre730Panel) {
const extractedReferencesResult = extractPanelsReferences(
// it is ~safe~ to cast to `SavedDashboardPanel730ToLatest` because above we've checked that there are only >=7.3 panels
(panels as unknown) as SavedDashboardPanel730ToLatest[],
deps
);

panels = (extractedReferencesResult.map((res) => res.panel) as unknown) as Array<
Record<string, string>
>;
extractedReferencesResult.forEach((res) => {
panelReferences.push(...res.references);
});
}

// TODO: This extraction should be done by EmbeddablePersistableStateService
// https://github.com/elastic/kibana/issues/82830
Expand Down
43 changes: 43 additions & 0 deletions test/functional/apps/dashboard/bwc_import.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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 path from 'path';
import { FtrProviderContext } from '../../ftr_provider_context';

export default function ({ getService, getPageObjects }: FtrProviderContext) {
const PageObjects = getPageObjects(['dashboard', 'header', 'settings', 'savedObjects', 'common']);
const dashboardExpect = getService('dashboardExpect');

describe('bwc import', function describeIndexTests() {
before(async function () {
await PageObjects.dashboard.initTests();
await PageObjects.settings.navigateTo();
await PageObjects.settings.clickKibanaSavedObjects();
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', 'dashboard_6_0_1.json')
);
await PageObjects.settings.associateIndexPattern(
'dd684000-8255-11eb-a5e7-93c302c8f329',
'logstash-*'
);
await PageObjects.savedObjects.clickConfirmChanges();
await PageObjects.savedObjects.clickImportDone();
await PageObjects.common.navigateToApp('dashboard');
});

describe('6.0.1 dashboard', () => {
it('loads an imported dashboard', async function () {
await PageObjects.dashboard.gotoDashboardLandingPage();
await PageObjects.dashboard.loadSavedDashboard('My custom bwc dashboard');
await PageObjects.header.waitUntilLoadingHasFinished();

await dashboardExpect.metricValuesExist(['14,004']);
});
});
});
}
46 changes: 46 additions & 0 deletions test/functional/apps/dashboard/exports/dashboard_6_0_1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
[
{
"_id": "924ed3d0-8256-11eb-a5e7-93c302c8f329",
"_type": "dashboard",
"_source": {
"title": "My custom bwc dashboard",
"hits": 0,
"description": "",
"panelsJSON": "[{\"size_x\":6,\"size_y\":3,\"panelIndex\":1,\"type\":\"visualization\",\"id\":\"1bdf34a0-8266-11eb-a5e7-93c302c8f329\",\"col\":1,\"row\":1}]",
"optionsJSON": "{\"darkTheme\":false}",
"uiStateJSON": "{\"P-1\":{\"vis\":{\"defaultColors\":{\"0 - 100\":\"rgb(0,104,55)\"}}}}",
"version": 1,
"timeRestore": true,
"timeTo": "Wed Apr 20 2016 23:59:59 GMT+0200",
"timeFrom": "Thu Jan 01 2015 00:00:00 GMT+0100",
"refreshInterval": {
"display": "Off",
"pause": false,
"value": 0
},
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[],\"highlightAll\":true,\"version\":true}"
}
},
"_meta": {
"savedObjectVersion": 2
}
},
{
"_id": "1bdf34a0-8266-11eb-a5e7-93c302c8f329",
"_type": "visualization",
"_source": {
"title": "My custom bwc viz",
"visState": "{\"title\":\"My custom bwc viz\",\"type\":\"metric\",\"params\":{\"addTooltip\":true,\"addLegend\":false,\"type\":\"gauge\",\"gauge\":{\"verticalSplit\":false,\"autoExtend\":false,\"percentageMode\":false,\"gaugeType\":\"Metric\",\"gaugeStyle\":\"Full\",\"backStyle\":\"Full\",\"orientation\":\"vertical\",\"colorSchema\":\"Green to Red\",\"gaugeColorMode\":\"None\",\"useRange\":false,\"colorsRange\":[{\"from\":0,\"to\":100}],\"invertColors\":false,\"labels\":{\"show\":true,\"color\":\"black\"},\"scale\":{\"show\":false,\"labels\":false,\"color\":\"#333\",\"width\":2},\"type\":\"simple\",\"style\":{\"fontSize\":60,\"bgColor\":false,\"labelColor\":false,\"subText\":\"\"}}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}}]}",
"uiStateJSON": "{\"vis\":{\"defaultColors\":{\"0 - 100\":\"rgb(0,104,55)\"}}}",
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"dd684000-8255-11eb-a5e7-93c302c8f329\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
}
},
"_meta": {
"savedObjectVersion": 2
}
}
]
1 change: 1 addition & 0 deletions test/functional/apps/dashboard/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) {

loadTestFile(require.resolve('./dashboard_time_picker'));
loadTestFile(require.resolve('./bwc_shared_urls'));
loadTestFile(require.resolve('./bwc_import'));
loadTestFile(require.resolve('./panel_replacing'));
loadTestFile(require.resolve('./panel_cloning'));
loadTestFile(require.resolve('./copy_panel_to'));
Expand Down