Skip to content
This repository has been archived by the owner on Oct 29, 2020. It is now read-only.

Commit

Permalink
Merge pull request #14 from smithclay/dashboard-api
Browse files Browse the repository at this point in the history
Add Support for Dashboards API
  • Loading branch information
paultyng authored Jan 24, 2018
2 parents 4131ea7 + 009a3e2 commit 6591d69
Show file tree
Hide file tree
Showing 4 changed files with 446 additions and 0 deletions.
106 changes: 106 additions & 0 deletions api/dashboards.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package api

import (
"fmt"
"net/url"
)

func (c *Client) queryDashboards() ([]Dashboard, error) {
dashboards := []Dashboard{}
reqURL, err := url.Parse("/dashboards.json")

if err != nil {
return nil, err
}
nextPath := reqURL.String()

for nextPath != "" {
resp := struct {
Dashboards []Dashboard `json:"dashboards,omitempty"`
}{}

nextPath, err = c.Do("GET", nextPath, nil, &resp)
if err != nil {
return nil, err
}

dashboards = append(dashboards, resp.Dashboards...)
}
return dashboards, nil
}

// GetDashboard returns a specific dashboard for the account.
func (c *Client) GetDashboard(id int) (*Dashboard, error) {
reqURL, err := url.Parse(fmt.Sprintf("/dashboards/%v.json", id))

if err != nil {
return nil, err
}

resp := struct {
Dashboard Dashboard `json:"dashboard,omitempty"`
}{}

_, err = c.Do("GET", reqURL.String(), nil, &resp)
if err != nil {
return nil, err
}

return &resp.Dashboard, nil
}

// ListDashboards returns all dashboards for the account.
func (c *Client) ListDashboards() ([]Dashboard, error) {
return c.queryDashboards()
}

// CreateDashboard creates dashboard given the passed configuration.
func (c *Client) CreateDashboard(dashboard Dashboard) (*Dashboard, error) {
req := struct {
Dashboard Dashboard `json:"dashboard"`
}{
Dashboard: dashboard,
}

resp := struct {
Dashboard Dashboard `json:"dashboard,omitempty"`
}{}

u := &url.URL{Path: "/dashboards.json"}
_, err := c.Do("POST", u.String(), req, &resp)
if err != nil {
return nil, err
}

return &resp.Dashboard, nil
}

// UpdateDashboard updates a dashboard given the passed configuration
func (c *Client) UpdateDashboard(dashboard Dashboard) (*Dashboard, error) {
id := dashboard.ID

req := struct {
Dashboard Dashboard `json:"dashboard"`
}{
Dashboard: dashboard,
}

resp := struct {
Dashboard Dashboard `json:"dashboard,omitempty"`
}{}

u := &url.URL{Path: fmt.Sprintf("/dashboards/%v.json", id)}
_, err := c.Do("PUT", u.String(), req, &resp)
if err != nil {
return nil, err
}

return &resp.Dashboard, nil
}

// DeleteDashboard deletes an existing dashboard given the passed configuration
func (c *Client) DeleteDashboard(id int) error {
u := &url.URL{Path: fmt.Sprintf("/dashboards/%v.json", id)}
_, err := c.Do("DELETE", u.String(), nil, nil)
return err
}
206 changes: 206 additions & 0 deletions api/dashboards_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
package api

import (
"net/http"
"testing"
)

func TestDashboards_Basic(t *testing.T) {
c := newTestAPIClient(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`
{
"dashboards": [
{
"id": 129507,
"title": "Election!",
"icon": "bar-chart",
"created_at": "2016-02-20T01:57:58Z",
"updated_at": "2016-09-27T22:59:21Z",
"visibility": "all",
"editable": "editable_by_all",
"ui_url": "https://insights.newrelic.com/accounts/1136088/dashboards/129507",
"api_url": "https://api.newrelic.com/v2/dashboards/129507",
"owner_email": "[email protected]",
"filter": null
}
]
}
`))
}))

apps, err := c.queryDashboards()
if err != nil {
t.Log(err)
t.Fatal("queryDashboards error")
}

if len(apps) == 0 {
t.Fatal("No dashboards found")
}
}

func TestGetDashboard(t *testing.T) {
c := newTestAPIClient(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`
{
"dashboard": {
"id": 1234,
"title": "Test",
"icon": "bar-chart",
"created_at": "2016-02-20T01:57:58Z",
"updated_at": "2016-09-27T22:59:21Z",
"visibility": "all",
"editable": "editable_by_all",
"ui_url": "https://insights.newrelic.com/accounts/1136088/dashboards/129507",
"api_url": "https://api.newrelic.com/v2/dashboards/129507",
"owner_email": "[email protected]",
"metadata": {
"version": 1
},
"filter": null,
"widgets": [
{
"visualization": "facet_bar_chart",
"account_id": 1,
"data": [
{
"nrql": "SELECT percentile(duration, 95) FROM SyntheticCheck FACET monitorName since 7 days ago"
}
],
"presentation": {
"title": "95th Percentile Load Time (ms)",
"notes": null,
"drilldown_dashboard_id": null
},
"layout": {
"width": 2,
"height": 1,
"row": 1,
"column": 1
}
}
]
}
}
`))
}))

