Skip to content

Commit 7d2add9

Browse files
authored
Add support for Grafana 10.3.x (#3)
* Add support for Grafana 10.3.x * PR review feedback
1 parent 94012c7 commit 7d2add9

File tree

3 files changed

+92
-20
lines changed

3 files changed

+92
-20
lines changed

api/grafana/grafana.go

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ package grafana
22

33
import (
44
"context"
5+
"errors"
56
"net/url"
67
"strconv"
78

89
"github.com/grafana/detect-angular-dashboards/api"
910
)
1011

12+
var errUnknownAngularStatus = errors.New("could not determine if plugin is angular or not, use GCOM instead")
13+
1114
const DefaultBaseURL = "http://127.0.0.1:3000/api"
1215

1316
type APIClient struct {
@@ -72,19 +75,78 @@ func (cl APIClient) GetDashboard(ctx context.Context, uid string) (*Dashboard, e
7275
// FrontendSettings is the response returned by api/frontend/settings
7376
type FrontendSettings struct {
7477
// Panels is a map from panel plugin id to plugin metadata
75-
Panels map[string]struct {
76-
// AngularDetected is true if the plugin uses Angular APIs
77-
AngularDetected *bool
78-
}
78+
Panels map[string]FrontendSettingsPanel
7979

8080
// Datasources is a map from datasource names to plugin metadata
81-
Datasources map[string]struct {
82-
// Type is the plugin's ID
83-
Type string
81+
Datasources map[string]FrontendSettingsDatasource
82+
}
83+
84+
// FrontendSettingsPanel is a panel present in FrontendSettings.
85+
// Which fields are populated depends on the Grafana version.
86+
type FrontendSettingsPanel struct {
87+
// AngularDetected is true if the plugin uses Angular APIs
88+
// (present in Grafana >= 10.1.0 && < 10.3.0)
89+
AngularDetected *bool
90+
91+
// Angular contains the Angular metadata for the plugin
92+
// (present in Grafana >= 10.3.0)
93+
Angular *struct {
94+
// Detected is true if the plugin uses Angular APIs
95+
Detected bool
96+
}
97+
}
98+
99+
// IsAngular returns true if the panel plugin is an angular plugin.
100+
// The correct fields are used depending on the Grafana version.
101+
// If this information cannot be determined, it returns an errUnknownAngularStatus.
102+
func (p FrontendSettingsPanel) IsAngular() (bool, error) {
103+
if p.Angular != nil {
104+
// >= 10.3.0
105+
return p.Angular.Detected, nil
106+
}
107+
if p.AngularDetected != nil {
108+
// >= 10.1.0 && < 10.3.0
109+
return *p.AngularDetected, nil
110+
}
111+
// < 10.1.0
112+
return false, errUnknownAngularStatus
113+
}
114+
115+
// FrontendSettingsDatasource is a datasource present in FrontendSettings.
116+
// Which fields are populated depends on the Grafana version.
117+
type FrontendSettingsDatasource struct {
118+
// AngularDetected is true if the plugin uses Angular APIs
119+
// (present in Grafana >= 10.1.0 && < 10.3.0)
120+
AngularDetected *bool
121+
122+
// Meta contains plugin metadata
123+
Meta struct {
124+
// Angular contains angular plugin metadata
125+
// (present in Grafana >= 10.3.0)
126+
Angular *struct {
127+
// Detected is true if the plugin uses Angular APIs
128+
Detected bool
129+
}
130+
}
131+
132+
// Type is the plugin's ID
133+
Type string
134+
}
84135

85-
// AngularDetected is true if the plugin uses Angular APIs
86-
AngularDetected *bool
136+
// IsAngular returns true if the datasource plugin is an angular plugin.
137+
// The correct fields are used depending on the Grafana version.
138+
// If this information cannot be determined, it returns an errUnknownAngularStatus.
139+
func (d FrontendSettingsDatasource) IsAngular() (bool, error) {
140+
if d.Meta.Angular != nil {
141+
// >= 10.3.0
142+
return d.Meta.Angular.Detected, nil
143+
}
144+
if d.AngularDetected != nil {
145+
// >= 10.1.0 && < 10.3.0
146+
return *d.AngularDetected, nil
87147
}
148+
// < 10.1.0
149+
return false, errUnknownAngularStatus
88150
}
89151

90152
func (cl APIClient) GetFrontendSettings(ctx context.Context) (*FrontendSettings, error) {

api/grafana/models.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ type PanelDatasource struct {
2424
Type string
2525
}
2626

27-
type Panel struct {
27+
type DashboardPanel struct {
2828
Type string
2929
Title string
3030
Datasource interface{}
3131
}
3232

3333
type Dashboard struct {
34-
Panels []*Panel `json:"panels"`
35-
SchemaVersion int `json:"schemaVersion"`
34+
Panels []*DashboardPanel `json:"panels"`
35+
SchemaVersion int `json:"schemaVersion"`
3636
}

main.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,13 @@ func _main() error {
6666

6767
// Determine if we should use GCOM or frontendsettings
6868
var useGCOM bool
69-
// Get any key and see if AngularDetected is present or not.
70-
// From Grafana 10.1.0, it will always be present.
71-
// Before Grafana 10.1.0, it's always nil as it's not present in the body.
69+
// Get any key and see if Angular or AngularDetected is present or not.
70+
// With Grafana >= 10.3.0, Angular is present.
71+
// With Grafana >= 10.1.0 && < 10.3.0, AngularDetected is present.
72+
// With Grafana <= 10.1.0, it's always nil as it's not present in the body.
73+
// In the last case, we can only rely on the data in GCOM.
7274
for _, p := range frontendSettings.Panels {
73-
useGCOM = p.AngularDetected == nil
75+
useGCOM = p.Angular == nil && p.AngularDetected == nil
7476
break
7577
}
7678
if useGCOM {
@@ -115,11 +117,19 @@ func _main() error {
115117
}
116118
} else {
117119
log.Verbose().Log("Using frontendsettings to find Angular plugins")
118-
for pluginID, meta := range frontendSettings.Panels {
119-
angularDetected[pluginID] = *meta.AngularDetected
120+
for pluginID, panel := range frontendSettings.Panels {
121+
v, err := panel.IsAngular()
122+
if err != nil {
123+
return fmt.Errorf("%q is angular: %w", pluginID, err)
124+
}
125+
angularDetected[pluginID] = v
120126
}
121-
for _, meta := range frontendSettings.Datasources {
122-
angularDetected[meta.Type] = *meta.AngularDetected
127+
for _, ds := range frontendSettings.Datasources {
128+
v, err := ds.IsAngular()
129+
if err != nil {
130+
return fmt.Errorf("%q is angular: %w", ds.Type, err)
131+
}
132+
angularDetected[ds.Type] = v
123133
}
124134
}
125135

0 commit comments

Comments
 (0)