diff --git a/pkg/services/navtree/navtreeimpl/applinks_test.go b/pkg/services/navtree/navtreeimpl/applinks_test.go index 149805ae096..8b6cbb7c6a4 100644 --- a/pkg/services/navtree/navtreeimpl/applinks_test.go +++ b/pkg/services/navtree/navtreeimpl/applinks_test.go @@ -264,8 +264,8 @@ func TestAddAppLinks(t *testing.T) { treeRoot.AddSection(service.buildDataConnectionsNavLink(reqCtx)) connectionsNode := treeRoot.FindById("connections") require.Equal(t, "Connections", connectionsNode.Text) - require.Equal(t, "Connect Data", connectionsNode.Children[1].Text) - require.Equal(t, "connections-connect-data", connectionsNode.Children[1].Id) // Original "Connect Data" page + require.Equal(t, "Connect data", connectionsNode.Children[1].Text) + require.Equal(t, "connections-connect-data", connectionsNode.Children[1].Id) // Original "Connect data" page require.Equal(t, "", connectionsNode.Children[1].PluginID) err := service.addAppLinks(&treeRoot, reqCtx) @@ -273,8 +273,8 @@ func TestAddAppLinks(t *testing.T) { // Check if the standalone plugin page appears under the section where we registered it require.NoError(t, err) require.Equal(t, "Connections", connectionsNode.Text) - require.Equal(t, "Connect Data", connectionsNode.Children[1].Text) - require.Equal(t, "standalone-plugin-page-/connections/connect-data", connectionsNode.Children[1].Id) // Overridden "Connect Data" page + require.Equal(t, "Connect data", connectionsNode.Children[1].Text) + require.Equal(t, "standalone-plugin-page-/connections/connect-data", connectionsNode.Children[1].Id) // Overridden "Connect data" page require.Equal(t, "test-app3", connectionsNode.Children[1].PluginID) // Check if the standalone plugin page does not appear under the app section anymore diff --git a/pkg/services/navtree/navtreeimpl/navtree.go b/pkg/services/navtree/navtreeimpl/navtree.go index 8838fae9826..3dca0dbf63b 100644 --- a/pkg/services/navtree/navtreeimpl/navtree.go +++ b/pkg/services/navtree/navtreeimpl/navtree.go @@ -534,29 +534,37 @@ func (s *ServiceImpl) buildDataConnectionsNavLink(c *models.ReqContext) *navtree var children []*navtree.NavLink var navLink *navtree.NavLink - baseId := "connections" - baseUrl := s.cfg.AppSubURL + "/" + baseId + baseUrl := s.cfg.AppSubURL + "/connections" + // Your connections children = append(children, &navtree.NavLink{ - Id: baseId + "-datasources", - Text: "Data sources", - Icon: "database", - SubTitle: "Add and configure data sources", - Url: baseUrl + "/datasources", + Id: "connections-your-connections", + Text: "Your connections", + SubTitle: "Manage your existing connections", + Url: baseUrl + "/your-connections", + // Datasources + Children: []*navtree.NavLink{{ + Id: "connections-your-connections-datasources", + Text: "Datasources", + SubTitle: "Manage your existing datasource connections", + Url: baseUrl + "/your-connections/datasources", + }}, }) + // Connect data children = append(children, &navtree.NavLink{ - Id: baseId + "-connect-data", - Text: "Connect Data", - Icon: "plug", - SubTitle: "Manage data sources", - Url: baseUrl + "/connect-data", + Id: "connections-connect-data", + Text: "Connect data", + SubTitle: "Browse and create new connections", + Url: s.cfg.AppSubURL + "/connections/connect-data", + Children: []*navtree.NavLink{}, }) + // Connections (main) navLink = &navtree.NavLink{ Text: "Connections", Icon: "link", - Id: baseId, + Id: "connections", Url: baseUrl, Children: children, Section: navtree.NavSectionCore, diff --git a/public/app/features/connections/Connections.test.tsx b/public/app/features/connections/Connections.test.tsx new file mode 100644 index 00000000000..d6c8404848c --- /dev/null +++ b/public/app/features/connections/Connections.test.tsx @@ -0,0 +1,89 @@ +import { render, RenderResult, screen } from '@testing-library/react'; +import React from 'react'; +import { Provider } from 'react-redux'; +import { Router } from 'react-router-dom'; + +import { locationService } from '@grafana/runtime'; +import { getMockDataSources } from 'app/features/datasources/__mocks__'; +import * as api from 'app/features/datasources/api'; +import { configureStore } from 'app/store/configureStore'; + +import { getPluginsStateMock } from '../plugins/admin/__mocks__'; + +import Connections from './Connections'; +import { navIndex } from './__mocks__/store.navIndex.mock'; +import { ROUTE_BASE_ID, ROUTES } from './constants'; + +jest.mock('app/features/datasources/api'); + +const renderPage = ( + path = `/${ROUTE_BASE_ID}`, + store = configureStore({ navIndex, plugins: getPluginsStateMock([]) }) +): RenderResult => { + locationService.push(path); + + return render( + + + + + + ); +}; + +describe('Connections', () => { + const mockDatasources = getMockDataSources(3); + + beforeEach(() => { + (api.getDataSources as jest.Mock) = jest.fn().mockResolvedValue(mockDatasources); + }); + + test('shows the "Data sources" page by default', async () => { + renderPage(); + + expect(await screen.findByText('Datasources')).toBeVisible(); + expect(await screen.findByText('Manage your existing datasource connections')).toBeVisible(); + expect(await screen.findByRole('link', { name: /add data source/i })).toBeVisible(); + expect(await screen.findByText(mockDatasources[0].name)).toBeVisible(); + }); + + test('renders the correct tab even if accessing it with a "sub-url"', async () => { + renderPage(ROUTES.ConnectData); + + expect(await screen.findByText('Connect data')).toBeVisible(); + expect(await screen.findByText('Browse and create new connections')).toBeVisible(); + + // Should not render the "Your datasources" page + expect(screen.queryByText('Manage your existing datasource connections')).not.toBeInTheDocument(); + }); + + test('renders the "Connect data" page using a plugin in case it is a standalone plugin page', async () => { + // We are overriding the navIndex to have the "Connect data" page registered by a plugin + const standalonePluginPage = { + id: 'standalone-plugin-page-/connections/connect-data', + text: 'Connect data', + subTitle: 'Browse and create new connections', + url: '/connections/connect-data', + pluginId: 'grafana-easystart-app', + }; + const connections = { + ...navIndex.connections, + children: navIndex.connections.children?.map((child) => { + if (child.id === 'connections-connect-data') { + return standalonePluginPage; + } + + return child; + }), + }; + const store = configureStore({ + navIndex: { ...navIndex, connections, [standalonePluginPage.id]: standalonePluginPage }, + plugins: getPluginsStateMock([]), + }); + + renderPage(ROUTES.ConnectData, store); + + // We expect not to see the same text as if it was rendered by core. + expect(screen.queryByText('No results matching your query were found.')).not.toBeInTheDocument(); + }); +}); diff --git a/public/app/features/connections/Connections.tsx b/public/app/features/connections/Connections.tsx new file mode 100644 index 00000000000..4da675c5dac --- /dev/null +++ b/public/app/features/connections/Connections.tsx @@ -0,0 +1,43 @@ +import * as React from 'react'; +import { Route, Switch } from 'react-router-dom'; + +import { DataSourcesRoutesContext } from 'app/features/datasources/state'; +import { StoreState, useSelector } from 'app/types'; + +import { ROUTES } from './constants'; +import { + ConnectDataPage, + DataSourceDetailsPage, + DataSourcesListPage, + EditDataSourcePage, + NewDataSourcePage, +} from './pages'; + +export default function Connections() { + const navIndex = useSelector((state: StoreState) => state.navIndex); + const isConnectDataPageOverriden = Boolean(navIndex['standalone-plugin-page-/connections/connect-data']); + + return ( + + + + + + + + + {!isConnectDataPageOverriden && } + + {/* Default page */} + + + + ); +} diff --git a/public/app/features/connections/ConnectionsPage.test.tsx b/public/app/features/connections/ConnectionsPage.test.tsx deleted file mode 100644 index 489b581dad9..00000000000 --- a/public/app/features/connections/ConnectionsPage.test.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { render, RenderResult, screen } from '@testing-library/react'; -import React from 'react'; -import { Provider } from 'react-redux'; -import { Router } from 'react-router-dom'; - -import { locationService } from '@grafana/runtime'; -import { getMockDataSources } from 'app/features/datasources/__mocks__'; -import * as api from 'app/features/datasources/api'; -import { configureStore } from 'app/store/configureStore'; - -import { getPluginsStateMock } from '../plugins/admin/__mocks__'; - -import ConnectionsPage from './ConnectionsPage'; -import { navIndex } from './__mocks__/store.navIndex.mock'; -import { ROUTE_BASE_ID, ROUTES } from './constants'; - -jest.mock('app/features/datasources/api'); - -const renderPage = (path = `/${ROUTE_BASE_ID}`): RenderResult => { - // @ts-ignore - const store = configureStore({ navIndex, plugins: getPluginsStateMock([]) }); - locationService.push(path); - - return render( - - - - - - ); -}; - -describe('Connections Page', () => { - const mockDatasources = getMockDataSources(3); - - beforeEach(() => { - (api.getDataSources as jest.Mock) = jest.fn().mockResolvedValue(mockDatasources); - }); - - test('shows all tabs', async () => { - renderPage(); - - expect(await screen.findByLabelText('Tab Data sources')).toBeVisible(); - expect(await screen.findByLabelText('Tab Connect Data')).toBeVisible(); - }); - - test('shows the "Data sources" tab by default', async () => { - renderPage(); - - expect(await screen.findByRole('link', { name: /add data source/i })).toBeVisible(); - expect(await screen.findByText(mockDatasources[0].name)).toBeVisible(); - }); - - test('renders the correct tab even if accessing it with a "sub-url"', async () => { - renderPage(`${ROUTES.ConnectData}`); - - expect(screen.queryByText('No results matching your query were found.')).toBeInTheDocument(); - }); -}); diff --git a/public/app/features/connections/ConnectionsPage.tsx b/public/app/features/connections/ConnectionsPage.tsx deleted file mode 100644 index 74849e6b105..00000000000 --- a/public/app/features/connections/ConnectionsPage.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import * as React from 'react'; -import { Route, Switch } from 'react-router-dom'; - -import { Page } from 'app/core/components/Page/Page'; -import { DataSourcesList } from 'app/features/datasources/components/DataSourcesList'; -import { NewDataSource } from 'app/features/datasources/components/NewDataSource'; -import { DataSourcesRoutesContext } from 'app/features/datasources/state'; - -import { ROUTES } from './constants'; -import { useNavModel } from './hooks/useNavModel'; -import { ConnectData } from './tabs/ConnectData'; -import { DataSourcesEdit } from './tabs/DataSourcesEdit'; - -export default function ConnectionsPage() { - const navModel = useNavModel(); - - return ( - - - - - - - - - - {/* Default page */} - - - - - - ); -} diff --git a/public/app/features/connections/__mocks__/store.navIndex.mock.ts b/public/app/features/connections/__mocks__/store.navIndex.mock.ts index 6b81e6e5fbf..31507f66744 100644 --- a/public/app/features/connections/__mocks__/store.navIndex.mock.ts +++ b/public/app/features/connections/__mocks__/store.navIndex.mock.ts @@ -1,665 +1,101 @@ import { NavIndex, NavSection } from '@grafana/data'; export const navIndex: NavIndex = { - dashboards: { - id: 'dashboards', + home: { + id: 'home', + text: 'Home', + section: NavSection.Core, + icon: 'home-alt', + url: '/', + sortWeight: -2000, + }, + starred: { + id: 'starred', + text: 'Starred', + section: NavSection.Core, + icon: 'star', + sortWeight: -1900, + emptyMessageId: 'starred-empty', + parentItem: { + id: 'home', + text: 'Home', + section: NavSection.Core, + icon: 'home-alt', + url: '/', + sortWeight: -2000, + }, + }, + 'dashboards/browse': { + id: 'dashboards/browse', text: 'Dashboards', section: NavSection.Core, - subTitle: 'Manage dashboards and folders', + subTitle: 'Create and manage dashboards to visualize your data', icon: 'apps', url: '/dashboards', - sortWeight: -1800, + sortWeight: -1700, children: [ { - id: 'manage-dashboards', - text: 'Browse', - icon: 'sitemap', - url: '/dashboards', - }, - { - id: 'playlists', + id: 'dashboards/playlists', text: 'Playlists', + subTitle: 'Groups of dashboards that are displayed in a sequence', icon: 'presentation-play', url: '/playlists', }, { - id: 'snapshots', + id: 'dashboards/snapshots', text: 'Snapshots', + subTitle: 'Interactive, publically available, point-in-time representations of dashboards', icon: 'camera', url: '/dashboard/snapshots', }, { - id: 'library-panels', + id: 'dashboards/library-panels', text: 'Library panels', + subTitle: 'Reusable panels that can be added to multiple dashboards', icon: 'library-panel', url: '/library-panels', }, - { - id: 'divider', - text: 'Divider', - divider: true, - hideFromTabs: true, - }, - { - id: 'new-dashboard', - text: 'New dashboard', - icon: 'plus', - url: '/dashboard/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - { - id: 'new-folder', - text: 'New folder', - subTitle: 'Create a new folder to organize your dashboards', - icon: 'plus', - url: '/dashboards/folder/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - { - id: 'import', - text: 'Import', - subTitle: 'Import dashboard from file or Grafana.com', - icon: 'plus', - url: '/dashboard/import', - hideFromTabs: true, - showIconInNavbar: true, - }, ], - }, - 'manage-dashboards': { - id: 'manage-dashboards', - text: 'Browse', - icon: 'sitemap', - url: '/dashboards', parentItem: { - id: 'dashboards', - text: 'Dashboards', + id: 'home', + text: 'Home', section: NavSection.Core, - subTitle: 'Manage dashboards and folders', - icon: 'apps', - url: '/dashboards', - sortWeight: -1800, - children: [ - { - id: 'manage-dashboards', - text: 'Browse', - icon: 'sitemap', - url: '/dashboards', - }, - { - id: 'playlists', - text: 'Playlists', - icon: 'presentation-play', - url: '/playlists', - }, - { - id: 'snapshots', - text: 'Snapshots', - icon: 'camera', - url: '/dashboard/snapshots', - }, - { - id: 'library-panels', - text: 'Library panels', - icon: 'library-panel', - url: '/library-panels', - }, - { - id: 'divider', - text: 'Divider', - divider: true, - hideFromTabs: true, - }, - { - id: 'new-dashboard', - text: 'New dashboard', - icon: 'plus', - url: '/dashboard/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - { - id: 'new-folder', - text: 'New folder', - subTitle: 'Create a new folder to organize your dashboards', - icon: 'plus', - url: '/dashboards/folder/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - { - id: 'import', - text: 'Import', - subTitle: 'Import dashboard from file or Grafana.com', - icon: 'plus', - url: '/dashboard/import', - hideFromTabs: true, - showIconInNavbar: true, - }, - ], + icon: 'home-alt', + url: '/', + sortWeight: -2000, }, }, - playlists: { - id: 'playlists', + 'dashboards/playlists': { + id: 'dashboards/playlists', text: 'Playlists', + subTitle: 'Groups of dashboards that are displayed in a sequence', icon: 'presentation-play', url: '/playlists', - parentItem: { - id: 'dashboards', - text: 'Dashboards', - section: NavSection.Core, - subTitle: 'Manage dashboards and folders', - icon: 'apps', - url: '/dashboards', - sortWeight: -1800, - children: [ - { - id: 'manage-dashboards', - text: 'Browse', - icon: 'sitemap', - url: '/dashboards', - }, - { - id: 'playlists', - text: 'Playlists', - icon: 'presentation-play', - url: '/playlists', - }, - { - id: 'snapshots', - text: 'Snapshots', - icon: 'camera', - url: '/dashboard/snapshots', - }, - { - id: 'library-panels', - text: 'Library panels', - icon: 'library-panel', - url: '/library-panels', - }, - { - id: 'divider', - text: 'Divider', - divider: true, - hideFromTabs: true, - }, - { - id: 'new-dashboard', - text: 'New dashboard', - icon: 'plus', - url: '/dashboard/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - { - id: 'new-folder', - text: 'New folder', - subTitle: 'Create a new folder to organize your dashboards', - icon: 'plus', - url: '/dashboards/folder/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - { - id: 'import', - text: 'Import', - subTitle: 'Import dashboard from file or Grafana.com', - icon: 'plus', - url: '/dashboard/import', - hideFromTabs: true, - showIconInNavbar: true, - }, - ], - }, }, - snapshots: { - id: 'snapshots', + 'dashboards/snapshots': { + id: 'dashboards/snapshots', text: 'Snapshots', + subTitle: 'Interactive, publically available, point-in-time representations of dashboards', icon: 'camera', url: '/dashboard/snapshots', - parentItem: { - id: 'dashboards', - text: 'Dashboards', - section: NavSection.Core, - subTitle: 'Manage dashboards and folders', - icon: 'apps', - url: '/dashboards', - sortWeight: -1800, - children: [ - { - id: 'manage-dashboards', - text: 'Browse', - icon: 'sitemap', - url: '/dashboards', - }, - { - id: 'playlists', - text: 'Playlists', - icon: 'presentation-play', - url: '/playlists', - }, - { - id: 'snapshots', - text: 'Snapshots', - icon: 'camera', - url: '/dashboard/snapshots', - }, - { - id: 'library-panels', - text: 'Library panels', - icon: 'library-panel', - url: '/library-panels', - }, - { - id: 'divider', - text: 'Divider', - divider: true, - hideFromTabs: true, - }, - { - id: 'new-dashboard', - text: 'New dashboard', - icon: 'plus', - url: '/dashboard/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - { - id: 'new-folder', - text: 'New folder', - subTitle: 'Create a new folder to organize your dashboards', - icon: 'plus', - url: '/dashboards/folder/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - { - id: 'import', - text: 'Import', - subTitle: 'Import dashboard from file or Grafana.com', - icon: 'plus', - url: '/dashboard/import', - hideFromTabs: true, - showIconInNavbar: true, - }, - ], - }, }, - 'library-panels': { - id: 'library-panels', + 'dashboards/library-panels': { + id: 'dashboards/library-panels', text: 'Library panels', + subTitle: 'Reusable panels that can be added to multiple dashboards', icon: 'library-panel', url: '/library-panels', - parentItem: { - id: 'dashboards', - text: 'Dashboards', - section: NavSection.Core, - subTitle: 'Manage dashboards and folders', - icon: 'apps', - url: '/dashboards', - sortWeight: -1800, - children: [ - { - id: 'manage-dashboards', - text: 'Browse', - icon: 'sitemap', - url: '/dashboards', - }, - { - id: 'playlists', - text: 'Playlists', - icon: 'presentation-play', - url: '/playlists', - }, - { - id: 'snapshots', - text: 'Snapshots', - icon: 'camera', - url: '/dashboard/snapshots', - }, - { - id: 'library-panels', - text: 'Library panels', - icon: 'library-panel', - url: '/library-panels', - }, - { - id: 'divider', - text: 'Divider', - divider: true, - hideFromTabs: true, - }, - { - id: 'new-dashboard', - text: 'New dashboard', - icon: 'plus', - url: '/dashboard/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - { - id: 'new-folder', - text: 'New folder', - subTitle: 'Create a new folder to organize your dashboards', - icon: 'plus', - url: '/dashboards/folder/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - { - id: 'import', - text: 'Import', - subTitle: 'Import dashboard from file or Grafana.com', - icon: 'plus', - url: '/dashboard/import', - hideFromTabs: true, - showIconInNavbar: true, - }, - ], - }, - }, - divider: { - id: 'divider', - text: 'Divider', - divider: true, - hideFromTabs: true, - parentItem: { - id: 'alerting', - text: 'Alerting', - section: NavSection.Core, - subTitle: 'Alert rules and notifications', - icon: 'bell', - url: '/alerting/list', - sortWeight: -1600, - children: [ - { - id: 'alert-list', - text: 'Alert rules', - icon: 'list-ul', - url: '/alerting/list', - }, - { - id: 'receivers', - text: 'Contact points', - icon: 'comment-alt-share', - url: '/alerting/notifications', - }, - { - id: 'am-routes', - text: 'Notification policies', - icon: 'sitemap', - url: '/alerting/routes', - }, - { - id: 'silences', - text: 'Silences', - icon: 'bell-slash', - url: '/alerting/silences', - }, - { - id: 'groups', - text: 'Alert groups', - icon: 'layer-group', - url: '/alerting/groups', - }, - { - id: 'alerting-admin', - text: 'Admin', - icon: 'cog', - url: '/alerting/admin', - }, - { - id: 'divider', - text: 'Divider', - divider: true, - hideFromTabs: true, - }, - { - id: 'alert', - text: 'New alert rule', - subTitle: 'Create an alert rule', - icon: 'plus', - url: '/alerting/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - ], - }, - }, - 'new-dashboard': { - id: 'new-dashboard', - text: 'New dashboard', - icon: 'plus', - url: '/dashboard/new', - hideFromTabs: true, - showIconInNavbar: true, - parentItem: { - id: 'dashboards', - text: 'Dashboards', - section: NavSection.Core, - subTitle: 'Manage dashboards and folders', - icon: 'apps', - url: '/dashboards', - sortWeight: -1800, - children: [ - { - id: 'manage-dashboards', - text: 'Browse', - icon: 'sitemap', - url: '/dashboards', - }, - { - id: 'playlists', - text: 'Playlists', - icon: 'presentation-play', - url: '/playlists', - }, - { - id: 'snapshots', - text: 'Snapshots', - icon: 'camera', - url: '/dashboard/snapshots', - }, - { - id: 'library-panels', - text: 'Library panels', - icon: 'library-panel', - url: '/library-panels', - }, - { - id: 'divider', - text: 'Divider', - divider: true, - hideFromTabs: true, - }, - { - id: 'new-dashboard', - text: 'New dashboard', - icon: 'plus', - url: '/dashboard/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - { - id: 'new-folder', - text: 'New folder', - subTitle: 'Create a new folder to organize your dashboards', - icon: 'plus', - url: '/dashboards/folder/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - { - id: 'import', - text: 'Import', - subTitle: 'Import dashboard from file or Grafana.com', - icon: 'plus', - url: '/dashboard/import', - hideFromTabs: true, - showIconInNavbar: true, - }, - ], - }, - }, - 'new-folder': { - id: 'new-folder', - text: 'New folder', - subTitle: 'Create a new folder to organize your dashboards', - icon: 'plus', - url: '/dashboards/folder/new', - hideFromTabs: true, - showIconInNavbar: true, - parentItem: { - id: 'dashboards', - text: 'Dashboards', - section: NavSection.Core, - subTitle: 'Manage dashboards and folders', - icon: 'apps', - url: '/dashboards', - sortWeight: -1800, - children: [ - { - id: 'manage-dashboards', - text: 'Browse', - icon: 'sitemap', - url: '/dashboards', - }, - { - id: 'playlists', - text: 'Playlists', - icon: 'presentation-play', - url: '/playlists', - }, - { - id: 'snapshots', - text: 'Snapshots', - icon: 'camera', - url: '/dashboard/snapshots', - }, - { - id: 'library-panels', - text: 'Library panels', - icon: 'library-panel', - url: '/library-panels', - }, - { - id: 'divider', - text: 'Divider', - divider: true, - hideFromTabs: true, - }, - { - id: 'new-dashboard', - text: 'New dashboard', - icon: 'plus', - url: '/dashboard/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - { - id: 'new-folder', - text: 'New folder', - subTitle: 'Create a new folder to organize your dashboards', - icon: 'plus', - url: '/dashboards/folder/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - { - id: 'import', - text: 'Import', - subTitle: 'Import dashboard from file or Grafana.com', - icon: 'plus', - url: '/dashboard/import', - hideFromTabs: true, - showIconInNavbar: true, - }, - ], - }, - }, - import: { - id: 'import', - text: 'Import', - subTitle: 'Import dashboard from file or Grafana.com', - icon: 'plus', - url: '/dashboard/import', - hideFromTabs: true, - showIconInNavbar: true, - parentItem: { - id: 'dashboards', - text: 'Dashboards', - section: NavSection.Core, - subTitle: 'Manage dashboards and folders', - icon: 'apps', - url: '/dashboards', - sortWeight: -1800, - children: [ - { - id: 'manage-dashboards', - text: 'Browse', - icon: 'sitemap', - url: '/dashboards', - }, - { - id: 'playlists', - text: 'Playlists', - icon: 'presentation-play', - url: '/playlists', - }, - { - id: 'snapshots', - text: 'Snapshots', - icon: 'camera', - url: '/dashboard/snapshots', - }, - { - id: 'library-panels', - text: 'Library panels', - icon: 'library-panel', - url: '/library-panels', - }, - { - id: 'divider', - text: 'Divider', - divider: true, - hideFromTabs: true, - }, - { - id: 'new-dashboard', - text: 'New dashboard', - icon: 'plus', - url: '/dashboard/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - { - id: 'new-folder', - text: 'New folder', - subTitle: 'Create a new folder to organize your dashboards', - icon: 'plus', - url: '/dashboards/folder/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - { - id: 'import', - text: 'Import', - subTitle: 'Import dashboard from file or Grafana.com', - icon: 'plus', - url: '/dashboard/import', - hideFromTabs: true, - showIconInNavbar: true, - }, - ], - }, }, 'not-found': { text: 'Page not found', subTitle: '404 Error', icon: 'exclamation-triangle', }, + error: { + text: 'Page error', + subTitle: 'An unexpected error', + icon: 'exclamation-triangle', + }, explore: { id: 'explore', text: 'Explore', @@ -667,44 +103,57 @@ export const navIndex: NavIndex = { subTitle: 'Explore your data', icon: 'compass', url: '/explore', - sortWeight: -1700, + sortWeight: -1500, + parentItem: { + id: 'home', + text: 'Home', + section: NavSection.Core, + icon: 'home-alt', + url: '/', + sortWeight: -2000, + }, }, alerting: { id: 'alerting', text: 'Alerting', section: NavSection.Core, - subTitle: 'Alert rules and notifications', + subTitle: 'Learn about problems in your systems moments after they occur', icon: 'bell', - url: '/alerting/list', - sortWeight: -1600, + url: '/alerting', + sortWeight: -1400, children: [ { id: 'alert-list', text: 'Alert rules', + subTitle: 'Rules that determine whether an alert will fire', icon: 'list-ul', url: '/alerting/list', }, { id: 'receivers', text: 'Contact points', + subTitle: 'Decide how your contacts are notified when an alert fires', icon: 'comment-alt-share', url: '/alerting/notifications', }, { id: 'am-routes', text: 'Notification policies', + subTitle: 'Determine how alerts are routed to contact points', icon: 'sitemap', url: '/alerting/routes', }, { id: 'silences', text: 'Silences', + subTitle: 'Stop notifications from one or more alerting rules', icon: 'bell-slash', url: '/alerting/silences', }, { id: 'groups', text: 'Alert groups', + subTitle: 'See grouped alerts from an Alertmanager instance', icon: 'layer-group', url: '/alerting/groups', }, @@ -730,414 +179,55 @@ export const navIndex: NavIndex = { showIconInNavbar: true, }, ], + parentItem: { + id: 'home', + text: 'Home', + section: NavSection.Core, + icon: 'home-alt', + url: '/', + sortWeight: -2000, + }, }, 'alert-list': { id: 'alert-list', text: 'Alert rules', + subTitle: 'Rules that determine whether an alert will fire', icon: 'list-ul', url: '/alerting/list', - parentItem: { - id: 'alerting', - text: 'Alerting', - section: NavSection.Core, - subTitle: 'Alert rules and notifications', - icon: 'bell', - url: '/alerting/list', - sortWeight: -1600, - children: [ - { - id: 'alert-list', - text: 'Alert rules', - icon: 'list-ul', - url: '/alerting/list', - }, - { - id: 'receivers', - text: 'Contact points', - icon: 'comment-alt-share', - url: '/alerting/notifications', - }, - { - id: 'am-routes', - text: 'Notification policies', - icon: 'sitemap', - url: '/alerting/routes', - }, - { - id: 'silences', - text: 'Silences', - icon: 'bell-slash', - url: '/alerting/silences', - }, - { - id: 'groups', - text: 'Alert groups', - icon: 'layer-group', - url: '/alerting/groups', - }, - { - id: 'alerting-admin', - text: 'Admin', - icon: 'cog', - url: '/alerting/admin', - }, - { - id: 'divider', - text: 'Divider', - divider: true, - hideFromTabs: true, - }, - { - id: 'alert', - text: 'New alert rule', - subTitle: 'Create an alert rule', - icon: 'plus', - url: '/alerting/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - ], - }, }, receivers: { id: 'receivers', text: 'Contact points', + subTitle: 'Decide how your contacts are notified when an alert fires', icon: 'comment-alt-share', url: '/alerting/notifications', - parentItem: { - id: 'alerting', - text: 'Alerting', - section: NavSection.Core, - subTitle: 'Alert rules and notifications', - icon: 'bell', - url: '/alerting/list', - sortWeight: -1600, - children: [ - { - id: 'alert-list', - text: 'Alert rules', - icon: 'list-ul', - url: '/alerting/list', - }, - { - id: 'receivers', - text: 'Contact points', - icon: 'comment-alt-share', - url: '/alerting/notifications', - }, - { - id: 'am-routes', - text: 'Notification policies', - icon: 'sitemap', - url: '/alerting/routes', - }, - { - id: 'silences', - text: 'Silences', - icon: 'bell-slash', - url: '/alerting/silences', - }, - { - id: 'groups', - text: 'Alert groups', - icon: 'layer-group', - url: '/alerting/groups', - }, - { - id: 'alerting-admin', - text: 'Admin', - icon: 'cog', - url: '/alerting/admin', - }, - { - id: 'divider', - text: 'Divider', - divider: true, - hideFromTabs: true, - }, - { - id: 'alert', - text: 'New alert rule', - subTitle: 'Create an alert rule', - icon: 'plus', - url: '/alerting/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - ], - }, }, 'am-routes': { id: 'am-routes', text: 'Notification policies', + subTitle: 'Determine how alerts are routed to contact points', icon: 'sitemap', url: '/alerting/routes', - parentItem: { - id: 'alerting', - text: 'Alerting', - section: NavSection.Core, - subTitle: 'Alert rules and notifications', - icon: 'bell', - url: '/alerting/list', - sortWeight: -1600, - children: [ - { - id: 'alert-list', - text: 'Alert rules', - icon: 'list-ul', - url: '/alerting/list', - }, - { - id: 'receivers', - text: 'Contact points', - icon: 'comment-alt-share', - url: '/alerting/notifications', - }, - { - id: 'am-routes', - text: 'Notification policies', - icon: 'sitemap', - url: '/alerting/routes', - }, - { - id: 'silences', - text: 'Silences', - icon: 'bell-slash', - url: '/alerting/silences', - }, - { - id: 'groups', - text: 'Alert groups', - icon: 'layer-group', - url: '/alerting/groups', - }, - { - id: 'alerting-admin', - text: 'Admin', - icon: 'cog', - url: '/alerting/admin', - }, - { - id: 'divider', - text: 'Divider', - divider: true, - hideFromTabs: true, - }, - { - id: 'alert', - text: 'New alert rule', - subTitle: 'Create an alert rule', - icon: 'plus', - url: '/alerting/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - ], - }, }, silences: { id: 'silences', text: 'Silences', + subTitle: 'Stop notifications from one or more alerting rules', icon: 'bell-slash', url: '/alerting/silences', - parentItem: { - id: 'alerting', - text: 'Alerting', - section: NavSection.Core, - subTitle: 'Alert rules and notifications', - icon: 'bell', - url: '/alerting/list', - sortWeight: -1600, - children: [ - { - id: 'alert-list', - text: 'Alert rules', - icon: 'list-ul', - url: '/alerting/list', - }, - { - id: 'receivers', - text: 'Contact points', - icon: 'comment-alt-share', - url: '/alerting/notifications', - }, - { - id: 'am-routes', - text: 'Notification policies', - icon: 'sitemap', - url: '/alerting/routes', - }, - { - id: 'silences', - text: 'Silences', - icon: 'bell-slash', - url: '/alerting/silences', - }, - { - id: 'groups', - text: 'Alert groups', - icon: 'layer-group', - url: '/alerting/groups', - }, - { - id: 'alerting-admin', - text: 'Admin', - icon: 'cog', - url: '/alerting/admin', - }, - { - id: 'divider', - text: 'Divider', - divider: true, - hideFromTabs: true, - }, - { - id: 'alert', - text: 'New alert rule', - subTitle: 'Create an alert rule', - icon: 'plus', - url: '/alerting/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - ], - }, }, groups: { id: 'groups', text: 'Alert groups', + subTitle: 'See grouped alerts from an Alertmanager instance', icon: 'layer-group', url: '/alerting/groups', - parentItem: { - id: 'alerting', - text: 'Alerting', - section: NavSection.Core, - subTitle: 'Alert rules and notifications', - icon: 'bell', - url: '/alerting/list', - sortWeight: -1600, - children: [ - { - id: 'alert-list', - text: 'Alert rules', - icon: 'list-ul', - url: '/alerting/list', - }, - { - id: 'receivers', - text: 'Contact points', - icon: 'comment-alt-share', - url: '/alerting/notifications', - }, - { - id: 'am-routes', - text: 'Notification policies', - icon: 'sitemap', - url: '/alerting/routes', - }, - { - id: 'silences', - text: 'Silences', - icon: 'bell-slash', - url: '/alerting/silences', - }, - { - id: 'groups', - text: 'Alert groups', - icon: 'layer-group', - url: '/alerting/groups', - }, - { - id: 'alerting-admin', - text: 'Admin', - icon: 'cog', - url: '/alerting/admin', - }, - { - id: 'divider', - text: 'Divider', - divider: true, - hideFromTabs: true, - }, - { - id: 'alert', - text: 'New alert rule', - subTitle: 'Create an alert rule', - icon: 'plus', - url: '/alerting/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - ], - }, }, 'alerting-admin': { id: 'alerting-admin', text: 'Admin', icon: 'cog', url: '/alerting/admin', - parentItem: { - id: 'alerting', - text: 'Alerting', - section: NavSection.Core, - subTitle: 'Alert rules and notifications', - icon: 'bell', - url: '/alerting/list', - sortWeight: -1600, - children: [ - { - id: 'alert-list', - text: 'Alert rules', - icon: 'list-ul', - url: '/alerting/list', - }, - { - id: 'receivers', - text: 'Contact points', - icon: 'comment-alt-share', - url: '/alerting/notifications', - }, - { - id: 'am-routes', - text: 'Notification policies', - icon: 'sitemap', - url: '/alerting/routes', - }, - { - id: 'silences', - text: 'Silences', - icon: 'bell-slash', - url: '/alerting/silences', - }, - { - id: 'groups', - text: 'Alert groups', - icon: 'layer-group', - url: '/alerting/groups', - }, - { - id: 'alerting-admin', - text: 'Admin', - icon: 'cog', - url: '/alerting/admin', - }, - { - id: 'divider', - text: 'Divider', - divider: true, - hideFromTabs: true, - }, - { - id: 'alert', - text: 'New alert rule', - subTitle: 'Create an alert rule', - icon: 'plus', - url: '/alerting/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - ], - }, }, alert: { id: 'alert', @@ -1145,1146 +235,863 @@ export const navIndex: NavIndex = { subTitle: 'Create an alert rule', icon: 'plus', url: '/alerting/new', - hideFromTabs: true, - showIconInNavbar: true, - parentItem: { - id: 'alerting', - text: 'Alerting', - section: NavSection.Core, - subTitle: 'Alert rules and notifications', - icon: 'bell', - url: '/alerting/list', - sortWeight: -1600, - children: [ - { - id: 'alert-list', - text: 'Alert rules', - icon: 'list-ul', - url: '/alerting/list', - }, - { - id: 'receivers', - text: 'Contact points', - icon: 'comment-alt-share', - url: '/alerting/notifications', - }, - { - id: 'am-routes', - text: 'Notification policies', - icon: 'sitemap', - url: '/alerting/routes', - }, - { - id: 'silences', - text: 'Silences', - icon: 'bell-slash', - url: '/alerting/silences', - }, - { - id: 'groups', - text: 'Alert groups', - icon: 'layer-group', - url: '/alerting/groups', - }, - { - id: 'alerting-admin', - text: 'Admin', - icon: 'cog', - url: '/alerting/admin', - }, - { - id: 'divider', - text: 'Divider', - divider: true, - hideFromTabs: true, - }, - { - id: 'alert', - text: 'New alert rule', - subTitle: 'Create an alert rule', - icon: 'plus', - url: '/alerting/new', - hideFromTabs: true, - showIconInNavbar: true, - }, - ], - }, - }, - connections: { - id: 'connections', - text: 'Connections', - section: NavSection.Core, - icon: 'link', - url: '/connections', - sortWeight: -1500, - children: [ - { - id: 'connections-datasources', - text: 'Data sources', - description: 'Add and configure data sources', - icon: 'database', - url: '/connections/datasources', - active: false, - }, - { - id: 'connections-connect-data', - text: 'Connect Data', - description: 'Manage data sources', - icon: 'plug', - url: '/connections/connect-data', - active: false, - }, - ], - }, - 'connections-datasources': { - id: 'connections-datasources', - text: 'Data sources', - description: 'Add and configure data sources', - icon: 'database', - url: '/connections/datasources', - parentItem: { - id: 'connections', - text: 'Connections', - section: NavSection.Core, - icon: 'link', - url: '/connections', - sortWeight: -1500, - children: [ - { - id: 'connections-datasources', - text: 'Data sources', - description: 'Add and configure data sources', - icon: 'database', - url: '/connections/datasources', - }, - { - id: 'connections-plugins', - text: 'Plugins', - description: 'Manage plugins', - icon: 'plug', - url: '/connections/plugins', - }, - { - id: 'connections-cloud-integrations', - text: 'Cloud integrations', - description: 'Manage your cloud integrations', - icon: 'bolt', - url: '/connections/cloud-integrations', - }, - { - id: 'connections-recorded-queries', - text: 'Recorded queries', - description: 'Manage your recorded queries', - icon: 'record-audio', - url: '/connections/recorded-queries', - }, - ], - }, - }, - 'connections-plugins': { - id: 'connections-plugins', - text: 'Plugins', - description: 'Manage plugins', - icon: 'plug', - url: '/connections/plugins', - parentItem: { - id: 'connections', - text: 'Connections', - section: NavSection.Core, - icon: 'link', - url: '/connections', - sortWeight: -1500, - children: [ - { - id: 'connections-datasources', - text: 'Data sources', - description: 'Add and configure data sources', - icon: 'database', - url: '/connections/datasources', - }, - { - id: 'connections-plugins', - text: 'Plugins', - description: 'Manage plugins', - icon: 'plug', - url: '/connections/plugins', - }, - { - id: 'connections-cloud-integrations', - text: 'Cloud integrations', - description: 'Manage your cloud integrations', - icon: 'bolt', - url: '/connections/cloud-integrations', - }, - { - id: 'connections-recorded-queries', - text: 'Recorded queries', - description: 'Manage your recorded queries', - icon: 'record-audio', - url: '/connections/recorded-queries', - }, - ], - }, - }, - 'connections-cloud-integrations': { - id: 'connections-cloud-integrations', - text: 'Cloud integrations', - description: 'Manage your cloud integrations', - icon: 'bolt', - url: '/connections/cloud-integrations', - parentItem: { - id: 'connections', - text: 'Connections', - section: NavSection.Core, - icon: 'link', - url: '/connections', - sortWeight: -1500, - children: [ - { - id: 'connections-datasources', - text: 'Data sources', - description: 'Add and configure data sources', - icon: 'database', - url: '/connections/datasources', - }, - { - id: 'connections-plugins', - text: 'Plugins', - description: 'Manage plugins', - icon: 'plug', - url: '/connections/plugins', - }, - { - id: 'connections-cloud-integrations', - text: 'Cloud integrations', - description: 'Manage your cloud integrations', - icon: 'bolt', - url: '/connections/cloud-integrations', - }, - { - id: 'connections-recorded-queries', - text: 'Recorded queries', - description: 'Manage your recorded queries', - icon: 'record-audio', - url: '/connections/recorded-queries', - }, - ], - }, - }, - 'connections-recorded-queries': { - id: 'connections-recorded-queries', - text: 'Recorded queries', - description: 'Manage your recorded queries', - icon: 'record-audio', - url: '/connections/recorded-queries', - parentItem: { - id: 'connections', - text: 'Connections', - section: NavSection.Core, - icon: 'link', - url: '/connections', - sortWeight: -1500, - children: [ - { - id: 'connections-datasources', - text: 'Data sources', - description: 'Add and configure data sources', - icon: 'database', - url: '/connections/datasources', - }, - { - id: 'connections-plugins', - text: 'Plugins', - description: 'Manage plugins', - icon: 'plug', - url: '/connections/plugins', - }, - { - id: 'connections-cloud-integrations', - text: 'Cloud integrations', - description: 'Manage your cloud integrations', - icon: 'bolt', - url: '/connections/cloud-integrations', - }, - { - id: 'connections-recorded-queries', - text: 'Recorded queries', - description: 'Manage your recorded queries', - icon: 'record-audio', - url: '/connections/recorded-queries', - }, - ], - }, - }, - 'plugin-page-basic-app': { - id: 'plugin-page-basic-app', - text: 'Basic App', - section: NavSection.Plugin, - img: 'public/plugins/basic-app/img/logo.svg', - url: '/a/basic-app/one', - sortWeight: -1400, - children: [ - { - text: 'Page One', - url: '/a/basic-app/one', - }, - { - text: 'Page Two', - url: '/a/basic-app/two', - }, - { - text: 'Page Three', - url: '/a/basic-app/three', - }, - { - text: 'Page Four', - url: '/a/basic-app/four', - }, - { - text: 'Configuration', - icon: 'cog', - url: '/plugins/basic-app', - }, - ], - }, - undefined: { - text: 'Config', - url: '/plugins/grafana-synthetic-monitoring-app', - parentItem: { - id: 'plugin-page-grafana-synthetic-monitoring-app', - text: 'Synthetic Monitoring', - section: NavSection.Plugin, - img: 'public/plugins/grafana-synthetic-monitoring-app/img/logo.svg', - url: '/a/grafana-synthetic-monitoring-app/home', - sortWeight: -1400, - children: [ - { - text: 'Home', - url: '/a/grafana-synthetic-monitoring-app/home', - }, - { - text: 'Summary', - url: '/a/grafana-synthetic-monitoring-app/redirect?dashboard=summary', - }, - { - text: 'Checks', - url: '/a/grafana-synthetic-monitoring-app/checks', - }, - { - text: 'Probes', - url: '/a/grafana-synthetic-monitoring-app/probes', - }, - { - text: 'Alerts', - url: '/a/grafana-synthetic-monitoring-app/alerts', - }, - { - text: 'Config', - url: '/plugins/grafana-synthetic-monitoring-app', - }, - ], - }, - }, - 'plugin-page-cloudflare-app': { - id: 'plugin-page-cloudflare-app', - text: 'Cloudflare Grafana App', - section: NavSection.Plugin, - img: 'public/plugins/cloudflare-app/img/cf_icon.png', - sortWeight: -1400, - children: [ - { - text: 'Zones', - url: '/d/KAVdMAw9k', - }, - { - text: 'DNS Firewall', - url: '/d/QrKttDVqu', - }, - ], - }, - 'plugin-page-grafana-easystart-app': { - id: 'plugin-page-grafana-easystart-app', - text: 'Integrations and Connections', - section: NavSection.Plugin, - img: 'public/plugins/grafana-easystart-app/img/logo.svg', - url: '/a/grafana-easystart-app', - sortWeight: -1400, + hideFromTabs: true, + showIconInNavbar: true, }, - 'plugin-page-redis-explorer-app': { - id: 'plugin-page-redis-explorer-app', - text: 'Redis Explorer', - section: NavSection.Plugin, - img: 'public/plugins/redis-explorer-app/img/logo.svg', - url: '/a/redis-explorer-app/', - sortWeight: -1400, + connections: { + id: 'connections', + text: 'Connections', + section: NavSection.Core, + icon: 'link', + url: '/connections', + sortWeight: -1300, children: [ { - text: 'Home', - icon: 'home-alt', - url: '/a/redis-explorer-app/', - }, - { - text: 'Enterprise Clusters', - icon: 'apps', - url: '/d/1dKhTjtGk', - }, - { - text: 'Cluster Overview', - icon: 'monitor', - url: '/d/viroIzSGz', - }, - { - text: 'Cluster Nodes', - icon: 'sitemap', - url: '/d/hqze6rtGz', - }, - { - text: 'Cluster Databases', - icon: 'database', - url: '/d/k_A8MjtMk', + id: 'connections-your-connections', + text: 'Your connections', + subTitle: 'Manage your existing connections', + url: '/connections/your-connections', + children: [ + { + id: 'connections-your-connections-datasources', + text: 'Datasources', + subTitle: 'Manage your existing datasource connections', + url: '/connections/your-connections/datasources', + }, + { + id: 'standalone-plugin-page-/connections/your-connections/infrastructure', + text: 'Infrastructure', + url: '/connections/your-connections/infrastructure', + pluginId: 'grafana-easystart-app', + }, + ], }, { - text: 'Cluster Alerts', - icon: 'info-circle', - url: '/d/xESAiFcnk', + id: 'connections-connect-data', + text: 'Connect data', + subTitle: 'Browse and create new connections', + url: '/connections/connect-data', }, ], + parentItem: { + id: 'home', + text: 'Home', + section: NavSection.Core, + icon: 'home-alt', + url: '/', + sortWeight: -2000, + }, }, - 'plugin-page-grafana-synthetic-monitoring-app': { - id: 'plugin-page-grafana-synthetic-monitoring-app', - text: 'Synthetic Monitoring', - section: NavSection.Plugin, - img: 'public/plugins/grafana-synthetic-monitoring-app/img/logo.svg', - url: '/a/grafana-synthetic-monitoring-app/home', - sortWeight: -1400, + 'connections-your-connections': { + id: 'connections-your-connections', + text: 'Your connections', + subTitle: 'Manage your existing connections', + url: '/connections/your-connections', children: [ { - text: 'Home', - url: '/a/grafana-synthetic-monitoring-app/home', - }, - { - text: 'Summary', - url: '/a/grafana-synthetic-monitoring-app/redirect?dashboard=summary', - }, - { - text: 'Checks', - url: '/a/grafana-synthetic-monitoring-app/checks', - }, - { - text: 'Probes', - url: '/a/grafana-synthetic-monitoring-app/probes', - }, - { - text: 'Alerts', - url: '/a/grafana-synthetic-monitoring-app/alerts', + id: 'connections-your-connections-datasources', + text: 'Datasources', + subTitle: 'Manage your existing datasource connections', + url: '/connections/your-connections/datasources', }, { - text: 'Config', - url: '/plugins/grafana-synthetic-monitoring-app', + id: 'standalone-plugin-page-/connections/your-connections/infrastructure', + text: 'Infrastructure', + url: '/connections/your-connections/infrastructure', + pluginId: 'grafana-easystart-app', }, ], }, - 'plugin-page-grafana-k6-app': { - id: 'plugin-page-grafana-k6-app', - text: 'k6 Cloud App', - section: NavSection.Plugin, - img: 'public/plugins/grafana-k6-app/img/logo.svg', - url: '/a/grafana-k6-app', - sortWeight: -1400, + 'connections-your-connections-datasources': { + id: 'connections-your-connections-datasources', + text: 'Datasources', + subTitle: 'Manage your existing datasource connections', + url: '/connections/your-connections/datasources', + }, + 'standalone-plugin-page-/connections/your-connections/infrastructure': { + id: 'standalone-plugin-page-/connections/your-connections/infrastructure', + text: 'Infrastructure', + url: '/connections/your-connections/infrastructure', + pluginId: 'grafana-easystart-app', + }, + 'connections-connect-data': { + id: 'connections-connect-data', + text: 'Connect data', + subTitle: 'Browse and create new connections', + url: '/connections/connect-data', }, cfg: { id: 'cfg', - text: 'Configuration', + text: 'Administration', section: NavSection.Config, - subTitle: 'Organization: Main Org.', + subTitle: 'Organization: Main Org. 123', icon: 'cog', - url: '/datasources', - sortWeight: -1300, + url: '/admin', + sortWeight: -1100, children: [ { id: 'datasources', text: 'Data sources', - description: 'Add and configure data sources', + subTitle: 'Add and configure data sources', icon: 'database', url: '/datasources', }, { id: 'users', text: 'Users', - description: 'Manage org members', + subTitle: 'Invite and assign roles to users', icon: 'user', url: '/org/users', }, { id: 'teams', text: 'Teams', - description: 'Manage org groups', + subTitle: 'Groups of users that have common dashboard and permission needs', icon: 'users-alt', url: '/org/teams', }, { id: 'plugins', text: 'Plugins', - description: 'View and configure plugins', + subTitle: 'Extend the Grafana experience with plugins', icon: 'plug', url: '/plugins', }, { id: 'org-settings', text: 'Preferences', - description: 'Organization preferences', + subTitle: 'Manage preferences across an organization', icon: 'sliders-v-alt', url: '/org', }, { id: 'apikeys', text: 'API keys', - description: 'Create & manage API keys', + subTitle: 'Manage and create API keys that are used to interact with Grafana HTTP APIs', icon: 'key-skeleton-alt', url: '/org/apikeys', }, + { + id: 'serviceaccounts', + text: 'Service accounts', + subTitle: 'Use service accounts to run automated workloads in Grafana', + icon: 'gf-service-account', + url: '/org/serviceaccounts', + }, + { + id: 'admin', + text: 'Server admin', + section: NavSection.Config, + subTitle: 'Manage server-wide settings and access to resources such as organizations, users, and licenses', + icon: 'shield', + url: '/admin/server', + children: [ + { + id: 'global-users', + text: 'Users', + subTitle: 'Manage and create users across the whole Grafana server', + icon: 'user', + url: '/admin/users', + }, + { + id: 'global-orgs', + text: 'Organizations', + subTitle: 'Isolated instances of Grafana running on the same server', + icon: 'building', + url: '/admin/orgs', + }, + { + id: 'server-settings', + text: 'Settings', + subTitle: 'View the settings defined in your Grafana config', + icon: 'sliders-v-alt', + url: '/admin/settings', + }, + { + id: 'upgrading', + text: 'Stats and license', + icon: 'unlock', + url: '/admin/upgrading', + }, + ], + }, ], + parentItem: { + id: 'home', + text: 'Home', + section: NavSection.Core, + icon: 'home-alt', + url: '/', + sortWeight: -2000, + }, }, datasources: { id: 'datasources', text: 'Data sources', - description: 'Add and configure data sources', + subTitle: 'Add and configure data sources', icon: 'database', url: '/datasources', - parentItem: { - id: 'cfg', - text: 'Configuration', - section: NavSection.Config, - subTitle: 'Organization: Main Org.', - icon: 'cog', - url: '/datasources', - sortWeight: -1300, - children: [ - { - id: 'datasources', - text: 'Data sources', - description: 'Add and configure data sources', - icon: 'database', - url: '/datasources', - }, - { - id: 'users', - text: 'Users', - description: 'Manage org members', - icon: 'user', - url: '/org/users', - }, - { - id: 'teams', - text: 'Teams', - description: 'Manage org groups', - icon: 'users-alt', - url: '/org/teams', - }, - { - id: 'plugins', - text: 'Plugins', - description: 'View and configure plugins', - icon: 'plug', - url: '/plugins', - }, - { - id: 'org-settings', - text: 'Preferences', - description: 'Organization preferences', - icon: 'sliders-v-alt', - url: '/org', - }, - { - id: 'apikeys', - text: 'API keys', - description: 'Create & manage API keys', - icon: 'key-skeleton-alt', - url: '/org/apikeys', - }, - ], - }, }, users: { id: 'users', text: 'Users', - description: 'Manage org members', + subTitle: 'Invite and assign roles to users', icon: 'user', url: '/org/users', - parentItem: { - id: 'cfg', - text: 'Configuration', - section: NavSection.Config, - subTitle: 'Organization: Main Org.', - icon: 'cog', - url: '/datasources', - sortWeight: -1300, - children: [ - { - id: 'datasources', - text: 'Data sources', - description: 'Add and configure data sources', - icon: 'database', - url: '/datasources', - }, - { - id: 'users', - text: 'Users', - description: 'Manage org members', - icon: 'user', - url: '/org/users', - }, - { - id: 'teams', - text: 'Teams', - description: 'Manage org groups', - icon: 'users-alt', - url: '/org/teams', - }, - { - id: 'plugins', - text: 'Plugins', - description: 'View and configure plugins', - icon: 'plug', - url: '/plugins', - }, - { - id: 'org-settings', - text: 'Preferences', - description: 'Organization preferences', - icon: 'sliders-v-alt', - url: '/org', - }, - { - id: 'apikeys', - text: 'API keys', - description: 'Create & manage API keys', - icon: 'key-skeleton-alt', - url: '/org/apikeys', - }, - ], - }, }, teams: { id: 'teams', text: 'Teams', - description: 'Manage org groups', + subTitle: 'Groups of users that have common dashboard and permission needs', icon: 'users-alt', url: '/org/teams', - parentItem: { - id: 'cfg', - text: 'Configuration', - section: NavSection.Config, - subTitle: 'Organization: Main Org.', - icon: 'cog', - url: '/datasources', - sortWeight: -1300, - children: [ - { - id: 'datasources', - text: 'Data sources', - description: 'Add and configure data sources', - icon: 'database', - url: '/datasources', - }, - { - id: 'users', - text: 'Users', - description: 'Manage org members', - icon: 'user', - url: '/org/users', - }, - { - id: 'teams', - text: 'Teams', - description: 'Manage org groups', - icon: 'users-alt', - url: '/org/teams', - }, - { - id: 'plugins', - text: 'Plugins', - description: 'View and configure plugins', - icon: 'plug', - url: '/plugins', - }, - { - id: 'org-settings', - text: 'Preferences', - description: 'Organization preferences', - icon: 'sliders-v-alt', - url: '/org', - }, - { - id: 'apikeys', - text: 'API keys', - description: 'Create & manage API keys', - icon: 'key-skeleton-alt', - url: '/org/apikeys', - }, - ], - }, }, plugins: { id: 'plugins', text: 'Plugins', - description: 'View and configure plugins', + subTitle: 'Extend the Grafana experience with plugins', icon: 'plug', url: '/plugins', - parentItem: { - id: 'cfg', - text: 'Configuration', - section: NavSection.Config, - subTitle: 'Organization: Main Org.', - icon: 'cog', - url: '/datasources', - sortWeight: -1300, - children: [ - { - id: 'datasources', - text: 'Data sources', - description: 'Add and configure data sources', - icon: 'database', - url: '/datasources', - }, - { - id: 'users', - text: 'Users', - description: 'Manage org members', - icon: 'user', - url: '/org/users', - }, - { - id: 'teams', - text: 'Teams', - description: 'Manage org groups', - icon: 'users-alt', - url: '/org/teams', - }, - { - id: 'plugins', - text: 'Plugins', - description: 'View and configure plugins', - icon: 'plug', - url: '/plugins', - }, - { - id: 'org-settings', - text: 'Preferences', - description: 'Organization preferences', - icon: 'sliders-v-alt', - url: '/org', - }, - { - id: 'apikeys', - text: 'API keys', - description: 'Create & manage API keys', - icon: 'key-skeleton-alt', - url: '/org/apikeys', - }, - ], - }, }, 'org-settings': { id: 'org-settings', text: 'Preferences', - description: 'Organization preferences', + subTitle: 'Manage preferences across an organization', icon: 'sliders-v-alt', url: '/org', - parentItem: { - id: 'cfg', - text: 'Configuration', - section: NavSection.Config, - subTitle: 'Organization: Main Org.', - icon: 'cog', - url: '/datasources', - sortWeight: -1300, - children: [ - { - id: 'datasources', - text: 'Data sources', - description: 'Add and configure data sources', - icon: 'database', - url: '/datasources', - }, - { - id: 'users', - text: 'Users', - description: 'Manage org members', - icon: 'user', - url: '/org/users', - }, - { - id: 'teams', - text: 'Teams', - description: 'Manage org groups', - icon: 'users-alt', - url: '/org/teams', - }, - { - id: 'plugins', - text: 'Plugins', - description: 'View and configure plugins', - icon: 'plug', - url: '/plugins', - }, - { - id: 'org-settings', - text: 'Preferences', - description: 'Organization preferences', - icon: 'sliders-v-alt', - url: '/org', - }, - { - id: 'apikeys', - text: 'API keys', - description: 'Create & manage API keys', - icon: 'key-skeleton-alt', - url: '/org/apikeys', - }, - ], - }, }, apikeys: { id: 'apikeys', text: 'API keys', - description: 'Create & manage API keys', + subTitle: 'Manage and create API keys that are used to interact with Grafana HTTP APIs', icon: 'key-skeleton-alt', url: '/org/apikeys', - parentItem: { - id: 'cfg', - text: 'Configuration', - section: NavSection.Config, - subTitle: 'Organization: Main Org.', - icon: 'cog', - url: '/datasources', - sortWeight: -1300, - children: [ - { - id: 'datasources', - text: 'Data sources', - description: 'Add and configure data sources', - icon: 'database', - url: '/datasources', - }, - { - id: 'users', - text: 'Users', - description: 'Manage org members', - icon: 'user', - url: '/org/users', - }, - { - id: 'teams', - text: 'Teams', - description: 'Manage org groups', - icon: 'users-alt', - url: '/org/teams', - }, - { - id: 'plugins', - text: 'Plugins', - description: 'View and configure plugins', - icon: 'plug', - url: '/plugins', - }, - { - id: 'org-settings', - text: 'Preferences', - description: 'Organization preferences', - icon: 'sliders-v-alt', - url: '/org', - }, - { - id: 'apikeys', - text: 'API keys', - description: 'Create & manage API keys', - icon: 'key-skeleton-alt', - url: '/org/apikeys', - }, - ], - }, + }, + serviceaccounts: { + id: 'serviceaccounts', + text: 'Service accounts', + subTitle: 'Use service accounts to run automated workloads in Grafana', + icon: 'gf-service-account', + url: '/org/serviceaccounts', }, admin: { id: 'admin', - text: 'Server Admin', + text: 'Server admin', section: NavSection.Config, - subTitle: 'Manage all users and orgs', + subTitle: 'Manage server-wide settings and access to resources such as organizations, users, and licenses', icon: 'shield', - url: '/admin/users', - sortWeight: -1200, - hideFromTabs: true, + url: '/admin/server', children: [ { id: 'global-users', text: 'Users', + subTitle: 'Manage and create users across the whole Grafana server', icon: 'user', url: '/admin/users', }, { id: 'global-orgs', - text: 'Orgs', + text: 'Organizations', + subTitle: 'Isolated instances of Grafana running on the same server', icon: 'building', url: '/admin/orgs', }, { - id: 'server-settings', - text: 'Settings', - icon: 'sliders-v-alt', - url: '/admin/settings', + id: 'server-settings', + text: 'Settings', + subTitle: 'View the settings defined in your Grafana config', + icon: 'sliders-v-alt', + url: '/admin/settings', + }, + { + id: 'upgrading', + text: 'Stats and license', + icon: 'unlock', + url: '/admin/upgrading', + }, + ], + }, + 'global-users': { + id: 'global-users', + text: 'Users', + subTitle: 'Manage and create users across the whole Grafana server', + icon: 'user', + url: '/admin/users', + }, + 'global-orgs': { + id: 'global-orgs', + text: 'Organizations', + subTitle: 'Isolated instances of Grafana running on the same server', + icon: 'building', + url: '/admin/orgs', + }, + 'server-settings': { + id: 'server-settings', + text: 'Settings', + subTitle: 'View the settings defined in your Grafana config', + icon: 'sliders-v-alt', + url: '/admin/settings', + }, + upgrading: { + id: 'upgrading', + text: 'Stats and license', + icon: 'unlock', + url: '/admin/upgrading', + }, + monitoring: { + id: 'monitoring', + text: 'Monitoring', + section: NavSection.Core, + subTitle: 'Monitoring and infrastructure apps', + icon: 'heart-rate', + url: '/monitoring', + sortWeight: -900, + children: [ + { + id: 'plugin-page-grafana-synthetic-monitoring-app', + text: 'Synthetic Monitoring', + section: NavSection.Plugin, + img: 'public/plugins/grafana-synthetic-monitoring-app/img/logo.svg', + url: '/a/grafana-synthetic-monitoring-app/home', + sortWeight: 2, + isSection: true, + children: [ + { + text: 'Summary', + url: '/a/grafana-synthetic-monitoring-app/redirect?dashboard=summary', + pluginId: 'grafana-synthetic-monitoring-app', + }, + { + text: 'Checks', + url: '/a/grafana-synthetic-monitoring-app/checks', + pluginId: 'grafana-synthetic-monitoring-app', + }, + { + text: 'Probes', + url: '/a/grafana-synthetic-monitoring-app/probes', + pluginId: 'grafana-synthetic-monitoring-app', + }, + { + text: 'Alerts', + url: '/a/grafana-synthetic-monitoring-app/alerts', + pluginId: 'grafana-synthetic-monitoring-app', + }, + { + text: 'Config', + url: '/plugins/grafana-synthetic-monitoring-app', + pluginId: 'grafana-synthetic-monitoring-app', + }, + ], + pluginId: 'grafana-synthetic-monitoring-app', + }, + ], + parentItem: { + id: 'home', + text: 'Home', + section: NavSection.Core, + icon: 'home-alt', + url: '/', + sortWeight: -2000, + }, + }, + 'plugin-page-grafana-synthetic-monitoring-app': { + id: 'plugin-page-grafana-synthetic-monitoring-app', + text: 'Synthetic Monitoring', + section: NavSection.Plugin, + img: 'public/plugins/grafana-synthetic-monitoring-app/img/logo.svg', + url: '/a/grafana-synthetic-monitoring-app/home', + sortWeight: 2, + isSection: true, + children: [ + { + text: 'Summary', + url: '/a/grafana-synthetic-monitoring-app/redirect?dashboard=summary', + pluginId: 'grafana-synthetic-monitoring-app', + }, + { + text: 'Checks', + url: '/a/grafana-synthetic-monitoring-app/checks', + pluginId: 'grafana-synthetic-monitoring-app', + }, + { + text: 'Probes', + url: '/a/grafana-synthetic-monitoring-app/probes', + pluginId: 'grafana-synthetic-monitoring-app', }, { - id: 'admin-plugins', - text: 'Plugins', - icon: 'plug', - url: '/admin/plugins', + text: 'Alerts', + url: '/a/grafana-synthetic-monitoring-app/alerts', + pluginId: 'grafana-synthetic-monitoring-app', }, { - id: 'upgrading', - text: 'Stats and license', - icon: 'unlock', - url: '/admin/upgrading', + text: 'Config', + url: '/plugins/grafana-synthetic-monitoring-app', + pluginId: 'grafana-synthetic-monitoring-app', }, ], + pluginId: 'grafana-synthetic-monitoring-app', }, - 'global-users': { - id: 'global-users', - text: 'Users', - icon: 'user', - url: '/admin/users', + undefined: { + text: 'Cluster Alerts', + icon: 'info-circle', + url: '/d/xESAiFcnk', + pluginId: 'redis-explorer-app', parentItem: { - id: 'admin', - text: 'Server Admin', - section: NavSection.Config, - subTitle: 'Manage all users and orgs', - icon: 'shield', - url: '/admin/users', + id: 'plugin-page-redis-explorer-app', + text: 'Redis Explorer', + section: NavSection.Plugin, + img: 'public/plugins/redis-explorer-app/img/logo.svg', + url: '/a/redis-explorer-app/', sortWeight: -1200, - hideFromTabs: true, + isSection: true, children: [ { - id: 'global-users', - text: 'Users', - icon: 'user', - url: '/admin/users', + text: 'Enterprise Clusters', + icon: 'apps', + url: '/d/1dKhTjtGk', + pluginId: 'redis-explorer-app', }, { - id: 'global-orgs', - text: 'Orgs', - icon: 'building', - url: '/admin/orgs', + text: 'Cluster Overview', + icon: 'monitor', + url: '/d/viroIzSGz', + pluginId: 'redis-explorer-app', }, { - id: 'server-settings', - text: 'Settings', - icon: 'sliders-v-alt', - url: '/admin/settings', - }, - { - id: 'admin-plugins', - text: 'Plugins', - icon: 'plug', - url: '/admin/plugins', + text: 'Cluster Nodes', + icon: 'sitemap', + url: '/d/hqze6rtGz', + pluginId: 'redis-explorer-app', }, { - id: 'upgrading', - text: 'Stats and license', - icon: 'unlock', - url: '/admin/upgrading', + text: 'Cluster Databases', + icon: 'database', + url: '/d/k_A8MjtMk', + pluginId: 'redis-explorer-app', }, ], - }, - }, - 'global-orgs': { - id: 'global-orgs', - text: 'Orgs', - icon: 'building', - url: '/admin/orgs', - parentItem: { - id: 'admin', - text: 'Server Admin', - section: NavSection.Config, - subTitle: 'Manage all users and orgs', - icon: 'shield', - url: '/admin/users', - sortWeight: -1200, - hideFromTabs: true, - children: [ - { - id: 'global-users', - text: 'Users', - icon: 'user', - url: '/admin/users', - }, - { - id: 'global-orgs', - text: 'Orgs', - icon: 'building', - url: '/admin/orgs', - }, - { - id: 'server-settings', - text: 'Settings', - icon: 'sliders-v-alt', - url: '/admin/settings', - }, - { - id: 'admin-plugins', - text: 'Plugins', - icon: 'plug', - url: '/admin/plugins', - }, - { - id: 'upgrading', - text: 'Stats and license', - icon: 'unlock', - url: '/admin/upgrading', + pluginId: 'redis-explorer-app', + parentItem: { + id: 'apps', + text: 'Apps', + section: NavSection.Core, + subTitle: 'App plugins that extend the Grafana experience', + icon: 'apps', + url: '/apps', + sortWeight: -800, + children: [ + { + id: 'plugin-page-cloudflare-app', + text: 'Cloudflare Grafana App', + section: NavSection.Plugin, + img: 'public/plugins/cloudflare-app/img/cf_icon.png', + url: '/a/cloudflare-app', + sortWeight: -1200, + isSection: true, + children: [ + { + text: 'Zones', + url: '/d/KAVdMAw9k', + pluginId: 'cloudflare-app', + }, + { + text: 'DNS Firewall', + url: '/d/QrKttDVqu', + pluginId: 'cloudflare-app', + }, + ], + pluginId: 'cloudflare-app', + }, + { + id: 'plugin-page-grafana-easystart-app', + text: 'Integrations and Connections', + section: NavSection.Plugin, + img: 'public/plugins/grafana-easystart-app/img/logo.svg', + url: '/a/grafana-easystart-app', + sortWeight: -1200, + isSection: true, + children: [ + { + text: 'Custom page', + url: '/connections/custom-page', + pluginId: 'grafana-easystart-app', + }, + ], + pluginId: 'grafana-easystart-app', + }, + { + id: 'plugin-page-grafana-k6-app', + text: 'k6 Cloud App', + section: NavSection.Plugin, + img: 'public/plugins/grafana-k6-app/img/logo.svg', + url: '/a/grafana-k6-app', + sortWeight: -1200, + isSection: true, + pluginId: 'grafana-k6-app', + }, + { + id: 'plugin-page-myorg-app-basic', + text: 'Basic App', + section: NavSection.Plugin, + img: 'public/plugins/myorg-app-basic/img/logo.svg', + url: '/a/myorg-app-basic/one', + sortWeight: -1200, + isSection: true, + children: [ + { + text: 'Page Two', + url: '/a/myorg-app-basic/two', + pluginId: 'myorg-app-basic', + }, + { + text: 'Page Three', + url: '/a/myorg-app-basic/three', + pluginId: 'myorg-app-basic', + }, + { + text: 'Page Four', + url: '/a/myorg-app-basic/four', + pluginId: 'myorg-app-basic', + }, + { + text: 'Configuration', + icon: 'cog', + url: '/plugins/myorg-app-basic', + pluginId: 'myorg-app-basic', + }, + ], + pluginId: 'myorg-app-basic', + }, + ], + parentItem: { + id: 'home', + text: 'Home', + section: NavSection.Core, + icon: 'home-alt', + url: '/', + sortWeight: -2000, }, - ], + }, }, }, - 'server-settings': { - id: 'server-settings', - text: 'Settings', - icon: 'sliders-v-alt', - url: '/admin/settings', + apps: { + id: 'apps', + text: 'Apps', + section: NavSection.Core, + subTitle: 'App plugins that extend the Grafana experience', + icon: 'apps', + url: '/apps', + sortWeight: -800, + children: [ + { + id: 'plugin-page-cloudflare-app', + text: 'Cloudflare Grafana App', + section: NavSection.Plugin, + img: 'public/plugins/cloudflare-app/img/cf_icon.png', + url: '/a/cloudflare-app', + sortWeight: -1200, + isSection: true, + children: [ + { + text: 'Zones', + url: '/d/KAVdMAw9k', + pluginId: 'cloudflare-app', + }, + { + text: 'DNS Firewall', + url: '/d/QrKttDVqu', + pluginId: 'cloudflare-app', + }, + ], + pluginId: 'cloudflare-app', + }, + { + id: 'plugin-page-grafana-easystart-app', + text: 'Integrations and Connections', + section: NavSection.Plugin, + img: 'public/plugins/grafana-easystart-app/img/logo.svg', + url: '/a/grafana-easystart-app', + sortWeight: -1200, + isSection: true, + children: [ + { + text: 'Custom page', + url: '/connections/custom-page', + pluginId: 'grafana-easystart-app', + }, + ], + pluginId: 'grafana-easystart-app', + }, + { + id: 'plugin-page-grafana-k6-app', + text: 'k6 Cloud App', + section: NavSection.Plugin, + img: 'public/plugins/grafana-k6-app/img/logo.svg', + url: '/a/grafana-k6-app', + sortWeight: -1200, + isSection: true, + pluginId: 'grafana-k6-app', + }, + { + id: 'plugin-page-myorg-app-basic', + text: 'Basic App', + section: NavSection.Plugin, + img: 'public/plugins/myorg-app-basic/img/logo.svg', + url: '/a/myorg-app-basic/one', + sortWeight: -1200, + isSection: true, + children: [ + { + text: 'Page Two', + url: '/a/myorg-app-basic/two', + pluginId: 'myorg-app-basic', + }, + { + text: 'Page Three', + url: '/a/myorg-app-basic/three', + pluginId: 'myorg-app-basic', + }, + { + text: 'Page Four', + url: '/a/myorg-app-basic/four', + pluginId: 'myorg-app-basic', + }, + { + text: 'Configuration', + icon: 'cog', + url: '/plugins/myorg-app-basic', + pluginId: 'myorg-app-basic', + }, + ], + pluginId: 'myorg-app-basic', + }, + ], parentItem: { - id: 'admin', - text: 'Server Admin', - section: NavSection.Config, - subTitle: 'Manage all users and orgs', - icon: 'shield', - url: '/admin/users', - sortWeight: -1200, - hideFromTabs: true, - children: [ - { - id: 'global-users', - text: 'Users', - icon: 'user', - url: '/admin/users', - }, - { - id: 'global-orgs', - text: 'Orgs', - icon: 'building', - url: '/admin/orgs', - }, - { - id: 'server-settings', - text: 'Settings', - icon: 'sliders-v-alt', - url: '/admin/settings', - }, - { - id: 'admin-plugins', - text: 'Plugins', - icon: 'plug', - url: '/admin/plugins', - }, - { - id: 'upgrading', - text: 'Stats and license', - icon: 'unlock', - url: '/admin/upgrading', - }, - ], + id: 'home', + text: 'Home', + section: NavSection.Core, + icon: 'home-alt', + url: '/', + sortWeight: -2000, }, }, - 'admin-plugins': { - id: 'admin-plugins', - text: 'Plugins', - icon: 'plug', - url: '/admin/plugins', - parentItem: { - id: 'admin', - text: 'Server Admin', - section: NavSection.Config, - subTitle: 'Manage all users and orgs', - icon: 'shield', - url: '/admin/users', - sortWeight: -1200, - hideFromTabs: true, - children: [ - { - id: 'global-users', - text: 'Users', - icon: 'user', - url: '/admin/users', - }, - { - id: 'global-orgs', - text: 'Orgs', - icon: 'building', - url: '/admin/orgs', - }, - { - id: 'server-settings', - text: 'Settings', - icon: 'sliders-v-alt', - url: '/admin/settings', - }, - { - id: 'admin-plugins', - text: 'Plugins', - icon: 'plug', - url: '/admin/plugins', - }, - { - id: 'upgrading', - text: 'Stats and license', - icon: 'unlock', - url: '/admin/upgrading', - }, - ], - }, + 'plugin-page-cloudflare-app': { + id: 'plugin-page-cloudflare-app', + text: 'Cloudflare Grafana App', + section: NavSection.Plugin, + img: 'public/plugins/cloudflare-app/img/cf_icon.png', + url: '/a/cloudflare-app', + sortWeight: -1200, + isSection: true, + children: [ + { + text: 'Zones', + url: '/d/KAVdMAw9k', + pluginId: 'cloudflare-app', + }, + { + text: 'DNS Firewall', + url: '/d/QrKttDVqu', + pluginId: 'cloudflare-app', + }, + ], + pluginId: 'cloudflare-app', }, - upgrading: { - id: 'upgrading', - text: 'Stats and license', - icon: 'unlock', - url: '/admin/upgrading', + 'plugin-page-grafana-easystart-app': { + id: 'plugin-page-grafana-easystart-app', + text: 'Integrations and Connections', + section: NavSection.Plugin, + img: 'public/plugins/grafana-easystart-app/img/logo.svg', + url: '/a/grafana-easystart-app', + sortWeight: -1200, + isSection: true, + children: [ + { + text: 'Custom page', + url: '/connections/custom-page', + pluginId: 'grafana-easystart-app', + }, + ], + pluginId: 'grafana-easystart-app', + }, + 'plugin-page-grafana-k6-app': { + id: 'plugin-page-grafana-k6-app', + text: 'k6 Cloud App', + section: NavSection.Plugin, + img: 'public/plugins/grafana-k6-app/img/logo.svg', + url: '/a/grafana-k6-app', + sortWeight: -1200, + isSection: true, + pluginId: 'grafana-k6-app', + }, + 'plugin-page-myorg-app-basic': { + id: 'plugin-page-myorg-app-basic', + text: 'Basic App', + section: NavSection.Plugin, + img: 'public/plugins/myorg-app-basic/img/logo.svg', + url: '/a/myorg-app-basic/one', + sortWeight: -1200, + isSection: true, + children: [ + { + text: 'Page Two', + url: '/a/myorg-app-basic/two', + pluginId: 'myorg-app-basic', + }, + { + text: 'Page Three', + url: '/a/myorg-app-basic/three', + pluginId: 'myorg-app-basic', + }, + { + text: 'Page Four', + url: '/a/myorg-app-basic/four', + pluginId: 'myorg-app-basic', + }, + { + text: 'Configuration', + icon: 'cog', + url: '/plugins/myorg-app-basic', + pluginId: 'myorg-app-basic', + }, + ], + pluginId: 'myorg-app-basic', + }, + 'plugin-page-redis-explorer-app': { + id: 'plugin-page-redis-explorer-app', + text: 'Redis Explorer', + section: NavSection.Plugin, + img: 'public/plugins/redis-explorer-app/img/logo.svg', + url: '/a/redis-explorer-app/', + sortWeight: -1200, + isSection: true, + children: [ + { + text: 'Enterprise Clusters', + icon: 'apps', + url: '/d/1dKhTjtGk', + pluginId: 'redis-explorer-app', + }, + { + text: 'Cluster Overview', + icon: 'monitor', + url: '/d/viroIzSGz', + pluginId: 'redis-explorer-app', + }, + { + text: 'Cluster Nodes', + icon: 'sitemap', + url: '/d/hqze6rtGz', + pluginId: 'redis-explorer-app', + }, + { + text: 'Cluster Databases', + icon: 'database', + url: '/d/k_A8MjtMk', + pluginId: 'redis-explorer-app', + }, + ], + pluginId: 'redis-explorer-app', parentItem: { - id: 'admin', - text: 'Server Admin', - section: NavSection.Config, - subTitle: 'Manage all users and orgs', - icon: 'shield', - url: '/admin/users', - sortWeight: -1200, - hideFromTabs: true, + id: 'apps', + text: 'Apps', + section: NavSection.Core, + subTitle: 'App plugins that extend the Grafana experience', + icon: 'apps', + url: '/apps', + sortWeight: -800, children: [ { - id: 'global-users', - text: 'Users', - icon: 'user', - url: '/admin/users', - }, - { - id: 'global-orgs', - text: 'Orgs', - icon: 'building', - url: '/admin/orgs', - }, - { - id: 'server-settings', - text: 'Settings', - icon: 'sliders-v-alt', - url: '/admin/settings', - }, - { - id: 'admin-plugins', - text: 'Plugins', - icon: 'plug', - url: '/admin/plugins', - }, - { - id: 'upgrading', - text: 'Stats and license', - icon: 'unlock', - url: '/admin/upgrading', + id: 'plugin-page-cloudflare-app', + text: 'Cloudflare Grafana App', + section: NavSection.Plugin, + img: 'public/plugins/cloudflare-app/img/cf_icon.png', + url: '/a/cloudflare-app', + sortWeight: -1200, + isSection: true, + children: [ + { + text: 'Zones', + url: '/d/KAVdMAw9k', + pluginId: 'cloudflare-app', + }, + { + text: 'DNS Firewall', + url: '/d/QrKttDVqu', + pluginId: 'cloudflare-app', + }, + ], + pluginId: 'cloudflare-app', + }, + { + id: 'plugin-page-grafana-easystart-app', + text: 'Integrations and Connections', + section: NavSection.Plugin, + img: 'public/plugins/grafana-easystart-app/img/logo.svg', + url: '/a/grafana-easystart-app', + sortWeight: -1200, + isSection: true, + children: [ + { + text: 'Custom page', + url: '/connections/custom-page', + pluginId: 'grafana-easystart-app', + }, + ], + pluginId: 'grafana-easystart-app', + }, + { + id: 'plugin-page-grafana-k6-app', + text: 'k6 Cloud App', + section: NavSection.Plugin, + img: 'public/plugins/grafana-k6-app/img/logo.svg', + url: '/a/grafana-k6-app', + sortWeight: -1200, + isSection: true, + pluginId: 'grafana-k6-app', + }, + { + id: 'plugin-page-myorg-app-basic', + text: 'Basic App', + section: NavSection.Plugin, + img: 'public/plugins/myorg-app-basic/img/logo.svg', + url: '/a/myorg-app-basic/one', + sortWeight: -1200, + isSection: true, + children: [ + { + text: 'Page Two', + url: '/a/myorg-app-basic/two', + pluginId: 'myorg-app-basic', + }, + { + text: 'Page Three', + url: '/a/myorg-app-basic/three', + pluginId: 'myorg-app-basic', + }, + { + text: 'Page Four', + url: '/a/myorg-app-basic/four', + pluginId: 'myorg-app-basic', + }, + { + text: 'Configuration', + icon: 'cog', + url: '/plugins/myorg-app-basic', + pluginId: 'myorg-app-basic', + }, + ], + pluginId: 'myorg-app-basic', }, ], + parentItem: { + id: 'home', + text: 'Home', + section: NavSection.Core, + icon: 'home-alt', + url: '/', + sortWeight: -2000, + }, }, }, profile: { @@ -2293,22 +1100,23 @@ export const navIndex: NavIndex = { section: NavSection.Config, img: '/avatar/46d229b033af06a191ff2267bca9ae56', url: '/profile', - sortWeight: -1100, + sortWeight: -600, + roundIcon: true, children: [ { - id: 'profile-settings', + id: 'profile/settings', text: 'Preferences', icon: 'sliders-v-alt', url: '/profile', }, { - id: 'notifications', + id: 'profile/notifications', text: 'Notification history', icon: 'bell', - url: '/notifications', + url: '/profile/notifications', }, { - id: 'change-password', + id: 'profile/password', text: 'Change password', icon: 'lock', url: '/profile/password', @@ -2322,132 +1130,32 @@ export const navIndex: NavIndex = { hideFromTabs: true, }, ], + parentItem: { + id: 'home', + text: 'Home', + section: NavSection.Core, + icon: 'home-alt', + url: '/', + sortWeight: -2000, + }, }, - 'profile-settings': { - id: 'profile-settings', + 'profile/settings': { + id: 'profile/settings', text: 'Preferences', icon: 'sliders-v-alt', url: '/profile', - parentItem: { - id: 'profile', - text: 'admin', - section: NavSection.Config, - img: '/avatar/46d229b033af06a191ff2267bca9ae56', - url: '/profile', - sortWeight: -1100, - children: [ - { - id: 'profile-settings', - text: 'Preferences', - icon: 'sliders-v-alt', - url: '/profile', - }, - { - id: 'notifications', - text: 'Notification history', - icon: 'bell', - url: '/notifications', - }, - { - id: 'change-password', - text: 'Change password', - icon: 'lock', - url: '/profile/password', - }, - { - id: 'sign-out', - text: 'Sign out', - icon: 'arrow-from-right', - url: '/logout', - target: '_self', - hideFromTabs: true, - }, - ], - }, }, - notifications: { - id: 'notifications', + 'profile/notifications': { + id: 'profile/notifications', text: 'Notification history', icon: 'bell', - url: '/notifications', - parentItem: { - id: 'profile', - text: 'admin', - section: NavSection.Config, - img: '/avatar/46d229b033af06a191ff2267bca9ae56', - url: '/profile', - sortWeight: -1100, - children: [ - { - id: 'profile-settings', - text: 'Preferences', - icon: 'sliders-v-alt', - url: '/profile', - }, - { - id: 'notifications', - text: 'Notification history', - icon: 'bell', - url: '/notifications', - }, - { - id: 'change-password', - text: 'Change password', - icon: 'lock', - url: '/profile/password', - }, - { - id: 'sign-out', - text: 'Sign out', - icon: 'arrow-from-right', - url: '/logout', - target: '_self', - hideFromTabs: true, - }, - ], - }, + url: '/profile/notifications', }, - 'change-password': { - id: 'change-password', + 'profile/password': { + id: 'profile/password', text: 'Change password', icon: 'lock', url: '/profile/password', - parentItem: { - id: 'profile', - text: 'admin', - section: NavSection.Config, - img: '/avatar/46d229b033af06a191ff2267bca9ae56', - url: '/profile', - sortWeight: -1100, - children: [ - { - id: 'profile-settings', - text: 'Preferences', - icon: 'sliders-v-alt', - url: '/profile', - }, - { - id: 'notifications', - text: 'Notification history', - icon: 'bell', - url: '/notifications', - }, - { - id: 'change-password', - text: 'Change password', - icon: 'lock', - url: '/profile/password', - }, - { - id: 'sign-out', - text: 'Sign out', - icon: 'arrow-from-right', - url: '/logout', - target: '_self', - hideFromTabs: true, - }, - ], - }, }, 'sign-out': { id: 'sign-out', @@ -2456,50 +1164,22 @@ export const navIndex: NavIndex = { url: '/logout', target: '_self', hideFromTabs: true, - parentItem: { - id: 'profile', - text: 'admin', - section: NavSection.Config, - img: '/avatar/46d229b033af06a191ff2267bca9ae56', - url: '/profile', - sortWeight: -1100, - children: [ - { - id: 'profile-settings', - text: 'Preferences', - icon: 'sliders-v-alt', - url: '/profile', - }, - { - id: 'notifications', - text: 'Notification history', - icon: 'bell', - url: '/notifications', - }, - { - id: 'change-password', - text: 'Change password', - icon: 'lock', - url: '/profile/password', - }, - { - id: 'sign-out', - text: 'Sign out', - icon: 'arrow-from-right', - url: '/logout', - target: '_self', - hideFromTabs: true, - }, - ], - }, }, help: { id: 'help', text: 'Help', section: NavSection.Config, - subTitle: 'Grafana v9.0.0-pre (abb5c6109a)', + subTitle: 'Grafana v9.3.0-pre (8f5dc47e87)', icon: 'question-circle', url: '#', - sortWeight: -1000, + sortWeight: -500, + parentItem: { + id: 'home', + text: 'Home', + section: NavSection.Core, + icon: 'home-alt', + url: '/', + sortWeight: -2000, + }, }, }; diff --git a/public/app/features/connections/constants.ts b/public/app/features/connections/constants.ts index 98dfb78826d..561e44eed99 100644 --- a/public/app/features/connections/constants.ts +++ b/public/app/features/connections/constants.ts @@ -5,9 +5,18 @@ export const CLOUD_ONBOARDING_APP_ID = 'grafana-easystart-app'; export const ROUTE_BASE_ID = 'connections'; export const ROUTES = { - DataSources: `/${ROUTE_BASE_ID}/datasources`, - DataSourcesNew: `/${ROUTE_BASE_ID}/datasources/new`, - DataSourcesEdit: `/${ROUTE_BASE_ID}/datasources/edit/:uid`, + Base: `/${ROUTE_BASE_ID}`, + + // Your Connections + YourConnections: `/${ROUTE_BASE_ID}/your-connections`, + + // Your Connections / Datasources + DataSources: `/${ROUTE_BASE_ID}/your-connections/datasources`, + DataSourcesNew: `/${ROUTE_BASE_ID}/your-connections/datasources/new`, + DataSourcesEdit: `/${ROUTE_BASE_ID}/your-connections/datasources/edit/:uid`, DataSourcesDashboards: `/${ROUTE_BASE_ID}/datasources/edit/:uid/dashboards`, + + // Connect Data ConnectData: `/${ROUTE_BASE_ID}/connect-data`, + DataSourcesDetails: `/${ROUTE_BASE_ID}/connect-data/datasources/:id`, } as const; diff --git a/public/app/features/connections/pages/ConnectDataPage.tsx b/public/app/features/connections/pages/ConnectDataPage.tsx new file mode 100644 index 00000000000..ef8a25d8dbf --- /dev/null +++ b/public/app/features/connections/pages/ConnectDataPage.tsx @@ -0,0 +1,15 @@ +import * as React from 'react'; + +import { Page } from 'app/core/components/Page/Page'; + +import { ConnectData } from '../tabs/ConnectData'; + +export function ConnectDataPage() { + return ( + + + + + + ); +} diff --git a/public/app/features/connections/pages/DataSourceDetailsPage.tsx b/public/app/features/connections/pages/DataSourceDetailsPage.tsx new file mode 100644 index 00000000000..e39e0cafb8e --- /dev/null +++ b/public/app/features/connections/pages/DataSourceDetailsPage.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; + +import { Page } from 'app/core/components/Page/Page'; +import { StoreState, useSelector } from 'app/types'; + +export function DataSourceDetailsPage() { + const overrideNavId = 'standalone-plugin-page-/connections/connect-data'; + const navIndex = useSelector((state: StoreState) => state.navIndex); + const isConnectDataPageOverriden = Boolean(navIndex[overrideNavId]); + const navId = isConnectDataPageOverriden ? overrideNavId : 'connections-connect-data'; // The nav id changes (gets a prefix) if it is overriden by a plugin + + return ( + + Data Source Details (no exposed component from plugins yet) + + ); +} diff --git a/public/app/features/connections/pages/DataSourcesListPage.tsx b/public/app/features/connections/pages/DataSourcesListPage.tsx new file mode 100644 index 00000000000..518cc4c39db --- /dev/null +++ b/public/app/features/connections/pages/DataSourcesListPage.tsx @@ -0,0 +1,14 @@ +import * as React from 'react'; + +import { Page } from 'app/core/components/Page/Page'; +import { DataSourcesList } from 'app/features/datasources/components/DataSourcesList'; + +export function DataSourcesListPage() { + return ( + + + + + + ); +} diff --git a/public/app/features/connections/pages/EditDataSourcePage.tsx b/public/app/features/connections/pages/EditDataSourcePage.tsx new file mode 100644 index 00000000000..9dcad3fe006 --- /dev/null +++ b/public/app/features/connections/pages/EditDataSourcePage.tsx @@ -0,0 +1,27 @@ +import * as React from 'react'; +import { useLocation, useParams } from 'react-router-dom'; + +import { Page } from 'app/core/components/Page/Page'; +import { EditDataSource } from 'app/features/datasources/components/EditDataSource'; +import { useDataSource } from 'app/features/datasources/state/hooks'; +import { useGetSingle } from 'app/features/plugins/admin/state/hooks'; + +export function EditDataSourcePage() { + const { uid } = useParams<{ uid: string }>(); + const location = useLocation(); + const datasource = useDataSource(uid); + const datasourcePlugin = useGetSingle(datasource.type); + const params = new URLSearchParams(location.search); + const pageId = params.get('page'); + + return ( + + + + + + ); +} diff --git a/public/app/features/connections/pages/NewDataSourcePage.tsx b/public/app/features/connections/pages/NewDataSourcePage.tsx new file mode 100644 index 00000000000..08c659004e2 --- /dev/null +++ b/public/app/features/connections/pages/NewDataSourcePage.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; + +import { Page } from 'app/core/components/Page/Page'; +import { NewDataSource } from 'app/features/datasources/components/NewDataSource'; + +export function NewDataSourcePage() { + return ( + + + + + + ); +} diff --git a/public/app/features/connections/pages/index.tsx b/public/app/features/connections/pages/index.tsx new file mode 100644 index 00000000000..43dbb2aa8fa --- /dev/null +++ b/public/app/features/connections/pages/index.tsx @@ -0,0 +1,5 @@ +export { ConnectDataPage } from './ConnectDataPage'; +export { DataSourceDetailsPage } from './DataSourceDetailsPage'; +export { DataSourcesListPage } from './DataSourcesListPage'; +export { EditDataSourcePage } from './EditDataSourcePage'; +export { NewDataSourcePage } from './NewDataSourcePage'; diff --git a/public/app/features/connections/routes.tsx b/public/app/features/connections/routes.tsx index db117d9a784..8ce7dca5ad7 100644 --- a/public/app/features/connections/routes.tsx +++ b/public/app/features/connections/routes.tsx @@ -11,7 +11,7 @@ export function getRoutes(): RouteDescriptor[] { path: `/${ROUTE_BASE_ID}`, exact: false, component: SafeDynamicImport( - () => import(/* webpackChunkName: "DataConnectionsPage"*/ 'app/features/connections/ConnectionsPage') + () => import(/* webpackChunkName: "Connections"*/ 'app/features/connections/Connections') ), }, ]; diff --git a/public/app/features/connections/tabs/ConnectData/ConnectData.tsx b/public/app/features/connections/tabs/ConnectData/ConnectData.tsx index 24d45059ec0..7507a66229f 100644 --- a/public/app/features/connections/tabs/ConnectData/ConnectData.tsx +++ b/public/app/features/connections/tabs/ConnectData/ConnectData.tsx @@ -4,6 +4,8 @@ import React, { useMemo, useState } from 'react'; import { useStyles2, LoadingPlaceholder } from '@grafana/ui'; import { useGetAllWithFilters } from 'app/features/plugins/admin/state/hooks'; +import { ROUTES } from '../../constants'; + import { CardGrid } from './CardGrid'; import { CategoryHeader } from './CategoryHeader'; import { NoResults } from './NoResults'; @@ -31,7 +33,7 @@ export function ConnectData() { id: plugin.id, name: plugin.name, logo: plugin.info.logos.small, - url: `plugins/${plugin.id}`, + url: ROUTES.DataSourcesDetails.replace(':id', plugin.id), })), [plugins] ); diff --git a/public/app/features/connections/tabs/DataSourcesEdit/DataSourcesEdit.tsx b/public/app/features/connections/tabs/DataSourcesEdit/DataSourcesEdit.tsx deleted file mode 100644 index 44e589c7cdf..00000000000 --- a/public/app/features/connections/tabs/DataSourcesEdit/DataSourcesEdit.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; - -import { GrafanaRouteComponentProps } from 'app/core/navigation/types'; -import { EditDataSource } from 'app/features/datasources/components/EditDataSource'; - -export interface Props extends GrafanaRouteComponentProps<{ uid: string }> {} - -export function DataSourcesEdit(props: Props) { - const uid = props.match.params.uid; - const params = new URLSearchParams(props.location.search); - const pageId = params.get('page'); - - return ; -} diff --git a/public/app/features/connections/tabs/DataSourcesEdit/index.tsx b/public/app/features/connections/tabs/DataSourcesEdit/index.tsx deleted file mode 100644 index 081617892e3..00000000000 --- a/public/app/features/connections/tabs/DataSourcesEdit/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './DataSourcesEdit';