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": ""
},