github.com/influxdata/influxdb/v2@v2.7.6/dashboard.go (about)

     1  package influxdb
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"net/url"
     8  	"sort"
     9  	"time"
    10  
    11  	"github.com/influxdata/influxdb/v2/kit/platform"
    12  	"github.com/influxdata/influxdb/v2/kit/platform/errors"
    13  )
    14  
    15  // ErrDashboardNotFound is the error msg for a missing dashboard.
    16  const ErrDashboardNotFound = "dashboard not found"
    17  
    18  // ErrCellNotFound is the error msg for a missing cell.
    19  const ErrCellNotFound = "cell not found"
    20  
    21  // ErrViewNotFound is the error msg for a missing View.
    22  const ErrViewNotFound = "view not found"
    23  
    24  // ops for dashboard service.
    25  const (
    26  	OpFindDashboardByID       = "FindDashboardByID"
    27  	OpFindDashboards          = "FindDashboards"
    28  	OpCreateDashboard         = "CreateDashboard"
    29  	OpUpdateDashboard         = "UpdateDashboard"
    30  	OpAddDashboardCell        = "AddDashboardCell"
    31  	OpRemoveDashboardCell     = "RemoveDashboardCell"
    32  	OpUpdateDashboardCell     = "UpdateDashboardCell"
    33  	OpGetDashboardCellView    = "GetDashboardCellView"
    34  	OpUpdateDashboardCellView = "UpdateDashboardCellView"
    35  	OpDeleteDashboard         = "DeleteDashboard"
    36  	OpReplaceDashboardCells   = "ReplaceDashboardCells"
    37  )
    38  
    39  // DashboardService represents a service for managing dashboard data.
    40  type DashboardService interface {
    41  	// FindDashboardByID returns a single dashboard by ID.
    42  	FindDashboardByID(ctx context.Context, id platform.ID) (*Dashboard, error)
    43  
    44  	// FindDashboards returns a list of dashboards that match filter and the total count of matching dashboards.
    45  	// Additional options provide pagination & sorting.
    46  	FindDashboards(ctx context.Context, filter DashboardFilter, opts FindOptions) ([]*Dashboard, int, error)
    47  
    48  	// CreateDashboard creates a new dashboard and sets b.ID with the new identifier.
    49  	CreateDashboard(ctx context.Context, b *Dashboard) error
    50  
    51  	// UpdateDashboard updates a single dashboard with changeset.
    52  	// Returns the new dashboard state after update.
    53  	UpdateDashboard(ctx context.Context, id platform.ID, upd DashboardUpdate) (*Dashboard, error)
    54  
    55  	// AddDashboardCell adds a cell to a dashboard.
    56  	AddDashboardCell(ctx context.Context, id platform.ID, c *Cell, opts AddDashboardCellOptions) error
    57  
    58  	// RemoveDashboardCell removes a dashboard.
    59  	RemoveDashboardCell(ctx context.Context, dashboardID, cellID platform.ID) error
    60  
    61  	// UpdateDashboardCell replaces the dashboard cell with the provided ID.
    62  	UpdateDashboardCell(ctx context.Context, dashboardID, cellID platform.ID, upd CellUpdate) (*Cell, error)
    63  
    64  	// GetDashboardCellView retrieves a dashboard cells view.
    65  	GetDashboardCellView(ctx context.Context, dashboardID, cellID platform.ID) (*View, error)
    66  
    67  	// UpdateDashboardCellView retrieves a dashboard cells view.
    68  	UpdateDashboardCellView(ctx context.Context, dashboardID, cellID platform.ID, upd ViewUpdate) (*View, error)
    69  
    70  	// DeleteDashboard removes a dashboard by ID.
    71  	DeleteDashboard(ctx context.Context, id platform.ID) error
    72  
    73  	// ReplaceDashboardCells replaces all cells in a dashboard
    74  	ReplaceDashboardCells(ctx context.Context, id platform.ID, c []*Cell) error
    75  }
    76  
    77  // Dashboard represents all visual and query data for a dashboard.
    78  type Dashboard struct {
    79  	ID             platform.ID   `json:"id,omitempty"`
    80  	OrganizationID platform.ID   `json:"orgID,omitempty"`
    81  	Name           string        `json:"name"`
    82  	Description    string        `json:"description"`
    83  	Cells          []*Cell       `json:"cells"`
    84  	Meta           DashboardMeta `json:"meta"`
    85  	OwnerID        *platform.ID  `json:"owner,omitempty"`
    86  }
    87  
    88  // DashboardMeta contains meta information about dashboards
    89  type DashboardMeta struct {
    90  	CreatedAt time.Time `json:"createdAt"`
    91  	UpdatedAt time.Time `json:"updatedAt"`
    92  }
    93  
    94  // DefaultDashboardFindOptions are the default find options for dashboards
    95  var DefaultDashboardFindOptions = FindOptions{
    96  	SortBy: "ID",
    97  }
    98  
    99  // SortDashboards sorts a slice of dashboards by a field.
   100  func SortDashboards(opts FindOptions, ds []*Dashboard) {
   101  	var sorter func(i, j int) bool
   102  	switch opts.SortBy {
   103  	case "CreatedAt":
   104  		sorter = func(i, j int) bool {
   105  			return ds[j].Meta.CreatedAt.After(ds[i].Meta.CreatedAt)
   106  		}
   107  	case "UpdatedAt":
   108  		sorter = func(i, j int) bool {
   109  			return ds[j].Meta.UpdatedAt.After(ds[i].Meta.UpdatedAt)
   110  		}
   111  	case "Name":
   112  		sorter = func(i, j int) bool {
   113  			return ds[i].Name < ds[j].Name
   114  		}
   115  	default:
   116  		sorter = func(i, j int) bool {
   117  			if opts.Descending {
   118  				return ds[i].ID > ds[j].ID
   119  			}
   120  			return ds[i].ID < ds[j].ID
   121  		}
   122  	}
   123  
   124  	sort.Slice(ds, sorter)
   125  }
   126  
   127  // Cell holds positional information about a cell on dashboard and a reference to a cell.
   128  type Cell struct {
   129  	ID platform.ID `json:"id,omitempty"`
   130  	CellProperty
   131  	View *View `json:"-"`
   132  }
   133  
   134  // Marshals the cell
   135  func (c *Cell) MarshalJSON() ([]byte, error) {
   136  	type resp struct {
   137  		ID             *platform.ID    `json:"id,omitempty"`
   138  		Name           string          `json:"name,omitempty"`
   139  		ViewProperties json.RawMessage `json:"properties,omitempty"`
   140  		CellProperty
   141  	}
   142  	response := resp{
   143  		CellProperty: c.CellProperty,
   144  	}
   145  	if c.ID != 0 {
   146  		response.ID = &c.ID
   147  	}
   148  	if c.View != nil {
   149  		response.Name = c.View.Name
   150  		rawJSON, err := MarshalViewPropertiesJSON(c.View.Properties)
   151  		if err != nil {
   152  			return nil, err
   153  		}
   154  		response.ViewProperties = rawJSON
   155  	}
   156  	return json.Marshal(response)
   157  }
   158  
   159  func (c *Cell) UnmarshalJSON(b []byte) error {
   160  	var newCell struct {
   161  		ID             platform.ID     `json:"id,omitempty"`
   162  		Name           string          `json:"name,omitempty"`
   163  		ViewProperties json.RawMessage `json:"properties,omitempty"`
   164  		CellProperty
   165  	}
   166  	if err := json.Unmarshal(b, &newCell); err != nil {
   167  		return err
   168  	}
   169  
   170  	c.ID = newCell.ID
   171  	c.CellProperty = newCell.CellProperty
   172  
   173  	if newCell.Name != "" {
   174  		if c.View == nil {
   175  			c.View = new(View)
   176  		}
   177  		c.View.Name = newCell.Name
   178  	}
   179  
   180  	props, err := UnmarshalViewPropertiesJSON(newCell.ViewProperties)
   181  	if err == nil {
   182  		if c.View == nil {
   183  			c.View = new(View)
   184  		}
   185  		c.View.Properties = props
   186  	}
   187  
   188  	return nil
   189  }
   190  
   191  // CellProperty contains the properties of a cell.
   192  type CellProperty struct {
   193  	X int32 `json:"x"`
   194  	Y int32 `json:"y"`
   195  	W int32 `json:"w"`
   196  	H int32 `json:"h"`
   197  }
   198  
   199  // DashboardFilter is a filter for dashboards.
   200  type DashboardFilter struct {
   201  	IDs            []*platform.ID
   202  	OrganizationID *platform.ID
   203  	Organization   *string
   204  	OwnerID        *platform.ID
   205  }
   206  
   207  // QueryParams turns a dashboard filter into query params
   208  //
   209  // It implements PagingFilter.
   210  func (f DashboardFilter) QueryParams() map[string][]string {
   211  	qp := url.Values{}
   212  	for _, id := range f.IDs {
   213  		if id != nil {
   214  			qp.Add("id", id.String())
   215  		}
   216  	}
   217  
   218  	if f.OrganizationID != nil {
   219  		qp.Add("orgID", f.OrganizationID.String())
   220  	}
   221  
   222  	if f.Organization != nil {
   223  		qp.Add("org", *f.Organization)
   224  	}
   225  
   226  	if f.OwnerID != nil {
   227  		qp.Add("owner", f.OwnerID.String())
   228  	}
   229  
   230  	return qp
   231  }
   232  
   233  // DashboardUpdate is the patch structure for a dashboard.
   234  type DashboardUpdate struct {
   235  	Name        *string  `json:"name"`
   236  	Description *string  `json:"description"`
   237  	Cells       *[]*Cell `json:"cells"`
   238  }
   239  
   240  // Apply applies an update to a dashboard.
   241  func (u DashboardUpdate) Apply(d *Dashboard) error {
   242  	if u.Name != nil {
   243  		d.Name = *u.Name
   244  	}
   245  
   246  	if u.Description != nil {
   247  		d.Description = *u.Description
   248  	}
   249  
   250  	if u.Cells != nil {
   251  		d.Cells = *u.Cells
   252  	}
   253  
   254  	return nil
   255  }
   256  
   257  // Valid returns an error if the dashboard update is invalid.
   258  func (u DashboardUpdate) Valid() *errors.Error {
   259  	if u.Name == nil && u.Description == nil {
   260  		return &errors.Error{
   261  			Code: errors.EInvalid,
   262  			Msg:  "must update at least one attribute",
   263  		}
   264  	}
   265  
   266  	return nil
   267  }
   268  
   269  // AddDashboardCellOptions are options for adding a dashboard.
   270  type AddDashboardCellOptions struct {
   271  	View *View
   272  }
   273  
   274  // CellUpdate is the patch structure for a cell.
   275  type CellUpdate struct {
   276  	X *int32 `json:"x"`
   277  	Y *int32 `json:"y"`
   278  	W *int32 `json:"w"`
   279  	H *int32 `json:"h"`
   280  }
   281  
   282  // Apply applies an update to a Cell.
   283  func (u CellUpdate) Apply(c *Cell) error {
   284  	if u.X != nil {
   285  		c.X = *u.X
   286  	}
   287  
   288  	if u.Y != nil {
   289  		c.Y = *u.Y
   290  	}
   291  
   292  	if u.W != nil {
   293  		c.W = *u.W
   294  	}
   295  
   296  	if u.H != nil {
   297  		c.H = *u.H
   298  	}
   299  
   300  	return nil
   301  }
   302  
   303  // Valid returns an error if the cell update is invalid.
   304  func (u CellUpdate) Valid() *errors.Error {
   305  	if u.H == nil && u.W == nil && u.Y == nil && u.X == nil {
   306  		return &errors.Error{
   307  			Code: errors.EInvalid,
   308  			Msg:  "must update at least one attribute",
   309  		}
   310  	}
   311  
   312  	return nil
   313  }
   314  
   315  // ViewUpdate is a struct for updating Views.
   316  type ViewUpdate struct {
   317  	ViewContentsUpdate
   318  	Properties ViewProperties
   319  }
   320  
   321  // Valid validates the update struct. It expects minimal values to be set.
   322  func (u ViewUpdate) Valid() *errors.Error {
   323  	_, ok := u.Properties.(EmptyViewProperties)
   324  	if u.Name == nil && ok {
   325  		return &errors.Error{
   326  			Code: errors.EInvalid,
   327  			Msg:  "expected at least one attribute to be updated",
   328  		}
   329  	}
   330  
   331  	return nil
   332  }
   333  
   334  // Apply updates a view with the view updates properties.
   335  func (u ViewUpdate) Apply(v *View) error {
   336  	if err := u.Valid(); err != nil {
   337  		return err
   338  	}
   339  
   340  	if u.Name != nil {
   341  		v.Name = *u.Name
   342  	}
   343  
   344  	if u.Properties != nil {
   345  		v.Properties = u.Properties
   346  	}
   347  
   348  	return nil
   349  }
   350  
   351  // ViewContentsUpdate is a struct for updating the non properties content of a View.
   352  type ViewContentsUpdate struct {
   353  	Name *string `json:"name"`
   354  }
   355  
   356  // ViewFilter represents a set of filter that restrict the returned results.
   357  type ViewFilter struct {
   358  	ID    *platform.ID
   359  	Types []string
   360  }
   361  
   362  // View holds positional and visual information for a View.
   363  type View struct {
   364  	ViewContents
   365  	Properties ViewProperties
   366  }
   367  
   368  // ViewContents is the id and name of a specific view.
   369  type ViewContents struct {
   370  	ID   platform.ID `json:"id,omitempty"`
   371  	Name string      `json:"name"`
   372  }
   373  
   374  // Values for all supported view property types.
   375  const (
   376  	ViewPropertyTypeCheck              = "check"
   377  	ViewPropertyTypeGauge              = "gauge"
   378  	ViewPropertyTypeHeatMap            = "heatmap"
   379  	ViewPropertyTypeHistogram          = "histogram"
   380  	ViewPropertyTypeLogViewer          = "log-viewer"
   381  	ViewPropertyTypeMarkdown           = "markdown"
   382  	ViewPropertyTypeScatter            = "scatter"
   383  	ViewPropertyTypeSingleStat         = "single-stat"
   384  	ViewPropertyTypeSingleStatPlusLine = "line-plus-single-stat"
   385  	ViewPropertyTypeTable              = "table"
   386  	ViewPropertyTypeXY                 = "xy"
   387  	ViewPropertyTypeMosaic             = "mosaic"
   388  	ViewPropertyTypeBand               = "band"
   389  	ViewPropertyTypeGeo                = "geo"
   390  )
   391  
   392  // ViewProperties is used to mark other structures as conforming to a View.
   393  type ViewProperties interface {
   394  	viewProperties()
   395  	GetType() string
   396  }
   397  
   398  // EmptyViewProperties is visualization that has no values
   399  type EmptyViewProperties struct{}
   400  
   401  func (v EmptyViewProperties) viewProperties() {}
   402  
   403  func (v EmptyViewProperties) GetType() string { return "" }
   404  
   405  // UnmarshalViewPropertiesJSON unmarshals JSON bytes into a ViewProperties.
   406  func UnmarshalViewPropertiesJSON(b []byte) (ViewProperties, error) {
   407  	var v struct {
   408  		B json.RawMessage `json:"properties"`
   409  	}
   410  
   411  	if err := json.Unmarshal(b, &v); err != nil {
   412  		return nil, err
   413  	}
   414  
   415  	if len(v.B) == 0 {
   416  		// Then there wasn't any visualization field, so there's no need unmarshal it
   417  		return EmptyViewProperties{}, nil
   418  	}
   419  
   420  	var t struct {
   421  		Shape string `json:"shape"`
   422  		Type  string `json:"type"`
   423  	}
   424  
   425  	if err := json.Unmarshal(v.B, &t); err != nil {
   426  		return nil, err
   427  	}
   428  
   429  	var vis ViewProperties
   430  	switch t.Shape {
   431  	case "chronograf-v2":
   432  		switch t.Type {
   433  		case ViewPropertyTypeCheck:
   434  			var cv CheckViewProperties
   435  			if err := json.Unmarshal(v.B, &cv); err != nil {
   436  				return nil, err
   437  			}
   438  			vis = cv
   439  		case ViewPropertyTypeXY:
   440  			var xyv XYViewProperties
   441  			if err := json.Unmarshal(v.B, &xyv); err != nil {
   442  				return nil, err
   443  			}
   444  			vis = xyv
   445  		case ViewPropertyTypeSingleStat:
   446  			var ssv SingleStatViewProperties
   447  			if err := json.Unmarshal(v.B, &ssv); err != nil {
   448  				return nil, err
   449  			}
   450  			vis = ssv
   451  		case ViewPropertyTypeGauge:
   452  			var gv GaugeViewProperties
   453  			if err := json.Unmarshal(v.B, &gv); err != nil {
   454  				return nil, err
   455  			}
   456  			vis = gv
   457  		case ViewPropertyTypeGeo:
   458  			var gvw GeoViewProperties
   459  			if err := json.Unmarshal(v.B, &gvw); err != nil {
   460  				return nil, err
   461  			}
   462  			vis = gvw
   463  		case ViewPropertyTypeTable:
   464  			var tv TableViewProperties
   465  			if err := json.Unmarshal(v.B, &tv); err != nil {
   466  				return nil, err
   467  			}
   468  			vis = tv
   469  		case ViewPropertyTypeMarkdown:
   470  			var mv MarkdownViewProperties
   471  			if err := json.Unmarshal(v.B, &mv); err != nil {
   472  				return nil, err
   473  			}
   474  			vis = mv
   475  		case ViewPropertyTypeLogViewer: // happens in log viewer stays in log viewer.
   476  			var lv LogViewProperties
   477  			if err := json.Unmarshal(v.B, &lv); err != nil {
   478  				return nil, err
   479  			}
   480  			vis = lv
   481  		case ViewPropertyTypeSingleStatPlusLine:
   482  			var lv LinePlusSingleStatProperties
   483  			if err := json.Unmarshal(v.B, &lv); err != nil {
   484  				return nil, err
   485  			}
   486  			vis = lv
   487  		case ViewPropertyTypeHistogram:
   488  			var hv HistogramViewProperties
   489  			if err := json.Unmarshal(v.B, &hv); err != nil {
   490  				return nil, err
   491  			}
   492  			vis = hv
   493  		case ViewPropertyTypeHeatMap:
   494  			var hv HeatmapViewProperties
   495  			if err := json.Unmarshal(v.B, &hv); err != nil {
   496  				return nil, err
   497  			}
   498  			vis = hv
   499  		case ViewPropertyTypeScatter:
   500  			var sv ScatterViewProperties
   501  			if err := json.Unmarshal(v.B, &sv); err != nil {
   502  				return nil, err
   503  			}
   504  			vis = sv
   505  		case ViewPropertyTypeMosaic:
   506  			var mv MosaicViewProperties
   507  			if err := json.Unmarshal(v.B, &mv); err != nil {
   508  				return nil, err
   509  			}
   510  			vis = mv
   511  		case ViewPropertyTypeBand:
   512  			var bv BandViewProperties
   513  			if err := json.Unmarshal(v.B, &bv); err != nil {
   514  				return nil, err
   515  			}
   516  			vis = bv
   517  		}
   518  	case "empty":
   519  		var ev EmptyViewProperties
   520  		if err := json.Unmarshal(v.B, &ev); err != nil {
   521  			return nil, err
   522  		}
   523  		vis = ev
   524  	default:
   525  		return nil, fmt.Errorf("unknown shape %v", t.Shape)
   526  	}
   527  
   528  	return vis, nil
   529  }
   530  
   531  // MarshalViewPropertiesJSON encodes a view into JSON bytes.
   532  func MarshalViewPropertiesJSON(v ViewProperties) ([]byte, error) {
   533  	var s interface{}
   534  	switch vis := v.(type) {
   535  	case SingleStatViewProperties:
   536  		s = struct {
   537  			Shape string `json:"shape"`
   538  			SingleStatViewProperties
   539  		}{
   540  			Shape: "chronograf-v2",
   541  
   542  			SingleStatViewProperties: vis,
   543  		}
   544  	case TableViewProperties:
   545  		s = struct {
   546  			Shape string `json:"shape"`
   547  			TableViewProperties
   548  		}{
   549  			Shape: "chronograf-v2",
   550  
   551  			TableViewProperties: vis,
   552  		}
   553  	case GaugeViewProperties:
   554  		s = struct {
   555  			Shape string `json:"shape"`
   556  			GaugeViewProperties
   557  		}{
   558  			Shape: "chronograf-v2",
   559  
   560  			GaugeViewProperties: vis,
   561  		}
   562  	case GeoViewProperties:
   563  		s = struct {
   564  			Shape string `json:"shape"`
   565  			GeoViewProperties
   566  		}{
   567  			Shape:             "chronograf-v2",
   568  			GeoViewProperties: vis,
   569  		}
   570  	case XYViewProperties:
   571  		s = struct {
   572  			Shape string `json:"shape"`
   573  			XYViewProperties
   574  		}{
   575  			Shape: "chronograf-v2",
   576  
   577  			XYViewProperties: vis,
   578  		}
   579  	case BandViewProperties:
   580  		s = struct {
   581  			Shape string `json:"shape"`
   582  			BandViewProperties
   583  		}{
   584  			Shape: "chronograf-v2",
   585  
   586  			BandViewProperties: vis,
   587  		}
   588  	case LinePlusSingleStatProperties:
   589  		s = struct {
   590  			Shape string `json:"shape"`
   591  			LinePlusSingleStatProperties
   592  		}{
   593  			Shape: "chronograf-v2",
   594  
   595  			LinePlusSingleStatProperties: vis,
   596  		}
   597  	case HistogramViewProperties:
   598  		s = struct {
   599  			Shape string `json:"shape"`
   600  			HistogramViewProperties
   601  		}{
   602  			Shape: "chronograf-v2",
   603  
   604  			HistogramViewProperties: vis,
   605  		}
   606  	case HeatmapViewProperties:
   607  		s = struct {
   608  			Shape string `json:"shape"`
   609  			HeatmapViewProperties
   610  		}{
   611  			Shape: "chronograf-v2",
   612  
   613  			HeatmapViewProperties: vis,
   614  		}
   615  	case ScatterViewProperties:
   616  		s = struct {
   617  			Shape string `json:"shape"`
   618  			ScatterViewProperties
   619  		}{
   620  			Shape: "chronograf-v2",
   621  
   622  			ScatterViewProperties: vis,
   623  		}
   624  	case MosaicViewProperties:
   625  		s = struct {
   626  			Shape string `json:"shape"`
   627  			MosaicViewProperties
   628  		}{
   629  			Shape: "chronograf-v2",
   630  
   631  			MosaicViewProperties: vis,
   632  		}
   633  	case MarkdownViewProperties:
   634  		s = struct {
   635  			Shape string `json:"shape"`
   636  			MarkdownViewProperties
   637  		}{
   638  			Shape: "chronograf-v2",
   639  
   640  			MarkdownViewProperties: vis,
   641  		}
   642  	case LogViewProperties:
   643  		s = struct {
   644  			Shape string `json:"shape"`
   645  			LogViewProperties
   646  		}{
   647  			Shape:             "chronograf-v2",
   648  			LogViewProperties: vis,
   649  		}
   650  	case CheckViewProperties:
   651  		s = struct {
   652  			Shape string `json:"shape"`
   653  			CheckViewProperties
   654  		}{
   655  			Shape: "chronograf-v2",
   656  
   657  			CheckViewProperties: vis,
   658  		}
   659  	default:
   660  		s = struct {
   661  			Shape string `json:"shape"`
   662  			EmptyViewProperties
   663  		}{
   664  			Shape:               "empty",
   665  			EmptyViewProperties: EmptyViewProperties{},
   666  		}
   667  	}
   668  	return json.Marshal(s)
   669  }
   670  
   671  // MarshalJSON encodes a view to JSON bytes.
   672  func (v View) MarshalJSON() ([]byte, error) {
   673  	viewProperties, err := MarshalViewPropertiesJSON(v.Properties)
   674  	if err != nil {
   675  		return nil, err
   676  	}
   677  
   678  	return json.Marshal(struct {
   679  		ViewContents
   680  		ViewProperties json.RawMessage `json:"properties"`
   681  	}{
   682  		ViewContents:   v.ViewContents,
   683  		ViewProperties: viewProperties,
   684  	})
   685  }
   686  
   687  // UnmarshalJSON decodes JSON bytes into the corresponding view type (those that implement ViewProperties).
   688  func (c *View) UnmarshalJSON(b []byte) error {
   689  	if err := json.Unmarshal(b, &c.ViewContents); err != nil {
   690  		return err
   691  	}
   692  
   693  	v, err := UnmarshalViewPropertiesJSON(b)
   694  	if err != nil {
   695  		return err
   696  	}
   697  	c.Properties = v
   698  	return nil
   699  }
   700  
   701  // UnmarshalJSON decodes JSON bytes into the corresponding view update type (those that implement ViewProperties).
   702  func (u *ViewUpdate) UnmarshalJSON(b []byte) error {
   703  	if err := json.Unmarshal(b, &u.ViewContentsUpdate); err != nil {
   704  		return err
   705  	}
   706  
   707  	v, err := UnmarshalViewPropertiesJSON(b)
   708  	if err != nil {
   709  		return err
   710  	}
   711  	u.Properties = v
   712  	return nil
   713  }
   714  
   715  // MarshalJSON encodes a view to JSON bytes.
   716  func (u ViewUpdate) MarshalJSON() ([]byte, error) {
   717  	vis, err := MarshalViewPropertiesJSON(u.Properties)
   718  	if err != nil {
   719  		return nil, err
   720  	}
   721  
   722  	return json.Marshal(struct {
   723  		ViewContentsUpdate
   724  		ViewProperties json.RawMessage `json:"properties,omitempty"`
   725  	}{
   726  		ViewContentsUpdate: u.ViewContentsUpdate,
   727  		ViewProperties:     vis,
   728  	})
   729  }
   730  
   731  // LinePlusSingleStatProperties represents options for line plus single stat view in Chronograf
   732  type LinePlusSingleStatProperties struct {
   733  	Queries                    []DashboardQuery `json:"queries"`
   734  	Axes                       map[string]Axis  `json:"axes"`
   735  	Type                       string           `json:"type"`
   736  	StaticLegend               StaticLegend     `json:"staticLegend"`
   737  	ViewColors                 []ViewColor      `json:"colors"`
   738  	Prefix                     string           `json:"prefix"`
   739  	Suffix                     string           `json:"suffix"`
   740  	DecimalPlaces              DecimalPlaces    `json:"decimalPlaces"`
   741  	Note                       string           `json:"note"`
   742  	ShowNoteWhenEmpty          bool             `json:"showNoteWhenEmpty"`
   743  	XColumn                    string           `json:"xColumn"`
   744  	GenerateXAxisTicks         []string         `json:"generateXAxisTicks"`
   745  	XTotalTicks                int              `json:"xTotalTicks"`
   746  	XTickStart                 float64          `json:"xTickStart"`
   747  	XTickStep                  float64          `json:"xTickStep"`
   748  	YColumn                    string           `json:"yColumn"`
   749  	GenerateYAxisTicks         []string         `json:"generateYAxisTicks"`
   750  	YTotalTicks                int              `json:"yTotalTicks"`
   751  	YTickStart                 float64          `json:"yTickStart"`
   752  	YTickStep                  float64          `json:"yTickStep"`
   753  	ShadeBelow                 bool             `json:"shadeBelow"`
   754  	Position                   string           `json:"position"`
   755  	TimeFormat                 string           `json:"timeFormat"`
   756  	HoverDimension             string           `json:"hoverDimension"`
   757  	LegendColorizeRows         bool             `json:"legendColorizeRows"`
   758  	LegendHide                 bool             `json:"legendHide"`
   759  	LegendOpacity              float64          `json:"legendOpacity"`
   760  	LegendOrientationThreshold int              `json:"legendOrientationThreshold"`
   761  }
   762  
   763  // XYViewProperties represents options for line, bar, step, or stacked view in Chronograf
   764  type XYViewProperties struct {
   765  	Queries                    []DashboardQuery `json:"queries"`
   766  	Axes                       map[string]Axis  `json:"axes"`
   767  	Type                       string           `json:"type"`
   768  	StaticLegend               StaticLegend     `json:"staticLegend"`
   769  	Geom                       string           `json:"geom"` // Either "line", "step", "stacked", or "bar"
   770  	ViewColors                 []ViewColor      `json:"colors"`
   771  	Note                       string           `json:"note"`
   772  	ShowNoteWhenEmpty          bool             `json:"showNoteWhenEmpty"`
   773  	XColumn                    string           `json:"xColumn"`
   774  	GenerateXAxisTicks         []string         `json:"generateXAxisTicks"`
   775  	XTotalTicks                int              `json:"xTotalTicks"`
   776  	XTickStart                 float64          `json:"xTickStart"`
   777  	XTickStep                  float64          `json:"xTickStep"`
   778  	YColumn                    string           `json:"yColumn"`
   779  	GenerateYAxisTicks         []string         `json:"generateYAxisTicks"`
   780  	YTotalTicks                int              `json:"yTotalTicks"`
   781  	YTickStart                 float64          `json:"yTickStart"`
   782  	YTickStep                  float64          `json:"yTickStep"`
   783  	ShadeBelow                 bool             `json:"shadeBelow"`
   784  	Position                   string           `json:"position"`
   785  	TimeFormat                 string           `json:"timeFormat"`
   786  	HoverDimension             string           `json:"hoverDimension"`
   787  	LegendColorizeRows         bool             `json:"legendColorizeRows"`
   788  	LegendHide                 bool             `json:"legendHide"`
   789  	LegendOpacity              float64          `json:"legendOpacity"`
   790  	LegendOrientationThreshold int              `json:"legendOrientationThreshold"`
   791  }
   792  
   793  // BandViewProperties represents options for the band view
   794  type BandViewProperties struct {
   795  	Queries                    []DashboardQuery `json:"queries"`
   796  	Axes                       map[string]Axis  `json:"axes"`
   797  	Type                       string           `json:"type"`
   798  	StaticLegend               StaticLegend     `json:"staticLegend"`
   799  	Geom                       string           `json:"geom"`
   800  	ViewColors                 []ViewColor      `json:"colors"`
   801  	Note                       string           `json:"note"`
   802  	ShowNoteWhenEmpty          bool             `json:"showNoteWhenEmpty"`
   803  	TimeFormat                 string           `json:"timeFormat"`
   804  	HoverDimension             string           `json:"hoverDimension"`
   805  	XColumn                    string           `json:"xColumn"`
   806  	GenerateXAxisTicks         []string         `json:"generateXAxisTicks"`
   807  	XTotalTicks                int              `json:"xTotalTicks"`
   808  	XTickStart                 float64          `json:"xTickStart"`
   809  	XTickStep                  float64          `json:"xTickStep"`
   810  	YColumn                    string           `json:"yColumn"`
   811  	GenerateYAxisTicks         []string         `json:"generateYAxisTicks"`
   812  	YTotalTicks                int              `json:"yTotalTicks"`
   813  	YTickStart                 float64          `json:"yTickStart"`
   814  	YTickStep                  float64          `json:"yTickStep"`
   815  	UpperColumn                string           `json:"upperColumn"`
   816  	MainColumn                 string           `json:"mainColumn"`
   817  	LowerColumn                string           `json:"lowerColumn"`
   818  	LegendColorizeRows         bool             `json:"legendColorizeRows"`
   819  	LegendHide                 bool             `json:"legendHide"`
   820  	LegendOpacity              float64          `json:"legendOpacity"`
   821  	LegendOrientationThreshold int              `json:"legendOrientationThreshold"`
   822  }
   823  
   824  // CheckViewProperties represents options for a view representing a check
   825  type CheckViewProperties struct {
   826  	Type                       string           `json:"type"`
   827  	CheckID                    string           `json:"checkID"`
   828  	Queries                    []DashboardQuery `json:"queries"`
   829  	ViewColors                 []string         `json:"colors"`
   830  	LegendColorizeRows         bool             `json:"legendColorizeRows"`
   831  	LegendHide                 bool             `json:"legendHide"`
   832  	LegendOpacity              float64          `json:"legendOpacity"`
   833  	LegendOrientationThreshold int              `json:"legendOrientationThreshold"`
   834  }
   835  
   836  // SingleStatViewProperties represents options for single stat view in Chronograf
   837  type SingleStatViewProperties struct {
   838  	Type              string           `json:"type"`
   839  	Queries           []DashboardQuery `json:"queries"`
   840  	Prefix            string           `json:"prefix"`
   841  	TickPrefix        string           `json:"tickPrefix"`
   842  	Suffix            string           `json:"suffix"`
   843  	TickSuffix        string           `json:"tickSuffix"`
   844  	ViewColors        []ViewColor      `json:"colors"`
   845  	DecimalPlaces     DecimalPlaces    `json:"decimalPlaces"`
   846  	Note              string           `json:"note"`
   847  	ShowNoteWhenEmpty bool             `json:"showNoteWhenEmpty"`
   848  }
   849  
   850  // HistogramViewProperties represents options for histogram view in Chronograf
   851  type HistogramViewProperties struct {
   852  	Type                       string           `json:"type"`
   853  	Queries                    []DashboardQuery `json:"queries"`
   854  	ViewColors                 []ViewColor      `json:"colors"`
   855  	XColumn                    string           `json:"xColumn"`
   856  	FillColumns                []string         `json:"fillColumns"`
   857  	XDomain                    []float64        `json:"xDomain,omitempty"`
   858  	XAxisLabel                 string           `json:"xAxisLabel"`
   859  	Position                   string           `json:"position"`
   860  	BinCount                   int              `json:"binCount"`
   861  	Note                       string           `json:"note"`
   862  	ShowNoteWhenEmpty          bool             `json:"showNoteWhenEmpty"`
   863  	LegendColorizeRows         bool             `json:"legendColorizeRows"`
   864  	LegendHide                 bool             `json:"legendHide"`
   865  	LegendOpacity              float64          `json:"legendOpacity"`
   866  	LegendOrientationThreshold int              `json:"legendOrientationThreshold"`
   867  }
   868  
   869  // HeatmapViewProperties represents options for heatmap view in Chronograf
   870  type HeatmapViewProperties struct {
   871  	Type                       string           `json:"type"`
   872  	Queries                    []DashboardQuery `json:"queries"`
   873  	ViewColors                 []string         `json:"colors"`
   874  	BinSize                    int32            `json:"binSize"`
   875  	XColumn                    string           `json:"xColumn"`
   876  	GenerateXAxisTicks         []string         `json:"generateXAxisTicks"`
   877  	XTotalTicks                int              `json:"xTotalTicks"`
   878  	XTickStart                 float64          `json:"xTickStart"`
   879  	XTickStep                  float64          `json:"xTickStep"`
   880  	YColumn                    string           `json:"yColumn"`
   881  	GenerateYAxisTicks         []string         `json:"generateYAxisTicks"`
   882  	YTotalTicks                int              `json:"yTotalTicks"`
   883  	YTickStart                 float64          `json:"yTickStart"`
   884  	YTickStep                  float64          `json:"yTickStep"`
   885  	XDomain                    []float64        `json:"xDomain,omitempty"`
   886  	YDomain                    []float64        `json:"yDomain,omitempty"`
   887  	XAxisLabel                 string           `json:"xAxisLabel"`
   888  	YAxisLabel                 string           `json:"yAxisLabel"`
   889  	XPrefix                    string           `json:"xPrefix"`
   890  	XSuffix                    string           `json:"xSuffix"`
   891  	YPrefix                    string           `json:"yPrefix"`
   892  	YSuffix                    string           `json:"ySuffix"`
   893  	Note                       string           `json:"note"`
   894  	ShowNoteWhenEmpty          bool             `json:"showNoteWhenEmpty"`
   895  	TimeFormat                 string           `json:"timeFormat"`
   896  	LegendColorizeRows         bool             `json:"legendColorizeRows"`
   897  	LegendHide                 bool             `json:"legendHide"`
   898  	LegendOpacity              float64          `json:"legendOpacity"`
   899  	LegendOrientationThreshold int              `json:"legendOrientationThreshold"`
   900  }
   901  
   902  // ScatterViewProperties represents options for scatter view in Chronograf
   903  type ScatterViewProperties struct {
   904  	Type                       string           `json:"type"`
   905  	Queries                    []DashboardQuery `json:"queries"`
   906  	ViewColors                 []string         `json:"colors"`
   907  	FillColumns                []string         `json:"fillColumns"`
   908  	SymbolColumns              []string         `json:"symbolColumns"`
   909  	XColumn                    string           `json:"xColumn"`
   910  	GenerateXAxisTicks         []string         `json:"generateXAxisTicks"`
   911  	XTotalTicks                int              `json:"xTotalTicks"`
   912  	XTickStart                 float64          `json:"xTickStart"`
   913  	XTickStep                  float64          `json:"xTickStep"`
   914  	YColumn                    string           `json:"yColumn"`
   915  	GenerateYAxisTicks         []string         `json:"generateYAxisTicks"`
   916  	YTotalTicks                int              `json:"yTotalTicks"`
   917  	YTickStart                 float64          `json:"yTickStart"`
   918  	YTickStep                  float64          `json:"yTickStep"`
   919  	XDomain                    []float64        `json:"xDomain,omitempty"`
   920  	YDomain                    []float64        `json:"yDomain,omitempty"`
   921  	XAxisLabel                 string           `json:"xAxisLabel"`
   922  	YAxisLabel                 string           `json:"yAxisLabel"`
   923  	XPrefix                    string           `json:"xPrefix"`
   924  	XSuffix                    string           `json:"xSuffix"`
   925  	YPrefix                    string           `json:"yPrefix"`
   926  	YSuffix                    string           `json:"ySuffix"`
   927  	Note                       string           `json:"note"`
   928  	ShowNoteWhenEmpty          bool             `json:"showNoteWhenEmpty"`
   929  	TimeFormat                 string           `json:"timeFormat"`
   930  	LegendColorizeRows         bool             `json:"legendColorizeRows"`
   931  	LegendHide                 bool             `json:"legendHide"`
   932  	LegendOpacity              float64          `json:"legendOpacity"`
   933  	LegendOrientationThreshold int              `json:"legendOrientationThreshold"`
   934  }
   935  
   936  // MosaicViewProperties represents options for mosaic view in Chronograf
   937  type MosaicViewProperties struct {
   938  	Type                       string           `json:"type"`
   939  	Queries                    []DashboardQuery `json:"queries"`
   940  	ViewColors                 []string         `json:"colors"`
   941  	FillColumns                []string         `json:"fillColumns"`
   942  	XColumn                    string           `json:"xColumn"`
   943  	GenerateXAxisTicks         []string         `json:"generateXAxisTicks"`
   944  	XTotalTicks                int              `json:"xTotalTicks"`
   945  	XTickStart                 float64          `json:"xTickStart"`
   946  	XTickStep                  float64          `json:"xTickStep"`
   947  	YLabelColumnSeparator      string           `json:"yLabelColumnSeparator"`
   948  	YLabelColumns              []string         `json:"yLabelColumns"`
   949  	YSeriesColumns             []string         `json:"ySeriesColumns"`
   950  	XDomain                    []float64        `json:"xDomain,omitempty"`
   951  	YDomain                    []float64        `json:"yDomain,omitempty"`
   952  	XAxisLabel                 string           `json:"xAxisLabel"`
   953  	YAxisLabel                 string           `json:"yAxisLabel"`
   954  	XPrefix                    string           `json:"xPrefix"`
   955  	XSuffix                    string           `json:"xSuffix"`
   956  	YPrefix                    string           `json:"yPrefix"`
   957  	YSuffix                    string           `json:"ySuffix"`
   958  	Note                       string           `json:"note"`
   959  	ShowNoteWhenEmpty          bool             `json:"showNoteWhenEmpty"`
   960  	TimeFormat                 string           `json:"timeFormat"`
   961  	HoverDimension             string           `json:"hoverDimension"`
   962  	LegendColorizeRows         bool             `json:"legendColorizeRows"`
   963  	LegendHide                 bool             `json:"legendHide"`
   964  	LegendOpacity              float64          `json:"legendOpacity"`
   965  	LegendOrientationThreshold int              `json:"legendOrientationThreshold"`
   966  }
   967  
   968  // GaugeViewProperties represents options for gauge view in Chronograf
   969  type GaugeViewProperties struct {
   970  	Type              string           `json:"type"`
   971  	Queries           []DashboardQuery `json:"queries"`
   972  	Prefix            string           `json:"prefix"`
   973  	TickPrefix        string           `json:"tickPrefix"`
   974  	Suffix            string           `json:"suffix"`
   975  	TickSuffix        string           `json:"tickSuffix"`
   976  	ViewColors        []ViewColor      `json:"colors"`
   977  	DecimalPlaces     DecimalPlaces    `json:"decimalPlaces"`
   978  	Note              string           `json:"note"`
   979  	ShowNoteWhenEmpty bool             `json:"showNoteWhenEmpty"`
   980  }
   981  
   982  // Geographical coordinates
   983  type Datum struct {
   984  	Lat float64 `json:"lat"`
   985  	Lon float64 `json:"lon"`
   986  }
   987  
   988  // Single visualization layer properties of a chronograf map widget
   989  type GeoLayer struct {
   990  	Type           string `json:"type"`
   991  	RadiusField    string `json:"radiusField"`
   992  	ColorField     string `json:"colorField"`
   993  	IntensityField string `json:"intensityField"`
   994  	// circle layer properties
   995  	ViewColors         []ViewColor `json:"colors"`
   996  	Radius             int32       `json:"radius"`
   997  	Blur               int32       `json:"blur"`
   998  	RadiusDimension    Axis        `json:"radiusDimension,omitempty"`
   999  	ColorDimension     Axis        `json:"colorDimension,omitempty"`
  1000  	IntensityDimension Axis        `json:"intensityDimension,omitempty"`
  1001  	InterpolateColors  bool        `json:"interpolateColors"`
  1002  	// track layer properties
  1003  	TrackWidth   int32 `json:"trackWidth"`
  1004  	Speed        int32 `json:"speed"`
  1005  	RandomColors bool  `json:"randomColors"`
  1006  	// point layer properties
  1007  	IsClustered bool `json:"isClustered"`
  1008  }
  1009  
  1010  // GeoViewProperties represents options for map view in Chronograf
  1011  type GeoViewProperties struct {
  1012  	Type                   string           `json:"type"`
  1013  	Queries                []DashboardQuery `json:"queries"`
  1014  	Center                 Datum            `json:"center"`
  1015  	Zoom                   float64          `json:"zoom"`
  1016  	MapStyle               string           `json:"mapStyle"`
  1017  	AllowPanAndZoom        bool             `json:"allowPanAndZoom"`
  1018  	DetectCoordinateFields bool             `json:"detectCoordinateFields"`
  1019  	ViewColor              []ViewColor      `json:"colors"`
  1020  	GeoLayers              []GeoLayer       `json:"layers"`
  1021  	Note                   string           `json:"note"`
  1022  	ShowNoteWhenEmpty      bool             `json:"showNoteWhenEmpty"`
  1023  }
  1024  
  1025  // TableViewProperties represents options for table view in Chronograf
  1026  type TableViewProperties struct {
  1027  	Type              string           `json:"type"`
  1028  	Queries           []DashboardQuery `json:"queries"`
  1029  	ViewColors        []ViewColor      `json:"colors"`
  1030  	TableOptions      TableOptions     `json:"tableOptions"`
  1031  	FieldOptions      []RenamableField `json:"fieldOptions"`
  1032  	TimeFormat        string           `json:"timeFormat"`
  1033  	DecimalPlaces     DecimalPlaces    `json:"decimalPlaces"`
  1034  	Note              string           `json:"note"`
  1035  	ShowNoteWhenEmpty bool             `json:"showNoteWhenEmpty"`
  1036  }
  1037  
  1038  type MarkdownViewProperties struct {
  1039  	Type string `json:"type"`
  1040  	Note string `json:"note"`
  1041  }
  1042  
  1043  // LogViewProperties represents options for log viewer in Chronograf.
  1044  type LogViewProperties struct {
  1045  	Type    string            `json:"type"`
  1046  	Columns []LogViewerColumn `json:"columns"`
  1047  }
  1048  
  1049  // LogViewerColumn represents a specific column in a Log Viewer.
  1050  type LogViewerColumn struct {
  1051  	Name     string             `json:"name"`
  1052  	Position int32              `json:"position"`
  1053  	Settings []LogColumnSetting `json:"settings"`
  1054  }
  1055  
  1056  // LogColumnSetting represent the settings for a specific column of a Log Viewer.
  1057  type LogColumnSetting struct {
  1058  	Type  string `json:"type"`
  1059  	Value string `json:"value"`
  1060  	Name  string `json:"name,omitempty"`
  1061  }
  1062  
  1063  func (XYViewProperties) viewProperties()             {}
  1064  func (BandViewProperties) viewProperties()           {}
  1065  func (LinePlusSingleStatProperties) viewProperties() {}
  1066  func (SingleStatViewProperties) viewProperties()     {}
  1067  func (HistogramViewProperties) viewProperties()      {}
  1068  func (HeatmapViewProperties) viewProperties()        {}
  1069  func (ScatterViewProperties) viewProperties()        {}
  1070  func (MosaicViewProperties) viewProperties()         {}
  1071  func (GaugeViewProperties) viewProperties()          {}
  1072  func (GeoViewProperties) viewProperties()            {}
  1073  func (TableViewProperties) viewProperties()          {}
  1074  func (MarkdownViewProperties) viewProperties()       {}
  1075  func (LogViewProperties) viewProperties()            {}
  1076  func (CheckViewProperties) viewProperties()          {}
  1077  
  1078  func (v XYViewProperties) GetType() string             { return v.Type }
  1079  func (v BandViewProperties) GetType() string           { return v.Type }
  1080  func (v LinePlusSingleStatProperties) GetType() string { return v.Type }
  1081  func (v SingleStatViewProperties) GetType() string     { return v.Type }
  1082  func (v HistogramViewProperties) GetType() string      { return v.Type }
  1083  func (v HeatmapViewProperties) GetType() string        { return v.Type }
  1084  func (v ScatterViewProperties) GetType() string        { return v.Type }
  1085  func (v MosaicViewProperties) GetType() string         { return v.Type }
  1086  func (v GaugeViewProperties) GetType() string          { return v.Type }
  1087  func (v GeoViewProperties) GetType() string            { return v.Type }
  1088  func (v TableViewProperties) GetType() string          { return v.Type }
  1089  func (v MarkdownViewProperties) GetType() string       { return v.Type }
  1090  func (v LogViewProperties) GetType() string            { return v.Type }
  1091  func (v CheckViewProperties) GetType() string          { return v.Type }
  1092  
  1093  /////////////////////////////
  1094  // Old Chronograf Types
  1095  /////////////////////////////
  1096  
  1097  // DashboardQuery represents a query used in a dashboard cell
  1098  type DashboardQuery struct {
  1099  	Text          string        `json:"text"`
  1100  	EditMode      string        `json:"editMode"` // Either "builder" or "advanced"
  1101  	Name          string        `json:"name"`     // Term or phrase that refers to the query
  1102  	BuilderConfig BuilderConfig `json:"builderConfig"`
  1103  }
  1104  
  1105  type BuilderConfig struct {
  1106  	Buckets []string `json:"buckets"`
  1107  	Tags    []struct {
  1108  		Key                   string   `json:"key"`
  1109  		Values                []string `json:"values"`
  1110  		AggregateFunctionType string   `json:"aggregateFunctionType"`
  1111  	} `json:"tags"`
  1112  	Functions []struct {
  1113  		Name string `json:"name"`
  1114  	} `json:"functions"`
  1115  	AggregateWindow struct {
  1116  		Period     string `json:"period"`
  1117  		FillValues bool   `json:"fillValues"`
  1118  	} `json:"aggregateWindow"`
  1119  }
  1120  
  1121  // MarshalJSON is necessary for the time being. UI keeps breaking
  1122  // b/c it relies on these slices being populated/not nil. Other
  1123  // consumers may have same issue.
  1124  func (b BuilderConfig) MarshalJSON() ([]byte, error) {
  1125  	type alias BuilderConfig
  1126  	copyCfg := alias(b)
  1127  	if copyCfg.Buckets == nil {
  1128  		copyCfg.Buckets = []string{}
  1129  	}
  1130  	if copyCfg.Tags == nil {
  1131  		copyCfg.Tags = []struct {
  1132  			Key                   string   `json:"key"`
  1133  			Values                []string `json:"values"`
  1134  			AggregateFunctionType string   `json:"aggregateFunctionType"`
  1135  		}{}
  1136  	}
  1137  	if copyCfg.Functions == nil {
  1138  		copyCfg.Functions = []struct {
  1139  			Name string `json:"name"`
  1140  		}{}
  1141  	}
  1142  	return json.Marshal(copyCfg)
  1143  }
  1144  
  1145  // NewBuilderTag is a constructor for the builder config types. This
  1146  // isn't technically required, but working with struct literals with embedded
  1147  // struct tags is really painful. This is to get around that bit. Would be nicer
  1148  // to have these as actual types maybe.
  1149  func NewBuilderTag(key string, functionType string, values ...string) struct {
  1150  	Key                   string   `json:"key"`
  1151  	Values                []string `json:"values"`
  1152  	AggregateFunctionType string   `json:"aggregateFunctionType"`
  1153  } {
  1154  	return struct {
  1155  		Key                   string   `json:"key"`
  1156  		Values                []string `json:"values"`
  1157  		AggregateFunctionType string   `json:"aggregateFunctionType"`
  1158  	}{
  1159  		Key:                   key,
  1160  		Values:                values,
  1161  		AggregateFunctionType: functionType,
  1162  	}
  1163  }
  1164  
  1165  // Axis represents the visible extents of a visualization
  1166  type Axis struct {
  1167  	Bounds       []string `json:"bounds"` // bounds are an arbitrary list of client-defined strings that specify the viewport for a View
  1168  	LegacyBounds [2]int64 `json:"-"`      // legacy bounds are for testing a migration from an earlier version of axis
  1169  	Label        string   `json:"label"`  // label is a description of this Axis
  1170  	Prefix       string   `json:"prefix"` // Prefix represents a label prefix for formatting axis values
  1171  	Suffix       string   `json:"suffix"` // Suffix represents a label suffix for formatting axis values
  1172  	Base         string   `json:"base"`   // Base represents the radix for formatting axis values
  1173  	Scale        string   `json:"scale"`  // Scale is the axis formatting scale. Supported: "log", "linear"
  1174  }
  1175  
  1176  // ViewColor represents the encoding of data into visualizations
  1177  type ViewColor struct {
  1178  	ID    string  `json:"id"`    // ID is the unique id of the View color
  1179  	Type  string  `json:"type"`  // Type is how the color is used. Accepted (min,max,threshold)
  1180  	Hex   string  `json:"hex"`   // Hex is the hex number of the color
  1181  	Name  string  `json:"name"`  // Name is the user-facing name of the hex color
  1182  	Value float64 `json:"value"` // Value is the data value mapped to this color
  1183  }
  1184  
  1185  // StaticLegend represents the options specific to the static legend
  1186  type StaticLegend struct {
  1187  	ColorizeRows         bool    `json:"colorizeRows,omitempty"`
  1188  	HeightRatio          float64 `json:"heightRatio,omitempty"`
  1189  	Show                 bool    `json:"show,omitempty"`
  1190  	Opacity              float64 `json:"opacity,omitempty"`
  1191  	OrientationThreshold int     `json:"orientationThreshold,omitempty"`
  1192  	ValueAxis            string  `json:"valueAxis,omitempty"`
  1193  	WidthRatio           float64 `json:"widthRatio,omitempty"`
  1194  }
  1195  
  1196  // TableOptions is a type of options for a DashboardView with type Table
  1197  type TableOptions struct {
  1198  	VerticalTimeAxis bool           `json:"verticalTimeAxis"`
  1199  	SortBy           RenamableField `json:"sortBy"`
  1200  	Wrapping         string         `json:"wrapping"`
  1201  	FixFirstColumn   bool           `json:"fixFirstColumn"`
  1202  }
  1203  
  1204  // RenamableField is a column/row field in a DashboardView of type Table
  1205  type RenamableField struct {
  1206  	InternalName string `json:"internalName"`
  1207  	DisplayName  string `json:"displayName"`
  1208  	Visible      bool   `json:"visible"`
  1209  }
  1210  
  1211  // DecimalPlaces indicates whether decimal places should be enforced, and how many digits it should show.
  1212  type DecimalPlaces struct {
  1213  	IsEnforced bool  `json:"isEnforced"`
  1214  	Digits     int32 `json:"digits"`
  1215  }