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 <ashley.harrison@grafana.com>
This commit is contained in:
Josh Hunt 2022-11-18 15:11:59 +00:00 committed by GitHub
parent 8c72d19bcc
commit 5978dc138e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 213 additions and 44 deletions

View File

@ -41,6 +41,9 @@ const (
NavIDDashboardsBrowse = "dashboards/browse" NavIDDashboardsBrowse = "dashboards/browse"
NavIDCfg = "cfg" // NavIDCfg is the id for org configuration navigation node NavIDCfg = "cfg" // NavIDCfg is the id for org configuration navigation node
NavIDAdmin = "admin" NavIDAdmin = "admin"
NavIDAdminGeneral = "admin/general"
NavIDAdminPlugins = "admin/plugins"
NavIDAdminAccess = "admin/access"
NavIDAlertsAndIncidents = "alerts-and-incidents" NavIDAlertsAndIncidents = "alerts-and-incidents"
NavIDAlerting = "alerting" NavIDAlerting = "alerting"
NavIDMonitoring = "monitoring" NavIDMonitoring = "monitoring"
@ -111,22 +114,7 @@ func (root *NavTreeRoot) RemoveEmptySectionsAndApplyNewInformationArchitecture(t
} }
if topNavEnabled { if topNavEnabled {
orgAdminNode := root.FindById(NavIDCfg) ApplyAdminIA(root)
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)
}
}
// Move reports into dashboards // Move reports into dashboards
if reports := root.FindById(NavIDReporting); reports != nil { 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 { func FindById(nodes []*NavLink, id string) *NavLink {
for _, child := range nodes { for _, child := range nodes {
if child.Id == id { if child.Id == id {

View File

@ -33,18 +33,20 @@ func TestNavTreeRoot(t *testing.T) {
require.Equal(t, 2, len(treeRoot.Children)) 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{ treeRoot := NavTreeRoot{
Children: []*NavLink{ Children: []*NavLink{
{Id: NavIDCfg}, {Id: NavIDCfg},
{Id: NavIDAdmin, Children: []*NavLink{{Id: "child"}}}, {Id: NavIDAdmin, Children: []*NavLink{{Id: "upgrading"}, {Id: "plugins"}, {Id: "teams"}}},
}, },
} }
treeRoot.RemoveEmptySectionsAndApplyNewInformationArchitecture(true) treeRoot.RemoveEmptySectionsAndApplyNewInformationArchitecture(true)
require.Equal(t, "Administration", treeRoot.Children[0].Text) 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) { t.Run("Should move reports into Dashboards", func(t *testing.T) {

View File

@ -166,16 +166,8 @@ func (s *ServiceImpl) getServerAdminNode(c *models.ReqContext) *navtree.NavLink
Children: adminNavLinks, 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 len(adminNavLinks) > 0 {
if s.cfg.IsFeatureToggleEnabled(featuremgmt.FlagTopnav) { adminNode.Url = adminNavLinks[0].Url
adminNode.Url = s.cfg.AppSubURL + "/admin/server"
} else {
adminNode.Url = adminNavLinks[0].Url
}
} }
return adminNode return adminNode

View File

@ -262,6 +262,7 @@ func (s *ServiceImpl) readNavigationSettings() {
"grafana-incident-app": {SectionID: navtree.NavIDAlertsAndIncidents, SortWeight: 2, Text: "Incident"}, "grafana-incident-app": {SectionID: navtree.NavIDAlertsAndIncidents, SortWeight: 2, Text: "Incident"},
"grafana-ml-app": {SectionID: navtree.NavIDAlertsAndIncidents, SortWeight: 3, Text: "Machine Learning"}, "grafana-ml-app": {SectionID: navtree.NavIDAlertsAndIncidents, SortWeight: 3, Text: "Machine Learning"},
"grafana-cloud-link-app": {SectionID: navtree.NavIDCfg}, "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"}, "grafana-easystart-app": {SectionID: navtree.NavIDRoot, SortWeight: navtree.WeightSavedItems + 1, Text: "Connections"},
} }

View File

@ -69,6 +69,12 @@ export function getNavTitle(navId: string | undefined) {
return config.featureToggles.topnav return config.featureToggles.topnav
? t('nav.config.title', 'Administration') ? t('nav.config.title', 'Administration')
: t('nav.config.titleBeforeTopnav', 'Configuration'); : 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': case 'datasources':
return t('nav.datasources.title', 'Data sources'); return t('nav.datasources.title', 'Data sources');
case 'correlations': case 'correlations':
@ -80,7 +86,9 @@ export function getNavTitle(navId: string | undefined) {
case 'plugins': case 'plugins':
return t('nav.plugins.title', 'Plugins'); return t('nav.plugins.title', 'Plugins');
case 'org-settings': 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': case 'apikeys':
return t('nav.api-keys.title', 'API keys'); return t('nav.api-keys.title', 'API keys');
case 'serviceaccounts': case 'serviceaccounts':
@ -88,7 +96,9 @@ export function getNavTitle(navId: string | undefined) {
case 'admin': case 'admin':
return t('nav.admin.title', 'Server admin'); return t('nav.admin.title', 'Server admin');
case 'global-users': 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': case 'global-orgs':
return t('nav.global-orgs.title', 'Organizations'); return t('nav.global-orgs.title', 'Organizations');
case 'server-settings': case 'server-settings':

View File

@ -38,6 +38,18 @@ export function getAppRoutes(): RouteDescriptor[] {
path: '/monitoring', path: '/monitoring',
component: () => <NavLandingPage navId="monitoring" />, component: () => <NavLandingPage navId="monitoring" />,
}, },
{
path: '/admin/general',
component: () => <NavLandingPage navId="admin/general" />,
},
{
path: '/admin/plugins',
component: () => <NavLandingPage navId="admin/plugins" />,
},
{
path: '/admin/access',
component: () => <NavLandingPage navId="admin/access" />,
},
] ]
: []; : [];
@ -294,9 +306,14 @@ export function getAppRoutes(): RouteDescriptor[] {
component: () => (config.featureToggles.topnav ? <NavLandingPage navId="cfg" /> : <Redirect to="/admin/users" />), component: () => (config.featureToggles.topnav ? <NavLandingPage navId="cfg" /> : <Redirect to="/admin/users" />),
}, },
{ {
path: '/admin/server', path: '/admin/access',
component: () => component: () =>
config.featureToggles.topnav ? <NavLandingPage navId="admin" /> : <Redirect to="/admin/users" />, config.featureToggles.topnav ? <NavLandingPage navId="admin/access" /> : <Redirect to="/admin/users" />,
},
{
path: '/admin/config',
component: () =>
config.featureToggles.topnav ? <NavLandingPage navId="admin/config" /> : <Redirect to="/admin/org" />,
}, },
{ {
path: '/admin/settings', path: '/admin/settings',

View File

@ -99,6 +99,15 @@
"subtitle": "Serverweite Einstellungen und Zugriff auf Ressourcen wie Organisationen, Benutzer und Lizenzen verwalten", "subtitle": "Serverweite Einstellungen und Zugriff auf Ressourcen wie Organisationen, Benutzer und Lizenzen verwalten",
"title": "Server-Administrator" "title": "Server-Administrator"
}, },
"admin-access": {
"title": ""
},
"admin-general": {
"title": ""
},
"admin-plugins": {
"title": ""
},
"alerting": { "alerting": {
"subtitle": "Informiere dich über Probleme in deinen Systemen kurz nach deren Auftreten", "subtitle": "Informiere dich über Probleme in deinen Systemen kurz nach deren Auftreten",
"title": "Meldungen" "title": "Meldungen"
@ -184,7 +193,8 @@
}, },
"global-users": { "global-users": {
"subtitle": "Erstelle und verwalte Benutzer auf dem gesamten Grafana-Server", "subtitle": "Erstelle und verwalte Benutzer auf dem gesamten Grafana-Server",
"title": "Benutzer" "title": "Benutzer",
"titleBeforeTopnav": ""
}, },
"help": { "help": {
"title": "Hilfe" "title": "Hilfe"
@ -227,7 +237,8 @@
}, },
"org-settings": { "org-settings": {
"subtitle": "Verwalte Einstellungen in der gesamten Organisation", "subtitle": "Verwalte Einstellungen in der gesamten Organisation",
"title": "Einstellungen" "title": "Einstellungen",
"titleBeforeTopnav": ""
}, },
"playlists": { "playlists": {
"subtitle": "Gruppen von Dashboards, die in einer bestimmten Reihenfolge angezeigt werden", "subtitle": "Gruppen von Dashboards, die in einer bestimmten Reihenfolge angezeigt werden",

View File

@ -99,6 +99,15 @@
"subtitle": "Manage server-wide settings and access to resources such as organizations, users, and licenses", "subtitle": "Manage server-wide settings and access to resources such as organizations, users, and licenses",
"title": "Server admin" "title": "Server admin"
}, },
"admin-access": {
"title": "Users and access"
},
"admin-general": {
"title": "General"
},
"admin-plugins": {
"title": "Plugins and data"
},
"alerting": { "alerting": {
"subtitle": "Learn about problems in your systems moments after they occur", "subtitle": "Learn about problems in your systems moments after they occur",
"title": "Alerting" "title": "Alerting"
@ -184,7 +193,8 @@
}, },
"global-users": { "global-users": {
"subtitle": "Manage and create users across the whole Grafana server", "subtitle": "Manage and create users across the whole Grafana server",
"title": "Users" "title": "Users (All orgs)",
"titleBeforeTopnav": "Users"
}, },
"help": { "help": {
"title": "Help" "title": "Help"
@ -227,7 +237,8 @@
}, },
"org-settings": { "org-settings": {
"subtitle": "Manage preferences across an organization", "subtitle": "Manage preferences across an organization",
"title": "Preferences" "title": "Default preferences",
"titleBeforeTopnav": "Preferences"
}, },
"playlists": { "playlists": {
"subtitle": "Groups of dashboards that are displayed in a sequence", "subtitle": "Groups of dashboards that are displayed in a sequence",

View File

@ -99,6 +99,15 @@
"subtitle": "Administrar la configuración de todo el servidor y el acceso a recursos como organizaciones, usuarios y licencias", "subtitle": "Administrar la configuración de todo el servidor y el acceso a recursos como organizaciones, usuarios y licencias",
"title": "Administrador del servidor" "title": "Administrador del servidor"
}, },
"admin-access": {
"title": ""
},
"admin-general": {
"title": ""
},
"admin-plugins": {
"title": ""
},
"alerting": { "alerting": {
"subtitle": "Conozca los problemas de sus sistemas justo después de que se produzcan", "subtitle": "Conozca los problemas de sus sistemas justo después de que se produzcan",
"title": "Alertas" "title": "Alertas"
@ -184,7 +193,8 @@
}, },
"global-users": { "global-users": {
"subtitle": "Gestione y cree usuarios en todo el servidor Grafana", "subtitle": "Gestione y cree usuarios en todo el servidor Grafana",
"title": "Usuarios" "title": "Usuarios",
"titleBeforeTopnav": ""
}, },
"help": { "help": {
"title": "Ayuda" "title": "Ayuda"
@ -227,7 +237,8 @@
}, },
"org-settings": { "org-settings": {
"subtitle": "Gestionar las preferencias en una organización", "subtitle": "Gestionar las preferencias en una organización",
"title": "Preferencias" "title": "Preferencias",
"titleBeforeTopnav": ""
}, },
"playlists": { "playlists": {
"subtitle": "Grupos de paneles de control que se muestran en una secuencia", "subtitle": "Grupos de paneles de control que se muestran en una secuencia",

View File

@ -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", "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" "title": "Administrateur de serveur"
}, },
"admin-access": {
"title": ""
},
"admin-general": {
"title": ""
},
"admin-plugins": {
"title": ""
},
"alerting": { "alerting": {
"subtitle": "En savoir plus sur les problèmes dans vos systèmes quelques instants après qu'ils se produisent", "subtitle": "En savoir plus sur les problèmes dans vos systèmes quelques instants après qu'ils se produisent",
"title": "Alertes" "title": "Alertes"
@ -184,7 +193,8 @@
}, },
"global-users": { "global-users": {
"subtitle": "Gérer et créer des utilisateurs sur l'ensemble du serveur Grafana", "subtitle": "Gérer et créer des utilisateurs sur l'ensemble du serveur Grafana",
"title": "Utilisateurs" "title": "Utilisateurs",
"titleBeforeTopnav": ""
}, },
"help": { "help": {
"title": "Aide" "title": "Aide"
@ -227,7 +237,8 @@
}, },
"org-settings": { "org-settings": {
"subtitle": "Gérer les préférences au sein d'une organisation", "subtitle": "Gérer les préférences au sein d'une organisation",
"title": "Préférences" "title": "Préférences",
"titleBeforeTopnav": ""
}, },
"playlists": { "playlists": {
"subtitle": "Groupes de tableaux de bord affichés dans une séquence", "subtitle": "Groupes de tableaux de bord affichés dans une séquence",

View File

@ -99,6 +99,15 @@
"subtitle": "Mäʼnäģę şęřvęř-ŵįđę şęŧŧįʼnģş äʼnđ äččęşş ŧő řęşőūřčęş şūčĥ äş őřģäʼnįžäŧįőʼnş, ūşęřş, äʼnđ ľįčęʼnşęş", "subtitle": "Mäʼnäģę şęřvęř-ŵįđę şęŧŧįʼnģş äʼnđ äččęşş ŧő řęşőūřčęş şūčĥ äş őřģäʼnįžäŧįőʼnş, ūşęřş, äʼnđ ľįčęʼnşęş",
"title": "Ŝęřvęř äđmįʼn" "title": "Ŝęřvęř äđmįʼn"
}, },
"admin-access": {
"title": "Ůşęřş äʼnđ äččęşş"
},
"admin-general": {
"title": "Ğęʼnęřäľ"
},
"admin-plugins": {
"title": "Pľūģįʼnş äʼnđ đäŧä"
},
"alerting": { "alerting": {
"subtitle": "Ŀęäřʼn äþőūŧ přőþľęmş įʼn yőūř şyşŧęmş mőmęʼnŧş äƒŧęř ŧĥęy őččūř", "subtitle": "Ŀęäřʼn äþőūŧ přőþľęmş įʼn yőūř şyşŧęmş mőmęʼnŧş äƒŧęř ŧĥęy őččūř",
"title": "Åľęřŧįʼnģ" "title": "Åľęřŧįʼnģ"
@ -184,7 +193,8 @@
}, },
"global-users": { "global-users": {
"subtitle": "Mäʼnäģę äʼnđ čřęäŧę ūşęřş äčřőşş ŧĥę ŵĥőľę Ğřäƒäʼnä şęřvęř", "subtitle": "Mäʼnäģę äʼnđ čřęäŧę ūşęřş äčřőşş ŧĥę ŵĥőľę Ğřäƒäʼnä şęřvęř",
"title": "Ůşęřş" "title": "Ůşęřş (Åľľ őřģş)",
"titleBeforeTopnav": "Ůşęřş"
}, },
"help": { "help": {
"title": "Ħęľp" "title": "Ħęľp"
@ -227,7 +237,8 @@
}, },
"org-settings": { "org-settings": {
"subtitle": "Mäʼnäģę přęƒęřęʼnčęş äčřőşş äʼn őřģäʼnįžäŧįőʼn", "subtitle": "Mäʼnäģę přęƒęřęʼnčęş äčřőşş äʼn őřģäʼnįžäŧįőʼn",
"title": "Přęƒęřęʼnčęş" "title": "Đęƒäūľŧ přęƒęřęʼnčęş",
"titleBeforeTopnav": "Přęƒęřęʼnčęş"
}, },
"playlists": { "playlists": {
"subtitle": "Ğřőūpş őƒ đäşĥþőäřđş ŧĥäŧ äřę đįşpľäyęđ įʼn ä şęqūęʼnčę", "subtitle": "Ğřőūpş őƒ đäşĥþőäřđş ŧĥäŧ äřę đįşpľäyęđ įʼn ä şęqūęʼnčę",

View File

@ -99,6 +99,15 @@
"subtitle": "管理整个服务器范围的设置,以及对组织、用户和许可证等资源的访问权限", "subtitle": "管理整个服务器范围的设置,以及对组织、用户和许可证等资源的访问权限",
"title": "服务器管理员" "title": "服务器管理员"
}, },
"admin-access": {
"title": ""
},
"admin-general": {
"title": ""
},
"admin-plugins": {
"title": ""
},
"alerting": { "alerting": {
"subtitle": "在系统发生问题后立即获悉", "subtitle": "在系统发生问题后立即获悉",
"title": "警报" "title": "警报"
@ -184,7 +193,8 @@
}, },
"global-users": { "global-users": {
"subtitle": "在整个 Grafana 服务器上管理和创建用户", "subtitle": "在整个 Grafana 服务器上管理和创建用户",
"title": "用户" "title": "用户",
"titleBeforeTopnav": ""
}, },
"help": { "help": {
"title": "帮助" "title": "帮助"
@ -227,7 +237,8 @@
}, },
"org-settings": { "org-settings": {
"subtitle": "管理整个组织的首选项", "subtitle": "管理整个组织的首选项",
"title": "首选项" "title": "首选项",
"titleBeforeTopnav": ""
}, },
"playlists": { "playlists": {
"subtitle": "以序列显示的仪表板组", "subtitle": "以序列显示的仪表板组",