Skip to content

Commit 6f36ce6

Browse files
Main improved dashboard links (#622)
* Add missing options, functionality to DashboardLink Includes the ability to create direct links or a list of dashboard links, extra options like includeVars and targetBlank. * Add docstring to DashboardLink, remove the unused `dashboard` param Removing this parameter is a breaking change... It didn't actually impact the generated link, other than acting as an alias to 'title' in some cases. If preferred, I can restore it to retain that alias behaviour, and perhaps add a warning log message? * Update changelog * Fix the DashboardLink type param in docstrings * Fix the field name for URL in DashboardLinks * Correct type annotations for py37, py38 * Fix flake8 warnigns in docstring for DashboardLink * Add tests for DashboardLink * Fix flake8 complaints in tests/test_core.py
1 parent f5da3c7 commit 6f36ce6

File tree

3 files changed

+95
-12
lines changed

3 files changed

+95
-12
lines changed

CHANGELOG.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ Changelog
55
0.x.x (?)
66
==================
77

8+
* Extended DashboardLink to support links to dashboards and urls, as per the docs_
9+
10+
.. _`docs`: https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/manage-dashboard-links/#dashboard-links
11+
812
* Added ...
913
* Added Minimum option for Timeseries
1014
* Added Maximum option for Timeseries

grafanalib/core.py

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
encourage it by way of some defaults. Rather, they are ways of building
66
arbitrary Grafana JSON.
77
"""
8-
8+
from __future__ import annotations
99
import itertools
1010
import math
1111

1212
import string
1313
import warnings
1414
from numbers import Number
15+
from typing import Literal
1516

1617
import attr
1718
from attr.validators import in_, instance_of
@@ -74,7 +75,7 @@ def to_json_data(self):
7475
FLOT = 'flot'
7576

7677
ABSOLUTE_TYPE = 'absolute'
77-
DASHBOARD_TYPE = 'dashboard'
78+
DASHBOARD_TYPE = Literal['dashboards', 'link']
7879
ROW_TYPE = 'row'
7980
GRAPH_TYPE = 'graph'
8081
DISCRETE_TYPE = 'natel-discrete-panel'
@@ -300,6 +301,9 @@ def to_json_data(self):
300301
DEFAULT_AUTO_COUNT = 30
301302
DEFAULT_MIN_AUTO_INTERVAL = '10s'
302303

304+
DASHBOARD_LINK_ICON = Literal['bolt', 'cloud', 'dashboard', 'doc',
305+
'external link', 'info', 'question']
306+
303307

304308
@attr.s
305309
class Mapping(object):
@@ -875,24 +879,65 @@ def to_json_data(self):
875879

876880
@attr.s
877881
class DashboardLink(object):
878-
dashboard = attr.ib()
879-
uri = attr.ib()
880-
keepTime = attr.ib(
882+
"""Create a link to other dashboards, or external resources.
883+
884+
Dashboard Links come in two flavours; a list of dashboards, or a direct
885+
link to an arbitrary URL. These are controlled by the ``type`` parameter.
886+
A dashboard list targets a given set of tags, whereas for a link you must
887+
also provide the URL.
888+
889+
See `the documentation <https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/manage-dashboard-links/#dashboard-links>`
890+
for more information.
891+
892+
:param asDropdown: Controls if the list appears in a dropdown rather than
893+
tiling across the dashboard. Affects 'dashboards' type only. Defaults
894+
to False
895+
:param icon: Set the icon, from a predefined list. See
896+
``grafanalib.core.DASHBOARD_LINK_ICON`` for allowed values. Affects
897+
the 'link' type only. Defaults to 'external link'
898+
:param includeVars: Controls if data variables from the current dashboard
899+
are passed as query parameters to the linked target. Defaults to False
900+
:param keepTime: Controls if the current time range is passed as query
901+
parameters to the linked target. Defaults to False
902+
:param tags: A list of tags used to select dashboards for the link.
903+
Affects the 'dashboards' type only. Defaults to an empty list
904+
:param targetBlank: Controls if the link opens in a new tab. Defaults
905+
to False
906+
:param tooltip: Tooltip text that appears when hovering over the link.
907+
Affects the 'link' type only. Defaults to an empty string
908+
:param type: Controls the type of DashboardLink generated. Must be
909+
one of 'dashboards' or 'link'.
910+
:param uri: The url target of the external link. Affects the 'link'
911+
type only.
912+
"""
913+
asDropdown: bool = attr.ib(default=False, validator=instance_of(bool))
914+
icon: DASHBOARD_LINK_ICON = attr.ib(default='external link',
915+
validator=in_(DASHBOARD_LINK_ICON.__args__))
916+
includeVars: bool = attr.ib(default=False, validator=instance_of(bool))
917+
keepTime: bool = attr.ib(
881918
default=True,
882919
validator=instance_of(bool),
883920
)
884-
title = attr.ib(default=None)
885-
type = attr.ib(default=DASHBOARD_TYPE)
921+
tags: list[str] = attr.ib(factory=list, validator=instance_of(list))
922+
targetBlank: bool = attr.ib(default=False, validator=instance_of(bool))
923+
title: str = attr.ib(default="")
924+
tooltip: str = attr.ib(default="", validator=instance_of(str))
925+
type: DASHBOARD_TYPE = attr.ib(default='dashboards',
926+
validator=in_(DASHBOARD_TYPE.__args__))
927+
uri: str = attr.ib(default="", validator=instance_of(str))
886928

887929
def to_json_data(self):
888-
title = self.dashboard if self.title is None else self.title
889930
return {
890-
'dashUri': self.uri,
891-
'dashboard': self.dashboard,
931+
'asDropdown': self.asDropdown,
932+
'icon': self.icon,
933+
'includeVars': self.includeVars,
892934
'keepTime': self.keepTime,
893-
'title': title,
935+
'tags': self.tags,
936+
'targetBlank': self.targetBlank,
937+
'title': self.title,
938+
'tooltip': self.tooltip,
894939
'type': self.type,
895-
'url': self.uri,
940+
'url': self.uri
896941
}
897942

898943

grafanalib/tests/test_core.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,3 +1190,37 @@ def test_sql_target_with_source_files():
11901190
assert t.to_json_data()["targets"][0].rawQuery is True
11911191
assert t.to_json_data()["targets"][0].rawSql == "SELECT example\nFROM test\nWHERE example='example' AND example_date BETWEEN '1970-01-01' AND '1971-01-01';\n"
11921192
print(t.to_json_data()["targets"][0])
1193+
1194+
1195+
class TestDashboardLink():
1196+
1197+
def test_validators(self):
1198+
with pytest.raises(ValueError):
1199+
G.DashboardLink(
1200+
type='dashboard',
1201+
)
1202+
with pytest.raises(ValueError):
1203+
G.DashboardLink(
1204+
icon='not an icon'
1205+
)
1206+
1207+
def test_initialisation(self):
1208+
dl = G.DashboardLink().to_json_data()
1209+
assert dl['asDropdown'] is False
1210+
assert dl['icon'] == 'external link'
1211+
assert dl['includeVars'] is False
1212+
assert dl['keepTime'] is True
1213+
assert not dl['tags']
1214+
assert dl['targetBlank'] is False
1215+
assert dl['title'] == ""
1216+
assert dl['tooltip'] == ""
1217+
assert dl['type'] == 'dashboards'
1218+
assert dl['url'] == ""
1219+
1220+
url = 'https://grafana.com'
1221+
dl = G.DashboardLink(
1222+
uri=url,
1223+
type='link'
1224+
).to_json_data()
1225+
assert dl['url'] == url
1226+
assert dl['type'] == 'link'

0 commit comments

Comments
 (0)