mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
				
	
	
		
			284 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			284 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			Go
		
	
	
	
| package navtree
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"sort"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	// These weights may be used by an extension to reliably place
 | |
| 	// itself in relation to a particular item in the menu. The weights
 | |
| 	// are negative to ensure that the default items are placed above
 | |
| 	// any items with default weight.
 | |
| 
 | |
| 	WeightHome = (iota - 20) * 100
 | |
| 	WeightSavedItems
 | |
| 	WeightCreate
 | |
| 	WeightDashboard
 | |
| 	WeightExplore
 | |
| 	WeightAlerting
 | |
| 	WeightAlertsAndIncidents
 | |
| 	WeightMonitoring
 | |
| 	WeightDataConnections
 | |
| 	WeightApps
 | |
| 	WeightPlugin
 | |
| 	WeightConfig
 | |
| 	WeightAdmin
 | |
| 	WeightProfile
 | |
| 	WeightHelp
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	NavIDRoot               = "root"
 | |
| 	NavIDDashboards         = "dashboards/browse"
 | |
| 	NavIDCfg                = "cfg" // NavIDCfg is the id for org configuration navigation node
 | |
| 	NavIDAlertsAndIncidents = "alerts-and-incidents"
 | |
| 	NavIDAlerting           = "alerting"
 | |
| 	NavIDAlertingLegacy     = "alerting-legacy"
 | |
| 	NavIDMonitoring         = "monitoring"
 | |
| 	NavIDReporting          = "reports"
 | |
| 	NavIDApps               = "apps"
 | |
| 	NavIDCfgGeneral         = "cfg/general"
 | |
| 	NavIDCfgPlugins         = "cfg/plugins"
 | |
| 	NavIDCfgAccess          = "cfg/access"
 | |
| )
 | |
| 
 | |
| type NavLink struct {
 | |
| 	Id             string     `json:"id,omitempty"`
 | |
| 	Text           string     `json:"text"`
 | |
| 	SubTitle       string     `json:"subTitle,omitempty"`
 | |
| 	Icon           string     `json:"icon,omitempty"` // Available icons can be browsed in Storybook: https://developers.grafana.com/ui/latest/index.html?path=/story/docs-overview-icon--icons-overview
 | |
| 	Img            string     `json:"img,omitempty"`
 | |
| 	Url            string     `json:"url,omitempty"`
 | |
| 	Target         string     `json:"target,omitempty"`
 | |
| 	SortWeight     int64      `json:"sortWeight,omitempty"`
 | |
| 	HideFromTabs   bool       `json:"hideFromTabs,omitempty"`
 | |
| 	RoundIcon      bool       `json:"roundIcon,omitempty"`
 | |
| 	IsSection      bool       `json:"isSection,omitempty"`
 | |
| 	Children       []*NavLink `json:"children,omitempty"`
 | |
| 	HighlightText  string     `json:"highlightText,omitempty"`
 | |
| 	HighlightID    string     `json:"highlightId,omitempty"`
 | |
| 	EmptyMessageId string     `json:"emptyMessageId,omitempty"`
 | |
| 	PluginID       string     `json:"pluginId,omitempty"` // (Optional) The ID of the plugin that registered nav link (e.g. as a standalone plugin page)
 | |
| 	IsCreateAction bool       `json:"isCreateAction,omitempty"`
 | |
| }
 | |
| 
 | |
| func (node *NavLink) Sort() {
 | |
| 	Sort(node.Children)
 | |
| }
 | |
| 
 | |
| type NavTreeRoot struct {
 | |
| 	Children []*NavLink
 | |
| }
 | |
| 
 | |
| func (root *NavTreeRoot) AddSection(node *NavLink) {
 | |
| 	root.Children = append(root.Children, node)
 | |
| }
 | |
| 
 | |