dashboard, err := c.GetDashboard(1234)
if err != nil {
t.Log(err)
t.Fatal("getDashboard error")
}

if len(dashboard.Widgets) == 0 {
t.Fatal("Dashboard widgets found")
}
}

func TestCreateDashboardCondition(t *testing.T) {
c := newTestAPIClient(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`
{
"dashboard": {
"id": 1234,
"title": "Test",
"icon": "bar-chart",
"created_at": "2016-02-20T01:57:58Z",
"updated_at": "2016-09-27T22:59:21Z",
"visibility": "all",
"editable": "editable_by_all",
"ui_url": "https://insights.newrelic.com/accounts/1136088/dashboards/129507",
"api_url": "https://api.newrelic.com/v2/dashboards/129507",
"owner_email": "[email protected]",
"metadata": {
"version": 1
},
"filter": null,
"widgets": [
{
"visualization": "facet_bar_chart",
"account_id": 1,
"data": [
{
"nrql": "SELECT percentile(duration, 95) FROM SyntheticCheck FACET monitorName since 7 days ago"
}
],
"presentation": {
"title": "95th Percentile Load Time (ms)",
"notes": null,
"drilldown_dashboard_id": null
},
"layout": {
"width": 2,
"height": 1,
"row": 1,
"column": 1
}
}
]
}
}
`))
}))

dashboardWidgetLayout := DashboardWidgetLayout{
Width: 2,
Height: 1,
Row: 1,
Column: 1,
}

dashboardWidgetPresentation := DashboardWidgetPresentation{
Title: "95th Percentile Load Time (ms)",
Notes: "",
}

dashboardWidgetData := []DashboardWidgetData{
{
NRQL: "SELECT percentile(duration, 95) FROM SyntheticCheck FACET monitorName since 7 days ago",
},
}

dashboardWidgets := []DashboardWidget{
{
Visualization: "facet_bar_chart",
AccountID: 1,
Data: dashboardWidgetData,
Presentation: dashboardWidgetPresentation,
Layout: dashboardWidgetLayout,
},
}

dashboardMetadata := DashboardMetadata{
Version: 1,
}

dashboard := Dashboard{
Title: "Test",
Icon: "bar_chart",
Widgets: dashboardWidgets,
Metadata: dashboardMetadata,
}

dashboardResp, err := c.CreateDashboard(dashboard)

if err != nil {
t.Log(err)
t.Fatal("CreateDashboard error")
}
if dashboardResp == nil {
t.Log(err)
t.Fatal("CreateDashboard error")
}
if dashboard.Metadata.Version != 1 {
t.Fatal("CreateDashboard metadata version incorrect")
}
if dashboardResp.ID != 1234 {
t.Fatal("CreateDashboard ID was not parsed correctly")
}
}
49 changes: 49 additions & 0 deletions api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,3 +248,52 @@ type KeyTransaction struct {
EndUserSummary ApplicationEndUserSummary `json:"end_user_summary,omitempty"`
Links ApplicationLinks `json:"links,omitempty"`
}

// Dashboard represents information about a New Relic dashboard.
type Dashboard struct {
ID int `json:"id"`
Title string `json:"title,omitempty"`
Icon string `json:"icon,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
UpdatedAt string `json:"updated_at,omitempty"`
Visibility string `json:"visibility,omitempty"`
Editable string `json:"editable,omitempty"`
UIURL string `json:"ui_url,omitempty"`
APIRL string `json:"api_url,omitempty"`
OwnerEmail string `json:"owner_email,omitempty"`
Metadata DashboardMetadata `json:"metadata"`
Widgets []DashboardWidget `json:"widgets,omitempty"`
}

// DashboardMetadata represents metadata about the dashboard (like version)
type DashboardMetadata struct {
Version int `json:"version"`
}

// DashboardWidget represents a widget in a dashboard.
type DashboardWidget struct {
Visualization string `json:"visualization,omitempty"`
AccountID int `json:"account_id,omitempty"`
Data []DashboardWidgetData `json:"data,omitempty"`
Presentation DashboardWidgetPresentation `json:"presentation,omitempty"`
Layout DashboardWidgetLayout `json:"layout,omitempty"`
}

// DashboardWidgetData represents the data backing a dashboard widget.
type DashboardWidgetData struct {
NRQL string `json:"nrql,omitempty"`
}

// DashboardWidgetPresentation representations the visual presentation of a dashboard widget
type DashboardWidgetPresentation struct {
Title string `json:"title,omitempty"`
Notes string `json:"notes,omitempty"`
}

// DashboardWidgetLayout represents the layout of a widget in a dashboard.
type DashboardWidgetLayout struct {
Width int `json:"width"`
Height int `json:"height"`
Row int `json:"row"`
Column int `json:"column"`
}
Loading

0 comments on commit 6591d69

Please sign in to comment.