Dashboard: New panel in a dashboard is not deleted after "Discard"-ing changes in Panel Edit (#66476)

* add isNew notPersistedProperty to PanelModel

* if panel is newly created and user "Discard"s it, the panel is removed entirely

* add Todo's for when we remove the emptyDashboardPage FF

* add isNew to new panel after file dropping on dashboard page

* handle the "Apply" case

* CSV file dropping is not relevant to a new panel bc it doesnt open edit page
This commit is contained in:
Polina Boneva 2023-04-25 17:18:58 +03:00 committed by GitHub
parent 63777ea368
commit fe23c76250
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 18 additions and 1 deletions

View File

@ -77,6 +77,7 @@ export const AddPanelWidgetUnconnected = ({ panel, dashboard }: Props) => {
title: 'Panel Title', title: 'Panel Title',
datasource: panel.datasource, datasource: panel.datasource,
gridPos: { x: gridPos.x, y: gridPos.y, w: gridPos.w, h: gridPos.h }, gridPos: { x: gridPos.x, y: gridPos.y, w: gridPos.w, h: gridPos.h },
isNew: true,
}; };
dashboard.addPanel(newPanel); dashboard.addPanel(newPanel);

View File

@ -1,6 +1,7 @@
import { pick } from 'lodash'; import { pick } from 'lodash';
import store from 'app/core/store'; import store from 'app/core/store';
import { removePanel } from 'app/features/dashboard/utils/panel';
import { cleanUpPanelState } from 'app/features/panel/state/actions'; import { cleanUpPanelState } from 'app/features/panel/state/actions';
import { panelModelAndPluginReady } from 'app/features/panel/state/reducers'; import { panelModelAndPluginReady } from 'app/features/panel/state/reducers';
import { ThunkResult } from 'app/types'; import { ThunkResult } from 'app/types';
@ -113,9 +114,9 @@ export function exitPanelEditor(): ThunkResult<void> {
dashboard.exitPanelEditor(); dashboard.exitPanelEditor();
} }
const sourcePanel = getSourcePanel();
if (hasPanelChangedInPanelEdit(panel) && !shouldDiscardChanges) { if (hasPanelChangedInPanelEdit(panel) && !shouldDiscardChanges) {
const modifiedSaveModel = panel.getSaveModel(); const modifiedSaveModel = panel.getSaveModel();
const sourcePanel = getSourcePanel();
const panelTypeChanged = sourcePanel.type !== panel.type; const panelTypeChanged = sourcePanel.type !== panel.type;
dispatch(updateDuplicateLibraryPanels(panel, dashboard)); dispatch(updateDuplicateLibraryPanels(panel, dashboard));
@ -144,6 +145,15 @@ export function exitPanelEditor(): ThunkResult<void> {
}, 20); }, 20);
} }
// A new panel is only new until the first time we exit the panel editor
if (sourcePanel.isNew) {
if (!shouldDiscardChanges) {
delete sourcePanel.isNew;
} else {
dashboard && removePanel(dashboard, sourcePanel, true);
}
}
dispatch(cleanUpPanelState(panel.key)); dispatch(cleanUpPanelState(panel.key));
dispatch(closeEditor()); dispatch(closeEditor());
}; };

View File

@ -351,6 +351,7 @@ export class UnthemedDashboardPage extends PureComponent<Props, State> {
return updateStatePageNavFromProps(props, updatedState); return updateStatePageNavFromProps(props, updatedState);
} }
// Todo: Remove this when we remove the emptyDashboardPage toggle
onAddPanel = () => { onAddPanel = () => {
const { dashboard } = this.props; const { dashboard } = this.props;

View File

@ -185,6 +185,7 @@ export class DashboardGrid extends PureComponent<Props, State> {
return <DashboardRow key={panel.key} panel={panel} dashboard={this.props.dashboard} />; return <DashboardRow key={panel.key} panel={panel} dashboard={this.props.dashboard} />;
} }
// Todo: Remove this when we remove the emptyDashboardPage toggle
if (panel.type === 'add-panel') { if (panel.type === 'add-panel') {
return <AddPanelWidget key={panel.key} panel={panel} dashboard={this.props.dashboard} />; return <AddPanelWidget key={panel.key} panel={panel} dashboard={this.props.dashboard} />;
} }

View File

@ -293,6 +293,7 @@ export class DashboardModel implements TimeModel {
} }
private getPanelSaveModels() { private getPanelSaveModels() {
// Todo: Remove panel.type === 'add-panel' when we remove the emptyDashboardPage toggle
return this.panels return this.panels
.filter( .filter(
(panel) => (panel) =>

View File

@ -66,6 +66,7 @@ const notPersistedProperties: { [str: string]: boolean } = {
getDisplayTitle: true, getDisplayTitle: true,
dataSupport: true, dataSupport: true,
key: true, key: true,
isNew: true,
}; };
// For angular panels we need to clean up properties when changing type // For angular panels we need to clean up properties when changing type
@ -189,6 +190,7 @@ export class PanelModel implements DataConfigSource, IPanelModel {
hasRefreshed?: boolean; hasRefreshed?: boolean;
cacheTimeout?: string | null; cacheTimeout?: string | null;
queryCachingTTL?: number | null; queryCachingTTL?: number | null;
isNew?: boolean;
cachedPluginOptions: Record<string, PanelOptionsCache> = {}; cachedPluginOptions: Record<string, PanelOptionsCache> = {};
legend?: { show: boolean; sort?: string; sortDesc?: boolean }; legend?: { show: boolean; sort?: string; sortDesc?: boolean };

View File

@ -12,6 +12,7 @@ export function onCreateNewPanel(dashboard: DashboardModel): number | undefined
type: 'timeseries', type: 'timeseries',
title: 'Panel Title', title: 'Panel Title',
gridPos: calculateNewPanelGridPos(dashboard), gridPos: calculateNewPanelGridPos(dashboard),
isNew: true,
}; };
dashboard.addPanel(newPanel); dashboard.addPanel(newPanel);