mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Dashboards: Discard the entire panel if it is newly added (#87562)
This commit is contained in:
parent
c0881cc970
commit
66950c96f6
@ -1491,6 +1491,9 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Do not use any type assertions.", "3"],
|
[0, 0, 0, "Do not use any type assertions.", "3"],
|
||||||
[0, 0, 0, "Do not use any type assertions.", "4"]
|
[0, 0, 0, "Do not use any type assertions.", "4"]
|
||||||
],
|
],
|
||||||
|
"public/app/features/dashboard-scene/scene/NavToolbarActions.test.tsx:5381": [
|
||||||
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
|
],
|
||||||
"public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx:5381": [
|
"public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx:5381": [
|
||||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||||
],
|
],
|
||||||
|
@ -59,6 +59,63 @@ describe('PanelEditor', () => {
|
|||||||
const updatedPanel = gridItem.state.body as VizPanel;
|
const updatedPanel = gridItem.state.body as VizPanel;
|
||||||
expect(updatedPanel?.state.title).toBe('changed title');
|
expect(updatedPanel?.state.title).toBe('changed title');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should discard changes when unmounted and discard changes is marked as true', () => {
|
||||||
|
pluginToLoad = getTestPanelPlugin({ id: 'text', skipDataQuery: true });
|
||||||
|
|
||||||
|
const panel = new VizPanel({
|
||||||
|
key: 'panel-1',
|
||||||
|
pluginId: 'text',
|
||||||
|
});
|
||||||
|
|
||||||
|
const gridItem = new DashboardGridItem({ body: panel });
|
||||||
|
|
||||||
|
const editScene = buildPanelEditScene(panel);
|
||||||
|
const scene = new DashboardScene({
|
||||||
|
editPanel: editScene,
|
||||||
|
isEditing: true,
|
||||||
|
body: new SceneGridLayout({
|
||||||
|
children: [gridItem],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const deactivate = activateFullSceneTree(scene);
|
||||||
|
|
||||||
|
editScene.state.vizManager.state.panel.setState({ title: 'changed title' });
|
||||||
|
|
||||||
|
editScene.onDiscard();
|
||||||
|
deactivate();
|
||||||
|
|
||||||
|
const updatedPanel = gridItem.state.body as VizPanel;
|
||||||
|
expect(updatedPanel?.state.title).toBe(panel.state.title);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should discard a newly added panel', () => {
|
||||||
|
pluginToLoad = getTestPanelPlugin({ id: 'text', skipDataQuery: true });
|
||||||
|
|
||||||
|
const panel = new VizPanel({
|
||||||
|
key: 'panel-1',
|
||||||
|
pluginId: 'text',
|
||||||
|
});
|
||||||
|
|
||||||
|
const gridItem = new DashboardGridItem({ body: panel });
|
||||||
|
|
||||||
|
const editScene = buildPanelEditScene(panel, true);
|
||||||
|
const scene = new DashboardScene({
|
||||||
|
editPanel: editScene,
|
||||||
|
isEditing: true,
|
||||||
|
body: new SceneGridLayout({
|
||||||
|
children: [gridItem],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
editScene.onDiscard();
|
||||||
|
const deactivate = activateFullSceneTree(scene);
|
||||||
|
|
||||||
|
deactivate();
|
||||||
|
|
||||||
|
expect((scene.state.body as SceneGridLayout).state.children.length).toBe(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Handling library panels', () => {
|
describe('Handling library panels', () => {
|
||||||
|
@ -14,6 +14,7 @@ import { PanelOptionsPane } from './PanelOptionsPane';
|
|||||||
import { VizPanelManager, VizPanelManagerState } from './VizPanelManager';
|
import { VizPanelManager, VizPanelManagerState } from './VizPanelManager';
|
||||||
|
|
||||||
export interface PanelEditorState extends SceneObjectState {
|
export interface PanelEditorState extends SceneObjectState {
|
||||||
|
isNewPanel: boolean;
|
||||||
isDirty?: boolean;
|
isDirty?: boolean;
|
||||||
panelId: number;
|
panelId: number;
|
||||||
optionsPane: PanelOptionsPane;
|
optionsPane: PanelOptionsPane;
|
||||||
@ -59,6 +60,8 @@ export class PanelEditor extends SceneObjectBase<PanelEditorState> {
|
|||||||
return () => {
|
return () => {
|
||||||
if (!this._discardChanges) {
|
if (!this._discardChanges) {
|
||||||
this.commitChanges();
|
this.commitChanges();
|
||||||
|
} else if (this.state.isNewPanel) {
|
||||||
|
getDashboardSceneFor(this).removePanel(panelManager.state.sourcePanel.resolve()!);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -173,10 +176,11 @@ export class PanelEditor extends SceneObjectBase<PanelEditorState> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildPanelEditScene(panel: VizPanel): PanelEditor {
|
export function buildPanelEditScene(panel: VizPanel, isNewPanel = false): PanelEditor {
|
||||||
return new PanelEditor({
|
return new PanelEditor({
|
||||||
panelId: getPanelIdForVizPanel(panel),
|
panelId: getPanelIdForVizPanel(panel),
|
||||||
optionsPane: new PanelOptionsPane({}),
|
optionsPane: new PanelOptionsPane({}),
|
||||||
vizManager: VizPanelManager.createFor(panel),
|
vizManager: VizPanelManager.createFor(panel),
|
||||||
|
isNewPanel,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -779,7 +779,7 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> {
|
|||||||
return getPanelIdForVizPanel(row);
|
return getPanelIdForVizPanel(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
public onCreateNewPanel(): number {
|
public onCreateNewPanel(): VizPanel {
|
||||||
if (!this.state.isEditing) {
|
if (!this.state.isEditing) {
|
||||||
this.onEnterEditMode();
|
this.onEnterEditMode();
|
||||||
}
|
}
|
||||||
@ -788,7 +788,7 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> {
|
|||||||
|
|
||||||
this.addPanel(vizPanel);
|
this.addPanel(vizPanel);
|
||||||
|
|
||||||
return getPanelIdForVizPanel(vizPanel);
|
return vizPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -124,6 +124,7 @@ export class DashboardSceneUrlSync implements SceneObjectUrlSyncHandler {
|
|||||||
// Handle edit panel state
|
// Handle edit panel state
|
||||||
if (typeof values.editPanel === 'string') {
|
if (typeof values.editPanel === 'string') {
|
||||||
const panel = findVizPanelByKey(this._scene, values.editPanel);
|
const panel = findVizPanelByKey(this._scene, values.editPanel);
|
||||||
|
|
||||||
if (!panel) {
|
if (!panel) {
|
||||||
console.warn(`Panel ${values.editPanel} not found`);
|
console.warn(`Panel ${values.editPanel} not found`);
|
||||||
return;
|
return;
|
||||||
@ -144,6 +145,7 @@ export class DashboardSceneUrlSync implements SceneObjectUrlSyncHandler {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
update.editPanel = buildPanelEditScene(panel);
|
update.editPanel = buildPanelEditScene(panel);
|
||||||
} else if (editPanel && values.editPanel === null) {
|
} else if (editPanel && values.editPanel === null) {
|
||||||
update.editPanel = undefined;
|
update.editPanel = undefined;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { screen, render } from '@testing-library/react';
|
import { screen, render, act } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { TestProvider } from 'test/helpers/TestProvider';
|
import { TestProvider } from 'test/helpers/TestProvider';
|
||||||
@ -6,11 +6,13 @@ import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
|
|||||||
|
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
import { config } from '@grafana/runtime';
|
import { config } from '@grafana/runtime';
|
||||||
|
import { SceneGridLayout, SceneQueryRunner, SceneTimeRange, VizPanel } from '@grafana/scenes';
|
||||||
import { playlistSrv } from 'app/features/playlist/PlaylistSrv';
|
import { playlistSrv } from 'app/features/playlist/PlaylistSrv';
|
||||||
|
|
||||||
import { transformSaveModelToScene } from '../serialization/transformSaveModelToScene';
|
import { buildPanelEditScene } from '../panel-edit/PanelEditor';
|
||||||
import { transformSceneToSaveModel } from '../serialization/transformSceneToSaveModel';
|
|
||||||
|
|
||||||
|
import { DashboardGridItem } from './DashboardGridItem';
|
||||||
|
import { DashboardScene } from './DashboardScene';
|
||||||
import { ToolbarActions } from './NavToolbarActions';
|
import { ToolbarActions } from './NavToolbarActions';
|
||||||
|
|
||||||
jest.mock('app/features/playlist/PlaylistSrv', () => ({
|
jest.mock('app/features/playlist/PlaylistSrv', () => ({
|
||||||
@ -25,6 +27,17 @@ jest.mock('app/features/playlist/PlaylistSrv', () => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock('@grafana/runtime', () => ({
|
||||||
|
...jest.requireActual<Record<string, any>>('@grafana/runtime'),
|
||||||
|
getDataSourceSrv: () => ({
|
||||||
|
get: jest.fn(),
|
||||||
|
getInstanceSettings: jest.fn().mockReturnValue({
|
||||||
|
uid: 'datasource-uid',
|
||||||
|
name: 'datasource-name',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
describe('NavToolbarActions', () => {
|
describe('NavToolbarActions', () => {
|
||||||
describe('Given an already saved dashboard', () => {
|
describe('Given an already saved dashboard', () => {
|
||||||
it('Should show correct buttons when not in editing', async () => {
|
it('Should show correct buttons when not in editing', async () => {
|
||||||
@ -90,8 +103,9 @@ describe('NavToolbarActions', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Should show correct buttons when in settings menu', async () => {
|
it('Should show correct buttons when in settings menu', async () => {
|
||||||
setup();
|
const { dashboard } = setup();
|
||||||
|
|
||||||
|
dashboard.startUrlSync();
|
||||||
await userEvent.click(await screen.findByText('Edit'));
|
await userEvent.click(await screen.findByText('Edit'));
|
||||||
await userEvent.click(await screen.findByText('Settings'));
|
await userEvent.click(await screen.findByText('Settings'));
|
||||||
|
|
||||||
@ -101,6 +115,35 @@ describe('NavToolbarActions', () => {
|
|||||||
expect(screen.queryByText(selectors.pages.Dashboard.DashNav.playlistControls.stop)).not.toBeInTheDocument();
|
expect(screen.queryByText(selectors.pages.Dashboard.DashNav.playlistControls.stop)).not.toBeInTheDocument();
|
||||||
expect(screen.queryByText(selectors.pages.Dashboard.DashNav.playlistControls.next)).not.toBeInTheDocument();
|
expect(screen.queryByText(selectors.pages.Dashboard.DashNav.playlistControls.next)).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Should show correct buttons when editing a new panel', async () => {
|
||||||
|
const { dashboard } = setup();
|
||||||
|
await act(() => {
|
||||||
|
dashboard.onEnterEditMode();
|
||||||
|
const editingPanel = ((dashboard.state.body as SceneGridLayout).state.children[0] as DashboardGridItem).state
|
||||||
|
.body as VizPanel;
|
||||||
|
dashboard.setState({ editPanel: buildPanelEditScene(editingPanel, true) });
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await screen.findByText('Save dashboard')).toBeInTheDocument();
|
||||||
|
expect(await screen.findByText('Discard panel')).toBeInTheDocument();
|
||||||
|
expect(await screen.findByText('Back to dashboard')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should show correct buttons when editing an existing panel', async () => {
|
||||||
|
const { dashboard } = setup();
|
||||||
|
|
||||||
|
await act(() => {
|
||||||
|
dashboard.onEnterEditMode();
|
||||||
|
const editingPanel = ((dashboard.state.body as SceneGridLayout).state.children[0] as DashboardGridItem).state
|
||||||
|
.body as VizPanel;
|
||||||
|
dashboard.setState({ editPanel: buildPanelEditScene(editingPanel) });
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await screen.findByText('Save dashboard')).toBeInTheDocument();
|
||||||
|
expect(await screen.findByText('Discard panel changes')).toBeInTheDocument();
|
||||||
|
expect(await screen.findByText('Back to dashboard')).toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Given new sharing button', () => {
|
describe('Given new sharing button', () => {
|
||||||
@ -115,40 +158,51 @@ describe('NavToolbarActions', () => {
|
|||||||
config.featureToggles.newDashboardSharingComponent = true;
|
config.featureToggles.newDashboardSharingComponent = true;
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
expect(screen.queryByTestId(selectors.pages.Dashboard.DashNav.shareButton)).not.toBeInTheDocument();
|
expect(await screen.queryByTestId(selectors.pages.Dashboard.DashNav.shareButton)).not.toBeInTheDocument();
|
||||||
const newShareButton = screen.getByTestId(selectors.pages.Dashboard.DashNav.newShareButton.container);
|
const newShareButton = screen.getByTestId(selectors.pages.Dashboard.DashNav.newShareButton.container);
|
||||||
expect(newShareButton).toBeInTheDocument();
|
expect(newShareButton).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
let cleanUp = () => {};
|
|
||||||
|
|
||||||
function setup() {
|
function setup() {
|
||||||
const dashboard = transformSaveModelToScene({
|
const dashboard = new DashboardScene({
|
||||||
dashboard: {
|
$timeRange: new SceneTimeRange({ from: 'now-6h', to: 'now' }),
|
||||||
title: 'hello',
|
|
||||||
uid: 'my-uid',
|
|
||||||
schemaVersion: 30,
|
|
||||||
panels: [],
|
|
||||||
version: 10,
|
|
||||||
},
|
|
||||||
meta: {
|
meta: {
|
||||||
|
canEdit: true,
|
||||||
|
isNew: false,
|
||||||
|
canMakeEditable: true,
|
||||||
canSave: true,
|
canSave: true,
|
||||||
|
canShare: true,
|
||||||
|
canStar: true,
|
||||||
|
canAdmin: true,
|
||||||
|
canDelete: true,
|
||||||
},
|
},
|
||||||
|
title: 'hello',
|
||||||
|
uid: 'dash-1',
|
||||||
|
body: new SceneGridLayout({
|
||||||
|
children: [
|
||||||
|
new DashboardGridItem({
|
||||||
|
key: 'griditem-1',
|
||||||
|
x: 0,
|
||||||
|
body: new VizPanel({
|
||||||
|
title: 'Panel A',
|
||||||
|
key: 'panel-1',
|
||||||
|
pluginId: 'table',
|
||||||
|
$data: new SceneQueryRunner({ key: 'data-query-runner', queries: [{ refId: 'A' }] }),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
new DashboardGridItem({
|
||||||
|
body: new VizPanel({
|
||||||
|
title: 'Panel B',
|
||||||
|
key: 'panel-2',
|
||||||
|
pluginId: 'table',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Clear any data layers
|
|
||||||
dashboard.setState({ $data: undefined });
|
|
||||||
|
|
||||||
const initialSaveModel = transformSceneToSaveModel(dashboard);
|
|
||||||
dashboard.setInitialSaveModel(initialSaveModel);
|
|
||||||
|
|
||||||
dashboard.startUrlSync();
|
|
||||||
|
|
||||||
cleanUp();
|
|
||||||
cleanUp = dashboard.activate();
|
|
||||||
|
|
||||||
const context = getGrafanaContextMock();
|
const context = getGrafanaContextMock();
|
||||||
|
|
||||||
render(
|
render(
|
||||||
|
@ -22,7 +22,7 @@ import { Trans, t } from 'app/core/internationalization';
|
|||||||
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
||||||
import { playlistSrv } from 'app/features/playlist/PlaylistSrv';
|
import { playlistSrv } from 'app/features/playlist/PlaylistSrv';
|
||||||
|
|
||||||
import { PanelEditor } from '../panel-edit/PanelEditor';
|
import { PanelEditor, buildPanelEditScene } from '../panel-edit/PanelEditor';
|
||||||
import ShareButton from '../sharing/ShareButton/ShareButton';
|
import ShareButton from '../sharing/ShareButton/ShareButton';
|
||||||
import { ShareModal } from '../sharing/ShareModal';
|
import { ShareModal } from '../sharing/ShareModal';
|
||||||
import { DashboardInteractions } from '../utils/interactions';
|
import { DashboardInteractions } from '../utils/interactions';
|
||||||
@ -170,9 +170,9 @@ export function ToolbarActions({ dashboard }: Props) {
|
|||||||
testId={selectors.pages.AddDashboard.itemButton('Add new visualization menu item')}
|
testId={selectors.pages.AddDashboard.itemButton('Add new visualization menu item')}
|
||||||
label={t('dashboard.add-menu.visualization', 'Visualization')}
|
label={t('dashboard.add-menu.visualization', 'Visualization')}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const id = dashboard.onCreateNewPanel();
|
const vizPanel = dashboard.onCreateNewPanel();
|
||||||
DashboardInteractions.toolbarAddButtonClicked({ item: 'add_visualization' });
|
DashboardInteractions.toolbarAddButtonClicked({ item: 'add_visualization' });
|
||||||
locationService.partial({ editPanel: id });
|
dashboard.setState({ editPanel: buildPanelEditScene(vizPanel, true) });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
@ -415,11 +415,11 @@ export function ToolbarActions({ dashboard }: Props) {
|
|||||||
|
|
||||||
toolbarActions.push({
|
toolbarActions.push({
|
||||||
group: 'main-buttons',
|
group: 'main-buttons',
|
||||||
condition: isEditingPanel && !isEditingLibraryPanel && !editview && !meta.isNew && !isViewingPanel,
|
condition: isEditingPanel && !isEditingLibraryPanel && !editview && !isViewingPanel,
|
||||||
render: () => (
|
render: () => (
|
||||||
<Button
|
<Button
|
||||||
onClick={editPanel?.onDiscard}
|
onClick={editPanel?.onDiscard}
|
||||||
tooltip="Discard panel changes"
|
tooltip={editPanel?.state.isNewPanel ? 'Discard panel' : 'Discard panel changes'}
|
||||||
size="sm"
|
size="sm"
|
||||||
disabled={!isEditedPanelDirty || !isDirty}
|
disabled={!isEditedPanelDirty || !isDirty}
|
||||||
key="discard"
|
key="discard"
|
||||||
@ -427,7 +427,7 @@ export function ToolbarActions({ dashboard }: Props) {
|
|||||||
variant="destructive"
|
variant="destructive"
|
||||||
data-testid={selectors.components.NavToolbar.editDashboard.discardChangesButton}
|
data-testid={selectors.components.NavToolbar.editDashboard.discardChangesButton}
|
||||||
>
|
>
|
||||||
Discard panel changes
|
{editPanel?.state.isNewPanel ? 'Discard panel' : 'Discard panel changes'}
|
||||||
</Button>
|
</Button>
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
@ -76,6 +76,7 @@ it('creates new visualization when clicked Add visualization', () => {
|
|||||||
|
|
||||||
expect(reportInteraction).toHaveBeenCalledWith('dashboards_emptydashboard_clicked', { item: 'add_visualization' });
|
expect(reportInteraction).toHaveBeenCalledWith('dashboards_emptydashboard_clicked', { item: 'add_visualization' });
|
||||||
expect(locationService.partial).toHaveBeenCalled();
|
expect(locationService.partial).toHaveBeenCalled();
|
||||||
|
expect(locationService.partial).toHaveBeenCalledWith({ editPanel: undefined, firstPanel: true });
|
||||||
expect(onCreateNewPanel).toHaveBeenCalled();
|
expect(onCreateNewPanel).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
onCreateNewPanel,
|
onCreateNewPanel,
|
||||||
onImportDashboard,
|
onImportDashboard,
|
||||||
} from 'app/features/dashboard/utils/dashboard';
|
} from 'app/features/dashboard/utils/dashboard';
|
||||||
|
import { buildPanelEditScene } from 'app/features/dashboard-scene/panel-edit/PanelEditor';
|
||||||
import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene';
|
import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene';
|
||||||
import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions';
|
import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions';
|
||||||
import { useDispatch, useSelector } from 'app/types';
|
import { useDispatch, useSelector } from 'app/types';
|
||||||
@ -31,13 +32,15 @@ const DashboardEmpty = ({ dashboard, canCreate }: Props) => {
|
|||||||
const onAddVisualization = () => {
|
const onAddVisualization = () => {
|
||||||
let id;
|
let id;
|
||||||
if (dashboard instanceof DashboardScene) {
|
if (dashboard instanceof DashboardScene) {
|
||||||
id = dashboard.onCreateNewPanel();
|
const panel = dashboard.onCreateNewPanel();
|
||||||
|
dashboard.setState({ editPanel: buildPanelEditScene(panel, true) });
|
||||||
|
locationService.partial({ firstPanel: true });
|
||||||
} else {
|
} else {
|
||||||
id = onCreateNewPanel(dashboard, initialDatasource);
|
id = onCreateNewPanel(dashboard, initialDatasource);
|
||||||
dispatch(setInitialDatasource(undefined));
|
dispatch(setInitialDatasource(undefined));
|
||||||
|
locationService.partial({ editPanel: id, firstPanel: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
locationService.partial({ editPanel: id, firstPanel: true });
|
|
||||||
DashboardInteractions.emptyDashboardButtonClicked({ item: 'add_visualization' });
|
DashboardInteractions.emptyDashboardButtonClicked({ item: 'add_visualization' });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user