From e51734be79e030efceedabbdeea8eecbe29580c9 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 3 Apr 2018 12:08:12 -0600 Subject: [PATCH] Redirect to dashboard listing page when panel data can not be migrated. (#17394) * throw exeception when unable to migrate panel data * catch migrate exception and show toast * remove unneeded conversion to string * fix jest test * use forEach instead of map * fix jest tests * move toast and window.location change to constructor --- .../public/dashboard/grid/dashboard_grid.js | 23 ++++++++++++++++++- .../dashboard/grid/dashboard_grid.test.js | 6 +++++ .../grid/dashboard_grid_container.test.js | 7 ++++++ .../public/dashboard/panel/panel_utils.js | 13 +++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/core_plugins/kibana/public/dashboard/grid/dashboard_grid.js b/src/core_plugins/kibana/public/dashboard/grid/dashboard_grid.js index 883fbadc4c23d..0f83c6b6d097a 100644 --- a/src/core_plugins/kibana/public/dashboard/grid/dashboard_grid.js +++ b/src/core_plugins/kibana/public/dashboard/grid/dashboard_grid.js @@ -7,7 +7,9 @@ import classNames from 'classnames'; import { PanelUtils } from '../panel/panel_utils'; import { DashboardViewMode } from '../dashboard_view_mode'; import { DashboardPanel } from '../panel'; +import { toastNotifications } from 'ui/notify'; import { + DashboardConstants, DASHBOARD_GRID_COLUMN_COUNT, DASHBOARD_GRID_HEIGHT, } from '../dashboard_constants'; @@ -87,10 +89,25 @@ export class DashboardGrid extends React.Component { // A mapping of panelIndexes to grid items so we can set the zIndex appropriately on the last focused // item. this.gridItems = {}; + + let isLayoutInvalid = false; + let layout; + try { + layout = this.buildLayoutFromPanels(); + } catch (error) { + isLayoutInvalid = true; + toastNotifications.addDanger({ + title: 'Unable to load dashboard.', + text: error.message, + }); + window.location = `#${DashboardConstants.LANDING_PAGE_PATH}`; + } this.state = { focusedPanelIndex: undefined, - layout: this.buildLayoutFromPanels() + layout, + isLayoutInvalid, }; + // A mapping of panel type to embeddable handlers. Because this function reaches out of react and into angular, // if done in the render method, it appears to be triggering a scope.apply, which appears to be trigging a setState // call inside TSVB visualizations. Moving the function out of render appears to fix the issue. See @@ -200,6 +217,10 @@ export class DashboardGrid extends React.Component { } render() { + if (this.state.isLayoutInvalid) { + return null; + } + const { dashboardViewMode, maximizedPanelId, useMargins } = this.props; const isViewMode = dashboardViewMode === DashboardViewMode.VIEW; return ( diff --git a/src/core_plugins/kibana/public/dashboard/grid/dashboard_grid.test.js b/src/core_plugins/kibana/public/dashboard/grid/dashboard_grid.test.js index 04f80e78cb523..b47fd50d8d0cf 100644 --- a/src/core_plugins/kibana/public/dashboard/grid/dashboard_grid.test.js +++ b/src/core_plugins/kibana/public/dashboard/grid/dashboard_grid.test.js @@ -10,6 +10,12 @@ import { DashboardGrid } from './dashboard_grid'; jest.mock('ui/chrome', () => ({ getKibanaVersion: () => '6.0.0' }), { virtual: true }); +jest.mock('ui/notify', + () => ({ + toastNotifications: { + addDanger: () => {}, + } + }), { virtual: true }); function getProps(props = {}) { const defaultTestProps = { diff --git a/src/core_plugins/kibana/public/dashboard/grid/dashboard_grid_container.test.js b/src/core_plugins/kibana/public/dashboard/grid/dashboard_grid_container.test.js index f6543aaec9942..6db0fb9a8b9f2 100644 --- a/src/core_plugins/kibana/public/dashboard/grid/dashboard_grid_container.test.js +++ b/src/core_plugins/kibana/public/dashboard/grid/dashboard_grid_container.test.js @@ -12,6 +12,13 @@ import { updatePanels } from '../actions'; jest.mock('ui/chrome', () => ({ getKibanaVersion: () => '6.3.0' }), { virtual: true }); +jest.mock('ui/notify', + () => ({ + toastNotifications: { + addDanger: () => {}, + } + }), { virtual: true }); + function getProps(props = {}) { const defaultTestProps = { hidden: false, diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_utils.js b/src/core_plugins/kibana/public/dashboard/panel/panel_utils.js index f58750f32bdc7..c4894d2d4191b 100644 --- a/src/core_plugins/kibana/public/dashboard/panel/panel_utils.js +++ b/src/core_plugins/kibana/public/dashboard/panel/panel_utils.js @@ -1,3 +1,4 @@ +import _ from 'lodash'; import { DEFAULT_PANEL_WIDTH, DEFAULT_PANEL_HEIGHT } from '../dashboard_constants'; import chrome from 'ui/chrome'; @@ -8,6 +9,12 @@ export class PanelUtils { // 6.1 switched from gridster to react grid. React grid uses different variables for tracking layout static convertPanelDataPre_6_1(panel) { // eslint-disable-line camelcase + ['col', 'row'].forEach(key => { + if (!_.has(panel, key)) { + throw new Error(`Unable to migrate panel data for "6.1.0" backwards compatibility, panel does not contain expected field: ${key}`); + } + }); + panel.gridData = { x: panel.col - 1, y: panel.row - 1, @@ -30,6 +37,12 @@ export class PanelUtils { // 2) increase rows from 12 to 48 // Need to scale pre 6.3 panels so they maintain the same layout static convertPanelDataPre_6_3(panel) { // eslint-disable-line camelcase + ['w', 'x', 'h', 'y'].forEach(key => { + if (!_.has(panel.gridData, key)) { + throw new Error(`Unable to migrate panel data for "6.3.0" backwards compatibility, panel does not contain expected field: ${key}`); + } + }); + panel.gridData.w = panel.gridData.w * PANEL_WIDTH_SCALE_FACTOR; panel.gridData.x = panel.gridData.x * PANEL_WIDTH_SCALE_FACTOR; panel.gridData.h = panel.gridData.h * PANEL_HEIGHT_SCALE_FACTOR;