| func (root *NavTreeRoot) RemoveSection(node *NavLink) {
 | |
| 	var result []*NavLink
 | |
| 
 | |
| 	for _, child := range root.Children {
 | |
| 		if child != node {
 | |
| 			result = append(result, child)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	root.Children = result
 | |
| }
 | |
| 
 | |
| func (root *NavTreeRoot) FindById(id string) *NavLink {
 | |
| 	return FindById(root.Children, id)
 | |
| }
 | |
| func (root *NavTreeRoot) FindByURL(url string) *NavLink {
 | |
| 	return FindByURL(root.Children, url)
 | |
| }
 | |
| func (root *NavTreeRoot) Sort() {
 | |
| 	Sort(root.Children)
 | |
| }
 | |
| 
 | |
| func (root *NavTreeRoot) MarshalJSON() ([]byte, error) {
 | |
| 	return json.Marshal(root.Children)
 | |
| }
 | |
| 
 | |
| func Sort(nodes []*NavLink) {
 | |
| 	sort.SliceStable(nodes, func(i, j int) bool {
 | |
| 		iw := nodes[i].SortWeight
 | |
| 		if iw == 0 {
 | |
| 			iw = int64(i) + 1
 | |
| 		}
 | |
| 		jw := nodes[j].SortWeight
 | |
| 		if jw == 0 {
 | |
| 			jw = int64(j) + 1
 | |
| 		}
 | |
| 
 | |
| 		return iw < jw
 | |
| 	})
 | |
| 
 | |
| 	for _, child := range nodes {
 | |
| 		child.Sort()
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (root *NavTreeRoot) ApplyAdminIA(navAdminSubsectionsEnabled bool) {
 | |
| 	orgAdminNode := root.FindById(NavIDCfg)
 | |
| 
 | |
| 	if orgAdminNode != nil {
 | |
| 		adminNodeLinks := []*NavLink{}
 | |
| 
 | |
| 		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"))
 | |
| 
 | |
| 			generalNode := &NavLink{
 | |
| 				Text:     "General",
 | |
| 				SubTitle: "Manage default preferences and settings across Grafana",
 | |
| 				Id:       NavIDCfgGeneral,
 | |
| 				Url:      "/admin/general",
 | |
| 				Icon:     "shield",
 | |
| 				Children: generalNodeLinks,
 | |
| 			}
 | |
| 
 | |
| 			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)
 | |
| 			}
 | |
| 
 | |
| 			costManagementNode := root.FindById("plugin-page-grafana-costmanagementui-app")
 | |
| 
 | |
| 			if costManagementNode != nil {
 | |
| 				adminNodeLinks = append(adminNodeLinks, costManagementNode)
 | |
| 			}
 | |
| 
 | |
| 			costManagementMetricsNode := root.FindByURL("/a/grafana-costmanagementui-app/metrics")
 | |
| 			adaptiveMetricsNode := root.FindById("plugin-page-grafana-adaptive-metrics-app")
 | |
| 
 | |
| 			if costManagementMetricsNode != nil && adaptiveMetricsNode != nil {
 | |
| 				costManagementMetricsNode.Children = append(costManagementMetricsNode.Children, adaptiveMetricsNode)
 | |
| 			}
 | |
| 
 | |
| 			costManagementLogsNode := root.FindByURL("/a/grafana-costmanagementui-app/logs")
 | |
| 			logVolumeExplorerNode := root.FindById("plugin-page-grafana-logvolumeexplorer-app")
 | |
| 
 | |
| 			if costManagementLogsNode != nil && logVolumeExplorerNode != nil {
 | |
| 				costManagementLogsNode.Children = append(costManagementLogsNode.Children, logVolumeExplorerNode)
 | |
| 			}
 | |
| 		} 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
 | |
| 		} else {
 | |
| 			root.RemoveSection(orgAdminNode)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 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 {
 | |
| 			return child
 | |
| 		} else if len(child.Children) > 0 {
 | |
| 			if found := FindById(child.Children, id); found != nil {
 | |
| 				return found
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func FindByURL(nodes []*NavLink, url string) *NavLink {
 | |
| 	for _, child := range nodes {
 | |
| 		if child.Url == url {
 | |
| 			return child
 | |
| 		} else if len(child.Children) > 0 {
 | |
| 			if found := FindByURL(child.Children, url); found != nil {
 | |
| 				return found
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 |