mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Dashboard: Don't show unsaved changes modal for automatic schema changes (#50822)
* Dashboard: Don't show unsaved changes modal for automatic schema changes * More refinements * Fix logic in updateGridPos
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import { getPanelPlugin } from 'app/features/plugins/__mocks__/pluginMocks';
|
||||||
|
|
||||||
import { setContextSrv } from '../../../../core/services/context_srv';
|
import { setContextSrv } from '../../../../core/services/context_srv';
|
||||||
import { DashboardModel } from '../../state/DashboardModel';
|
import { DashboardModel } from '../../state/DashboardModel';
|
||||||
import { PanelModel } from '../../state/PanelModel';
|
import { PanelModel } from '../../state/PanelModel';
|
||||||
@@ -138,6 +140,17 @@ describe('DashboardPrompt', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Should ignore panel schema migrations', () => {
|
||||||
|
const { original, dash } = getTestContext();
|
||||||
|
const plugin = getPanelPlugin({}).setMigrationHandler((panel) => {
|
||||||
|
delete (panel as any).legend;
|
||||||
|
return { option1: 'Aasd' };
|
||||||
|
});
|
||||||
|
|
||||||
|
dash.panels[0].pluginLoaded(plugin);
|
||||||
|
expect(hasChanges(dash, original)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
describe('when called with fromFile', () => {
|
describe('when called with fromFile', () => {
|
||||||
it('then it should return true', () => {
|
it('then it should return true', () => {
|
||||||
const { original, dash } = getTestContext();
|
const { original, dash } = getTestContext();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as H from 'history';
|
import * as H from 'history';
|
||||||
import { each, filter, find } from 'lodash';
|
import { each, find } from 'lodash';
|
||||||
import React, { useContext, useEffect, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { Prompt } from 'react-router-dom';
|
import { Prompt } from 'react-router-dom';
|
||||||
@@ -184,22 +184,7 @@ function cleanDashboardFromIgnoredChanges(dashData: any) {
|
|||||||
// ignore iteration property
|
// ignore iteration property
|
||||||
delete dash.iteration;
|
delete dash.iteration;
|
||||||
|
|
||||||
dash.panels = filter(dash.panels, (panel) => {
|
dash.panels = [];
|
||||||
if (panel.repeatPanelId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove scopedVars
|
|
||||||
panel.scopedVars = undefined;
|
|
||||||
|
|
||||||
// ignore panel legend sort
|
|
||||||
if (panel.legend) {
|
|
||||||
delete panel.legend.sort;
|
|
||||||
delete panel.legend.sortDesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// ignore template variable values
|
// ignore template variable values
|
||||||
each(dash.getVariables(), (variable: any) => {
|
each(dash.getVariables(), (variable: any) => {
|
||||||
@@ -212,6 +197,10 @@ function cleanDashboardFromIgnoredChanges(dashData: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function hasChanges(current: DashboardModel, original: any) {
|
export function hasChanges(current: DashboardModel, original: any) {
|
||||||
|
if (current.hasUnsavedChanges()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const currentClean = cleanDashboardFromIgnoredChanges(current.getSaveModelClone());
|
const currentClean = cleanDashboardFromIgnoredChanges(current.getSaveModelClone());
|
||||||
const originalClean = cleanDashboardFromIgnoredChanges(original);
|
const originalClean = cleanDashboardFromIgnoredChanges(original);
|
||||||
|
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ export class DashboardRow extends React.Component<DashboardRowProps, any> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onUpdate = (title: string, repeat?: string | null) => {
|
onUpdate = (title: string, repeat?: string | null) => {
|
||||||
this.props.panel['title'] = title;
|
this.props.panel.setProperty('title', title);
|
||||||
this.props.panel['repeat'] = repeat ?? undefined;
|
this.props.panel.setProperty('repeat', repeat ?? undefined);
|
||||||
this.props.panel.render();
|
this.props.panel.render();
|
||||||
this.props.dashboard.processRepeats();
|
this.props.dashboard.processRepeats();
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
|
|||||||
@@ -122,7 +122,6 @@ export class DashboardGridUnconnected extends PureComponent<Props, State> {
|
|||||||
onResize: ItemCallback = (layout, oldItem, newItem) => {
|
onResize: ItemCallback = (layout, oldItem, newItem) => {
|
||||||
const panel = this.panelMap[newItem.i!];
|
const panel = this.panelMap[newItem.i!];
|
||||||
panel.updateGridPos(newItem);
|
panel.updateGridPos(newItem);
|
||||||
panel.configRev++; // trigger change handler
|
|
||||||
};
|
};
|
||||||
|
|
||||||
onResizeStop: ItemCallback = (layout, oldItem, newItem) => {
|
onResizeStop: ItemCallback = (layout, oldItem, newItem) => {
|
||||||
|
|||||||
@@ -367,6 +367,15 @@ describe('DashboardModel', () => {
|
|||||||
dashboard.toggleRow(dashboard.panels[1]);
|
dashboard.toggleRow(dashboard.panels[1]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not impact hasUnsavedChanges', () => {
|
||||||
|
expect(dashboard.hasUnsavedChanges()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should impact hasUnsavedChanges if panels have changes when row is collapsed', () => {
|
||||||
|
dashboard.panels[0].setProperty('title', 'new title');
|
||||||
|
expect(dashboard.hasUnsavedChanges()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it('should remove panels and put them inside collapsed row', () => {
|
it('should remove panels and put them inside collapsed row', () => {
|
||||||
expect(dashboard.panels.length).toBe(3);
|
expect(dashboard.panels.length).toBe(3);
|
||||||
expect(dashboard.panels[1].panels?.length).toBe(2);
|
expect(dashboard.panels[1].panels?.length).toBe(2);
|
||||||
|
|||||||
@@ -499,10 +499,6 @@ export class DashboardModel implements TimeModel {
|
|||||||
|
|
||||||
hasUnsavedChanges() {
|
hasUnsavedChanges() {
|
||||||
const changedPanel = this.panels.find((p) => p.hasChanged);
|
const changedPanel = this.panels.find((p) => p.hasChanged);
|
||||||
if (changedPanel) {
|
|
||||||
console.log('Panel has changed', changedPanel);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Boolean(changedPanel);
|
return Boolean(changedPanel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -875,6 +871,10 @@ export class DashboardModel implements TimeModel {
|
|||||||
row.panels = rowPanels.map((panel: PanelModel) => panel.getSaveModel());
|
row.panels = rowPanels.map((panel: PanelModel) => panel.getSaveModel());
|
||||||
row.collapsed = true;
|
row.collapsed = true;
|
||||||
|
|
||||||
|
if (rowPanels.some((panel) => panel.hasChanged)) {
|
||||||
|
row.configRev++;
|
||||||
|
}
|
||||||
|
|
||||||
// emit change event
|
// emit change event
|
||||||
this.events.publish(new DashboardPanelsChangedEvent());
|
this.events.publish(new DashboardPanelsChangedEvent());
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -435,6 +435,20 @@ describe('PanelModel', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('updateGridPos', () => {
|
||||||
|
it('Should not cause configRev if no change', () => {
|
||||||
|
model.gridPos = { w: 1, h: 1, x: 1, y: 2 };
|
||||||
|
model.updateGridPos({ w: 1, h: 1, x: 1, y: 2 });
|
||||||
|
expect(model.hasChanged).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should not cause configRev if gridPos is different', () => {
|
||||||
|
model.gridPos = { w: 1, h: 1, x: 1, y: 2 };
|
||||||
|
model.updateGridPos({ w: 10, h: 1, x: 1, y: 2 });
|
||||||
|
expect(model.hasChanged).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('destroy', () => {
|
describe('destroy', () => {
|
||||||
it('Should still preserve last query result', () => {
|
it('Should still preserve last query result', () => {
|
||||||
model.getQueryRunner().useLastResultFrom({
|
model.getQueryRunner().useLastResultFrom({
|
||||||
|
|||||||
@@ -298,10 +298,20 @@ export class PanelModel implements DataConfigSource, IPanelModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateGridPos(newPos: GridPos) {
|
updateGridPos(newPos: GridPos) {
|
||||||
|
if (
|
||||||
|
newPos.x === this.gridPos.x &&
|
||||||
|
newPos.y === this.gridPos.y &&
|
||||||
|
newPos.h === this.gridPos.h &&
|
||||||
|
newPos.w === this.gridPos.w
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.gridPos.x = newPos.x;
|
this.gridPos.x = newPos.x;
|
||||||
this.gridPos.y = newPos.y;
|
this.gridPos.y = newPos.y;
|
||||||
this.gridPos.w = newPos.w;
|
this.gridPos.w = newPos.w;
|
||||||
this.gridPos.h = newPos.h;
|
this.gridPos.h = newPos.h;
|
||||||
|
this.configRev++;
|
||||||
}
|
}
|
||||||
|
|
||||||
runAllPanelQueries(
|
runAllPanelQueries(
|
||||||
|
|||||||
Reference in New Issue
Block a user