forked from grafana/grafana
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmodels.go
269 lines (235 loc) · 7.41 KB
/
models.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
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
WeightBookmarks
WeightSavedItems
WeightDashboard
WeightExplore
WeightAlerting
WeightAlertsAndIncidents
WeightTestingAndSynthetics
WeightMonitoring
WeightCloudServiceProviders
WeightInfrastructure
WeightApplication
WeightFrontend
WeightAsserts
WeightDataConnections
WeightApps
WeightPlugin
WeightConfig
WeightProfile
WeightHelp
)
const (
NavIDRoot = "root"
NavIDDashboards = "dashboards/browse"
NavIDExplore = "explore"
NavIDCfg = "cfg" // NavIDCfg is the id for org configuration navigation node
NavIDAlertsAndIncidents = "alerts-and-incidents"
NavIDTestingAndSynthetics = "testing-and-synthetics"
NavIDAlerting = "alerting"
NavIDMonitoring = "monitoring"
NavIDInfrastructure = "infrastructure"
NavIDFrontend = "frontend"
NavIDReporting = "reports"
NavIDApps = "apps"
NavIDCfgGeneral = "cfg/general"
NavIDCfgPlugins = "cfg/plugins"
NavIDCfgAccess = "cfg/access"
NavIDBookmarks = "bookmarks"
)
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"`
Keywords []string `json:"keywords,omitempty"`
ParentItem *NavLink `json:"parentItem,omitempty"` // (Optional) The parent item of the nav link
}
func (node *NavLink) Sort() {
Sort(node.Children)
}
type NavTreeRoot struct {
Children []*NavLink
}
func (root *NavTreeRoot) AddSection(node *NavLink) {
root.Children = append(root.Children, node)
}
// RemoveSection removes a section from the root node. Does not recurse into children.
func (root *NavTreeRoot) RemoveSection(node *NavLink) {
var result []*NavLink
for _, child := range root.Children {
if child != node {
result = append(result, child)
}
}
root.Children = result
}
// RemoveSectionByID removes a section by ID from the root node and all its children
func (root *NavTreeRoot) RemoveSectionByID(id string) bool {
var result []*NavLink
for i, child := range root.Children {
if child.Id == id {
// Remove the node by slicing it out
result = append(root.Children[:i], root.Children[i+1:]...)
root.Children = result
return true
} else if len(child.Children) > 0 {
if removed := RemoveById(child, id); removed {
return true
}
}
}
return false
}
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) ApplyHelpVersion(version string) {
helpNode := root.FindById("help")
if helpNode != nil {
helpNode.SubTitle = version
}
}
func (root *NavTreeRoot) ApplyCostManagementIA() {
orgAdminNode := root.FindById(NavIDCfg)
var costManagementApp *NavLink
var adaptiveMetricsApp *NavLink
var adaptiveLogsApp *NavLink
var attributionsApp *NavLink
var logVolumeExplorerApp *NavLink
if orgAdminNode != nil {
adminNodeLinks := []*NavLink{}
for _, element := range orgAdminNode.Children {
switch navId := element.Id; navId {
case "plugin-page-grafana-costmanagementui-app":
costManagementApp = element
case "plugin-page-grafana-adaptive-metrics-app":
adaptiveMetricsApp = element
case "plugin-page-grafana-adaptivelogs-app":
adaptiveLogsApp = element
case "plugin-page-grafana-attributions-app":
attributionsApp = element
case "plugin-page-grafana-logvolumeexplorer-app":
logVolumeExplorerApp = element
default:
adminNodeLinks = append(adminNodeLinks, element)
}
}
if costManagementApp != nil {
costManagementMetricsNode := FindByURL(costManagementApp.Children, "/a/grafana-costmanagementui-app/metrics")
if costManagementMetricsNode != nil {
if adaptiveMetricsApp != nil {
costManagementMetricsNode.Children = append(costManagementMetricsNode.Children, adaptiveMetricsApp)
}
if attributionsApp != nil {
costManagementMetricsNode.Children = append(costManagementMetricsNode.Children, attributionsApp)
}
}
costManagementLogsNode := FindByURL(costManagementApp.Children, "/a/grafana-costmanagementui-app/logs")
if costManagementLogsNode != nil {
if adaptiveLogsApp != nil {
costManagementLogsNode.Children = append(costManagementLogsNode.Children, adaptiveLogsApp)
}
if logVolumeExplorerApp != nil {
costManagementLogsNode.Children = append(costManagementLogsNode.Children, logVolumeExplorerApp)
}
}
adminNodeLinks = append(adminNodeLinks, costManagementApp)
}
orgAdminNode.Children = adminNodeLinks
}
}
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
}
func RemoveById(node *NavLink, id string) bool {
var result []*NavLink
for i, child := range node.Children {
if child.Id == id {
// Remove the node by slicing it out
result = append(node.Children[:i], node.Children[i+1:]...)
node.Children = result
return true
} else if len(child.Children) > 0 {
if removed := RemoveById(child, id); removed {
return true
}
}
}
return false
}