mirror of
https://github.com/grafana/grafana.git
synced 2024-11-25 10:20:29 -06:00
LibraryPanels: Prevents duplicate repeated panels from being created (#38804)
* LibraryPanels: Prevents duplicate repeated panels from being created * Tests: adds tests * Chore: updates after PR feedback
This commit is contained in:
parent
d913e46e37
commit
3b0910e470
@ -1,6 +1,6 @@
|
||||
import { thunkTester } from '../../../../../../test/core/thunk/thunkTester';
|
||||
import { closeEditor, initialState, PanelEditorState } from './reducers';
|
||||
import { initPanelEditor, exitPanelEditor } from './actions';
|
||||
import { exitPanelEditor, initPanelEditor, skipPanelUpdate } from './actions';
|
||||
import { cleanUpEditPanel, panelModelAndPluginReady } from '../../../state/reducers';
|
||||
import { DashboardModel, PanelModel } from '../../../state';
|
||||
import { getPanelPlugin } from 'app/features/plugins/__mocks__/pluginMocks';
|
||||
@ -125,4 +125,46 @@ describe('panelEditor actions', () => {
|
||||
expect(sourcePanel.getOptions()).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('skipPanelUpdate', () => {
|
||||
describe('when called with panel with an library uid different from the modified panel', () => {
|
||||
it('then it should return true', () => {
|
||||
const meta: any = {};
|
||||
const modified: any = { libraryPanel: { uid: '123', name: 'Name', meta, version: 1 } };
|
||||
const panel: any = { libraryPanel: { uid: '456', name: 'Name', meta, version: 1 } };
|
||||
|
||||
expect(skipPanelUpdate(modified, panel)).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when called with a panel that is the same as the modified panel', () => {
|
||||
it('then it should return true', () => {
|
||||
const meta: any = {};
|
||||
const modified: any = { editSourceId: 14, libraryPanel: { uid: '123', name: 'Name', meta, version: 1 } };
|
||||
const panel: any = { id: 14, libraryPanel: { uid: '123', name: 'Name', meta, version: 1 } };
|
||||
|
||||
expect(skipPanelUpdate(modified, panel)).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when called with a panel that is repeated', () => {
|
||||
it('then it should return true', () => {
|
||||
const meta: any = {};
|
||||
const modified: any = { libraryPanel: { uid: '123', name: 'Name', meta, version: 1 } };
|
||||
const panel: any = { repeatPanelId: 14, libraryPanel: { uid: '123', name: 'Name', meta, version: 1 } };
|
||||
|
||||
expect(skipPanelUpdate(modified, panel)).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when called with a panel that is a duplicate of the modified panel', () => {
|
||||
it('then it should return false', () => {
|
||||
const meta: any = {};
|
||||
const modified: any = { libraryPanel: { uid: '123', name: 'Name', meta, version: 1 } };
|
||||
const panel: any = { libraryPanel: { uid: '123', name: 'Name', meta, version: 1 } };
|
||||
|
||||
expect(skipPanelUpdate(modified, panel)).toEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -4,9 +4,9 @@ import {
|
||||
closeEditor,
|
||||
PANEL_EDITOR_UI_STATE_STORAGE_KEY,
|
||||
PanelEditorUIState,
|
||||
setDiscardChanges,
|
||||
setPanelEditorUIState,
|
||||
updateEditorInitState,
|
||||
setDiscardChanges,
|
||||
} from './reducers';
|
||||
import { cleanUpEditPanel, panelModelAndPluginReady } from '../../../state/reducers';
|
||||
import store from 'app/core/store';
|
||||
@ -33,38 +33,68 @@ export function discardPanelChanges(): ThunkResult<void> {
|
||||
};
|
||||
}
|
||||
|
||||
function updateDuplicateLibraryPanels(modifiedPanel: PanelModel, dashboard: DashboardModel | null, dispatch: any) {
|
||||
if (modifiedPanel.libraryPanel?.uid === undefined || !dashboard) {
|
||||
return;
|
||||
}
|
||||
|
||||
const modifiedSaveModel = modifiedPanel.getSaveModel();
|
||||
for (const panel of dashboard.panels) {
|
||||
if (panel.libraryPanel?.uid !== modifiedPanel.libraryPanel!.uid) {
|
||||
continue;
|
||||
export function updateDuplicateLibraryPanels(
|
||||
modifiedPanel: PanelModel,
|
||||
dashboard: DashboardModel | null
|
||||
): ThunkResult<void> {
|
||||
return (dispatch) => {
|
||||
if (modifiedPanel.libraryPanel?.uid === undefined || !dashboard) {
|
||||
return;
|
||||
}
|
||||
|
||||
panel.restoreModel({
|
||||
...modifiedSaveModel,
|
||||
...pick(panel, 'gridPos', 'id'),
|
||||
});
|
||||
const modifiedSaveModel = modifiedPanel.getSaveModel();
|
||||
for (const panel of dashboard.panels) {
|
||||
if (skipPanelUpdate(modifiedPanel, panel)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Loaded plugin is not included in the persisted properties
|
||||
// So is not handled by restoreModel
|
||||
const pluginChanged = panel.plugin?.meta.id !== modifiedPanel.plugin?.meta.id;
|
||||
panel.plugin = modifiedPanel.plugin;
|
||||
panel.configRev++;
|
||||
panel.restoreModel({
|
||||
...modifiedSaveModel,
|
||||
...pick(panel, 'gridPos', 'id'),
|
||||
});
|
||||
|
||||
if (pluginChanged) {
|
||||
dispatch(panelModelAndPluginReady({ panelId: panel.id, plugin: panel.plugin! }));
|
||||
// Loaded plugin is not included in the persisted properties
|
||||
// So is not handled by restoreModel
|
||||
const pluginChanged = panel.plugin?.meta.id !== modifiedPanel.plugin?.meta.id;
|
||||
panel.plugin = modifiedPanel.plugin;
|
||||
panel.configRev++;
|
||||
|
||||
if (pluginChanged) {
|
||||
dispatch(panelModelAndPluginReady({ panelId: panel.id, plugin: panel.plugin! }));
|
||||
}
|
||||
|
||||
// Resend last query result on source panel query runner
|
||||
// But do this after the panel edit editor exit process has completed
|
||||
setTimeout(() => {
|
||||
panel.getQueryRunner().useLastResultFrom(modifiedPanel.getQueryRunner());
|
||||
}, 20);
|
||||
}
|
||||
|
||||
// Resend last query result on source panel query runner
|
||||
// But do this after the panel edit editor exit process has completed
|
||||
setTimeout(() => {
|
||||
panel.getQueryRunner().useLastResultFrom(modifiedPanel.getQueryRunner());
|
||||
}, 20);
|
||||
if (modifiedPanel.repeat) {
|
||||
// We skip any repeated library panels so we need to update them by calling processRepeats
|
||||
// But do this after the panel edit editor exit process has completed
|
||||
setTimeout(() => dashboard.processRepeats(), 20);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function skipPanelUpdate(modifiedPanel: PanelModel, panelToUpdate: PanelModel): boolean {
|
||||
// don't update library panels that aren't of the same type
|
||||
if (panelToUpdate.libraryPanel?.uid !== modifiedPanel.libraryPanel!.uid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// don't update the modifiedPanel twice
|
||||
if (panelToUpdate.id && panelToUpdate.id === modifiedPanel.editSourceId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// don't update library panels that are repeated
|
||||
if (panelToUpdate.repeatPanelId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function exitPanelEditor(): ThunkResult<void> {
|
||||
@ -78,7 +108,7 @@ export function exitPanelEditor(): ThunkResult<void> {
|
||||
const sourcePanel = getSourcePanel();
|
||||
const panelTypeChanged = sourcePanel.type !== panel.type;
|
||||
|
||||
updateDuplicateLibraryPanels(panel, dashboard, dispatch);
|
||||
dispatch(updateDuplicateLibraryPanels(panel, dashboard));
|
||||
|
||||
// restore the source panel ID before we update source panel
|
||||
modifiedSaveModel.id = sourcePanel.id;
|
||||
|
Loading…
Reference in New Issue
Block a user