From f71bfd88c5a73b75354f85e2e6fd91289e3d6daa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 6 Jan 2023 15:21:40 +0100 Subject: [PATCH] DataSourceList: Build a dashboard button to open new dashboard in panel edit with data source already set (#60532) * New dashboard with preset data source * Updates * use replace instead * Tests: fix failing tests * Chore: add UID to the error message Co-authored-by: Levente Balogh --- .../AddPanelWidget/AddPanelWidget.tsx | 1 + .../containers/NewDashboardWithDS.tsx | 45 +++++++++++++++++++ .../components/DataSourcesList.test.tsx | 2 +- .../components/DataSourcesList.tsx | 9 +++- .../pages/DataSourcesListPage.test.tsx | 4 +- public/app/routes/routes.tsx | 23 ++++++---- 6 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 public/app/features/dashboard/containers/NewDashboardWithDS.tsx diff --git a/public/app/features/dashboard/components/AddPanelWidget/AddPanelWidget.tsx b/public/app/features/dashboard/components/AddPanelWidget/AddPanelWidget.tsx index 5507d06d2b0..cf158139c4f 100644 --- a/public/app/features/dashboard/components/AddPanelWidget/AddPanelWidget.tsx +++ b/public/app/features/dashboard/components/AddPanelWidget/AddPanelWidget.tsx @@ -75,6 +75,7 @@ export const AddPanelWidgetUnconnected = ({ panel, dashboard }: Props) => { const newPanel: Partial = { type: 'timeseries', title: 'Panel Title', + datasource: panel.datasource, gridPos: { x: gridPos.x, y: gridPos.y, w: gridPos.w, h: gridPos.h }, }; diff --git a/public/app/features/dashboard/containers/NewDashboardWithDS.tsx b/public/app/features/dashboard/containers/NewDashboardWithDS.tsx new file mode 100644 index 00000000000..833d85fa0cc --- /dev/null +++ b/public/app/features/dashboard/containers/NewDashboardWithDS.tsx @@ -0,0 +1,45 @@ +import React, { useEffect, useState } from 'react'; + +import { getDataSourceSrv, locationService } from '@grafana/runtime'; +import { Page } from 'app/core/components/Page/Page'; +import { GrafanaRouteComponentProps } from 'app/core/navigation/types'; + +import { getNewDashboardModelData, setDashboardToFetchFromLocalStorage } from '../state/initDashboard'; + +export default function NewDashboardWithDS(props: GrafanaRouteComponentProps<{ datasourceUid: string }>) { + const [error, setError] = useState(null); + const { datasourceUid } = props.match.params; + + useEffect(() => { + const ds = getDataSourceSrv().getInstanceSettings(datasourceUid); + if (!ds) { + setError('Data source not found'); + return; + } + + const newDashboard = getNewDashboardModelData(); + const { dashboard } = newDashboard; + dashboard.panels[0] = { + ...dashboard.panels[0], + datasource: { + uid: ds.uid, + type: ds.type, + }, + }; + + setDashboardToFetchFromLocalStorage(newDashboard); + locationService.replace('/dashboard/new'); + }, [datasourceUid]); + + if (error) { + return ( + + +
Data source with UID "{datasourceUid}" not found.
+
+
+ ); + } + + return null; +} diff --git a/public/app/features/datasources/components/DataSourcesList.test.tsx b/public/app/features/datasources/components/DataSourcesList.test.tsx index 36db8204a1d..79ecf990151 100644 --- a/public/app/features/datasources/components/DataSourcesList.test.tsx +++ b/public/app/features/datasources/components/DataSourcesList.test.tsx @@ -38,7 +38,7 @@ describe('', () => { expect(await screen.findAllByRole('listitem')).toHaveLength(3); expect(await screen.findAllByRole('heading')).toHaveLength(3); - expect(await screen.findAllByRole('link', { name: 'Build a Dashboard' })).toHaveLength(3); + expect(await screen.findAllByRole('link', { name: /Build a dashboard/i })).toHaveLength(3); expect(await screen.findAllByRole('link', { name: 'Explore' })).toHaveLength(3); }); diff --git a/public/app/features/datasources/components/DataSourcesList.tsx b/public/app/features/datasources/components/DataSourcesList.tsx index 281d2e7dd67..5ddf8953038 100644 --- a/public/app/features/datasources/components/DataSourcesList.tsx +++ b/public/app/features/datasources/components/DataSourcesList.tsx @@ -100,8 +100,13 @@ export function DataSourcesListView({ ]} - - Build a Dashboard + + Build a dashboard {hasExploreRights && ( { getDataSourcesMock.mockResolvedValue(getMockDataSources(3)); setup({ isSortAscending: true }); - expect(await screen.findAllByRole('link', { name: 'Build a Dashboard' })).toHaveLength(3); + expect(await screen.findAllByRole('link', { name: /Build a dashboard/i })).toHaveLength(3); expect(screen.queryAllByRole('link', { name: 'Explore' })).toHaveLength(0); }); @@ -88,7 +88,7 @@ describe('Render', () => { getDataSourcesMock.mockResolvedValue(getMockDataSources(3)); setup({ isSortAscending: true }); - expect(await screen.findAllByRole('link', { name: 'Build a Dashboard' })).toHaveLength(3); + expect(await screen.findAllByRole('link', { name: /Build a dashboard/i })).toHaveLength(3); expect(screen.queryAllByRole('link', { name: 'Explore' })).toHaveLength(3); }); diff --git a/public/app/routes/routes.tsx b/public/app/routes/routes.tsx index cd224d9bb75..f2895ca0785 100644 --- a/public/app/routes/routes.tsx +++ b/public/app/routes/routes.tsx @@ -74,14 +74,6 @@ export function getAppRoutes(): RouteDescriptor[] { () => import(/* webpackChunkName: "DashboardPage" */ '../features/dashboard/containers/DashboardPage') ), }, - { - path: '/dashboard/:type/:slug', - pageClass: 'page-dashboard', - routeName: DashboardRoutes.Normal, - component: SafeDynamicImport( - () => import(/* webpackChunkName: "DashboardPage" */ '../features/dashboard/containers/DashboardPage') - ), - }, { path: '/dashboard/new', roles: () => contextSrv.evaluatePermission(() => ['Editor', 'Admin'], [AccessControlAction.DashboardsCreate]), @@ -91,6 +83,21 @@ export function getAppRoutes(): RouteDescriptor[] { () => import(/* webpackChunkName: "DashboardPage" */ '../features/dashboard/containers/NewDashboardPage') ), }, + { + path: '/dashboard/new-with-ds/:datasourceUid', + roles: () => contextSrv.evaluatePermission(() => ['Editor', 'Admin'], [AccessControlAction.DashboardsCreate]), + component: SafeDynamicImport( + () => import(/* webpackChunkName: "DashboardPage" */ '../features/dashboard/containers/NewDashboardWithDS') + ), + }, + { + path: '/dashboard/:type/:slug', + pageClass: 'page-dashboard', + routeName: DashboardRoutes.Normal, + component: SafeDynamicImport( + () => import(/* webpackChunkName: "DashboardPage" */ '../features/dashboard/containers/DashboardPage') + ), + }, { path: '/d-solo/:uid/:slug', pageClass: 'dashboard-solo',