diff --git a/packages/grafana-e2e-selectors/src/selectors/components.ts b/packages/grafana-e2e-selectors/src/selectors/components.ts index 3a763ec3fe5..677fe0d0d84 100644 --- a/packages/grafana-e2e-selectors/src/selectors/components.ts +++ b/packages/grafana-e2e-selectors/src/selectors/components.ts @@ -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', + }, }; diff --git a/public/app/core/components/PageNotFound/EntityNotFound.tsx b/public/app/core/components/PageNotFound/EntityNotFound.tsx index 24edfa76f5c..c749d30aa19 100644 --- a/public/app/core/components/PageNotFound/EntityNotFound.tsx +++ b/public/app/core/components/PageNotFound/EntityNotFound.tsx @@ -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 ( -
+
We're looking but can't seem to find this {entity.toLowerCase()}. Try returning{' '} home or seeking help on the{' '} diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.tsx index e2bc1828f39..2b04bec57de 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.tsx @@ -392,6 +392,10 @@ export class DashboardScene extends SceneObjectBase { 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({ diff --git a/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.test.tsx b/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.test.tsx new file mode 100644 index 00000000000..47d5cd076b3 --- /dev/null +++ b/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.test.tsx @@ -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( + + + + + + + + ); + + expect(await screen.findByTestId(selectors.components.EntityNotFound.container)).toBeInTheDocument(); + }); +}); diff --git a/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.tsx b/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.tsx index 553710923cf..7687efa6107 100644 --- a/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.tsx @@ -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; + const emptyState = ( + + ); const withPanels = ( -
+
); + const notFound = meta.dashboardNotFound && ; + + let body = [withPanels]; + + if (notFound) { + body = [notFound]; + } else if (isEmpty) { + body = [emptyState, withPanels]; + } + return ( {editPanel && } @@ -55,7 +68,7 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps - {scopes && } + {scopes && !meta.dashboardNotFound && } {controls && hasControls && (
-
- <>{isEmpty && emptyState} - {withPanels} -
+
{body}
)} diff --git a/public/app/features/dashboard-scene/scene/NavToolbarActions.test.tsx b/public/app/features/dashboard-scene/scene/NavToolbarActions.test.tsx index 797a80fe51d..ce2bfb8fa66 100644 --- a/public/app/features/dashboard-scene/scene/NavToolbarActions.test.tsx +++ b/public/app/features/dashboard-scene/scene/NavToolbarActions.test.tsx @@ -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', diff --git a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx index 18a6a336ccf..47a714cc1dc 100644 --- a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx +++ b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx @@ -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: () => ( { - 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');