From 5978dc138ea1df9972b148cefd9866a5e7628528 Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Fri, 18 Nov 2022 15:11:59 +0000 Subject: [PATCH] Nav: Split Admin into three sections for new IA (#58229) * start to split admin into two sections * most of new admin nav implemented * landing pages * hide admin for non-admins * update admin redirects if not topnav * clean up * updated IA for admin (still WIP) * move plugin pages into correct admin sections * fix backend unit test * move correlations into the correct section * add translations for admin sections Co-authored-by: Ashley Harrison --- pkg/services/navtree/models.go | 113 +++++++++++++++--- pkg/services/navtree/models_test.go | 8 +- pkg/services/navtree/navtreeimpl/admin.go | 10 +- pkg/services/navtree/navtreeimpl/applinks.go | 1 + .../NavBar/navBarItem-translations.ts | 14 ++- public/app/routes/routes.tsx | 21 +++- public/locales/de-DE/grafana.json | 15 ++- public/locales/en-US/grafana.json | 15 ++- public/locales/es-ES/grafana.json | 15 ++- public/locales/fr-FR/grafana.json | 15 ++- public/locales/pseudo-LOCALE/grafana.json | 15 ++- public/locales/zh-Hans/grafana.json | 15 ++- 12 files changed, 213 insertions(+), 44 deletions(-) diff --git a/pkg/services/navtree/models.go b/pkg/services/navtree/models.go index 8f521be5a46..728dc6cda51 100644 --- a/pkg/services/navtree/models.go +++ b/pkg/services/navtree/models.go @@ -41,6 +41,9 @@ const ( NavIDDashboardsBrowse = "dashboards/browse" NavIDCfg = "cfg" // NavIDCfg is the id for org configuration navigation node NavIDAdmin = "admin" + NavIDAdminGeneral = "admin/general" + NavIDAdminPlugins = "admin/plugins" + NavIDAdminAccess = "admin/access" NavIDAlertsAndIncidents = "alerts-and-incidents" NavIDAlerting = "alerting" NavIDMonitoring = "monitoring" @@ -111,22 +114,7 @@ func (root *NavTreeRoot) RemoveEmptySectionsAndApplyNewInformationArchitecture(t } if topNavEnabled { - orgAdminNode := root.FindById(NavIDCfg) - - if orgAdminNode != nil { - orgAdminNode.Url = "/admin" - orgAdminNode.Text = "Administration" - } - - if serverAdminNode := root.FindById(NavIDAdmin); serverAdminNode != nil { - serverAdminNode.Url = "/admin/server" - serverAdminNode.SortWeight = 0 - - if orgAdminNode != nil { - orgAdminNode.Children = append(orgAdminNode.Children, serverAdminNode) - root.RemoveSection(serverAdminNode) - } - } + ApplyAdminIA(root) // Move reports into dashboards if reports := root.FindById(NavIDReporting); reports != nil { @@ -181,6 +169,99 @@ func Sort(nodes []*NavLink) { } } +func ApplyAdminIA(root *NavTreeRoot) { + orgAdminNode := root.FindById(NavIDCfg) + + if orgAdminNode != nil { + orgAdminNode.Url = "/admin" + orgAdminNode.Text = "Administration" + + generalNodeLinks := []*NavLink{} + pluginsNodeLinks := []*NavLink{} + accessNodeLinks := []*NavLink{} + + generalNodeLinks = AppendIfNotNil(generalNodeLinks, root.FindById("upgrading")) + if orgSettings := root.FindById("org-settings"); orgSettings != nil { + orgSettings.Text = "Default preferences" + generalNodeLinks = append(generalNodeLinks, orgSettings) + } + generalNodeLinks = AppendIfNotNil(generalNodeLinks, root.FindById("global-orgs")) + generalNodeLinks = AppendIfNotNil(generalNodeLinks, root.FindById("server-settings")) + + pluginsNodeLinks = AppendIfNotNil(pluginsNodeLinks, root.FindById("plugins")) + pluginsNodeLinks = AppendIfNotNil(pluginsNodeLinks, root.FindById("datasources")) + pluginsNodeLinks = AppendIfNotNil(pluginsNodeLinks, root.FindById("correlations")) + pluginsNodeLinks = AppendIfNotNil(pluginsNodeLinks, root.FindById("plugin-page-grafana-cloud-link-app")) + pluginsNodeLinks = AppendIfNotNil(pluginsNodeLinks, root.FindById("recordedQueries")) // enterprise only + + accessNodeLinks = AppendIfNotNil(accessNodeLinks, root.FindById("users")) + if globalUsers := root.FindById("global-users"); globalUsers != nil { + globalUsers.Text = "Users (All orgs)" + accessNodeLinks = append(accessNodeLinks, globalUsers) + } + accessNodeLinks = AppendIfNotNil(accessNodeLinks, root.FindById("teams")) + accessNodeLinks = AppendIfNotNil(accessNodeLinks, root.FindById("serviceaccounts")) + accessNodeLinks = AppendIfNotNil(accessNodeLinks, root.FindById("apikeys")) + accessNodeLinks = AppendIfNotNil(accessNodeLinks, root.FindById("plugin-page-grafana-auth-app")) // Cloud Access Policies + + generalNode := &NavLink{ + Text: "General", + Id: NavIDAdminGeneral, + Url: "/admin/general", + Icon: "shield", + Children: generalNodeLinks, + } + + pluginsNode := &NavLink{ + Text: "Plugins and data", + Id: NavIDAdminPlugins, + Url: "/admin/plugins", + Icon: "shield", + Children: pluginsNodeLinks, + } + + accessNode := &NavLink{ + Text: "Users and access", + Id: NavIDAdminAccess, + Url: "/admin/access", + Icon: "shield", + Children: accessNodeLinks, + } + + adminNodeLinks := []*NavLink{} + + if len(generalNode.Children) > 0 { + adminNodeLinks = append(adminNodeLinks, generalNode) + } + + if len(pluginsNode.Children) > 0 { + adminNodeLinks = append(adminNodeLinks, pluginsNode) + } + + if len(accessNode.Children) > 0 { + adminNodeLinks = append(adminNodeLinks, accessNode) + } + + if len(adminNodeLinks) > 0 { + orgAdminNode.Children = adminNodeLinks + } else { + root.RemoveSection(orgAdminNode) + } + } + + if serverAdminNode := root.FindById(NavIDAdmin); serverAdminNode != nil { + root.RemoveSection(serverAdminNode) + } +} + +func AppendIfNotNil(children []*NavLink, newChild *NavLink) []*NavLink { + if newChild != nil { + return append(children, newChild) + } + + return children +} + func FindById(nodes []*NavLink, id string) *NavLink { for _, child := range nodes { if child.Id == id { diff --git a/pkg/services/navtree/models_test.go b/pkg/services/navtree/models_test.go index 21cd52a8dce..66f8a01ab55 100644 --- a/pkg/services/navtree/models_test.go +++ b/pkg/services/navtree/models_test.go @@ -33,18 +33,20 @@ func TestNavTreeRoot(t *testing.T) { require.Equal(t, 2, len(treeRoot.Children)) }) - t.Run("Should move admin section into cfg and rename when topnav is enabled", func(t *testing.T) { + t.Run("Should create 3 new sections in the Admin node when topnav is enabled", func(t *testing.T) { treeRoot := NavTreeRoot{ Children: []*NavLink{ {Id: NavIDCfg}, - {Id: NavIDAdmin, Children: []*NavLink{{Id: "child"}}}, + {Id: NavIDAdmin, Children: []*NavLink{{Id: "upgrading"}, {Id: "plugins"}, {Id: "teams"}}}, }, } treeRoot.RemoveEmptySectionsAndApplyNewInformationArchitecture(true) require.Equal(t, "Administration", treeRoot.Children[0].Text) - require.Equal(t, NavIDAdmin, treeRoot.Children[0].Children[0].Id) + require.Equal(t, NavIDAdminGeneral, treeRoot.Children[0].Children[0].Id) + require.Equal(t, NavIDAdminPlugins, treeRoot.Children[0].Children[1].Id) + require.Equal(t, NavIDAdminAccess, treeRoot.Children[0].Children[2].Id) }) t.Run("Should move reports into Dashboards", func(t *testing.T) { diff --git a/pkg/services/navtree/navtreeimpl/admin.go b/pkg/services/navtree/navtreeimpl/admin.go index c024aeb7f97..7bf7a95ec46 100644 --- a/pkg/services/navtree/navtreeimpl/admin.go +++ b/pkg/services/navtree/navtreeimpl/admin.go @@ -166,16 +166,8 @@ func (s *ServiceImpl) getServerAdminNode(c *models.ReqContext) *navtree.NavLink Children: adminNavLinks, } - if s.cfg.IsFeatureToggleEnabled(featuremgmt.FlagTopnav) { - adminNode.SubTitle = "Manage server-wide settings and access to resources such as organizations, users, and licenses" - } - if len(adminNavLinks) > 0 { - if s.cfg.IsFeatureToggleEnabled(featuremgmt.FlagTopnav) { - adminNode.Url = s.cfg.AppSubURL + "/admin/server" - } else { - adminNode.Url = adminNavLinks[0].Url - } + adminNode.Url = adminNavLinks[0].Url } return adminNode diff --git a/pkg/services/navtree/navtreeimpl/applinks.go b/pkg/services/navtree/navtreeimpl/applinks.go index e59a4d6bd09..189315b8e1f 100644 --- a/pkg/services/navtree/navtreeimpl/applinks.go +++ b/pkg/services/navtree/navtreeimpl/applinks.go @@ -262,6 +262,7 @@ func (s *ServiceImpl) readNavigationSettings() { "grafana-incident-app": {SectionID: navtree.NavIDAlertsAndIncidents, SortWeight: 2, Text: "Incident"}, "grafana-ml-app": {SectionID: navtree.NavIDAlertsAndIncidents, SortWeight: 3, Text: "Machine Learning"}, "grafana-cloud-link-app": {SectionID: navtree.NavIDCfg}, + "grafana-auth-app": {SectionID: navtree.NavIDCfg}, "grafana-easystart-app": {SectionID: navtree.NavIDRoot, SortWeight: navtree.WeightSavedItems + 1, Text: "Connections"}, } diff --git a/public/app/core/components/NavBar/navBarItem-translations.ts b/public/app/core/components/NavBar/navBarItem-translations.ts index db6a018ebb4..ea674073cf7 100644 --- a/public/app/core/components/NavBar/navBarItem-translations.ts +++ b/public/app/core/components/NavBar/navBarItem-translations.ts @@ -69,6 +69,12 @@ export function getNavTitle(navId: string | undefined) { return config.featureToggles.topnav ? t('nav.config.title', 'Administration') : t('nav.config.titleBeforeTopnav', 'Configuration'); + case 'admin/general': + return t('nav.admin-general.title', 'General'); + case 'admin/plugins': + return t('nav.admin-plugins.title', 'Plugins and data'); + case 'admin/access': + return t('nav.admin-access.title', 'Users and access'); case 'datasources': return t('nav.datasources.title', 'Data sources'); case 'correlations': @@ -80,7 +86,9 @@ export function getNavTitle(navId: string | undefined) { case 'plugins': return t('nav.plugins.title', 'Plugins'); case 'org-settings': - return t('nav.org-settings.title', 'Preferences'); + return config.featureToggles.topnav + ? t('nav.org-settings.title', 'Default preferences') + : t('nav.org-settings.titleBeforeTopnav', 'Preferences'); case 'apikeys': return t('nav.api-keys.title', 'API keys'); case 'serviceaccounts': @@ -88,7 +96,9 @@ export function getNavTitle(navId: string | undefined) { case 'admin': return t('nav.admin.title', 'Server admin'); case 'global-users': - return t('nav.global-users.title', 'Users'); + return config.featureToggles.topnav + ? t('nav.global-users.title', 'Users (All orgs)') + : t('nav.global-users.titleBeforeTopnav', 'Users'); case 'global-orgs': return t('nav.global-orgs.title', 'Organizations'); case 'server-settings': diff --git a/public/app/routes/routes.tsx b/public/app/routes/routes.tsx index 17b5d38a063..9fda8c87041 100644 --- a/public/app/routes/routes.tsx +++ b/public/app/routes/routes.tsx @@ -38,6 +38,18 @@ export function getAppRoutes(): RouteDescriptor[] { path: '/monitoring', component: () => , }, + { + path: '/admin/general', + component: () => , + }, + { + path: '/admin/plugins', + component: () => , + }, + { + path: '/admin/access', + component: () => , + }, ] : []; @@ -294,9 +306,14 @@ export function getAppRoutes(): RouteDescriptor[] { component: () => (config.featureToggles.topnav ? : ), }, { - path: '/admin/server', + path: '/admin/access', component: () => - config.featureToggles.topnav ? : , + config.featureToggles.topnav ? : , + }, + { + path: '/admin/config', + component: () => + config.featureToggles.topnav ? : , }, { path: '/admin/settings', diff --git a/public/locales/de-DE/grafana.json b/public/locales/de-DE/grafana.json index 940eb77aa34..e3d9a9abaab 100644 --- a/public/locales/de-DE/grafana.json +++ b/public/locales/de-DE/grafana.json @@ -99,6 +99,15 @@ "subtitle": "Serverweite Einstellungen und Zugriff auf Ressourcen wie Organisationen, Benutzer und Lizenzen verwalten", "title": "Server-Administrator" }, + "admin-access": { + "title": "" + }, + "admin-general": { + "title": "" + }, + "admin-plugins": { + "title": "" + }, "alerting": { "subtitle": "Informiere dich über Probleme in deinen Systemen kurz nach deren Auftreten", "title": "Meldungen" @@ -184,7 +193,8 @@ }, "global-users": { "subtitle": "Erstelle und verwalte Benutzer auf dem gesamten Grafana-Server", - "title": "Benutzer" + "title": "Benutzer", + "titleBeforeTopnav": "" }, "help": { "title": "Hilfe" @@ -227,7 +237,8 @@ }, "org-settings": { "subtitle": "Verwalte Einstellungen in der gesamten Organisation", - "title": "Einstellungen" + "title": "Einstellungen", + "titleBeforeTopnav": "" }, "playlists": { "subtitle": "Gruppen von Dashboards, die in einer bestimmten Reihenfolge angezeigt werden", diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index c3d7bab249e..2a68c15a74c 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -99,6 +99,15 @@ "subtitle": "Manage server-wide settings and access to resources such as organizations, users, and licenses", "title": "Server admin" }, + "admin-access": { + "title": "Users and access" + }, + "admin-general": { + "title": "General" + }, + "admin-plugins": { + "title": "Plugins and data" + }, "alerting": { "subtitle": "Learn about problems in your systems moments after they occur", "title": "Alerting" @@ -184,7 +193,8 @@ }, "global-users": { "subtitle": "Manage and create users across the whole Grafana server", - "title": "Users" + "title": "Users (All orgs)", + "titleBeforeTopnav": "Users" }, "help": { "title": "Help" @@ -227,7 +237,8 @@ }, "org-settings": { "subtitle": "Manage preferences across an organization", - "title": "Preferences" + "title": "Default preferences", + "titleBeforeTopnav": "Preferences" }, "playlists": { "subtitle": "Groups of dashboards that are displayed in a sequence", diff --git a/public/locales/es-ES/grafana.json b/public/locales/es-ES/grafana.json index b6020ca1118..f3bd4e0cc7b 100644 --- a/public/locales/es-ES/grafana.json +++ b/public/locales/es-ES/grafana.json @@ -99,6 +99,15 @@ "subtitle": "Administrar la configuración de todo el servidor y el acceso a recursos como organizaciones, usuarios y licencias", "title": "Administrador del servidor" }, + "admin-access": { + "title": "" + }, + "admin-general": { + "title": "" + }, + "admin-plugins": { + "title": "" + }, "alerting": { "subtitle": "Conozca los problemas de sus sistemas justo después de que se produzcan", "title": "Alertas" @@ -184,7 +193,8 @@ }, "global-users": { "subtitle": "Gestione y cree usuarios en todo el servidor Grafana", - "title": "Usuarios" + "title": "Usuarios", + "titleBeforeTopnav": "" }, "help": { "title": "Ayuda" @@ -227,7 +237,8 @@ }, "org-settings": { "subtitle": "Gestionar las preferencias en una organización", - "title": "Preferencias" + "title": "Preferencias", + "titleBeforeTopnav": "" }, "playlists": { "subtitle": "Grupos de paneles de control que se muestran en una secuencia", diff --git a/public/locales/fr-FR/grafana.json b/public/locales/fr-FR/grafana.json index 50ee9d5efa8..1bcdb9254ca 100644 --- a/public/locales/fr-FR/grafana.json +++ b/public/locales/fr-FR/grafana.json @@ -99,6 +99,15 @@ "subtitle": "Gérer les paramètres à l'échelle du serveur et l'accès aux ressources telles que les organisations, les utilisateurs et les licences", "title": "Administrateur de serveur" }, + "admin-access": { + "title": "" + }, + "admin-general": { + "title": "" + }, + "admin-plugins": { + "title": "" + }, "alerting": { "subtitle": "En savoir plus sur les problèmes dans vos systèmes quelques instants après qu'ils se produisent", "title": "Alertes" @@ -184,7 +193,8 @@ }, "global-users": { "subtitle": "Gérer et créer des utilisateurs sur l'ensemble du serveur Grafana", - "title": "Utilisateurs" + "title": "Utilisateurs", + "titleBeforeTopnav": "" }, "help": { "title": "Aide" @@ -227,7 +237,8 @@ }, "org-settings": { "subtitle": "Gérer les préférences au sein d'une organisation", - "title": "Préférences" + "title": "Préférences", + "titleBeforeTopnav": "" }, "playlists": { "subtitle": "Groupes de tableaux de bord affichés dans une séquence", diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json index cef669c3987..1ec222378bf 100644 --- a/public/locales/pseudo-LOCALE/grafana.json +++ b/public/locales/pseudo-LOCALE/grafana.json @@ -99,6 +99,15 @@ "subtitle": "Mäʼnäģę şęřvęř-ŵįđę şęŧŧįʼnģş äʼnđ äččęşş ŧő řęşőūřčęş şūčĥ äş őřģäʼnįžäŧįőʼnş, ūşęřş, äʼnđ ľįčęʼnşęş", "title": "Ŝęřvęř äđmįʼn" }, + "admin-access": { + "title": "Ůşęřş äʼnđ äččęşş" + }, + "admin-general": { + "title": "Ğęʼnęřäľ" + }, + "admin-plugins": { + "title": "Pľūģįʼnş äʼnđ đäŧä" + }, "alerting": { "subtitle": "Ŀęäřʼn äþőūŧ přőþľęmş įʼn yőūř şyşŧęmş mőmęʼnŧş äƒŧęř ŧĥęy őččūř", "title": "Åľęřŧįʼnģ" @@ -184,7 +193,8 @@ }, "global-users": { "subtitle": "Mäʼnäģę äʼnđ čřęäŧę ūşęřş äčřőşş ŧĥę ŵĥőľę Ğřäƒäʼnä şęřvęř", - "title": "Ůşęřş" + "title": "Ůşęřş (Åľľ őřģş)", + "titleBeforeTopnav": "Ůşęřş" }, "help": { "title": "Ħęľp" @@ -227,7 +237,8 @@ }, "org-settings": { "subtitle": "Mäʼnäģę přęƒęřęʼnčęş äčřőşş äʼn őřģäʼnįžäŧįőʼn", - "title": "Přęƒęřęʼnčęş" + "title": "Đęƒäūľŧ přęƒęřęʼnčęş", + "titleBeforeTopnav": "Přęƒęřęʼnčęş" }, "playlists": { "subtitle": "Ğřőūpş őƒ đäşĥþőäřđş ŧĥäŧ äřę đįşpľäyęđ įʼn ä şęqūęʼnčę", diff --git a/public/locales/zh-Hans/grafana.json b/public/locales/zh-Hans/grafana.json index c1623c71043..4122d706209 100644 --- a/public/locales/zh-Hans/grafana.json +++ b/public/locales/zh-Hans/grafana.json @@ -99,6 +99,15 @@ "subtitle": "管理整个服务器范围的设置,以及对组织、用户和许可证等资源的访问权限", "title": "服务器管理员" }, + "admin-access": { + "title": "" + }, + "admin-general": { + "title": "" + }, + "admin-plugins": { + "title": "" + }, "alerting": { "subtitle": "在系统发生问题后立即获悉", "title": "警报" @@ -184,7 +193,8 @@ }, "global-users": { "subtitle": "在整个 Grafana 服务器上管理和创建用户", - "title": "用户" + "title": "用户", + "titleBeforeTopnav": "" }, "help": { "title": "帮助" @@ -227,7 +237,8 @@ }, "org-settings": { "subtitle": "管理整个组织的首选项", - "title": "首选项" + "title": "首选项", + "titleBeforeTopnav": "" }, "playlists": { "subtitle": "以序列显示的仪表板组",