Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
B
brian-dashboard-manager
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
geant-swd
brian
brian-dashboard-manager
Commits
739007aa
Commit
739007aa
authored
6 months ago
by
Bjarke Madsen
Browse files
Options
Downloads
Patches
Plain Diff
Minor refactor
parent
62efb3e6
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
brian_dashboard_manager/templating/helpers.py
+90
-135
90 additions, 135 deletions
brian_dashboard_manager/templating/helpers.py
brian_dashboard_manager/templating/render.py
+21
-15
21 additions, 15 deletions
brian_dashboard_manager/templating/render.py
with
111 additions
and
150 deletions
brian_dashboard_manager/templating/helpers.py
+
90
−
135
View file @
739007aa
...
@@ -744,7 +744,7 @@ def default_interface_panel_generator(gridPos, use_all_traffic=True, use_ipv6=Tr
...
@@ -744,7 +744,7 @@ def default_interface_panel_generator(gridPos, use_all_traffic=True, use_ipv6=Tr
:return: function that generates panel definitions
:return: function that generates panel definitions
"""
"""
def
get_panel_definitions
(
panel
s
,
datasource
,
errors
=
False
):
def
get_panel_definitions
(
panel
_data
,
datasource
,
errors
=
False
):
"""
"""
Generates the panel definitions for the dashboard based on the
Generates the panel definitions for the dashboard based on the
panel data for the panel types (traffic, errors, IPv6).
panel data for the panel types (traffic, errors, IPv6).
...
@@ -760,21 +760,21 @@ def default_interface_panel_generator(gridPos, use_all_traffic=True, use_ipv6=Tr
...
@@ -760,21 +760,21 @@ def default_interface_panel_generator(gridPos, use_all_traffic=True, use_ipv6=Tr
"""
"""
result
=
[]
result
=
[]
for
panel
in
panel
s
:
for
interface
in
panel
_data
:
if
use_all_traffic
:
if
use_all_traffic
:
result
.
append
(
get_panel_fields
({
result
.
append
(
get_panel_fields
({
**
panel
,
**
interface
,
**
next
(
gridPos
)
**
next
(
gridPos
)
},
'
traffic
'
,
datasource
))
},
'
traffic
'
,
datasource
))
if
use_ipv6
:
if
use_ipv6
:
if
panel
.
get
(
'
has_v6
'
,
False
):
if
interface
.
get
(
'
has_v6
'
,
False
):
result
.
append
(
get_panel_fields
({
result
.
append
(
get_panel_fields
({
**
panel
,
**
interface
,
**
next
(
gridPos
)
**
next
(
gridPos
)
},
'
IPv6
'
,
datasource
))
},
'
IPv6
'
,
datasource
))
if
errors
:
if
errors
:
result
.
append
(
get_panel_fields
({
result
.
append
(
get_panel_fields
({
**
panel
,
**
interface
,
**
next
(
gridPos
)
**
next
(
gridPos
)
},
'
errors
'
,
datasource
))
},
'
errors
'
,
datasource
))
...
@@ -901,7 +901,7 @@ def get_aggregate_dashboard_data(title, remotes, datasource, tag):
...
@@ -901,7 +901,7 @@ def get_aggregate_dashboard_data(title, remotes, datasource, tag):
return
result
return
result
def
get_
nren_
dashboard_data_single
(
data
,
datasource
,
tag
):
def
get_dashboard_
with_agg_
data_single
(
data
,
datasource
,
tag
):
"""
"""
Helper for generating dashboard definitions for a single NREN.
Helper for generating dashboard definitions for a single NREN.
...
@@ -917,14 +917,14 @@ def get_nren_dashboard_data_single(data, datasource, tag):
...
@@ -917,14 +917,14 @@ def get_nren_dashboard_data_single(data, datasource, tag):
:return: dashboard definition for the NREN dashboard
:return: dashboard definition for the NREN dashboard
"""
"""
nren
,
dash
=
data
dashboard_name
,
dashboard_data
=
data
id_gen
=
num_generator
()
id_gen
=
num_generator
()
if
len
(
dash
[
'
AGGREGATES
'
]
)
>
0
:
if
len
(
dash
board_data
.
get
(
'
AGGREGATES
'
,
[])
)
>
0
:
agg_panels
=
create_aggregate_panel
(
agg_panels
=
create_aggregate_panel
(
f
'
Aggregate -
{
nren
}
'
,
f
'
Aggregate -
{
dashboard_name
}
'
,
gridPos_generator
(
id_gen
,
agg
=
True
),
gridPos_generator
(
id_gen
,
agg
=
True
),
dash
[
'
AGGREGATES
'
],
datasource
)
dash
board_data
[
'
AGGREGATES
'
],
datasource
)
gridPos
=
gridPos_generator
(
id_gen
,
start
=
2
)
gridPos
=
gridPos_generator
(
id_gen
,
start
=
2
)
else
:
else
:
gridPos
=
gridPos_generator
(
id_gen
)
gridPos
=
gridPos_generator
(
id_gen
)
...
@@ -933,113 +933,50 @@ def get_nren_dashboard_data_single(data, datasource, tag):
...
@@ -933,113 +933,50 @@ def get_nren_dashboard_data_single(data, datasource, tag):
panel_gen
=
default_interface_panel_generator
(
gridPos
,
use_all_traffic
=
True
,
use_ipv6
=
False
)
panel_gen
=
default_interface_panel_generator
(
gridPos
,
use_all_traffic
=
True
,
use_ipv6
=
False
)
panel_ipv6_gen
=
default_interface_panel_generator
(
gridPos
,
use_all_traffic
=
False
,
use_ipv6
=
True
)
panel_ipv6_gen
=
default_interface_panel_generator
(
gridPos
,
use_all_traffic
=
False
,
use_ipv6
=
True
)
services_dropdown
=
create_dropdown_panel
(
'
Services
'
,
**
next
(
gridPos
))
def
sort_key
(
panel
):
def
sort_key
(
panel
):
sort
=
panel
.
get
(
'
sort
'
)
sort
=
panel
.
get
(
'
sort
'
)
if
not
sort
:
if
not
sort
:
return
'
ZZZ
'
+
panel
.
get
(
'
hostname
'
)
# sort to end
return
'
ZZZ
'
+
panel
.
get
(
'
hostname
'
)
# sort to end
return
sort
return
sort
service_panels
=
panel_gen
(
services_dropdown
=
create_dropdown_panel
(
'
Services
'
,
panels
=
[],
**
next
(
gridPos
),
collapsed
=
False
)
sorted
(
dash
[
'
SERVICES
'
],
key
=
sort_key
),
datasource
)
service_panels
=
panel_gen
(
sorted
(
dashboard_data
.
get
(
'
SERVICES
'
,
[]),
key
=
sort_key
),
datasource
)
services_ipv6_dropdown
=
create_dropdown_panel
(
'
Services - IPv6 Only
'
,
**
next
(
gridPos
))
service_ipv6_panels
=
panel_ipv6_gen
(
sorted
(
dash
[
'
SERVICES
'
],
key
=
sort_key
),
datasource
)
iface_dropdown
=
create_dropdown_panel
(
'
Interfaces
'
,
**
next
(
gridPos
))
phys_panels
=
panel_gen
(
dash
[
'
PHYSICAL
'
],
datasource
,
True
)
dropdown_groups
=
[{
'
dropdown
'
:
services_dropdown
,
'
panels
'
:
service_panels
,
}]
if
len
(
service_ipv6_panels
)
>
0
:
dropdown_groups
.
append
({
'
dropdown
'
:
services_ipv6_dropdown
,
'
panels
'
:
service_ipv6_panels
})
dropdown_groups
.
append
({
'
dropdown
'
:
iface_dropdown
,
'
panels
'
:
phys_panels
,
})
result
=
{
'
nren_name
'
:
nren
,
'
datasource
'
:
datasource
,
'
aggregate_panels
'
:
agg_panels
,
'
dropdown_groups
'
:
dropdown_groups
}
if
isinstance
(
tag
,
list
):
result
[
'
tags
'
]
=
tag
else
:
result
[
'
tag
'
]
=
tag
return
result
def
get_re_peer_dashboard_data_single
(
data
,
datasource
,
tag
):
"""
Helper for generating dashboard definitions for a single R&E Peer.
NREN dashboards have two aggregate panels (ingress and egress),
and two dropdown panels for services and interfaces.
:param data: data for the dashboard, including the R&E Peer name and
the panel data
:param datasource: datasource to use for the panels
:param tag: tag to use for the dashboard, used for dashboard dropdowns on
the home dashboard.
:return: dashboard definition for the R&E Peer dashboard
"""
peer
,
dash
=
data
id_gen
=
num_generator
()
if
len
(
dash
[
'
AGGREGATES
'
])
>
0
:
service_ipv6_panels
=
panel_ipv6_gen
(
sorted
(
dashboard_data
.
get
(
'
SERVICES
'
,
[]),
key
=
sort_key
),
datasource
)
agg_panels
=
create_aggregate_panel
(
services_ipv6_dropdown
=
create_dropdown_panel
(
f
'
Aggregate -
{
peer
}
'
,
'
Services - IPv6 Only
'
,
panels
=
service_ipv6_panels
,
**
next
(
gridPos
),
collapsed
=
True
)
gridPos_generator
(
id_gen
,
agg
=
True
),
dash
[
'
AGGREGATES
'
],
datasource
)
gridPos
=
gridPos_generator
(
id_gen
,
start
=
2
)
else
:
gridPos
=
gridPos_generator
(
id_gen
)
agg_panels
=
[]
panel_gen
=
default_interface_panel_generator
(
gridPos
,
use_all_traffic
=
True
,
use_ipv6
=
True
)
phys_panels
=
panel_gen
(
dashboard_data
.
get
(
'
PHYSICAL
'
,
[]),
datasource
,
errors
=
True
)
iface_dropdown
=
create_dropdown_panel
(
'
Interfaces
'
,
panels
=
phys_panels
,
**
next
(
gridPos
),
collapsed
=
True
)
services_dropdown
=
create_dropdown_panel
(
'
Services
'
,
**
next
(
gridPos
))
panels
=
[]
def
sort_key
(
panel
):
num_dropdowns
=
sum
(
1
for
p
in
[
service_panels
,
service_ipv6_panels
,
phys_panels
]
if
len
(
p
)
>
0
)
sort
=
panel
.
get
(
'
sort
'
)
if
not
sort
:
return
'
ZZZ
'
+
panel
.
get
(
'
hostname
'
)
# sort to end
return
sort
service_panels
=
panel_gen
(
if
len
(
service_panels
)
>
0
and
num_dropdowns
>
1
:
sorted
(
dash
[
'
SERVICES
'
],
key
=
sort_key
),
datasource
)
panels
.
append
(
services_dropdown
)
panels
.
extend
(
service_panels
)
if
ace_dropdown
=
create_dropdown_panel
(
'
Interfaces
'
,
**
next
(
gridPos
))
if
len
(
service_ipv6_panels
)
>
0
and
num_dropdowns
>
1
:
phys_panels
=
panel_gen
(
dash
[
'
PHYSICAL
'
],
datasource
,
True
)
panels
.
append
(
services_ipv6_dropdown
)
dropdown_groups
=
[{
if
len
(
phys_panels
)
>
0
and
num_dropdowns
>
1
:
'
dropdown
'
:
services_dropdown
,
panels
.
append
(
iface_dropdown
)
'
panels
'
:
service_panels
,
}]
dropdown_groups
.
append
({
if
num_dropdowns
<=
1
:
'
dropdown
'
:
iface_dropdown
,
# if there is only one dropdown, just add all the panels instead
'
panels
'
:
phys_panels
,
if
service_panels
:
})
panels
.
extend
(
service_panels
)
elif
service_ipv6_panels
:
panels
.
extend
(
service_ipv6_panels
)
elif
phys_panels
:
panels
.
extend
(
phys_panels
)
result
=
{
result
=
{
'
nren_name
'
:
peer
,
'
title
'
:
dashboard_name
,
'
datasource
'
:
datasource
,
'
datasource
'
:
datasource
,
'
aggregate_panels
'
:
agg_panels
,
'
aggregate_panels
'
:
agg_panels
,
'
dropdown_groups
'
:
dropdown_group
s
'
panels
'
:
panel
s
}
}
if
isinstance
(
tag
,
list
):
if
isinstance
(
tag
,
list
):
result
[
'
tags
'
]
=
tag
result
[
'
tags
'
]
=
tag
...
@@ -1049,48 +986,35 @@ def get_re_peer_dashboard_data_single(data, datasource, tag):
...
@@ -1049,48 +986,35 @@ def get_re_peer_dashboard_data_single(data, datasource, tag):
return
result
return
result
def
get_service_dashboard_data_single
(
data
,
datasource
,
tag
):
def
get_dashboard_data_single
(
data
,
datasource
,
tag
,
panel_generator
=
default_interface_panel_generator
,
errors
=
False
):
"""
"""
Helper for generating dashboard definitions for
a single service
.
Helper for generating dashboard definitions for
non-NREN dashboards
.
:param data: data for the dashboard, including the
service
name and
:param data: data for the dashboard, including the
dashboard
name and
the panel data
the panel data
:param datasource: datasource to use for the panels
:param datasource: datasource to use for the panels
:param tag: tag to use for the dashboard, used for dashboard dropdowns on
:param tag: tag to use for the dashboard, used for dashboard dropdowns on
the home dashboard.
the home dashboard.
:param panel_generator: function for generating panel definitions
:param errors: whether or not to include an error panel for each interface
:return: dashboard definition for the
service
dashboard
:return: dashboard definition for the
NREN
dashboard
"""
"""
service_name
,
dash
=
data
id_gen
=
num_generator
()
id_gen
=
num_generator
()
gridPos
=
gridPos_generator
(
id_gen
)
gridPos
=
gridPos_generator
(
id_gen
)
panel_gen
=
panel_generator
(
gridPos
)
panel_gen
=
default_interface_panel_generator
(
gridPos
,
use_all_traffic
=
True
,
use_ipv6
=
False
)
name
,
panel_data
=
data
services_dropdown
=
create_dropdown_panel
(
'
Services
'
,
**
next
(
gridPos
))
def
sort_key
(
panel
):
sort
=
panel
.
get
(
'
sort
'
)
if
not
sort
:
return
'
ZZZ
'
+
panel
.
get
(
'
hostname
'
)
# sort to end
return
sort
service_panels
=
panel_gen
(
sorted
(
dash
[
'
SERVICES
'
],
key
=
sort_key
),
datasource
)
dropdown_groups
=
[{
'
dropdown
'
:
services_dropdown
,
'
panels
'
:
service_panels
,
}]
result
=
{
result
=
{
'
nren_name
'
:
service_
name
,
'
title
'
:
name
,
'
datasource
'
:
datasource
,
'
datasource
'
:
datasource
,
'
aggregate_panels
'
:
[],
'
panels
'
:
panel_gen
(
panel_data
,
datasource
,
errors
),
'
dropdown_groups
'
:
dropdown_groups
}
}
if
isinstance
(
tag
,
list
):
if
isinstance
(
tag
,
list
):
result
[
'
tags
'
]
=
tag
result
[
'
tags
'
]
=
tag
else
:
else
:
...
@@ -1099,15 +1023,15 @@ def get_service_dashboard_data_single(data, datasource, tag):
...
@@ -1099,15 +1023,15 @@ def get_service_dashboard_data_single(data, datasource, tag):
return
result
return
result
def
get_dashboard_data_single
(
def
get_dashboard_data_
dropdown_
single
(
data
,
datasource
,
tag
,
data
,
datasource
,
tag
,
panel_generator
=
default_interface_panel_generator
,
panel_generator
=
default_interface_panel_generator
,
errors
=
False
):
errors
=
False
):
"""
"""
Helper for generating dashboard definitions for
non-NREN
dashboards.
Helper for generating dashboard definitions for dashboard
s with dropdown
s.
:param data: data for the dashboard, including the dashboard name and
:param data: data for the dashboard, including the dashboard name and
the panel data
the
dropdown groups with each group containing
panel data
:param datasource: datasource to use for the panels
:param datasource: datasource to use for the panels
:param tag: tag to use for the dashboard, used for dashboard dropdowns on
:param tag: tag to use for the dashboard, used for dashboard dropdowns on
the home dashboard.
the home dashboard.
...
@@ -1121,13 +1045,20 @@ def get_dashboard_data_single(
...
@@ -1121,13 +1045,20 @@ def get_dashboard_data_single(
gridPos
=
gridPos_generator
(
id_gen
)
gridPos
=
gridPos_generator
(
id_gen
)
panel_gen
=
panel_generator
(
gridPos
)
panel_gen
=
panel_generator
(
gridPos
)
name
,
panels
=
data
name
,
panel_groups
=
data
panels
=
[]
result
=
{
result
=
{
'
title
'
:
name
,
'
title
'
:
name
,
'
datasource
'
:
datasource
,
'
datasource
'
:
datasource
,
'
panels
'
:
list
(
panel_gen
(
panels
,
datasource
,
errors
)),
'
panels
'
:
panels
}
}
for
group
,
_panels
in
panel_groups
.
items
():
dropdown
=
create_dropdown_panel
(
group
,
panels
=
list
(
panel_gen
(
_panels
,
datasource
,
errors
)),
collapsed
=
True
,
**
next
(
gridPos
))
panels
.
append
(
dropdown
)
if
isinstance
(
tag
,
list
):
if
isinstance
(
tag
,
list
):
result
[
'
tags
'
]
=
tag
result
[
'
tags
'
]
=
tag
else
:
else
:
...
@@ -1160,10 +1091,34 @@ def get_dashboard_data(
...
@@ -1160,10 +1091,34 @@ def get_dashboard_data(
yield
from
map
(
func
,
data
.
items
())
yield
from
map
(
func
,
data
.
items
())
def
get_dashboard_data_dropdown
(
data
,
datasource
,
tag
,
panel_generator
=
default_interface_panel_generator
,
errors
=
False
):
"""
Helper for generating dashboard definitions for interface-based non-NREN dashboards.
:param data: the dashboard names and the panel data for each dashboard
:param datasource: datasource to use for the panels
:param tag: tag to use for the dashboard, used for dashboard dropdowns on
the home dashboard.
:param panel_generator: function for generating panel definitions
:param errors: whether or not to include an error panel for each interface
:return: generator for dashboard definitions for each dashboard
"""
func
=
partial
(
get_dashboard_data_dropdown_single
,
datasource
=
datasource
,
tag
=
tag
,
panel_generator
=
panel_generator
,
errors
=
errors
)
yield
from
map
(
func
,
data
.
items
())
def
get_nren_dashboard_data
(
data
,
datasource
,
tag
):
def
get_nren_dashboard_data
(
data
,
datasource
,
tag
):
func
=
partial
(
func
=
partial
(
get_
nren_
dashboard_data_single
,
get_dashboard_
with_agg_
data_single
,
datasource
=
datasource
,
datasource
=
datasource
,
tag
=
tag
)
tag
=
tag
)
...
@@ -1172,7 +1127,7 @@ def get_nren_dashboard_data(data, datasource, tag):
...
@@ -1172,7 +1127,7 @@ def get_nren_dashboard_data(data, datasource, tag):
def
get_re_peer_dashboard_data
(
data
,
datasource
,
tag
):
def
get_re_peer_dashboard_data
(
data
,
datasource
,
tag
):
func
=
partial
(
func
=
partial
(
get_
re_peer_
dashboard_data_single
,
get_dashboard_
with_agg_
data_single
,
datasource
=
datasource
,
datasource
=
datasource
,
tag
=
tag
)
tag
=
tag
)
...
@@ -1181,7 +1136,7 @@ def get_re_peer_dashboard_data(data, datasource, tag):
...
@@ -1181,7 +1136,7 @@ def get_re_peer_dashboard_data(data, datasource, tag):
def
get_service_dashboard_data
(
data
,
datasource
,
tag
):
def
get_service_dashboard_data
(
data
,
datasource
,
tag
):
func
=
partial
(
func
=
partial
(
get_
service_
dashboard_data_single
,
get_dashboard_
with_agg_
data_single
,
datasource
=
datasource
,
datasource
=
datasource
,
tag
=
tag
)
tag
=
tag
)
...
...
This diff is collapsed.
Click to expand it.
brian_dashboard_manager/templating/render.py
+
21
−
15
View file @
739007aa
BASE_DROPDOWN_PANEL
=
{
BASE_DROPDOWN_PANEL
=
{
"
aliasColors
"
:
{},
"
aliasColors
"
:
{},
"
collapsed
"
:
False
,
"
datasource
"
:
None
,
"
datasource
"
:
None
,
"
fill
"
:
None
,
"
fill
"
:
None
,
"
fillGradient
"
:
None
,
"
fillGradient
"
:
None
,
...
@@ -121,7 +120,7 @@ INFOBOX = {
...
@@ -121,7 +120,7 @@ INFOBOX = {
}
}
def
create_dropdown_panel
(
title
,
id
,
y
,
**
kwargs
):
def
create_dropdown_panel
(
title
,
id
,
y
,
panels
,
collapsed
=
True
,
**
kwargs
):
"""
"""
Creates a dropdown panel from the given data.
Creates a dropdown panel from the given data.
...
@@ -132,11 +131,18 @@ def create_dropdown_panel(title, id, y, **kwargs):
...
@@ -132,11 +131,18 @@ def create_dropdown_panel(title, id, y, **kwargs):
:return: rendered dropdown panel JSON
:return: rendered dropdown panel JSON
"""
"""
# If collapsed is false, panels should come after the dropdown panel, not inside it
if
not
collapsed
and
panels
:
raise
ValueError
(
"
Collapsed dropdown panels cannot have panels, add them after the dropdown panel.
"
)
return
{
return
{
**
BASE_DROPDOWN_PANEL
,
**
BASE_DROPDOWN_PANEL
,
"
collapsed
"
:
collapsed
,
"
id
"
:
id
,
"
id
"
:
id
,
"
gridPos
"
:
{
"
h
"
:
1
,
"
w
"
:
24
,
"
x
"
:
0
,
"
y
"
:
y
},
"
gridPos
"
:
{
"
h
"
:
1
,
"
w
"
:
24
,
"
x
"
:
0
,
"
y
"
:
y
},
"
title
"
:
title
,
"
title
"
:
title
,
"
panels
"
:
panels
,
}
}
...
@@ -313,31 +319,31 @@ def create_panel(
...
@@ -313,31 +319,31 @@ def create_panel(
return
result
return
result
def
render_with_aggregate_dashboard
(
def
render_with_aggregate_dashboard
(
title
,
aggregate_panels
,
panels
,
tag
=
None
,
tags
=
None
,
infobox
=
True
,
**
_
):
nren_name
,
aggregate_panels
,
dropdown_groups
,
tag
=
None
,
tags
=
None
,
**
_
):
assert
tag
or
tags
assert
tag
or
tags
panels
=
[
INFOBOX
,
*
aggregate_panels
]
if
infobox
:
for
group
in
dropdown_groups
:
panels
=
[
INFOBOX
,
*
aggregate_panels
,
*
panels
]
panels
.
append
(
group
[
"
dropdown
"
])
else
:
panels
.
extend
(
group
[
"
panels
"
])
panels
=
[
*
aggregate_panels
,
*
panels
]
return
{
return
{
**
BASE_DASHBOARD
,
**
BASE_DASHBOARD
,
"
tags
"
:
tags
or
[
tag
],
"
tags
"
:
tags
or
[
tag
],
"
title
"
:
nren_nam
e
,
"
title
"
:
titl
e
,
"
panels
"
:
panels
,
"
panels
"
:
panels
,
}
}
def
render_simple_dashboard
(
title
,
tag
=
None
,
tags
=
None
,
panels
=
None
,
**
_
):
def
render_simple_dashboard
(
title
,
tag
=
None
,
tags
=
None
,
panels
=
None
,
infobox
=
True
,
**
_
):
assert
tag
or
tags
assert
tag
or
tags
if
infobox
:
panels
=
[
INFOBOX
,
*
(
panels
or
[])]
else
:
panels
=
panels
or
[]
return
{
return
{
**
BASE_DASHBOARD
,
**
BASE_DASHBOARD
,
"
tags
"
:
tags
or
[
tag
],
"
tags
"
:
tags
or
[
tag
],
"
title
"
:
title
,
"
title
"
:
title
,
"
panels
"
:
[
"
panels
"
:
panels
,
INFOBOX
,
*
(
panels
or
[]),
],
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment