diff --git a/bolt/dashboard.go b/bolt/dashboard.go index afd2832095..2cbe912a9d 100644 --- a/bolt/dashboard.go +++ b/bolt/dashboard.go @@ -356,6 +356,10 @@ func (c *Client) forEachDashboard(ctx context.Context, tx *bolt.Tx, fn func(*pla // UpdateDashboard updates a dashboard according the parameters set on upd. func (c *Client) UpdateDashboard(ctx context.Context, id platform.ID, upd platform.DashboardUpdate) (*platform.Dashboard, error) { + if err := upd.Valid(); err != nil { + return nil, err + } + var d *platform.Dashboard err := c.db.Update(func(tx *bolt.Tx) error { dash, err := c.updateDashboard(ctx, tx, id, upd) diff --git a/dashboard.go b/dashboard.go index 04d37826e4..c09b540a9c 100644 --- a/dashboard.go +++ b/dashboard.go @@ -45,9 +45,10 @@ type DashboardService interface { // Dashboard represents all visual and query data for a dashboard type Dashboard struct { - ID ID `json:"id,omitempty"` - Name string `json:"name"` - Cells []*Cell `json:"cells"` + ID ID `json:"id,omitempty"` + Name string `json:"name"` + Description string `json:"description"` + Cells []*Cell `json:"cells"` } // Cell holds positional information about a cell on dashboard and a reference to a cell. @@ -67,14 +68,8 @@ type DashboardFilter struct { // DashboardUpdate is the patch structure for a dashboard. type DashboardUpdate struct { - Name *string `json:"name"` -} - -// AddDashboardCellOptions are options for adding a dashboard. -type AddDashboardCellOptions struct { - // UsingView specifies the view that should be used as a template - // for the new cells view. - UsingView ID + Name *string `json:"name"` + Description *string `json:"description"` } // Apply applies an update to a dashboard. @@ -83,9 +78,29 @@ func (u DashboardUpdate) Apply(d *Dashboard) error { d.Name = *u.Name } + if u.Description != nil { + d.Description = *u.Description + } + return nil } +// Valid returns an error if the dashboard update is invalid. +func (u DashboardUpdate) Valid() error { + if u.Name == nil && u.Description == nil { + return fmt.Errorf("must update at least one attribute") + } + + return nil +} + +// AddDashboardCellOptions are options for adding a dashboard. +type AddDashboardCellOptions struct { + // UsingView specifies the view that should be used as a template + // for the new cells view. + UsingView ID +} + // CellUpdate is the patch structure for a cell. type CellUpdate struct { X *int32 `json:"x"` @@ -119,12 +134,3 @@ func (u CellUpdate) Apply(c *Cell) error { return nil } - -// Valid returns an error if the dashboard update is invalid. -func (u DashboardUpdate) Valid() error { - if u.Name == nil { - return fmt.Errorf("must update at least one attribute") - } - - return nil -} diff --git a/http/dashboard_test.go b/http/dashboard_test.go index 0b97028ffa..1dc5633a1b 100644 --- a/http/dashboard_test.go +++ b/http/dashboard_test.go @@ -43,8 +43,9 @@ func TestService_handleGetDashboards(t *testing.T) { FindDashboardsF: func(ctx context.Context, filter platform.DashboardFilter) ([]*platform.Dashboard, int, error) { return []*platform.Dashboard{ { - ID: platformtesting.MustIDBase16("da7aba5e5d81e550"), - Name: "hello", + ID: platformtesting.MustIDBase16("da7aba5e5d81e550"), + Name: "hello", + Description: "oh hello there!", Cells: []*platform.Cell{ { ID: platformtesting.MustIDBase16("da7aba5e5d81e550"), @@ -77,6 +78,7 @@ func TestService_handleGetDashboards(t *testing.T) { { "id": "da7aba5e5d81e550", "name": "hello", + "description": "oh hello there!", "cells": [ { "id": "da7aba5e5d81e550", @@ -99,6 +101,7 @@ func TestService_handleGetDashboards(t *testing.T) { { "id": "0ca2204eca2204e0", "name": "example", + "description": "", "cells": [], "links": { "self": "/api/v2/dashboards/0ca2204eca2204e0", @@ -227,6 +230,7 @@ func TestService_handleGetDashboard(t *testing.T) { { "id": "020f755c3c082000", "name": "hello", + "description": "", "cells": [ { "id": "da7aba5e5d81e550", @@ -337,8 +341,9 @@ func TestService_handlePostDashboard(t *testing.T) { }, args: args{ dashboard: &platform.Dashboard{ - ID: platformtesting.MustIDBase16("020f755c3c082000"), - Name: "hello", + ID: platformtesting.MustIDBase16("020f755c3c082000"), + Name: "hello", + Description: "howdy there", Cells: []*platform.Cell{ { ID: platformtesting.MustIDBase16("da7aba5e5d81e550"), @@ -358,6 +363,7 @@ func TestService_handlePostDashboard(t *testing.T) { { "id": "020f755c3c082000", "name": "hello", + "description": "howdy there", "cells": [ { "id": "da7aba5e5d81e550", @@ -575,6 +581,7 @@ func TestService_handlePatchDashboard(t *testing.T) { { "id": "020f755c3c082000", "name": "example", + "description": "", "cells": [ { "id": "da7aba5e5d81e550", diff --git a/http/swagger.yml b/http/swagger.yml index c9296d5d82..cee6351e07 100644 --- a/http/swagger.yml +++ b/http/swagger.yml @@ -4394,6 +4394,10 @@ components: type: string name: type: string + description: user-facing name of the dashboard + description: + type: string + description: user-facing description of the dashboard cells: $ref: "#/components/schemas/Cells" Dashboards: diff --git a/inmem/dashboard.go b/inmem/dashboard.go index ca6b0a0e54..8d0652948d 100644 --- a/inmem/dashboard.go +++ b/inmem/dashboard.go @@ -83,17 +83,21 @@ func (s *Service) PutDashboard(ctx context.Context, o *platform.Dashboard) error // UpdateDashboard implements platform.DashboardService interface. func (s *Service) UpdateDashboard(ctx context.Context, id platform.ID, upd platform.DashboardUpdate) (*platform.Dashboard, error) { - o, err := s.FindDashboardByID(ctx, id) + if err := upd.Valid(); err != nil { + return nil, err + } + + d, err := s.FindDashboardByID(ctx, id) if err != nil { return nil, err } - if upd.Name != nil { - o.Name = *upd.Name + if err := upd.Apply(d); err != nil { + return nil, err } - s.dashboardKV.Store(o.ID.String(), o) - return o, nil + s.dashboardKV.Store(d.ID.String(), d) + return d, nil } // DeleteDashboard implements platform.DashboardService interface. @@ -105,6 +109,7 @@ func (s *Service) DeleteDashboard(ctx context.Context, id platform.ID) error { return nil } +// AddDashboardCell adds a new cell to the dashboard. func (s *Service) AddDashboardCell(ctx context.Context, id platform.ID, cell *platform.Cell, opts platform.AddDashboardCellOptions) error { d, err := s.FindDashboardByID(ctx, id) if err != nil { @@ -119,6 +124,7 @@ func (s *Service) AddDashboardCell(ctx context.Context, id platform.ID, cell *pl return s.PutDashboard(ctx, d) } +// PutDashboardCell replaces a dashboad cell with the cell contents. func (s *Service) PutDashboardCell(ctx context.Context, id platform.ID, cell *platform.Cell) error { d, err := s.FindDashboardByID(ctx, id) if err != nil { @@ -134,6 +140,7 @@ func (s *Service) PutDashboardCell(ctx context.Context, id platform.ID, cell *pl return s.PutDashboard(ctx, d) } +// RemoveDashboardCell removes a dashboard cell from the dashboard. func (s *Service) RemoveDashboardCell(ctx context.Context, dashboardID platform.ID, cellID platform.ID) error { d, err := s.FindDashboardByID(ctx, dashboardID) if err != nil { @@ -160,6 +167,7 @@ func (s *Service) RemoveDashboardCell(ctx context.Context, dashboardID platform. } +// UpdateDashboardCell will remove a cell from a dashboard. func (s *Service) UpdateDashboardCell(ctx context.Context, dashboardID platform.ID, cellID platform.ID, upd platform.CellUpdate) (*platform.Cell, error) { d, err := s.FindDashboardByID(ctx, dashboardID) if err != nil { @@ -190,6 +198,7 @@ func (s *Service) UpdateDashboardCell(ctx context.Context, dashboardID platform. return cell, nil } +// ReplaceDashboardCells replaces many dashboard cells. func (s *Service) ReplaceDashboardCells(ctx context.Context, id platform.ID, cs []*platform.Cell) error { d, err := s.FindDashboardByID(ctx, id) if err != nil { diff --git a/inmem/dashboard_test.go b/inmem/dashboard_test.go index a27888ff8c..3641b9a665 100644 --- a/inmem/dashboard_test.go +++ b/inmem/dashboard_test.go @@ -11,7 +11,7 @@ import ( func initDashboardService(f platformtesting.DashboardFields, t *testing.T) (platform.DashboardService, func()) { s := NewService() s.IDGenerator = f.IDGenerator - ctx := context.TODO() + ctx := context.Background() for _, b := range f.Dashboards { if err := s.PutDashboard(ctx, b); err != nil { t.Fatalf("failed to populate Dashboards") diff --git a/testing/dashboards.go b/testing/dashboards.go index fb90b17065..b8e6b96227 100644 --- a/testing/dashboards.go +++ b/testing/dashboards.go @@ -665,9 +665,9 @@ func UpdateDashboard( t *testing.T, ) { type args struct { - name string - id platform.ID - retention int + name string + description string + id platform.ID } type wants struct { err error @@ -705,6 +705,59 @@ func UpdateDashboard( }, }, }, + { + name: "update description", + fields: DashboardFields{ + Dashboards: []*platform.Dashboard{ + { + ID: MustIDBase16(dashOneID), + Name: "dashboard1", + }, + { + ID: MustIDBase16(dashTwoID), + Name: "dashboard2", + }, + }, + }, + args: args{ + id: MustIDBase16(dashOneID), + description: "changed", + }, + wants: wants{ + dashboard: &platform.Dashboard{ + ID: MustIDBase16(dashOneID), + Name: "dashboard1", + Description: "changed", + }, + }, + }, + { + name: "update description and name", + fields: DashboardFields{ + Dashboards: []*platform.Dashboard{ + { + ID: MustIDBase16(dashOneID), + Name: "dashboard1", + }, + { + ID: MustIDBase16(dashTwoID), + Name: "dashboard2", + }, + }, + }, + args: args{ + id: MustIDBase16(dashOneID), + description: "changed", + name: "changed", + }, + wants: wants{ + dashboard: &platform.Dashboard{ + ID: MustIDBase16(dashOneID), + Name: "changed", + Description: "changed", + }, + }, + }, } for _, tt := range tests { @@ -717,6 +770,9 @@ func UpdateDashboard( if tt.args.name != "" { upd.Name = &tt.args.name } + if tt.args.description != "" { + upd.Description = &tt.args.description + } dashboard, err := s.UpdateDashboard(ctx, tt.args.id, upd) if (err != nil) != (tt.wants.err != nil) {