Dashboards: Remove emptyDashboardPage feature flag (#81188)

* remove emptyDashboardPage feature toggle from DashNav

* remove emptyDashboardPage feature toggle from NewDashboardWithDS

* remove emptyDashboardPage feature toggle from DashboardGrid

* remove emptyDashboardPage feature toggle from DashboardModel

* remove emptyDashboardPage feature toggle from initDashboard

* remove unused AddPanelWidged component

* remove add-panel type from test

* remove emptyDashboardPage feature flag from registry.go
This commit is contained in:
Sergej-Vlasov 2024-01-25 14:04:29 +00:00 committed by GitHub
parent d66d7a9642
commit 9ba13dd309
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 18 additions and 554 deletions

View File

@ -2434,22 +2434,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not use any type assertions.", "1"],
[0, 0, 0, "Do not use any type assertions.", "2"]
],
"public/app/features/dashboard/components/AddPanelWidget/AddPanelWidget.test.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
"public/app/features/dashboard/components/AddPanelWidget/AddPanelWidget.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "1"],
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "2"],
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "3"],
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "4"],
[0, 0, 0, "Styles should be written using objects.", "5"],
[0, 0, 0, "Styles should be written using objects.", "6"],
[0, 0, 0, "Styles should be written using objects.", "7"],
[0, 0, 0, "Styles should be written using objects.", "8"],
[0, 0, 0, "Styles should be written using objects.", "9"],
[0, 0, 0, "Styles should be written using objects.", "10"]
],
"public/app/features/dashboard/components/AddWidgetModal/AddWidgetModal.tsx:5381": [
[0, 0, 0, "Styles should be written using objects.", "0"],
[0, 0, 0, "Styles should be written using objects.", "1"],

View File

@ -32,7 +32,6 @@ Some features are enabled by default. You can disable these feature by setting t
| `athenaAsyncQueryDataSupport` | Enable async query data support for Athena | Yes |
| `cloudwatchNewRegionsHandler` | Refactor of /regions endpoint, no user-facing changes | Yes |
| `nestedFolderPicker` | Enables the new folder picker to work with nested folders. Requires the nestedFolders feature toggle | Yes |
| `emptyDashboardPage` | Enable the redesigned user interface of a dashboard page that includes no panels | Yes |
| `disablePrometheusExemplarSampling` | Disable Prometheus exemplar sampling | |
| `logsContextDatasourceUi` | Allow datasource to provide custom UI for context view | Yes |
| `lokiQuerySplitting` | Split large interval queries into subqueries with smaller time intervals | Yes |

View File

@ -54,7 +54,6 @@ export interface FeatureToggles {
accessControlOnCall?: boolean;
nestedFolders?: boolean;
nestedFolderPicker?: boolean;
emptyDashboardPage?: boolean;
disablePrometheusExemplarSampling?: boolean;
alertingBacktesting?: boolean;
editPanelCSVDragAndDrop?: boolean;

View File

@ -313,17 +313,6 @@ var (
AllowSelfServe: true,
Created: time.Date(2023, time.July, 24, 12, 0, 0, 0, time.UTC),
},
{
Name: "emptyDashboardPage",
Description: "Enable the redesigned user interface of a dashboard page that includes no panels",
Stage: FeatureStageGeneralAvailability,
FrontendOnly: true,
Expression: "true", // enabled by default
Owner: grafanaDashboardsSquad,
AllowSelfServe: false,
HideFromAdminPage: true,
Created: time.Date(2023, time.March, 28, 12, 0, 0, 0, time.UTC),
},
{
Name: "disablePrometheusExemplarSampling",
Description: "Disable Prometheus exemplar sampling",

View File

@ -35,7 +35,6 @@ mysqlAnsiQuotes,experimental,@grafana/backend-platform,2022-10-12,false,false,fa
accessControlOnCall,preview,@grafana/identity-access-team,2022-10-19,false,false,false,false
nestedFolders,preview,@grafana/backend-platform,2022-10-22,false,false,false,false
nestedFolderPicker,GA,@grafana/grafana-frontend-platform,2023-07-24,false,false,false,true
emptyDashboardPage,GA,@grafana/dashboards-squad,2023-03-28,false,false,false,true
disablePrometheusExemplarSampling,GA,@grafana/observability-metrics,2022-12-19,false,false,false,false
alertingBacktesting,experimental,@grafana/alerting-squad,2022-10-20,false,false,false,false
editPanelCSVDragAndDrop,experimental,@grafana/grafana-bi-squad,2022-12-20,false,false,false,true

1 Name Stage Owner Created requiresDevMode RequiresLicense RequiresRestart FrontendOnly
35 accessControlOnCall preview @grafana/identity-access-team 2022-10-19 false false false false
36 nestedFolders preview @grafana/backend-platform 2022-10-22 false false false false
37 nestedFolderPicker GA @grafana/grafana-frontend-platform 2023-07-24 false false false true
emptyDashboardPage GA @grafana/dashboards-squad 2023-03-28 false false false true
38 disablePrometheusExemplarSampling GA @grafana/observability-metrics 2022-12-19 false false false false
39 alertingBacktesting experimental @grafana/alerting-squad 2022-10-20 false false false false
40 editPanelCSVDragAndDrop experimental @grafana/grafana-bi-squad 2022-12-20 false false false true

View File

@ -151,10 +151,6 @@ const (
// Enables the new folder picker to work with nested folders. Requires the nestedFolders feature toggle
FlagNestedFolderPicker = "nestedFolderPicker"
// FlagEmptyDashboardPage
// Enable the redesigned user interface of a dashboard page that includes no panels
FlagEmptyDashboardPage = "emptyDashboardPage"
// FlagDisablePrometheusExemplarSampling
// Disable Prometheus exemplar sampling
FlagDisablePrometheusExemplarSampling = "disablePrometheusExemplarSampling"

View File

@ -1,32 +0,0 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { PanelModel } from '../../state';
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
import { AddPanelWidgetUnconnected as AddPanelWidget, Props } from './AddPanelWidget';
const getTestContext = (propOverrides?: object) => {
const props: Props = {
dashboard: createDashboardModelFixture(),
panel: new PanelModel({}),
addPanel: jest.fn() as any,
};
Object.assign(props, propOverrides);
return render(<AddPanelWidget {...props} />);
};
describe('AddPanelWidget', () => {
it('should render component without error', () => {
expect(() => {
getTestContext();
});
});
it('should render the add panel actions', () => {
getTestContext();
expect(screen.getByText(/Add a new panel/i)).toBeInTheDocument();
expect(screen.getByText(/Add a new row/i)).toBeInTheDocument();
expect(screen.getByText(/Add a panel from the panel library/i)).toBeInTheDocument();
});
});

View File

@ -1,299 +0,0 @@
import { css, cx, keyframes } from '@emotion/css';
import { chain, cloneDeep, defaults, find, sortBy } from 'lodash';
import React, { useMemo, useState } from 'react';
import { connect, MapDispatchToProps } from 'react-redux';
import tinycolor from 'tinycolor2';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { locationService, reportInteraction } from '@grafana/runtime';
import { Icon, IconButton, useStyles2 } from '@grafana/ui';
import { CardButton } from 'app/core/components/CardButton';
import config from 'app/core/config';
import { LS_PANEL_COPY_KEY } from 'app/core/constants';
import store from 'app/core/store';
import { addPanel } from 'app/features/dashboard/state/reducers';
import {
LibraryPanelsSearch,
LibraryPanelsSearchVariant,
} from '../../../library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch';
import { LibraryElementDTO } from '../../../library-panels/types';
import { DashboardModel, PanelModel } from '../../state';
export type PanelPluginInfo = { id: number; defaults: { gridPos: { w: number; h: number }; title: string } };
export interface OwnProps {
panel: PanelModel;
dashboard: DashboardModel;
}
export interface DispatchProps {
addPanel: typeof addPanel;
}
export type Props = OwnProps & DispatchProps;
const getCopiedPanelPlugins = () => {
const panels = chain(config.panels)
.filter({ hideFromList: false })
.map((item) => item)
.value();
const copiedPanels = [];
const copiedPanelJson = store.get(LS_PANEL_COPY_KEY);
if (copiedPanelJson) {
const copiedPanel = JSON.parse(copiedPanelJson);
const pluginInfo: any = find(panels, { id: copiedPanel.type });
if (pluginInfo) {
const pluginCopy = cloneDeep(pluginInfo);
pluginCopy.name = copiedPanel.title;
pluginCopy.sort = -1;
pluginCopy.defaults = copiedPanel;
copiedPanels.push(pluginCopy);
}
}
return sortBy(copiedPanels, 'sort');
};
export const AddPanelWidgetUnconnected = ({ panel, dashboard }: Props) => {
const [addPanelView, setAddPanelView] = useState(false);
const onCancelAddPanel = (evt: React.MouseEvent<HTMLButtonElement>) => {
evt.preventDefault();
dashboard.removePanel(panel);
};
const onBack = () => {
setAddPanelView(false);
};
const onCreateNewPanel = () => {
const { gridPos } = panel;
const newPanel: Partial<PanelModel> = {
type: 'timeseries',
title: 'Panel Title',
datasource: panel.datasource,
gridPos: { x: gridPos.x, y: gridPos.y, w: gridPos.w, h: gridPos.h },
isNew: true,
};
dashboard.addPanel(newPanel);
dashboard.removePanel(panel);
locationService.partial({ editPanel: newPanel.id });
};
const onPasteCopiedPanel = (panelPluginInfo: PanelPluginInfo) => {
const { gridPos } = panel;
const newPanel = {
type: panelPluginInfo.id,
title: 'Panel Title',
gridPos: {
x: gridPos.x,
y: gridPos.y,
w: panelPluginInfo.defaults.gridPos.w,
h: panelPluginInfo.defaults.gridPos.h,
},
};
// apply panel template / defaults
if (panelPluginInfo.defaults) {
defaults(newPanel, panelPluginInfo.defaults);
newPanel.title = panelPluginInfo.defaults.title;
store.delete(LS_PANEL_COPY_KEY);
}
dashboard.addPanel(newPanel);
dashboard.removePanel(panel);
};
const onAddLibraryPanel = (panelInfo: LibraryElementDTO) => {
const { gridPos } = panel;
const newPanel = {
...panelInfo.model,
gridPos,
libraryPanel: panelInfo,
};
dashboard.addPanel(newPanel);
dashboard.removePanel(panel);
};
const onCreateNewRow = () => {
const newRow = {
type: 'row',
title: 'Row title',
gridPos: { x: 0, y: 0 },
};
dashboard.addPanel(newRow);
dashboard.removePanel(panel);
};
const styles = useStyles2(getStyles);
const copiedPanelPlugins = useMemo(() => getCopiedPanelPlugins(), []);
return (
<div className={styles.wrapper}>
<div className={cx('panel-container', styles.callToAction)}>
<AddPanelWidgetHandle onCancel={onCancelAddPanel} onBack={addPanelView ? onBack : undefined} styles={styles}>
{addPanelView ? 'Add panel from panel library' : 'Add panel'}
</AddPanelWidgetHandle>
{addPanelView ? (
<LibraryPanelsSearch onClick={onAddLibraryPanel} variant={LibraryPanelsSearchVariant.Tight} showPanelFilter />
) : (
<div className={styles.actionsWrapper}>
<CardButton
icon="file-blank"
aria-label={selectors.pages.AddDashboard.addNewPanel}
onClick={() => {
reportInteraction('Create new panel');
onCreateNewPanel();
}}
>
Add a new panel
</CardButton>
<CardButton
icon="wrap-text"
aria-label={selectors.pages.AddDashboard.addNewRow}
onClick={() => {
reportInteraction('Create new row');
onCreateNewRow();
}}
>
Add a new row
</CardButton>
<CardButton
icon="book-open"
aria-label={selectors.pages.AddDashboard.addNewPanelLibrary}
onClick={() => {
reportInteraction('Add a panel from the panel library');
setAddPanelView(true);
}}
>
Add a panel from the panel library
</CardButton>
{copiedPanelPlugins.length === 1 && (
<CardButton
icon="clipboard-alt"
aria-label={selectors.pages.AddDashboard.addNewPanelLibrary}
onClick={() => {
reportInteraction('Paste panel from clipboard');
onPasteCopiedPanel(copiedPanelPlugins[0]);
}}
>
Paste panel from clipboard
</CardButton>
)}
</div>
)}
</div>
</div>
);
};
const mapDispatchToProps: MapDispatchToProps<DispatchProps, OwnProps> = { addPanel };
export const AddPanelWidget = connect(undefined, mapDispatchToProps)(AddPanelWidgetUnconnected);
interface AddPanelWidgetHandleProps {
onCancel: (e: React.MouseEvent<HTMLButtonElement>) => void;
onBack?: () => void;
children?: string;
styles: AddPanelStyles;
}
const AddPanelWidgetHandle = ({ children, onBack, onCancel, styles }: AddPanelWidgetHandleProps) => {
return (
<div className={cx(styles.headerRow, 'grid-drag-handle')}>
{onBack && (
<div className={styles.backButton}>
<IconButton name="arrow-left" onClick={onBack} size="xl" tooltip="Go back" />
</div>
)}
{!onBack && (
<div className={styles.backButton}>
<Icon name="panel-add" size="xl" />
</div>
)}
{children && <span>{children}</span>}
<div className="flex-grow-1" />
<IconButton aria-label="Close 'Add Panel' widget" name="times" onClick={onCancel} tooltip="Close widget" />
</div>
);
};
const getStyles = (theme: GrafanaTheme2) => {
const pulsate = keyframes`
0% {box-shadow: 0 0 0 2px ${theme.colors.background.canvas}, 0 0 0px 4px ${theme.colors.primary.main};}
50% {box-shadow: 0 0 0 2px ${theme.components.dashboard.background}, 0 0 0px 4px ${tinycolor(
theme.colors.primary.main
)
.darken(20)
.toHexString()};}
100% {box-shadow: 0 0 0 2px ${theme.components.dashboard.background}, 0 0 0px 4px ${theme.colors.primary.main};}
`;
return {
// wrapper is used to make sure box-shadow animation isn't cut off in dashboard page
wrapper: css`
height: 100%;
padding-top: ${theme.spacing(0.5)};
`,
callToAction: css`
overflow: hidden;
outline: 2px dotted transparent;
outline-offset: 2px;
box-shadow:
0 0 0 2px black,
0 0 0px 4px #1f60c4;
animation: ${pulsate} 2s ease infinite;
`,
actionsWrapper: css`
height: 100%;
display: grid;
grid-template-columns: repeat(2, 1fr);
column-gap: ${theme.spacing(1)};
row-gap: ${theme.spacing(1)};
padding: ${theme.spacing(0, 1, 1, 1)};
// This is to make the last action full width (if by itself)
& > div:nth-child(2n-1):nth-last-of-type(1) {
grid-column: span 2;
}
`,
headerRow: css`
display: flex;
align-items: center;
height: 38px;
flex-shrink: 0;
width: 100%;
font-size: ${theme.typography.fontSize};
font-weight: ${theme.typography.fontWeightMedium};
padding-left: ${theme.spacing(1)};
transition: background-color 0.1s ease-in-out;
cursor: move;
&:hover {
background: ${theme.colors.background.secondary};
}
`,
backButton: css`
display: flex;
align-items: center;
cursor: pointer;
padding-left: ${theme.spacing(0.5)};
width: ${theme.spacing(4)};
`,
noMargin: css`
margin: 0;
`,
};
};
type AddPanelStyles = ReturnType<typeof getStyles>;

View File

@ -1,78 +0,0 @@
.add-panel-widget-container {
height: 100%;
}
.add-panel-widget {
height: 100%;
}
.add-panel-widget__header {
top: 0;
position: absolute;
padding: 0 8px;
display: flex;
align-items: center;
width: 100%;
cursor: move;
background: $page-header-bg;
box-shadow: $page-header-shadow;
border-bottom: 1px solid $page-header-border-color;
.gicon {
font-size: 30px;
margin-right: $space-md;
}
&:hover {
transition: background-color 0.1s ease-in-out;
background-color: $panel-header-hover-bg;
}
}
.add-panel-widget__title {
font-size: $font-size-md;
font-weight: $font-weight-semi-bold;
margin-right: $space-xl;
}
.add-panel-widget__link {
margin: 0 $space-sm;
width: 170px;
height: 88px !important;
flex-direction: column !important;
}
.add-panel-widget__icon {
margin-bottom: $space-sm;
.gicon {
color: white;
height: 44px;
width: 53px;
position: relative;
left: 5px;
}
}
.add-panel-widget__create {
display: inherit;
margin-bottom: $space-lg;
// this is to have the big button appear centered
margin-top: 55px;
}
.add-panel-widget__actions {
display: inherit;
}
.add-panel-widget__action {
margin: 0 $space-xs;
}
.add-panel-widget__btn-container {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}

View File

@ -1 +0,0 @@
export { AddPanelWidget } from './AddPanelWidget';

View File

@ -59,7 +59,6 @@ export interface OwnProps {
hideTimePicker: boolean;
folderTitle?: string;
title: string;
onAddPanel: () => void;
}
export function addCustomLeftAction(content: DynamicDashNavButtonModel) {
@ -251,7 +250,7 @@ export const DashNav = React.memo<Props>((props) => {
};
const renderRightActions = () => {
const { dashboard, onAddPanel, isFullscreen, kioskMode, hideTimePicker } = props;
const { dashboard, isFullscreen, kioskMode, hideTimePicker } = props;
const { canSave, canEdit, showSettings, canShare } = dashboard.meta;
const { snapshot } = dashboard;
const snapshotUrl = snapshot && snapshot.originalUrl;
@ -310,25 +309,13 @@ export const DashNav = React.memo<Props>((props) => {
}
if (canEdit && !isFullscreen) {
if (config.featureToggles.emptyDashboardPage) {
buttons.push(
<AddPanelButton
dashboard={dashboard}
onToolbarAddMenuOpen={DashboardInteractions.toolbarAddClick}
key="panel-add-dropdown"
/>
);
} else {
buttons.push(
<ToolbarButton
tooltip={t('dashboard.toolbar.add-panel', 'Add panel')}
icon="panel-add"
iconSize="xl"
onClick={onAddPanel}
key="button-panel-add"
/>
);
}
buttons.push(
<AddPanelButton
dashboard={dashboard}
onToolbarAddMenuOpen={DashboardInteractions.toolbarAddClick}
key="panel-add-dropdown"
/>
);
}
if (canShare) {

View File

@ -37,7 +37,6 @@ import { liveTimer } from '../dashgrid/liveTimer';
import { getTimeSrv } from '../services/TimeSrv';
import { cleanUpDashboardAndVariables } from '../state/actions';
import { initDashboard } from '../state/initDashboard';
import { calculateNewPanelGridPos } from '../utils/panel';
import { DashboardPageRouteParams, DashboardPageRouteSearchParams } from './types';
@ -265,29 +264,6 @@ export class UnthemedDashboardPage extends PureComponent<Props, State> {
return updateStatePageNavFromProps(props, updatedState);
}
// Todo: Remove this when we remove the emptyDashboardPage toggle
onAddPanel = () => {
const { dashboard } = this.props;
if (!dashboard) {
return;
}
// Return if the "Add panel" exists already
if (dashboard.panels.length > 0 && dashboard.panels[0].type === 'add-panel') {
return;
}
dashboard.addPanel({
type: 'add-panel',
gridPos: calculateNewPanelGridPos(dashboard),
title: 'Panel Title',
});
// scroll to top after adding panel
this.setState({ updateScrollTop: 0 });
};
setScrollRef = (scrollElement: HTMLDivElement): void => {
this.setState({ scrollElement });
};
@ -355,7 +331,6 @@ export class UnthemedDashboardPage extends PureComponent<Props, State> {
title={dashboard.title}
folderTitle={dashboard.meta.folderTitle}
isFullscreen={!!viewPanel}
onAddPanel={this.onAddPanel}
kioskMode={kioskMode}
hideTimePicker={dashboard.timepicker.hidden}
/>

View File

@ -1,11 +1,10 @@
import React, { useEffect, useState } from 'react';
import { config, getDataSourceSrv, locationService } from '@grafana/runtime';
import { getDataSourceSrv, locationService } from '@grafana/runtime';
import { Page } from 'app/core/components/Page/Page';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import { useDispatch } from 'app/types';
import { getNewDashboardModelData, setDashboardToFetchFromLocalStorage } from '../state/initDashboard';
import { setInitialDatasource } from '../state/reducers';
export default function NewDashboardWithDS(props: GrafanaRouteComponentProps<{ datasourceUid: string }>) {
@ -20,21 +19,7 @@ export default function NewDashboardWithDS(props: GrafanaRouteComponentProps<{ d
return;
}
if (!config.featureToggles.emptyDashboardPage) {
const newDashboard = getNewDashboardModelData();
const { dashboard } = newDashboard;
dashboard.panels[0] = {
...dashboard.panels[0],
datasource: {
uid: ds.uid,
type: ds.type,
},
};
setDashboardToFetchFromLocalStorage(newDashboard);
} else {
dispatch(setInitialDatasource(datasourceUid));
}
dispatch(setInitialDatasource(datasourceUid));
locationService.replace('/dashboard/new');
}, [datasourceUid, dispatch]);

View File

@ -14,7 +14,6 @@ import { VariablesChanged } from 'app/features/variables/types';
import { DashboardPanelsChangedEvent } from 'app/types/events';
import { AddLibraryPanelWidget } from '../components/AddLibraryPanelWidget';
import { AddPanelWidget } from '../components/AddPanelWidget';
import { DashboardRow } from '../components/DashboardRow';
import { DashboardModel, PanelModel } from '../state';
import { GridPos } from '../state/PanelModel';
@ -262,11 +261,6 @@ export class DashboardGrid extends PureComponent<Props, State> {
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') {
return <AddPanelWidget key={panel.key} panel={panel} dashboard={this.props.dashboard} />;
}
if (panel.type === 'add-library-panel') {
return <AddLibraryPanelWidget key={panel.key} panel={panel} dashboard={this.props.dashboard} />;
}
@ -302,7 +296,7 @@ export class DashboardGrid extends PureComponent<Props, State> {
render() {
const { isEditable, dashboard } = this.props;
if (config.featureToggles.emptyDashboardPage && dashboard.panels.length === 0) {
if (dashboard.panels.length === 0) {
return <DashboardEmpty dashboard={dashboard} canCreate={isEditable} />;
}

View File

@ -116,17 +116,11 @@ describe('DashboardModel', () => {
expect(keys[1]).toBe('editable');
});
it('should remove add panel panels', () => {
it('should have only 1 panel after adding panel to a new dashboard', () => {
const model = createDashboardModelFixture();
model.addPanel({
type: 'add-panel',
});
model.addPanel({
type: 'graph',
});
model.addPanel({
type: 'add-panel',
});
const saveModel = model.getSaveModelClone();
const panels = saveModel.panels;

View File

@ -302,12 +302,8 @@ export class DashboardModel implements TimeModel {
}
private getPanelSaveModels() {
// Todo: Remove panel.type === 'add-panel' when we remove the emptyDashboardPage toggle
return this.panels
.filter(
(panel) =>
this.isSnapshotTruthy() || !(panel.type === 'add-panel' || panel.repeatPanelId || panel.repeatedByRow)
)
.filter((panel) => this.isSnapshotTruthy() || !(panel.repeatPanelId || panel.repeatedByRow))
.map((panel) => {
// Clean libarary panels on save
if (panel.libraryPanel) {

View File

@ -91,7 +91,7 @@ function describeInitScenario(description: string, scenarioFn: ScenarioFn) {
title: 'My cool dashboard',
panels: [
{
type: 'add-panel',
type: 'stat',
gridPos: { x: 0, y: 0, w: 12, h: 9 },
title: 'Panel Title',
id: 2,

View File

@ -130,7 +130,7 @@ async function fetchDashboard(
if (args.urlFolderUid) {
await dispatch(getFolderByUid(args.urlFolderUid));
}
return getNewDashboardModelData(args.urlFolderUid, args.panelType);
return getNewDashboardModelData(args.urlFolderUid);
}
case DashboardRoutes.Path: {
const path = args.urlSlug ?? '';
@ -300,20 +300,7 @@ export function initDashboard(args: InitDashboardArgs): ThunkResult<void> {
};
}
export function getNewDashboardModelData(
urlFolderUid?: string,
panelType?: string
): { dashboard: any; meta: DashboardMeta } {
const panels = config.featureToggles.emptyDashboardPage
? []
: [
{
type: panelType ?? 'add-panel',
gridPos: { x: 0, y: 0, w: 12, h: 9 },
title: 'Panel Title',
},
];
export function getNewDashboardModelData(urlFolderUid?: string): { dashboard: any; meta: DashboardMeta } {
const data = {
meta: {
canStar: false,
@ -324,7 +311,7 @@ export function getNewDashboardModelData(
},
dashboard: {
title: 'New dashboard',
panels,
panels: [],
},
};

View File

@ -22,15 +22,6 @@ interface AddPanelToDashboardOptions {
time: Dashboard['time'];
}
function createDashboard(): DashboardDTO {
const dto = getNewDashboardModelData();
// getNewDashboardModelData adds by default the "add-panel" panel. We don't want that.
dto.dashboard.panels = [];
return dto;
}
/**
* Returns transformations for the logs table visualisation in explore.
* If the logs table supports a labels column, we need to extract the fields.
@ -96,7 +87,7 @@ export async function setDashboardInLocalStorage(options: AddPanelToDashboardOpt
throw AddToDashboardError.FETCH_DASHBOARD;
}
} else {
dto = createDashboard();
dto = getNewDashboardModelData();
}
dto.dashboard.panels = [panel, ...(dto.dashboard.panels ?? [])];

View File

@ -31,7 +31,6 @@
@import 'layout/lists';
// COMPONENTS
@import '../app/features/dashboard/components/AddPanelWidget/AddPanelWidget';
@import 'components/scrollbar';
@import 'components/buttons';
@import 'components/navs';