mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
DashboardScene: Show dashboard not found view (#89342)
* DashboardScene: Show dashboard not found view * Test fix * Use correct selector
This commit is contained in:
parent
8eabef1f91
commit
d46df10d30
@ -603,4 +603,7 @@ export const Components = {
|
||||
headerOrderSwitch: 'data-testid header-order-switch',
|
||||
headerPreviewSwitch: 'data-testid header-preview-switch',
|
||||
},
|
||||
EntityNotFound: {
|
||||
container: 'data-testid entity-not-found',
|
||||
},
|
||||
};
|
||||
|
@ -2,6 +2,7 @@ import { css } from '@emotion/css';
|
||||
import React from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { EmptyState, TextLink, useStyles2 } from '@grafana/ui';
|
||||
|
||||
export interface Props {
|
||||
@ -15,7 +16,7 @@ export function EntityNotFound({ entity = 'Page' }: Props) {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.container} data-testid={selectors.components.EntityNotFound.container}>
|
||||
<EmptyState message={`${entity} not found`} variant="not-found">
|
||||
We're looking but can't seem to find this {entity.toLowerCase()}. Try returning{' '}
|
||||
<TextLink href="/">home</TextLink> or seeking help on the{' '}
|
||||
|
@ -392,6 +392,10 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> {
|
||||
public getPageNav(location: H.Location, navIndex: NavIndex) {
|
||||
const { meta, viewPanelScene, editPanel } = this.state;
|
||||
|
||||
if (meta.dashboardNotFound) {
|
||||
return { text: 'Not found' };
|
||||
}
|
||||
|
||||
let pageNav: NavModelItem = {
|
||||
text: this.state.title,
|
||||
url: getDashboardUrl({
|
||||
|
@ -0,0 +1,65 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { Router } from 'react-router';
|
||||
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
|
||||
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { GrafanaContext } from 'app/core/context/GrafanaContext';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
|
||||
import { transformSaveModelToScene } from '../serialization/transformSaveModelToScene';
|
||||
|
||||
describe('DashboardSceneRenderer', () => {
|
||||
it('should render Not Found notice when dashboard is not found', async () => {
|
||||
const scene = transformSaveModelToScene({
|
||||
meta: {
|
||||
isSnapshot: true,
|
||||
dashboardNotFound: true,
|
||||
canStar: false,
|
||||
canDelete: false,
|
||||
canSave: false,
|
||||
canEdit: false,
|
||||
canShare: false,
|
||||
},
|
||||
dashboard: {
|
||||
title: 'Not found',
|
||||
uid: 'uid',
|
||||
schemaVersion: 0,
|
||||
// Disabling build in annotations to avoid mocking Grafana data source
|
||||
annotations: {
|
||||
list: [
|
||||
{
|
||||
builtIn: 1,
|
||||
datasource: {
|
||||
type: 'grafana',
|
||||
uid: '-- Grafana --',
|
||||
},
|
||||
enable: false,
|
||||
hide: true,
|
||||
iconColor: 'rgba(0, 211, 255, 1)',
|
||||
name: 'Annotations & Alerts',
|
||||
type: 'dashboard',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const store = configureStore({});
|
||||
const context = getGrafanaContextMock();
|
||||
|
||||
render(
|
||||
<GrafanaContext.Provider value={context}>
|
||||
<Provider store={store}>
|
||||
<Router history={locationService.getHistory()}>
|
||||
<scene.Component model={scene} />
|
||||
</Router>
|
||||
</Provider>
|
||||
</GrafanaContext.Provider>
|
||||
);
|
||||
|
||||
expect(await screen.findByTestId(selectors.components.EntityNotFound.container)).toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -7,6 +7,7 @@ import { selectors } from '@grafana/e2e-selectors';
|
||||
import { SceneComponentProps } from '@grafana/scenes';
|
||||
import { CustomScrollbar, useStyles2 } from '@grafana/ui';
|
||||
import { Page } from 'app/core/components/Page/Page';
|
||||
import { EntityNotFound } from 'app/core/components/PageNotFound/EntityNotFound';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
import DashboardEmpty from 'app/features/dashboard/dashgrid/DashboardEmpty';
|
||||
import { useSelector } from 'app/types';
|
||||
@ -35,14 +36,26 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps<DashboardS
|
||||
);
|
||||
}
|
||||
|
||||
const emptyState = <DashboardEmpty dashboard={model} canCreate={!!model.state.meta.canEdit} />;
|
||||
const emptyState = (
|
||||
<DashboardEmpty dashboard={model} canCreate={!!model.state.meta.canEdit} key="dashboard-empty-state" />
|
||||
);
|
||||
|
||||
const withPanels = (
|
||||
<div className={cx(styles.body, !hasControls && styles.bodyWithoutControls)}>
|
||||
<div className={cx(styles.body, !hasControls && styles.bodyWithoutControls)} key="dashboard-panels">
|
||||
<bodyToRender.Component model={bodyToRender} />
|
||||
</div>
|
||||
);
|
||||
|
||||
const notFound = meta.dashboardNotFound && <EntityNotFound entity="Dashboard" key="dashboard-not-found" />;
|
||||
|
||||
let body = [withPanels];
|
||||
|
||||
if (notFound) {
|
||||
body = [notFound];
|
||||
} else if (isEmpty) {
|
||||
body = [emptyState, withPanels];
|
||||
}
|
||||
|
||||
return (
|
||||
<Page navModel={navModel} pageNav={pageNav} layout={PageLayoutType.Custom}>
|
||||
{editPanel && <editPanel.Component model={editPanel} />}
|
||||
@ -55,7 +68,7 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps<DashboardS
|
||||
scopes && isScopesExpanded && styles.pageContainerWithScopesExpanded
|
||||
)}
|
||||
>
|
||||
{scopes && <scopes.Component model={scopes} />}
|
||||
{scopes && !meta.dashboardNotFound && <scopes.Component model={scopes} />}
|
||||
<NavToolbarActions dashboard={model} />
|
||||
{controls && hasControls && (
|
||||
<div
|
||||
@ -71,10 +84,7 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps<DashboardS
|
||||
className={styles.scrollbarContainer}
|
||||
testId={selectors.pages.Dashboard.DashNav.scrollContainer}
|
||||
>
|
||||
<div className={cx(styles.canvasContent, isHomePage && styles.homePagePadding)}>
|
||||
<>{isEmpty && emptyState}</>
|
||||
{withPanels}
|
||||
</div>
|
||||
<div className={cx(styles.canvasContent, isHomePage && styles.homePagePadding)}>{body}</div>
|
||||
</CustomScrollbar>
|
||||
</div>
|
||||
)}
|
||||
|
@ -8,6 +8,7 @@ import { selectors } from '@grafana/e2e-selectors';
|
||||
import { config, locationService } from '@grafana/runtime';
|
||||
import { SceneGridLayout, SceneQueryRunner, SceneTimeRange, UrlSyncContextProvider, VizPanel } from '@grafana/scenes';
|
||||
import { playlistSrv } from 'app/features/playlist/PlaylistSrv';
|
||||
import { DashboardMeta } from 'app/types';
|
||||
|
||||
import { buildPanelEditScene } from '../panel-edit/PanelEditor';
|
||||
|
||||
@ -163,9 +164,27 @@ describe('NavToolbarActions', () => {
|
||||
expect(newShareButton).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Snapshot', () => {
|
||||
it('should show link button when is a snapshot', () => {
|
||||
setup({
|
||||
isSnapshot: true,
|
||||
});
|
||||
|
||||
expect(screen.queryByTestId('button-snapshot')).toBeInTheDocument();
|
||||
});
|
||||
it('should not show link button when is not found dashboard', () => {
|
||||
setup({
|
||||
isSnapshot: true,
|
||||
dashboardNotFound: true,
|
||||
});
|
||||
|
||||
expect(screen.queryByTestId('button-snapshot')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function setup() {
|
||||
function setup(meta?: DashboardMeta) {
|
||||
const dashboard = new DashboardScene({
|
||||
$timeRange: new SceneTimeRange({ from: 'now-6h', to: 'now' }),
|
||||
meta: {
|
||||
@ -177,6 +196,7 @@ function setup() {
|
||||
canStar: true,
|
||||
canAdmin: true,
|
||||
canDelete: true,
|
||||
...meta,
|
||||
},
|
||||
title: 'hello',
|
||||
uid: 'dash-1',
|
||||
|
@ -139,7 +139,7 @@ export function ToolbarActions({ dashboard }: Props) {
|
||||
|
||||
toolbarActions.push({
|
||||
group: 'icon-actions',
|
||||
condition: meta.isSnapshot && !isEditing,
|
||||
condition: meta.isSnapshot && !meta.dashboardNotFound && !isEditing,
|
||||
render: () => (
|
||||
<GoToSnapshotOriginButton
|
||||
key="go-to-snapshot-origin"
|
||||
|
@ -92,7 +92,9 @@ export class DashboardLoaderSrv {
|
||||
return result;
|
||||
})
|
||||
.catch(() => {
|
||||
return this._dashboardLoadFailed('Not found', true);
|
||||
const dash = this._dashboardLoadFailed('Not found', true);
|
||||
dash.dashboard.uid = uid;
|
||||
return dash;
|
||||
});
|
||||
} else {
|
||||
throw new Error('Dashboard uid or slug required');
|
||||
|
Loading…
Reference in New Issue
Block a user