Skip to content

Commit 736d67d

Browse files
github-vincent-miszczakVincent MiszczakGiedriusS
authored
feat: dashboard versions API support (#194)
* feat: dashboard versions API support * chore: add test and update style * improve naming Co-authored-by: Giedrius Statkevičius <[email protected]> Co-authored-by: Vincent Miszczak <[email protected]> Co-authored-by: Giedrius Statkevičius <[email protected]>
1 parent edae16a commit 736d67d

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

rest-dashboard.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,38 @@ func (r *Client) GetDashboardBySlug(ctx context.Context, slug string) (Board, Bo
116116
return r.getDashboard(ctx, path)
117117
}
118118

119+
// DashboardVersion represents a response from /api/dashboards/id/:dashboardId/versions API
120+
type DashboardVersion struct {
121+
ID uint `json:"id"`
122+
DashboardID uint `json:"dashboardId"`
123+
ParentVersion uint `json:"parentVersion"`
124+
RestoredFrom uint `json:"restoredFrom"`
125+
Version uint `json:"version"`
126+
Created time.Time `json:"created"`
127+
CreatedBy string `json:"createdBy"`
128+
Message string `json:"message"`
129+
}
130+
131+
// GetDashboardVersionsByDashboardID reflects /api/dashboards/id/:dashboardId/versions API call
132+
func (r *Client) GetDashboardVersionsByDashboardID(ctx context.Context, dashboardID uint, params ...QueryParam) ([]DashboardVersion, error) {
133+
var (
134+
raw []byte
135+
code int
136+
err error
137+
)
138+
139+
if raw, code, err = r.get(ctx, fmt.Sprintf("api/dashboards/id/%d/versions", dashboardID), queryParams(params...)); err != nil {
140+
return nil, err
141+
}
142+
if code != 200 {
143+
return nil, fmt.Errorf("HTTP error %d: returns %s", code, raw)
144+
}
145+
var versions []DashboardVersion
146+
err = json.Unmarshal(raw, &versions)
147+
148+
return versions, err
149+
}
150+
119151
// getDashboard loads a dashboard from Grafana instance along with metadata for a dashboard.
120152
// For dashboards from a filesystem set "file/" prefix for slug. By default dashboards from
121153
// a database assumed. Database dashboards may have "db/" prefix or may have not, it will
@@ -396,8 +428,34 @@ type (
396428
SearchParam func(*url.Values)
397429
// SearchParamType is a type accepted by SearchType func.
398430
SearchParamType string
431+
// QueryParam is a type for specifying arbitrary API parameters
432+
QueryParam func(*url.Values)
399433
)
400434

435+
// queryParams returns url.Values built from multiple QueryParam
436+
func queryParams(params ...QueryParam) url.Values {
437+
u := url.URL{}
438+
q := u.Query()
439+
for _, p := range params {
440+
p(&q)
441+
}
442+
return q
443+
}
444+
445+
// QueryParamStart sets `start` parameter
446+
func QueryParamStart(start uint) QueryParam {
447+
return func(v *url.Values) {
448+
v.Set("start", strconv.Itoa(int(start)))
449+
}
450+
}
451+
452+
// QueryParamLimit sets `limit` parameter
453+
func QueryParamLimit(limit uint) QueryParam {
454+
return func(v *url.Values) {
455+
v.Set("limit", strconv.Itoa(int(limit)))
456+
}
457+
}
458+
401459
// Search entities to be used with SearchType().
402460
const (
403461
SearchTypeFolder SearchParamType = "dash-folder"

rest-dashboard_integration_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,69 @@ func Test_Dashboard_CRUD_By_UID(t *testing.T) {
116116
}
117117

118118
}
119+
120+
func Test_GetDashboardVersionsByDashboardID(t *testing.T) {
121+
var (
122+
board sdk.Board
123+
err error
124+
start = sdk.QueryParamStart(0)
125+
limit = sdk.QueryParamLimit(10)
126+
)
127+
ctx := context.Background()
128+
client := getClient(t)
129+
raw, _ := ioutil.ReadFile("testdata/new-empty-dashboard-2.6.json")
130+
131+
if err = json.Unmarshal(raw, &board); err != nil {
132+
t.Fatal(err)
133+
}
134+
board.UID = "1234"
135+
if _, err = client.DeleteDashboardByUID(ctx, board.UID); err != nil {
136+
t.Fatal(err)
137+
}
138+
139+
params := sdk.SetDashboardParams{
140+
FolderID: sdk.DefaultFolderId,
141+
Overwrite: false,
142+
}
143+
// create initial dashboard
144+
if _, err = client.SetDashboard(ctx, board, params); err != nil {
145+
t.Fatal(err)
146+
}
147+
148+
board, _, err = client.GetDashboardByUID(ctx, board.UID)
149+
if err != nil {
150+
t.Fatal(err)
151+
}
152+
153+
// update dashboard to create a new version
154+
params.Overwrite = true
155+
if _, err = client.SetDashboard(ctx, board, params); err != nil {
156+
t.Fatal(err)
157+
}
158+
board, _, err = client.GetDashboardByUID(ctx, board.UID)
159+
if err != nil {
160+
t.Fatal(err)
161+
}
162+
163+
// fetch versions
164+
versions, err := client.GetDashboardVersionsByDashboardID(ctx, board.ID, start, limit)
165+
if err != nil {
166+
t.Fatal(err)
167+
}
168+
169+
// we should have 2 versions
170+
if len(versions) != 2 {
171+
t.Fatal("dashboard should have 2 versions")
172+
}
173+
// the latest version in Grafana should match the current version of the board
174+
// API returns versions sorted DESC
175+
if versions[0].Version != board.Version {
176+
t.Fatal("dashboard version from dashboards/uid/:uid API does not match latest dashboard version from dashboards/id/:dashboardId/versions API")
177+
}
178+
179+
// fetch non-existing dashboard to validate error case
180+
_, err = client.GetDashboardVersionsByDashboardID(ctx, 42, start, limit)
181+
if err == nil {
182+
t.Fatal("when fetching dashboard version with erroneous inputs, it should return an error, got nil error")
183+
}
184+
}

0 commit comments

Comments
 (0)