mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
d66d7a9642
commit
9ba13dd309
@ -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"],
|
||||
|
@ -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 |
|
||||
|
@ -54,7 +54,6 @@ export interface FeatureToggles {
|
||||
accessControlOnCall?: boolean;
|
||||
nestedFolders?: boolean;
|
||||
nestedFolderPicker?: boolean;
|
||||
emptyDashboardPage?: boolean;
|
||||
disablePrometheusExemplarSampling?: boolean;
|
||||
alertingBacktesting?: boolean;
|
||||
editPanelCSVDragAndDrop?: boolean;
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
@ -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();
|
||||
});
|
||||
});
|
@ -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>;
|
@ -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;
|
||||
}
|
@ -1 +0,0 @@
|
||||
export { AddPanelWidget } from './AddPanelWidget';
|
@ -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) {
|
||||
|
@ -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}
|
||||
/>
|
||||
|
@ -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]);
|
||||
|
@ -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} />;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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: [],
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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 ?? [])];
|
||||
|
@ -31,7 +31,6 @@
|
||||
@import 'layout/lists';
|
||||
|
||||
// COMPONENTS
|
||||
@import '../app/features/dashboard/components/AddPanelWidget/AddPanelWidget';
|
||||
@import 'components/scrollbar';
|
||||
@import 'components/buttons';
|
||||
@import 'components/navs';
|
||||
|
Loading…
Reference in New Issue
Block a user