diff --git a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx index 7727cd6a3ad..365caab319d 100644 --- a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx +++ b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx @@ -1,6 +1,5 @@ // Libraries import React, { PureComponent } from 'react'; -import { hot } from 'react-hot-loader'; import ReactGridLayout, { ItemCallback } from 'react-grid-layout'; import classNames from 'classnames'; // @ts-ignore @@ -98,11 +97,22 @@ export interface Props { isPanelEditorOpen?: boolean; } -export class DashboardGrid extends PureComponent { +export interface State { + isLayoutInitialized: boolean; +} +export class DashboardGrid extends PureComponent { private panelMap: { [id: string]: PanelModel } = {}; private panelRef: { [id: string]: HTMLElement } = {}; private eventSubs = new Subscription(); + constructor(props: Props) { + super(props); + + this.state = { + isLayoutInitialized: false, + }; + } + componentDidMount() { const { dashboard } = this.props; this.eventSubs.add(dashboard.events.subscribe(DashboardPanelsChangedEvent, this.triggerForceUpdate)); @@ -153,8 +163,10 @@ export class DashboardGrid extends PureComponent { this.props.dashboard.sortPanelsByGridPos(); - // Call render() after any changes. This is called when the layout loads - this.forceUpdate(); + // onLayoutChange is called onMount this marks layout as initialized and we are ready to render panels + if (!this.state.isLayoutInitialized) { + this.setState({ isLayoutInitialized: true }); + } }; triggerForceUpdate = () => { @@ -163,10 +175,6 @@ export class DashboardGrid extends PureComponent { updateGridPos = (item: ReactGridLayout.Layout, layout: ReactGridLayout.Layout[]) => { this.panelMap[item.i!].updateGridPos(item); - - // react-grid-layout has a bug (#670), and onLayoutChange() is only called when the component is mounted. - // So it's required to call it explicitly when panel resized or moved to save layout changes. - this.onLayoutChange(layout); }; onResize: ItemCallback = (layout, oldItem, newItem) => { @@ -259,7 +267,6 @@ export class DashboardGrid extends PureComponent { render() { const { dashboard, viewPanel } = this.props; - return ( { ); } } - -export default hot(module)(DashboardGrid); diff --git a/public/app/features/dashboard/state/DashboardModel.ts b/public/app/features/dashboard/state/DashboardModel.ts index b359b21dcbb..073d336431e 100644 --- a/public/app/features/dashboard/state/DashboardModel.ts +++ b/public/app/features/dashboard/state/DashboardModel.ts @@ -1088,6 +1088,13 @@ export class DashboardModel { return this.meta.canEdit || this.meta.canMakeEditable; } + shouldUpdateDashboardPanelFromJSON(updatedPanel: PanelModel, panel: PanelModel) { + const shouldUpdateGridPositionLayout = !isEqual(updatedPanel?.gridPos, panel?.gridPos); + if (shouldUpdateGridPositionLayout) { + this.events.publish(new DashboardPanelsChangedEvent()); + } + } + private getPanelRepeatVariable(panel: PanelModel) { return this.getVariablesFromState().find((variable) => variable.name === panel.repeat); } diff --git a/public/app/features/inspector/InspectJSONTab.tsx b/public/app/features/inspector/InspectJSONTab.tsx index f0c469dc41f..296d9b101fa 100644 --- a/public/app/features/inspector/InspectJSONTab.tsx +++ b/public/app/features/inspector/InspectJSONTab.tsx @@ -105,6 +105,7 @@ export class InspectJSONTab extends PureComponent { appEvents.emit(AppEvents.alertError, ['Unable to apply']); } else { const updates = JSON.parse(this.state.text); + dashboard!.shouldUpdateDashboardPanelFromJSON(updates, panel!); panel!.restoreModel(updates); panel!.refresh(); appEvents.emit(AppEvents.alertSuccess, ['Panel model updated']);