From 366731d8d9473384f68d553d2884759aed570b2d Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Fri, 23 Sep 2022 16:08:08 +0100 Subject: [PATCH] Navigation: Add descriptions to NavModelItems (#55669) * add some descriptions! * Update some descriptions * Tweak playlist description * fix unit tests + betterer --- pkg/services/navtree/models.go | 1 + pkg/services/navtree/navtreeimpl/admin.go | 12 +-- pkg/services/navtree/navtreeimpl/navtree.go | 85 ++++++++++--------- .../AppChrome/NavLandingPage.test.tsx | 6 +- .../components/AppChrome/NavLandingPage.tsx | 2 +- .../core/components/PageNew/PageHeader.tsx | 2 +- .../app/features/admin/AdminListOrgsPage.tsx | 2 +- .../app/features/admin/UserListAdminPage.tsx | 2 +- public/app/features/api-keys/ApiKeysPage.tsx | 1 - 9 files changed, 59 insertions(+), 54 deletions(-) diff --git a/pkg/services/navtree/models.go b/pkg/services/navtree/models.go index 6b86780b342..7bad049b31a 100644 --- a/pkg/services/navtree/models.go +++ b/pkg/services/navtree/models.go @@ -58,6 +58,7 @@ func GetServerAdminNode(children []*NavLink) *NavLink { return &NavLink{ Text: "Server admin", SubTitle: "Manage all users and orgs", + Description: "Manage server-wide settings and access to resources such as organizations, users, and licenses", HideFromTabs: true, Id: "admin", Icon: "shield", diff --git a/pkg/services/navtree/navtreeimpl/admin.go b/pkg/services/navtree/navtreeimpl/admin.go index 612e8632b51..a86ed5bae94 100644 --- a/pkg/services/navtree/navtreeimpl/admin.go +++ b/pkg/services/navtree/navtreeimpl/admin.go @@ -40,7 +40,7 @@ func (s *ServiceImpl) setupConfigNodes(c *models.ReqContext) ([]*navtree.NavLink configNodes = append(configNodes, &navtree.NavLink{ Text: "Users", Id: "users", - Description: "Manage org members", + Description: "Invite and assign roles to users", Icon: "user", Url: s.cfg.AppSubURL + "/org/users", }) @@ -50,7 +50,7 @@ func (s *ServiceImpl) setupConfigNodes(c *models.ReqContext) ([]*navtree.NavLink configNodes = append(configNodes, &navtree.NavLink{ Text: "Teams", Id: "teams", - Description: "Manage org groups", + Description: "Groups of users that have common dashboard and permission needs", Icon: "users-alt", Url: s.cfg.AppSubURL + "/org/teams", }) @@ -61,7 +61,7 @@ func (s *ServiceImpl) setupConfigNodes(c *models.ReqContext) ([]*navtree.NavLink configNodes = append(configNodes, &navtree.NavLink{ Text: "Plugins", Id: "plugins", - Description: "View and configure plugins", + Description: "Extend the Grafana experience with plugins", Icon: "plug", Url: s.cfg.AppSubURL + "/plugins", }) @@ -71,7 +71,7 @@ func (s *ServiceImpl) setupConfigNodes(c *models.ReqContext) ([]*navtree.NavLink configNodes = append(configNodes, &navtree.NavLink{ Text: "Preferences", Id: "org-settings", - Description: "Organization preferences", + Description: "Manage preferences across an organization", Icon: "sliders-v-alt", Url: s.cfg.AppSubURL + "/org", }) @@ -88,7 +88,7 @@ func (s *ServiceImpl) setupConfigNodes(c *models.ReqContext) ([]*navtree.NavLink configNodes = append(configNodes, &navtree.NavLink{ Text: "API keys", Id: "apikeys", - Description: "Create & manage API keys", + Description: "Manage and create API keys that are used to interact with Grafana HTTP APIs", Icon: "key-skeleton-alt", Url: s.cfg.AppSubURL + "/org/apikeys", }) @@ -98,7 +98,7 @@ func (s *ServiceImpl) setupConfigNodes(c *models.ReqContext) ([]*navtree.NavLink configNodes = append(configNodes, &navtree.NavLink{ Text: "Service accounts", Id: "serviceaccounts", - Description: "Manage service accounts", + Description: "Use service accounts to run automated workloads in Grafana", Icon: "gf-service-account", Url: s.cfg.AppSubURL + "/org/serviceaccounts", }) diff --git a/pkg/services/navtree/navtreeimpl/navtree.go b/pkg/services/navtree/navtreeimpl/navtree.go index 433bcb1cd52..839a668da52 100644 --- a/pkg/services/navtree/navtreeimpl/navtree.go +++ b/pkg/services/navtree/navtreeimpl/navtree.go @@ -77,14 +77,15 @@ func (s *ServiceImpl) GetNavTree(c *models.ReqContext, hasEditPerm bool, prefs * dashboardsUrl := "/dashboards" dashboardLink := &navtree.NavLink{ - Text: "Dashboards", - Id: "dashboards", - SubTitle: "Manage dashboards and folders", - Icon: "apps", - Url: s.cfg.AppSubURL + dashboardsUrl, - SortWeight: navtree.WeightDashboard, - Section: navtree.NavSectionCore, - Children: dashboardChildLinks, + Text: "Dashboards", + Id: "dashboards", + Description: "Create and manage dashboards to visualize your data", + SubTitle: "Manage dashboards and folders", + Icon: "apps", + Url: s.cfg.AppSubURL + dashboardsUrl, + SortWeight: navtree.WeightDashboard, + Section: navtree.NavSectionCore, + Children: dashboardChildLinks, } if s.features.IsEnabled(featuremgmt.FlagTopnav) { @@ -135,7 +136,7 @@ func (s *ServiceImpl) GetNavTree(c *models.ReqContext, hasEditPerm bool, prefs * navTree = append(navTree, &navtree.NavLink{ Text: "Apps", Icon: "apps", - Description: "App plugins", + Description: "App plugins that extend the Grafana experience", Id: "apps", Children: appLinks, Section: navtree.NavSectionCore, @@ -357,22 +358,24 @@ func (s *ServiceImpl) buildDashboardNavLinks(c *models.ReqContext, hasEditPerm b }) } dashboardChildNavs = append(dashboardChildNavs, &navtree.NavLink{ - Text: "Playlists", Id: "dashboards/playlists", Url: s.cfg.AppSubURL + "/playlists", Icon: "presentation-play", + Text: "Playlists", Description: "Groups of dashboards that are displayed in a sequence", Id: "dashboards/playlists", Url: s.cfg.AppSubURL + "/playlists", Icon: "presentation-play", }) if c.IsSignedIn { dashboardChildNavs = append(dashboardChildNavs, &navtree.NavLink{ - Text: "Snapshots", - Id: "dashboards/snapshots", - Url: s.cfg.AppSubURL + "/dashboard/snapshots", - Icon: "camera", + Text: "Snapshots", + Description: "Interactive, publically available, point-in-time representations of dashboards", + Id: "dashboards/snapshots", + Url: s.cfg.AppSubURL + "/dashboard/snapshots", + Icon: "camera", }) dashboardChildNavs = append(dashboardChildNavs, &navtree.NavLink{ - Text: "Library panels", - Id: "dashboards/library-panels", - Url: s.cfg.AppSubURL + "/library-panels", - Icon: "library-panel", + Text: "Library panels", + Description: "Reusable panels that can be added to multiple dashboards", + Id: "dashboards/library-panels", + Url: s.cfg.AppSubURL + "/library-panels", + Icon: "library-panel", }) } @@ -427,13 +430,14 @@ func (s *ServiceImpl) buildLegacyAlertNavLinks(c *models.ReqContext) []*navtree. } var alertNav = navtree.NavLink{ - Text: "Alerting", - SubTitle: "Alert rules and notifications", - Id: "alerting-legacy", - Icon: "bell", - Children: alertChildNavs, - Section: navtree.NavSectionCore, - SortWeight: navtree.WeightAlerting, + Text: "Alerting", + Description: "Learn about problems in your systems moments after they occur", + SubTitle: "Alert rules and notifications", + Id: "alerting-legacy", + Icon: "bell", + Children: alertChildNavs, + Section: navtree.NavSectionCore, + SortWeight: navtree.WeightAlerting, } if s.features.IsEnabled(featuremgmt.FlagTopnav) { @@ -451,21 +455,21 @@ func (s *ServiceImpl) buildAlertNavLinks(c *models.ReqContext, hasEditPerm bool) if hasAccess(ac.ReqViewer, ac.EvalAny(ac.EvalPermission(ac.ActionAlertingRuleRead), ac.EvalPermission(ac.ActionAlertingRuleExternalRead))) { alertChildNavs = append(alertChildNavs, &navtree.NavLink{ - Text: "Alert rules", Id: "alert-list", Url: s.cfg.AppSubURL + "/alerting/list", Icon: "list-ul", + Text: "Alert rules", Description: "Rules that determine whether an alert will fire", Id: "alert-list", Url: s.cfg.AppSubURL + "/alerting/list", Icon: "list-ul", }) } if hasAccess(ac.ReqOrgAdminOrEditor, ac.EvalAny(ac.EvalPermission(ac.ActionAlertingNotificationsRead), ac.EvalPermission(ac.ActionAlertingNotificationsExternalRead))) { alertChildNavs = append(alertChildNavs, &navtree.NavLink{ - Text: "Contact points", Id: "receivers", Url: s.cfg.AppSubURL + "/alerting/notifications", + Text: "Contact points", Description: "Decide how your contacts are notified when an alert fires", Id: "receivers", Url: s.cfg.AppSubURL + "/alerting/notifications", Icon: "comment-alt-share", SubTitle: "Manage the settings of your contact points", }) - alertChildNavs = append(alertChildNavs, &navtree.NavLink{Text: "Notification policies", Id: "am-routes", Url: s.cfg.AppSubURL + "/alerting/routes", Icon: "sitemap"}) + alertChildNavs = append(alertChildNavs, &navtree.NavLink{Text: "Notification policies", Description: "Determine how alerts are routed to contact points", Id: "am-routes", Url: s.cfg.AppSubURL + "/alerting/routes", Icon: "sitemap"}) } if hasAccess(ac.ReqViewer, ac.EvalAny(ac.EvalPermission(ac.ActionAlertingInstanceRead), ac.EvalPermission(ac.ActionAlertingInstancesExternalRead))) { - alertChildNavs = append(alertChildNavs, &navtree.NavLink{Text: "Silences", Id: "silences", Url: s.cfg.AppSubURL + "/alerting/silences", Icon: "bell-slash"}) - alertChildNavs = append(alertChildNavs, &navtree.NavLink{Text: "Alert groups", Id: "groups", Url: s.cfg.AppSubURL + "/alerting/groups", Icon: "layer-group"}) + alertChildNavs = append(alertChildNavs, &navtree.NavLink{Text: "Silences", Description: "Stop notifications from one or more alerting rules", Id: "silences", Url: s.cfg.AppSubURL + "/alerting/silences", Icon: "bell-slash"}) + alertChildNavs = append(alertChildNavs, &navtree.NavLink{Text: "Alert groups", Description: "See grouped alerts from an Alertmanager instance", Id: "groups", Url: s.cfg.AppSubURL + "/alerting/groups", Icon: "layer-group"}) } if c.OrgRole == org.RoleAdmin { @@ -490,13 +494,14 @@ func (s *ServiceImpl) buildAlertNavLinks(c *models.ReqContext, hasEditPerm bool) if len(alertChildNavs) > 0 { var alertNav = navtree.NavLink{ - Text: "Alerting", - SubTitle: "Alert rules and notifications", - Id: "alerting", - Icon: "bell", - Children: alertChildNavs, - Section: navtree.NavSectionCore, - SortWeight: navtree.WeightAlerting, + Text: "Alerting", + Description: "Learn about problems in your systems moments after they occur", + SubTitle: "Alert rules and notifications", + Id: "alerting", + Icon: "bell", + Children: alertChildNavs, + Section: navtree.NavSectionCore, + SortWeight: navtree.WeightAlerting, } if s.features.IsEnabled(featuremgmt.FlagTopnav) { @@ -562,19 +567,19 @@ func (s *ServiceImpl) buildAdminNavLinks(c *models.ReqContext) []*navtree.NavLin if hasAccess(ac.ReqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersRead, ac.ScopeGlobalUsersAll)) { adminNavLinks = append(adminNavLinks, &navtree.NavLink{ - Text: "Users", Id: "global-users", Url: s.cfg.AppSubURL + "/admin/users", Icon: "user", + Text: "Users", Description: "Manage and create users across the whole Grafana server", Id: "global-users", Url: s.cfg.AppSubURL + "/admin/users", Icon: "user", }) } if hasGlobalAccess(ac.ReqGrafanaAdmin, orgsAccessEvaluator) { adminNavLinks = append(adminNavLinks, &navtree.NavLink{ - Text: "Orgs", Id: "global-orgs", Url: s.cfg.AppSubURL + "/admin/orgs", Icon: "building", + Text: "Organizations", Description: "Isolated instances of Grafana running on the same server", Id: "global-orgs", Url: s.cfg.AppSubURL + "/admin/orgs", Icon: "building", }) } if hasAccess(ac.ReqGrafanaAdmin, ac.EvalPermission(ac.ActionSettingsRead)) { adminNavLinks = append(adminNavLinks, &navtree.NavLink{ - Text: "Settings", Id: "server-settings", Url: s.cfg.AppSubURL + "/admin/settings", Icon: "sliders-v-alt", + Text: "Settings", Description: "View the settings defined in your Grafana config", Id: "server-settings", Url: s.cfg.AppSubURL + "/admin/settings", Icon: "sliders-v-alt", }) } diff --git a/public/app/core/components/AppChrome/NavLandingPage.test.tsx b/public/app/core/components/AppChrome/NavLandingPage.test.tsx index 850a61fe8b2..e773e879ca3 100644 --- a/public/app/core/components/AppChrome/NavLandingPage.test.tsx +++ b/public/app/core/components/AppChrome/NavLandingPage.test.tsx @@ -27,7 +27,7 @@ describe('NavLandingPage', () => { const mockChild3 = { text: 'Child 3', id: 'child3', - subTitle: 'Child 3 subtitle', + description: 'Child 3 subtitle', url: 'mock-section-url/child3', hideFromTabs: true, children: [ @@ -86,9 +86,9 @@ describe('NavLandingPage', () => { expect(screen.getByRole('heading', { name: mockChild3.text })).toBeInTheDocument(); }); - it('renders the subTitle for a nested section', () => { + it('renders the description for a nested section', () => { setup(); - expect(screen.getByText(mockChild3.subTitle)).toBeInTheDocument(); + expect(screen.getByText(mockChild3.description)).toBeInTheDocument(); }); it('renders a link for a nested child', () => { diff --git a/public/app/core/components/AppChrome/NavLandingPage.tsx b/public/app/core/components/AppChrome/NavLandingPage.tsx index 12c0c34ba65..38298cf665f 100644 --- a/public/app/core/components/AppChrome/NavLandingPage.tsx +++ b/public/app/core/components/AppChrome/NavLandingPage.tsx @@ -40,7 +40,7 @@ export function NavLandingPage({ navId }: Props) {

{child.text}

-
{child.subTitle}
+
{child.description}
{child.children?.map((child) => ( diff --git a/public/app/features/admin/AdminListOrgsPage.tsx b/public/app/features/admin/AdminListOrgsPage.tsx index 2573ebbed9c..da5fe17d823 100644 --- a/public/app/features/admin/AdminListOrgsPage.tsx +++ b/public/app/features/admin/AdminListOrgsPage.tsx @@ -30,7 +30,7 @@ export default function AdminListOrgsPages() { }, [fetchOrgs]); return ( - + <>
diff --git a/public/app/features/admin/UserListAdminPage.tsx b/public/app/features/admin/UserListAdminPage.tsx index dc9240b7921..a4cee991c77 100644 --- a/public/app/features/admin/UserListAdminPage.tsx +++ b/public/app/features/admin/UserListAdminPage.tsx @@ -77,7 +77,7 @@ const UserListAdminPageUnConnected = ({ const showLicensedRole = useMemo(() => users.some((user) => user.licensedRole), [users]); return ( - +
diff --git a/public/app/features/api-keys/ApiKeysPage.tsx b/public/app/features/api-keys/ApiKeysPage.tsx index ccef6706904..c3030d4e2bd 100644 --- a/public/app/features/api-keys/ApiKeysPage.tsx +++ b/public/app/features/api-keys/ApiKeysPage.tsx @@ -52,7 +52,6 @@ function mapStateToProps(state: StoreState) { const defaultPageProps = { navId: 'apikeys', - subTitle: 'Manage and create API keys that are used to interact with Grafana HTTP APIs.', }; const mapDispatchToProps = {