diff --git a/pkg/api/index.go b/pkg/api/index.go index 966f6af846d..db692c272f6 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -166,7 +166,7 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV hs.HooksService.RunIndexDataHooks(&data, c) - data.NavTree.ApplyAdminIA() + data.NavTree.ApplyAdminIA(hs.Cfg.IsFeatureToggleEnabled(featuremgmt.FlagNavAdminSubsections)) data.NavTree.Sort() return &data, nil diff --git a/pkg/services/navtree/models.go b/pkg/services/navtree/models.go index 8b2e7e9c746..1054d87802e 100644 --- a/pkg/services/navtree/models.go +++ b/pkg/services/navtree/models.go @@ -38,6 +38,9 @@ const ( NavIDMonitoring = "monitoring" NavIDReporting = "reports" NavIDApps = "apps" + NavIDCfgGeneral = "cfg/general" + NavIDCfgPlugins = "cfg/plugins" + NavIDCfgAccess = "cfg/access" ) type NavLink struct { @@ -115,33 +118,103 @@ func Sort(nodes []*NavLink) { } } -func (root *NavTreeRoot) ApplyAdminIA() { +func (root *NavTreeRoot) ApplyAdminIA(navAdminSubsectionsEnabled bool) { orgAdminNode := root.FindById(NavIDCfg) if orgAdminNode != nil { adminNodeLinks := []*NavLink{} - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("datasources")) - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("plugins")) - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("global-users")) - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("teams")) - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("serviceaccounts")) - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("apikeys")) - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("org-settings")) - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("authentication")) - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("server-settings")) - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("global-orgs")) - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("feature-toggles")) + if navAdminSubsectionsEnabled { + generalNodeLinks := []*NavLink{} + generalNodeLinks = AppendIfNotNil(generalNodeLinks, root.FindById("upgrading")) // TODO does this even exist + generalNodeLinks = AppendIfNotNil(generalNodeLinks, root.FindById("licensing")) + generalNodeLinks = AppendIfNotNil(generalNodeLinks, root.FindById("org-settings")) + generalNodeLinks = AppendIfNotNil(generalNodeLinks, root.FindById("server-settings")) + generalNodeLinks = AppendIfNotNil(generalNodeLinks, root.FindById("global-orgs")) + generalNodeLinks = AppendIfNotNil(generalNodeLinks, root.FindById("feature-toggles")) + generalNodeLinks = AppendIfNotNil(generalNodeLinks, root.FindById("storage")) - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("upgrading")) - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("licensing")) - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("recordedQueries")) // enterprise only - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("correlations")) - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("plugin-page-grafana-cloud-link-app")) + generalNode := &NavLink{ + Text: "General", + SubTitle: "Manage default preferences and settings across Grafana", + Id: NavIDCfgGeneral, + Url: "/admin/general", + Icon: "shield", + Children: generalNodeLinks, + } - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("ldap")) - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("standalone-plugin-page-/a/grafana-auth-app")) // Cloud Access Policies - adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("storage")) + pluginsNodeLinks := []*NavLink{} + pluginsNodeLinks = AppendIfNotNil(pluginsNodeLinks, root.FindById("plugins")) + pluginsNodeLinks = AppendIfNotNil(pluginsNodeLinks, root.FindById("datasources")) + pluginsNodeLinks = AppendIfNotNil(pluginsNodeLinks, root.FindById("recordedQueries")) + pluginsNodeLinks = AppendIfNotNil(pluginsNodeLinks, root.FindById("correlations")) + pluginsNodeLinks = AppendIfNotNil(pluginsNodeLinks, root.FindById("plugin-page-grafana-cloud-link-app")) + + pluginsNode := &NavLink{ + Text: "Plugins and data", + SubTitle: "Install plugins and define the relationships between data", + Id: NavIDCfgPlugins, + Url: "/admin/plugins", + Icon: "shield", + Children: pluginsNodeLinks, + } + + accessNodeLinks := []*NavLink{} + accessNodeLinks = AppendIfNotNil(accessNodeLinks, root.FindById("global-users")) + accessNodeLinks = AppendIfNotNil(accessNodeLinks, root.FindById("teams")) + accessNodeLinks = AppendIfNotNil(accessNodeLinks, root.FindById("standalone-plugin-page-/a/grafana-auth-app")) + accessNodeLinks = AppendIfNotNil(accessNodeLinks, root.FindById("serviceaccounts")) + accessNodeLinks = AppendIfNotNil(accessNodeLinks, root.FindById("apikeys")) + + usersNode := &NavLink{ + Text: "Users and access", + SubTitle: "Configure access for individual users, teams, and service accounts", + Id: NavIDCfgAccess, + Url: "/admin/access", + Icon: "shield", + Children: accessNodeLinks, + } + + if len(generalNode.Children) > 0 { + adminNodeLinks = append(adminNodeLinks, generalNode) + } + + if len(pluginsNode.Children) > 0 { + adminNodeLinks = append(adminNodeLinks, pluginsNode) + } + + if len(usersNode.Children) > 0 { + adminNodeLinks = append(adminNodeLinks, usersNode) + } + + authenticationNode := root.FindById("authentication") + if authenticationNode != nil { + authenticationNode.IsSection = true + adminNodeLinks = append(adminNodeLinks, authenticationNode) + } + } else { + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("datasources")) + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("plugins")) + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("global-users")) + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("teams")) + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("serviceaccounts")) + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("apikeys")) + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("org-settings")) + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("authentication")) + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("server-settings")) + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("global-orgs")) + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("feature-toggles")) + + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("upgrading")) + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("licensing")) + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("recordedQueries")) // enterprise only + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("correlations")) + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("plugin-page-grafana-cloud-link-app")) + + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("ldap")) + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("standalone-plugin-page-/a/grafana-auth-app")) // Cloud Access Policies + adminNodeLinks = AppendIfNotNil(adminNodeLinks, root.FindById("storage")) + } if len(adminNodeLinks) > 0 { orgAdminNode.Children = adminNodeLinks diff --git a/public/app/core/utils/navBarItem-translations.ts b/public/app/core/utils/navBarItem-translations.ts index 48f5e3d493f..2c08370ad4f 100644 --- a/public/app/core/utils/navBarItem-translations.ts +++ b/public/app/core/utils/navBarItem-translations.ts @@ -74,6 +74,12 @@ export function getNavTitle(navId: string | undefined) { return t('nav.alerting-admin.title', 'Admin'); case 'cfg': return t('nav.config.title', 'Administration'); + case 'cfg/general': + return t('nav.config-general.title', 'General'); + case 'cfg/plugins': + return t('nav.config-plugins.title', 'Plugins and data'); + case 'cfg/access': + return t('nav.config-access.title', 'Users and access'); case 'datasources': return t('nav.datasources.title', 'Data sources'); case 'authentication': @@ -230,6 +236,12 @@ export function getNavSubTitle(navId: string | undefined) { 'nav.admin.subtitle', 'Manage server-wide settings and access to resources such as organizations, users, and licenses' ); + case 'cfg/general': + return t('nav.config-general.subtitle', 'Manage default preferences and settings across Grafana'); + case 'cfg/plugins': + return t('nav.config-plugins.subtitle', 'Install plugins and define the relationships between data'); + case 'cfg/access': + return t('nav.config-access.subtitle', 'Configure access for individual users, teams, and service accounts'); case 'apps': return t('nav.apps.subtitle', 'App plugins that extend the Grafana experience'); case 'monitoring': diff --git a/public/app/routes/routes.tsx b/public/app/routes/routes.tsx index dce15c3584e..b46e9e8f86d 100644 --- a/public/app/routes/routes.tsx +++ b/public/app/routes/routes.tsx @@ -197,15 +197,15 @@ export function getAppRoutes(): RouteDescriptor[] { }, { path: '/admin/general', - component: () => , + component: () => , }, { path: '/admin/plugins', - component: () => , + component: () => , }, { path: '/admin/access', - component: () => , + component: () => , }, { path: '/org', @@ -295,14 +295,6 @@ export function getAppRoutes(): RouteDescriptor[] { ) : () => , }, - { - path: '/admin/access', - component: () => , - }, - { - path: '/admin/config', - component: () => , - }, { path: '/admin/settings', component: SafeDynamicImport( diff --git a/public/locales/de-DE/grafana.json b/public/locales/de-DE/grafana.json index 61e16dbea00..9f6aa35d392 100644 --- a/public/locales/de-DE/grafana.json +++ b/public/locales/de-DE/grafana.json @@ -517,6 +517,18 @@ "config": { "title": "Verwaltung" }, + "config-access": { + "subtitle": "", + "title": "" + }, + "config-general": { + "subtitle": "", + "title": "" + }, + "config-plugins": { + "subtitle": "", + "title": "" + }, "connect-data": { "title": "" }, diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 601a0ea8b87..40f90682684 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -517,6 +517,18 @@ "config": { "title": "Administration" }, + "config-access": { + "subtitle": "Configure access for individual users, teams, and service accounts", + "title": "Users and access" + }, + "config-general": { + "subtitle": "Manage default preferences and settings across Grafana", + "title": "General" + }, + "config-plugins": { + "subtitle": "Install plugins and define the relationships between data", + "title": "Plugins and data" + }, "connect-data": { "title": "Connect data" }, diff --git a/public/locales/es-ES/grafana.json b/public/locales/es-ES/grafana.json index 671d2059313..0fa848259d1 100644 --- a/public/locales/es-ES/grafana.json +++ b/public/locales/es-ES/grafana.json @@ -523,6 +523,18 @@ "config": { "title": "Administración" }, + "config-access": { + "subtitle": "", + "title": "" + }, + "config-general": { + "subtitle": "", + "title": "" + }, + "config-plugins": { + "subtitle": "", + "title": "" + }, "connect-data": { "title": "" }, diff --git a/public/locales/fr-FR/grafana.json b/public/locales/fr-FR/grafana.json index 48997a11644..13a678be1b2 100644 --- a/public/locales/fr-FR/grafana.json +++ b/public/locales/fr-FR/grafana.json @@ -523,6 +523,18 @@ "config": { "title": "Administration" }, + "config-access": { + "subtitle": "", + "title": "" + }, + "config-general": { + "subtitle": "", + "title": "" + }, + "config-plugins": { + "subtitle": "", + "title": "" + }, "connect-data": { "title": "" }, diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json index 5af63ced102..12d900228c1 100644 --- a/public/locales/pseudo-LOCALE/grafana.json +++ b/public/locales/pseudo-LOCALE/grafana.json @@ -517,6 +517,18 @@ "config": { "title": "Åđmįʼnįşŧřäŧįőʼn" }, + "config-access": { + "subtitle": "Cőʼnƒįģūřę äččęşş ƒőř įʼnđįvįđūäľ ūşęřş, ŧęämş, äʼnđ şęřvįčę äččőūʼnŧş", + "title": "Ůşęřş äʼnđ äččęşş" + }, + "config-general": { + "subtitle": "Mäʼnäģę đęƒäūľŧ přęƒęřęʼnčęş äʼnđ şęŧŧįʼnģş äčřőşş Ğřäƒäʼnä", + "title": "Ğęʼnęřäľ" + }, + "config-plugins": { + "subtitle": "Ĩʼnşŧäľľ pľūģįʼnş äʼnđ đęƒįʼnę ŧĥę řęľäŧįőʼnşĥįpş þęŧŵęęʼn đäŧä", + "title": "Pľūģįʼnş äʼnđ đäŧä" + }, "connect-data": { "title": "Cőʼnʼnęčŧ đäŧä" }, diff --git a/public/locales/zh-Hans/grafana.json b/public/locales/zh-Hans/grafana.json index 23bfbaee5cb..27adff77cae 100644 --- a/public/locales/zh-Hans/grafana.json +++ b/public/locales/zh-Hans/grafana.json @@ -511,6 +511,18 @@ "config": { "title": "管理" }, + "config-access": { + "subtitle": "", + "title": "" + }, + "config-general": { + "subtitle": "", + "title": "" + }, + "config-plugins": { + "subtitle": "", + "title": "" + }, "connect-data": { "title": "" },