mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Datasources: Refactor the list page (#51438)
* refactor(Data Sources): rename file to follow naming convention * refactor: use react-redux hooks for interacting with the store * tests: update data-sources list related test files * refactor: extract datasource list page contents * refactor: pass dataSources to the DataSourcesList as a prop * refactor: use proper typing for navIndex mocks
This commit is contained in:
parent
689639cdb0
commit
99de3313f7
22560
.betterer.results
22560
.betterer.results
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@ import { locationService } from '@grafana/runtime';
|
|||||||
import { configureStore } from 'app/store/configureStore';
|
import { configureStore } from 'app/store/configureStore';
|
||||||
|
|
||||||
import DataConnectionsPage from './DataConnectionsPage';
|
import DataConnectionsPage from './DataConnectionsPage';
|
||||||
import navIndex from './__mocks__/store.navIndex.mock';
|
import { navIndex } from './__mocks__/store.navIndex.mock';
|
||||||
import { ROUTE_BASE_ID, ROUTES } from './constants';
|
import { ROUTE_BASE_ID, ROUTES } from './constants';
|
||||||
|
|
||||||
const renderPage = (path = `/${ROUTE_BASE_ID}`): RenderResult => {
|
const renderPage = (path = `/${ROUTE_BASE_ID}`): RenderResult => {
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
export default {
|
import { NavIndex, NavSection } from '@grafana/data';
|
||||||
|
|
||||||
|
export const navIndex: NavIndex = {
|
||||||
dashboards: {
|
dashboards: {
|
||||||
id: 'dashboards',
|
id: 'dashboards',
|
||||||
text: 'Dashboards',
|
text: 'Dashboards',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Manage dashboards and folders',
|
subTitle: 'Manage dashboards and folders',
|
||||||
icon: 'apps',
|
icon: 'apps',
|
||||||
url: '/dashboards',
|
url: '/dashboards',
|
||||||
@ -74,7 +76,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'dashboards',
|
id: 'dashboards',
|
||||||
text: 'Dashboards',
|
text: 'Dashboards',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Manage dashboards and folders',
|
subTitle: 'Manage dashboards and folders',
|
||||||
icon: 'apps',
|
icon: 'apps',
|
||||||
url: '/dashboards',
|
url: '/dashboards',
|
||||||
@ -147,7 +149,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'dashboards',
|
id: 'dashboards',
|
||||||
text: 'Dashboards',
|
text: 'Dashboards',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Manage dashboards and folders',
|
subTitle: 'Manage dashboards and folders',
|
||||||
icon: 'apps',
|
icon: 'apps',
|
||||||
url: '/dashboards',
|
url: '/dashboards',
|
||||||
@ -220,7 +222,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'dashboards',
|
id: 'dashboards',
|
||||||
text: 'Dashboards',
|
text: 'Dashboards',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Manage dashboards and folders',
|
subTitle: 'Manage dashboards and folders',
|
||||||
icon: 'apps',
|
icon: 'apps',
|
||||||
url: '/dashboards',
|
url: '/dashboards',
|
||||||
@ -293,7 +295,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'dashboards',
|
id: 'dashboards',
|
||||||
text: 'Dashboards',
|
text: 'Dashboards',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Manage dashboards and folders',
|
subTitle: 'Manage dashboards and folders',
|
||||||
icon: 'apps',
|
icon: 'apps',
|
||||||
url: '/dashboards',
|
url: '/dashboards',
|
||||||
@ -366,7 +368,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'alerting',
|
id: 'alerting',
|
||||||
text: 'Alerting',
|
text: 'Alerting',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Alert rules and notifications',
|
subTitle: 'Alert rules and notifications',
|
||||||
icon: 'bell',
|
icon: 'bell',
|
||||||
url: '/alerting/list',
|
url: '/alerting/list',
|
||||||
@ -436,7 +438,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'dashboards',
|
id: 'dashboards',
|
||||||
text: 'Dashboards',
|
text: 'Dashboards',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Manage dashboards and folders',
|
subTitle: 'Manage dashboards and folders',
|
||||||
icon: 'apps',
|
icon: 'apps',
|
||||||
url: '/dashboards',
|
url: '/dashboards',
|
||||||
@ -512,7 +514,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'dashboards',
|
id: 'dashboards',
|
||||||
text: 'Dashboards',
|
text: 'Dashboards',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Manage dashboards and folders',
|
subTitle: 'Manage dashboards and folders',
|
||||||
icon: 'apps',
|
icon: 'apps',
|
||||||
url: '/dashboards',
|
url: '/dashboards',
|
||||||
@ -588,7 +590,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'dashboards',
|
id: 'dashboards',
|
||||||
text: 'Dashboards',
|
text: 'Dashboards',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Manage dashboards and folders',
|
subTitle: 'Manage dashboards and folders',
|
||||||
icon: 'apps',
|
icon: 'apps',
|
||||||
url: '/dashboards',
|
url: '/dashboards',
|
||||||
@ -661,7 +663,7 @@ export default {
|
|||||||
explore: {
|
explore: {
|
||||||
id: 'explore',
|
id: 'explore',
|
||||||
text: 'Explore',
|
text: 'Explore',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Explore your data',
|
subTitle: 'Explore your data',
|
||||||
icon: 'compass',
|
icon: 'compass',
|
||||||
url: '/explore',
|
url: '/explore',
|
||||||
@ -670,7 +672,7 @@ export default {
|
|||||||
alerting: {
|
alerting: {
|
||||||
id: 'alerting',
|
id: 'alerting',
|
||||||
text: 'Alerting',
|
text: 'Alerting',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Alert rules and notifications',
|
subTitle: 'Alert rules and notifications',
|
||||||
icon: 'bell',
|
icon: 'bell',
|
||||||
url: '/alerting/list',
|
url: '/alerting/list',
|
||||||
@ -737,7 +739,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'alerting',
|
id: 'alerting',
|
||||||
text: 'Alerting',
|
text: 'Alerting',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Alert rules and notifications',
|
subTitle: 'Alert rules and notifications',
|
||||||
icon: 'bell',
|
icon: 'bell',
|
||||||
url: '/alerting/list',
|
url: '/alerting/list',
|
||||||
@ -805,7 +807,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'alerting',
|
id: 'alerting',
|
||||||
text: 'Alerting',
|
text: 'Alerting',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Alert rules and notifications',
|
subTitle: 'Alert rules and notifications',
|
||||||
icon: 'bell',
|
icon: 'bell',
|
||||||
url: '/alerting/list',
|
url: '/alerting/list',
|
||||||
@ -873,7 +875,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'alerting',
|
id: 'alerting',
|
||||||
text: 'Alerting',
|
text: 'Alerting',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Alert rules and notifications',
|
subTitle: 'Alert rules and notifications',
|
||||||
icon: 'bell',
|
icon: 'bell',
|
||||||
url: '/alerting/list',
|
url: '/alerting/list',
|
||||||
@ -941,7 +943,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'alerting',
|
id: 'alerting',
|
||||||
text: 'Alerting',
|
text: 'Alerting',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Alert rules and notifications',
|
subTitle: 'Alert rules and notifications',
|
||||||
icon: 'bell',
|
icon: 'bell',
|
||||||
url: '/alerting/list',
|
url: '/alerting/list',
|
||||||
@ -1009,7 +1011,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'alerting',
|
id: 'alerting',
|
||||||
text: 'Alerting',
|
text: 'Alerting',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Alert rules and notifications',
|
subTitle: 'Alert rules and notifications',
|
||||||
icon: 'bell',
|
icon: 'bell',
|
||||||
url: '/alerting/list',
|
url: '/alerting/list',
|
||||||
@ -1077,7 +1079,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'alerting',
|
id: 'alerting',
|
||||||
text: 'Alerting',
|
text: 'Alerting',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Alert rules and notifications',
|
subTitle: 'Alert rules and notifications',
|
||||||
icon: 'bell',
|
icon: 'bell',
|
||||||
url: '/alerting/list',
|
url: '/alerting/list',
|
||||||
@ -1148,7 +1150,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'alerting',
|
id: 'alerting',
|
||||||
text: 'Alerting',
|
text: 'Alerting',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
subTitle: 'Alert rules and notifications',
|
subTitle: 'Alert rules and notifications',
|
||||||
icon: 'bell',
|
icon: 'bell',
|
||||||
url: '/alerting/list',
|
url: '/alerting/list',
|
||||||
@ -1211,7 +1213,7 @@ export default {
|
|||||||
'data-connections': {
|
'data-connections': {
|
||||||
id: 'data-connections',
|
id: 'data-connections',
|
||||||
text: 'Data Connections',
|
text: 'Data Connections',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
icon: 'link',
|
icon: 'link',
|
||||||
url: '/data-connections',
|
url: '/data-connections',
|
||||||
sortWeight: -1500,
|
sortWeight: -1500,
|
||||||
@ -1259,7 +1261,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'data-connections',
|
id: 'data-connections',
|
||||||
text: 'Data Connections',
|
text: 'Data Connections',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
icon: 'link',
|
icon: 'link',
|
||||||
url: '/data-connections',
|
url: '/data-connections',
|
||||||
sortWeight: -1500,
|
sortWeight: -1500,
|
||||||
@ -1304,7 +1306,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'data-connections',
|
id: 'data-connections',
|
||||||
text: 'Data Connections',
|
text: 'Data Connections',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
icon: 'link',
|
icon: 'link',
|
||||||
url: '/data-connections',
|
url: '/data-connections',
|
||||||
sortWeight: -1500,
|
sortWeight: -1500,
|
||||||
@ -1349,7 +1351,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'data-connections',
|
id: 'data-connections',
|
||||||
text: 'Data Connections',
|
text: 'Data Connections',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
icon: 'link',
|
icon: 'link',
|
||||||
url: '/data-connections',
|
url: '/data-connections',
|
||||||
sortWeight: -1500,
|
sortWeight: -1500,
|
||||||
@ -1394,7 +1396,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'data-connections',
|
id: 'data-connections',
|
||||||
text: 'Data Connections',
|
text: 'Data Connections',
|
||||||
section: 'core',
|
section: NavSection.Core,
|
||||||
icon: 'link',
|
icon: 'link',
|
||||||
url: '/data-connections',
|
url: '/data-connections',
|
||||||
sortWeight: -1500,
|
sortWeight: -1500,
|
||||||
@ -1433,7 +1435,7 @@ export default {
|
|||||||
'plugin-page-basic-app': {
|
'plugin-page-basic-app': {
|
||||||
id: 'plugin-page-basic-app',
|
id: 'plugin-page-basic-app',
|
||||||
text: 'Basic App',
|
text: 'Basic App',
|
||||||
section: 'plugin',
|
section: NavSection.Plugin,
|
||||||
img: 'public/plugins/basic-app/img/logo.svg',
|
img: 'public/plugins/basic-app/img/logo.svg',
|
||||||
url: '/a/basic-app/one',
|
url: '/a/basic-app/one',
|
||||||
sortWeight: -1400,
|
sortWeight: -1400,
|
||||||
@ -1467,7 +1469,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'plugin-page-grafana-synthetic-monitoring-app',
|
id: 'plugin-page-grafana-synthetic-monitoring-app',
|
||||||
text: 'Synthetic Monitoring',
|
text: 'Synthetic Monitoring',
|
||||||
section: 'plugin',
|
section: NavSection.Plugin,
|
||||||
img: 'public/plugins/grafana-synthetic-monitoring-app/img/logo.svg',
|
img: 'public/plugins/grafana-synthetic-monitoring-app/img/logo.svg',
|
||||||
url: '/a/grafana-synthetic-monitoring-app/home',
|
url: '/a/grafana-synthetic-monitoring-app/home',
|
||||||
sortWeight: -1400,
|
sortWeight: -1400,
|
||||||
@ -1502,7 +1504,7 @@ export default {
|
|||||||
'plugin-page-cloudflare-app': {
|
'plugin-page-cloudflare-app': {
|
||||||
id: 'plugin-page-cloudflare-app',
|
id: 'plugin-page-cloudflare-app',
|
||||||
text: 'Cloudflare Grafana App',
|
text: 'Cloudflare Grafana App',
|
||||||
section: 'plugin',
|
section: NavSection.Plugin,
|
||||||
img: 'public/plugins/cloudflare-app/img/cf_icon.png',
|
img: 'public/plugins/cloudflare-app/img/cf_icon.png',
|
||||||
sortWeight: -1400,
|
sortWeight: -1400,
|
||||||
children: [
|
children: [
|
||||||
@ -1519,7 +1521,7 @@ export default {
|
|||||||
'plugin-page-grafana-easystart-app': {
|
'plugin-page-grafana-easystart-app': {
|
||||||
id: 'plugin-page-grafana-easystart-app',
|
id: 'plugin-page-grafana-easystart-app',
|
||||||
text: 'Integrations and Connections',
|
text: 'Integrations and Connections',
|
||||||
section: 'plugin',
|
section: NavSection.Plugin,
|
||||||
img: 'public/plugins/grafana-easystart-app/img/logo.svg',
|
img: 'public/plugins/grafana-easystart-app/img/logo.svg',
|
||||||
url: '/a/grafana-easystart-app',
|
url: '/a/grafana-easystart-app',
|
||||||
sortWeight: -1400,
|
sortWeight: -1400,
|
||||||
@ -1527,7 +1529,7 @@ export default {
|
|||||||
'plugin-page-redis-explorer-app': {
|
'plugin-page-redis-explorer-app': {
|
||||||
id: 'plugin-page-redis-explorer-app',
|
id: 'plugin-page-redis-explorer-app',
|
||||||
text: 'Redis Explorer',
|
text: 'Redis Explorer',
|
||||||
section: 'plugin',
|
section: NavSection.Plugin,
|
||||||
img: 'public/plugins/redis-explorer-app/img/logo.svg',
|
img: 'public/plugins/redis-explorer-app/img/logo.svg',
|
||||||
url: '/a/redis-explorer-app/',
|
url: '/a/redis-explorer-app/',
|
||||||
sortWeight: -1400,
|
sortWeight: -1400,
|
||||||
@ -1567,7 +1569,7 @@ export default {
|
|||||||
'plugin-page-grafana-synthetic-monitoring-app': {
|
'plugin-page-grafana-synthetic-monitoring-app': {
|
||||||
id: 'plugin-page-grafana-synthetic-monitoring-app',
|
id: 'plugin-page-grafana-synthetic-monitoring-app',
|
||||||
text: 'Synthetic Monitoring',
|
text: 'Synthetic Monitoring',
|
||||||
section: 'plugin',
|
section: NavSection.Plugin,
|
||||||
img: 'public/plugins/grafana-synthetic-monitoring-app/img/logo.svg',
|
img: 'public/plugins/grafana-synthetic-monitoring-app/img/logo.svg',
|
||||||
url: '/a/grafana-synthetic-monitoring-app/home',
|
url: '/a/grafana-synthetic-monitoring-app/home',
|
||||||
sortWeight: -1400,
|
sortWeight: -1400,
|
||||||
@ -1601,7 +1603,7 @@ export default {
|
|||||||
'plugin-page-grafana-k6-app': {
|
'plugin-page-grafana-k6-app': {
|
||||||
id: 'plugin-page-grafana-k6-app',
|
id: 'plugin-page-grafana-k6-app',
|
||||||
text: 'k6 Cloud App',
|
text: 'k6 Cloud App',
|
||||||
section: 'plugin',
|
section: NavSection.Plugin,
|
||||||
img: 'public/plugins/grafana-k6-app/img/logo.svg',
|
img: 'public/plugins/grafana-k6-app/img/logo.svg',
|
||||||
url: '/a/grafana-k6-app',
|
url: '/a/grafana-k6-app',
|
||||||
sortWeight: -1400,
|
sortWeight: -1400,
|
||||||
@ -1609,7 +1611,7 @@ export default {
|
|||||||
cfg: {
|
cfg: {
|
||||||
id: 'cfg',
|
id: 'cfg',
|
||||||
text: 'Configuration',
|
text: 'Configuration',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
subTitle: 'Organization: Main Org.',
|
subTitle: 'Organization: Main Org.',
|
||||||
icon: 'cog',
|
icon: 'cog',
|
||||||
url: '/datasources',
|
url: '/datasources',
|
||||||
@ -1668,7 +1670,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'cfg',
|
id: 'cfg',
|
||||||
text: 'Configuration',
|
text: 'Configuration',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
subTitle: 'Organization: Main Org.',
|
subTitle: 'Organization: Main Org.',
|
||||||
icon: 'cog',
|
icon: 'cog',
|
||||||
url: '/datasources',
|
url: '/datasources',
|
||||||
@ -1728,7 +1730,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'cfg',
|
id: 'cfg',
|
||||||
text: 'Configuration',
|
text: 'Configuration',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
subTitle: 'Organization: Main Org.',
|
subTitle: 'Organization: Main Org.',
|
||||||
icon: 'cog',
|
icon: 'cog',
|
||||||
url: '/datasources',
|
url: '/datasources',
|
||||||
@ -1788,7 +1790,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'cfg',
|
id: 'cfg',
|
||||||
text: 'Configuration',
|
text: 'Configuration',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
subTitle: 'Organization: Main Org.',
|
subTitle: 'Organization: Main Org.',
|
||||||
icon: 'cog',
|
icon: 'cog',
|
||||||
url: '/datasources',
|
url: '/datasources',
|
||||||
@ -1848,7 +1850,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'cfg',
|
id: 'cfg',
|
||||||
text: 'Configuration',
|
text: 'Configuration',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
subTitle: 'Organization: Main Org.',
|
subTitle: 'Organization: Main Org.',
|
||||||
icon: 'cog',
|
icon: 'cog',
|
||||||
url: '/datasources',
|
url: '/datasources',
|
||||||
@ -1908,7 +1910,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'cfg',
|
id: 'cfg',
|
||||||
text: 'Configuration',
|
text: 'Configuration',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
subTitle: 'Organization: Main Org.',
|
subTitle: 'Organization: Main Org.',
|
||||||
icon: 'cog',
|
icon: 'cog',
|
||||||
url: '/datasources',
|
url: '/datasources',
|
||||||
@ -1968,7 +1970,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'cfg',
|
id: 'cfg',
|
||||||
text: 'Configuration',
|
text: 'Configuration',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
subTitle: 'Organization: Main Org.',
|
subTitle: 'Organization: Main Org.',
|
||||||
icon: 'cog',
|
icon: 'cog',
|
||||||
url: '/datasources',
|
url: '/datasources',
|
||||||
@ -2022,7 +2024,7 @@ export default {
|
|||||||
admin: {
|
admin: {
|
||||||
id: 'admin',
|
id: 'admin',
|
||||||
text: 'Server Admin',
|
text: 'Server Admin',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
subTitle: 'Manage all users and orgs',
|
subTitle: 'Manage all users and orgs',
|
||||||
icon: 'shield',
|
icon: 'shield',
|
||||||
url: '/admin/users',
|
url: '/admin/users',
|
||||||
@ -2069,7 +2071,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'admin',
|
id: 'admin',
|
||||||
text: 'Server Admin',
|
text: 'Server Admin',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
subTitle: 'Manage all users and orgs',
|
subTitle: 'Manage all users and orgs',
|
||||||
icon: 'shield',
|
icon: 'shield',
|
||||||
url: '/admin/users',
|
url: '/admin/users',
|
||||||
@ -2117,7 +2119,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'admin',
|
id: 'admin',
|
||||||
text: 'Server Admin',
|
text: 'Server Admin',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
subTitle: 'Manage all users and orgs',
|
subTitle: 'Manage all users and orgs',
|
||||||
icon: 'shield',
|
icon: 'shield',
|
||||||
url: '/admin/users',
|
url: '/admin/users',
|
||||||
@ -2165,7 +2167,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'admin',
|
id: 'admin',
|
||||||
text: 'Server Admin',
|
text: 'Server Admin',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
subTitle: 'Manage all users and orgs',
|
subTitle: 'Manage all users and orgs',
|
||||||
icon: 'shield',
|
icon: 'shield',
|
||||||
url: '/admin/users',
|
url: '/admin/users',
|
||||||
@ -2213,7 +2215,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'admin',
|
id: 'admin',
|
||||||
text: 'Server Admin',
|
text: 'Server Admin',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
subTitle: 'Manage all users and orgs',
|
subTitle: 'Manage all users and orgs',
|
||||||
icon: 'shield',
|
icon: 'shield',
|
||||||
url: '/admin/users',
|
url: '/admin/users',
|
||||||
@ -2261,7 +2263,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'admin',
|
id: 'admin',
|
||||||
text: 'Server Admin',
|
text: 'Server Admin',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
subTitle: 'Manage all users and orgs',
|
subTitle: 'Manage all users and orgs',
|
||||||
icon: 'shield',
|
icon: 'shield',
|
||||||
url: '/admin/users',
|
url: '/admin/users',
|
||||||
@ -2304,7 +2306,7 @@ export default {
|
|||||||
profile: {
|
profile: {
|
||||||
id: 'profile',
|
id: 'profile',
|
||||||
text: 'admin',
|
text: 'admin',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
img: '/avatar/46d229b033af06a191ff2267bca9ae56',
|
img: '/avatar/46d229b033af06a191ff2267bca9ae56',
|
||||||
url: '/profile',
|
url: '/profile',
|
||||||
sortWeight: -1100,
|
sortWeight: -1100,
|
||||||
@ -2345,7 +2347,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'profile',
|
id: 'profile',
|
||||||
text: 'admin',
|
text: 'admin',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
img: '/avatar/46d229b033af06a191ff2267bca9ae56',
|
img: '/avatar/46d229b033af06a191ff2267bca9ae56',
|
||||||
url: '/profile',
|
url: '/profile',
|
||||||
sortWeight: -1100,
|
sortWeight: -1100,
|
||||||
@ -2387,7 +2389,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'profile',
|
id: 'profile',
|
||||||
text: 'admin',
|
text: 'admin',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
img: '/avatar/46d229b033af06a191ff2267bca9ae56',
|
img: '/avatar/46d229b033af06a191ff2267bca9ae56',
|
||||||
url: '/profile',
|
url: '/profile',
|
||||||
sortWeight: -1100,
|
sortWeight: -1100,
|
||||||
@ -2429,7 +2431,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'profile',
|
id: 'profile',
|
||||||
text: 'admin',
|
text: 'admin',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
img: '/avatar/46d229b033af06a191ff2267bca9ae56',
|
img: '/avatar/46d229b033af06a191ff2267bca9ae56',
|
||||||
url: '/profile',
|
url: '/profile',
|
||||||
sortWeight: -1100,
|
sortWeight: -1100,
|
||||||
@ -2473,7 +2475,7 @@ export default {
|
|||||||
parentItem: {
|
parentItem: {
|
||||||
id: 'profile',
|
id: 'profile',
|
||||||
text: 'admin',
|
text: 'admin',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
img: '/avatar/46d229b033af06a191ff2267bca9ae56',
|
img: '/avatar/46d229b033af06a191ff2267bca9ae56',
|
||||||
url: '/profile',
|
url: '/profile',
|
||||||
sortWeight: -1100,
|
sortWeight: -1100,
|
||||||
@ -2510,7 +2512,7 @@ export default {
|
|||||||
help: {
|
help: {
|
||||||
id: 'help',
|
id: 'help',
|
||||||
text: 'Help',
|
text: 'Help',
|
||||||
section: 'config',
|
section: NavSection.Config,
|
||||||
subTitle: 'Grafana v9.0.0-pre (abb5c6109a)',
|
subTitle: 'Grafana v9.0.0-pre (abb5c6109a)',
|
||||||
icon: 'question-circle',
|
icon: 'question-circle',
|
||||||
url: '#',
|
url: '#',
|
||||||
|
@ -1,18 +1,30 @@
|
|||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { LayoutModes } from '@grafana/data';
|
import { LayoutModes } from '@grafana/data';
|
||||||
|
import { configureStore } from 'app/store/configureStore';
|
||||||
|
import { DataSourcesState } from 'app/types';
|
||||||
|
|
||||||
import DataSourcesList from './DataSourcesList';
|
import DataSourcesList from './DataSourcesList';
|
||||||
import { getMockDataSources } from './__mocks__/dataSourcesMocks';
|
import { getMockDataSources } from './__mocks__/dataSourcesMocks';
|
||||||
|
import { initialState } from './state/reducers';
|
||||||
|
|
||||||
const setup = () => {
|
const setup = (stateOverride?: Partial<DataSourcesState>) => {
|
||||||
const props = {
|
const store = configureStore({
|
||||||
dataSources: getMockDataSources(3),
|
dataSources: {
|
||||||
layoutMode: LayoutModes.Grid,
|
...initialState,
|
||||||
};
|
dataSources: getMockDataSources(3),
|
||||||
|
layoutMode: LayoutModes.Grid,
|
||||||
|
...stateOverride,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return render(<DataSourcesList {...props} />);
|
return render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<DataSourcesList dataSources={getMockDataSources(3)} />
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('DataSourcesList', () => {
|
describe('DataSourcesList', () => {
|
@ -1,17 +1,16 @@
|
|||||||
// Libraries
|
// Libraries
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import React, { FC } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { DataSourceSettings, LayoutMode } from '@grafana/data';
|
import { DataSourceSettings } from '@grafana/data';
|
||||||
import { Card, Tag, useStyles } from '@grafana/ui';
|
import { Card, Tag, useStyles } from '@grafana/ui';
|
||||||
|
|
||||||
export interface Props {
|
export type Props = {
|
||||||
dataSources: DataSourceSettings[];
|
dataSources: DataSourceSettings[];
|
||||||
layoutMode: LayoutMode;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export const DataSourcesList: FC<Props> = ({ dataSources, layoutMode }) => {
|
export const DataSourcesList = ({ dataSources }: Props) => {
|
||||||
const styles = useStyles(getStyles);
|
const styles = useStyles(getStyles);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
26
public/app/features/datasources/DataSourcesListHeader.tsx
Normal file
26
public/app/features/datasources/DataSourcesListHeader.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import React, { useCallback } from 'react';
|
||||||
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
|
|
||||||
|
import PageActionBar from 'app/core/components/PageActionBar/PageActionBar';
|
||||||
|
import { contextSrv } from 'app/core/core';
|
||||||
|
import { AccessControlAction, StoreState } from 'app/types';
|
||||||
|
|
||||||
|
import { setDataSourcesSearchQuery } from './state/reducers';
|
||||||
|
import { getDataSourcesSearchQuery } from './state/selectors';
|
||||||
|
|
||||||
|
export const DataSourcesListHeader = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const setSearchQuery = useCallback((q: string) => dispatch(setDataSourcesSearchQuery(q)), [dispatch]);
|
||||||
|
const searchQuery = useSelector(({ dataSources }: StoreState) => getDataSourcesSearchQuery(dataSources));
|
||||||
|
const canCreateDataSource = contextSrv.hasPermission(AccessControlAction.DataSourcesCreate);
|
||||||
|
|
||||||
|
const linkButton = {
|
||||||
|
href: 'datasources/new',
|
||||||
|
title: 'Add data source',
|
||||||
|
disabled: !canCreateDataSource,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageActionBar searchQuery={searchQuery} setSearchQuery={setSearchQuery} linkButton={linkButton} key="action-bar" />
|
||||||
|
);
|
||||||
|
};
|
@ -1,11 +1,15 @@
|
|||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { DataSourceSettings, NavModel, LayoutModes } from '@grafana/data';
|
import { DataSourceSettings, LayoutModes } from '@grafana/data';
|
||||||
|
import { configureStore } from 'app/store/configureStore';
|
||||||
|
import { DataSourcesState } from 'app/types';
|
||||||
|
|
||||||
import { DataSourcesListPage, Props } from './DataSourcesListPage';
|
import { DataSourcesListPage } from './DataSourcesListPage';
|
||||||
import { getMockDataSources } from './__mocks__/dataSourcesMocks';
|
import { getMockDataSources } from './__mocks__/dataSourcesMocks';
|
||||||
import { setDataSourcesLayoutMode, setDataSourcesSearchQuery } from './state/reducers';
|
import navIndex from './__mocks__/store.navIndex.mock';
|
||||||
|
import { initialState } from './state/reducers';
|
||||||
|
|
||||||
jest.mock('app/core/core', () => {
|
jest.mock('app/core/core', () => {
|
||||||
return {
|
return {
|
||||||
@ -15,29 +19,30 @@ jest.mock('app/core/core', () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const setup = (propOverrides?: object) => {
|
const getMock = jest.fn().mockResolvedValue([]);
|
||||||
const props: Props = {
|
|
||||||
dataSources: [] as DataSourceSettings[],
|
|
||||||
layoutMode: LayoutModes.Grid,
|
|
||||||
loadDataSources: jest.fn(),
|
|
||||||
navModel: {
|
|
||||||
main: {
|
|
||||||
text: 'Configuration',
|
|
||||||
},
|
|
||||||
node: {
|
|
||||||
text: 'Data Sources',
|
|
||||||
},
|
|
||||||
} as NavModel,
|
|
||||||
dataSourcesCount: 0,
|
|
||||||
searchQuery: '',
|
|
||||||
setDataSourcesSearchQuery,
|
|
||||||
setDataSourcesLayoutMode,
|
|
||||||
hasFetched: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.assign(props, propOverrides);
|
jest.mock('app/core/services/backend_srv', () => ({
|
||||||
|
...jest.requireActual('app/core/services/backend_srv'),
|
||||||
|
getBackendSrv: () => ({ get: getMock }),
|
||||||
|
}));
|
||||||
|
|
||||||
return render(<DataSourcesListPage {...props} />);
|
const setup = (stateOverride?: Partial<DataSourcesState>) => {
|
||||||
|
const store = configureStore({
|
||||||
|
dataSources: {
|
||||||
|
...initialState,
|
||||||
|
dataSources: [] as DataSourceSettings[],
|
||||||
|
layoutMode: LayoutModes.Grid,
|
||||||
|
hasFetched: false,
|
||||||
|
...stateOverride,
|
||||||
|
},
|
||||||
|
navIndex,
|
||||||
|
});
|
||||||
|
|
||||||
|
return render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<DataSourcesListPage />
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('Render', () => {
|
describe('Render', () => {
|
||||||
|
@ -1,98 +1,22 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React from 'react';
|
||||||
import { connect, ConnectedProps } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { IconName } from '@grafana/ui';
|
|
||||||
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
|
||||||
import { Page } from 'app/core/components/Page/Page';
|
import { Page } from 'app/core/components/Page/Page';
|
||||||
import PageActionBar from 'app/core/components/PageActionBar/PageActionBar';
|
|
||||||
import { contextSrv } from 'app/core/core';
|
|
||||||
import { getNavModel } from 'app/core/selectors/navModel';
|
import { getNavModel } from 'app/core/selectors/navModel';
|
||||||
import { StoreState, AccessControlAction } from 'app/types';
|
import { StoreState } from 'app/types';
|
||||||
|
|
||||||
import DataSourcesList from './DataSourcesList';
|
import { DataSourcesListPageContent } from './DataSourcesListPageContent';
|
||||||
import { loadDataSources } from './state/actions';
|
|
||||||
import { setDataSourcesLayoutMode, setDataSourcesSearchQuery } from './state/reducers';
|
|
||||||
import {
|
|
||||||
getDataSources,
|
|
||||||
getDataSourcesCount,
|
|
||||||
getDataSourcesLayoutMode,
|
|
||||||
getDataSourcesSearchQuery,
|
|
||||||
} from './state/selectors';
|
|
||||||
|
|
||||||
function mapStateToProps(state: StoreState) {
|
export const DataSourcesListPage = () => {
|
||||||
return {
|
const navModel = useSelector(({ navIndex }: StoreState) => getNavModel(navIndex, 'datasources'));
|
||||||
navModel: getNavModel(state.navIndex, 'datasources'),
|
|
||||||
dataSources: getDataSources(state.dataSources),
|
|
||||||
layoutMode: getDataSourcesLayoutMode(state.dataSources),
|
|
||||||
dataSourcesCount: getDataSourcesCount(state.dataSources),
|
|
||||||
searchQuery: getDataSourcesSearchQuery(state.dataSources),
|
|
||||||
hasFetched: state.dataSources.hasFetched,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
return (
|
||||||
loadDataSources,
|
<Page navModel={navModel}>
|
||||||
setDataSourcesSearchQuery,
|
<Page.Contents>
|
||||||
setDataSourcesLayoutMode,
|
<DataSourcesListPageContent />
|
||||||
|
</Page.Contents>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
export default DataSourcesListPage;
|
||||||
|
|
||||||
export type Props = ConnectedProps<typeof connector>;
|
|
||||||
|
|
||||||
const emptyListModel = {
|
|
||||||
title: 'No data sources defined',
|
|
||||||
buttonIcon: 'database' as IconName,
|
|
||||||
buttonLink: 'datasources/new',
|
|
||||||
buttonTitle: 'Add data source',
|
|
||||||
proTip: 'You can also define data sources through configuration files.',
|
|
||||||
proTipLink: 'http://docs.grafana.org/administration/provisioning/#datasources?utm_source=grafana_ds_list',
|
|
||||||
proTipLinkTitle: 'Learn more',
|
|
||||||
proTipTarget: '_blank',
|
|
||||||
};
|
|
||||||
|
|
||||||
export class DataSourcesListPage extends PureComponent<Props> {
|
|
||||||
componentDidMount() {
|
|
||||||
this.props.loadDataSources();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { dataSources, dataSourcesCount, navModel, layoutMode, searchQuery, setDataSourcesSearchQuery, hasFetched } =
|
|
||||||
this.props;
|
|
||||||
|
|
||||||
const canCreateDataSource = contextSrv.hasPermission(AccessControlAction.DataSourcesCreate);
|
|
||||||
|
|
||||||
const linkButton = {
|
|
||||||
href: 'datasources/new',
|
|
||||||
title: 'Add data source',
|
|
||||||
disabled: !canCreateDataSource,
|
|
||||||
};
|
|
||||||
|
|
||||||
const emptyList = {
|
|
||||||
...emptyListModel,
|
|
||||||
buttonDisabled: !canCreateDataSource,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Page navModel={navModel}>
|
|
||||||
<Page.Contents isLoading={!hasFetched}>
|
|
||||||
<>
|
|
||||||
{hasFetched && dataSourcesCount === 0 && <EmptyListCTA {...emptyList} />}
|
|
||||||
{hasFetched &&
|
|
||||||
dataSourcesCount > 0 && [
|
|
||||||
<PageActionBar
|
|
||||||
searchQuery={searchQuery}
|
|
||||||
setSearchQuery={(query) => setDataSourcesSearchQuery(query)}
|
|
||||||
linkButton={linkButton}
|
|
||||||
key="action-bar"
|
|
||||||
/>,
|
|
||||||
<DataSourcesList dataSources={dataSources} layoutMode={layoutMode} key="list" />,
|
|
||||||
]}
|
|
||||||
</>
|
|
||||||
</Page.Contents>
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connector(DataSourcesListPage);
|
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
import React, { useEffect } from 'react';
|
||||||
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
import { IconName } from '@grafana/ui';
|
||||||
|
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
||||||
|
import PageLoader from 'app/core/components/PageLoader/PageLoader';
|
||||||
|
import { contextSrv } from 'app/core/core';
|
||||||
|
import { StoreState, AccessControlAction } from 'app/types';
|
||||||
|
|
||||||
|
import DataSourcesList from './DataSourcesList';
|
||||||
|
import { DataSourcesListHeader } from './DataSourcesListHeader';
|
||||||
|
import { loadDataSources } from './state/actions';
|
||||||
|
import { getDataSourcesCount, getDataSources } from './state/selectors';
|
||||||
|
|
||||||
|
const buttonIcon: IconName = 'database';
|
||||||
|
const emptyListModel = {
|
||||||
|
title: 'No data sources defined',
|
||||||
|
buttonIcon,
|
||||||
|
buttonLink: 'datasources/new',
|
||||||
|
buttonTitle: 'Add data source',
|
||||||
|
proTip: 'You can also define data sources through configuration files.',
|
||||||
|
proTipLink: 'http://docs.grafana.org/administration/provisioning/#datasources?utm_source=grafana_ds_list',
|
||||||
|
proTipLinkTitle: 'Learn more',
|
||||||
|
proTipTarget: '_blank',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DataSourcesListPageContent = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const dataSources = useSelector((state: StoreState) => getDataSources(state.dataSources));
|
||||||
|
const dataSourcesCount = useSelector(({ dataSources }: StoreState) => getDataSourcesCount(dataSources));
|
||||||
|
const hasFetched = useSelector(({ dataSources }: StoreState) => dataSources.hasFetched);
|
||||||
|
const canCreateDataSource = contextSrv.hasPermission(AccessControlAction.DataSourcesCreate);
|
||||||
|
const emptyList = {
|
||||||
|
...emptyListModel,
|
||||||
|
buttonDisabled: !canCreateDataSource,
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!hasFetched) {
|
||||||
|
dispatch(loadDataSources());
|
||||||
|
}
|
||||||
|
}, [dispatch, hasFetched]);
|
||||||
|
|
||||||
|
if (!hasFetched) {
|
||||||
|
return <PageLoader />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataSourcesCount === 0) {
|
||||||
|
return <EmptyListCTA {...emptyList} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DataSourcesListHeader />
|
||||||
|
<DataSourcesList dataSources={dataSources} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
2633
public/app/features/datasources/__mocks__/store.navIndex.mock.ts
Normal file
2633
public/app/features/datasources/__mocks__/store.navIndex.mock.ts
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user