From 4c76cd335d2b2942de4c75949172538e4772e1ac Mon Sep 17 00:00:00 2001 From: Iris Scholten Date: Wed, 18 Apr 2018 16:48:44 -0700 Subject: [PATCH 01/48] Move FieldNames out of TableOptions and into DashboardCell as FieldOptions Add Precision to RenamableField --- bolt/internal/internal.go | 39 +++--- bolt/internal/internal.pb.go | 261 ++++++++++++++++++----------------- bolt/internal/internal.proto | 5 +- chronograf.go | 13 +- 4 files changed, 165 insertions(+), 153 deletions(-) diff --git a/bolt/internal/internal.go b/bolt/internal/internal.go index 78c8e28644..f6daf29812 100644 --- a/bolt/internal/internal.go +++ b/bolt/internal/internal.go @@ -273,24 +273,24 @@ func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) { Visible: c.TableOptions.SortBy.Visible, } - fieldNames := make([]*RenamableField, len(c.TableOptions.FieldNames)) - for i, field := range c.TableOptions.FieldNames { - fieldNames[i] = &RenamableField{ - InternalName: field.InternalName, - DisplayName: field.DisplayName, - Visible: field.Visible, - } - } - tableOptions := &TableOptions{ TimeFormat: c.TableOptions.TimeFormat, VerticalTimeAxis: c.TableOptions.VerticalTimeAxis, SortBy: sortBy, Wrapping: c.TableOptions.Wrapping, - FieldNames: fieldNames, FixFirstColumn: c.TableOptions.FixFirstColumn, } + fieldOptions := make([]*RenamableField, len(c.FieldOptions)) + for i, field := range c.FieldOptions { + fieldOptions[i] = &RenamableField{ + InternalName: field.InternalName, + DisplayName: field.DisplayName, + Visible: field.Visible, + Precision: field.Precision, + } + } + cells[i] = &DashboardCell{ ID: c.ID, X: c.X, @@ -307,6 +307,7 @@ func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) { Orientation: c.Legend.Orientation, }, TableOptions: tableOptions, + FieldOptions: fieldOptions, } } templates := make([]*Template, len(d.Templates)) @@ -442,20 +443,19 @@ func UnmarshalDashboard(data []byte, d *chronograf.Dashboard) error { sortBy.Visible = c.TableOptions.SortBy.Visible } tableOptions.SortBy = sortBy - - fieldNames := make([]chronograf.RenamableField, len(c.TableOptions.FieldNames)) - for i, field := range c.TableOptions.FieldNames { - fieldNames[i] = chronograf.RenamableField{} - fieldNames[i].InternalName = field.InternalName - fieldNames[i].DisplayName = field.DisplayName - fieldNames[i].Visible = field.Visible - } - tableOptions.FieldNames = fieldNames tableOptions.TimeFormat = c.TableOptions.TimeFormat tableOptions.VerticalTimeAxis = c.TableOptions.VerticalTimeAxis tableOptions.Wrapping = c.TableOptions.Wrapping tableOptions.FixFirstColumn = c.TableOptions.FixFirstColumn + } + fieldOptions := make([]chronograf.RenamableField, len(c.FieldOptions)) + for i, field := range c.FieldOptions { + fieldOptions[i] = chronograf.RenamableField{} + fieldOptions[i].InternalName = field.InternalName + fieldOptions[i].DisplayName = field.DisplayName + fieldOptions[i].Visible = field.Visible + fieldOptions[i].Precision = field.Precision } // FIXME: this is merely for legacy cells and @@ -478,6 +478,7 @@ func UnmarshalDashboard(data []byte, d *chronograf.Dashboard) error { CellColors: colors, Legend: legend, TableOptions: tableOptions, + FieldOptions: fieldOptions, } } diff --git a/bolt/internal/internal.pb.go b/bolt/internal/internal.pb.go index f805b26e95..8b8a23a8f8 100644 --- a/bolt/internal/internal.pb.go +++ b/bolt/internal/internal.pb.go @@ -220,18 +220,19 @@ func (m *Dashboard) GetOrganization() string { } type DashboardCell struct { - X int32 `protobuf:"varint,1,opt,name=x,proto3" json:"x,omitempty"` - Y int32 `protobuf:"varint,2,opt,name=y,proto3" json:"y,omitempty"` - W int32 `protobuf:"varint,3,opt,name=w,proto3" json:"w,omitempty"` - H int32 `protobuf:"varint,4,opt,name=h,proto3" json:"h,omitempty"` - Queries []*Query `protobuf:"bytes,5,rep,name=queries" json:"queries,omitempty"` - Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` - Type string `protobuf:"bytes,7,opt,name=type,proto3" json:"type,omitempty"` - ID string `protobuf:"bytes,8,opt,name=ID,proto3" json:"ID,omitempty"` - Axes map[string]*Axis `protobuf:"bytes,9,rep,name=axes" json:"axes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"` - Colors []*Color `protobuf:"bytes,10,rep,name=colors" json:"colors,omitempty"` - Legend *Legend `protobuf:"bytes,11,opt,name=legend" json:"legend,omitempty"` - TableOptions *TableOptions `protobuf:"bytes,12,opt,name=tableOptions" json:"tableOptions,omitempty"` + X int32 `protobuf:"varint,1,opt,name=x,proto3" json:"x,omitempty"` + Y int32 `protobuf:"varint,2,opt,name=y,proto3" json:"y,omitempty"` + W int32 `protobuf:"varint,3,opt,name=w,proto3" json:"w,omitempty"` + H int32 `protobuf:"varint,4,opt,name=h,proto3" json:"h,omitempty"` + Queries []*Query `protobuf:"bytes,5,rep,name=queries" json:"queries,omitempty"` + Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` + Type string `protobuf:"bytes,7,opt,name=type,proto3" json:"type,omitempty"` + ID string `protobuf:"bytes,8,opt,name=ID,proto3" json:"ID,omitempty"` + Axes map[string]*Axis `protobuf:"bytes,9,rep,name=axes" json:"axes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"` + Colors []*Color `protobuf:"bytes,10,rep,name=colors" json:"colors,omitempty"` + Legend *Legend `protobuf:"bytes,11,opt,name=legend" json:"legend,omitempty"` + TableOptions *TableOptions `protobuf:"bytes,12,opt,name=tableOptions" json:"tableOptions,omitempty"` + FieldOptions []*RenamableField `protobuf:"bytes,13,rep,name=fieldOptions" json:"fieldOptions,omitempty"` } func (m *DashboardCell) Reset() { *m = DashboardCell{} } @@ -323,13 +324,19 @@ func (m *DashboardCell) GetTableOptions() *TableOptions { return nil } +func (m *DashboardCell) GetFieldOptions() []*RenamableField { + if m != nil { + return m.FieldOptions + } + return nil +} + type TableOptions struct { - TimeFormat string `protobuf:"bytes,1,opt,name=timeFormat,proto3" json:"timeFormat,omitempty"` - VerticalTimeAxis bool `protobuf:"varint,2,opt,name=verticalTimeAxis,proto3" json:"verticalTimeAxis,omitempty"` - SortBy *RenamableField `protobuf:"bytes,3,opt,name=sortBy" json:"sortBy,omitempty"` - Wrapping string `protobuf:"bytes,4,opt,name=wrapping,proto3" json:"wrapping,omitempty"` - FieldNames []*RenamableField `protobuf:"bytes,5,rep,name=fieldNames" json:"fieldNames,omitempty"` - FixFirstColumn bool `protobuf:"varint,6,opt,name=fixFirstColumn,proto3" json:"fixFirstColumn,omitempty"` + TimeFormat string `protobuf:"bytes,1,opt,name=timeFormat,proto3" json:"timeFormat,omitempty"` + VerticalTimeAxis bool `protobuf:"varint,2,opt,name=verticalTimeAxis,proto3" json:"verticalTimeAxis,omitempty"` + SortBy *RenamableField `protobuf:"bytes,3,opt,name=sortBy" json:"sortBy,omitempty"` + Wrapping string `protobuf:"bytes,4,opt,name=wrapping,proto3" json:"wrapping,omitempty"` + FixFirstColumn bool `protobuf:"varint,5,opt,name=fixFirstColumn,proto3" json:"fixFirstColumn,omitempty"` } func (m *TableOptions) Reset() { *m = TableOptions{} } @@ -365,13 +372,6 @@ func (m *TableOptions) GetWrapping() string { return "" } -func (m *TableOptions) GetFieldNames() []*RenamableField { - if m != nil { - return m.FieldNames - } - return nil -} - func (m *TableOptions) GetFixFirstColumn() bool { if m != nil { return m.FixFirstColumn @@ -383,6 +383,7 @@ type RenamableField struct { InternalName string `protobuf:"bytes,1,opt,name=internalName,proto3" json:"internalName,omitempty"` DisplayName string `protobuf:"bytes,2,opt,name=displayName,proto3" json:"displayName,omitempty"` Visible bool `protobuf:"varint,3,opt,name=visible,proto3" json:"visible,omitempty"` + Precision int32 `protobuf:"varint,4,opt,name=precision,proto3" json:"precision,omitempty"` } func (m *RenamableField) Reset() { *m = RenamableField{} } @@ -411,6 +412,13 @@ func (m *RenamableField) GetVisible() bool { return false } +func (m *RenamableField) GetPrecision() int32 { + if m != nil { + return m.Precision + } + return 0 +} + type Color struct { ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` Type string `protobuf:"bytes,2,opt,name=Type,proto3" json:"Type,omitempty"` @@ -1338,105 +1346,106 @@ func init() { func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) } var fileDescriptorInternal = []byte{ - // 1599 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xcd, 0x6f, 0xdb, 0xc8, - 0x15, 0x07, 0x45, 0x51, 0x12, 0x9f, 0x1c, 0xd7, 0x98, 0x1a, 0x09, 0x9b, 0x16, 0x85, 0x4a, 0xf4, - 0x43, 0xfd, 0x88, 0x1b, 0x28, 0x28, 0x10, 0x04, 0x6d, 0x00, 0xd9, 0x6a, 0x52, 0x37, 0x4e, 0xec, - 0x8c, 0x6c, 0xf7, 0x54, 0x04, 0x23, 0x69, 0x24, 0x11, 0xa1, 0x48, 0x76, 0x48, 0xda, 0x62, 0xcf, - 0x3d, 0xf5, 0x8f, 0x28, 0x50, 0xa0, 0xfd, 0x07, 0x8a, 0x5e, 0xf6, 0xb4, 0xf7, 0xfd, 0x87, 0x76, - 0x8f, 0x8b, 0x37, 0x1f, 0x24, 0x65, 0x29, 0x41, 0x16, 0x58, 0xec, 0x6d, 0x7e, 0xef, 0x3d, 0xbd, - 0x99, 0xf7, 0xfd, 0x28, 0xd8, 0x0f, 0xa2, 0x8c, 0x8b, 0x88, 0x85, 0x47, 0x89, 0x88, 0xb3, 0x98, - 0x74, 0x0c, 0xf6, 0xff, 0x61, 0x43, 0x6b, 0x1c, 0xe7, 0x62, 0xca, 0xc9, 0x3e, 0x34, 0x4e, 0x47, - 0x9e, 0xd5, 0xb3, 0xfa, 0x36, 0x6d, 0x9c, 0x8e, 0x08, 0x81, 0xe6, 0x1b, 0xb6, 0xe2, 0x5e, 0xa3, - 0x67, 0xf5, 0x5d, 0x2a, 0xcf, 0x48, 0xbb, 0x2c, 0x12, 0xee, 0xd9, 0x8a, 0x86, 0x67, 0xf2, 0x10, - 0x3a, 0x57, 0x29, 0x6a, 0x5b, 0x71, 0xaf, 0x29, 0xe9, 0x25, 0x46, 0xde, 0x05, 0x4b, 0xd3, 0xdb, - 0x58, 0xcc, 0x3c, 0x47, 0xf1, 0x0c, 0x26, 0x07, 0x60, 0x5f, 0xd1, 0x33, 0xaf, 0x25, 0xc9, 0x78, - 0x24, 0x1e, 0xb4, 0x47, 0x7c, 0xce, 0xf2, 0x30, 0xf3, 0xda, 0x3d, 0xab, 0xdf, 0xa1, 0x06, 0xa2, - 0x9e, 0x4b, 0x1e, 0xf2, 0x85, 0x60, 0x73, 0xaf, 0xa3, 0xf4, 0x18, 0x4c, 0x8e, 0x80, 0x9c, 0x46, - 0x29, 0x9f, 0xe6, 0x82, 0x8f, 0xdf, 0x07, 0xc9, 0x35, 0x17, 0xc1, 0xbc, 0xf0, 0x5c, 0xa9, 0x60, - 0x07, 0x07, 0x6f, 0x79, 0xcd, 0x33, 0x86, 0x77, 0x83, 0x54, 0x65, 0x20, 0xf1, 0x61, 0x6f, 0xbc, - 0x64, 0x82, 0xcf, 0xc6, 0x7c, 0x2a, 0x78, 0xe6, 0x75, 0x25, 0x7b, 0x83, 0x86, 0x32, 0xe7, 0x62, - 0xc1, 0xa2, 0xe0, 0xef, 0x2c, 0x0b, 0xe2, 0xc8, 0xdb, 0x53, 0x32, 0x75, 0x1a, 0x7a, 0x89, 0xc6, - 0x21, 0xf7, 0xee, 0x29, 0x2f, 0xe1, 0x99, 0xfc, 0x08, 0x5c, 0x6d, 0x0c, 0xbd, 0xf0, 0xf6, 0x25, - 0xa3, 0x22, 0xf8, 0xff, 0xb7, 0xc0, 0x1d, 0xb1, 0x74, 0x39, 0x89, 0x99, 0x98, 0x7d, 0x52, 0x24, - 0x1e, 0x81, 0x33, 0xe5, 0x61, 0x98, 0x7a, 0x76, 0xcf, 0xee, 0x77, 0x07, 0x0f, 0x8e, 0xca, 0x10, - 0x97, 0x7a, 0x4e, 0x78, 0x18, 0x52, 0x25, 0x45, 0x1e, 0x83, 0x9b, 0xf1, 0x55, 0x12, 0xb2, 0x8c, - 0xa7, 0x5e, 0x53, 0xfe, 0x84, 0x54, 0x3f, 0xb9, 0xd4, 0x2c, 0x5a, 0x09, 0x6d, 0x19, 0xea, 0x6c, - 0x1b, 0xea, 0x7f, 0x66, 0xc3, 0xbd, 0x8d, 0xeb, 0xc8, 0x1e, 0x58, 0x6b, 0xf9, 0x72, 0x87, 0x5a, - 0x6b, 0x44, 0x85, 0x7c, 0xb5, 0x43, 0xad, 0x02, 0xd1, 0xad, 0xcc, 0x1c, 0x87, 0x5a, 0xb7, 0x88, - 0x96, 0x32, 0x5f, 0x1c, 0x6a, 0x2d, 0xc9, 0x2f, 0xa1, 0xfd, 0xb7, 0x9c, 0x8b, 0x80, 0xa7, 0x9e, - 0x23, 0x5f, 0xf7, 0xbd, 0xea, 0x75, 0x6f, 0x73, 0x2e, 0x0a, 0x6a, 0xf8, 0xe8, 0x0d, 0x99, 0x6b, - 0x2a, 0x71, 0xe4, 0x19, 0x69, 0x19, 0xe6, 0x65, 0x5b, 0xd1, 0xf0, 0xac, 0xbd, 0xa8, 0xb2, 0x05, - 0xbd, 0xf8, 0x3b, 0x68, 0xb2, 0x35, 0x4f, 0x3d, 0x57, 0xea, 0xff, 0xc9, 0x07, 0x1c, 0x76, 0x34, - 0x5c, 0xf3, 0xf4, 0x8f, 0x51, 0x26, 0x0a, 0x2a, 0xc5, 0xc9, 0x2f, 0xa0, 0x35, 0x8d, 0xc3, 0x58, - 0xa4, 0x1e, 0xdc, 0x7d, 0xd8, 0x09, 0xd2, 0xa9, 0x66, 0x93, 0x3e, 0xb4, 0x42, 0xbe, 0xe0, 0xd1, - 0x4c, 0xe6, 0x4d, 0x77, 0x70, 0x50, 0x09, 0x9e, 0x49, 0x3a, 0xd5, 0x7c, 0xf2, 0x0c, 0xf6, 0x32, - 0x36, 0x09, 0xf9, 0x79, 0x82, 0x5e, 0x4c, 0x65, 0x0e, 0x75, 0x07, 0xf7, 0x6b, 0xf1, 0xa8, 0x71, - 0xe9, 0x86, 0xec, 0xc3, 0x97, 0xe0, 0x96, 0x2f, 0xc4, 0x12, 0x7a, 0xcf, 0x0b, 0xe9, 0x6f, 0x97, - 0xe2, 0x91, 0xfc, 0x14, 0x9c, 0x1b, 0x16, 0xe6, 0x2a, 0x57, 0xba, 0x83, 0xfd, 0x4a, 0xe7, 0x70, - 0x1d, 0xa4, 0x54, 0x31, 0x9f, 0x35, 0x9e, 0x5a, 0xfe, 0x3f, 0x1b, 0xb0, 0x57, 0xbf, 0x87, 0xfc, - 0x18, 0x20, 0x0b, 0x56, 0xfc, 0x45, 0x2c, 0x56, 0x2c, 0xd3, 0x3a, 0x6b, 0x14, 0xf2, 0x2b, 0x38, - 0xb8, 0xe1, 0x22, 0x0b, 0xa6, 0x2c, 0xbc, 0x0c, 0x56, 0x1c, 0xf5, 0xc9, 0x5b, 0x3a, 0x74, 0x8b, - 0x4e, 0x1e, 0x43, 0x2b, 0x8d, 0x45, 0x76, 0x5c, 0xc8, 0x78, 0x77, 0x07, 0x5e, 0xf5, 0x0e, 0xca, - 0x23, 0xb6, 0xc2, 0x7b, 0x5f, 0x04, 0x3c, 0x9c, 0x51, 0x2d, 0x87, 0x15, 0x7e, 0x2b, 0x58, 0x92, - 0x04, 0xd1, 0xc2, 0x74, 0x11, 0x83, 0xc9, 0x53, 0x80, 0x39, 0x0a, 0x63, 0xe2, 0x9b, 0xfc, 0xf8, - 0xb0, 0xc6, 0x9a, 0x2c, 0xf9, 0x39, 0xec, 0xcf, 0x83, 0xf5, 0x8b, 0x40, 0xa4, 0xd9, 0x49, 0x1c, - 0xe6, 0xab, 0x48, 0x66, 0x4d, 0x87, 0xde, 0xa1, 0xfa, 0x09, 0xec, 0x6f, 0x6a, 0xc1, 0xf4, 0x37, - 0x17, 0xc8, 0xda, 0x53, 0xfe, 0xd8, 0xa0, 0x91, 0x1e, 0x74, 0x67, 0x41, 0x9a, 0x84, 0xac, 0xa8, - 0x95, 0x67, 0x9d, 0x84, 0xbd, 0xe6, 0x26, 0x48, 0x83, 0x49, 0xa8, 0x5a, 0x66, 0x87, 0x1a, 0xe8, - 0x2f, 0xc0, 0x91, 0xe9, 0x53, 0x2b, 0x76, 0xd7, 0x14, 0xbb, 0x6c, 0xb1, 0x8d, 0x5a, 0x8b, 0x3d, - 0x00, 0xfb, 0x4f, 0x7c, 0xad, 0xbb, 0x2e, 0x1e, 0xcb, 0x96, 0xd0, 0xac, 0xb5, 0x84, 0x43, 0x70, - 0xae, 0x65, 0xec, 0x55, 0xa9, 0x2a, 0xe0, 0x3f, 0x87, 0x96, 0x4a, 0xbf, 0x52, 0xb3, 0x55, 0xd3, - 0xdc, 0x83, 0xee, 0xb9, 0x08, 0x78, 0x94, 0xa9, 0x22, 0xd7, 0x26, 0xd4, 0x48, 0xfe, 0xff, 0x2c, - 0x68, 0xca, 0x98, 0xfa, 0xb0, 0x17, 0xf2, 0x05, 0x9b, 0x16, 0xc7, 0x71, 0x1e, 0xcd, 0x52, 0xcf, - 0xea, 0xd9, 0x7d, 0x9b, 0x6e, 0xd0, 0xc8, 0x7d, 0x68, 0x4d, 0x14, 0xb7, 0xd1, 0xb3, 0xfb, 0x2e, - 0xd5, 0x08, 0x9f, 0x16, 0xb2, 0x09, 0x0f, 0xb5, 0x09, 0x0a, 0xa0, 0x74, 0x22, 0xf8, 0x3c, 0x58, - 0x6b, 0x33, 0x34, 0x42, 0x7a, 0x9a, 0xcf, 0x91, 0xae, 0x2c, 0xd1, 0x08, 0x0d, 0x98, 0xb0, 0xb4, - 0xac, 0x7c, 0x3c, 0xa3, 0xe6, 0x74, 0xca, 0x42, 0x53, 0xfa, 0x0a, 0xf8, 0x9f, 0x5b, 0x38, 0x30, - 0x54, 0x2b, 0xdb, 0xf2, 0xf0, 0x0f, 0xa0, 0x83, 0x6d, 0xee, 0xdd, 0x0d, 0x13, 0xda, 0xe0, 0x36, - 0xe2, 0x6b, 0x26, 0xc8, 0x6f, 0xa1, 0x25, 0x2b, 0x64, 0x47, 0x5b, 0x35, 0xea, 0xa4, 0x57, 0xa9, - 0x16, 0x2b, 0x1b, 0x4f, 0xb3, 0xd6, 0x78, 0x4a, 0x63, 0x9d, 0xba, 0xb1, 0x8f, 0xc0, 0xc1, 0x0e, - 0x56, 0xc8, 0xd7, 0xef, 0xd4, 0xac, 0xfa, 0x9c, 0x92, 0xf2, 0xaf, 0xe0, 0xde, 0xc6, 0x8d, 0xe5, - 0x4d, 0xd6, 0xe6, 0x4d, 0x55, 0xb5, 0xbb, 0xba, 0xba, 0xb1, 0x94, 0x52, 0x1e, 0xf2, 0x69, 0xc6, - 0x67, 0x3a, 0xeb, 0x4a, 0xec, 0xff, 0xdb, 0xaa, 0xf4, 0xca, 0xfb, 0x30, 0x45, 0xa7, 0xf1, 0x6a, - 0xc5, 0xa2, 0x99, 0x56, 0x6d, 0x20, 0xfa, 0x6d, 0x36, 0xd1, 0xaa, 0x1b, 0xb3, 0x09, 0x62, 0x91, - 0xe8, 0x08, 0x36, 0x44, 0x82, 0xb9, 0xb3, 0xe2, 0x2c, 0xcd, 0x05, 0x5f, 0xf1, 0x28, 0xd3, 0x2e, - 0xa8, 0x93, 0xc8, 0x03, 0x68, 0x67, 0x6c, 0xf1, 0x0e, 0x7b, 0x94, 0x8e, 0x64, 0xc6, 0x16, 0xaf, - 0x78, 0x41, 0x7e, 0x08, 0xae, 0xac, 0x52, 0xc9, 0x52, 0xe1, 0xec, 0x48, 0xc2, 0x2b, 0x5e, 0xf8, - 0x5f, 0x59, 0xd0, 0x1a, 0x73, 0x71, 0xc3, 0xc5, 0x27, 0x4d, 0xc2, 0xfa, 0xfe, 0x61, 0x7f, 0x64, - 0xff, 0x68, 0xee, 0xde, 0x3f, 0x9c, 0x6a, 0xff, 0x38, 0x04, 0x67, 0x2c, 0xa6, 0xa7, 0x23, 0xf9, - 0x22, 0x9b, 0x2a, 0x80, 0xd9, 0x38, 0x9c, 0x66, 0xc1, 0x0d, 0xd7, 0x4b, 0x89, 0x46, 0x5b, 0x03, - 0xb2, 0xb3, 0x63, 0x13, 0xf8, 0x86, 0xbb, 0x89, 0xff, 0x2f, 0x0b, 0x5a, 0x67, 0xac, 0x88, 0xf3, - 0x6c, 0x2b, 0x6b, 0x7b, 0xd0, 0x1d, 0x26, 0x49, 0x18, 0x4c, 0x37, 0x2a, 0xb5, 0x46, 0x42, 0x89, - 0xd7, 0xb5, 0x78, 0x28, 0x5f, 0xd4, 0x49, 0x38, 0x1d, 0x4e, 0xe4, 0xd2, 0xa0, 0x36, 0x80, 0xda, - 0x74, 0x50, 0xbb, 0x82, 0x64, 0xa2, 0xd3, 0x86, 0x79, 0x16, 0xcf, 0xc3, 0xf8, 0x56, 0x7a, 0xa7, - 0x43, 0x4b, 0xec, 0x7f, 0xd1, 0x80, 0xe6, 0x77, 0x35, 0xe8, 0xf7, 0xc0, 0x0a, 0x74, 0x72, 0x58, - 0x41, 0x39, 0xf6, 0xdb, 0xb5, 0xb1, 0xef, 0x41, 0xbb, 0x10, 0x2c, 0x5a, 0xf0, 0xd4, 0xeb, 0xc8, - 0x6e, 0x64, 0xa0, 0xe4, 0xc8, 0xba, 0x53, 0xf3, 0xde, 0xa5, 0x06, 0x96, 0x75, 0x04, 0xb5, 0x3a, - 0xfa, 0x8d, 0x5e, 0x0d, 0xba, 0x77, 0x47, 0xcb, 0xae, 0x8d, 0xe0, 0xdb, 0x1b, 0xc1, 0x5f, 0x5a, - 0xe0, 0x94, 0x45, 0x78, 0xb2, 0x59, 0x84, 0x27, 0x55, 0x11, 0x8e, 0x8e, 0x4d, 0x11, 0x8e, 0x8e, - 0x11, 0xd3, 0x0b, 0x53, 0x84, 0xf4, 0x02, 0x83, 0xf5, 0x52, 0xc4, 0x79, 0x72, 0x5c, 0xa8, 0xa8, - 0xba, 0xb4, 0xc4, 0x98, 0xb9, 0x7f, 0x59, 0x72, 0xa1, 0x5d, 0xed, 0x52, 0x8d, 0x30, 0xcf, 0xcf, - 0x64, 0x83, 0x52, 0xce, 0x55, 0x80, 0xfc, 0x0c, 0x1c, 0x8a, 0xce, 0x93, 0x1e, 0xde, 0x88, 0x8b, - 0x24, 0x53, 0xc5, 0x45, 0xa5, 0xea, 0x83, 0x41, 0x27, 0xbc, 0xf9, 0x7c, 0xf8, 0x35, 0xb4, 0xc6, - 0xcb, 0x60, 0x9e, 0x99, 0x05, 0xeb, 0xfb, 0xb5, 0x06, 0x17, 0xac, 0xb8, 0xe4, 0x51, 0x2d, 0xe2, - 0xbf, 0x05, 0xb7, 0x24, 0x56, 0xcf, 0xb1, 0xea, 0xcf, 0x21, 0xd0, 0xbc, 0x8a, 0x82, 0xcc, 0x94, - 0x3a, 0x9e, 0xd1, 0xd8, 0xb7, 0x39, 0x8b, 0xb2, 0x20, 0x2b, 0x4c, 0xa9, 0x1b, 0xec, 0x3f, 0xd1, - 0xcf, 0x47, 0x75, 0x57, 0x49, 0xc2, 0x85, 0x6e, 0x1b, 0x0a, 0xc8, 0x4b, 0xe2, 0x5b, 0xae, 0x3a, - 0xbe, 0x4d, 0x15, 0xf0, 0xff, 0x0a, 0xee, 0x30, 0xe4, 0x22, 0xa3, 0x79, 0xc8, 0x77, 0x4d, 0xe2, - 0x3f, 0x8f, 0xcf, 0xdf, 0x98, 0x17, 0xe0, 0xb9, 0x6a, 0x11, 0xf6, 0x9d, 0x16, 0xf1, 0x8a, 0x25, - 0xec, 0x74, 0x24, 0xf3, 0xdc, 0xa6, 0x1a, 0xf9, 0xff, 0xb1, 0xa0, 0x89, 0xbd, 0xa8, 0xa6, 0xba, - 0xf9, 0xb1, 0x3e, 0x76, 0x21, 0xe2, 0x9b, 0x60, 0xc6, 0x85, 0x31, 0xce, 0x60, 0xe9, 0xf4, 0xe9, - 0x92, 0x97, 0x03, 0x5f, 0x23, 0xcc, 0x35, 0xfc, 0xba, 0x30, 0xb5, 0x54, 0xcb, 0x35, 0x24, 0x53, - 0xc5, 0xc4, 0xcd, 0x6e, 0x9c, 0x27, 0x5c, 0x0c, 0x67, 0xab, 0xc0, 0x6c, 0x40, 0x35, 0x8a, 0xff, - 0x5c, 0x7d, 0xaf, 0x6c, 0x75, 0x34, 0x6b, 0xf7, 0xb7, 0xcd, 0xdd, 0x97, 0xfb, 0xff, 0xb5, 0xa0, - 0xfd, 0x5a, 0xef, 0x6a, 0x75, 0x2b, 0xac, 0x0f, 0x5a, 0xd1, 0xd8, 0xb0, 0x62, 0x00, 0x87, 0x46, - 0x66, 0xe3, 0x7e, 0xe5, 0x85, 0x9d, 0x3c, 0xed, 0xd1, 0x66, 0x19, 0xac, 0x4f, 0xf9, 0x5c, 0xb9, - 0xdc, 0x94, 0xd9, 0x15, 0xf0, 0xad, 0xa8, 0xf4, 0xa0, 0x6b, 0x3e, 0xd3, 0xe2, 0xd0, 0x0c, 0x98, - 0x3a, 0xc9, 0x1f, 0x40, 0xeb, 0x24, 0x8e, 0xe6, 0xc1, 0x82, 0xf4, 0xa1, 0x39, 0xcc, 0xb3, 0xa5, - 0xd4, 0xd8, 0x1d, 0x1c, 0xd6, 0x0a, 0x3f, 0xcf, 0x96, 0x4a, 0x86, 0x4a, 0x09, 0xff, 0xf7, 0x00, - 0x15, 0x0d, 0xa7, 0x44, 0x15, 0x8d, 0x37, 0xfc, 0x16, 0x53, 0x26, 0x95, 0x5a, 0x3a, 0x74, 0x07, - 0xc7, 0xff, 0x03, 0xb8, 0xc7, 0x79, 0x10, 0xce, 0x4e, 0xa3, 0x79, 0x8c, 0xad, 0xe3, 0x9a, 0x8b, - 0xb4, 0x8a, 0x97, 0x81, 0xe8, 0x6e, 0xec, 0x22, 0x65, 0x0d, 0x69, 0x34, 0x69, 0xc9, 0x3f, 0x01, - 0x9e, 0x7c, 0x1d, 0x00, 0x00, 0xff, 0xff, 0xb6, 0xb2, 0x98, 0x60, 0x16, 0x10, 0x00, 0x00, + // 1614 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x5b, 0x8f, 0xe3, 0x48, + 0x15, 0x96, 0xe3, 0x38, 0x89, 0x4f, 0x32, 0x4d, 0xab, 0x68, 0xed, 0x9a, 0x05, 0xa1, 0x60, 0x71, + 0x09, 0x97, 0x6d, 0x56, 0xbd, 0x42, 0x42, 0xab, 0x65, 0xa5, 0x74, 0x87, 0x59, 0x9a, 0xe9, 0x99, + 0xee, 0xa9, 0x74, 0x37, 0x4f, 0x68, 0x55, 0x49, 0x2a, 0x49, 0x69, 0x1d, 0xdb, 0x94, 0xed, 0xee, + 0x98, 0x67, 0x9e, 0xf9, 0x09, 0x48, 0x48, 0xf0, 0x07, 0x10, 0xef, 0xbc, 0xf3, 0xc4, 0xbf, 0x59, + 0x1e, 0xd1, 0xa9, 0x8b, 0xed, 0x74, 0x32, 0xa3, 0x41, 0x42, 0xbc, 0xd5, 0x77, 0x4e, 0xe5, 0x54, + 0x9d, 0xdb, 0x57, 0xc7, 0x81, 0x23, 0x11, 0xe7, 0x5c, 0xc6, 0x2c, 0x3a, 0x4d, 0x65, 0x92, 0x27, + 0xa4, 0x67, 0x71, 0xf8, 0x07, 0x17, 0x3a, 0xd3, 0xa4, 0x90, 0x73, 0x4e, 0x8e, 0xa0, 0x75, 0x39, + 0x09, 0x9c, 0xa1, 0x33, 0x72, 0x69, 0xeb, 0x72, 0x42, 0x08, 0xb4, 0x5f, 0xb1, 0x0d, 0x0f, 0x5a, + 0x43, 0x67, 0xe4, 0x53, 0xb5, 0x46, 0xd9, 0x6d, 0x99, 0xf2, 0xc0, 0xd5, 0x32, 0x5c, 0x93, 0x0f, + 0xa0, 0x77, 0x97, 0xa1, 0xb5, 0x0d, 0x0f, 0xda, 0x4a, 0x5e, 0x61, 0xd4, 0xdd, 0xb0, 0x2c, 0x7b, + 0x4c, 0xe4, 0x22, 0xf0, 0xb4, 0xce, 0x62, 0x72, 0x0c, 0xee, 0x1d, 0xbd, 0x0a, 0x3a, 0x4a, 0x8c, + 0x4b, 0x12, 0x40, 0x77, 0xc2, 0x97, 0xac, 0x88, 0xf2, 0xa0, 0x3b, 0x74, 0x46, 0x3d, 0x6a, 0x21, + 0xda, 0xb9, 0xe5, 0x11, 0x5f, 0x49, 0xb6, 0x0c, 0x7a, 0xda, 0x8e, 0xc5, 0xe4, 0x14, 0xc8, 0x65, + 0x9c, 0xf1, 0x79, 0x21, 0xf9, 0xf4, 0x4b, 0x91, 0xde, 0x73, 0x29, 0x96, 0x65, 0xe0, 0x2b, 0x03, + 0x07, 0x34, 0x78, 0xca, 0x4b, 0x9e, 0x33, 0x3c, 0x1b, 0x94, 0x29, 0x0b, 0x49, 0x08, 0x83, 0xe9, + 0x9a, 0x49, 0xbe, 0x98, 0xf2, 0xb9, 0xe4, 0x79, 0xd0, 0x57, 0xea, 0x1d, 0x19, 0xee, 0xb9, 0x96, + 0x2b, 0x16, 0x8b, 0xdf, 0xb3, 0x5c, 0x24, 0x71, 0x30, 0xd0, 0x7b, 0x9a, 0x32, 0x8c, 0x12, 0x4d, + 0x22, 0x1e, 0x3c, 0xd3, 0x51, 0xc2, 0x35, 0xf9, 0x16, 0xf8, 0xc6, 0x19, 0x7a, 0x13, 0x1c, 0x29, + 0x45, 0x2d, 0x08, 0xff, 0xee, 0x80, 0x3f, 0x61, 0xd9, 0x7a, 0x96, 0x30, 0xb9, 0x78, 0xa7, 0x4c, + 0x7c, 0x08, 0xde, 0x9c, 0x47, 0x51, 0x16, 0xb8, 0x43, 0x77, 0xd4, 0x3f, 0x7b, 0xff, 0xb4, 0x4a, + 0x71, 0x65, 0xe7, 0x82, 0x47, 0x11, 0xd5, 0xbb, 0xc8, 0x47, 0xe0, 0xe7, 0x7c, 0x93, 0x46, 0x2c, + 0xe7, 0x59, 0xd0, 0x56, 0x3f, 0x21, 0xf5, 0x4f, 0x6e, 0x8d, 0x8a, 0xd6, 0x9b, 0xf6, 0x1c, 0xf5, + 0xf6, 0x1d, 0x0d, 0xbf, 0x72, 0xe1, 0xd9, 0xce, 0x71, 0x64, 0x00, 0xce, 0x56, 0xdd, 0xdc, 0xa3, + 0xce, 0x16, 0x51, 0xa9, 0x6e, 0xed, 0x51, 0xa7, 0x44, 0xf4, 0xa8, 0x2a, 0xc7, 0xa3, 0xce, 0x23, + 0xa2, 0xb5, 0xaa, 0x17, 0x8f, 0x3a, 0x6b, 0xf2, 0x43, 0xe8, 0xfe, 0xae, 0xe0, 0x52, 0xf0, 0x2c, + 0xf0, 0xd4, 0xed, 0xbe, 0x56, 0xdf, 0xee, 0x75, 0xc1, 0x65, 0x49, 0xad, 0x1e, 0xa3, 0xa1, 0x6a, + 0x4d, 0x17, 0x8e, 0x5a, 0xa3, 0x2c, 0xc7, 0xba, 0xec, 0x6a, 0x19, 0xae, 0x4d, 0x14, 0x75, 0xb5, + 0x60, 0x14, 0x7f, 0x06, 0x6d, 0xb6, 0xe5, 0x59, 0xe0, 0x2b, 0xfb, 0xdf, 0x79, 0x43, 0xc0, 0x4e, + 0xc7, 0x5b, 0x9e, 0xfd, 0x32, 0xce, 0x65, 0x49, 0xd5, 0x76, 0xf2, 0x03, 0xe8, 0xcc, 0x93, 0x28, + 0x91, 0x59, 0x00, 0x4f, 0x2f, 0x76, 0x81, 0x72, 0x6a, 0xd4, 0x64, 0x04, 0x9d, 0x88, 0xaf, 0x78, + 0xbc, 0x50, 0x75, 0xd3, 0x3f, 0x3b, 0xae, 0x37, 0x5e, 0x29, 0x39, 0x35, 0x7a, 0xf2, 0x09, 0x0c, + 0x72, 0x36, 0x8b, 0xf8, 0x75, 0x8a, 0x51, 0xcc, 0x54, 0x0d, 0xf5, 0xcf, 0xde, 0x6b, 0xe4, 0xa3, + 0xa1, 0xa5, 0x3b, 0x7b, 0xc9, 0xa7, 0x30, 0x58, 0x0a, 0x1e, 0x2d, 0xec, 0x6f, 0x9f, 0xa9, 0x4b, + 0x05, 0xf5, 0x6f, 0x29, 0x8f, 0xd9, 0x06, 0x7f, 0xf1, 0x1c, 0xb7, 0xd1, 0x9d, 0xdd, 0x1f, 0x7c, + 0x0e, 0x7e, 0xe5, 0x1f, 0x36, 0xe0, 0x97, 0xbc, 0x54, 0xd9, 0xf2, 0x29, 0x2e, 0xc9, 0x77, 0xc1, + 0x7b, 0x60, 0x51, 0xa1, 0x2b, 0xad, 0x7f, 0x76, 0x54, 0x5b, 0x1d, 0x6f, 0x45, 0x46, 0xb5, 0xf2, + 0x93, 0xd6, 0xcf, 0x9d, 0xf0, 0x5f, 0x0e, 0x0c, 0x9a, 0xb7, 0x24, 0xdf, 0x06, 0xc8, 0xc5, 0x86, + 0x3f, 0x4f, 0xe4, 0x86, 0xe5, 0xc6, 0x66, 0x43, 0x42, 0x7e, 0x04, 0xc7, 0x0f, 0x5c, 0xe6, 0x62, + 0xce, 0xa2, 0x5b, 0xb1, 0xe1, 0x68, 0x4f, 0x9d, 0xd2, 0xa3, 0x7b, 0x72, 0xf2, 0x11, 0x74, 0xb2, + 0x44, 0xe6, 0xe7, 0xa5, 0xaa, 0x96, 0xb7, 0x79, 0x67, 0xf6, 0x21, 0x3f, 0x3c, 0x4a, 0x96, 0xa6, + 0x22, 0x5e, 0x59, 0x0e, 0xb2, 0x98, 0x7c, 0x1f, 0x8e, 0x96, 0x62, 0xfb, 0x5c, 0xc8, 0x2c, 0xbf, + 0x48, 0xa2, 0x62, 0xa3, 0x4b, 0xb9, 0x47, 0x9f, 0x48, 0xc3, 0x3f, 0x3a, 0x70, 0xb4, 0x6b, 0x1e, + 0x7b, 0xc0, 0x9e, 0xac, 0x1a, 0x50, 0xbb, 0xb5, 0x23, 0x23, 0x43, 0xe8, 0x2f, 0x44, 0x96, 0x46, + 0xac, 0x6c, 0xf4, 0x68, 0x53, 0x84, 0x84, 0xf3, 0x20, 0x32, 0x31, 0x8b, 0x34, 0x6f, 0xf6, 0xa8, + 0x85, 0x48, 0x0a, 0xa9, 0xe4, 0x73, 0x91, 0x61, 0x83, 0xe9, 0x5e, 0xa8, 0x05, 0xe1, 0x0a, 0x3c, + 0x55, 0x61, 0x0d, 0x3e, 0xf0, 0x2d, 0x1f, 0x28, 0x16, 0x6e, 0x35, 0x58, 0xf8, 0x18, 0xdc, 0x5f, + 0xf1, 0xad, 0x21, 0x66, 0x5c, 0x56, 0xac, 0xd1, 0x6e, 0xb0, 0xc6, 0x09, 0x78, 0xf7, 0x2a, 0xc1, + 0xba, 0x9b, 0x35, 0x08, 0x3f, 0x83, 0x8e, 0xae, 0xd0, 0xca, 0xb2, 0xd3, 0xb0, 0x3c, 0x84, 0xfe, + 0xb5, 0x14, 0x3c, 0xce, 0x35, 0x0f, 0x18, 0x07, 0x1b, 0xa2, 0xf0, 0x6f, 0x0e, 0xb4, 0x55, 0xe2, + 0x42, 0x18, 0x44, 0x7c, 0xc5, 0xe6, 0xe5, 0x79, 0x52, 0xc4, 0x8b, 0x2c, 0x70, 0x86, 0xee, 0xc8, + 0xa5, 0x3b, 0x32, 0xf2, 0x1e, 0x74, 0x66, 0x5a, 0xdb, 0x1a, 0xba, 0x23, 0x9f, 0x1a, 0x84, 0x57, + 0x8b, 0xd8, 0x8c, 0x47, 0xc6, 0x05, 0x0d, 0x70, 0x77, 0x2a, 0xf9, 0x52, 0x6c, 0x8d, 0x1b, 0x06, + 0xa1, 0x3c, 0x2b, 0x96, 0x28, 0xd7, 0x9e, 0x18, 0x84, 0x0e, 0xcc, 0x58, 0x56, 0x91, 0x03, 0xae, + 0xd1, 0x72, 0x36, 0x67, 0x91, 0x65, 0x07, 0x0d, 0xc2, 0x7f, 0x38, 0xf8, 0xa6, 0x68, 0xb6, 0xdb, + 0x8b, 0xf0, 0x37, 0xa0, 0x87, 0x4c, 0xf8, 0xc5, 0x03, 0x93, 0xc6, 0xe1, 0x2e, 0xe2, 0x7b, 0x26, + 0xc9, 0x4f, 0xa1, 0xa3, 0xda, 0xe0, 0x00, 0xf3, 0x5a, 0x73, 0x2a, 0xaa, 0xd4, 0x6c, 0xab, 0xb8, + 0xa9, 0xdd, 0xe0, 0xa6, 0xca, 0x59, 0xaf, 0xe9, 0xec, 0x87, 0xe0, 0x21, 0xc9, 0x95, 0xea, 0xf6, + 0x07, 0x2d, 0x6b, 0x2a, 0xd4, 0xbb, 0xc2, 0x3b, 0x78, 0xb6, 0x73, 0x62, 0x75, 0x92, 0xb3, 0x7b, + 0x52, 0xdd, 0xd2, 0xbe, 0x69, 0x61, 0xec, 0x97, 0x8c, 0x47, 0x7c, 0x9e, 0xf3, 0x85, 0xa9, 0xc9, + 0x0a, 0x87, 0x7f, 0x76, 0x6a, 0xbb, 0xea, 0x3c, 0x2c, 0xe0, 0x79, 0xb2, 0xd9, 0xb0, 0x78, 0x61, + 0x4c, 0x5b, 0x88, 0x71, 0x5b, 0xcc, 0x8c, 0xe9, 0xd6, 0x62, 0x86, 0x58, 0xa6, 0x26, 0x83, 0x2d, + 0x99, 0x62, 0xed, 0x6c, 0x38, 0xcb, 0x0a, 0xc9, 0x37, 0x3c, 0xce, 0x4d, 0x08, 0x9a, 0x22, 0xf2, + 0x3e, 0x74, 0x73, 0xb6, 0xfa, 0x02, 0x89, 0xc8, 0x64, 0x32, 0x67, 0xab, 0x17, 0xbc, 0x24, 0xdf, + 0x04, 0x5f, 0x51, 0x97, 0x52, 0xe9, 0x74, 0xf6, 0x94, 0xe0, 0x05, 0x2f, 0xc3, 0x7f, 0x3b, 0xd0, + 0x99, 0x72, 0xf9, 0xc0, 0xe5, 0x3b, 0x3d, 0x96, 0xcd, 0x11, 0xc5, 0x7d, 0xcb, 0x88, 0xd2, 0x3e, + 0x3c, 0xa2, 0x78, 0xf5, 0x88, 0x72, 0x02, 0xde, 0x54, 0xce, 0x2f, 0x27, 0xea, 0x46, 0x2e, 0xd5, + 0x00, 0xab, 0x71, 0x3c, 0xcf, 0xc5, 0x03, 0x37, 0x73, 0x8b, 0x41, 0x7b, 0x6f, 0x68, 0xef, 0xc0, + 0xb0, 0xf0, 0x5f, 0x8e, 0x2f, 0xe1, 0x9f, 0x1c, 0xe8, 0x5c, 0xb1, 0x32, 0x29, 0xf2, 0xbd, 0xaa, + 0x1d, 0x42, 0x7f, 0x9c, 0xa6, 0x91, 0x98, 0xef, 0x74, 0x6a, 0x43, 0x84, 0x3b, 0x5e, 0x36, 0xf2, + 0xa1, 0x63, 0xd1, 0x14, 0xe1, 0x13, 0x70, 0xa1, 0xe6, 0x0a, 0x3d, 0x24, 0x34, 0x9e, 0x00, 0x3d, + 0x4e, 0x28, 0x25, 0x06, 0x6d, 0x5c, 0xe4, 0xc9, 0x32, 0x4a, 0x1e, 0x0d, 0x9b, 0x56, 0x38, 0xfc, + 0x67, 0x0b, 0xda, 0xff, 0xaf, 0x59, 0x60, 0x00, 0x8e, 0x30, 0xc5, 0xe1, 0x88, 0x6a, 0x32, 0xe8, + 0x36, 0x26, 0x83, 0x00, 0xba, 0xa5, 0x64, 0xf1, 0x8a, 0x67, 0x41, 0x4f, 0xb1, 0x91, 0x85, 0x4a, + 0xa3, 0xfa, 0x4e, 0x8f, 0x04, 0x3e, 0xb5, 0xb0, 0xea, 0x23, 0x68, 0xf4, 0xd1, 0x4f, 0xcc, 0xf4, + 0xd0, 0x7f, 0xfa, 0xde, 0x1e, 0x1a, 0x1a, 0xfe, 0x77, 0xef, 0xec, 0x57, 0x0e, 0x78, 0x55, 0x13, + 0x5e, 0xec, 0x36, 0xe1, 0x45, 0xdd, 0x84, 0x93, 0x73, 0xdb, 0x84, 0x93, 0x73, 0xc4, 0xf4, 0xc6, + 0x36, 0x21, 0xbd, 0xc1, 0x64, 0x7d, 0x2e, 0x93, 0x22, 0x3d, 0x2f, 0x75, 0x56, 0x7d, 0x5a, 0x61, + 0xac, 0xdc, 0xdf, 0xac, 0xb9, 0x34, 0xa1, 0xf6, 0xa9, 0x41, 0x58, 0xe7, 0x57, 0x8a, 0xa0, 0x74, + 0x70, 0x35, 0x20, 0xdf, 0x03, 0x8f, 0x62, 0xf0, 0x54, 0x84, 0x77, 0xf2, 0xa2, 0xc4, 0x54, 0x6b, + 0xd1, 0xa8, 0xfe, 0xa6, 0x30, 0x05, 0x6f, 0xbf, 0x30, 0x7e, 0x0c, 0x9d, 0xe9, 0x5a, 0x2c, 0x73, + 0x3b, 0x83, 0x7d, 0xbd, 0x41, 0x70, 0x62, 0xc3, 0x95, 0x8e, 0x9a, 0x2d, 0xe1, 0x6b, 0xf0, 0x2b, + 0x61, 0x7d, 0x1d, 0xa7, 0x79, 0x1d, 0x02, 0xed, 0xbb, 0x58, 0xe4, 0xb6, 0xd5, 0x71, 0x8d, 0xce, + 0xbe, 0x2e, 0x58, 0x9c, 0x8b, 0xbc, 0xb4, 0xad, 0x6e, 0x71, 0xf8, 0xb1, 0xb9, 0x3e, 0x9a, 0xbb, + 0x4b, 0x53, 0x2e, 0x0d, 0x6d, 0x68, 0xa0, 0x0e, 0x49, 0x1e, 0xb9, 0x66, 0x7c, 0x97, 0x6a, 0x10, + 0xfe, 0x16, 0xfc, 0x71, 0xc4, 0x65, 0x4e, 0x8b, 0x88, 0x1f, 0x7a, 0x89, 0x7f, 0x3d, 0xbd, 0x7e, + 0x65, 0x6f, 0x80, 0xeb, 0x9a, 0x22, 0xdc, 0x27, 0x14, 0xf1, 0x82, 0xa5, 0xec, 0x72, 0xa2, 0xea, + 0xdc, 0xa5, 0x06, 0x85, 0x7f, 0x71, 0xa0, 0x8d, 0x5c, 0xd4, 0x30, 0xdd, 0x7e, 0x1b, 0x8f, 0xdd, + 0xc8, 0xe4, 0x41, 0x2c, 0xb8, 0xb4, 0xce, 0x59, 0xac, 0x82, 0x3e, 0x5f, 0xf3, 0xea, 0xc1, 0x37, + 0x08, 0x6b, 0x0d, 0x3f, 0x40, 0x6c, 0x2f, 0x35, 0x6a, 0x0d, 0xc5, 0x54, 0x2b, 0x71, 0x7c, 0x9b, + 0x16, 0x29, 0x97, 0xe3, 0xc5, 0x46, 0xc4, 0x2a, 0xe9, 0x3d, 0xda, 0x90, 0x84, 0x9f, 0xe9, 0x4f, + 0x9a, 0x3d, 0x46, 0x73, 0x0e, 0x7f, 0xfe, 0x3c, 0xbd, 0x79, 0xf8, 0x57, 0x07, 0xba, 0x2f, 0xcd, + 0x40, 0xd6, 0xf4, 0xc2, 0x79, 0xa3, 0x17, 0xad, 0x1d, 0x2f, 0xce, 0xe0, 0xc4, 0xee, 0xd9, 0x39, + 0x5f, 0x47, 0xe1, 0xa0, 0xce, 0x44, 0xb4, 0x5d, 0x25, 0xeb, 0x5d, 0xbe, 0x68, 0x6e, 0x77, 0xf7, + 0x1c, 0x4a, 0xf8, 0x5e, 0x56, 0x86, 0xd0, 0xb7, 0x5f, 0x72, 0x49, 0x64, 0x1f, 0x98, 0xa6, 0x28, + 0x3c, 0x83, 0xce, 0x45, 0x12, 0x2f, 0xc5, 0x8a, 0x8c, 0xa0, 0x3d, 0x2e, 0xf2, 0xb5, 0xb2, 0xd8, + 0x3f, 0x3b, 0x69, 0x34, 0x7e, 0x91, 0xaf, 0xf5, 0x1e, 0xaa, 0x76, 0x84, 0x9f, 0x02, 0xd4, 0x32, + 0x7c, 0x25, 0xea, 0x6c, 0xbc, 0xe2, 0x8f, 0x58, 0x32, 0x99, 0xb2, 0xd2, 0xa3, 0x07, 0x34, 0xe1, + 0x2f, 0xc0, 0x3f, 0x2f, 0x44, 0xb4, 0xb8, 0x8c, 0x97, 0x09, 0x52, 0xc7, 0x3d, 0x97, 0x59, 0x9d, + 0x2f, 0x0b, 0x31, 0xdc, 0xc8, 0x22, 0x55, 0x0f, 0x19, 0x34, 0xeb, 0xa8, 0xff, 0x09, 0x3e, 0xfe, + 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x5f, 0x83, 0xed, 0xad, 0x39, 0x10, 0x00, 0x00, } diff --git a/bolt/internal/internal.proto b/bolt/internal/internal.proto index b680b62002..2fc1d65ce8 100644 --- a/bolt/internal/internal.proto +++ b/bolt/internal/internal.proto @@ -39,6 +39,7 @@ message DashboardCell { repeated Color colors = 10; // Colors represent encoding data values to color Legend legend = 11; // Legend is summary information for a cell TableOptions tableOptions = 12; // TableOptions for visualization of cell with type 'table' + repeated RenamableField fieldOptions = 13; // Options for each of the fields returned in a cell } message TableOptions { @@ -46,14 +47,14 @@ message TableOptions { bool verticalTimeAxis = 2; // time axis should be a column not row RenamableField sortBy = 3; // which column should a table be sorted by string wrapping = 4; // option for text wrapping - repeated RenamableField fieldNames = 5; // names and renames for column/row fields - bool fixFirstColumn = 6; // first column should be fixed/frozen + bool fixFirstColumn = 5; // first column should be fixed/frozen } message RenamableField { string internalName = 1; // name of column string displayName = 2; // what column is renamed to bool visible = 3; // Represents whether RenamableField is visible + int32 precision = 4; // Represents how precise the values of this field should be } message Color { diff --git a/chronograf.go b/chronograf.go index bdc9d5fc9d..a14de9a41e 100644 --- a/chronograf.go +++ b/chronograf.go @@ -575,6 +575,7 @@ type DashboardCell struct { CellColors []CellColor `json:"colors"` Legend Legend `json:"legend"` TableOptions TableOptions `json:"tableOptions,omitempty"` + FieldOptions []RenamableField `json:"fieldOptions"` } // RenamableField is a column/row field in a DashboardCell of type Table @@ -582,16 +583,16 @@ type RenamableField struct { InternalName string `json:"internalName"` DisplayName string `json:"displayName"` Visible bool `json:"visible"` + Precision int32 `json:"precision"` } // TableOptions is a type of options for a DashboardCell with type Table type TableOptions struct { - TimeFormat string `json:"timeFormat"` - VerticalTimeAxis bool `json:"verticalTimeAxis"` - SortBy RenamableField `json:"sortBy"` - Wrapping string `json:"wrapping"` - FieldNames []RenamableField `json:"fieldNames"` - FixFirstColumn bool `json:"fixFirstColumn"` + TimeFormat string `json:"timeFormat"` + VerticalTimeAxis bool `json:"verticalTimeAxis"` + SortBy RenamableField `json:"sortBy"` + Wrapping string `json:"wrapping"` + FixFirstColumn bool `json:"fixFirstColumn"` } // DashboardsStore is the storage and retrieval of dashboards From 8e11d3d05716fb3f424981a214c86d2cfae74a35 Mon Sep 17 00:00:00 2001 From: Iris Scholten Date: Wed, 18 Apr 2018 17:08:26 -0700 Subject: [PATCH 02/48] Update go tests by removing FieldNames from TableOptions and adding FieldOptions to DashboardCell Add precision to sortBy values --- bolt/internal/internal_test.go | 29 +++++++++++++++-------------- integrations/server_test.go | 10 ++++++---- server/cells_test.go | 2 +- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/bolt/internal/internal_test.go b/bolt/internal/internal_test.go index 75c87816f1..cf66c41fd3 100644 --- a/bolt/internal/internal_test.go +++ b/bolt/internal/internal_test.go @@ -196,8 +196,8 @@ func Test_MarshalDashboard(t *testing.T) { }, TableOptions: chronograf.TableOptions{ TimeFormat: "", - FieldNames: []chronograf.RenamableField{}, }, + FieldOptions: []chronograf.RenamableField{}, }, }, Templates: []chronograf.Template{}, @@ -263,7 +263,8 @@ func Test_MarshalDashboard_WithLegacyBounds(t *testing.T) { TableOptions: chronograf.TableOptions{ TimeFormat: "MM:DD:YYYY", }, - Type: "line", + FieldOptions: []chronograf.RenamableField{}, + Type: "line", }, }, Templates: []chronograf.Template{}, @@ -319,9 +320,9 @@ func Test_MarshalDashboard_WithLegacyBounds(t *testing.T) { }, TableOptions: chronograf.TableOptions{ TimeFormat: "MM:DD:YYYY", - FieldNames: []chronograf.RenamableField{}, }, - Type: "line", + FieldOptions: []chronograf.RenamableField{}, + Type: "line", }, }, Templates: []chronograf.Template{}, @@ -384,6 +385,7 @@ func Test_MarshalDashboard_WithEmptyLegacyBounds(t *testing.T) { TableOptions: chronograf.TableOptions{ TimeFormat: "MM:DD:YYYY", }, + FieldOptions: []chronograf.RenamableField{}, }, }, Templates: []chronograf.Template{}, @@ -435,9 +437,9 @@ func Test_MarshalDashboard_WithEmptyLegacyBounds(t *testing.T) { }, TableOptions: chronograf.TableOptions{ TimeFormat: "MM:DD:YYYY", - FieldNames: []chronograf.RenamableField{}, }, - Type: "line", + FieldOptions: []chronograf.RenamableField{}, + Type: "line", }, }, Templates: []chronograf.Template{}, @@ -468,14 +470,13 @@ func Test_MarshalDashboard_WithEmptyCellType(t *testing.T) { ID: 1, Cells: []chronograf.DashboardCell{ { - ID: "9b5367de-c552-4322-a9e8-7f384cbd235c", - Type: "line", - Queries: []chronograf.DashboardQuery{}, - Axes: map[string]chronograf.Axis{}, - CellColors: []chronograf.CellColor{}, - TableOptions: chronograf.TableOptions{ - FieldNames: []chronograf.RenamableField{}, - }, + ID: "9b5367de-c552-4322-a9e8-7f384cbd235c", + Type: "line", + Queries: []chronograf.DashboardQuery{}, + Axes: map[string]chronograf.Axis{}, + CellColors: []chronograf.CellColor{}, + TableOptions: chronograf.TableOptions{}, + FieldOptions: []chronograf.RenamableField{}, }, }, Templates: []chronograf.Template{}, diff --git a/integrations/server_test.go b/integrations/server_test.go index 8cce376861..19b5911cf9 100644 --- a/integrations/server_test.go +++ b/integrations/server_test.go @@ -553,12 +553,13 @@ func TestServer(t *testing.T) { "sortBy":{ "internalName": "", "displayName": "", - "visible": false + "visible": false, + "precision": 0 }, "wrapping": "", - "fieldNames": null, "fixFirstColumn": false }, + "fieldOptions": null, "links": { "self": "/chronograf/v1/dashboards/1000/cells/8f61c619-dd9b-4761-8aa8-577f27247093" } @@ -804,12 +805,13 @@ func TestServer(t *testing.T) { "sortBy":{ "internalName":"", "displayName":"", - "visible":false + "visible":false, + "precision":0 }, "wrapping":"", - "fieldNames":null, "fixFirstColumn":false }, + "fieldOptions":null, "legend":{ "type": "static", "orientation": "bottom" diff --git a/server/cells_test.go b/server/cells_test.go index 38c2ef5c5e..20eeec392f 100644 --- a/server/cells_test.go +++ b/server/cells_test.go @@ -532,7 +532,7 @@ func TestService_ReplaceDashboardCell(t *testing.T) { } } `))), - want: `{"i":"3c5c4102-fa40-4585-a8f9-917c77e37192","x":0,"y":0,"w":4,"h":4,"name":"Untitled Cell","queries":[{"query":"SELECT mean(\"usage_user\") AS \"mean_usage_user\" FROM \"telegraf\".\"autogen\".\"cpu\" WHERE time \u003e :dashboardTime: AND \"cpu\"=:cpu: GROUP BY :interval: FILL(null)","queryConfig":{"id":"3cd3eaa4-a4b8-44b3-b69e-0c7bf6b91d9e","database":"telegraf","measurement":"cpu","retentionPolicy":"autogen","fields":[{"value":"mean","type":"func","alias":"mean_usage_user","args":[{"value":"usage_user","type":"field","alias":""}]}],"tags":{"cpu":["ChristohersMBP2.lan"]},"groupBy":{"time":"2s","tags":[]},"areTagsAccepted":true,"fill":"null","rawText":"SELECT mean(\"usage_user\") AS \"mean_usage_user\" FROM \"telegraf\".\"autogen\".\"cpu\" WHERE time \u003e :dashboardTime: AND \"cpu\"=:cpu: GROUP BY :interval: FILL(null)","range":{"upper":"","lower":"now() - 15m"},"shifts":[]},"source":""}],"axes":{"x":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""},"y":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""},"y2":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""}},"type":"line","colors":[{"id":"0","type":"min","hex":"#00C9FF","name":"laser","value":"0"},{"id":"1","type":"max","hex":"#9394FF","name":"comet","value":"100"}],"legend":{},"tableOptions":{"timeFormat":"","verticalTimeAxis":false,"sortBy":{"internalName":"","displayName":"","visible":false},"wrapping":"","fieldNames":null,"fixFirstColumn":false},"links":{"self":"/chronograf/v1/dashboards/1/cells/3c5c4102-fa40-4585-a8f9-917c77e37192"}} + want: `{"i":"3c5c4102-fa40-4585-a8f9-917c77e37192","x":0,"y":0,"w":4,"h":4,"name":"Untitled Cell","queries":[{"query":"SELECT mean(\"usage_user\") AS \"mean_usage_user\" FROM \"telegraf\".\"autogen\".\"cpu\" WHERE time \u003e :dashboardTime: AND \"cpu\"=:cpu: GROUP BY :interval: FILL(null)","queryConfig":{"id":"3cd3eaa4-a4b8-44b3-b69e-0c7bf6b91d9e","database":"telegraf","measurement":"cpu","retentionPolicy":"autogen","fields":[{"value":"mean","type":"func","alias":"mean_usage_user","args":[{"value":"usage_user","type":"field","alias":""}]}],"tags":{"cpu":["ChristohersMBP2.lan"]},"groupBy":{"time":"2s","tags":[]},"areTagsAccepted":true,"fill":"null","rawText":"SELECT mean(\"usage_user\") AS \"mean_usage_user\" FROM \"telegraf\".\"autogen\".\"cpu\" WHERE time \u003e :dashboardTime: AND \"cpu\"=:cpu: GROUP BY :interval: FILL(null)","range":{"upper":"","lower":"now() - 15m"},"shifts":[]},"source":""}],"axes":{"x":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""},"y":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""},"y2":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""}},"type":"line","colors":[{"id":"0","type":"min","hex":"#00C9FF","name":"laser","value":"0"},{"id":"1","type":"max","hex":"#9394FF","name":"comet","value":"100"}],"legend":{},"tableOptions":{"timeFormat":"","verticalTimeAxis":false,"sortBy":{"internalName":"","displayName":"","visible":false,"precision":0},"wrapping":"","fixFirstColumn":false},"fieldOptions":null,"links":{"self":"/chronograf/v1/dashboards/1/cells/3c5c4102-fa40-4585-a8f9-917c77e37192"}} `, }, { From 9d14e24c0f0be9834d944b00086001086a3d3ef1 Mon Sep 17 00:00:00 2001 From: Iris Scholten Date: Thu, 19 Apr 2018 09:55:50 -0700 Subject: [PATCH 03/48] Change bool fixFirstColumn back to index 6 and reserve index 5 in internal.proto --- bolt/internal/internal.pb.go | 206 +++++++++++++++++------------------ bolt/internal/internal.proto | 3 +- 2 files changed, 105 insertions(+), 104 deletions(-) diff --git a/bolt/internal/internal.pb.go b/bolt/internal/internal.pb.go index 8b8a23a8f8..ccc50f8b5a 100644 --- a/bolt/internal/internal.pb.go +++ b/bolt/internal/internal.pb.go @@ -336,7 +336,7 @@ type TableOptions struct { VerticalTimeAxis bool `protobuf:"varint,2,opt,name=verticalTimeAxis,proto3" json:"verticalTimeAxis,omitempty"` SortBy *RenamableField `protobuf:"bytes,3,opt,name=sortBy" json:"sortBy,omitempty"` Wrapping string `protobuf:"bytes,4,opt,name=wrapping,proto3" json:"wrapping,omitempty"` - FixFirstColumn bool `protobuf:"varint,5,opt,name=fixFirstColumn,proto3" json:"fixFirstColumn,omitempty"` + FixFirstColumn bool `protobuf:"varint,6,opt,name=fixFirstColumn,proto3" json:"fixFirstColumn,omitempty"` } func (m *TableOptions) Reset() { *m = TableOptions{} } @@ -1346,106 +1346,106 @@ func init() { func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) } var fileDescriptorInternal = []byte{ - // 1614 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x5b, 0x8f, 0xe3, 0x48, - 0x15, 0x96, 0xe3, 0x38, 0x89, 0x4f, 0x32, 0x4d, 0xab, 0x68, 0xed, 0x9a, 0x05, 0xa1, 0x60, 0x71, - 0x09, 0x97, 0x6d, 0x56, 0xbd, 0x42, 0x42, 0xab, 0x65, 0xa5, 0x74, 0x87, 0x59, 0x9a, 0xe9, 0x99, - 0xee, 0xa9, 0x74, 0x37, 0x4f, 0x68, 0x55, 0x49, 0x2a, 0x49, 0x69, 0x1d, 0xdb, 0x94, 0xed, 0xee, - 0x98, 0x67, 0x9e, 0xf9, 0x09, 0x48, 0x48, 0xf0, 0x07, 0x10, 0xef, 0xbc, 0xf3, 0xc4, 0xbf, 0x59, - 0x1e, 0xd1, 0xa9, 0x8b, 0xed, 0x74, 0x32, 0xa3, 0x41, 0x42, 0xbc, 0xd5, 0x77, 0x4e, 0xe5, 0x54, - 0x9d, 0xdb, 0x57, 0xc7, 0x81, 0x23, 0x11, 0xe7, 0x5c, 0xc6, 0x2c, 0x3a, 0x4d, 0x65, 0x92, 0x27, - 0xa4, 0x67, 0x71, 0xf8, 0x07, 0x17, 0x3a, 0xd3, 0xa4, 0x90, 0x73, 0x4e, 0x8e, 0xa0, 0x75, 0x39, - 0x09, 0x9c, 0xa1, 0x33, 0x72, 0x69, 0xeb, 0x72, 0x42, 0x08, 0xb4, 0x5f, 0xb1, 0x0d, 0x0f, 0x5a, - 0x43, 0x67, 0xe4, 0x53, 0xb5, 0x46, 0xd9, 0x6d, 0x99, 0xf2, 0xc0, 0xd5, 0x32, 0x5c, 0x93, 0x0f, - 0xa0, 0x77, 0x97, 0xa1, 0xb5, 0x0d, 0x0f, 0xda, 0x4a, 0x5e, 0x61, 0xd4, 0xdd, 0xb0, 0x2c, 0x7b, - 0x4c, 0xe4, 0x22, 0xf0, 0xb4, 0xce, 0x62, 0x72, 0x0c, 0xee, 0x1d, 0xbd, 0x0a, 0x3a, 0x4a, 0x8c, - 0x4b, 0x12, 0x40, 0x77, 0xc2, 0x97, 0xac, 0x88, 0xf2, 0xa0, 0x3b, 0x74, 0x46, 0x3d, 0x6a, 0x21, - 0xda, 0xb9, 0xe5, 0x11, 0x5f, 0x49, 0xb6, 0x0c, 0x7a, 0xda, 0x8e, 0xc5, 0xe4, 0x14, 0xc8, 0x65, - 0x9c, 0xf1, 0x79, 0x21, 0xf9, 0xf4, 0x4b, 0x91, 0xde, 0x73, 0x29, 0x96, 0x65, 0xe0, 0x2b, 0x03, - 0x07, 0x34, 0x78, 0xca, 0x4b, 0x9e, 0x33, 0x3c, 0x1b, 0x94, 0x29, 0x0b, 0x49, 0x08, 0x83, 0xe9, - 0x9a, 0x49, 0xbe, 0x98, 0xf2, 0xb9, 0xe4, 0x79, 0xd0, 0x57, 0xea, 0x1d, 0x19, 0xee, 0xb9, 0x96, - 0x2b, 0x16, 0x8b, 0xdf, 0xb3, 0x5c, 0x24, 0x71, 0x30, 0xd0, 0x7b, 0x9a, 0x32, 0x8c, 0x12, 0x4d, - 0x22, 0x1e, 0x3c, 0xd3, 0x51, 0xc2, 0x35, 0xf9, 0x16, 0xf8, 0xc6, 0x19, 0x7a, 0x13, 0x1c, 0x29, - 0x45, 0x2d, 0x08, 0xff, 0xee, 0x80, 0x3f, 0x61, 0xd9, 0x7a, 0x96, 0x30, 0xb9, 0x78, 0xa7, 0x4c, - 0x7c, 0x08, 0xde, 0x9c, 0x47, 0x51, 0x16, 0xb8, 0x43, 0x77, 0xd4, 0x3f, 0x7b, 0xff, 0xb4, 0x4a, - 0x71, 0x65, 0xe7, 0x82, 0x47, 0x11, 0xd5, 0xbb, 0xc8, 0x47, 0xe0, 0xe7, 0x7c, 0x93, 0x46, 0x2c, - 0xe7, 0x59, 0xd0, 0x56, 0x3f, 0x21, 0xf5, 0x4f, 0x6e, 0x8d, 0x8a, 0xd6, 0x9b, 0xf6, 0x1c, 0xf5, - 0xf6, 0x1d, 0x0d, 0xbf, 0x72, 0xe1, 0xd9, 0xce, 0x71, 0x64, 0x00, 0xce, 0x56, 0xdd, 0xdc, 0xa3, - 0xce, 0x16, 0x51, 0xa9, 0x6e, 0xed, 0x51, 0xa7, 0x44, 0xf4, 0xa8, 0x2a, 0xc7, 0xa3, 0xce, 0x23, - 0xa2, 0xb5, 0xaa, 0x17, 0x8f, 0x3a, 0x6b, 0xf2, 0x43, 0xe8, 0xfe, 0xae, 0xe0, 0x52, 0xf0, 0x2c, - 0xf0, 0xd4, 0xed, 0xbe, 0x56, 0xdf, 0xee, 0x75, 0xc1, 0x65, 0x49, 0xad, 0x1e, 0xa3, 0xa1, 0x6a, - 0x4d, 0x17, 0x8e, 0x5a, 0xa3, 0x2c, 0xc7, 0xba, 0xec, 0x6a, 0x19, 0xae, 0x4d, 0x14, 0x75, 0xb5, - 0x60, 0x14, 0x7f, 0x06, 0x6d, 0xb6, 0xe5, 0x59, 0xe0, 0x2b, 0xfb, 0xdf, 0x79, 0x43, 0xc0, 0x4e, - 0xc7, 0x5b, 0x9e, 0xfd, 0x32, 0xce, 0x65, 0x49, 0xd5, 0x76, 0xf2, 0x03, 0xe8, 0xcc, 0x93, 0x28, - 0x91, 0x59, 0x00, 0x4f, 0x2f, 0x76, 0x81, 0x72, 0x6a, 0xd4, 0x64, 0x04, 0x9d, 0x88, 0xaf, 0x78, - 0xbc, 0x50, 0x75, 0xd3, 0x3f, 0x3b, 0xae, 0x37, 0x5e, 0x29, 0x39, 0x35, 0x7a, 0xf2, 0x09, 0x0c, - 0x72, 0x36, 0x8b, 0xf8, 0x75, 0x8a, 0x51, 0xcc, 0x54, 0x0d, 0xf5, 0xcf, 0xde, 0x6b, 0xe4, 0xa3, - 0xa1, 0xa5, 0x3b, 0x7b, 0xc9, 0xa7, 0x30, 0x58, 0x0a, 0x1e, 0x2d, 0xec, 0x6f, 0x9f, 0xa9, 0x4b, - 0x05, 0xf5, 0x6f, 0x29, 0x8f, 0xd9, 0x06, 0x7f, 0xf1, 0x1c, 0xb7, 0xd1, 0x9d, 0xdd, 0x1f, 0x7c, - 0x0e, 0x7e, 0xe5, 0x1f, 0x36, 0xe0, 0x97, 0xbc, 0x54, 0xd9, 0xf2, 0x29, 0x2e, 0xc9, 0x77, 0xc1, - 0x7b, 0x60, 0x51, 0xa1, 0x2b, 0xad, 0x7f, 0x76, 0x54, 0x5b, 0x1d, 0x6f, 0x45, 0x46, 0xb5, 0xf2, - 0x93, 0xd6, 0xcf, 0x9d, 0xf0, 0x5f, 0x0e, 0x0c, 0x9a, 0xb7, 0x24, 0xdf, 0x06, 0xc8, 0xc5, 0x86, - 0x3f, 0x4f, 0xe4, 0x86, 0xe5, 0xc6, 0x66, 0x43, 0x42, 0x7e, 0x04, 0xc7, 0x0f, 0x5c, 0xe6, 0x62, - 0xce, 0xa2, 0x5b, 0xb1, 0xe1, 0x68, 0x4f, 0x9d, 0xd2, 0xa3, 0x7b, 0x72, 0xf2, 0x11, 0x74, 0xb2, - 0x44, 0xe6, 0xe7, 0xa5, 0xaa, 0x96, 0xb7, 0x79, 0x67, 0xf6, 0x21, 0x3f, 0x3c, 0x4a, 0x96, 0xa6, - 0x22, 0x5e, 0x59, 0x0e, 0xb2, 0x98, 0x7c, 0x1f, 0x8e, 0x96, 0x62, 0xfb, 0x5c, 0xc8, 0x2c, 0xbf, - 0x48, 0xa2, 0x62, 0xa3, 0x4b, 0xb9, 0x47, 0x9f, 0x48, 0xc3, 0x3f, 0x3a, 0x70, 0xb4, 0x6b, 0x1e, - 0x7b, 0xc0, 0x9e, 0xac, 0x1a, 0x50, 0xbb, 0xb5, 0x23, 0x23, 0x43, 0xe8, 0x2f, 0x44, 0x96, 0x46, - 0xac, 0x6c, 0xf4, 0x68, 0x53, 0x84, 0x84, 0xf3, 0x20, 0x32, 0x31, 0x8b, 0x34, 0x6f, 0xf6, 0xa8, - 0x85, 0x48, 0x0a, 0xa9, 0xe4, 0x73, 0x91, 0x61, 0x83, 0xe9, 0x5e, 0xa8, 0x05, 0xe1, 0x0a, 0x3c, - 0x55, 0x61, 0x0d, 0x3e, 0xf0, 0x2d, 0x1f, 0x28, 0x16, 0x6e, 0x35, 0x58, 0xf8, 0x18, 0xdc, 0x5f, - 0xf1, 0xad, 0x21, 0x66, 0x5c, 0x56, 0xac, 0xd1, 0x6e, 0xb0, 0xc6, 0x09, 0x78, 0xf7, 0x2a, 0xc1, - 0xba, 0x9b, 0x35, 0x08, 0x3f, 0x83, 0x8e, 0xae, 0xd0, 0xca, 0xb2, 0xd3, 0xb0, 0x3c, 0x84, 0xfe, - 0xb5, 0x14, 0x3c, 0xce, 0x35, 0x0f, 0x18, 0x07, 0x1b, 0xa2, 0xf0, 0x6f, 0x0e, 0xb4, 0x55, 0xe2, - 0x42, 0x18, 0x44, 0x7c, 0xc5, 0xe6, 0xe5, 0x79, 0x52, 0xc4, 0x8b, 0x2c, 0x70, 0x86, 0xee, 0xc8, - 0xa5, 0x3b, 0x32, 0xf2, 0x1e, 0x74, 0x66, 0x5a, 0xdb, 0x1a, 0xba, 0x23, 0x9f, 0x1a, 0x84, 0x57, - 0x8b, 0xd8, 0x8c, 0x47, 0xc6, 0x05, 0x0d, 0x70, 0x77, 0x2a, 0xf9, 0x52, 0x6c, 0x8d, 0x1b, 0x06, - 0xa1, 0x3c, 0x2b, 0x96, 0x28, 0xd7, 0x9e, 0x18, 0x84, 0x0e, 0xcc, 0x58, 0x56, 0x91, 0x03, 0xae, - 0xd1, 0x72, 0x36, 0x67, 0x91, 0x65, 0x07, 0x0d, 0xc2, 0x7f, 0x38, 0xf8, 0xa6, 0x68, 0xb6, 0xdb, - 0x8b, 0xf0, 0x37, 0xa0, 0x87, 0x4c, 0xf8, 0xc5, 0x03, 0x93, 0xc6, 0xe1, 0x2e, 0xe2, 0x7b, 0x26, - 0xc9, 0x4f, 0xa1, 0xa3, 0xda, 0xe0, 0x00, 0xf3, 0x5a, 0x73, 0x2a, 0xaa, 0xd4, 0x6c, 0xab, 0xb8, - 0xa9, 0xdd, 0xe0, 0xa6, 0xca, 0x59, 0xaf, 0xe9, 0xec, 0x87, 0xe0, 0x21, 0xc9, 0x95, 0xea, 0xf6, - 0x07, 0x2d, 0x6b, 0x2a, 0xd4, 0xbb, 0xc2, 0x3b, 0x78, 0xb6, 0x73, 0x62, 0x75, 0x92, 0xb3, 0x7b, - 0x52, 0xdd, 0xd2, 0xbe, 0x69, 0x61, 0xec, 0x97, 0x8c, 0x47, 0x7c, 0x9e, 0xf3, 0x85, 0xa9, 0xc9, - 0x0a, 0x87, 0x7f, 0x76, 0x6a, 0xbb, 0xea, 0x3c, 0x2c, 0xe0, 0x79, 0xb2, 0xd9, 0xb0, 0x78, 0x61, - 0x4c, 0x5b, 0x88, 0x71, 0x5b, 0xcc, 0x8c, 0xe9, 0xd6, 0x62, 0x86, 0x58, 0xa6, 0x26, 0x83, 0x2d, - 0x99, 0x62, 0xed, 0x6c, 0x38, 0xcb, 0x0a, 0xc9, 0x37, 0x3c, 0xce, 0x4d, 0x08, 0x9a, 0x22, 0xf2, - 0x3e, 0x74, 0x73, 0xb6, 0xfa, 0x02, 0x89, 0xc8, 0x64, 0x32, 0x67, 0xab, 0x17, 0xbc, 0x24, 0xdf, - 0x04, 0x5f, 0x51, 0x97, 0x52, 0xe9, 0x74, 0xf6, 0x94, 0xe0, 0x05, 0x2f, 0xc3, 0x7f, 0x3b, 0xd0, - 0x99, 0x72, 0xf9, 0xc0, 0xe5, 0x3b, 0x3d, 0x96, 0xcd, 0x11, 0xc5, 0x7d, 0xcb, 0x88, 0xd2, 0x3e, - 0x3c, 0xa2, 0x78, 0xf5, 0x88, 0x72, 0x02, 0xde, 0x54, 0xce, 0x2f, 0x27, 0xea, 0x46, 0x2e, 0xd5, - 0x00, 0xab, 0x71, 0x3c, 0xcf, 0xc5, 0x03, 0x37, 0x73, 0x8b, 0x41, 0x7b, 0x6f, 0x68, 0xef, 0xc0, - 0xb0, 0xf0, 0x5f, 0x8e, 0x2f, 0xe1, 0x9f, 0x1c, 0xe8, 0x5c, 0xb1, 0x32, 0x29, 0xf2, 0xbd, 0xaa, - 0x1d, 0x42, 0x7f, 0x9c, 0xa6, 0x91, 0x98, 0xef, 0x74, 0x6a, 0x43, 0x84, 0x3b, 0x5e, 0x36, 0xf2, - 0xa1, 0x63, 0xd1, 0x14, 0xe1, 0x13, 0x70, 0xa1, 0xe6, 0x0a, 0x3d, 0x24, 0x34, 0x9e, 0x00, 0x3d, - 0x4e, 0x28, 0x25, 0x06, 0x6d, 0x5c, 0xe4, 0xc9, 0x32, 0x4a, 0x1e, 0x0d, 0x9b, 0x56, 0x38, 0xfc, - 0x67, 0x0b, 0xda, 0xff, 0xaf, 0x59, 0x60, 0x00, 0x8e, 0x30, 0xc5, 0xe1, 0x88, 0x6a, 0x32, 0xe8, - 0x36, 0x26, 0x83, 0x00, 0xba, 0xa5, 0x64, 0xf1, 0x8a, 0x67, 0x41, 0x4f, 0xb1, 0x91, 0x85, 0x4a, - 0xa3, 0xfa, 0x4e, 0x8f, 0x04, 0x3e, 0xb5, 0xb0, 0xea, 0x23, 0x68, 0xf4, 0xd1, 0x4f, 0xcc, 0xf4, - 0xd0, 0x7f, 0xfa, 0xde, 0x1e, 0x1a, 0x1a, 0xfe, 0x77, 0xef, 0xec, 0x57, 0x0e, 0x78, 0x55, 0x13, - 0x5e, 0xec, 0x36, 0xe1, 0x45, 0xdd, 0x84, 0x93, 0x73, 0xdb, 0x84, 0x93, 0x73, 0xc4, 0xf4, 0xc6, - 0x36, 0x21, 0xbd, 0xc1, 0x64, 0x7d, 0x2e, 0x93, 0x22, 0x3d, 0x2f, 0x75, 0x56, 0x7d, 0x5a, 0x61, - 0xac, 0xdc, 0xdf, 0xac, 0xb9, 0x34, 0xa1, 0xf6, 0xa9, 0x41, 0x58, 0xe7, 0x57, 0x8a, 0xa0, 0x74, - 0x70, 0x35, 0x20, 0xdf, 0x03, 0x8f, 0x62, 0xf0, 0x54, 0x84, 0x77, 0xf2, 0xa2, 0xc4, 0x54, 0x6b, - 0xd1, 0xa8, 0xfe, 0xa6, 0x30, 0x05, 0x6f, 0xbf, 0x30, 0x7e, 0x0c, 0x9d, 0xe9, 0x5a, 0x2c, 0x73, - 0x3b, 0x83, 0x7d, 0xbd, 0x41, 0x70, 0x62, 0xc3, 0x95, 0x8e, 0x9a, 0x2d, 0xe1, 0x6b, 0xf0, 0x2b, - 0x61, 0x7d, 0x1d, 0xa7, 0x79, 0x1d, 0x02, 0xed, 0xbb, 0x58, 0xe4, 0xb6, 0xd5, 0x71, 0x8d, 0xce, - 0xbe, 0x2e, 0x58, 0x9c, 0x8b, 0xbc, 0xb4, 0xad, 0x6e, 0x71, 0xf8, 0xb1, 0xb9, 0x3e, 0x9a, 0xbb, - 0x4b, 0x53, 0x2e, 0x0d, 0x6d, 0x68, 0xa0, 0x0e, 0x49, 0x1e, 0xb9, 0x66, 0x7c, 0x97, 0x6a, 0x10, - 0xfe, 0x16, 0xfc, 0x71, 0xc4, 0x65, 0x4e, 0x8b, 0x88, 0x1f, 0x7a, 0x89, 0x7f, 0x3d, 0xbd, 0x7e, - 0x65, 0x6f, 0x80, 0xeb, 0x9a, 0x22, 0xdc, 0x27, 0x14, 0xf1, 0x82, 0xa5, 0xec, 0x72, 0xa2, 0xea, - 0xdc, 0xa5, 0x06, 0x85, 0x7f, 0x71, 0xa0, 0x8d, 0x5c, 0xd4, 0x30, 0xdd, 0x7e, 0x1b, 0x8f, 0xdd, - 0xc8, 0xe4, 0x41, 0x2c, 0xb8, 0xb4, 0xce, 0x59, 0xac, 0x82, 0x3e, 0x5f, 0xf3, 0xea, 0xc1, 0x37, - 0x08, 0x6b, 0x0d, 0x3f, 0x40, 0x6c, 0x2f, 0x35, 0x6a, 0x0d, 0xc5, 0x54, 0x2b, 0x71, 0x7c, 0x9b, - 0x16, 0x29, 0x97, 0xe3, 0xc5, 0x46, 0xc4, 0x2a, 0xe9, 0x3d, 0xda, 0x90, 0x84, 0x9f, 0xe9, 0x4f, - 0x9a, 0x3d, 0x46, 0x73, 0x0e, 0x7f, 0xfe, 0x3c, 0xbd, 0x79, 0xf8, 0x57, 0x07, 0xba, 0x2f, 0xcd, - 0x40, 0xd6, 0xf4, 0xc2, 0x79, 0xa3, 0x17, 0xad, 0x1d, 0x2f, 0xce, 0xe0, 0xc4, 0xee, 0xd9, 0x39, - 0x5f, 0x47, 0xe1, 0xa0, 0xce, 0x44, 0xb4, 0x5d, 0x25, 0xeb, 0x5d, 0xbe, 0x68, 0x6e, 0x77, 0xf7, - 0x1c, 0x4a, 0xf8, 0x5e, 0x56, 0x86, 0xd0, 0xb7, 0x5f, 0x72, 0x49, 0x64, 0x1f, 0x98, 0xa6, 0x28, - 0x3c, 0x83, 0xce, 0x45, 0x12, 0x2f, 0xc5, 0x8a, 0x8c, 0xa0, 0x3d, 0x2e, 0xf2, 0xb5, 0xb2, 0xd8, - 0x3f, 0x3b, 0x69, 0x34, 0x7e, 0x91, 0xaf, 0xf5, 0x1e, 0xaa, 0x76, 0x84, 0x9f, 0x02, 0xd4, 0x32, - 0x7c, 0x25, 0xea, 0x6c, 0xbc, 0xe2, 0x8f, 0x58, 0x32, 0x99, 0xb2, 0xd2, 0xa3, 0x07, 0x34, 0xe1, - 0x2f, 0xc0, 0x3f, 0x2f, 0x44, 0xb4, 0xb8, 0x8c, 0x97, 0x09, 0x52, 0xc7, 0x3d, 0x97, 0x59, 0x9d, - 0x2f, 0x0b, 0x31, 0xdc, 0xc8, 0x22, 0x55, 0x0f, 0x19, 0x34, 0xeb, 0xa8, 0xff, 0x09, 0x3e, 0xfe, - 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x5f, 0x83, 0xed, 0xad, 0x39, 0x10, 0x00, 0x00, + // 1615 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x5f, 0x8f, 0xe3, 0x48, + 0x11, 0x97, 0xe3, 0x38, 0x89, 0x2b, 0xd9, 0x61, 0xd4, 0x8c, 0xee, 0xcc, 0x81, 0x50, 0xb0, 0xf8, + 0x13, 0xfe, 0xdc, 0x70, 0x9a, 0x13, 0x12, 0x3a, 0x1d, 0x27, 0x65, 0x26, 0xec, 0x31, 0xec, 0xec, + 0xce, 0x6c, 0x67, 0x66, 0x78, 0x42, 0xa7, 0x4e, 0xd2, 0x49, 0x5a, 0xe7, 0xd8, 0xa6, 0x6d, 0xcf, + 0xc4, 0x3c, 0xf3, 0xcc, 0x47, 0x40, 0x42, 0x82, 0x2f, 0x80, 0x78, 0xe7, 0x9d, 0x27, 0xbe, 0xcd, + 0xf1, 0x88, 0xaa, 0xff, 0xd8, 0xce, 0x24, 0xbb, 0x5a, 0x24, 0xc4, 0x5b, 0xff, 0xaa, 0x2a, 0xd5, + 0x5d, 0xd5, 0x55, 0xbf, 0x2e, 0x07, 0x8e, 0x44, 0x9c, 0x73, 0x19, 0xb3, 0xe8, 0x34, 0x95, 0x49, + 0x9e, 0x90, 0x9e, 0xc5, 0xe1, 0x1f, 0x5c, 0xe8, 0x4c, 0x93, 0x42, 0xce, 0x39, 0x39, 0x82, 0xd6, + 0xe5, 0x24, 0x70, 0x86, 0xce, 0xc8, 0xa5, 0xad, 0xcb, 0x09, 0x21, 0xd0, 0x7e, 0xc5, 0x36, 0x3c, + 0x68, 0x0d, 0x9d, 0x91, 0x4f, 0xd5, 0x1a, 0x65, 0xb7, 0x65, 0xca, 0x03, 0x57, 0xcb, 0x70, 0x4d, + 0x3e, 0x80, 0xde, 0x5d, 0x86, 0xde, 0x36, 0x3c, 0x68, 0x2b, 0x79, 0x85, 0x51, 0x77, 0xc3, 0xb2, + 0xec, 0x31, 0x91, 0x8b, 0xc0, 0xd3, 0x3a, 0x8b, 0xc9, 0x31, 0xb8, 0x77, 0xf4, 0x2a, 0xe8, 0x28, + 0x31, 0x2e, 0x49, 0x00, 0xdd, 0x09, 0x5f, 0xb2, 0x22, 0xca, 0x83, 0xee, 0xd0, 0x19, 0xf5, 0xa8, + 0x85, 0xe8, 0xe7, 0x96, 0x47, 0x7c, 0x25, 0xd9, 0x32, 0xe8, 0x69, 0x3f, 0x16, 0x93, 0x53, 0x20, + 0x97, 0x71, 0xc6, 0xe7, 0x85, 0xe4, 0xd3, 0x2f, 0x45, 0x7a, 0xcf, 0xa5, 0x58, 0x96, 0x81, 0xaf, + 0x1c, 0x1c, 0xd0, 0xe0, 0x2e, 0x2f, 0x79, 0xce, 0x70, 0x6f, 0x50, 0xae, 0x2c, 0x24, 0x21, 0x0c, + 0xa6, 0x6b, 0x26, 0xf9, 0x62, 0xca, 0xe7, 0x92, 0xe7, 0x41, 0x5f, 0xa9, 0x77, 0x64, 0x68, 0x73, + 0x2d, 0x57, 0x2c, 0x16, 0xbf, 0x67, 0xb9, 0x48, 0xe2, 0x60, 0xa0, 0x6d, 0x9a, 0x32, 0xcc, 0x12, + 0x4d, 0x22, 0x1e, 0x3c, 0xd3, 0x59, 0xc2, 0x35, 0xf9, 0x16, 0xf8, 0x26, 0x18, 0x7a, 0x13, 0x1c, + 0x29, 0x45, 0x2d, 0x08, 0xff, 0xee, 0x80, 0x3f, 0x61, 0xd9, 0x7a, 0x96, 0x30, 0xb9, 0x78, 0xa7, + 0x9b, 0xf8, 0x10, 0xbc, 0x39, 0x8f, 0xa2, 0x2c, 0x70, 0x87, 0xee, 0xa8, 0x7f, 0xf6, 0xfe, 0x69, + 0x75, 0xc5, 0x95, 0x9f, 0x0b, 0x1e, 0x45, 0x54, 0x5b, 0x91, 0x8f, 0xc0, 0xcf, 0xf9, 0x26, 0x8d, + 0x58, 0xce, 0xb3, 0xa0, 0xad, 0x7e, 0x42, 0xea, 0x9f, 0xdc, 0x1a, 0x15, 0xad, 0x8d, 0xf6, 0x02, + 0xf5, 0xf6, 0x03, 0x0d, 0xbf, 0x72, 0xe1, 0xd9, 0xce, 0x76, 0x64, 0x00, 0xce, 0x56, 0x9d, 0xdc, + 0xa3, 0xce, 0x16, 0x51, 0xa9, 0x4e, 0xed, 0x51, 0xa7, 0x44, 0xf4, 0xa8, 0x2a, 0xc7, 0xa3, 0xce, + 0x23, 0xa2, 0xb5, 0xaa, 0x17, 0x8f, 0x3a, 0x6b, 0xf2, 0x43, 0xe8, 0xfe, 0xae, 0xe0, 0x52, 0xf0, + 0x2c, 0xf0, 0xd4, 0xe9, 0xbe, 0x56, 0x9f, 0xee, 0x75, 0xc1, 0x65, 0x49, 0xad, 0x1e, 0xb3, 0xa1, + 0x6a, 0x4d, 0x17, 0x8e, 0x5a, 0xa3, 0x2c, 0xc7, 0xba, 0xec, 0x6a, 0x19, 0xae, 0x4d, 0x16, 0x75, + 0xb5, 0x60, 0x16, 0x7f, 0x06, 0x6d, 0xb6, 0xe5, 0x59, 0xe0, 0x2b, 0xff, 0xdf, 0x79, 0x43, 0xc2, + 0x4e, 0xc7, 0x5b, 0x9e, 0xfd, 0x32, 0xce, 0x65, 0x49, 0x95, 0x39, 0xf9, 0x01, 0x74, 0xe6, 0x49, + 0x94, 0xc8, 0x2c, 0x80, 0xa7, 0x07, 0xbb, 0x40, 0x39, 0x35, 0x6a, 0x32, 0x82, 0x4e, 0xc4, 0x57, + 0x3c, 0x5e, 0xa8, 0xba, 0xe9, 0x9f, 0x1d, 0xd7, 0x86, 0x57, 0x4a, 0x4e, 0x8d, 0x9e, 0x7c, 0x02, + 0x83, 0x9c, 0xcd, 0x22, 0x7e, 0x9d, 0x62, 0x16, 0x33, 0x55, 0x43, 0xfd, 0xb3, 0xf7, 0x1a, 0xf7, + 0xd1, 0xd0, 0xd2, 0x1d, 0x5b, 0xf2, 0x29, 0x0c, 0x96, 0x82, 0x47, 0x0b, 0xfb, 0xdb, 0x67, 0xea, + 0x50, 0x41, 0xfd, 0x5b, 0xca, 0x63, 0xb6, 0xc1, 0x5f, 0x3c, 0x47, 0x33, 0xba, 0x63, 0xfd, 0xc1, + 0xe7, 0xe0, 0x57, 0xf1, 0x61, 0x03, 0x7e, 0xc9, 0x4b, 0x75, 0x5b, 0x3e, 0xc5, 0x25, 0xf9, 0x2e, + 0x78, 0x0f, 0x2c, 0x2a, 0x74, 0xa5, 0xf5, 0xcf, 0x8e, 0x6a, 0xaf, 0xe3, 0xad, 0xc8, 0xa8, 0x56, + 0x7e, 0xd2, 0xfa, 0xb9, 0x13, 0xfe, 0xcb, 0x81, 0x41, 0xf3, 0x94, 0xe4, 0xdb, 0x00, 0xb9, 0xd8, + 0xf0, 0xe7, 0x89, 0xdc, 0xb0, 0xdc, 0xf8, 0x6c, 0x48, 0xc8, 0x8f, 0xe0, 0xf8, 0x81, 0xcb, 0x5c, + 0xcc, 0x59, 0x74, 0x2b, 0x36, 0x1c, 0xfd, 0xa9, 0x5d, 0x7a, 0x74, 0x4f, 0x4e, 0x3e, 0x82, 0x4e, + 0x96, 0xc8, 0xfc, 0xbc, 0x54, 0xd5, 0xf2, 0xb6, 0xe8, 0x8c, 0x1d, 0xf2, 0xc3, 0xa3, 0x64, 0x69, + 0x2a, 0xe2, 0x95, 0xe5, 0x20, 0x8b, 0xc9, 0xf7, 0xe1, 0x68, 0x29, 0xb6, 0xcf, 0x85, 0xcc, 0xf2, + 0x8b, 0x24, 0x2a, 0x36, 0xb1, 0xaa, 0x9c, 0x1e, 0x7d, 0x22, 0x0d, 0xff, 0xe8, 0xc0, 0xd1, 0xae, + 0x7b, 0xec, 0x01, 0xbb, 0xb3, 0x6a, 0x40, 0x1d, 0xd6, 0x8e, 0x8c, 0x0c, 0xa1, 0xbf, 0x10, 0x59, + 0x1a, 0xb1, 0xb2, 0xd1, 0xa3, 0x4d, 0x11, 0x12, 0xce, 0x83, 0xc8, 0xc4, 0x2c, 0xd2, 0xbc, 0xd9, + 0xa3, 0x16, 0x22, 0x29, 0xa4, 0x92, 0xcf, 0x45, 0x86, 0x0d, 0xa6, 0x7b, 0xa1, 0x16, 0x84, 0x2b, + 0xf0, 0x54, 0x85, 0x35, 0xf8, 0xc0, 0xb7, 0x7c, 0xa0, 0x58, 0xb8, 0xd5, 0x60, 0xe1, 0x63, 0x70, + 0x7f, 0xc5, 0xb7, 0x86, 0x98, 0x71, 0x59, 0xb1, 0x46, 0xbb, 0xc1, 0x1a, 0x27, 0xe0, 0xdd, 0xab, + 0x0b, 0xd6, 0xdd, 0xac, 0x41, 0xf8, 0x19, 0x74, 0x74, 0x85, 0x56, 0x9e, 0x9d, 0x86, 0xe7, 0x21, + 0xf4, 0xaf, 0xa5, 0xe0, 0x71, 0xae, 0x79, 0xc0, 0x04, 0xd8, 0x10, 0x85, 0x7f, 0x73, 0xa0, 0xad, + 0x2e, 0x2e, 0x84, 0x41, 0xc4, 0x57, 0x6c, 0x5e, 0x9e, 0x27, 0x45, 0xbc, 0xc8, 0x02, 0x67, 0xe8, + 0x8e, 0x5c, 0xba, 0x23, 0x23, 0xef, 0x41, 0x67, 0xa6, 0xb5, 0xad, 0xa1, 0x3b, 0xf2, 0xa9, 0x41, + 0x78, 0xb4, 0x88, 0xcd, 0x78, 0x64, 0x42, 0xd0, 0x00, 0xad, 0x53, 0xc9, 0x97, 0x62, 0x6b, 0xc2, + 0x30, 0x08, 0xe5, 0x59, 0xb1, 0x44, 0xb9, 0x8e, 0xc4, 0x20, 0x0c, 0x60, 0xc6, 0xb2, 0x8a, 0x1c, + 0x70, 0x8d, 0x9e, 0xb3, 0x39, 0x8b, 0x2c, 0x3b, 0x68, 0x10, 0xfe, 0xc3, 0xc1, 0x37, 0x45, 0xb3, + 0xdd, 0x5e, 0x86, 0xbf, 0x01, 0x3d, 0x64, 0xc2, 0x2f, 0x1e, 0x98, 0x34, 0x01, 0x77, 0x11, 0xdf, + 0x33, 0x49, 0x7e, 0x0a, 0x1d, 0xd5, 0x06, 0x07, 0x98, 0xd7, 0xba, 0x53, 0x59, 0xa5, 0xc6, 0xac, + 0xe2, 0xa6, 0x76, 0x83, 0x9b, 0xaa, 0x60, 0xbd, 0x66, 0xb0, 0x1f, 0x82, 0x87, 0x24, 0x57, 0xaa, + 0xd3, 0x1f, 0xf4, 0xac, 0xa9, 0x50, 0x5b, 0x85, 0x77, 0xf0, 0x6c, 0x67, 0xc7, 0x6a, 0x27, 0x67, + 0x77, 0xa7, 0xba, 0xa5, 0x7d, 0xd3, 0xc2, 0xd8, 0x2f, 0x19, 0x8f, 0xf8, 0x3c, 0xe7, 0x0b, 0x53, + 0x93, 0x15, 0x0e, 0xff, 0xec, 0xd4, 0x7e, 0xd5, 0x7e, 0x58, 0xc0, 0xf3, 0x64, 0xb3, 0x61, 0xf1, + 0xc2, 0xb8, 0xb6, 0x10, 0xf3, 0xb6, 0x98, 0x19, 0xd7, 0xad, 0xc5, 0x0c, 0xb1, 0x4c, 0xcd, 0x0d, + 0xb6, 0x64, 0x8a, 0xb5, 0xb3, 0xe1, 0x2c, 0x2b, 0x24, 0xdf, 0xf0, 0x38, 0x37, 0x29, 0x68, 0x8a, + 0xc8, 0xfb, 0xd0, 0xcd, 0xd9, 0xea, 0x0b, 0x24, 0x22, 0x73, 0x93, 0x39, 0x5b, 0xbd, 0xe0, 0x25, + 0xf9, 0x26, 0xf8, 0x8a, 0xba, 0x94, 0x4a, 0x5f, 0x67, 0x4f, 0x09, 0x5e, 0xf0, 0x32, 0xfc, 0xb7, + 0x03, 0x9d, 0x29, 0x97, 0x0f, 0x5c, 0xbe, 0xd3, 0x63, 0xd9, 0x1c, 0x51, 0xdc, 0xb7, 0x8c, 0x28, + 0xed, 0xc3, 0x23, 0x8a, 0x57, 0x8f, 0x28, 0x27, 0xe0, 0x4d, 0xe5, 0xfc, 0x72, 0xa2, 0x4e, 0xe4, + 0x52, 0x0d, 0xb0, 0x1a, 0xc7, 0xf3, 0x5c, 0x3c, 0x70, 0x33, 0xb7, 0x18, 0xb4, 0xf7, 0x86, 0xf6, + 0x0e, 0x0c, 0x0b, 0xff, 0xe5, 0xf8, 0x12, 0xfe, 0xc9, 0x81, 0xce, 0x15, 0x2b, 0x93, 0x22, 0xdf, + 0xab, 0xda, 0x21, 0xf4, 0xc7, 0x69, 0x1a, 0x89, 0xf9, 0x4e, 0xa7, 0x36, 0x44, 0x68, 0xf1, 0xb2, + 0x71, 0x1f, 0x3a, 0x17, 0x4d, 0x11, 0x3e, 0x01, 0x17, 0x6a, 0xae, 0xd0, 0x43, 0x42, 0xe3, 0x09, + 0xd0, 0xe3, 0x84, 0x52, 0x62, 0xd2, 0xc6, 0x45, 0x9e, 0x2c, 0xa3, 0xe4, 0x51, 0x65, 0xa7, 0x47, + 0x2b, 0x1c, 0xfe, 0xb3, 0x05, 0xed, 0xff, 0xd7, 0x2c, 0x30, 0x00, 0x47, 0x98, 0xe2, 0x70, 0x44, + 0x35, 0x19, 0x74, 0x1b, 0x93, 0x41, 0x00, 0xdd, 0x52, 0xb2, 0x78, 0xc5, 0xb3, 0xa0, 0xa7, 0xd8, + 0xc8, 0x42, 0xa5, 0x51, 0x7d, 0xa7, 0x47, 0x02, 0x9f, 0x5a, 0x58, 0xf5, 0x11, 0x34, 0xfa, 0xe8, + 0x27, 0x66, 0x7a, 0xe8, 0x3f, 0x7d, 0x6f, 0x0f, 0x0d, 0x0d, 0xff, 0xbb, 0x77, 0xf6, 0x2b, 0x07, + 0xbc, 0xaa, 0x09, 0x2f, 0x76, 0x9b, 0xf0, 0xa2, 0x6e, 0xc2, 0xc9, 0xb9, 0x6d, 0xc2, 0xc9, 0x39, + 0x62, 0x7a, 0x63, 0x9b, 0x90, 0xde, 0xe0, 0x65, 0x7d, 0x2e, 0x93, 0x22, 0x3d, 0x2f, 0xf5, 0xad, + 0xfa, 0xb4, 0xc2, 0x58, 0xb9, 0xbf, 0x59, 0x73, 0x69, 0x52, 0xed, 0x53, 0x83, 0xb0, 0xce, 0xaf, + 0x14, 0x41, 0xe9, 0xe4, 0x6a, 0x40, 0xbe, 0x07, 0x1e, 0xc5, 0xe4, 0xa9, 0x0c, 0xef, 0xdc, 0x8b, + 0x12, 0x53, 0xad, 0x45, 0xa7, 0xfa, 0x9b, 0xc2, 0x14, 0xbc, 0xfd, 0xc2, 0xf8, 0x31, 0x74, 0xa6, + 0x6b, 0xb1, 0xcc, 0xed, 0x0c, 0xf6, 0xf5, 0x06, 0xc1, 0x89, 0x0d, 0x57, 0x3a, 0x6a, 0x4c, 0xc2, + 0xd7, 0xe0, 0x57, 0xc2, 0xfa, 0x38, 0x4e, 0xf3, 0x38, 0x04, 0xda, 0x77, 0xb1, 0xc8, 0x6d, 0xab, + 0xe3, 0x1a, 0x83, 0x7d, 0x5d, 0xb0, 0x38, 0x17, 0x79, 0x69, 0x5b, 0xdd, 0xe2, 0xf0, 0x63, 0x73, + 0x7c, 0x74, 0x77, 0x97, 0xa6, 0x5c, 0x1a, 0xda, 0xd0, 0x40, 0x6d, 0x92, 0x3c, 0x72, 0xcd, 0xf8, + 0x2e, 0xd5, 0x20, 0xfc, 0x2d, 0xf8, 0xe3, 0x88, 0xcb, 0x9c, 0x16, 0x11, 0x3f, 0xf4, 0x12, 0xff, + 0x7a, 0x7a, 0xfd, 0xca, 0x9e, 0x00, 0xd7, 0x35, 0x45, 0xb8, 0x4f, 0x28, 0xe2, 0x05, 0x4b, 0xd9, + 0xe5, 0x44, 0xd5, 0xb9, 0x4b, 0x0d, 0x0a, 0xff, 0xe2, 0x40, 0x1b, 0xb9, 0xa8, 0xe1, 0xba, 0xfd, + 0x36, 0x1e, 0xbb, 0x91, 0xc9, 0x83, 0x58, 0x70, 0x69, 0x83, 0xb3, 0x58, 0x25, 0x7d, 0xbe, 0xe6, + 0xd5, 0x83, 0x6f, 0x10, 0xd6, 0x1a, 0x7e, 0x80, 0xd8, 0x5e, 0x6a, 0xd4, 0x1a, 0x8a, 0xa9, 0x56, + 0xe2, 0xf8, 0x36, 0x2d, 0x52, 0x2e, 0xc7, 0x8b, 0x8d, 0xb0, 0x03, 0x52, 0x43, 0x12, 0x7e, 0xa6, + 0x3f, 0x69, 0xf6, 0x18, 0xcd, 0x39, 0xfc, 0xf9, 0xf3, 0xf4, 0xe4, 0xe1, 0x5f, 0x1d, 0xe8, 0xbe, + 0x34, 0x03, 0x59, 0x33, 0x0a, 0xe7, 0x8d, 0x51, 0xb4, 0x76, 0xa2, 0x38, 0x83, 0x13, 0x6b, 0xb3, + 0xb3, 0xbf, 0xce, 0xc2, 0x41, 0x9d, 0xc9, 0x68, 0xbb, 0xba, 0xac, 0x77, 0xf9, 0xa2, 0xb9, 0xdd, + 0xb5, 0x39, 0x74, 0xe1, 0x7b, 0xb7, 0x32, 0x84, 0xbe, 0xfd, 0x92, 0x4b, 0x22, 0xfb, 0xc0, 0x34, + 0x45, 0xe1, 0x19, 0x74, 0x2e, 0x92, 0x78, 0x29, 0x56, 0x64, 0x04, 0xed, 0x71, 0x91, 0xaf, 0x95, + 0xc7, 0xfe, 0xd9, 0x49, 0xa3, 0xf1, 0x8b, 0x7c, 0xad, 0x6d, 0xa8, 0xb2, 0x08, 0x3f, 0x05, 0xa8, + 0x65, 0xf8, 0x4a, 0xd4, 0xb7, 0xf1, 0x8a, 0x3f, 0x62, 0xc9, 0x64, 0xca, 0x4b, 0x8f, 0x1e, 0xd0, + 0x84, 0xbf, 0x00, 0xff, 0xbc, 0x10, 0xd1, 0xe2, 0x32, 0x5e, 0x26, 0x48, 0x1d, 0xf7, 0x5c, 0x66, + 0xf5, 0x7d, 0x59, 0x88, 0xe9, 0x46, 0x16, 0xa9, 0x7a, 0xc8, 0xa0, 0x59, 0x47, 0xfd, 0x4f, 0xf0, + 0xf1, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xd1, 0xd1, 0x5d, 0x3c, 0x39, 0x10, 0x00, 0x00, } diff --git a/bolt/internal/internal.proto b/bolt/internal/internal.proto index 2fc1d65ce8..f4693d29b8 100644 --- a/bolt/internal/internal.proto +++ b/bolt/internal/internal.proto @@ -47,7 +47,8 @@ message TableOptions { bool verticalTimeAxis = 2; // time axis should be a column not row RenamableField sortBy = 3; // which column should a table be sorted by string wrapping = 4; // option for text wrapping - bool fixFirstColumn = 5; // first column should be fixed/frozen + reserved 5 + bool fixFirstColumn = 6; // first column should be fixed/frozen } message RenamableField { From a0adb2e20661ea920333ef833eb05c6bbd7f2941 Mon Sep 17 00:00:00 2001 From: Iris Scholten Date: Thu, 19 Apr 2018 17:27:05 -0700 Subject: [PATCH 04/48] Move timeFormat from TableOptions to DashboardCell in the Server Update tests according to the change --- bolt/internal/internal.go | 4 +- bolt/internal/internal.pb.go | 219 +++++++++++++++++---------------- bolt/internal/internal.proto | 29 ++--- bolt/internal/internal_test.go | 27 ++-- chronograf.go | 2 +- integrations/server_test.go | 4 +- server/cells_test.go | 2 +- 7 files changed, 142 insertions(+), 145 deletions(-) diff --git a/bolt/internal/internal.go b/bolt/internal/internal.go index f6daf29812..51722f2e4b 100644 --- a/bolt/internal/internal.go +++ b/bolt/internal/internal.go @@ -274,7 +274,6 @@ func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) { } tableOptions := &TableOptions{ - TimeFormat: c.TableOptions.TimeFormat, VerticalTimeAxis: c.TableOptions.VerticalTimeAxis, SortBy: sortBy, Wrapping: c.TableOptions.Wrapping, @@ -308,6 +307,7 @@ func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) { }, TableOptions: tableOptions, FieldOptions: fieldOptions, + TimeFormat: c.TimeFormat, } } templates := make([]*Template, len(d.Templates)) @@ -443,7 +443,6 @@ func UnmarshalDashboard(data []byte, d *chronograf.Dashboard) error { sortBy.Visible = c.TableOptions.SortBy.Visible } tableOptions.SortBy = sortBy - tableOptions.TimeFormat = c.TableOptions.TimeFormat tableOptions.VerticalTimeAxis = c.TableOptions.VerticalTimeAxis tableOptions.Wrapping = c.TableOptions.Wrapping tableOptions.FixFirstColumn = c.TableOptions.FixFirstColumn @@ -479,6 +478,7 @@ func UnmarshalDashboard(data []byte, d *chronograf.Dashboard) error { Legend: legend, TableOptions: tableOptions, FieldOptions: fieldOptions, + TimeFormat: c.TimeFormat, } } diff --git a/bolt/internal/internal.pb.go b/bolt/internal/internal.pb.go index ccc50f8b5a..f4edc8b351 100644 --- a/bolt/internal/internal.pb.go +++ b/bolt/internal/internal.pb.go @@ -233,6 +233,7 @@ type DashboardCell struct { Legend *Legend `protobuf:"bytes,11,opt,name=legend" json:"legend,omitempty"` TableOptions *TableOptions `protobuf:"bytes,12,opt,name=tableOptions" json:"tableOptions,omitempty"` FieldOptions []*RenamableField `protobuf:"bytes,13,rep,name=fieldOptions" json:"fieldOptions,omitempty"` + TimeFormat string `protobuf:"bytes,14,opt,name=timeFormat,proto3" json:"timeFormat,omitempty"` } func (m *DashboardCell) Reset() { *m = DashboardCell{} } @@ -331,8 +332,14 @@ func (m *DashboardCell) GetFieldOptions() []*RenamableField { return nil } +func (m *DashboardCell) GetTimeFormat() string { + if m != nil { + return m.TimeFormat + } + return "" +} + type TableOptions struct { - TimeFormat string `protobuf:"bytes,1,opt,name=timeFormat,proto3" json:"timeFormat,omitempty"` VerticalTimeAxis bool `protobuf:"varint,2,opt,name=verticalTimeAxis,proto3" json:"verticalTimeAxis,omitempty"` SortBy *RenamableField `protobuf:"bytes,3,opt,name=sortBy" json:"sortBy,omitempty"` Wrapping string `protobuf:"bytes,4,opt,name=wrapping,proto3" json:"wrapping,omitempty"` @@ -344,13 +351,6 @@ func (m *TableOptions) String() string { return proto.CompactTextStri func (*TableOptions) ProtoMessage() {} func (*TableOptions) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{3} } -func (m *TableOptions) GetTimeFormat() string { - if m != nil { - return m.TimeFormat - } - return "" -} - func (m *TableOptions) GetVerticalTimeAxis() bool { if m != nil { return m.VerticalTimeAxis @@ -1346,106 +1346,107 @@ func init() { func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) } var fileDescriptorInternal = []byte{ - // 1615 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x5f, 0x8f, 0xe3, 0x48, - 0x11, 0x97, 0xe3, 0x38, 0x89, 0x2b, 0xd9, 0x61, 0xd4, 0x8c, 0xee, 0xcc, 0x81, 0x50, 0xb0, 0xf8, - 0x13, 0xfe, 0xdc, 0x70, 0x9a, 0x13, 0x12, 0x3a, 0x1d, 0x27, 0x65, 0x26, 0xec, 0x31, 0xec, 0xec, + // 1627 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xdd, 0x8f, 0xe3, 0x48, + 0x11, 0x97, 0x13, 0x3b, 0x89, 0x2b, 0xd9, 0x61, 0xd4, 0xac, 0xee, 0xcc, 0x81, 0x50, 0xb0, 0xf8, + 0x08, 0x1f, 0x37, 0x9c, 0xe6, 0x84, 0x84, 0x4e, 0xc7, 0x49, 0x99, 0x09, 0x7b, 0xcc, 0xee, 0xec, 0xce, 0x6c, 0x67, 0x66, 0x78, 0x42, 0xa7, 0x4e, 0xd2, 0x49, 0x5a, 0xe7, 0xd8, 0xa6, 0x6d, 0xcf, - 0xc4, 0x3c, 0xf3, 0xcc, 0x47, 0x40, 0x42, 0x82, 0x2f, 0x80, 0x78, 0xe7, 0x9d, 0x27, 0xbe, 0xcd, - 0xf1, 0x88, 0xaa, 0xff, 0xd8, 0xce, 0x24, 0xbb, 0x5a, 0x24, 0xc4, 0x5b, 0xff, 0xaa, 0x2a, 0xd5, - 0x5d, 0xd5, 0x55, 0xbf, 0x2e, 0x07, 0x8e, 0x44, 0x9c, 0x73, 0x19, 0xb3, 0xe8, 0x34, 0x95, 0x49, - 0x9e, 0x90, 0x9e, 0xc5, 0xe1, 0x1f, 0x5c, 0xe8, 0x4c, 0x93, 0x42, 0xce, 0x39, 0x39, 0x82, 0xd6, - 0xe5, 0x24, 0x70, 0x86, 0xce, 0xc8, 0xa5, 0xad, 0xcb, 0x09, 0x21, 0xd0, 0x7e, 0xc5, 0x36, 0x3c, - 0x68, 0x0d, 0x9d, 0x91, 0x4f, 0xd5, 0x1a, 0x65, 0xb7, 0x65, 0xca, 0x03, 0x57, 0xcb, 0x70, 0x4d, - 0x3e, 0x80, 0xde, 0x5d, 0x86, 0xde, 0x36, 0x3c, 0x68, 0x2b, 0x79, 0x85, 0x51, 0x77, 0xc3, 0xb2, - 0xec, 0x31, 0x91, 0x8b, 0xc0, 0xd3, 0x3a, 0x8b, 0xc9, 0x31, 0xb8, 0x77, 0xf4, 0x2a, 0xe8, 0x28, - 0x31, 0x2e, 0x49, 0x00, 0xdd, 0x09, 0x5f, 0xb2, 0x22, 0xca, 0x83, 0xee, 0xd0, 0x19, 0xf5, 0xa8, - 0x85, 0xe8, 0xe7, 0x96, 0x47, 0x7c, 0x25, 0xd9, 0x32, 0xe8, 0x69, 0x3f, 0x16, 0x93, 0x53, 0x20, - 0x97, 0x71, 0xc6, 0xe7, 0x85, 0xe4, 0xd3, 0x2f, 0x45, 0x7a, 0xcf, 0xa5, 0x58, 0x96, 0x81, 0xaf, - 0x1c, 0x1c, 0xd0, 0xe0, 0x2e, 0x2f, 0x79, 0xce, 0x70, 0x6f, 0x50, 0xae, 0x2c, 0x24, 0x21, 0x0c, - 0xa6, 0x6b, 0x26, 0xf9, 0x62, 0xca, 0xe7, 0x92, 0xe7, 0x41, 0x5f, 0xa9, 0x77, 0x64, 0x68, 0x73, - 0x2d, 0x57, 0x2c, 0x16, 0xbf, 0x67, 0xb9, 0x48, 0xe2, 0x60, 0xa0, 0x6d, 0x9a, 0x32, 0xcc, 0x12, - 0x4d, 0x22, 0x1e, 0x3c, 0xd3, 0x59, 0xc2, 0x35, 0xf9, 0x16, 0xf8, 0x26, 0x18, 0x7a, 0x13, 0x1c, - 0x29, 0x45, 0x2d, 0x08, 0xff, 0xee, 0x80, 0x3f, 0x61, 0xd9, 0x7a, 0x96, 0x30, 0xb9, 0x78, 0xa7, - 0x9b, 0xf8, 0x10, 0xbc, 0x39, 0x8f, 0xa2, 0x2c, 0x70, 0x87, 0xee, 0xa8, 0x7f, 0xf6, 0xfe, 0x69, - 0x75, 0xc5, 0x95, 0x9f, 0x0b, 0x1e, 0x45, 0x54, 0x5b, 0x91, 0x8f, 0xc0, 0xcf, 0xf9, 0x26, 0x8d, - 0x58, 0xce, 0xb3, 0xa0, 0xad, 0x7e, 0x42, 0xea, 0x9f, 0xdc, 0x1a, 0x15, 0xad, 0x8d, 0xf6, 0x02, - 0xf5, 0xf6, 0x03, 0x0d, 0xbf, 0x72, 0xe1, 0xd9, 0xce, 0x76, 0x64, 0x00, 0xce, 0x56, 0x9d, 0xdc, - 0xa3, 0xce, 0x16, 0x51, 0xa9, 0x4e, 0xed, 0x51, 0xa7, 0x44, 0xf4, 0xa8, 0x2a, 0xc7, 0xa3, 0xce, - 0x23, 0xa2, 0xb5, 0xaa, 0x17, 0x8f, 0x3a, 0x6b, 0xf2, 0x43, 0xe8, 0xfe, 0xae, 0xe0, 0x52, 0xf0, - 0x2c, 0xf0, 0xd4, 0xe9, 0xbe, 0x56, 0x9f, 0xee, 0x75, 0xc1, 0x65, 0x49, 0xad, 0x1e, 0xb3, 0xa1, - 0x6a, 0x4d, 0x17, 0x8e, 0x5a, 0xa3, 0x2c, 0xc7, 0xba, 0xec, 0x6a, 0x19, 0xae, 0x4d, 0x16, 0x75, - 0xb5, 0x60, 0x16, 0x7f, 0x06, 0x6d, 0xb6, 0xe5, 0x59, 0xe0, 0x2b, 0xff, 0xdf, 0x79, 0x43, 0xc2, - 0x4e, 0xc7, 0x5b, 0x9e, 0xfd, 0x32, 0xce, 0x65, 0x49, 0x95, 0x39, 0xf9, 0x01, 0x74, 0xe6, 0x49, - 0x94, 0xc8, 0x2c, 0x80, 0xa7, 0x07, 0xbb, 0x40, 0x39, 0x35, 0x6a, 0x32, 0x82, 0x4e, 0xc4, 0x57, - 0x3c, 0x5e, 0xa8, 0xba, 0xe9, 0x9f, 0x1d, 0xd7, 0x86, 0x57, 0x4a, 0x4e, 0x8d, 0x9e, 0x7c, 0x02, - 0x83, 0x9c, 0xcd, 0x22, 0x7e, 0x9d, 0x62, 0x16, 0x33, 0x55, 0x43, 0xfd, 0xb3, 0xf7, 0x1a, 0xf7, - 0xd1, 0xd0, 0xd2, 0x1d, 0x5b, 0xf2, 0x29, 0x0c, 0x96, 0x82, 0x47, 0x0b, 0xfb, 0xdb, 0x67, 0xea, - 0x50, 0x41, 0xfd, 0x5b, 0xca, 0x63, 0xb6, 0xc1, 0x5f, 0x3c, 0x47, 0x33, 0xba, 0x63, 0xfd, 0xc1, - 0xe7, 0xe0, 0x57, 0xf1, 0x61, 0x03, 0x7e, 0xc9, 0x4b, 0x75, 0x5b, 0x3e, 0xc5, 0x25, 0xf9, 0x2e, - 0x78, 0x0f, 0x2c, 0x2a, 0x74, 0xa5, 0xf5, 0xcf, 0x8e, 0x6a, 0xaf, 0xe3, 0xad, 0xc8, 0xa8, 0x56, - 0x7e, 0xd2, 0xfa, 0xb9, 0x13, 0xfe, 0xcb, 0x81, 0x41, 0xf3, 0x94, 0xe4, 0xdb, 0x00, 0xb9, 0xd8, - 0xf0, 0xe7, 0x89, 0xdc, 0xb0, 0xdc, 0xf8, 0x6c, 0x48, 0xc8, 0x8f, 0xe0, 0xf8, 0x81, 0xcb, 0x5c, - 0xcc, 0x59, 0x74, 0x2b, 0x36, 0x1c, 0xfd, 0xa9, 0x5d, 0x7a, 0x74, 0x4f, 0x4e, 0x3e, 0x82, 0x4e, - 0x96, 0xc8, 0xfc, 0xbc, 0x54, 0xd5, 0xf2, 0xb6, 0xe8, 0x8c, 0x1d, 0xf2, 0xc3, 0xa3, 0x64, 0x69, - 0x2a, 0xe2, 0x95, 0xe5, 0x20, 0x8b, 0xc9, 0xf7, 0xe1, 0x68, 0x29, 0xb6, 0xcf, 0x85, 0xcc, 0xf2, - 0x8b, 0x24, 0x2a, 0x36, 0xb1, 0xaa, 0x9c, 0x1e, 0x7d, 0x22, 0x0d, 0xff, 0xe8, 0xc0, 0xd1, 0xae, - 0x7b, 0xec, 0x01, 0xbb, 0xb3, 0x6a, 0x40, 0x1d, 0xd6, 0x8e, 0x8c, 0x0c, 0xa1, 0xbf, 0x10, 0x59, - 0x1a, 0xb1, 0xb2, 0xd1, 0xa3, 0x4d, 0x11, 0x12, 0xce, 0x83, 0xc8, 0xc4, 0x2c, 0xd2, 0xbc, 0xd9, - 0xa3, 0x16, 0x22, 0x29, 0xa4, 0x92, 0xcf, 0x45, 0x86, 0x0d, 0xa6, 0x7b, 0xa1, 0x16, 0x84, 0x2b, - 0xf0, 0x54, 0x85, 0x35, 0xf8, 0xc0, 0xb7, 0x7c, 0xa0, 0x58, 0xb8, 0xd5, 0x60, 0xe1, 0x63, 0x70, - 0x7f, 0xc5, 0xb7, 0x86, 0x98, 0x71, 0x59, 0xb1, 0x46, 0xbb, 0xc1, 0x1a, 0x27, 0xe0, 0xdd, 0xab, - 0x0b, 0xd6, 0xdd, 0xac, 0x41, 0xf8, 0x19, 0x74, 0x74, 0x85, 0x56, 0x9e, 0x9d, 0x86, 0xe7, 0x21, - 0xf4, 0xaf, 0xa5, 0xe0, 0x71, 0xae, 0x79, 0xc0, 0x04, 0xd8, 0x10, 0x85, 0x7f, 0x73, 0xa0, 0xad, - 0x2e, 0x2e, 0x84, 0x41, 0xc4, 0x57, 0x6c, 0x5e, 0x9e, 0x27, 0x45, 0xbc, 0xc8, 0x02, 0x67, 0xe8, - 0x8e, 0x5c, 0xba, 0x23, 0x23, 0xef, 0x41, 0x67, 0xa6, 0xb5, 0xad, 0xa1, 0x3b, 0xf2, 0xa9, 0x41, - 0x78, 0xb4, 0x88, 0xcd, 0x78, 0x64, 0x42, 0xd0, 0x00, 0xad, 0x53, 0xc9, 0x97, 0x62, 0x6b, 0xc2, - 0x30, 0x08, 0xe5, 0x59, 0xb1, 0x44, 0xb9, 0x8e, 0xc4, 0x20, 0x0c, 0x60, 0xc6, 0xb2, 0x8a, 0x1c, - 0x70, 0x8d, 0x9e, 0xb3, 0x39, 0x8b, 0x2c, 0x3b, 0x68, 0x10, 0xfe, 0xc3, 0xc1, 0x37, 0x45, 0xb3, - 0xdd, 0x5e, 0x86, 0xbf, 0x01, 0x3d, 0x64, 0xc2, 0x2f, 0x1e, 0x98, 0x34, 0x01, 0x77, 0x11, 0xdf, - 0x33, 0x49, 0x7e, 0x0a, 0x1d, 0xd5, 0x06, 0x07, 0x98, 0xd7, 0xba, 0x53, 0x59, 0xa5, 0xc6, 0xac, - 0xe2, 0xa6, 0x76, 0x83, 0x9b, 0xaa, 0x60, 0xbd, 0x66, 0xb0, 0x1f, 0x82, 0x87, 0x24, 0x57, 0xaa, - 0xd3, 0x1f, 0xf4, 0xac, 0xa9, 0x50, 0x5b, 0x85, 0x77, 0xf0, 0x6c, 0x67, 0xc7, 0x6a, 0x27, 0x67, - 0x77, 0xa7, 0xba, 0xa5, 0x7d, 0xd3, 0xc2, 0xd8, 0x2f, 0x19, 0x8f, 0xf8, 0x3c, 0xe7, 0x0b, 0x53, - 0x93, 0x15, 0x0e, 0xff, 0xec, 0xd4, 0x7e, 0xd5, 0x7e, 0x58, 0xc0, 0xf3, 0x64, 0xb3, 0x61, 0xf1, - 0xc2, 0xb8, 0xb6, 0x10, 0xf3, 0xb6, 0x98, 0x19, 0xd7, 0xad, 0xc5, 0x0c, 0xb1, 0x4c, 0xcd, 0x0d, - 0xb6, 0x64, 0x8a, 0xb5, 0xb3, 0xe1, 0x2c, 0x2b, 0x24, 0xdf, 0xf0, 0x38, 0x37, 0x29, 0x68, 0x8a, - 0xc8, 0xfb, 0xd0, 0xcd, 0xd9, 0xea, 0x0b, 0x24, 0x22, 0x73, 0x93, 0x39, 0x5b, 0xbd, 0xe0, 0x25, - 0xf9, 0x26, 0xf8, 0x8a, 0xba, 0x94, 0x4a, 0x5f, 0x67, 0x4f, 0x09, 0x5e, 0xf0, 0x32, 0xfc, 0xb7, - 0x03, 0x9d, 0x29, 0x97, 0x0f, 0x5c, 0xbe, 0xd3, 0x63, 0xd9, 0x1c, 0x51, 0xdc, 0xb7, 0x8c, 0x28, - 0xed, 0xc3, 0x23, 0x8a, 0x57, 0x8f, 0x28, 0x27, 0xe0, 0x4d, 0xe5, 0xfc, 0x72, 0xa2, 0x4e, 0xe4, - 0x52, 0x0d, 0xb0, 0x1a, 0xc7, 0xf3, 0x5c, 0x3c, 0x70, 0x33, 0xb7, 0x18, 0xb4, 0xf7, 0x86, 0xf6, - 0x0e, 0x0c, 0x0b, 0xff, 0xe5, 0xf8, 0x12, 0xfe, 0xc9, 0x81, 0xce, 0x15, 0x2b, 0x93, 0x22, 0xdf, - 0xab, 0xda, 0x21, 0xf4, 0xc7, 0x69, 0x1a, 0x89, 0xf9, 0x4e, 0xa7, 0x36, 0x44, 0x68, 0xf1, 0xb2, - 0x71, 0x1f, 0x3a, 0x17, 0x4d, 0x11, 0x3e, 0x01, 0x17, 0x6a, 0xae, 0xd0, 0x43, 0x42, 0xe3, 0x09, - 0xd0, 0xe3, 0x84, 0x52, 0x62, 0xd2, 0xc6, 0x45, 0x9e, 0x2c, 0xa3, 0xe4, 0x51, 0x65, 0xa7, 0x47, - 0x2b, 0x1c, 0xfe, 0xb3, 0x05, 0xed, 0xff, 0xd7, 0x2c, 0x30, 0x00, 0x47, 0x98, 0xe2, 0x70, 0x44, - 0x35, 0x19, 0x74, 0x1b, 0x93, 0x41, 0x00, 0xdd, 0x52, 0xb2, 0x78, 0xc5, 0xb3, 0xa0, 0xa7, 0xd8, - 0xc8, 0x42, 0xa5, 0x51, 0x7d, 0xa7, 0x47, 0x02, 0x9f, 0x5a, 0x58, 0xf5, 0x11, 0x34, 0xfa, 0xe8, - 0x27, 0x66, 0x7a, 0xe8, 0x3f, 0x7d, 0x6f, 0x0f, 0x0d, 0x0d, 0xff, 0xbb, 0x77, 0xf6, 0x2b, 0x07, - 0xbc, 0xaa, 0x09, 0x2f, 0x76, 0x9b, 0xf0, 0xa2, 0x6e, 0xc2, 0xc9, 0xb9, 0x6d, 0xc2, 0xc9, 0x39, - 0x62, 0x7a, 0x63, 0x9b, 0x90, 0xde, 0xe0, 0x65, 0x7d, 0x2e, 0x93, 0x22, 0x3d, 0x2f, 0xf5, 0xad, - 0xfa, 0xb4, 0xc2, 0x58, 0xb9, 0xbf, 0x59, 0x73, 0x69, 0x52, 0xed, 0x53, 0x83, 0xb0, 0xce, 0xaf, - 0x14, 0x41, 0xe9, 0xe4, 0x6a, 0x40, 0xbe, 0x07, 0x1e, 0xc5, 0xe4, 0xa9, 0x0c, 0xef, 0xdc, 0x8b, - 0x12, 0x53, 0xad, 0x45, 0xa7, 0xfa, 0x9b, 0xc2, 0x14, 0xbc, 0xfd, 0xc2, 0xf8, 0x31, 0x74, 0xa6, - 0x6b, 0xb1, 0xcc, 0xed, 0x0c, 0xf6, 0xf5, 0x06, 0xc1, 0x89, 0x0d, 0x57, 0x3a, 0x6a, 0x4c, 0xc2, - 0xd7, 0xe0, 0x57, 0xc2, 0xfa, 0x38, 0x4e, 0xf3, 0x38, 0x04, 0xda, 0x77, 0xb1, 0xc8, 0x6d, 0xab, - 0xe3, 0x1a, 0x83, 0x7d, 0x5d, 0xb0, 0x38, 0x17, 0x79, 0x69, 0x5b, 0xdd, 0xe2, 0xf0, 0x63, 0x73, - 0x7c, 0x74, 0x77, 0x97, 0xa6, 0x5c, 0x1a, 0xda, 0xd0, 0x40, 0x6d, 0x92, 0x3c, 0x72, 0xcd, 0xf8, - 0x2e, 0xd5, 0x20, 0xfc, 0x2d, 0xf8, 0xe3, 0x88, 0xcb, 0x9c, 0x16, 0x11, 0x3f, 0xf4, 0x12, 0xff, - 0x7a, 0x7a, 0xfd, 0xca, 0x9e, 0x00, 0xd7, 0x35, 0x45, 0xb8, 0x4f, 0x28, 0xe2, 0x05, 0x4b, 0xd9, - 0xe5, 0x44, 0xd5, 0xb9, 0x4b, 0x0d, 0x0a, 0xff, 0xe2, 0x40, 0x1b, 0xb9, 0xa8, 0xe1, 0xba, 0xfd, - 0x36, 0x1e, 0xbb, 0x91, 0xc9, 0x83, 0x58, 0x70, 0x69, 0x83, 0xb3, 0x58, 0x25, 0x7d, 0xbe, 0xe6, - 0xd5, 0x83, 0x6f, 0x10, 0xd6, 0x1a, 0x7e, 0x80, 0xd8, 0x5e, 0x6a, 0xd4, 0x1a, 0x8a, 0xa9, 0x56, - 0xe2, 0xf8, 0x36, 0x2d, 0x52, 0x2e, 0xc7, 0x8b, 0x8d, 0xb0, 0x03, 0x52, 0x43, 0x12, 0x7e, 0xa6, - 0x3f, 0x69, 0xf6, 0x18, 0xcd, 0x39, 0xfc, 0xf9, 0xf3, 0xf4, 0xe4, 0xe1, 0x5f, 0x1d, 0xe8, 0xbe, - 0x34, 0x03, 0x59, 0x33, 0x0a, 0xe7, 0x8d, 0x51, 0xb4, 0x76, 0xa2, 0x38, 0x83, 0x13, 0x6b, 0xb3, - 0xb3, 0xbf, 0xce, 0xc2, 0x41, 0x9d, 0xc9, 0x68, 0xbb, 0xba, 0xac, 0x77, 0xf9, 0xa2, 0xb9, 0xdd, - 0xb5, 0x39, 0x74, 0xe1, 0x7b, 0xb7, 0x32, 0x84, 0xbe, 0xfd, 0x92, 0x4b, 0x22, 0xfb, 0xc0, 0x34, - 0x45, 0xe1, 0x19, 0x74, 0x2e, 0x92, 0x78, 0x29, 0x56, 0x64, 0x04, 0xed, 0x71, 0x91, 0xaf, 0x95, - 0xc7, 0xfe, 0xd9, 0x49, 0xa3, 0xf1, 0x8b, 0x7c, 0xad, 0x6d, 0xa8, 0xb2, 0x08, 0x3f, 0x05, 0xa8, - 0x65, 0xf8, 0x4a, 0xd4, 0xb7, 0xf1, 0x8a, 0x3f, 0x62, 0xc9, 0x64, 0xca, 0x4b, 0x8f, 0x1e, 0xd0, - 0x84, 0xbf, 0x00, 0xff, 0xbc, 0x10, 0xd1, 0xe2, 0x32, 0x5e, 0x26, 0x48, 0x1d, 0xf7, 0x5c, 0x66, - 0xf5, 0x7d, 0x59, 0x88, 0xe9, 0x46, 0x16, 0xa9, 0x7a, 0xc8, 0xa0, 0x59, 0x47, 0xfd, 0x4f, 0xf0, - 0xf1, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xd1, 0xd1, 0x5d, 0x3c, 0x39, 0x10, 0x00, 0x00, + 0xc4, 0x3c, 0xf3, 0xcc, 0x2b, 0x6f, 0x48, 0x48, 0xf0, 0x0f, 0x20, 0x1e, 0x91, 0x78, 0xe7, 0x1f, + 0x82, 0x47, 0x54, 0xfd, 0x61, 0x3b, 0x93, 0xec, 0x6a, 0x91, 0xd0, 0xbd, 0xf5, 0xaf, 0xaa, 0x52, + 0xdd, 0x55, 0x5d, 0xf5, 0xeb, 0x72, 0xe0, 0x48, 0xc4, 0x39, 0x97, 0x31, 0x8b, 0x4e, 0x52, 0x99, + 0xe4, 0x09, 0xe9, 0x59, 0x1c, 0xfe, 0xbe, 0x0d, 0x9d, 0x69, 0x52, 0xc8, 0x39, 0x27, 0x47, 0xd0, + 0xba, 0x98, 0x04, 0xce, 0xd0, 0x19, 0xb5, 0x69, 0xeb, 0x62, 0x42, 0x08, 0xb8, 0xaf, 0xd8, 0x86, + 0x07, 0xad, 0xa1, 0x33, 0xf2, 0xa9, 0x5a, 0xa3, 0xec, 0xa6, 0x4c, 0x79, 0xd0, 0xd6, 0x32, 0x5c, + 0x93, 0x0f, 0xa0, 0x77, 0x9b, 0xa1, 0xb7, 0x0d, 0x0f, 0x5c, 0x25, 0xaf, 0x30, 0xea, 0xae, 0x59, + 0x96, 0x3d, 0x24, 0x72, 0x11, 0x78, 0x5a, 0x67, 0x31, 0x39, 0x86, 0xf6, 0x2d, 0xbd, 0x0c, 0x3a, + 0x4a, 0x8c, 0x4b, 0x12, 0x40, 0x77, 0xc2, 0x97, 0xac, 0x88, 0xf2, 0xa0, 0x3b, 0x74, 0x46, 0x3d, + 0x6a, 0x21, 0xfa, 0xb9, 0xe1, 0x11, 0x5f, 0x49, 0xb6, 0x0c, 0x7a, 0xda, 0x8f, 0xc5, 0xe4, 0x04, + 0xc8, 0x45, 0x9c, 0xf1, 0x79, 0x21, 0xf9, 0xf4, 0x4b, 0x91, 0xde, 0x71, 0x29, 0x96, 0x65, 0xe0, + 0x2b, 0x07, 0x07, 0x34, 0xb8, 0xcb, 0x4b, 0x9e, 0x33, 0xdc, 0x1b, 0x94, 0x2b, 0x0b, 0x49, 0x08, + 0x83, 0xe9, 0x9a, 0x49, 0xbe, 0x98, 0xf2, 0xb9, 0xe4, 0x79, 0xd0, 0x57, 0xea, 0x1d, 0x19, 0xda, + 0x5c, 0xc9, 0x15, 0x8b, 0xc5, 0xef, 0x58, 0x2e, 0x92, 0x38, 0x18, 0x68, 0x9b, 0xa6, 0x0c, 0xb3, + 0x44, 0x93, 0x88, 0x07, 0x4f, 0x74, 0x96, 0x70, 0x4d, 0xbe, 0x05, 0xbe, 0x09, 0x86, 0x5e, 0x07, + 0x47, 0x4a, 0x51, 0x0b, 0xc2, 0xbf, 0x3b, 0xe0, 0x4f, 0x58, 0xb6, 0x9e, 0x25, 0x4c, 0x2e, 0xde, + 0xe9, 0x26, 0x3e, 0x04, 0x6f, 0xce, 0xa3, 0x28, 0x0b, 0xda, 0xc3, 0xf6, 0xa8, 0x7f, 0xfa, 0xfe, + 0x49, 0x75, 0xc5, 0x95, 0x9f, 0x73, 0x1e, 0x45, 0x54, 0x5b, 0x91, 0x8f, 0xc0, 0xcf, 0xf9, 0x26, + 0x8d, 0x58, 0xce, 0xb3, 0xc0, 0x55, 0x3f, 0x21, 0xf5, 0x4f, 0x6e, 0x8c, 0x8a, 0xd6, 0x46, 0x7b, + 0x81, 0x7a, 0xfb, 0x81, 0x86, 0x7f, 0x74, 0xe1, 0xc9, 0xce, 0x76, 0x64, 0x00, 0xce, 0x56, 0x9d, + 0xdc, 0xa3, 0xce, 0x16, 0x51, 0xa9, 0x4e, 0xed, 0x51, 0xa7, 0x44, 0xf4, 0xa0, 0x2a, 0xc7, 0xa3, + 0xce, 0x03, 0xa2, 0xb5, 0xaa, 0x17, 0x8f, 0x3a, 0x6b, 0xf2, 0x43, 0xe8, 0xfe, 0xb6, 0xe0, 0x52, + 0xf0, 0x2c, 0xf0, 0xd4, 0xe9, 0xbe, 0x56, 0x9f, 0xee, 0x75, 0xc1, 0x65, 0x49, 0xad, 0x1e, 0xb3, + 0xa1, 0x6a, 0x4d, 0x17, 0x8e, 0x5a, 0xa3, 0x2c, 0xc7, 0xba, 0xec, 0x6a, 0x19, 0xae, 0x4d, 0x16, + 0x75, 0xb5, 0x60, 0x16, 0x7f, 0x06, 0x2e, 0xdb, 0xf2, 0x2c, 0xf0, 0x95, 0xff, 0xef, 0xbc, 0x21, + 0x61, 0x27, 0xe3, 0x2d, 0xcf, 0x7e, 0x19, 0xe7, 0xb2, 0xa4, 0xca, 0x9c, 0xfc, 0x00, 0x3a, 0xf3, + 0x24, 0x4a, 0x64, 0x16, 0xc0, 0xe3, 0x83, 0x9d, 0xa3, 0x9c, 0x1a, 0x35, 0x19, 0x41, 0x27, 0xe2, + 0x2b, 0x1e, 0x2f, 0x54, 0xdd, 0xf4, 0x4f, 0x8f, 0x6b, 0xc3, 0x4b, 0x25, 0xa7, 0x46, 0x4f, 0x3e, + 0x81, 0x41, 0xce, 0x66, 0x11, 0xbf, 0x4a, 0x31, 0x8b, 0x99, 0xaa, 0xa1, 0xfe, 0xe9, 0x7b, 0x8d, + 0xfb, 0x68, 0x68, 0xe9, 0x8e, 0x2d, 0xf9, 0x14, 0x06, 0x4b, 0xc1, 0xa3, 0x85, 0xfd, 0xed, 0x13, + 0x75, 0xa8, 0xa0, 0xfe, 0x2d, 0xe5, 0x31, 0xdb, 0xe0, 0x2f, 0x9e, 0xa1, 0x19, 0xdd, 0xb1, 0x26, + 0xdf, 0x06, 0xc8, 0xc5, 0x86, 0x3f, 0x4b, 0xe4, 0x86, 0xe5, 0xa6, 0x0c, 0x1b, 0x92, 0x0f, 0x3e, + 0x07, 0xbf, 0x8a, 0x1f, 0x1b, 0xf4, 0x4b, 0x5e, 0xaa, 0xdb, 0xf4, 0x29, 0x2e, 0xc9, 0x77, 0xc1, + 0xbb, 0x67, 0x51, 0xa1, 0x2b, 0xb1, 0x7f, 0x7a, 0x54, 0xef, 0x3a, 0xde, 0x8a, 0x8c, 0x6a, 0xe5, + 0x27, 0xad, 0x9f, 0x3b, 0xe1, 0x3f, 0x1c, 0x18, 0x34, 0xa3, 0x20, 0x3f, 0x82, 0xe3, 0x7b, 0x2e, + 0x73, 0x31, 0x67, 0xd1, 0x8d, 0xd8, 0x70, 0xb4, 0x57, 0x5e, 0x7a, 0x74, 0x4f, 0x4e, 0x3e, 0x82, + 0x4e, 0x96, 0xc8, 0xfc, 0xac, 0x54, 0xd5, 0xf2, 0xb6, 0xe8, 0x8c, 0x1d, 0xf2, 0xc3, 0x83, 0x64, + 0x69, 0x2a, 0xe2, 0x95, 0xe5, 0x20, 0x8b, 0xc9, 0xf7, 0xe1, 0x68, 0x29, 0xb6, 0xcf, 0x84, 0xcc, + 0xf2, 0xf3, 0x24, 0x2a, 0x36, 0xb1, 0xaa, 0x9c, 0x1e, 0x7d, 0x24, 0x7d, 0xee, 0xf6, 0x9c, 0xe3, + 0xd6, 0x73, 0xb7, 0xe7, 0x1d, 0x77, 0xc2, 0x3f, 0x38, 0x70, 0xb4, 0xbb, 0x15, 0xf6, 0x83, 0x3d, + 0x85, 0x6a, 0x46, 0x9d, 0x96, 0x1d, 0x19, 0x19, 0x42, 0x7f, 0x21, 0xb2, 0x34, 0x62, 0x65, 0xa3, + 0x5f, 0x9b, 0x22, 0x24, 0x9f, 0x7b, 0x91, 0x89, 0x59, 0xa4, 0x39, 0xb4, 0x47, 0x2d, 0x44, 0x82, + 0x48, 0x25, 0x9f, 0x8b, 0x0c, 0x9b, 0x4d, 0xf7, 0x45, 0x2d, 0x08, 0x57, 0xe0, 0xa9, 0x6a, 0x6b, + 0x70, 0x83, 0x6f, 0xb9, 0x41, 0x31, 0x72, 0xab, 0xc1, 0xc8, 0xc7, 0xd0, 0xfe, 0x15, 0xdf, 0x1a, + 0x92, 0xc6, 0x65, 0xc5, 0x20, 0x6e, 0x83, 0x41, 0x9e, 0x82, 0x77, 0xa7, 0x2e, 0x53, 0x77, 0xb6, + 0x06, 0xe1, 0x67, 0xd0, 0xd1, 0xd5, 0x5a, 0x79, 0x76, 0x1a, 0x9e, 0x87, 0xd0, 0xbf, 0x92, 0x82, + 0xc7, 0xb9, 0xe6, 0x04, 0x13, 0x60, 0x43, 0x14, 0xfe, 0xcd, 0x01, 0x57, 0x5d, 0x62, 0x08, 0x83, + 0x88, 0xaf, 0xd8, 0xbc, 0x3c, 0x4b, 0x8a, 0x78, 0x91, 0x05, 0xce, 0xb0, 0x3d, 0x6a, 0xd3, 0x1d, + 0x19, 0x79, 0x0f, 0x3a, 0x33, 0xad, 0x6d, 0x0d, 0xdb, 0x23, 0x9f, 0x1a, 0x84, 0x47, 0x8b, 0xd8, + 0x8c, 0x47, 0x26, 0x04, 0x0d, 0xd0, 0x3a, 0x95, 0x7c, 0x29, 0xb6, 0x26, 0x0c, 0x83, 0x50, 0x9e, + 0x15, 0x4b, 0x94, 0xeb, 0x48, 0x0c, 0xc2, 0x00, 0x66, 0x2c, 0xab, 0x88, 0x02, 0xd7, 0xe8, 0x39, + 0x9b, 0xb3, 0xc8, 0x32, 0x85, 0x06, 0xe1, 0x3f, 0x1d, 0x7c, 0x5f, 0x34, 0xf3, 0xed, 0x65, 0xf8, + 0x1b, 0xd0, 0x43, 0x56, 0xfc, 0xe2, 0x9e, 0x49, 0x13, 0x70, 0x17, 0xf1, 0x1d, 0x93, 0xe4, 0xa7, + 0xd0, 0x51, 0x25, 0x7f, 0x80, 0x85, 0xad, 0x3b, 0x95, 0x55, 0x6a, 0xcc, 0x2a, 0x9e, 0x72, 0x1b, + 0x3c, 0x55, 0x05, 0xeb, 0x35, 0x83, 0xfd, 0x10, 0x3c, 0x24, 0xbc, 0x52, 0x9d, 0xfe, 0xa0, 0x67, + 0x4d, 0x8b, 0xda, 0x2a, 0xbc, 0x85, 0x27, 0x3b, 0x3b, 0x56, 0x3b, 0x39, 0xbb, 0x3b, 0xd5, 0xed, + 0xeb, 0x9b, 0x76, 0xc5, 0xde, 0xc9, 0x78, 0xc4, 0xe7, 0x39, 0x5f, 0x98, 0x9a, 0xac, 0x70, 0xf8, + 0x67, 0xa7, 0xf6, 0xab, 0xf6, 0xc3, 0x02, 0x9e, 0x27, 0x9b, 0x0d, 0x8b, 0x17, 0xc6, 0xb5, 0x85, + 0x98, 0xb7, 0xc5, 0xcc, 0xb8, 0x6e, 0x2d, 0x66, 0x88, 0x65, 0x6a, 0x6e, 0xb0, 0x25, 0x53, 0xac, + 0x9d, 0x0d, 0x67, 0x59, 0x21, 0xf9, 0x86, 0xc7, 0xb9, 0x49, 0x41, 0x53, 0x44, 0xde, 0x87, 0x6e, + 0xce, 0x56, 0x5f, 0x20, 0xe9, 0x98, 0x9b, 0xcc, 0xd9, 0xea, 0x05, 0x2f, 0xc9, 0x37, 0xc1, 0x57, + 0x34, 0xa6, 0x54, 0xfa, 0x3a, 0x7b, 0x4a, 0xf0, 0x82, 0x97, 0xe1, 0x7f, 0x1c, 0xe8, 0x4c, 0xb9, + 0xbc, 0xe7, 0xf2, 0x9d, 0x1e, 0xce, 0xe6, 0xb8, 0xd2, 0x7e, 0xcb, 0xb8, 0xe2, 0x1e, 0x1e, 0x57, + 0xbc, 0x7a, 0x5c, 0x79, 0x0a, 0xde, 0x54, 0xce, 0x2f, 0x26, 0xea, 0x44, 0x6d, 0xaa, 0x01, 0x56, + 0xe3, 0x78, 0x9e, 0x8b, 0x7b, 0x6e, 0x66, 0x18, 0x83, 0xf6, 0xde, 0xd3, 0xde, 0x81, 0xc1, 0xe1, + 0x7f, 0x1c, 0x65, 0xc2, 0x3f, 0x39, 0xd0, 0xb9, 0x64, 0x65, 0x52, 0xe4, 0x7b, 0x55, 0x3b, 0x84, + 0xfe, 0x38, 0x4d, 0x23, 0x31, 0xdf, 0xe9, 0xd4, 0x86, 0x08, 0x2d, 0x5e, 0x36, 0xee, 0x43, 0xe7, + 0xa2, 0x29, 0x42, 0xba, 0x3f, 0x57, 0x33, 0x86, 0x1e, 0x18, 0x1a, 0x74, 0xaf, 0x47, 0x0b, 0xa5, + 0xc4, 0xa4, 0x8d, 0x8b, 0x3c, 0x59, 0x46, 0xc9, 0x83, 0xca, 0x4e, 0x8f, 0x56, 0x38, 0xfc, 0x57, + 0x0b, 0xdc, 0xaf, 0x6a, 0x2e, 0x18, 0x80, 0x23, 0x4c, 0x71, 0x38, 0xa2, 0x9a, 0x12, 0xba, 0x8d, + 0x29, 0x21, 0x80, 0x6e, 0x29, 0x59, 0xbc, 0xe2, 0x59, 0xd0, 0x53, 0x6c, 0x64, 0xa1, 0xd2, 0xa8, + 0xbe, 0xd3, 0xe3, 0x81, 0x4f, 0x2d, 0xac, 0xfa, 0x08, 0x1a, 0x7d, 0xf4, 0x13, 0x33, 0x49, 0xf4, + 0x1f, 0xbf, 0xbd, 0x87, 0x06, 0x88, 0xff, 0xdf, 0x9b, 0xfa, 0x6f, 0x07, 0xbc, 0xaa, 0x09, 0xcf, + 0x77, 0x9b, 0xf0, 0xbc, 0x6e, 0xc2, 0xc9, 0x99, 0x6d, 0xc2, 0xc9, 0x19, 0x62, 0x7a, 0x6d, 0x9b, + 0x90, 0x5e, 0xe3, 0x65, 0x7d, 0x2e, 0x93, 0x22, 0x3d, 0x2b, 0xf5, 0xad, 0xfa, 0xb4, 0xc2, 0x58, + 0xb9, 0xbf, 0x5e, 0x73, 0x69, 0x52, 0xed, 0x53, 0x83, 0xb0, 0xce, 0x2f, 0x15, 0x41, 0xe9, 0xe4, + 0x6a, 0x40, 0xbe, 0x07, 0x1e, 0xc5, 0xe4, 0xa9, 0x0c, 0xef, 0xdc, 0x8b, 0x12, 0x53, 0xad, 0x45, + 0xa7, 0xfa, 0xfb, 0xc2, 0x14, 0xbc, 0xfd, 0xda, 0xf8, 0x31, 0x74, 0xa6, 0x6b, 0xb1, 0xcc, 0xed, + 0x3c, 0xf6, 0xf5, 0x06, 0xc1, 0x89, 0x0d, 0x57, 0x3a, 0x6a, 0x4c, 0xc2, 0xd7, 0xe0, 0x57, 0xc2, + 0xfa, 0x38, 0x4e, 0xf3, 0x38, 0x04, 0xdc, 0xdb, 0x58, 0xe4, 0xb6, 0xd5, 0x71, 0x8d, 0xc1, 0xbe, + 0x2e, 0x58, 0x9c, 0x8b, 0xbc, 0xb4, 0xad, 0x6e, 0x71, 0xf8, 0xb1, 0x39, 0x3e, 0xba, 0xbb, 0x4d, + 0x53, 0x2e, 0x0d, 0x6d, 0x68, 0xa0, 0x36, 0x49, 0x1e, 0xb8, 0x66, 0xfc, 0x36, 0xd5, 0x20, 0xfc, + 0x0d, 0xf8, 0xe3, 0x88, 0xcb, 0x9c, 0x16, 0x11, 0x3f, 0xf4, 0x12, 0x3f, 0x9f, 0x5e, 0xbd, 0xb2, + 0x27, 0xc0, 0x75, 0x4d, 0x11, 0xed, 0x47, 0x14, 0xf1, 0x82, 0xa5, 0xec, 0x62, 0xa2, 0xea, 0xbc, + 0x4d, 0x0d, 0x0a, 0xff, 0xe2, 0x80, 0x8b, 0x5c, 0xd4, 0x70, 0xed, 0xbe, 0x8d, 0xc7, 0xae, 0x65, + 0x72, 0x2f, 0x16, 0x5c, 0xda, 0xe0, 0x2c, 0x56, 0x49, 0x9f, 0xaf, 0x79, 0xf5, 0xe0, 0x1b, 0x84, + 0xb5, 0x86, 0x1f, 0x23, 0xb6, 0x97, 0x1a, 0xb5, 0x86, 0x62, 0xaa, 0x95, 0x38, 0x24, 0x4e, 0x8b, + 0x94, 0xcb, 0xf1, 0x62, 0x23, 0xec, 0xb0, 0xd4, 0x90, 0x84, 0x9f, 0xe9, 0xcf, 0x9b, 0x3d, 0x46, + 0x73, 0x0e, 0x7f, 0x0a, 0x3d, 0x3e, 0x79, 0xf8, 0x57, 0x07, 0xba, 0x2f, 0xcd, 0x70, 0xd6, 0x8c, + 0xc2, 0x79, 0x63, 0x14, 0xad, 0x9d, 0x28, 0x4e, 0xe1, 0xa9, 0xb5, 0xd9, 0xd9, 0x5f, 0x67, 0xe1, + 0xa0, 0xce, 0x64, 0xd4, 0xad, 0x2e, 0xeb, 0x5d, 0xbe, 0x6e, 0x6e, 0x76, 0x6d, 0x0e, 0x5d, 0xf8, + 0xde, 0xad, 0x0c, 0xa1, 0x6f, 0xbf, 0xea, 0x92, 0xc8, 0x3e, 0x30, 0x4d, 0x51, 0x78, 0x0a, 0x9d, + 0xf3, 0x24, 0x5e, 0x8a, 0x15, 0x19, 0x81, 0x3b, 0x2e, 0xf2, 0xb5, 0xf2, 0xd8, 0x3f, 0x7d, 0xda, + 0x68, 0xfc, 0x22, 0x5f, 0x6b, 0x1b, 0xaa, 0x2c, 0xc2, 0x4f, 0x01, 0x6a, 0x19, 0xbe, 0x12, 0xf5, + 0x6d, 0xbc, 0xe2, 0x0f, 0x58, 0x32, 0x99, 0xf2, 0xd2, 0xa3, 0x07, 0x34, 0xe1, 0x2f, 0xc0, 0x3f, + 0x2b, 0x44, 0xb4, 0xb8, 0x88, 0x97, 0x09, 0x52, 0xc7, 0x1d, 0x97, 0x59, 0x7d, 0x5f, 0x16, 0x62, + 0xba, 0x91, 0x45, 0xaa, 0x1e, 0x32, 0x68, 0xd6, 0x51, 0xff, 0x19, 0x7c, 0xfc, 0xdf, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x54, 0x72, 0x77, 0x46, 0x45, 0x10, 0x00, 0x00, } diff --git a/bolt/internal/internal.proto b/bolt/internal/internal.proto index f4693d29b8..9373e54c85 100644 --- a/bolt/internal/internal.proto +++ b/bolt/internal/internal.proto @@ -27,27 +27,28 @@ message Dashboard { } message DashboardCell { - int32 x = 1; // X-coordinate of Cell in the Dashboard - int32 y = 2; // Y-coordinate of Cell in the Dashboard - int32 w = 3; // Width of Cell in the Dashboard - int32 h = 4; // Height of Cell in the Dashboard - repeated Query queries = 5; // Time-series data queries for Dashboard - string name = 6; // User-facing name for this Dashboard - string type = 7; // Dashboard visualization type - string ID = 8; // id is the unique id of the dashboard. MIGRATED FIELD added in 1.2.0-beta6 - map axes = 9; // Axes represent the graphical viewport for a cell's visualizations - repeated Color colors = 10; // Colors represent encoding data values to color - Legend legend = 11; // Legend is summary information for a cell - TableOptions tableOptions = 12; // TableOptions for visualization of cell with type 'table' + int32 x = 1; // X-coordinate of Cell in the Dashboard + int32 y = 2; // Y-coordinate of Cell in the Dashboard + int32 w = 3; // Width of Cell in the Dashboard + int32 h = 4; // Height of Cell in the Dashboard + repeated Query queries = 5; // Time-series data queries for Dashboard + string name = 6; // User-facing name for this Dashboard + string type = 7; // Dashboard visualization type + string ID = 8; // id is the unique id of the dashboard. MIGRATED FIELD added in 1.2.0-beta6 + map axes = 9; // Axes represent the graphical viewport for a cell's visualizations + repeated Color colors = 10; // Colors represent encoding data values to color + Legend legend = 11; // Legend is summary information for a cell + TableOptions tableOptions = 12; // TableOptions for visualization of cell with type 'table' repeated RenamableField fieldOptions = 13; // Options for each of the fields returned in a cell + string timeFormat = 14; // format for time } message TableOptions { - string timeFormat = 1; // format for time + reserved 1; bool verticalTimeAxis = 2; // time axis should be a column not row RenamableField sortBy = 3; // which column should a table be sorted by string wrapping = 4; // option for text wrapping - reserved 5 + reserved 5; bool fixFirstColumn = 6; // first column should be fixed/frozen } diff --git a/bolt/internal/internal_test.go b/bolt/internal/internal_test.go index cf66c41fd3..ff4bf0ce94 100644 --- a/bolt/internal/internal_test.go +++ b/bolt/internal/internal_test.go @@ -194,10 +194,9 @@ func Test_MarshalDashboard(t *testing.T) { Value: "100", }, }, - TableOptions: chronograf.TableOptions{ - TimeFormat: "", - }, + TableOptions: chronograf.TableOptions{}, FieldOptions: []chronograf.RenamableField{}, + TimeFormat: "", }, }, Templates: []chronograf.Template{}, @@ -260,9 +259,8 @@ func Test_MarshalDashboard_WithLegacyBounds(t *testing.T) { Type: "static", Orientation: "bottom", }, - TableOptions: chronograf.TableOptions{ - TimeFormat: "MM:DD:YYYY", - }, + TableOptions: chronograf.TableOptions{}, + TimeFormat: "MM:DD:YYYY", FieldOptions: []chronograf.RenamableField{}, Type: "line", }, @@ -318,10 +316,9 @@ func Test_MarshalDashboard_WithLegacyBounds(t *testing.T) { Type: "static", Orientation: "bottom", }, - TableOptions: chronograf.TableOptions{ - TimeFormat: "MM:DD:YYYY", - }, + TableOptions: chronograf.TableOptions{}, FieldOptions: []chronograf.RenamableField{}, + TimeFormat: "MM:DD:YYYY", Type: "line", }, }, @@ -381,11 +378,10 @@ func Test_MarshalDashboard_WithEmptyLegacyBounds(t *testing.T) { Value: "100", }, }, - Type: "line", - TableOptions: chronograf.TableOptions{ - TimeFormat: "MM:DD:YYYY", - }, + Type: "line", + TableOptions: chronograf.TableOptions{}, FieldOptions: []chronograf.RenamableField{}, + TimeFormat: "MM:DD:YYYY", }, }, Templates: []chronograf.Template{}, @@ -435,10 +431,9 @@ func Test_MarshalDashboard_WithEmptyLegacyBounds(t *testing.T) { Value: "100", }, }, - TableOptions: chronograf.TableOptions{ - TimeFormat: "MM:DD:YYYY", - }, + TableOptions: chronograf.TableOptions{}, FieldOptions: []chronograf.RenamableField{}, + TimeFormat: "MM:DD:YYYY", Type: "line", }, }, diff --git a/chronograf.go b/chronograf.go index a14de9a41e..9259f0e480 100644 --- a/chronograf.go +++ b/chronograf.go @@ -576,6 +576,7 @@ type DashboardCell struct { Legend Legend `json:"legend"` TableOptions TableOptions `json:"tableOptions,omitempty"` FieldOptions []RenamableField `json:"fieldOptions"` + TimeFormat string `json:"timeFormat"` } // RenamableField is a column/row field in a DashboardCell of type Table @@ -588,7 +589,6 @@ type RenamableField struct { // TableOptions is a type of options for a DashboardCell with type Table type TableOptions struct { - TimeFormat string `json:"timeFormat"` VerticalTimeAxis bool `json:"verticalTimeAxis"` SortBy RenamableField `json:"sortBy"` Wrapping string `json:"wrapping"` diff --git a/integrations/server_test.go b/integrations/server_test.go index 19b5911cf9..84b2d11ca6 100644 --- a/integrations/server_test.go +++ b/integrations/server_test.go @@ -548,7 +548,6 @@ func TestServer(t *testing.T) { "orientation": "bottom" }, "tableOptions":{ - "timeFormat": "", "verticalTimeAxis": false, "sortBy":{ "internalName": "", @@ -560,6 +559,7 @@ func TestServer(t *testing.T) { "fixFirstColumn": false }, "fieldOptions": null, + "timeFormat": "", "links": { "self": "/chronograf/v1/dashboards/1000/cells/8f61c619-dd9b-4761-8aa8-577f27247093" } @@ -800,7 +800,6 @@ func TestServer(t *testing.T) { } ], "tableOptions":{ - "timeFormat":"", "verticalTimeAxis":false, "sortBy":{ "internalName":"", @@ -812,6 +811,7 @@ func TestServer(t *testing.T) { "fixFirstColumn":false }, "fieldOptions":null, + "timeFormat":"", "legend":{ "type": "static", "orientation": "bottom" diff --git a/server/cells_test.go b/server/cells_test.go index 20eeec392f..87018ea488 100644 --- a/server/cells_test.go +++ b/server/cells_test.go @@ -532,7 +532,7 @@ func TestService_ReplaceDashboardCell(t *testing.T) { } } `))), - want: `{"i":"3c5c4102-fa40-4585-a8f9-917c77e37192","x":0,"y":0,"w":4,"h":4,"name":"Untitled Cell","queries":[{"query":"SELECT mean(\"usage_user\") AS \"mean_usage_user\" FROM \"telegraf\".\"autogen\".\"cpu\" WHERE time \u003e :dashboardTime: AND \"cpu\"=:cpu: GROUP BY :interval: FILL(null)","queryConfig":{"id":"3cd3eaa4-a4b8-44b3-b69e-0c7bf6b91d9e","database":"telegraf","measurement":"cpu","retentionPolicy":"autogen","fields":[{"value":"mean","type":"func","alias":"mean_usage_user","args":[{"value":"usage_user","type":"field","alias":""}]}],"tags":{"cpu":["ChristohersMBP2.lan"]},"groupBy":{"time":"2s","tags":[]},"areTagsAccepted":true,"fill":"null","rawText":"SELECT mean(\"usage_user\") AS \"mean_usage_user\" FROM \"telegraf\".\"autogen\".\"cpu\" WHERE time \u003e :dashboardTime: AND \"cpu\"=:cpu: GROUP BY :interval: FILL(null)","range":{"upper":"","lower":"now() - 15m"},"shifts":[]},"source":""}],"axes":{"x":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""},"y":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""},"y2":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""}},"type":"line","colors":[{"id":"0","type":"min","hex":"#00C9FF","name":"laser","value":"0"},{"id":"1","type":"max","hex":"#9394FF","name":"comet","value":"100"}],"legend":{},"tableOptions":{"timeFormat":"","verticalTimeAxis":false,"sortBy":{"internalName":"","displayName":"","visible":false,"precision":0},"wrapping":"","fixFirstColumn":false},"fieldOptions":null,"links":{"self":"/chronograf/v1/dashboards/1/cells/3c5c4102-fa40-4585-a8f9-917c77e37192"}} + want: `{"i":"3c5c4102-fa40-4585-a8f9-917c77e37192","x":0,"y":0,"w":4,"h":4,"name":"Untitled Cell","queries":[{"query":"SELECT mean(\"usage_user\") AS \"mean_usage_user\" FROM \"telegraf\".\"autogen\".\"cpu\" WHERE time \u003e :dashboardTime: AND \"cpu\"=:cpu: GROUP BY :interval: FILL(null)","queryConfig":{"id":"3cd3eaa4-a4b8-44b3-b69e-0c7bf6b91d9e","database":"telegraf","measurement":"cpu","retentionPolicy":"autogen","fields":[{"value":"mean","type":"func","alias":"mean_usage_user","args":[{"value":"usage_user","type":"field","alias":""}]}],"tags":{"cpu":["ChristohersMBP2.lan"]},"groupBy":{"time":"2s","tags":[]},"areTagsAccepted":true,"fill":"null","rawText":"SELECT mean(\"usage_user\") AS \"mean_usage_user\" FROM \"telegraf\".\"autogen\".\"cpu\" WHERE time \u003e :dashboardTime: AND \"cpu\"=:cpu: GROUP BY :interval: FILL(null)","range":{"upper":"","lower":"now() - 15m"},"shifts":[]},"source":""}],"axes":{"x":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""},"y":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""},"y2":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""}},"type":"line","colors":[{"id":"0","type":"min","hex":"#00C9FF","name":"laser","value":"0"},{"id":"1","type":"max","hex":"#9394FF","name":"comet","value":"100"}],"legend":{},"tableOptions":{"verticalTimeAxis":false,"sortBy":{"internalName":"","displayName":"","visible":false,"precision":0},"wrapping":"","fixFirstColumn":false},"fieldOptions":null,"timeFormat":"","links":{"self":"/chronograf/v1/dashboards/1/cells/3c5c4102-fa40-4585-a8f9-917c77e37192"}} `, }, { From 265897d17bb0d89fcc9f2556723a869a1a0e82f2 Mon Sep 17 00:00:00 2001 From: Iris Scholten Date: Thu, 19 Apr 2018 18:57:22 -0700 Subject: [PATCH 05/48] WIP Move timeFormat and fieldNames/fieldOptions outside of tableOptions in the client --- .../dashboards/actions/cellEditorOverlay.js | 7 ++ ui/src/dashboards/components/TableOptions.tsx | 77 ++++++++++++------- ui/src/dashboards/components/Visualization.js | 16 +++- .../dashboards/reducers/cellEditorOverlay.js | 6 ++ ui/src/shared/components/Layout.js | 13 +++- ui/src/shared/components/RefreshingGraph.js | 12 +++ ui/src/shared/components/TableGraph.js | 44 +++++------ ui/src/shared/constants/tableGraph.js | 2 - ui/src/utils/timeSeriesTransformers.js | 18 +++-- .../components/TableOptions.test.tsx | 4 +- 10 files changed, 134 insertions(+), 65 deletions(-) diff --git a/ui/src/dashboards/actions/cellEditorOverlay.js b/ui/src/dashboards/actions/cellEditorOverlay.js index f9efe0de08..dae56aa318 100644 --- a/ui/src/dashboards/actions/cellEditorOverlay.js +++ b/ui/src/dashboards/actions/cellEditorOverlay.js @@ -64,3 +64,10 @@ export const updateLineColors = lineColors => ({ lineColors, }, }) + +export const updateDisplayOptions = update => ({ + type: 'UPDATE_DISPLAY_OPTIONS', + payload: { + update, + }, +}) diff --git a/ui/src/dashboards/components/TableOptions.tsx b/ui/src/dashboards/components/TableOptions.tsx index eb4f872c32..f9025bc50c 100644 --- a/ui/src/dashboards/components/TableOptions.tsx +++ b/ui/src/dashboards/components/TableOptions.tsx @@ -14,7 +14,10 @@ import _ from 'lodash' import ThresholdsList from 'src/shared/components/ThresholdsList' import ThresholdsListTypeToggle from 'src/shared/components/ThresholdsListTypeToggle' -import {updateTableOptions} from 'src/dashboards/actions/cellEditorOverlay' +import { + updateTableOptions, + updateDisplayOptions, +} from 'src/dashboards/actions/cellEditorOverlay' import {TIME_FIELD_DEFAULT} from 'src/shared/constants/tableGraph' import {QueryConfig} from 'src/types/query' import {ErrorHandling} from 'src/shared/decorators/errors' @@ -31,17 +34,18 @@ interface RenamableField { } interface Options { - timeFormat: string verticalTimeAxis: boolean sortBy: RenamableField - fieldNames: RenamableField[] fixFirstColumn: boolean } interface Props { queryConfigs: QueryConfig[] handleUpdateTableOptions: (options: Options) => void + handleUpdateDisplayOptions: (displayOption: string | RenamableField[]) => void tableOptions: Options + fieldOptions: RenamableField[] + timeFormat: string onResetFocus: () => void } @@ -53,10 +57,9 @@ export class TableOptions extends PureComponent { } public componentWillMount() { - const {handleUpdateTableOptions, tableOptions} = this.props - handleUpdateTableOptions({ - ...tableOptions, - fieldNames: this.computedFieldNames, + const {handleUpdateDisplayOptions, tableOptions} = this.props + handleUpdateDisplayOptions({ + fieldOptions: this.computedFieldOptions, }) } @@ -72,12 +75,14 @@ export class TableOptions extends PureComponent { public render() { const { - tableOptions: {timeFormat, fieldNames, verticalTimeAxis, fixFirstColumn}, + tableOptions: {verticalTimeAxis, fixFirstColumn}, + fieldOptions, + timeFormat, onResetFocus, tableOptions, } = this.props - const tableSortByOptions = fieldNames.map(field => ({ + const tableSortByOptions = fieldOptions.map(field => ({ key: field.internalName, text: field.displayName || field.internalName, })) @@ -109,7 +114,7 @@ export class TableOptions extends PureComponent { /> @@ -122,21 +127,21 @@ export class TableOptions extends PureComponent { ) } - private get fieldNames() { - const {tableOptions: {fieldNames}} = this.props - return fieldNames || [] + private get fieldOptions() { + return this.props.fieldOptions || [] } private get timeField() { return ( - this.fieldNames.find(f => f.internalName === 'time') || TIME_FIELD_DEFAULT + this.fieldOptions.find(f => f.internalName === 'time') || + TIME_FIELD_DEFAULT ) } private moveField(dragIndex, hoverIndex) { - const {handleUpdateTableOptions, tableOptions} = this.props - const {fieldNames} = tableOptions - const fields = fieldNames.length > 1 ? fieldNames : this.computedFieldNames + const {handleUpdateDisplayOptions, tableOptions, fieldOptions} = this.props + const fields = + fieldOptions.length > 1 ? fieldOptions : this.computedFieldOptions const dragField = fields[dragIndex] const removedFields = _.concat( @@ -148,19 +153,18 @@ export class TableOptions extends PureComponent { [dragField], _.slice(removedFields, hoverIndex) ) - handleUpdateTableOptions({ - ...tableOptions, - fieldNames: addedFields, + handleUpdateDisplayOptions({ + fieldOptions: addedFields, }) } - private get computedFieldNames() { + private get computedFieldOptions() { const {queryConfigs} = this.props const queryFields = _.flatten( queryConfigs.map(({measurement, fields}) => { return fields.map(({alias}) => { const internalName = `${measurement}.${alias}` - const existing = this.fieldNames.find( + const existing = this.fieldOptions.find( c => c.internalName === internalName ) return existing || {internalName, displayName: '', visible: true} @@ -183,8 +187,8 @@ export class TableOptions extends PureComponent { } private handleTimeFormatChange = timeFormat => { - const {tableOptions, handleUpdateTableOptions} = this.props - handleUpdateTableOptions({...tableOptions, timeFormat}) + const {handleUpdateDisplayOptions} = this.props + handleUpdateDisplayOptions({timeFormat}) } private handleToggleVerticalTimeAxis = verticalTimeAxis => () => { @@ -199,9 +203,14 @@ export class TableOptions extends PureComponent { } private handleFieldUpdate = field => { - const {handleUpdateTableOptions, tableOptions} = this.props - const {sortBy, fieldNames} = tableOptions - const updatedFields = fieldNames.map( + const { + handleUpdateTableOptions, + handleUpdateDisplayOptions, + tableOptions, + fieldOptions, + } = this.props + const {sortBy} = tableOptions + const updatedFields = fieldOptions.map( f => (f.internalName === field.internalName ? field : f) ) const updatedSortBy = @@ -211,18 +220,28 @@ export class TableOptions extends PureComponent { handleUpdateTableOptions({ ...tableOptions, - fieldNames: updatedFields, sortBy: updatedSortBy, }) + handleUpdateDisplayOptions({ + fieldOptions: updatedFields, + }) } } -const mapStateToProps = ({cellEditorOverlay: {cell: {tableOptions}}}) => ({ +const mapStateToProps = ({ + cellEditorOverlay: {cell: {tableOptions, timeFormat, fieldOptions}}, +}) => ({ tableOptions, + timeFormat, + fieldOptions, }) const mapDispatchToProps = dispatch => ({ handleUpdateTableOptions: bindActionCreators(updateTableOptions, dispatch), + handleUpdateDisplayOptions: bindActionCreators( + updateDisplayOptions, + dispatch + ), }) export default connect(mapStateToProps, mapDispatchToProps)(TableOptions) diff --git a/ui/src/dashboards/components/Visualization.js b/ui/src/dashboards/components/Visualization.js index 82cf5ce831..750accbad8 100644 --- a/ui/src/dashboards/components/Visualization.js +++ b/ui/src/dashboards/components/Visualization.js @@ -24,6 +24,8 @@ const DashVisualization = ( staticLegend, thresholdsListColors, tableOptions, + timeFormat, + fieldOptions, }, {source: {links: {proxy}}} ) => { @@ -49,6 +51,8 @@ const DashVisualization = ( editQueryStatus={editQueryStatus} resizerTopHeight={resizerTopHeight} staticLegend={staticLegend} + timeFormat={timeFormat} + fieldOptions={fieldOptions} /> @@ -73,6 +77,14 @@ DashVisualization.propTypes = { }), }), tableOptions: shape({}), + timeFormat: string.isRequired, + fieldOptions: arrayOf( + shape({ + internalName: string.isRequired, + displayName: string.isRequired, + visible: string.isRequired, + }) + ), resizerTopHeight: number, thresholdsListColors: colorsNumberSchema, gaugeColors: colorsNumberSchema, @@ -93,7 +105,7 @@ const mapStateToProps = ({ thresholdsListColors, gaugeColors, lineColors, - cell: {type, axes, tableOptions}, + cell: {type, axes, tableOptions, fieldOptions, timeFormat}, }, }) => ({ gaugeColors, @@ -102,6 +114,8 @@ const mapStateToProps = ({ type, axes, tableOptions, + fieldOptions, + timeFormat, }) export default connect(mapStateToProps, null)(DashVisualization) diff --git a/ui/src/dashboards/reducers/cellEditorOverlay.js b/ui/src/dashboards/reducers/cellEditorOverlay.js index d51d2c503c..42c73fbedf 100644 --- a/ui/src/dashboards/reducers/cellEditorOverlay.js +++ b/ui/src/dashboards/reducers/cellEditorOverlay.js @@ -116,6 +116,12 @@ export default function cellEditorOverlay(state = initialState, action) { return {...state, lineColors} } + + case 'UPDATE_DISPLAY_OPTIONS': { + const {update} = action.payload + const cell = {...state.cell, ...update} + return {...state, cell} + } } return state diff --git a/ui/src/shared/components/Layout.js b/ui/src/shared/components/Layout.js index 684afbc858..ff727452e4 100644 --- a/ui/src/shared/components/Layout.js +++ b/ui/src/shared/components/Layout.js @@ -45,7 +45,16 @@ const Layout = ( { host, cell, - cell: {h, axes, type, colors, legend, tableOptions}, + cell: { + h, + axes, + type, + colors, + legend, + timeFormat, + fieldOptions, + tableOptions, + }, source, sources, onZoom, @@ -85,6 +94,8 @@ const Layout = ( axes={axes} type={type} tableOptions={tableOptions} + fieldOptions={fieldOptions} + timeFormat={timeFormat} staticLegend={IS_STATIC_LEGEND(legend)} cellHeight={h} onZoom={onZoom} diff --git a/ui/src/shared/components/RefreshingGraph.js b/ui/src/shared/components/RefreshingGraph.js index 56c906347b..fc82a37a76 100644 --- a/ui/src/shared/components/RefreshingGraph.js +++ b/ui/src/shared/components/RefreshingGraph.js @@ -33,6 +33,8 @@ const RefreshingGraph = ({ timeRange, cellHeight, autoRefresh, + fieldOptions, + timeFormat, resizerTopHeight, staticLegend, manualRefresh, // when changed, re-mounts the component @@ -101,6 +103,8 @@ const RefreshingGraph = ({ cellHeight={cellHeight} resizeCoords={resizeCoords} tableOptions={tableOptions} + fieldOptions={fieldOptions} + timeFormat={timeFormat} resizerTopHeight={resizerTopHeight} handleSetHoverTime={handleSetHoverTime} /> @@ -159,6 +163,14 @@ RefreshingGraph.propTypes = { cellID: string, inView: bool, tableOptions: shape({}), + fieldOptions: arrayOf( + shape({ + internalName: string.isRequired, + displayName: string.isRequired, + visible: bool.isRequired, + }) + ), + timeFormat: string.isRequired, hoverTime: string.isRequired, handleSetHoverTime: func.isRequired, } diff --git a/ui/src/shared/components/TableGraph.js b/ui/src/shared/components/TableGraph.js index 9a1db53e48..e12128a19c 100644 --- a/ui/src/shared/components/TableGraph.js +++ b/ui/src/shared/components/TableGraph.js @@ -61,12 +61,9 @@ class TableGraph extends Component { const {sortField, sortDirection} = this.state const { - tableOptions: { - sortBy: {internalName}, - fieldNames, - verticalTimeAxis, - timeFormat, - }, + tableOptions: {sortBy: {internalName}, verticalTimeAxis}, + timeFormat, + fieldOptions, } = nextProps let direction, sortFieldName @@ -91,7 +88,7 @@ class TableGraph extends Component { sortFieldName, direction, verticalTimeAxis, - fieldNames, + fieldOptions, timeFormat ) @@ -166,7 +163,7 @@ class TableGraph extends Component { const {tableOptions} = this.props const {data, sortField, sortDirection} = this.state const verticalTimeAxis = _.get(tableOptions, 'verticalTimeAxis', true) - const fieldNames = _.get(tableOptions, 'fieldNames', [TIME_FIELD_DEFAULT]) + const fieldOptions = _.get(this.props, 'fieldOptions', [TIME_FIELD_DEFAULT]) let direction if (fieldName === sortField) { @@ -180,7 +177,7 @@ class TableGraph extends Component { fieldName, direction, verticalTimeAxis, - fieldNames + fieldOptions ) this.setState({ @@ -226,22 +223,25 @@ class TableGraph extends Component { sortField, sortDirection, } = this.state - const {tableOptions, colors} = parent.props + const { + tableOptions, + fieldOptions = [TIME_FIELD_DEFAULT], + colors, + } = parent.props const { timeFormat = TIME_FORMAT_DEFAULT, verticalTimeAxis = VERTICAL_TIME_AXIS_DEFAULT, fixFirstColumn = FIX_FIRST_COLUMN_DEFAULT, - fieldNames = [TIME_FIELD_DEFAULT], } = tableOptions const cellData = processedData[rowIndex][columnIndex] - const timeFieldIndex = fieldNames.findIndex( + const timeFieldIndex = fieldOptions.findIndex( field => field.internalName === TIME_FIELD_DEFAULT.internalName ) - const visibleTime = _.get(fieldNames, [timeFieldIndex, 'visible'], true) + const visibleTime = _.get(fieldOptions, [timeFieldIndex, 'visible'], true) const isFixedRow = rowIndex === 0 && columnIndex > 0 const isFixedColumn = fixFirstColumn && rowIndex > 0 && columnIndex === 0 @@ -277,7 +277,7 @@ class TableGraph extends Component { } const foundField = - isFieldName && fieldNames.find(field => field.internalName === cellData) + isFieldName && fieldOptions.find(field => field.internalName === cellData) const fieldName = foundField && (foundField.displayName || foundField.internalName) @@ -394,7 +394,6 @@ class TableGraph extends Component { TableGraph.propTypes = { data: arrayOf(shape()), tableOptions: shape({ - timeFormat: string.isRequired, verticalTimeAxis: bool.isRequired, sortBy: shape({ internalName: string.isRequired, @@ -402,15 +401,16 @@ TableGraph.propTypes = { visible: bool.isRequired, }).isRequired, wrapping: string.isRequired, - fieldNames: arrayOf( - shape({ - internalName: string.isRequired, - displayName: string.isRequired, - visible: bool.isRequired, - }) - ).isRequired, fixFirstColumn: bool, }), + timeFormat: string.isRequired, + fieldOptions: arrayOf( + shape({ + internalName: string.isRequired, + displayName: string.isRequired, + visible: bool.isRequired, + }) + ).isRequired, hoverTime: string, handleSetHoverTime: func, colors: colorsStringSchema, diff --git a/ui/src/shared/constants/tableGraph.js b/ui/src/shared/constants/tableGraph.js index 04ba2ede50..52b19dfa28 100644 --- a/ui/src/shared/constants/tableGraph.js +++ b/ui/src/shared/constants/tableGraph.js @@ -36,9 +36,7 @@ export const FORMAT_OPTIONS = [ export const DEFAULT_TABLE_OPTIONS = { verticalTimeAxis: VERTICAL_TIME_AXIS_DEFAULT, - timeFormat: TIME_FORMAT_DEFAULT, sortBy: TIME_FIELD_DEFAULT, wrapping: 'truncate', - fieldNames: [TIME_FIELD_DEFAULT], fixFirstColumn: FIX_FIRST_COLUMN_DEFAULT, } diff --git a/ui/src/utils/timeSeriesTransformers.js b/ui/src/utils/timeSeriesTransformers.js index f1bebd87d0..28eb625da0 100644 --- a/ui/src/utils/timeSeriesTransformers.js +++ b/ui/src/utils/timeSeriesTransformers.js @@ -184,12 +184,14 @@ export const timeSeriesToTableGraph = raw => { } } -export const filterTableColumns = (data, fieldNames) => { +export const filterTableColumns = (data, fieldOptions) => { const visibility = {} const filteredData = map(data, (row, i) => { return filter(row, (col, j) => { if (i === 0) { - const foundField = fieldNames.find(field => field.internalName === col) + const foundField = fieldOptions.find( + field => field.internalName === col + ) visibility[j] = foundField ? foundField.visible : true } return visibility[j] @@ -198,8 +200,8 @@ export const filterTableColumns = (data, fieldNames) => { return filteredData[0].length ? filteredData : [[]] } -export const orderTableColumns = (data, fieldNames) => { - const fieldsSortOrder = fieldNames.map(fieldName => { +export const orderTableColumns = (data, fieldOptions) => { + const fieldsSortOrder = fieldOptions.map(fieldName => { return _.findIndex(data[0], dataLabel => { return dataLabel === fieldName.internalName }) @@ -216,7 +218,7 @@ export const processTableData = ( sortFieldName, direction, verticalTimeAxis, - fieldNames, + fieldOptions, timeFormat ) => { const sortIndex = _.indexOf(data[0], sortFieldName) @@ -225,12 +227,12 @@ export const processTableData = ( ..._.orderBy(_.drop(data, 1), sortIndex, [direction]), ] const sortedTimeVals = map(sortedData, r => r[0]) - const filteredData = filterTableColumns(sortedData, fieldNames) - const orderedData = orderTableColumns(filteredData, fieldNames) + const filteredData = filterTableColumns(sortedData, fieldOptions) + const orderedData = orderTableColumns(filteredData, fieldOptions) const processedData = verticalTimeAxis ? orderedData : _.unzip(orderedData) const {widths: columnWidths, totalWidths} = calculateColumnWidths( processedData, - fieldNames, + fieldOptions, timeFormat, verticalTimeAxis ) diff --git a/ui/test/dashboards/components/TableOptions.test.tsx b/ui/test/dashboards/components/TableOptions.test.tsx index e65fbe0310..1672cc1564 100644 --- a/ui/test/dashboards/components/TableOptions.test.tsx +++ b/ui/test/dashboards/components/TableOptions.test.tsx @@ -16,12 +16,12 @@ const defaultProps = { queryConfigs: [], tableOptions: { columnNames: [], - fieldNames: [], fixFirstColumn: true, sortBy: {displayName: '', internalName: '', visible: true}, - timeFormat: '', verticalTimeAxis: true, }, + fieldOptions: [], + timeFormat: '', } const setup = (override = {}) => { From a34085a4b1bf31e5416c178da958c52ca69f8a04 Mon Sep 17 00:00:00 2001 From: Iris Scholten Date: Fri, 20 Apr 2018 13:41:34 -0700 Subject: [PATCH 06/48] Update Swagger with fieldOptions and Timeformat change and precision --- server/swagger.json | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/server/swagger.json b/server/swagger.json index cc1f15706c..140ae39ca9 100644 --- a/server/swagger.json +++ b/server/swagger.json @@ -4653,11 +4653,6 @@ } }, "tableOptions": { - "timeFormat": { - "description": - "timeFormat describes the display format for time values according to moment.js date formatting", - "type": "string" - }, "verticalTimeAxis": { "description": "verticalTimeAxis describes the orientation of the table by indicating whether the time axis will be displayed vertically", @@ -4675,20 +4670,25 @@ "type": "string", "enum": ["truncate", "wrap", "single-line"] }, - "fieldNames": { - "description": - "fieldNames represent the fields retrieved by the query with customization options", - "type": "array", - "items": { - "$ref": "#/definitions/RenamableField" - } - }, "fixFirstColumn": { "description": "fixFirstColumn indicates whether the first column of the table should be locked", "type": "boolean" } }, + "fieldOptions": { + "description": + "fieldOptions represent the fields retrieved by the query with customization options", + "type": "array", + "items": { + "$ref": "#/definitions/RenamableField" + } + }, + "timeFormat": { + "description": + "timeFormat describes the display format for time values according to moment.js date formatting", + "type": "string" + }, "links": { "type": "object", "properties": { @@ -5025,6 +5025,11 @@ "description": "visible indicates whether this field should be visible on the table", "type": "boolean" + }, + "precision": { + "description": + "precision indicates how precise each number value should be", + "type": "integer" } } }, From edd8ea27da9b381aaedcf1414f594e71dfddb8e9 Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Tue, 24 Apr 2018 09:13:08 -0700 Subject: [PATCH 07/48] Change expressionID to bodyID --- ui/src/ifql/components/ExpressionNode.tsx | 4 ++-- ui/src/ifql/components/From.tsx | 6 +++--- ui/src/ifql/components/FuncArg.tsx | 10 +++++----- ui/src/ifql/components/FuncArgBool.tsx | 6 +++--- ui/src/ifql/components/FuncArgInput.tsx | 6 +++--- ui/src/ifql/components/FuncArgs.tsx | 6 +++--- ui/src/ifql/components/FuncNode.tsx | 10 +++++----- ui/src/ifql/components/FuncSelector.tsx | 4 ++-- ui/src/ifql/containers/IFQLPage.tsx | 15 ++++++--------- ui/src/types/ifql.ts | 6 +++--- ui/test/ifql/components/From.test.tsx | 2 +- ui/test/ifql/components/FuncArg.test.tsx | 2 +- ui/test/ifql/components/FuncSelector.test.tsx | 6 +++--- 13 files changed, 40 insertions(+), 43 deletions(-) diff --git a/ui/src/ifql/components/ExpressionNode.tsx b/ui/src/ifql/components/ExpressionNode.tsx index 5f6fabe916..16f559f1df 100644 --- a/ui/src/ifql/components/ExpressionNode.tsx +++ b/ui/src/ifql/components/ExpressionNode.tsx @@ -23,7 +23,7 @@ class ExpressionNode extends PureComponent {

@@ -32,7 +32,7 @@ class ExpressionNode extends PureComponent { { } private handleChooseDatabase = (item: DropdownItem): void => { - const {argKey, funcID, onChangeArg, expressionID} = this.props + const {argKey, funcID, onChangeArg, bodyID} = this.props onChangeArg({ funcID, key: argKey, value: item.text, - expressionID, + bodyID, generate: true, }) } diff --git a/ui/src/ifql/components/FuncArg.tsx b/ui/src/ifql/components/FuncArg.tsx index 091786a48a..18d57ab099 100644 --- a/ui/src/ifql/components/FuncArg.tsx +++ b/ui/src/ifql/components/FuncArg.tsx @@ -14,7 +14,7 @@ interface Props { argKey: string value: string | boolean type: string - expressionID: string + bodyID: string onChangeArg: OnChangeArg onGenerateScript: () => void } @@ -29,7 +29,7 @@ class FuncArg extends PureComponent { funcName, funcID, onChangeArg, - expressionID, + bodyID, onGenerateScript, } = this.props @@ -39,7 +39,7 @@ class FuncArg extends PureComponent { argKey={argKey} funcID={funcID} value={this.value} - expressionID={expressionID} + bodyID={bodyID} onChangeArg={onChangeArg} /> ) @@ -60,7 +60,7 @@ class FuncArg extends PureComponent { value={this.value} argKey={argKey} funcID={funcID} - expressionID={expressionID} + bodyID={bodyID} onChangeArg={onChangeArg} onGenerateScript={onGenerateScript} /> @@ -74,7 +74,7 @@ class FuncArg extends PureComponent { argKey={argKey} funcID={funcID} onChangeArg={onChangeArg} - expressionID={expressionID} + bodyID={bodyID} onGenerateScript={onGenerateScript} /> ) diff --git a/ui/src/ifql/components/FuncArgBool.tsx b/ui/src/ifql/components/FuncArgBool.tsx index a8ec37e8e0..0fe3fbd89b 100644 --- a/ui/src/ifql/components/FuncArgBool.tsx +++ b/ui/src/ifql/components/FuncArgBool.tsx @@ -7,7 +7,7 @@ interface Props { argKey: string value: boolean funcID: string - expressionID: string + bodyID: string onChangeArg: OnChangeArg onGenerateScript: () => void } @@ -23,8 +23,8 @@ class FuncArgBool extends PureComponent { } private handleToggle = (value: boolean): void => { - const {argKey, funcID, expressionID, onChangeArg} = this.props - onChangeArg({funcID, key: argKey, value, generate: true, expressionID}) + const {argKey, funcID, bodyID, onChangeArg} = this.props + onChangeArg({funcID, key: argKey, value, generate: true, bodyID}) } } diff --git a/ui/src/ifql/components/FuncArgInput.tsx b/ui/src/ifql/components/FuncArgInput.tsx index ea0070a80a..694b89b3d2 100644 --- a/ui/src/ifql/components/FuncArgInput.tsx +++ b/ui/src/ifql/components/FuncArgInput.tsx @@ -7,7 +7,7 @@ interface Props { argKey: string value: string type: string - expressionID: string + bodyID: string onChangeArg: OnChangeArg onGenerateScript: () => void } @@ -44,13 +44,13 @@ class FuncArgInput extends PureComponent { } private handleChange = (e: ChangeEvent) => { - const {funcID, argKey, expressionID} = this.props + const {funcID, argKey, bodyID} = this.props this.props.onChangeArg({ funcID, key: argKey, value: e.target.value, - expressionID, + bodyID, }) } } diff --git a/ui/src/ifql/components/FuncArgs.tsx b/ui/src/ifql/components/FuncArgs.tsx index c8be0ac3c9..910f3caa96 100644 --- a/ui/src/ifql/components/FuncArgs.tsx +++ b/ui/src/ifql/components/FuncArgs.tsx @@ -6,7 +6,7 @@ import {Func} from 'src/types/ifql' interface Props { func: Func - expressionID: string + bodyID: string onChangeArg: OnChangeArg onGenerateScript: () => void } @@ -14,7 +14,7 @@ interface Props { @ErrorHandling export default class FuncArgs extends PureComponent { public render() { - const {expressionID, func, onChangeArg, onGenerateScript} = this.props + const {bodyID, func, onChangeArg, onGenerateScript} = this.props return (
@@ -28,7 +28,7 @@ export default class FuncArgs extends PureComponent { funcID={func.id} funcName={func.name} onChangeArg={onChangeArg} - expressionID={expressionID} + bodyID={bodyID} onGenerateScript={onGenerateScript} /> ) diff --git a/ui/src/ifql/components/FuncNode.tsx b/ui/src/ifql/components/FuncNode.tsx index 7d83005cec..6bb8bbfcd2 100644 --- a/ui/src/ifql/components/FuncNode.tsx +++ b/ui/src/ifql/components/FuncNode.tsx @@ -5,8 +5,8 @@ import {ErrorHandling} from 'src/shared/decorators/errors' interface Props { func: Func - expressionID: string - onDelete: (funcID: string, expressionID: string) => void + bodyID: string + onDelete: (funcID: string, bodyID: string) => void onChangeArg: OnChangeArg onGenerateScript: () => void } @@ -25,7 +25,7 @@ export default class FuncNode extends PureComponent { } public render() { - const {expressionID, func, onChangeArg, onGenerateScript} = this.props + const {bodyID, func, onChangeArg, onGenerateScript} = this.props const {isOpen} = this.state return ( @@ -37,7 +37,7 @@ export default class FuncNode extends PureComponent { )} @@ -49,7 +49,7 @@ export default class FuncNode extends PureComponent { } private handleDelete = (): void => { - this.props.onDelete(this.props.func.id, this.props.expressionID) + this.props.onDelete(this.props.func.id, this.props.bodyID) } private handleClick = (e: MouseEvent): void => { diff --git a/ui/src/ifql/components/FuncSelector.tsx b/ui/src/ifql/components/FuncSelector.tsx index 8654f6ef1d..a3e2c2a821 100644 --- a/ui/src/ifql/components/FuncSelector.tsx +++ b/ui/src/ifql/components/FuncSelector.tsx @@ -14,7 +14,7 @@ interface State { interface Props { funcs: string[] - expressionID: string + bodyID: string onAddNode: OnAddNode } @@ -66,7 +66,7 @@ export class FuncSelector extends PureComponent { private handleAddNode = (name: string) => { this.handleCloseList() - this.props.onAddNode(name, this.props.expressionID) + this.props.onAddNode(name, this.props.bodyID) } private get availableFuncs() { diff --git a/ui/src/ifql/containers/IFQLPage.tsx b/ui/src/ifql/containers/IFQLPage.tsx index ba7008824b..49ed8e3a23 100644 --- a/ui/src/ifql/containers/IFQLPage.tsx +++ b/ui/src/ifql/containers/IFQLPage.tsx @@ -116,10 +116,10 @@ export class IFQLPage extends PureComponent { value, generate, funcID, - expressionID, + bodyID, }: InputArg): void => { const body = this.state.body.map(expression => { - if (expression.id !== expressionID) { + if (expression.id !== bodyID) { return expression } @@ -183,9 +183,9 @@ export class IFQLPage extends PureComponent { this.setState({script}) } - private handleAddNode = (name: string, expressionID: string): void => { + private handleAddNode = (name: string, bodyID: string): void => { const script = this.state.body.reduce((acc, expression) => { - if (expression.id === expressionID) { + if (expression.id === bodyID) { const {funcs} = expression return `${acc}${this.funcsToScript(funcs)}\n\t|> ${name}()\n\n` } @@ -196,14 +196,11 @@ export class IFQLPage extends PureComponent { this.getASTResponse(script) } - private handleDeleteFuncNode = ( - funcID: string, - expressionID: string - ): void => { + private handleDeleteFuncNode = (funcID: string, bodyID: string): void => { // TODO: export this and test functionality const script = this.state.body .map((expression, expressionIndex) => { - if (expression.id !== expressionID) { + if (expression.id !== bodyID) { return expression.source } diff --git a/ui/src/types/ifql.ts b/ui/src/types/ifql.ts index 4cf3326e85..e8b725bffd 100644 --- a/ui/src/types/ifql.ts +++ b/ui/src/types/ifql.ts @@ -1,7 +1,7 @@ // function definitions -export type OnDeleteFuncNode = (funcID: string, expressionID: string) => void +export type OnDeleteFuncNode = (funcID: string, bodyID: string) => void export type OnChangeArg = (inputArg: InputArg) => void -export type OnAddNode = (expressionID: string, funcName: string) => void +export type OnAddNode = (bodyID: string, funcName: string) => void export type OnGenerateScript = (script: string) => void export type OnChangeScript = (script: string) => void export type OnSubmitScript = () => void @@ -17,7 +17,7 @@ export interface Handlers { export interface InputArg { funcID: string - expressionID: string + bodyID: string key: string value: string | boolean generate?: boolean diff --git a/ui/test/ifql/components/From.test.tsx b/ui/test/ifql/components/From.test.tsx index 4a8adad3d9..41466f527e 100644 --- a/ui/test/ifql/components/From.test.tsx +++ b/ui/test/ifql/components/From.test.tsx @@ -9,7 +9,7 @@ const setup = () => { funcID: '1', argKey: 'db', value: 'db1', - expressionID: '2', + bodyID: '2', onChangeArg: () => {}, } diff --git a/ui/test/ifql/components/FuncArg.test.tsx b/ui/test/ifql/components/FuncArg.test.tsx index 98949f4a84..65d5a5367e 100644 --- a/ui/test/ifql/components/FuncArg.test.tsx +++ b/ui/test/ifql/components/FuncArg.test.tsx @@ -5,7 +5,7 @@ import FuncArg from 'src/ifql/components/FuncArg' const setup = () => { const props = { funcID: '', - expressionID: '', + bodyID: '', funcName: '', argKey: '', value: '', diff --git a/ui/test/ifql/components/FuncSelector.test.tsx b/ui/test/ifql/components/FuncSelector.test.tsx index 8218876099..1ec41d1273 100644 --- a/ui/test/ifql/components/FuncSelector.test.tsx +++ b/ui/test/ifql/components/FuncSelector.test.tsx @@ -8,7 +8,7 @@ import FuncList from 'src/ifql/components/FuncList' const setup = (override = {}) => { const props = { funcs: ['count', 'range'], - expressionID: '1', + bodyID: '1', onAddNode: () => {}, ...override, } @@ -133,7 +133,7 @@ describe('IFQL.Components.FuncsButton', () => { const onAddNode = jest.fn() const {wrapper, props} = setup({onAddNode}) const [, func2] = props.funcs - const {expressionID} = props + const {bodyID} = props const dropdownButton = wrapper.find('button') dropdownButton.simulate('click') @@ -148,7 +148,7 @@ describe('IFQL.Components.FuncsButton', () => { input.simulate('keyDown', {key: 'ArrowDown'}) input.simulate('keyDown', {key: 'Enter'}) - expect(onAddNode).toHaveBeenCalledWith(func2, expressionID) + expect(onAddNode).toHaveBeenCalledWith(func2, bodyID) }) }) }) From 1b80d2a2ff96f2c8adac8087b21eae42361e536c Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Tue, 24 Apr 2018 09:33:32 -0700 Subject: [PATCH 08/48] Use correct ID in funcNode --- ui/src/ifql/components/BodyBuilder.tsx | 8 ++++---- ui/src/ifql/components/ExpressionNode.tsx | 8 ++++---- ui/src/ifql/components/FuncArgs.tsx | 2 +- ui/src/ifql/components/FuncNode.tsx | 2 +- ui/src/ifql/containers/IFQLPage.tsx | 10 +++++----- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/ui/src/ifql/components/BodyBuilder.tsx b/ui/src/ifql/components/BodyBuilder.tsx index b1602438e7..0acd7e308c 100644 --- a/ui/src/ifql/components/BodyBuilder.tsx +++ b/ui/src/ifql/components/BodyBuilder.tsx @@ -22,8 +22,8 @@ class BodyBuilder extends PureComponent { if (d.funcs) { return ( @@ -36,10 +36,10 @@ class BodyBuilder extends PureComponent { return ( ) }) diff --git a/ui/src/ifql/components/ExpressionNode.tsx b/ui/src/ifql/components/ExpressionNode.tsx index 16f559f1df..a76f0c7e38 100644 --- a/ui/src/ifql/components/ExpressionNode.tsx +++ b/ui/src/ifql/components/ExpressionNode.tsx @@ -8,14 +8,14 @@ import {Func} from 'src/types/ifql' interface Props { funcNames: any[] - id: string + bodyID: string funcs: Func[] } // an Expression is a group of one or more functions class ExpressionNode extends PureComponent { public render() { - const {id, funcNames, funcs} = this.props + const {bodyID, funcNames, funcs} = this.props return ( {({onDeleteFuncNode, onAddNode, onChangeArg, onGenerateScript}) => { @@ -23,7 +23,7 @@ class ExpressionNode extends PureComponent {

@@ -32,7 +32,7 @@ class ExpressionNode extends PureComponent { { type={type} argKey={key} value={value} + bodyID={bodyID} funcID={func.id} funcName={func.name} onChangeArg={onChangeArg} - bodyID={bodyID} onGenerateScript={onGenerateScript} /> ) diff --git a/ui/src/ifql/components/FuncNode.tsx b/ui/src/ifql/components/FuncNode.tsx index 6bb8bbfcd2..47f049f6e6 100644 --- a/ui/src/ifql/components/FuncNode.tsx +++ b/ui/src/ifql/components/FuncNode.tsx @@ -36,8 +36,8 @@ export default class FuncNode extends PureComponent { {isOpen && ( )} diff --git a/ui/src/ifql/containers/IFQLPage.tsx b/ui/src/ifql/containers/IFQLPage.tsx index 49ed8e3a23..662e48d7d7 100644 --- a/ui/src/ifql/containers/IFQLPage.tsx +++ b/ui/src/ifql/containers/IFQLPage.tsx @@ -199,12 +199,12 @@ export class IFQLPage extends PureComponent { private handleDeleteFuncNode = (funcID: string, bodyID: string): void => { // TODO: export this and test functionality const script = this.state.body - .map((expression, expressionIndex) => { - if (expression.id !== bodyID) { - return expression.source + .map((body, bodyIndex) => { + if (body.id !== bodyID) { + return body.source } - const funcs = expression.funcs.filter(f => f.id !== funcID) + const funcs = body.funcs.filter(f => f.id !== funcID) const source = funcs.reduce((acc, f, i) => { if (i === 0) { return `${f.source}` @@ -213,7 +213,7 @@ export class IFQLPage extends PureComponent { return `${acc}\n\t${f.source}` }, '') - const isLast = expressionIndex === this.state.body.length - 1 + const isLast = bodyIndex === this.state.body.length - 1 if (isLast) { return `${source}` } From 29fe9d1119d3cbc772a96fa3b46a381b02f4e42d Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Tue, 24 Apr 2018 10:54:17 -0700 Subject: [PATCH 09/48] Fix delete to work with variable declarations --- ui/src/ifql/components/BodyBuilder.tsx | 3 +- ui/src/ifql/components/ExpressionNode.tsx | 4 +- ui/src/ifql/components/FuncNode.tsx | 13 ++++-- ui/src/ifql/containers/IFQLPage.tsx | 53 +++++++++++++++++------ ui/src/types/ifql.ts | 8 +++- 5 files changed, 61 insertions(+), 20 deletions(-) diff --git a/ui/src/ifql/components/BodyBuilder.tsx b/ui/src/ifql/components/BodyBuilder.tsx index 0acd7e308c..a6d8d6f647 100644 --- a/ui/src/ifql/components/BodyBuilder.tsx +++ b/ui/src/ifql/components/BodyBuilder.tsx @@ -22,8 +22,9 @@ class BodyBuilder extends PureComponent { if (d.funcs) { return ( diff --git a/ui/src/ifql/components/ExpressionNode.tsx b/ui/src/ifql/components/ExpressionNode.tsx index a76f0c7e38..2b57b2cfd4 100644 --- a/ui/src/ifql/components/ExpressionNode.tsx +++ b/ui/src/ifql/components/ExpressionNode.tsx @@ -10,12 +10,13 @@ interface Props { funcNames: any[] bodyID: string funcs: Func[] + declarationID?: string } // an Expression is a group of one or more functions class ExpressionNode extends PureComponent { public render() { - const {bodyID, funcNames, funcs} = this.props + const {declarationID, bodyID, funcNames, funcs} = this.props return ( {({onDeleteFuncNode, onAddNode, onChangeArg, onGenerateScript}) => { @@ -35,6 +36,7 @@ class ExpressionNode extends PureComponent { bodyID={bodyID} onChangeArg={onChangeArg} onDelete={onDeleteFuncNode} + declarationID={declarationID} onGenerateScript={onGenerateScript} /> ))} diff --git a/ui/src/ifql/components/FuncNode.tsx b/ui/src/ifql/components/FuncNode.tsx index 47f049f6e6..a8c52f78a5 100644 --- a/ui/src/ifql/components/FuncNode.tsx +++ b/ui/src/ifql/components/FuncNode.tsx @@ -1,12 +1,13 @@ import React, {PureComponent, MouseEvent} from 'react' import FuncArgs from 'src/ifql/components/FuncArgs' -import {OnChangeArg, Func} from 'src/types/ifql' +import {OnDeleteFuncNode, OnChangeArg, Func} from 'src/types/ifql' import {ErrorHandling} from 'src/shared/decorators/errors' interface Props { func: Func bodyID: string - onDelete: (funcID: string, bodyID: string) => void + declarationID?: string + onDelete: OnDeleteFuncNode onChangeArg: OnChangeArg onGenerateScript: () => void } @@ -17,6 +18,10 @@ interface State { @ErrorHandling export default class FuncNode extends PureComponent { + public static defaultProps: Partial = { + declarationID: '', + } + constructor(props) { super(props) this.state = { @@ -49,7 +54,9 @@ export default class FuncNode extends PureComponent { } private handleDelete = (): void => { - this.props.onDelete(this.props.func.id, this.props.bodyID) + const {func, bodyID, declarationID} = this.props + + this.props.onDelete({funcID: func.id, bodyID, declarationID}) } private handleClick = (e: MouseEvent): void => { diff --git a/ui/src/ifql/containers/IFQLPage.tsx b/ui/src/ifql/containers/IFQLPage.tsx index 662e48d7d7..2b970f6100 100644 --- a/ui/src/ifql/containers/IFQLPage.tsx +++ b/ui/src/ifql/containers/IFQLPage.tsx @@ -5,7 +5,7 @@ import {connect} from 'react-redux' import TimeMachine from 'src/ifql/components/TimeMachine' import KeyboardShortcuts from 'src/shared/components/KeyboardShortcuts' import {Suggestion, FlatBody} from 'src/types/ifql' -import {InputArg, Handlers} from 'src/types/ifql' +import {InputArg, Handlers, DeleteFuncNodeArgs} from 'src/types/ifql' import {bodyNodes} from 'src/ifql/helpers' import {getSuggestions, getAST} from 'src/ifql/apis' @@ -196,35 +196,60 @@ export class IFQLPage extends PureComponent { this.getASTResponse(script) } - private handleDeleteFuncNode = (funcID: string, bodyID: string): void => { - // TODO: export this and test functionality + private handleDeleteFuncNode = (ids: DeleteFuncNodeArgs): void => { + const {funcID, declarationID = '', bodyID} = ids + const script = this.state.body .map((body, bodyIndex) => { if (body.id !== bodyID) { return body.source } - const funcs = body.funcs.filter(f => f.id !== funcID) - const source = funcs.reduce((acc, f, i) => { - if (i === 0) { - return `${f.source}` + const isLast = bodyIndex === this.state.body.length - 1 + + if (declarationID) { + const declaration = body.declarations.find( + d => d.id === declarationID + ) + + if (!declaration) { + return } - return `${acc}\n\t${f.source}` - }, '') - - const isLast = bodyIndex === this.state.body.length - 1 - if (isLast) { - return `${source}` + const functions = declaration.funcs.filter(f => f.id !== funcID) + const s = this.funcsToSource(functions) + return `${declaration.name} = ${this.parseLastSource(s, isLast)}` } - return `${source}\n\n` + const funcs = body.funcs.filter(f => f.id !== funcID) + const source = this.funcsToSource(funcs) + return this.parseLastSource(source, isLast) }) .join('') this.getASTResponse(script) } + // formats the last line of a body string to include two new lines + private parseLastSource = (source: string, isLast: boolean): string => { + if (isLast) { + return `${source}` + } + + return `${source}\n\n` + } + + // funcsToSource takes a list of funtion nodes and returns an ifql script + private funcsToSource = (funcs): string => { + return funcs.reduce((acc, f, i) => { + if (i === 0) { + return `${f.source}` + } + + return `${acc}\n\t${f.source}` + }, '') + } + private getASTResponse = async (script: string) => { const {links} = this.props diff --git a/ui/src/types/ifql.ts b/ui/src/types/ifql.ts index e8b725bffd..289609efeb 100644 --- a/ui/src/types/ifql.ts +++ b/ui/src/types/ifql.ts @@ -1,5 +1,5 @@ // function definitions -export type OnDeleteFuncNode = (funcID: string, bodyID: string) => void +export type OnDeleteFuncNode = (ids: DeleteFuncNodeArgs) => void export type OnChangeArg = (inputArg: InputArg) => void export type OnAddNode = (bodyID: string, funcName: string) => void export type OnGenerateScript = (script: string) => void @@ -15,6 +15,12 @@ export interface Handlers { onGenerateScript: OnGenerateScript } +export interface DeleteFuncNodeArgs { + funcID: string + bodyID: string + declarationID?: string +} + export interface InputArg { funcID: string bodyID: string From 57fa9e1c1630d53750605730f3f6500c930156e6 Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Tue, 24 Apr 2018 13:36:59 -0700 Subject: [PATCH 10/48] Fix function argument editing --- ui/src/ifql/components/FuncArg.tsx | 11 ++-- ui/src/ifql/components/FuncArgInput.tsx | 4 +- ui/src/ifql/components/FuncArgs.tsx | 10 ++- ui/src/ifql/components/FuncNode.tsx | 9 ++- ui/src/ifql/containers/IFQLPage.tsx | 81 +++++++++++++++++------- ui/src/types/ifql.ts | 1 + ui/test/ifql/components/FuncArg.test.tsx | 1 + 7 files changed, 87 insertions(+), 30 deletions(-) diff --git a/ui/src/ifql/components/FuncArg.tsx b/ui/src/ifql/components/FuncArg.tsx index 18d57ab099..389f199946 100644 --- a/ui/src/ifql/components/FuncArg.tsx +++ b/ui/src/ifql/components/FuncArg.tsx @@ -15,6 +15,7 @@ interface Props { value: string | boolean type: string bodyID: string + declarationID: string onChangeArg: OnChangeArg onGenerateScript: () => void } @@ -26,10 +27,11 @@ class FuncArg extends PureComponent { argKey, value, type, - funcName, - funcID, - onChangeArg, bodyID, + funcID, + funcName, + onChangeArg, + declarationID, onGenerateScript, } = this.props @@ -62,6 +64,7 @@ class FuncArg extends PureComponent { funcID={funcID} bodyID={bodyID} onChangeArg={onChangeArg} + declarationID={declarationID} onGenerateScript={onGenerateScript} /> ) @@ -72,9 +75,9 @@ class FuncArg extends PureComponent { ) diff --git a/ui/src/ifql/components/FuncArgInput.tsx b/ui/src/ifql/components/FuncArgInput.tsx index 694b89b3d2..644e8f316e 100644 --- a/ui/src/ifql/components/FuncArgInput.tsx +++ b/ui/src/ifql/components/FuncArgInput.tsx @@ -8,6 +8,7 @@ interface Props { value: string type: string bodyID: string + declarationID: string onChangeArg: OnChangeArg onGenerateScript: () => void } @@ -44,12 +45,13 @@ class FuncArgInput extends PureComponent { } private handleChange = (e: ChangeEvent) => { - const {funcID, argKey, bodyID} = this.props + const {funcID, argKey, bodyID, declarationID} = this.props this.props.onChangeArg({ funcID, key: argKey, value: e.target.value, + declarationID, bodyID, }) } diff --git a/ui/src/ifql/components/FuncArgs.tsx b/ui/src/ifql/components/FuncArgs.tsx index 4a33df9c94..10c75d4cf1 100644 --- a/ui/src/ifql/components/FuncArgs.tsx +++ b/ui/src/ifql/components/FuncArgs.tsx @@ -8,13 +8,20 @@ interface Props { func: Func bodyID: string onChangeArg: OnChangeArg + declarationID: string onGenerateScript: () => void } @ErrorHandling export default class FuncArgs extends PureComponent { public render() { - const {bodyID, func, onChangeArg, onGenerateScript} = this.props + const { + func, + bodyID, + onChangeArg, + declarationID, + onGenerateScript, + } = this.props return (
@@ -29,6 +36,7 @@ export default class FuncArgs extends PureComponent { funcID={func.id} funcName={func.name} onChangeArg={onChangeArg} + declarationID={declarationID} onGenerateScript={onGenerateScript} /> ) diff --git a/ui/src/ifql/components/FuncNode.tsx b/ui/src/ifql/components/FuncNode.tsx index a8c52f78a5..343f6bd1bf 100644 --- a/ui/src/ifql/components/FuncNode.tsx +++ b/ui/src/ifql/components/FuncNode.tsx @@ -30,7 +30,13 @@ export default class FuncNode extends PureComponent { } public render() { - const {bodyID, func, onChangeArg, onGenerateScript} = this.props + const { + func, + bodyID, + onChangeArg, + declarationID, + onGenerateScript, + } = this.props const {isOpen} = this.state return ( @@ -43,6 +49,7 @@ export default class FuncNode extends PureComponent { func={func} bodyID={bodyID} onChangeArg={onChangeArg} + declarationID={declarationID} onGenerateScript={onGenerateScript} /> )} diff --git a/ui/src/ifql/containers/IFQLPage.tsx b/ui/src/ifql/containers/IFQLPage.tsx index 2b970f6100..f4b95b3abb 100644 --- a/ui/src/ifql/containers/IFQLPage.tsx +++ b/ui/src/ifql/containers/IFQLPage.tsx @@ -1,11 +1,12 @@ import React, {PureComponent} from 'react' import {connect} from 'react-redux' +import _ from 'lodash' import TimeMachine from 'src/ifql/components/TimeMachine' import KeyboardShortcuts from 'src/shared/components/KeyboardShortcuts' import {Suggestion, FlatBody} from 'src/types/ifql' -import {InputArg, Handlers, DeleteFuncNodeArgs} from 'src/types/ifql' +import {InputArg, Handlers, DeleteFuncNodeArgs, Func} from 'src/types/ifql' import {bodyNodes} from 'src/ifql/helpers' import {getSuggestions, getAST} from 'src/ifql/apis' @@ -108,7 +109,7 @@ export class IFQLPage extends PureComponent { } private handleGenerateScript = (): void => { - this.getASTResponse(this.expressionsToScript) + this.getASTResponse(this.bodyToScript) } private handleChangeArg = ({ @@ -116,30 +117,41 @@ export class IFQLPage extends PureComponent { value, generate, funcID, + declarationID = '', bodyID, }: InputArg): void => { - const body = this.state.body.map(expression => { - if (expression.id !== bodyID) { - return expression + const body = this.state.body.map(b => { + if (b.id !== bodyID) { + return b } - const funcs = expression.funcs.map(f => { - if (f.id !== funcID) { - return f - } - - const args = f.args.map(a => { - if (a.key === key) { - return {...a, value} + if (declarationID) { + const declarations = b.declarations.map(d => { + if (d.id !== declarationID) { + return d } - return a + const functions = this.editFuncArgs({ + funcs: d.funcs, + funcID, + key, + value, + }) + + return {...d, funcs: functions} }) - return {...f, args} + return {...b, declarations} + } + + const funcs = this.editFuncArgs({ + funcs: b.funcs, + funcID, + key, + value, }) - return {...expression, funcs} + return {...b, funcs} }) this.setState({body}, () => { @@ -149,9 +161,32 @@ export class IFQLPage extends PureComponent { }) } - private get expressionsToScript(): string { - return this.state.body.reduce((acc, expression) => { - return `${acc + this.funcsToScript(expression.funcs)}\n\n` + private editFuncArgs = ({funcs, funcID, key, value}): Func[] => { + return funcs.map(f => { + if (f.id !== funcID) { + return f + } + + const args = f.args.map(a => { + if (a.key === key) { + return {...a, value} + } + + return a + }) + + return {...f, args} + }) + } + + private get bodyToScript(): string { + return this.state.body.reduce((acc, b) => { + if (b.declarations.length) { + const funcs = _.get(b, 'declarations.0.funcs', []) + return `${acc}${this.funcsToScript(funcs)}\n\n` + } + + return `${acc}${this.funcsToScript(b.funcs)}\n\n` }, '') } @@ -184,13 +219,13 @@ export class IFQLPage extends PureComponent { } private handleAddNode = (name: string, bodyID: string): void => { - const script = this.state.body.reduce((acc, expression) => { - if (expression.id === bodyID) { - const {funcs} = expression + const script = this.state.body.reduce((acc, body) => { + if (body.id === bodyID) { + const {funcs} = body return `${acc}${this.funcsToScript(funcs)}\n\t|> ${name}()\n\n` } - return acc + expression.source + return acc + body.source }, '') this.getASTResponse(script) diff --git a/ui/src/types/ifql.ts b/ui/src/types/ifql.ts index 289609efeb..2f5b8eb462 100644 --- a/ui/src/types/ifql.ts +++ b/ui/src/types/ifql.ts @@ -24,6 +24,7 @@ export interface DeleteFuncNodeArgs { export interface InputArg { funcID: string bodyID: string + declarationID?: string key: string value: string | boolean generate?: boolean diff --git a/ui/test/ifql/components/FuncArg.test.tsx b/ui/test/ifql/components/FuncArg.test.tsx index 65d5a5367e..7dabb0cc2a 100644 --- a/ui/test/ifql/components/FuncArg.test.tsx +++ b/ui/test/ifql/components/FuncArg.test.tsx @@ -7,6 +7,7 @@ const setup = () => { funcID: '', bodyID: '', funcName: '', + declarationID: '', argKey: '', value: '', type: '', From 80495027edd87839d5cc5abe4bce4bd6a69cfa7c Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Tue, 24 Apr 2018 14:34:42 -0700 Subject: [PATCH 11/48] Repair adding a func node --- ui/src/ifql/components/ExpressionNode.tsx | 1 + ui/src/ifql/components/FuncSelector.tsx | 4 ++- ui/src/ifql/containers/IFQLPage.tsx | 25 +++++++++++++++---- ui/src/types/ifql.ts | 6 ++++- ui/test/ifql/components/FuncSelector.test.tsx | 5 ++-- 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/ui/src/ifql/components/ExpressionNode.tsx b/ui/src/ifql/components/ExpressionNode.tsx index 2b57b2cfd4..c945acc3b7 100644 --- a/ui/src/ifql/components/ExpressionNode.tsx +++ b/ui/src/ifql/components/ExpressionNode.tsx @@ -27,6 +27,7 @@ class ExpressionNode extends PureComponent { bodyID={bodyID} funcs={funcNames} onAddNode={onAddNode} + declarationID={declarationID} />

{funcs.map(func => ( diff --git a/ui/src/ifql/components/FuncSelector.tsx b/ui/src/ifql/components/FuncSelector.tsx index a3e2c2a821..6e2fdae10e 100644 --- a/ui/src/ifql/components/FuncSelector.tsx +++ b/ui/src/ifql/components/FuncSelector.tsx @@ -15,6 +15,7 @@ interface State { interface Props { funcs: string[] bodyID: string + declarationID: string onAddNode: OnAddNode } @@ -65,8 +66,9 @@ export class FuncSelector extends PureComponent { } private handleAddNode = (name: string) => { + const {bodyID, declarationID} = this.props this.handleCloseList() - this.props.onAddNode(name, this.props.bodyID) + this.props.onAddNode(name, bodyID, declarationID) } private get availableFuncs() { diff --git a/ui/src/ifql/containers/IFQLPage.tsx b/ui/src/ifql/containers/IFQLPage.tsx index f4b95b3abb..cf0fcfd3cf 100644 --- a/ui/src/ifql/containers/IFQLPage.tsx +++ b/ui/src/ifql/containers/IFQLPage.tsx @@ -45,7 +45,7 @@ export class IFQLPage extends PureComponent { ast: null, suggestions: [], script: - 'foo = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\nfrom(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\n', + 'foo = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\nbar = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\n', } } @@ -218,19 +218,34 @@ export class IFQLPage extends PureComponent { this.setState({script}) } - private handleAddNode = (name: string, bodyID: string): void => { + private handleAddNode = ( + name: string, + bodyID: string, + declarationID: string + ): void => { const script = this.state.body.reduce((acc, body) => { if (body.id === bodyID) { - const {funcs} = body - return `${acc}${this.funcsToScript(funcs)}\n\t|> ${name}()\n\n` + const declaration = body.declarations.find(d => d.id === declarationID) + if (declaration) { + return `${acc}${declaration.name} = ${this.appendFunc( + declaration.funcs, + name + )}` + } + + return `${acc}${this.appendFunc(body.funcs, name)}` } - return acc + body.source + return `${acc}${body.source}` }, '') this.getASTResponse(script) } + private appendFunc = (funcs, name): string => { + return `${this.funcsToScript(funcs)}\n\t|> ${name}()\n\n` + } + private handleDeleteFuncNode = (ids: DeleteFuncNodeArgs): void => { const {funcID, declarationID = '', bodyID} = ids diff --git a/ui/src/types/ifql.ts b/ui/src/types/ifql.ts index 2f5b8eb462..65bd406f93 100644 --- a/ui/src/types/ifql.ts +++ b/ui/src/types/ifql.ts @@ -1,7 +1,11 @@ // function definitions export type OnDeleteFuncNode = (ids: DeleteFuncNodeArgs) => void export type OnChangeArg = (inputArg: InputArg) => void -export type OnAddNode = (bodyID: string, funcName: string) => void +export type OnAddNode = ( + bodyID: string, + funcName: string, + declarationID: string +) => void export type OnGenerateScript = (script: string) => void export type OnChangeScript = (script: string) => void export type OnSubmitScript = () => void diff --git a/ui/test/ifql/components/FuncSelector.test.tsx b/ui/test/ifql/components/FuncSelector.test.tsx index 1ec41d1273..e4dfa27b10 100644 --- a/ui/test/ifql/components/FuncSelector.test.tsx +++ b/ui/test/ifql/components/FuncSelector.test.tsx @@ -9,6 +9,7 @@ const setup = (override = {}) => { const props = { funcs: ['count', 'range'], bodyID: '1', + declarationID: '2', onAddNode: () => {}, ...override, } @@ -133,7 +134,7 @@ describe('IFQL.Components.FuncsButton', () => { const onAddNode = jest.fn() const {wrapper, props} = setup({onAddNode}) const [, func2] = props.funcs - const {bodyID} = props + const {bodyID, declarationID} = props const dropdownButton = wrapper.find('button') dropdownButton.simulate('click') @@ -148,7 +149,7 @@ describe('IFQL.Components.FuncsButton', () => { input.simulate('keyDown', {key: 'ArrowDown'}) input.simulate('keyDown', {key: 'Enter'}) - expect(onAddNode).toHaveBeenCalledWith(func2, bodyID) + expect(onAddNode).toHaveBeenCalledWith(func2, bodyID, declarationID) }) }) }) From 6d5924adb7673fcd6f18af2b68fe4e394d6bc491 Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Tue, 24 Apr 2018 14:49:44 -0700 Subject: [PATCH 12/48] Fix FROM db dropdown --- ui/src/ifql/components/From.tsx | 4 +++- ui/src/ifql/components/FuncArg.tsx | 1 + ui/src/ifql/containers/IFQLPage.tsx | 10 ++++++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/ui/src/ifql/components/From.tsx b/ui/src/ifql/components/From.tsx index e8c8980e7a..4ecdf9b73b 100644 --- a/ui/src/ifql/components/From.tsx +++ b/ui/src/ifql/components/From.tsx @@ -10,6 +10,7 @@ interface Props { argKey: string value: string bodyID: string + declarationID: string onChangeArg: OnChangeArg } @@ -56,12 +57,13 @@ class From extends PureComponent { } private handleChooseDatabase = (item: DropdownItem): void => { - const {argKey, funcID, onChangeArg, bodyID} = this.props + const {argKey, funcID, onChangeArg, bodyID, declarationID} = this.props onChangeArg({ funcID, key: argKey, value: item.text, bodyID, + declarationID, generate: true, }) } diff --git a/ui/src/ifql/components/FuncArg.tsx b/ui/src/ifql/components/FuncArg.tsx index 389f199946..26427592ad 100644 --- a/ui/src/ifql/components/FuncArg.tsx +++ b/ui/src/ifql/components/FuncArg.tsx @@ -42,6 +42,7 @@ class FuncArg extends PureComponent { funcID={funcID} value={this.value} bodyID={bodyID} + declarationID={declarationID} onChangeArg={onChangeArg} /> ) diff --git a/ui/src/ifql/containers/IFQLPage.tsx b/ui/src/ifql/containers/IFQLPage.tsx index cf0fcfd3cf..1ccf4289ca 100644 --- a/ui/src/ifql/containers/IFQLPage.tsx +++ b/ui/src/ifql/containers/IFQLPage.tsx @@ -182,8 +182,14 @@ export class IFQLPage extends PureComponent { private get bodyToScript(): string { return this.state.body.reduce((acc, b) => { if (b.declarations.length) { - const funcs = _.get(b, 'declarations.0.funcs', []) - return `${acc}${this.funcsToScript(funcs)}\n\n` + const declaration = _.get(b, 'declarations.0', false) + if (!declaration) { + return acc + } + + return `${acc}${declaration.name} = ${this.funcsToScript( + declaration.funcs + )}\n\n` } return `${acc}${this.funcsToScript(b.funcs)}\n\n` From 996c143536928f9c2fb1bdcaced2a068cf3b656e Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Tue, 24 Apr 2018 14:51:38 -0700 Subject: [PATCH 13/48] Fix boolean arg --- ui/src/ifql/components/FuncArg.tsx | 1 + ui/src/ifql/components/FuncArgBool.tsx | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ui/src/ifql/components/FuncArg.tsx b/ui/src/ifql/components/FuncArg.tsx index 26427592ad..03ef847486 100644 --- a/ui/src/ifql/components/FuncArg.tsx +++ b/ui/src/ifql/components/FuncArg.tsx @@ -79,6 +79,7 @@ class FuncArg extends PureComponent { bodyID={bodyID} funcID={funcID} onChangeArg={onChangeArg} + declarationID={declarationID} onGenerateScript={onGenerateScript} /> ) diff --git a/ui/src/ifql/components/FuncArgBool.tsx b/ui/src/ifql/components/FuncArgBool.tsx index 0fe3fbd89b..e87b0f8dcd 100644 --- a/ui/src/ifql/components/FuncArgBool.tsx +++ b/ui/src/ifql/components/FuncArgBool.tsx @@ -8,6 +8,7 @@ interface Props { value: boolean funcID: string bodyID: string + declarationID: string onChangeArg: OnChangeArg onGenerateScript: () => void } @@ -23,8 +24,15 @@ class FuncArgBool extends PureComponent { } private handleToggle = (value: boolean): void => { - const {argKey, funcID, bodyID, onChangeArg} = this.props - onChangeArg({funcID, key: argKey, value, generate: true, bodyID}) + const {argKey, funcID, bodyID, onChangeArg, declarationID} = this.props + onChangeArg({ + key: argKey, + value, + funcID, + bodyID, + declarationID, + generate: true, + }) } } From eaa3ef4623be01c3422731f1c33c7170cddab66f Mon Sep 17 00:00:00 2001 From: Brandon Farmer Date: Tue, 24 Apr 2018 14:52:12 -0700 Subject: [PATCH 14/48] Add custom error handling for line graphs --- .../data_explorer/containers/DataExplorer.tsx | 10 ---------- ui/src/shared/components/InvalidData.tsx | 17 +++++++++++++++++ ui/src/shared/components/LineGraph.js | 5 +++-- 3 files changed, 20 insertions(+), 12 deletions(-) create mode 100644 ui/src/shared/components/InvalidData.tsx diff --git a/ui/src/data_explorer/containers/DataExplorer.tsx b/ui/src/data_explorer/containers/DataExplorer.tsx index 57ae430f96..9b6e59d026 100644 --- a/ui/src/data_explorer/containers/DataExplorer.tsx +++ b/ui/src/data_explorer/containers/DataExplorer.tsx @@ -1,5 +1,4 @@ import React, {PureComponent} from 'react' -import PropTypes from 'prop-types' import {connect} from 'react-redux' import {bindActionCreators} from 'redux' import {withRouter, InjectedRouter} from 'react-router' @@ -52,15 +51,6 @@ interface State { @ErrorHandling export class DataExplorer extends PureComponent { - public static childContextTypes = { - source: PropTypes.shape({ - links: PropTypes.shape({ - proxy: PropTypes.string.isRequired, - self: PropTypes.string.isRequired, - }).isRequired, - }).isRequired, - } - constructor(props) { super(props) diff --git a/ui/src/shared/components/InvalidData.tsx b/ui/src/shared/components/InvalidData.tsx new file mode 100644 index 0000000000..52174b8136 --- /dev/null +++ b/ui/src/shared/components/InvalidData.tsx @@ -0,0 +1,17 @@ +import React, {PureComponent} from 'react' + +class InvalidData extends PureComponent<{}> { + public render() { + return ( +

+ The data returned from the query can't be visualized with this graph + type. Try updating the query or selecting a different graph type. +

+ ) + } +} + +export default InvalidData diff --git a/ui/src/shared/components/LineGraph.js b/ui/src/shared/components/LineGraph.js index f64411e6db..6d74de4313 100644 --- a/ui/src/shared/components/LineGraph.js +++ b/ui/src/shared/components/LineGraph.js @@ -6,9 +6,10 @@ import SingleStat from 'src/shared/components/SingleStat' import {timeSeriesToDygraph} from 'utils/timeSeriesTransformers' import {colorsStringSchema} from 'shared/schemas' -import {ErrorHandling} from 'src/shared/decorators/errors' +import {ErrorHandlingWith} from 'src/shared/decorators/errors' +import InvalidData from 'src/shared/components/InvalidData' -@ErrorHandling +@ErrorHandlingWith(InvalidData, true) class LineGraph extends Component { constructor(props) { super(props) From f7457f7753f0ef6bc071f4cb2ae06ddc5a257e56 Mon Sep 17 00:00:00 2001 From: Brandon Farmer Date: Tue, 24 Apr 2018 15:00:08 -0700 Subject: [PATCH 15/48] Remove error handling debug flag --- ui/src/shared/components/LineGraph.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/shared/components/LineGraph.js b/ui/src/shared/components/LineGraph.js index 6d74de4313..d2cb421199 100644 --- a/ui/src/shared/components/LineGraph.js +++ b/ui/src/shared/components/LineGraph.js @@ -9,7 +9,7 @@ import {colorsStringSchema} from 'shared/schemas' import {ErrorHandlingWith} from 'src/shared/decorators/errors' import InvalidData from 'src/shared/components/InvalidData' -@ErrorHandlingWith(InvalidData, true) +@ErrorHandlingWith(InvalidData) class LineGraph extends Component { constructor(props) { super(props) From 2a2a315e4662c92fd2e8ff91f7a63c2f6b2a58df Mon Sep 17 00:00:00 2001 From: ebb-tide Date: Tue, 24 Apr 2018 15:02:09 -0700 Subject: [PATCH 16/48] replace sortField and sortDirection everywhere --- ui/src/shared/components/TableGraph.js | 36 ++++++++++---------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/ui/src/shared/components/TableGraph.js b/ui/src/shared/components/TableGraph.js index 02e972c29a..b2c745a293 100644 --- a/ui/src/shared/components/TableGraph.js +++ b/ui/src/shared/components/TableGraph.js @@ -186,34 +186,29 @@ class TableGraph extends Component { } } - handleClickFieldName = fieldName => () => { + handleClickFieldName = clickedFieldName => () => { const {tableOptions} = this.props - const {timeFormat} = tableOptions - const {data, sortField, sortDirection} = this.state - const verticalTimeAxis = _.get(tableOptions, 'verticalTimeAxis', true) + const {data, sort} = this.state const fieldNames = _.get(tableOptions, 'fieldNames', [TIME_FIELD_DEFAULT]) - let direction - if (fieldName === sortField) { - direction = sortDirection === ASCENDING ? DESCENDING : ASCENDING + if (clickedFieldName === sort.field) { + sort.direction = sort.direction === ASCENDING ? DESCENDING : ASCENDING } else { - direction = DEFAULT_SORT_DIRECTION + sort.field = clickedFieldName + sort.direction = DEFAULT_SORT_DIRECTION } const {transformedData, sortedTimeVals} = transformTableData( data, - fieldName, - direction, - verticalTimeAxis, + sort, fieldNames, - timeFormat + tableOptions ) this.setState({ transformedData, sortedTimeVals, - sortField: fieldName, - sortDirection: direction, + sort, }) } @@ -251,8 +246,7 @@ class TableGraph extends Component { hoveredColumnIndex, hoveredRowIndex, transformedData, - sortField, - sortDirection, + sort, } = this.state const {tableOptions, colors} = parent.props @@ -318,9 +312,9 @@ class TableGraph extends Component { 'table-graph-cell__numerical': dataIsNumerical, 'table-graph-cell__field-name': isFieldName, 'table-graph-cell__sort-asc': - isFieldName && sortField === cellData && sortDirection === ASCENDING, + isFieldName && sort.field === cellData && sort.direction === ASCENDING, 'table-graph-cell__sort-desc': - isFieldName && sortField === cellData && sortDirection === DESCENDING, + isFieldName && sort.field === cellData && sort.direction === DESCENDING, }) const cellContents = isTimeData @@ -353,8 +347,7 @@ class TableGraph extends Component { hoveredColumnIndex, hoveredRowIndex, timeColumnWidth, - sortField, - sortDirection, + sort, transformedData, } = this.state const {hoverTime, tableOptions, colors} = this.props @@ -399,8 +392,7 @@ class TableGraph extends Component { enableFixedRowScroll={true} scrollToRow={scrollToRow} scrollToColumn={scrollToColumn} - sortField={sortField} - sortDirection={sortDirection} + sort={sort} cellRenderer={this.cellRenderer} hoveredColumnIndex={hoveredColumnIndex} hoveredRowIndex={hoveredRowIndex} From ca1cb97225e0f35c78e18efc614444739d50018f Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Tue, 24 Apr 2018 15:02:13 -0700 Subject: [PATCH 17/48] Fix not handling literal variable declarations --- ui/src/ifql/containers/IFQLPage.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ui/src/ifql/containers/IFQLPage.tsx b/ui/src/ifql/containers/IFQLPage.tsx index 1ccf4289ca..db8ba47c07 100644 --- a/ui/src/ifql/containers/IFQLPage.tsx +++ b/ui/src/ifql/containers/IFQLPage.tsx @@ -45,7 +45,7 @@ export class IFQLPage extends PureComponent { ast: null, suggestions: [], script: - 'foo = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\nbar = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\n', + 'foo = "baz"\n\nfoo = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\nbar = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\n', } } @@ -187,6 +187,10 @@ export class IFQLPage extends PureComponent { return acc } + if (!declaration.funcs) { + return `${acc}${b.source}\n\n` + } + return `${acc}${declaration.name} = ${this.funcsToScript( declaration.funcs )}\n\n` From f0ee615e548c85f44a41abf2e7208b1ba1eebc39 Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Tue, 24 Apr 2018 15:02:19 -0700 Subject: [PATCH 18/48] Fix tests --- ui/test/ifql/components/From.test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/test/ifql/components/From.test.tsx b/ui/test/ifql/components/From.test.tsx index 41466f527e..d859f9728c 100644 --- a/ui/test/ifql/components/From.test.tsx +++ b/ui/test/ifql/components/From.test.tsx @@ -10,6 +10,7 @@ const setup = () => { argKey: 'db', value: 'db1', bodyID: '2', + declarationID: '1', onChangeArg: () => {}, } From 3e5a27ce6f86dda28adb3b9903c096eb6dd6ebf7 Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 24 Apr 2018 16:49:38 -0700 Subject: [PATCH 19/48] Polish error state in line graph --- ui/src/shared/components/InvalidData.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/ui/src/shared/components/InvalidData.tsx b/ui/src/shared/components/InvalidData.tsx index 52174b8136..17b50c5519 100644 --- a/ui/src/shared/components/InvalidData.tsx +++ b/ui/src/shared/components/InvalidData.tsx @@ -3,13 +3,12 @@ import React, {PureComponent} from 'react' class InvalidData extends PureComponent<{}> { public render() { return ( -

- The data returned from the query can't be visualized with this graph - type. Try updating the query or selecting a different graph type. -

+
+

+ The data returned from the query can't be visualized with this graph + type.
Try updating the query or selecting a different graph type. +

+
) } } From 0bdc032ce6db071beaa84d52dc77d42e7ac0ca5c Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 24 Apr 2018 17:14:11 -0700 Subject: [PATCH 20/48] Make auto refresh dropdown more compact --- .../shared/components/AutoRefreshDropdown.js | 4 ++-- ui/src/shared/data/autoRefreshes.js | 20 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ui/src/shared/components/AutoRefreshDropdown.js b/ui/src/shared/components/AutoRefreshDropdown.js index 92f338cd8c..7a1d068307 100644 --- a/ui/src/shared/components/AutoRefreshDropdown.js +++ b/ui/src/shared/components/AutoRefreshDropdown.js @@ -41,7 +41,7 @@ class AutoRefreshDropdown extends Component { paused: +milliseconds === 0, })} > -
+
)}
  • - {preventCustomTimeRange ? '' : 'Relative '}Time Ranges + {preventCustomTimeRange ? '' : 'Relative '}Time
  • {timeRanges.map(item => { return ( diff --git a/ui/src/shared/data/timeRanges.js b/ui/src/shared/data/timeRanges.js index 914f0ddd73..1631bcd934 100644 --- a/ui/src/shared/data/timeRanges.js +++ b/ui/src/shared/data/timeRanges.js @@ -2,73 +2,73 @@ export const timeRanges = [ { defaultGroupBy: '10s', seconds: 300, - inputValue: 'Past 5 minutes', + inputValue: 'Past 5m', lower: 'now() - 5m', upper: null, - menuOption: 'Past 5 minutes', + menuOption: 'Past 5m', }, { defaultGroupBy: '1m', seconds: 900, - inputValue: 'Past 15 minutes', + inputValue: 'Past 15m', lower: 'now() - 15m', upper: null, - menuOption: 'Past 15 minutes', + menuOption: 'Past 15m', }, { defaultGroupBy: '1m', seconds: 3600, - inputValue: 'Past hour', + inputValue: 'Past 1h', lower: 'now() - 1h', upper: null, - menuOption: 'Past hour', + menuOption: 'Past 1h', }, { defaultGroupBy: '1m', seconds: 21600, - inputValue: 'Past 6 hours', + inputValue: 'Past 6h', lower: 'now() - 6h', upper: null, - menuOption: 'Past 6 hours', + menuOption: 'Past 6h', }, { defaultGroupBy: '5m', seconds: 43200, - inputValue: 'Past 12 hours', + inputValue: 'Past 12h', lower: 'now() - 12h', upper: null, - menuOption: 'Past 12 hours', + menuOption: 'Past 12h', }, { defaultGroupBy: '10m', seconds: 86400, - inputValue: 'Past 24 hours', + inputValue: 'Past 24h', lower: 'now() - 24h', upper: null, - menuOption: 'Past 24 hours', + menuOption: 'Past 24h', }, { defaultGroupBy: '30m', seconds: 172800, - inputValue: 'Past 2 days', + inputValue: 'Past 2d', lower: 'now() - 2d', upper: null, - menuOption: 'Past 2 days', + menuOption: 'Past 2d', }, { defaultGroupBy: '1h', seconds: 604800, - inputValue: 'Past 7 days', + inputValue: 'Past 7d', lower: 'now() - 7d', upper: null, - menuOption: 'Past 7 days', + menuOption: 'Past 7d', }, { defaultGroupBy: '6h', seconds: 2592000, - inputValue: 'Past 30 days', + inputValue: 'Past 30d', lower: 'now() - 30d', upper: null, - menuOption: 'Past 30 days', + menuOption: 'Past 30d', }, ] From ebcdba9b667ed7a61550a6e48444ab150aa0b507 Mon Sep 17 00:00:00 2001 From: ebb-tide Date: Tue, 24 Apr 2018 23:22:48 -0700 Subject: [PATCH 22/48] Front end work for taking fieldOptions out of tableOptions on to cell --- .../dashboards/actions/cellEditorOverlay.js | 13 +- ui/src/dashboards/components/TableOptions.tsx | 90 ++++++------ .../dashboards/reducers/cellEditorOverlay.js | 20 ++- ui/src/dashboards/utils/tableGraph.ts | 52 ++++--- ui/src/shared/apis/index.js | 4 +- ui/src/shared/components/TableGraph.js | 82 ++++++----- ui/src/shared/constants/tableGraph.js | 3 + ui/src/types/dashboard.ts | 3 +- .../components/TableOptions.test.tsx | 4 +- ui/test/utils/timeSeriesTransformers.test.js | 139 ++++++++++-------- 10 files changed, 233 insertions(+), 177 deletions(-) diff --git a/ui/src/dashboards/actions/cellEditorOverlay.js b/ui/src/dashboards/actions/cellEditorOverlay.js index dae56aa318..8038ff6b98 100644 --- a/ui/src/dashboards/actions/cellEditorOverlay.js +++ b/ui/src/dashboards/actions/cellEditorOverlay.js @@ -65,9 +65,16 @@ export const updateLineColors = lineColors => ({ }, }) -export const updateDisplayOptions = update => ({ - type: 'UPDATE_DISPLAY_OPTIONS', +export const changeTimeFormat = timeFormat => ({ + type: 'CHANGE_TIME_FORMAT', payload: { - update, + timeFormat, + }, +}) + +export const updateFieldOptions = fieldOptions => ({ + type: 'UPDATE_FIELD_OPTIONS', + payload: { + fieldOptions, }, }) diff --git a/ui/src/dashboards/components/TableOptions.tsx b/ui/src/dashboards/components/TableOptions.tsx index 2778ce79af..78f0d24be6 100644 --- a/ui/src/dashboards/components/TableOptions.tsx +++ b/ui/src/dashboards/components/TableOptions.tsx @@ -16,13 +16,14 @@ import ThresholdsListTypeToggle from 'src/shared/components/ThresholdsListTypeTo import { updateTableOptions, - updateDisplayOptions, + updateFieldOptions, + changeTimeFormat, } from 'src/dashboards/actions/cellEditorOverlay' import {TIME_FIELD_DEFAULT} from 'src/shared/constants/tableGraph' import {QueryConfig} from 'src/types/query' import {ErrorHandling} from 'src/shared/decorators/errors' -interface Option { +interface DropdownOption { text: string key: string } @@ -31,9 +32,10 @@ interface RenamableField { internalName: string displayName: string visible: boolean + precision: number } -interface Options { +interface TableOptionsInterface { verticalTimeAxis: boolean sortBy: RenamableField fixFirstColumn: boolean @@ -41,9 +43,10 @@ interface Options { interface Props { queryConfigs: QueryConfig[] - handleUpdateTableOptions: (options: Options) => void - handleUpdateDisplayOptions: (displayOption: string | RenamableField[]) => void - tableOptions: Options + handleUpdateTableOptions: (options: TableOptionsInterface) => void + handleUpdateFieldOptions: (fieldOptions: RenamableField[]) => void + handleChangeTimeFormat: (timeFormat: string) => void + tableOptions: TableOptionsInterface fieldOptions: RenamableField[] timeFormat: string onResetFocus: () => void @@ -111,37 +114,33 @@ export class TableOptions extends Component { } private moveField(dragIndex, hoverIndex) { - const {handleUpdateTableOptions, tableOptions} = this.props - const {fieldNames} = tableOptions - const dragField = fieldNames[dragIndex] - const removedFields = _.concat( - _.slice(fieldNames, 0, dragIndex), - _.slice(fieldNames, dragIndex + 1) + const {handleUpdateFieldOptions, fieldOptions} = this.props + + const draggedField = fieldOptions[dragIndex] + + const fieldOptionsRemoved = _.concat( + _.slice(fieldOptions, 0, dragIndex), + _.slice(fieldOptions, dragIndex + 1) ) - const addedFields = _.concat( - _.slice(removedFields, 0, hoverIndex), - [dragField], - _.slice(removedFields, hoverIndex) + + const fieldOptionsAdded = _.concat( + _.slice(fieldOptionsRemoved, 0, hoverIndex), + [draggedField], + _.slice(fieldOptionsRemoved, hoverIndex) ) - handleUpdateDisplayOptions({ - fieldOptions: addedFields, - }) + + handleUpdateFieldOptions(fieldOptionsAdded) } - private handleChooseSortBy = (option: Option) => { - const {tableOptions, handleUpdateTableOptions} = this.props - const sortBy = { - displayName: option.text === option.key ? '' : option.text, - internalName: option.key, - visible: true, - } - + private handleChooseSortBy = (option: DropdownOption) => { + const {tableOptions, handleUpdateTableOptions, fieldOptions} = this.props + const sortBy = fieldOptions.find(f => f.internalName === option.key) handleUpdateTableOptions({...tableOptions, sortBy}) } private handleTimeFormatChange = timeFormat => { - const {handleUpdateDisplayOptions} = this.props - handleUpdateDisplayOptions({timeFormat}) + const {handleChangeTimeFormat} = this.props + handleChangeTimeFormat(timeFormat) } private handleToggleVerticalTimeAxis = verticalTimeAxis => () => { @@ -158,32 +157,31 @@ export class TableOptions extends Component { private handleFieldUpdate = field => { const { handleUpdateTableOptions, - handleUpdateDisplayOptions, + handleUpdateFieldOptions, tableOptions, fieldOptions, } = this.props const {sortBy} = tableOptions - const updatedFields = fieldOptions.map( + + const updatedFieldOptions = fieldOptions.map( f => (f.internalName === field.internalName ? field : f) ) - const updatedSortBy = - sortBy.internalName === field.internalName - ? {...sortBy, displayName: field.displayName} - : sortBy - handleUpdateTableOptions({ - ...tableOptions, - sortBy: updatedSortBy, - }) - handleUpdateDisplayOptions({ - fieldOptions: updatedFields, - }) + if (sortBy.internalName === field.internalName) { + const updatedSortBy = {...sortBy, displayName: field.displayName} + handleUpdateTableOptions({ + ...tableOptions, + sortBy: updatedSortBy, + }) + } + + handleUpdateFieldOptions(updatedFieldOptions) } } const mapStateToProps = ({ cellEditorOverlay: { - cell: {tableOptions}, + cell: {tableOptions, timeFormat, fieldOptions}, }, }) => ({ tableOptions, @@ -193,10 +191,8 @@ const mapStateToProps = ({ const mapDispatchToProps = dispatch => ({ handleUpdateTableOptions: bindActionCreators(updateTableOptions, dispatch), - handleUpdateDisplayOptions: bindActionCreators( - updateDisplayOptions, - dispatch - ), + handleUpdateFieldOptions: bindActionCreators(updateFieldOptions, dispatch), + handleChangeTimeFormat: bindActionCreators(changeTimeFormat, dispatch), }) export default connect(mapStateToProps, mapDispatchToProps)(TableOptions) diff --git a/ui/src/dashboards/reducers/cellEditorOverlay.js b/ui/src/dashboards/reducers/cellEditorOverlay.js index cd23707e95..6cc605bac5 100644 --- a/ui/src/dashboards/reducers/cellEditorOverlay.js +++ b/ui/src/dashboards/reducers/cellEditorOverlay.js @@ -114,17 +114,25 @@ export default function cellEditorOverlay(state = initialState, action) { return {...state, cell} } + case 'CHANGE_TIME_FORMAT': { + const {timeFormat} = action.payload + const cell = {...state.cell, timeFormat} + + return {...state, cell} + } + + case 'UPDATE_FIELD_OPTIONS': { + const {fieldOptions} = action.payload + const cell = {...state.cell, fieldOptions} + + return {...state, cell} + } + case 'UPDATE_LINE_COLORS': { const {lineColors} = action.payload return {...state, lineColors} } - - case 'UPDATE_DISPLAY_OPTIONS': { - const {update} = action.payload - const cell = {...state.cell, ...update} - return {...state, cell} - } } return state diff --git a/ui/src/dashboards/utils/tableGraph.ts b/ui/src/dashboards/utils/tableGraph.ts index a31e3af9dd..e7e9664376 100644 --- a/ui/src/dashboards/utils/tableGraph.ts +++ b/ui/src/dashboards/utils/tableGraph.ts @@ -6,6 +6,7 @@ import { CELL_HORIZONTAL_PADDING, TIME_FIELD_DEFAULT, DEFAULT_TIME_FORMAT, + DEFAULT_PRECISION, } from 'src/shared/constants/tableGraph' const calculateTimeColumnWidth = timeFormat => { @@ -30,7 +31,7 @@ const updateMaxWidths = ( maxColumnWidths, topRow, isTopRow, - fieldNames, + fieldOptions, timeFormatWidth, verticalTimeAxis ) => { @@ -41,7 +42,7 @@ const updateMaxWidths = ( (verticalTimeAxis && isTopRow) || (!verticalTimeAxis && c === 0) const foundField = isLabel - ? fieldNames.find(field => field.internalName === col) + ? fieldOptions.find(field => field.internalName === col) : undefined const colValue = foundField && foundField.displayName ? foundField.displayName : `${col}` @@ -77,23 +78,28 @@ const updateMaxWidths = ( ) } -export const computeFieldNames = (existingFieldNames, sortedLabels) => { +export const computeFieldOptions = (existingFieldOptions, sortedLabels) => { const timeField = - existingFieldNames.find(f => f.internalName === 'time') || + existingFieldOptions.find(f => f.internalName === 'time') || TIME_FIELD_DEFAULT let astNames = [timeField] sortedLabels.forEach(({label}) => { - const field = {internalName: label, displayName: '', visible: true} + const field = { + internalName: label, + displayName: '', + visible: true, + precision: DEFAULT_PRECISION, + } astNames = [...astNames, field] }) - const intersection = existingFieldNames.filter(f => { + const intersection = existingFieldOptions.filter(f => { return astNames.find(a => a.internalName === f.internalName) }) const newFields = astNames.filter(a => { - return !existingFieldNames.find(f => f.internalName === a.internalName) + return !existingFieldOptions.find(f => f.internalName === a.internalName) }) return [...intersection, ...newFields] @@ -101,7 +107,7 @@ export const computeFieldNames = (existingFieldNames, sortedLabels) => { export const calculateColumnWidths = ( data, - fieldNames, + fieldOptions, timeFormat, verticalTimeAxis ) => { @@ -116,7 +122,7 @@ export const calculateColumnWidths = ( acc, data[0], r === 0, - fieldNames, + fieldOptions, timeFormatWidth, verticalTimeAxis ) @@ -125,12 +131,14 @@ export const calculateColumnWidths = ( ) } -export const filterTableColumns = (data, fieldNames) => { +export const filterTableColumns = (data, fieldOptions) => { const visibility = {} const filteredData = map(data, (row, i) => { return filter(row, (col, j) => { if (i === 0) { - const foundField = fieldNames.find(field => field.internalName === col) + const foundField = fieldOptions.find( + field => field.internalName === col + ) visibility[j] = foundField ? foundField.visible : true } return visibility[j] @@ -139,10 +147,10 @@ export const filterTableColumns = (data, fieldNames) => { return filteredData[0].length ? filteredData : [[]] } -export const orderTableColumns = (data, fieldNames) => { - const fieldsSortOrder = fieldNames.map(fieldName => { +export const orderTableColumns = (data, fieldOptions) => { + const fieldsSortOrder = fieldOptions.map(fieldOption => { return _.findIndex(data[0], dataLabel => { - return dataLabel === fieldName.internalName + return dataLabel === fieldOption.internalName }) }) const filteredFieldSortOrder = filter(fieldsSortOrder, f => f !== -1) @@ -152,20 +160,26 @@ export const orderTableColumns = (data, fieldNames) => { return orderedData[0].length ? orderedData : [[]] } -export const transformTableData = (data, sort, fieldNames, tableOptions) => { - const {verticalTimeAxis, timeFormat} = tableOptions +export const transformTableData = ( + data, + sort, + fieldOptions, + tableOptions, + timeFormat +) => { + const {verticalTimeAxis} = tableOptions const sortIndex = _.indexOf(data[0], sort.field) const sortedData = [ data[0], ..._.orderBy(_.drop(data, 1), sortIndex, [sort.direction]), ] const sortedTimeVals = map(sortedData, r => r[0]) - const filteredData = filterTableColumns(sortedData, fieldNames) - const orderedData = orderTableColumns(filteredData, fieldNames) + const filteredData = filterTableColumns(sortedData, fieldOptions) + const orderedData = orderTableColumns(filteredData, fieldOptions) const transformedData = verticalTimeAxis ? orderedData : _.unzip(orderedData) const {widths: columnWidths, totalWidths} = calculateColumnWidths( transformedData, - fieldNames, + fieldOptions, timeFormat, verticalTimeAxis ) diff --git a/ui/src/shared/apis/index.js b/ui/src/shared/apis/index.js index f66aa35f5f..3620097f82 100644 --- a/ui/src/shared/apis/index.js +++ b/ui/src/shared/apis/index.js @@ -185,7 +185,9 @@ export const testAlertOutput = async (kapacitor, outputName) => { export const getAllServices = async kapacitor => { try { - const {data: {services}} = await kapacitorProxy(kapacitor, 'GET','/kapacitor/v1/service-tests') + const { + data: {services}, + } = await kapacitorProxy(kapacitor, 'GET', '/kapacitor/v1/service-tests') return services } catch (error) { console.error(error) diff --git a/ui/src/shared/components/TableGraph.js b/ui/src/shared/components/TableGraph.js index 942870e221..271d734d90 100644 --- a/ui/src/shared/components/TableGraph.js +++ b/ui/src/shared/components/TableGraph.js @@ -13,10 +13,10 @@ const {arrayOf, bool, shape, string, func} = PropTypes import {timeSeriesToTableGraph} from 'src/utils/timeSeriesTransformers' import { - computeFieldNames, + computeFieldOptions, transformTableData, } from 'src/dashboards/utils/tableGraph' -import {updateTableOptions} from 'src/dashboards/actions/cellEditorOverlay' +import {updateFieldOptions} from 'src/dashboards/actions/cellEditorOverlay' import { NULL_ARRAY_INDEX, @@ -58,19 +58,19 @@ class TableGraph extends Component { } } - handleUpdateTableOptions = (fieldNames, tableOptions) => { + handleUpdateFieldOptions = fieldOptions => { const {isInCEO} = this.props if (!isInCEO) { return } - this.props.handleUpdateTableOptions({...tableOptions, fieldNames}) + this.props.handleUpdateFieldOptions(fieldOptions) } componentWillReceiveProps(nextProps) { const updatedProps = _.keys(nextProps).filter( k => !_.isEqual(this.props[k], nextProps[k]) ) - const {tableOptions} = nextProps + const {tableOptions, fieldOptions, timeFormat} = nextProps let result = {} @@ -80,10 +80,11 @@ class TableGraph extends Component { const data = _.get(result, 'data', this.state.data) const sortedLabels = _.get(result, 'sortedLabels', this.state.sortedLabels) - const fieldNames = computeFieldNames(tableOptions.fieldNames, sortedLabels) + + const computedFieldOptions = computeFieldOptions(fieldOptions, sortedLabels) if (_.includes(updatedProps, 'data')) { - this.handleUpdateTableOptions(fieldNames, tableOptions) + this.handleUpdateFieldOptions(computedFieldOptions) } if (_.isEmpty(data[0])) { @@ -106,14 +107,22 @@ class TableGraph extends Component { if ( _.includes(updatedProps, 'data') || - _.includes(updatedProps, 'tableOptions') + _.includes(updatedProps, 'tableOptions') || + _.includes(updatedProps, 'fieldOptions') || + _.includes(updatedProps, 'timeFormat') ) { const { transformedData, sortedTimeVals, columnWidths, totalWidths, - } = transformTableData(data, sort, fieldNames, tableOptions) + } = transformTableData( + data, + sort, + computedFieldOptions, + tableOptions, + timeFormat + ) this.setState({ data, @@ -187,33 +196,28 @@ class TableGraph extends Component { } handleClickFieldName = fieldName => () => { - const {tableOptions} = this.props - const {timeFormat} = tableOptions - const {data, sortField, sortDirection} = this.state - const verticalTimeAxis = _.get(tableOptions, 'verticalTimeAxis', true) - const fieldOptions = _.get(this.props, 'fieldOptions', [TIME_FIELD_DEFAULT]) + const {data, sort} = this.state + const {tableOptions, timeFormat, fieldOptions} = this.props - let direction - if (fieldName === sortField) { - direction = sortDirection === ASCENDING ? DESCENDING : ASCENDING + if (fieldName === sort.field) { + sort.direction = sort.direction === ASCENDING ? DESCENDING : ASCENDING } else { - direction = DEFAULT_SORT_DIRECTION + sort.field = fieldName + sort.direction = DEFAULT_SORT_DIRECTION } const {transformedData, sortedTimeVals} = transformTableData( data, - fieldName, - direction, - verticalTimeAxis, + sort, fieldOptions, + tableOptions, timeFormat ) this.setState({ transformedData, sortedTimeVals, - sortField: fieldName, - sortDirection: direction, + sort, }) } @@ -251,17 +255,17 @@ class TableGraph extends Component { hoveredColumnIndex, hoveredRowIndex, transformedData, - sortField, - sortDirection, + sort, } = this.state + const { - tableOptions, fieldOptions = [TIME_FIELD_DEFAULT], + timeFormat = DEFAULT_TIME_FORMAT, + tableOptions, colors, } = parent.props const { - timeFormat = DEFAULT_TIME_FORMAT, verticalTimeAxis = VERTICAL_TIME_AXIS_DEFAULT, fixFirstColumn = FIX_FIRST_COLUMN_DEFAULT, } = tableOptions @@ -321,9 +325,9 @@ class TableGraph extends Component { 'table-graph-cell__numerical': dataIsNumerical, 'table-graph-cell__field-name': isFieldName, 'table-graph-cell__sort-asc': - isFieldName && sortField === cellData && sortDirection === ASCENDING, + isFieldName && sort.field === cellData && sort.direction === ASCENDING, 'table-graph-cell__sort-desc': - isFieldName && sortField === cellData && sortDirection === DESCENDING, + isFieldName && sort.field === cellData && sort.direction === DESCENDING, }) const cellContents = isTimeData @@ -356,11 +360,16 @@ class TableGraph extends Component { hoveredColumnIndex, hoveredRowIndex, timeColumnWidth, - sortField, - sortDirection, + sort, transformedData, } = this.state - const {hoverTime, tableOptions, colors} = this.props + const { + hoverTime, + tableOptions, + colors, + fieldOptions, + timeFormat, + } = this.props const {fixFirstColumn = FIX_FIRST_COLUMN_DEFAULT} = tableOptions const columnCount = _.get(transformedData, ['0', 'length'], 0) const rowCount = columnCount === 0 ? 0 : transformedData.length @@ -402,14 +411,15 @@ class TableGraph extends Component { enableFixedRowScroll={true} scrollToRow={scrollToRow} scrollToColumn={scrollToColumn} - sortField={sortField} - sortDirection={sortDirection} cellRenderer={this.cellRenderer} hoveredColumnIndex={hoveredColumnIndex} hoveredRowIndex={hoveredRowIndex} hoverTime={hoverTime} colors={colors} + sort={sort} + fieldOptions={fieldOptions} tableOptions={tableOptions} + timeFormat={timeFormat} timeColumnWidth={timeColumnWidth} classNameBottomRightGrid="table-graph--scroll-window" /> @@ -442,7 +452,7 @@ TableGraph.propTypes = { }) ).isRequired, hoverTime: string, - handleUpdateTableOptions: func, + handleUpdateFieldOptions: func, handleSetHoverTime: func, colors: colorsStringSchema, queryASTs: arrayOf(shape()), @@ -450,7 +460,7 @@ TableGraph.propTypes = { } const mapDispatchToProps = dispatch => ({ - handleUpdateTableOptions: bindActionCreators(updateTableOptions, dispatch), + handleUpdateFieldOptions: bindActionCreators(updateFieldOptions, dispatch), }) export default connect(null, mapDispatchToProps)(TableGraph) diff --git a/ui/src/shared/constants/tableGraph.js b/ui/src/shared/constants/tableGraph.js index 999c0149fd..4b7d9e5822 100644 --- a/ui/src/shared/constants/tableGraph.js +++ b/ui/src/shared/constants/tableGraph.js @@ -5,10 +5,13 @@ export const NULL_HOVER_TIME = '0' export const TIME_FORMAT_TOOLTIP_LINK = 'http://momentjs.com/docs/#/parsing/string-format/' +export const DEFAULT_PRECISION = 0 + export const TIME_FIELD_DEFAULT = { internalName: 'time', displayName: '', visible: true, + precision: DEFAULT_PRECISION, } export const ASCENDING = 'asc' diff --git a/ui/src/types/dashboard.ts b/ui/src/types/dashboard.ts index 8bcdb63824..f033594c9c 100644 --- a/ui/src/types/dashboard.ts +++ b/ui/src/types/dashboard.ts @@ -18,6 +18,7 @@ interface FieldName { internalName: string displayName: string visible: boolean + precision: number } interface TableOptions { @@ -26,7 +27,6 @@ interface TableOptions { sortBy: FieldName wrapping: string fixFirstColumn: boolean - fieldNames: FieldName[] } interface CellLinks { @@ -55,6 +55,7 @@ export interface Cell { axes: Axes colors: ColorString[] tableOptions: TableOptions + fieldOptions: FieldName[] links: CellLinks legend: Legend } diff --git a/ui/test/dashboards/components/TableOptions.test.tsx b/ui/test/dashboards/components/TableOptions.test.tsx index 0c05f815a8..c6d4e3a8c5 100644 --- a/ui/test/dashboards/components/TableOptions.test.tsx +++ b/ui/test/dashboards/components/TableOptions.test.tsx @@ -12,12 +12,14 @@ import ThresholdsListTypeToggle from 'src/shared/components/ThresholdsListTypeTo const defaultProps = { handleUpdateTableOptions: () => {}, + handleUpdateFieldOptions: () => {}, + handleChangeTimeFormat: () => {}, onResetFocus: () => {}, queryConfigs: [], tableOptions: { columnNames: [], fixFirstColumn: true, - sortBy: {displayName: '', internalName: '', visible: true}, + sortBy: {displayName: '', internalName: '', visible: true, precision: 0}, verticalTimeAxis: true, }, fieldOptions: [], diff --git a/ui/test/utils/timeSeriesTransformers.test.js b/ui/test/utils/timeSeriesTransformers.test.js index f4d44e8e6f..906f9253e4 100644 --- a/ui/test/utils/timeSeriesTransformers.test.js +++ b/ui/test/utils/timeSeriesTransformers.test.js @@ -494,18 +494,18 @@ describe('filterTableColumns', () => { [3000, 2000, 1000], ] - const fieldNames = [ - {internalName: 'time', displayName: 'Time', visible: true}, - {internalName: 'f1', displayName: '', visible: false}, - {internalName: 'f2', displayName: 'F2', visible: false}, + const fieldOptions = [ + {internalName: 'time', displayName: 'Time', visible: true, precision: 0}, + {internalName: 'f1', displayName: '', visible: false, precision: 0}, + {internalName: 'f2', displayName: 'F2', visible: false, precision: 0}, ] - const actual = filterTableColumns(data, fieldNames) + const actual = filterTableColumns(data, fieldOptions) const expected = [['time'], [1000], [2000], [3000]] expect(actual).toEqual(expected) }) - it('returns an array of an empty array if all fieldNames are not visible', () => { + it('returns an array of an empty array if all fieldOptions are not visible', () => { const data = [ ['time', 'f1', 'f2'], [1000, 3000, 2000], @@ -513,13 +513,13 @@ describe('filterTableColumns', () => { [3000, 2000, 1000], ] - const fieldNames = [ - {internalName: 'time', displayName: 'Time', visible: false}, - {internalName: 'f1', displayName: '', visible: false}, - {internalName: 'f2', displayName: 'F2', visible: false}, + const fieldOptions = [ + {internalName: 'time', displayName: 'Time', visible: false, precision: 0}, + {internalName: 'f1', displayName: '', visible: false, precision: 0}, + {internalName: 'f2', displayName: 'F2', visible: false, precision: 0}, ] - const actual = filterTableColumns(data, fieldNames) + const actual = filterTableColumns(data, fieldOptions) const expected = [[]] expect(actual).toEqual(expected) }) @@ -534,18 +534,21 @@ describe('transformTableData', () => { [3000, 2000, 1000], ] const sort = {field: 'f1', direction: DEFAULT_SORT_DIRECTION} - const tableOptions = { - verticalTimeAxis: true, - timeFormat: DEFAULT_TIME_FORMAT, - } - - const fieldNames = [ - {internalName: 'time', displayName: 'Time', visible: true}, - {internalName: 'f1', displayName: '', visible: true}, - {internalName: 'f2', displayName: 'F2', visible: true}, + const tableOptions = {verticalTimeAxis: true} + const timeFormat = DEFAULT_TIME_FORMAT + const fieldOptions = [ + {internalName: 'time', displayName: 'Time', visible: true, precision: 0}, + {internalName: 'f1', displayName: '', visible: true, precision: 0}, + {internalName: 'f2', displayName: 'F2', visible: true, precision: 0}, ] - const actual = transformTableData(data, sort, fieldNames, tableOptions) + const actual = transformTableData( + data, + sort, + fieldOptions, + tableOptions, + timeFormat + ) const expected = [ ['time', 'f1', 'f2'], [2000, 1000, 3000], @@ -563,21 +566,22 @@ describe('transformTableData', () => { [2000, 1000, 3000], [3000, 2000, 1000], ] - const sort = {field: 'time', direction: DEFAULT_SORT_DIRECTION} - - const tableOptions = { - verticalTimeAxis: true, - timeFormat: DEFAULT_TIME_FORMAT, - } - - const fieldNames = [ - {internalName: 'time', displayName: 'Time', visible: true}, - {internalName: 'f1', displayName: '', visible: false}, - {internalName: 'f2', displayName: 'F2', visible: true}, + const tableOptions = {verticalTimeAxis: true} + const timeFormat = DEFAULT_TIME_FORMAT + const fieldOptions = [ + {internalName: 'time', displayName: 'Time', visible: true, precision: 0}, + {internalName: 'f1', displayName: '', visible: false, precision: 0}, + {internalName: 'f2', displayName: 'F2', visible: true, precision: 0}, ] - const actual = transformTableData(data, sort, fieldNames, tableOptions) + const actual = transformTableData( + data, + sort, + fieldOptions, + tableOptions, + timeFormat + ) const expected = [['time', 'f2'], [1000, 2000], [2000, 3000], [3000, 1000]] @@ -593,19 +597,22 @@ describe('transformTableData', () => { ] const sort = {field: 'f1', direction: DEFAULT_SORT_DIRECTION} + const tableOptions = {verticalTimeAxis: true} + const timeFormat = DEFAULT_TIME_FORMAT - const tableOptions = { - verticalTimeAxis: true, - timeFormat: DEFAULT_TIME_FORMAT, - } - - const fieldNames = [ - {internalName: 'time', displayName: 'Time', visible: true}, - {internalName: 'f1', displayName: '', visible: false}, - {internalName: 'f2', displayName: 'F2', visible: true}, + const fieldOptions = [ + {internalName: 'time', displayName: 'Time', visible: true, precision: 0}, + {internalName: 'f1', displayName: '', visible: false, precision: 0}, + {internalName: 'f2', displayName: 'F2', visible: true, precision: 0}, ] - const actual = transformTableData(data, sort, fieldNames, tableOptions) + const actual = transformTableData( + data, + sort, + fieldOptions, + tableOptions, + timeFormat + ) const expected = [['time', 'f2'], [2000, 3000], [3000, 1000], [1000, 2000]] @@ -623,19 +630,22 @@ describe('if verticalTimeAxis is false', () => { ] const sort = {field: 'time', direction: DEFAULT_SORT_DIRECTION} + const tableOptions = {verticalTimeAxis: false} + const timeFormat = DEFAULT_TIME_FORMAT - const tableOptions = { - verticalTimeAxis: false, - timeFormat: DEFAULT_TIME_FORMAT, - } - - const fieldNames = [ - {internalName: 'time', displayName: 'Time', visible: true}, - {internalName: 'f1', displayName: '', visible: true}, - {internalName: 'f2', displayName: 'F2', visible: true}, + const fieldOptions = [ + {internalName: 'time', displayName: 'Time', visible: true, precision: 0}, + {internalName: 'f1', displayName: '', visible: true, precision: 0}, + {internalName: 'f2', displayName: 'F2', visible: true, precision: 0}, ] - const actual = transformTableData(data, sort, fieldNames, tableOptions) + const actual = transformTableData( + data, + sort, + fieldOptions, + tableOptions, + timeFormat + ) const expected = [ ['time', 1000, 2000, 3000], @@ -655,19 +665,22 @@ describe('if verticalTimeAxis is false', () => { ] const sort = {field: 'f1', direction: DEFAULT_SORT_DIRECTION} + const tableOptions = {verticalTimeAxis: false} + const timeFormat = DEFAULT_TIME_FORMAT - const tableOptions = { - verticalTimeAxis: false, - timeFormat: DEFAULT_TIME_FORMAT, - } - - const fieldNames = [ - {internalName: 'time', displayName: 'Time', visible: true}, - {internalName: 'f1', displayName: '', visible: false}, - {internalName: 'f2', displayName: 'F2', visible: true}, + const fieldOptions = [ + {internalName: 'time', displayName: 'Time', visible: true, precision: 0}, + {internalName: 'f1', displayName: '', visible: false, precision: 0}, + {internalName: 'f2', displayName: 'F2', visible: true, precision: 0}, ] - const actual = transformTableData(data, sort, fieldNames, tableOptions) + const actual = transformTableData( + data, + sort, + fieldOptions, + tableOptions, + timeFormat + ) const expected = [['time', 2000, 3000, 1000], ['f2', 3000, 1000, 2000]] From 1589282891fd45ce95e95c193f9288997ba1eb5d Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 25 Apr 2018 12:29:58 -0700 Subject: [PATCH 23/48] Implement SubSections in Chronograf admin page --- .../chronograf/AdminChronografPage.js | 64 +++++++++++++++++-- ui/src/index.tsx | 5 +- ui/src/side_nav/containers/SideNav.tsx | 12 ++-- 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/ui/src/admin/containers/chronograf/AdminChronografPage.js b/ui/src/admin/containers/chronograf/AdminChronografPage.js index 2815bd1fa4..5e1eb9f77d 100644 --- a/ui/src/admin/containers/chronograf/AdminChronografPage.js +++ b/ui/src/admin/containers/chronograf/AdminChronografPage.js @@ -2,10 +2,52 @@ import React from 'react' import PropTypes from 'prop-types' import {connect} from 'react-redux' -import AdminTabs from 'src/admin/components/chronograf/AdminTabs' +import SubSections from 'src/shared/components/SubSections' import FancyScrollbar from 'shared/components/FancyScrollbar' -const AdminChronografPage = ({me}) => ( +import UsersPage from 'src/admin/containers/chronograf/UsersPage' +import AllUsersPage from 'src/admin/containers/chronograf/AllUsersPage' +import OrganizationsPage from 'src/admin/containers/chronograf/OrganizationsPage' +import ProvidersPage from 'src/admin/containers/ProvidersPage' + +import { + isUserAuthorized, + ADMIN_ROLE, + SUPERADMIN_ROLE, +} from 'src/auth/Authorized' + +const sections = me => [ + { + url: 'current-organization', + name: 'Current Org', + enabled: isUserAuthorized(me.role, ADMIN_ROLE), + component: ( + + ), + }, + { + url: 'all-users', + name: 'All Users', + enabled: isUserAuthorized(me.role, SUPERADMIN_ROLE), + component: , + }, + { + url: 'all-organizations', + name: 'All Orgs', + enabled: isUserAuthorized(me.role, SUPERADMIN_ROLE), + component: ( + + ), + }, + { + url: 'organization-mappings', + name: 'Org Mappings', + enabled: isUserAuthorized(me.role, SUPERADMIN_ROLE), + component: , + }, +] + +const AdminChronografPage = ({me, source, params: {tab}}) => (
    @@ -16,9 +58,12 @@ const AdminChronografPage = ({me}) => (
    -
    - -
    +
    @@ -35,6 +80,15 @@ AdminChronografPage.propTypes = { id: string.isRequired, }), }).isRequired, + params: shape({ + tab: string, + }).isRequired, + source: shape({ + id: string.isRequired, + links: shape({ + users: string.isRequired, + }), + }).isRequired, } const mapStateToProps = ({auth: {me}}) => ({ diff --git a/ui/src/index.tsx b/ui/src/index.tsx index 5f8572b98f..9d8b0d651f 100644 --- a/ui/src/index.tsx +++ b/ui/src/index.tsx @@ -146,7 +146,10 @@ class Root extends PureComponent<{}, State> { path="kapacitors/:id/edit:hash" component={KapacitorPage} /> - + diff --git a/ui/src/side_nav/containers/SideNav.tsx b/ui/src/side_nav/containers/SideNav.tsx index 7c8e93e623..2240357b05 100644 --- a/ui/src/side_nav/containers/SideNav.tsx +++ b/ui/src/side_nav/containers/SideNav.tsx @@ -122,14 +122,16 @@ class SideNav extends PureComponent { - + Chronograf @@ -163,9 +165,7 @@ class SideNav extends PureComponent { const mapStateToProps = ({ auth: {isUsingAuth, logoutLink, me}, - app: { - ephemeral: {inPresentationMode}, - }, + app: {ephemeral: {inPresentationMode}}, links, }) => ({ isHidden: inPresentationMode, From 3afa98ce738a84b658b904026d988130a2af039e Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 25 Apr 2018 12:30:11 -0700 Subject: [PATCH 24/48] Remove obsolete component --- .../admin/components/chronograf/AdminTabs.js | 78 ------------------- 1 file changed, 78 deletions(-) delete mode 100644 ui/src/admin/components/chronograf/AdminTabs.js diff --git a/ui/src/admin/components/chronograf/AdminTabs.js b/ui/src/admin/components/chronograf/AdminTabs.js deleted file mode 100644 index 48ac81fd83..0000000000 --- a/ui/src/admin/components/chronograf/AdminTabs.js +++ /dev/null @@ -1,78 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' - -import { - isUserAuthorized, - ADMIN_ROLE, - SUPERADMIN_ROLE, -} from 'src/auth/Authorized' - -import {Tab, Tabs, TabPanel, TabPanels, TabList} from 'shared/components/Tabs' -import OrganizationsPage from 'src/admin/containers/chronograf/OrganizationsPage' -import UsersPage from 'src/admin/containers/chronograf/UsersPage' -import ProvidersPage from 'src/admin/containers/ProvidersPage' -import AllUsersPage from 'src/admin/containers/chronograf/AllUsersPage' - -const ORGANIZATIONS_TAB_NAME = 'All Orgs' -const PROVIDERS_TAB_NAME = 'Org Mappings' -const CURRENT_ORG_USERS_TAB_NAME = 'Current Org' -const ALL_USERS_TAB_NAME = 'All Users' - -const AdminTabs = ({ - me: {currentOrganization: meCurrentOrganization, role: meRole, id: meID}, -}) => { - const tabs = [ - { - requiredRole: ADMIN_ROLE, - type: CURRENT_ORG_USERS_TAB_NAME, - component: ( - - ), - }, - { - requiredRole: SUPERADMIN_ROLE, - type: ALL_USERS_TAB_NAME, - component: , - }, - { - requiredRole: SUPERADMIN_ROLE, - type: ORGANIZATIONS_TAB_NAME, - component: ( - - ), - }, - { - requiredRole: SUPERADMIN_ROLE, - type: PROVIDERS_TAB_NAME, - component: , - }, - ].filter(t => isUserAuthorized(meRole, t.requiredRole)) - - return ( - - - {tabs.map((t, i) => {tabs[i].type})} - - - {tabs.map((t, i) => ( - {t.component} - ))} - - - ) -} - -const {shape, string} = PropTypes - -AdminTabs.propTypes = { - me: shape({ - id: string.isRequired, - role: string.isRequired, - currentOrganization: shape({ - name: string.isRequired, - id: string.isRequired, - }), - }).isRequired, -} - -export default AdminTabs From 2892a22e04d4c7325e4d531b5cd6f93a71942166 Mon Sep 17 00:00:00 2001 From: ebb-tide Date: Wed, 25 Apr 2018 13:33:50 -0700 Subject: [PATCH 25/48] Handle responses from queries with errors --- ui/src/utils/groupBy.js | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/ui/src/utils/groupBy.js b/ui/src/utils/groupBy.js index 74e9e7b09a..dc6869c7aa 100644 --- a/ui/src/utils/groupBy.js +++ b/ui/src/utils/groupBy.js @@ -2,8 +2,11 @@ import _ from 'lodash' import {shiftDate} from 'shared/query/helpers' import {map, reduce, forEach, concat, clone} from 'fast.js' -const groupByMap = (responses, responseIndex, groupByColumns) => { - const firstColumns = _.get(responses, [0, 'series', 0, 'columns']) +const groupByMap = (results, responseIndex, groupByColumns) => { + if (_.isEmpty(results)) { + return [] + } + const firstColumns = _.get(results, [0, 'series', 0, 'columns']) const accum = [ { responseIndex, @@ -15,14 +18,14 @@ const groupByMap = (responses, responseIndex, groupByColumns) => { ...firstColumns.slice(1), ], groupByColumns, - name: _.get(responses, [0, 'series', 0, 'name']), + name: _.get(results, [0, 'series', 0, 'name']), values: [], }, ], }, ] - const seriesArray = _.get(responses, [0, 'series']) + const seriesArray = _.get(results, [0, 'series']) seriesArray.forEach(s => { const prevValues = accum[0].series[0].values const tagsToAdd = groupByColumns.map(gb => s.tags[gb]) @@ -35,13 +38,17 @@ const groupByMap = (responses, responseIndex, groupByColumns) => { const constructResults = (raw, groupBys) => { return _.flatten( map(raw, (response, index) => { - const responses = _.get(response, 'response.results', []) + const results = _.get(response, 'response.results', []) + + const successfulResults = _.filter( + results, + r => !_.get(r, 'error', false) + ) if (groupBys[index]) { - return groupByMap(responses, index, groupBys[index]) + return groupByMap(successfulResults, index, groupBys[index]) } - - return map(responses, r => ({...r, responseIndex: index})) + return map(successfulResults, r => ({...r, responseIndex: index})) }) ) } @@ -221,8 +228,8 @@ export const groupByTimeSeriesTransform = (raw, groupBys) => { if (!groupBys) { groupBys = Array(raw.length).fill(false) } - const results = constructResults(raw, groupBys) + const results = constructResults(raw, groupBys) const serieses = constructSerieses(results) const {cells, sortedLabels, seriesLabels} = constructCells(serieses) From 3615f13c21c7c14030d25412f05bbb9035b5be6b Mon Sep 17 00:00:00 2001 From: ebb-tide Date: Wed, 25 Apr 2018 14:26:00 -0700 Subject: [PATCH 26/48] Pass ability to editQueryStatus to all graph types --- ui/src/shared/components/RefreshingGraph.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/src/shared/components/RefreshingGraph.js b/ui/src/shared/components/RefreshingGraph.js index 12c935ae1a..34ad1fbabd 100644 --- a/ui/src/shared/components/RefreshingGraph.js +++ b/ui/src/shared/components/RefreshingGraph.js @@ -63,6 +63,7 @@ const RefreshingGraph = ({ templates={templates} autoRefresh={autoRefresh} cellHeight={cellHeight} + editQueryStatus={editQueryStatus} prefix={prefix} suffix={suffix} inView={inView} @@ -81,6 +82,7 @@ const RefreshingGraph = ({ autoRefresh={autoRefresh} cellHeight={cellHeight} resizerTopHeight={resizerTopHeight} + editQueryStatus={editQueryStatus} resizeCoords={resizeCoords} cellID={cellID} prefix={prefix} @@ -105,6 +107,7 @@ const RefreshingGraph = ({ cellHeight={cellHeight} resizeCoords={resizeCoords} tableOptions={tableOptions} + editQueryStatus={editQueryStatus} resizerTopHeight={resizerTopHeight} handleSetHoverTime={handleSetHoverTime} isInCEO={isInCEO} From 973d514c04b4dca77d75b7676c79db07c48512be Mon Sep 17 00:00:00 2001 From: Brandon Farmer Date: Wed, 25 Apr 2018 14:35:36 -0700 Subject: [PATCH 27/48] Properly handle strings in data for line graphs --- ui/src/shared/components/LineGraph.js | 31 +++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/ui/src/shared/components/LineGraph.js b/ui/src/shared/components/LineGraph.js index d2cb421199..9338ba7d96 100644 --- a/ui/src/shared/components/LineGraph.js +++ b/ui/src/shared/components/LineGraph.js @@ -1,3 +1,4 @@ +import _ from 'lodash' import React, {Component} from 'react' import PropTypes from 'prop-types' import Dygraph from 'shared/components/Dygraph' @@ -9,15 +10,36 @@ import {colorsStringSchema} from 'shared/schemas' import {ErrorHandlingWith} from 'src/shared/decorators/errors' import InvalidData from 'src/shared/components/InvalidData' +const validateTimeSeries = timeseries => { + return _.every(timeseries, r => + _.every(r, (v, i) => { + if (i === 0) { + return true + } + return _.isNumber(v) || _.isNull(v) + }) + ) +} @ErrorHandlingWith(InvalidData) class LineGraph extends Component { constructor(props) { super(props) + this.invalidData = false } componentWillMount() { const {data, isInDataExplorer} = this.props + this.parseTimeSeries(data, isInDataExplorer) + } + + parseTimeSeries(data, isInDataExplorer) { this._timeSeries = timeSeriesToDygraph(data, isInDataExplorer) + const valid = validateTimeSeries(_.get(this._timeSeries, 'timeSeries', [])) + if (valid) { + this.invalidData = false + } else { + this.invalidData = true + } } componentWillUpdate(nextProps) { @@ -26,14 +48,15 @@ class LineGraph extends Component { data !== nextProps.data || activeQueryIndex !== nextProps.activeQueryIndex ) { - this._timeSeries = timeSeriesToDygraph( - nextProps.data, - nextProps.isInDataExplorer - ) + this.parseTimeSeries(nextProps.data, nextProps.isInDataExplorer) } } render() { + if (this.invalidData) { + return + } + const { data, axes, From d9455a7646e56c2f445a0123762505bb6cfcd600 Mon Sep 17 00:00:00 2001 From: ebb-tide Date: Wed, 25 Apr 2018 14:53:54 -0700 Subject: [PATCH 28/48] Restore groupBy naming behavior for lineGraphs --- ui/src/utils/groupBy.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ui/src/utils/groupBy.js b/ui/src/utils/groupBy.js index dc6869c7aa..cf23a6cd81 100644 --- a/ui/src/utils/groupBy.js +++ b/ui/src/utils/groupBy.js @@ -99,11 +99,15 @@ const constructCells = serieses => { vals, })) + const tagSet = map(Object.keys(tags), tag => `[${tag}=${tags[tag]}]`) + .sort() + .join('') + const unsortedLabels = map(columns.slice(1), (field, i) => ({ label: groupByColumns && i <= groupByColumns.length - 1 ? `${field}` - : `${measurement}.${field}`, + : `${measurement}.${field}${tagSet}`, responseIndex, seriesIndex, })) From f1d197a4322f6dc36020dda41a2f33a28c6263e3 Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 25 Apr 2018 15:10:15 -0700 Subject: [PATCH 29/48] Prettier --- ui/src/side_nav/containers/SideNav.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/src/side_nav/containers/SideNav.tsx b/ui/src/side_nav/containers/SideNav.tsx index 2240357b05..5f28254bf7 100644 --- a/ui/src/side_nav/containers/SideNav.tsx +++ b/ui/src/side_nav/containers/SideNav.tsx @@ -165,7 +165,9 @@ class SideNav extends PureComponent { const mapStateToProps = ({ auth: {isUsingAuth, logoutLink, me}, - app: {ephemeral: {inPresentationMode}}, + app: { + ephemeral: {inPresentationMode}, + }, links, }) => ({ isHidden: inPresentationMode, From e0dc57e4e35c2e5a6d313641f535340413e31f6a Mon Sep 17 00:00:00 2001 From: ebb-tide Date: Wed, 25 Apr 2018 15:11:01 -0700 Subject: [PATCH 30/48] Fix linter error. --- ui/src/side_nav/containers/SideNav.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/src/side_nav/containers/SideNav.tsx b/ui/src/side_nav/containers/SideNav.tsx index 2240357b05..5f28254bf7 100644 --- a/ui/src/side_nav/containers/SideNav.tsx +++ b/ui/src/side_nav/containers/SideNav.tsx @@ -165,7 +165,9 @@ class SideNav extends PureComponent { const mapStateToProps = ({ auth: {isUsingAuth, logoutLink, me}, - app: {ephemeral: {inPresentationMode}}, + app: { + ephemeral: {inPresentationMode}, + }, links, }) => ({ isHidden: inPresentationMode, From 8b52c83c408f2da2f40b4ad1eb870944fec06668 Mon Sep 17 00:00:00 2001 From: Brandon Farmer Date: Wed, 25 Apr 2018 16:33:47 -0700 Subject: [PATCH 31/48] Stricter check for line graph data --- ui/src/shared/components/LineGraph.js | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/ui/src/shared/components/LineGraph.js b/ui/src/shared/components/LineGraph.js index 9338ba7d96..47b5145b34 100644 --- a/ui/src/shared/components/LineGraph.js +++ b/ui/src/shared/components/LineGraph.js @@ -12,19 +12,17 @@ import InvalidData from 'src/shared/components/InvalidData' const validateTimeSeries = timeseries => { return _.every(timeseries, r => - _.every(r, (v, i) => { - if (i === 0) { - return true - } - return _.isNumber(v) || _.isNull(v) - }) + _.every( + r, + (v, i) => (i === 0 && Date.parse(v)) || _.isNumber(v) || _.isNull(v) + ) ) } @ErrorHandlingWith(InvalidData) class LineGraph extends Component { constructor(props) { super(props) - this.invalidData = false + this.isValidData = true } componentWillMount() { @@ -34,12 +32,9 @@ class LineGraph extends Component { parseTimeSeries(data, isInDataExplorer) { this._timeSeries = timeSeriesToDygraph(data, isInDataExplorer) - const valid = validateTimeSeries(_.get(this._timeSeries, 'timeSeries', [])) - if (valid) { - this.invalidData = false - } else { - this.invalidData = true - } + this.isValidData = validateTimeSeries( + _.get(this._timeSeries, 'timeSeries', []) + ) } componentWillUpdate(nextProps) { @@ -53,7 +48,7 @@ class LineGraph extends Component { } render() { - if (this.invalidData) { + if (!this.isValidData) { return } From 78bfe2cec33f4908c28bace1c9063a8815848a75 Mon Sep 17 00:00:00 2001 From: ebb-tide Date: Wed, 25 Apr 2018 17:05:56 -0700 Subject: [PATCH 32/48] PR review suggestions --- ui/src/utils/groupBy.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/ui/src/utils/groupBy.js b/ui/src/utils/groupBy.js index cf23a6cd81..ff6cd898e5 100644 --- a/ui/src/utils/groupBy.js +++ b/ui/src/utils/groupBy.js @@ -18,7 +18,7 @@ const groupByMap = (results, responseIndex, groupByColumns) => { ...firstColumns.slice(1), ], groupByColumns, - name: _.get(results, [0, 'series', 0, 'name']), + name: _.get(results, [0, 'series', 0, 'name'], ''), values: [], }, ], @@ -40,10 +40,7 @@ const constructResults = (raw, groupBys) => { map(raw, (response, index) => { const results = _.get(response, 'response.results', []) - const successfulResults = _.filter( - results, - r => !_.get(r, 'error', false) - ) + const successfulResults = _.filter(results, r => _.isNil(r.error)) if (groupBys[index]) { return groupByMap(successfulResults, index, groupBys[index]) @@ -88,16 +85,14 @@ const constructCells = serieses => { name: measurement, columns, groupByColumns, - values, + values = [], seriesIndex, responseIndex, tags = {}, }, ind ) => { - const rows = map(values || [], vals => ({ - vals, - })) + const rows = map(values, vals => ({vals})) const tagSet = map(Object.keys(tags), tag => `[${tag}=${tags[tag]}]`) .sort() From b91e1274cf58dc4188f9212de709d0295fe67f04 Mon Sep 17 00:00:00 2001 From: ebb-tide Date: Thu, 26 Apr 2018 11:10:34 -0700 Subject: [PATCH 33/48] DEFAULT's should come first --- ui/src/dashboards/components/TableOptions.tsx | 4 ++-- ui/src/dashboards/utils/tableGraph.ts | 8 +++---- ui/src/shared/components/TableGraph.js | 24 +++++++++---------- ui/src/shared/constants/tableGraph.js | 13 +++++----- 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/ui/src/dashboards/components/TableOptions.tsx b/ui/src/dashboards/components/TableOptions.tsx index 78f0d24be6..6a0fe3dcc8 100644 --- a/ui/src/dashboards/components/TableOptions.tsx +++ b/ui/src/dashboards/components/TableOptions.tsx @@ -19,7 +19,7 @@ import { updateFieldOptions, changeTimeFormat, } from 'src/dashboards/actions/cellEditorOverlay' -import {TIME_FIELD_DEFAULT} from 'src/shared/constants/tableGraph' +import {DEFAULT_TIME_FIELD} from 'src/shared/constants/tableGraph' import {QueryConfig} from 'src/types/query' import {ErrorHandling} from 'src/shared/decorators/errors' @@ -90,7 +90,7 @@ export class TableOptions extends Component { onToggleVerticalTimeAxis={this.handleToggleVerticalTimeAxis} /> diff --git a/ui/src/dashboards/utils/tableGraph.ts b/ui/src/dashboards/utils/tableGraph.ts index e7e9664376..fc535b11a3 100644 --- a/ui/src/dashboards/utils/tableGraph.ts +++ b/ui/src/dashboards/utils/tableGraph.ts @@ -4,7 +4,7 @@ import {map, reduce, filter} from 'fast.js' import { CELL_HORIZONTAL_PADDING, - TIME_FIELD_DEFAULT, + DEFAULT_TIME_FIELD, DEFAULT_TIME_FORMAT, DEFAULT_PRECISION, } from 'src/shared/constants/tableGraph' @@ -49,12 +49,12 @@ const updateMaxWidths = ( const columnLabel = topRow[c] const useTimeWidth = - (columnLabel === TIME_FIELD_DEFAULT.internalName && + (columnLabel === DEFAULT_TIME_FIELD.internalName && verticalTimeAxis && !isTopRow) || (!verticalTimeAxis && isTopRow && - topRow[0] === TIME_FIELD_DEFAULT.internalName && + topRow[0] === DEFAULT_TIME_FIELD.internalName && c !== 0) const currentWidth = useTimeWidth @@ -81,7 +81,7 @@ const updateMaxWidths = ( export const computeFieldOptions = (existingFieldOptions, sortedLabels) => { const timeField = existingFieldOptions.find(f => f.internalName === 'time') || - TIME_FIELD_DEFAULT + DEFAULT_TIME_FIELD let astNames = [timeField] sortedLabels.forEach(({label}) => { diff --git a/ui/src/shared/components/TableGraph.js b/ui/src/shared/components/TableGraph.js index 271d734d90..e9ab526272 100644 --- a/ui/src/shared/components/TableGraph.js +++ b/ui/src/shared/components/TableGraph.js @@ -19,15 +19,15 @@ import { import {updateFieldOptions} from 'src/dashboards/actions/cellEditorOverlay' import { - NULL_ARRAY_INDEX, - NULL_HOVER_TIME, - DEFAULT_TIME_FORMAT, - TIME_FIELD_DEFAULT, ASCENDING, DESCENDING, + NULL_HOVER_TIME, + NULL_ARRAY_INDEX, + DEFAULT_TIME_FIELD, + DEFAULT_TIME_FORMAT, DEFAULT_SORT_DIRECTION, - FIX_FIRST_COLUMN_DEFAULT, - VERTICAL_TIME_AXIS_DEFAULT, + DEFAULT_FIX_FIRST_COLUMN, + DEFAULT_VERTICAL_TIME_AXIS, } from 'src/shared/constants/tableGraph' import {generateThresholdsListHexs} from 'shared/constants/colorOperations' @@ -42,7 +42,7 @@ class TableGraph extends Component { const sortField = _.get( this.props, ['tableOptions', 'sortBy', 'internalName'], - TIME_FIELD_DEFAULT.internalName + DEFAULT_TIME_FIELD.internalName ) this.state = { @@ -259,21 +259,21 @@ class TableGraph extends Component { } = this.state const { - fieldOptions = [TIME_FIELD_DEFAULT], + fieldOptions = [DEFAULT_TIME_FIELD], timeFormat = DEFAULT_TIME_FORMAT, tableOptions, colors, } = parent.props const { - verticalTimeAxis = VERTICAL_TIME_AXIS_DEFAULT, - fixFirstColumn = FIX_FIRST_COLUMN_DEFAULT, + verticalTimeAxis = DEFAULT_VERTICAL_TIME_AXIS, + fixFirstColumn = DEFAULT_FIX_FIRST_COLUMN, } = tableOptions const cellData = transformedData[rowIndex][columnIndex] const timeFieldIndex = fieldOptions.findIndex( - field => field.internalName === TIME_FIELD_DEFAULT.internalName + field => field.internalName === DEFAULT_TIME_FIELD.internalName ) const visibleTime = _.get(fieldOptions, [timeFieldIndex, 'visible'], true) @@ -370,7 +370,7 @@ class TableGraph extends Component { fieldOptions, timeFormat, } = this.props - const {fixFirstColumn = FIX_FIRST_COLUMN_DEFAULT} = tableOptions + const {fixFirstColumn = DEFAULT_FIX_FIRST_COLUMN} = tableOptions const columnCount = _.get(transformedData, ['0', 'length'], 0) const rowCount = columnCount === 0 ? 0 : transformedData.length diff --git a/ui/src/shared/constants/tableGraph.js b/ui/src/shared/constants/tableGraph.js index 4b7d9e5822..af4b969eab 100644 --- a/ui/src/shared/constants/tableGraph.js +++ b/ui/src/shared/constants/tableGraph.js @@ -7,7 +7,7 @@ export const TIME_FORMAT_TOOLTIP_LINK = export const DEFAULT_PRECISION = 0 -export const TIME_FIELD_DEFAULT = { +export const DEFAULT_TIME_FIELD = { internalName: 'time', displayName: '', visible: true, @@ -18,8 +18,8 @@ export const ASCENDING = 'asc' export const DESCENDING = 'desc' export const DEFAULT_SORT_DIRECTION = ASCENDING -export const FIX_FIRST_COLUMN_DEFAULT = true -export const VERTICAL_TIME_AXIS_DEFAULT = true +export const DEFAULT_FIX_FIRST_COLUMN = true +export const DEFAULT_VERTICAL_TIME_AXIS = true export const CELL_HORIZONTAL_PADDING = 30 @@ -38,9 +38,8 @@ export const FORMAT_OPTIONS = [ ] export const DEFAULT_TABLE_OPTIONS = { - verticalTimeAxis: VERTICAL_TIME_AXIS_DEFAULT, - timeFormat: DEFAULT_TIME_FORMAT, - sortBy: TIME_FIELD_DEFAULT, + verticalTimeAxis: DEFAULT_VERTICAL_TIME_AXIS, + sortBy: DEFAULT_TIME_FIELD, wrapping: 'truncate', - fixFirstColumn: FIX_FIRST_COLUMN_DEFAULT, + fixFirstColumn: DEFAULT_FIX_FIRST_COLUMN, } From 39f2eeb146fcdb74da8fa6c68400b4164d7bb2d1 Mon Sep 17 00:00:00 2001 From: ebb-tide Date: Thu, 26 Apr 2018 12:30:01 -0700 Subject: [PATCH 34/48] Add timeFormat and fieldOptions to default new cell --- .../components/GraphOptionsTimeFormat.tsx | 2 +- ui/src/dashboards/components/TableOptions.tsx | 2 +- ui/src/dashboards/constants/cellEditor.js | 2 +- ui/src/dashboards/constants/index.js | 40 ++++++++++++++++++- ui/src/dashboards/utils/tableGraph.ts | 4 +- ui/src/shared/components/Layout.js | 18 +++++++++ ui/src/shared/components/LayoutRenderer.js | 18 +++++++++ ui/src/shared/components/RefreshingGraph.js | 13 +++++- ui/src/shared/components/TableGraph.js | 9 ++--- ui/src/shared/constants/tableGraph.js | 33 --------------- .../GraphOptionsTimeFormat.test.tsx | 2 +- .../reducers/cellEditorOverlay.test.js | 2 +- ui/test/utils/timeSeriesTransformers.test.js | 6 +-- 13 files changed, 98 insertions(+), 53 deletions(-) diff --git a/ui/src/dashboards/components/GraphOptionsTimeFormat.tsx b/ui/src/dashboards/components/GraphOptionsTimeFormat.tsx index 5e44af6cf1..3709df855d 100644 --- a/ui/src/dashboards/components/GraphOptionsTimeFormat.tsx +++ b/ui/src/dashboards/components/GraphOptionsTimeFormat.tsx @@ -6,7 +6,7 @@ import { TIME_FORMAT_CUSTOM, DEFAULT_TIME_FORMAT, TIME_FORMAT_TOOLTIP_LINK, -} from 'src/shared/constants/tableGraph' +} from 'src/dashboards/constants' import {ErrorHandling} from 'src/shared/decorators/errors' interface TimeFormatOptions { diff --git a/ui/src/dashboards/components/TableOptions.tsx b/ui/src/dashboards/components/TableOptions.tsx index 6a0fe3dcc8..c90e6fea6f 100644 --- a/ui/src/dashboards/components/TableOptions.tsx +++ b/ui/src/dashboards/components/TableOptions.tsx @@ -19,7 +19,7 @@ import { updateFieldOptions, changeTimeFormat, } from 'src/dashboards/actions/cellEditorOverlay' -import {DEFAULT_TIME_FIELD} from 'src/shared/constants/tableGraph' +import {DEFAULT_TIME_FIELD} from 'src/dashboards/constants' import {QueryConfig} from 'src/types/query' import {ErrorHandling} from 'src/shared/decorators/errors' diff --git a/ui/src/dashboards/constants/cellEditor.js b/ui/src/dashboards/constants/cellEditor.js index 4530b2c671..a3a617db3d 100644 --- a/ui/src/dashboards/constants/cellEditor.js +++ b/ui/src/dashboards/constants/cellEditor.js @@ -1,4 +1,4 @@ -import {DEFAULT_TABLE_OPTIONS} from 'src/shared/constants/tableGraph' +import {DEFAULT_TABLE_OPTIONS} from 'src/dashboards/constants' import {stringifyColorValues} from 'src/shared/constants/colorOperations' import { CELL_TYPE_LINE, diff --git a/ui/src/dashboards/constants/index.js b/ui/src/dashboards/constants/index.js index 8a343c1d24..645d7303cf 100644 --- a/ui/src/dashboards/constants/index.js +++ b/ui/src/dashboards/constants/index.js @@ -1,4 +1,7 @@ -import {DEFAULT_TABLE_OPTIONS} from 'src/shared/constants/tableGraph' +import { + DEFAULT_VERTICAL_TIME_AXIS, + DEFAULT_FIX_FIRST_COLUMN, +} from 'src/shared/constants/tableGraph' import {CELL_TYPE_LINE} from 'src/dashboards/graphics/graph' export const UNTITLED_CELL_LINE = 'Untitled Line Graph' @@ -11,6 +14,39 @@ export const UNTITLED_CELL_SINGLE_STAT = 'Untitled Single Stat' export const UNTITLED_CELL_GAUGE = 'Untitled Gauge' export const UNTITLED_CELL_TABLE = 'Untitled Table' +export const TIME_FORMAT_TOOLTIP_LINK = + 'http://momentjs.com/docs/#/parsing/string-format/' + +export const DEFAULT_PRECISION = 0 + +export const DEFAULT_TIME_FIELD = { + internalName: 'time', + displayName: '', + visible: true, + precision: DEFAULT_PRECISION, +} + +export const DEFAULT_TABLE_OPTIONS = { + verticalTimeAxis: DEFAULT_VERTICAL_TIME_AXIS, + sortBy: DEFAULT_TIME_FIELD, + wrapping: 'truncate', + fixFirstColumn: DEFAULT_FIX_FIRST_COLUMN, +} + +export const DEFAULT_TIME_FORMAT = 'MM/DD/YYYY HH:mm:ss' +export const TIME_FORMAT_CUSTOM = 'Custom' + +export const FORMAT_OPTIONS = [ + {text: DEFAULT_TIME_FORMAT}, + {text: 'MM/DD/YYYY HH:mm:ss.SSS'}, + {text: 'YYYY-MM-DD HH:mm:ss'}, + {text: 'HH:mm:ss'}, + {text: 'HH:mm:ss.SSS'}, + {text: 'MMMM D, YYYY HH:mm:ss'}, + {text: 'dddd, MMMM D, YYYY HH:mm:ss'}, + {text: TIME_FORMAT_CUSTOM}, +] + export const NEW_DEFAULT_DASHBOARD_CELL = { x: 0, y: 0, @@ -20,6 +56,8 @@ export const NEW_DEFAULT_DASHBOARD_CELL = { type: CELL_TYPE_LINE, queries: [], tableOptions: DEFAULT_TABLE_OPTIONS, + timeFormat: DEFAULT_TIME_FORMAT, + fieldOptions: [DEFAULT_TIME_FIELD], } export const EMPTY_DASHBOARD = { diff --git a/ui/src/dashboards/utils/tableGraph.ts b/ui/src/dashboards/utils/tableGraph.ts index fc535b11a3..37cdcbb9b5 100644 --- a/ui/src/dashboards/utils/tableGraph.ts +++ b/ui/src/dashboards/utils/tableGraph.ts @@ -2,12 +2,12 @@ import calculateSize from 'calculate-size' import _ from 'lodash' import {map, reduce, filter} from 'fast.js' +import {CELL_HORIZONTAL_PADDING} from 'src/shared/constants/tableGraph' import { - CELL_HORIZONTAL_PADDING, DEFAULT_TIME_FIELD, DEFAULT_TIME_FORMAT, DEFAULT_PRECISION, -} from 'src/shared/constants/tableGraph' +} from 'src/dashboards/constants' const calculateTimeColumnWidth = timeFormat => { // Force usage of longest format names for ideal measurement diff --git a/ui/src/shared/components/Layout.js b/ui/src/shared/components/Layout.js index b3e80d1f1b..352fa10b0d 100644 --- a/ui/src/shared/components/Layout.js +++ b/ui/src/shared/components/Layout.js @@ -151,6 +151,24 @@ const propTypes = { name: string.isRequired, type: string.isRequired, colors: colorsStringSchema, + tableOptions: shape({ + verticalTimeAxis: bool.isRequired, + sortBy: shape({ + internalName: string.isRequired, + displayName: string.isRequired, + visible: bool.isRequired, + }).isRequired, + wrapping: string.isRequired, + fixFirstColumn: bool.isRequired, + }), + timeFormat: string.isRequired, + fieldOptions: arrayOf( + shape({ + internalName: string.isRequired, + displayName: string.isRequired, + visible: bool.isRequired, + }).isRequired + ), }).isRequired, templates: arrayOf(shape()), host: string, diff --git a/ui/src/shared/components/LayoutRenderer.js b/ui/src/shared/components/LayoutRenderer.js index 1308bdf4d0..42f46a50cc 100644 --- a/ui/src/shared/components/LayoutRenderer.js +++ b/ui/src/shared/components/LayoutRenderer.js @@ -173,6 +173,24 @@ LayoutRenderer.propTypes = { i: string.isRequired, name: string.isRequired, type: string.isRequired, + timeFormat: string.isRequired, + tableOptions: shape({ + verticalTimeAxis: bool.isRequired, + sortBy: shape({ + internalName: string.isRequired, + displayName: string.isRequired, + visible: bool.isRequired, + }).isRequired, + wrapping: string.isRequired, + fixFirstColumn: bool.isRequired, + }), + fieldOptions: arrayOf( + shape({ + internalName: string.isRequired, + displayName: string.isRequired, + visible: bool.isRequired, + }).isRequired + ), }).isRequired ), templates: arrayOf(shape()), diff --git a/ui/src/shared/components/RefreshingGraph.js b/ui/src/shared/components/RefreshingGraph.js index 9d0aba8387..63275655c2 100644 --- a/ui/src/shared/components/RefreshingGraph.js +++ b/ui/src/shared/components/RefreshingGraph.js @@ -168,13 +168,22 @@ RefreshingGraph.propTypes = { colors: colorsStringSchema, cellID: string, inView: bool, - tableOptions: shape({}), + tableOptions: shape({ + verticalTimeAxis: bool.isRequired, + sortBy: shape({ + internalName: string.isRequired, + displayName: string.isRequired, + visible: bool.isRequired, + }).isRequired, + wrapping: string.isRequired, + fixFirstColumn: bool.isRequired, + }), fieldOptions: arrayOf( shape({ internalName: string.isRequired, displayName: string.isRequired, visible: bool.isRequired, - }) + }).isRequired ), timeFormat: string.isRequired, hoverTime: string.isRequired, diff --git a/ui/src/shared/components/TableGraph.js b/ui/src/shared/components/TableGraph.js index e9ab526272..1e32298f30 100644 --- a/ui/src/shared/components/TableGraph.js +++ b/ui/src/shared/components/TableGraph.js @@ -17,19 +17,16 @@ import { transformTableData, } from 'src/dashboards/utils/tableGraph' import {updateFieldOptions} from 'src/dashboards/actions/cellEditorOverlay' - +import {DEFAULT_TIME_FIELD, DEFAULT_TIME_FORMAT} from 'src/dashboards/constants' import { ASCENDING, DESCENDING, NULL_HOVER_TIME, NULL_ARRAY_INDEX, - DEFAULT_TIME_FIELD, - DEFAULT_TIME_FORMAT, - DEFAULT_SORT_DIRECTION, DEFAULT_FIX_FIRST_COLUMN, DEFAULT_VERTICAL_TIME_AXIS, + DEFAULT_SORT_DIRECTION, } from 'src/shared/constants/tableGraph' - import {generateThresholdsListHexs} from 'shared/constants/colorOperations' import {colorsStringSchema} from 'shared/schemas' import {ErrorHandling} from 'src/shared/decorators/errors' @@ -441,7 +438,7 @@ TableGraph.propTypes = { visible: bool.isRequired, }).isRequired, wrapping: string.isRequired, - fixFirstColumn: bool, + fixFirstColumn: bool.isRequired, }), timeFormat: string.isRequired, fieldOptions: arrayOf( diff --git a/ui/src/shared/constants/tableGraph.js b/ui/src/shared/constants/tableGraph.js index af4b969eab..c32309ed78 100644 --- a/ui/src/shared/constants/tableGraph.js +++ b/ui/src/shared/constants/tableGraph.js @@ -2,18 +2,6 @@ export const NULL_ARRAY_INDEX = -1 export const NULL_HOVER_TIME = '0' -export const TIME_FORMAT_TOOLTIP_LINK = - 'http://momentjs.com/docs/#/parsing/string-format/' - -export const DEFAULT_PRECISION = 0 - -export const DEFAULT_TIME_FIELD = { - internalName: 'time', - displayName: '', - visible: true, - precision: DEFAULT_PRECISION, -} - export const ASCENDING = 'asc' export const DESCENDING = 'desc' export const DEFAULT_SORT_DIRECTION = ASCENDING @@ -22,24 +10,3 @@ export const DEFAULT_FIX_FIRST_COLUMN = true export const DEFAULT_VERTICAL_TIME_AXIS = true export const CELL_HORIZONTAL_PADDING = 30 - -export const DEFAULT_TIME_FORMAT = 'MM/DD/YYYY HH:mm:ss' -export const TIME_FORMAT_CUSTOM = 'Custom' - -export const FORMAT_OPTIONS = [ - {text: DEFAULT_TIME_FORMAT}, - {text: 'MM/DD/YYYY HH:mm:ss.SSS'}, - {text: 'YYYY-MM-DD HH:mm:ss'}, - {text: 'HH:mm:ss'}, - {text: 'HH:mm:ss.SSS'}, - {text: 'MMMM D, YYYY HH:mm:ss'}, - {text: 'dddd, MMMM D, YYYY HH:mm:ss'}, - {text: TIME_FORMAT_CUSTOM}, -] - -export const DEFAULT_TABLE_OPTIONS = { - verticalTimeAxis: DEFAULT_VERTICAL_TIME_AXIS, - sortBy: DEFAULT_TIME_FIELD, - wrapping: 'truncate', - fixFirstColumn: DEFAULT_FIX_FIRST_COLUMN, -} diff --git a/ui/test/dashboards/components/GraphOptionsTimeFormat.test.tsx b/ui/test/dashboards/components/GraphOptionsTimeFormat.test.tsx index 0ecd160d91..bffbba1ab8 100644 --- a/ui/test/dashboards/components/GraphOptionsTimeFormat.test.tsx +++ b/ui/test/dashboards/components/GraphOptionsTimeFormat.test.tsx @@ -8,7 +8,7 @@ import QuestionMarkTooltip from 'src/shared/components/QuestionMarkTooltip' import { TIME_FORMAT_CUSTOM, TIME_FORMAT_TOOLTIP_LINK, -} from 'src/shared/constants/tableGraph' +} from 'src/dashboards/constants' const setup = (override = {}) => { const props = { diff --git a/ui/test/dashboards/reducers/cellEditorOverlay.test.js b/ui/test/dashboards/reducers/cellEditorOverlay.test.js index d9fd5c1c18..1fe88c7d77 100644 --- a/ui/test/dashboards/reducers/cellEditorOverlay.test.js +++ b/ui/test/dashboards/reducers/cellEditorOverlay.test.js @@ -11,7 +11,7 @@ import { updateLineColors, updateAxes, } from 'src/dashboards/actions/cellEditorOverlay' -import {DEFAULT_TABLE_OPTIONS} from 'src/shared/constants/tableGraph' +import {DEFAULT_TABLE_OPTIONS} from 'src/dashboards/constants' import { validateGaugeColors, diff --git a/ui/test/utils/timeSeriesTransformers.test.js b/ui/test/utils/timeSeriesTransformers.test.js index 906f9253e4..bc635f632d 100644 --- a/ui/test/utils/timeSeriesTransformers.test.js +++ b/ui/test/utils/timeSeriesTransformers.test.js @@ -8,10 +8,8 @@ import { transformTableData, } from 'src/dashboards/utils/tableGraph' -import { - DEFAULT_SORT_DIRECTION, - DEFAULT_TIME_FORMAT, -} from 'src/shared/constants/tableGraph' +import {DEFAULT_SORT_DIRECTION} from 'src/shared/constants/tableGraph' +import {DEFAULT_TIME_FORMAT} from 'src/dashboards/constants' describe('timeSeriesToDygraph', () => { it('parses a raw InfluxDB response into a dygraph friendly data format', () => { From 2656f610d5793704a142d8a50e30b21701dd616a Mon Sep 17 00:00:00 2001 From: Brandon Farmer Date: Thu, 26 Apr 2018 16:23:38 -0700 Subject: [PATCH 35/48] Return correct value in column for falsey data Co-authored-by: Brandon Farmer Co-authored-by: Deniz Kusefoglu --- ui/src/dashboards/utils/tableGraph.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/dashboards/utils/tableGraph.ts b/ui/src/dashboards/utils/tableGraph.ts index a31e3af9dd..881d12c2b6 100644 --- a/ui/src/dashboards/utils/tableGraph.ts +++ b/ui/src/dashboards/utils/tableGraph.ts @@ -147,7 +147,7 @@ export const orderTableColumns = (data, fieldNames) => { }) const filteredFieldSortOrder = filter(fieldsSortOrder, f => f !== -1) const orderedData = map(data, row => { - return row.map((v, j, arr) => arr[filteredFieldSortOrder[j]] || v) + return row.map((__, j, arr) => arr[filteredFieldSortOrder[j]]) }) return orderedData[0].length ? orderedData : [[]] } From bfdce4594fe56b477dac53d1d80a3d88ffbb8928 Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Wed, 25 Apr 2018 10:45:56 -0700 Subject: [PATCH 36/48] Fix formatting for body sources missing newlines --- ui/src/ifql/components/BodyBuilder.tsx | 23 ++++++++++------ ui/src/ifql/components/ExpressionNode.tsx | 14 +++++----- ui/src/ifql/containers/IFQLPage.tsx | 32 +++++++++++++++++------ ui/src/style/components/func-node.scss | 1 - 4 files changed, 45 insertions(+), 25 deletions(-) diff --git a/ui/src/ifql/components/BodyBuilder.tsx b/ui/src/ifql/components/BodyBuilder.tsx index a6d8d6f647..e81855fa64 100644 --- a/ui/src/ifql/components/BodyBuilder.tsx +++ b/ui/src/ifql/components/BodyBuilder.tsx @@ -21,17 +21,24 @@ class BodyBuilder extends PureComponent { return b.declarations.map(d => { if (d.funcs) { return ( - +
    +
    {d.name} =
    + +
    ) } - return
    {b.source}
    + return ( +
    + {b.source} +
    + ) }) } diff --git a/ui/src/ifql/components/ExpressionNode.tsx b/ui/src/ifql/components/ExpressionNode.tsx index c945acc3b7..8ef81749bb 100644 --- a/ui/src/ifql/components/ExpressionNode.tsx +++ b/ui/src/ifql/components/ExpressionNode.tsx @@ -22,14 +22,6 @@ class ExpressionNode extends PureComponent { {({onDeleteFuncNode, onAddNode, onChangeArg, onGenerateScript}) => { return (
    -

    - -

    {funcs.map(func => ( { onGenerateScript={onGenerateScript} /> ))} +
    ) }} diff --git a/ui/src/ifql/containers/IFQLPage.tsx b/ui/src/ifql/containers/IFQLPage.tsx index db8ba47c07..2ad7d99b42 100644 --- a/ui/src/ifql/containers/IFQLPage.tsx +++ b/ui/src/ifql/containers/IFQLPage.tsx @@ -45,7 +45,7 @@ export class IFQLPage extends PureComponent { ast: null, suggestions: [], script: - 'foo = "baz"\n\nfoo = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\nbar = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\n', + 'baz = "baz"\n\nfoo = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\nbar = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\n', } } @@ -234,7 +234,9 @@ export class IFQLPage extends PureComponent { declarationID: string ): void => { const script = this.state.body.reduce((acc, body) => { - if (body.id === bodyID) { + const {id, source, funcs} = body + + if (id === bodyID) { const declaration = body.declarations.find(d => d.id === declarationID) if (declaration) { return `${acc}${declaration.name} = ${this.appendFunc( @@ -243,10 +245,10 @@ export class IFQLPage extends PureComponent { )}` } - return `${acc}${this.appendFunc(body.funcs, name)}` + return `${acc}${this.appendFunc(funcs, name)}` } - return `${acc}${body.source}` + return `${acc}${this.formatSource(source)}` }, '') this.getASTResponse(script) @@ -262,7 +264,7 @@ export class IFQLPage extends PureComponent { const script = this.state.body .map((body, bodyIndex) => { if (body.id !== bodyID) { - return body.source + return this.formatSource(body.source) } const isLast = bodyIndex === this.state.body.length - 1 @@ -278,24 +280,38 @@ export class IFQLPage extends PureComponent { const functions = declaration.funcs.filter(f => f.id !== funcID) const s = this.funcsToSource(functions) - return `${declaration.name} = ${this.parseLastSource(s, isLast)}` + return `${declaration.name} = ${this.formatLastSource(s, isLast)}` } const funcs = body.funcs.filter(f => f.id !== funcID) const source = this.funcsToSource(funcs) - return this.parseLastSource(source, isLast) + return this.formatLastSource(source, isLast) }) .join('') this.getASTResponse(script) } + private formatSource = (source: string): string => { + // currently a bug in the AST which does not add newlines to literal variable assignment bodies + if (!source.match(/\n\n/)) { + return `${source}\n\n` + } + + return `${source}` + } + // formats the last line of a body string to include two new lines - private parseLastSource = (source: string, isLast: boolean): string => { + private formatLastSource = (source: string, isLast: boolean): string => { if (isLast) { return `${source}` } + // currently a bug in the AST which does not add newlines to literal variable assignment bodies + if (!source.match(/\n\n/)) { + return `${source}\n\n` + } + return `${source}\n\n` } diff --git a/ui/src/style/components/func-node.scss b/ui/src/style/components/func-node.scss index 84c3b13742..82dcfed978 100644 --- a/ui/src/style/components/func-node.scss +++ b/ui/src/style/components/func-node.scss @@ -14,7 +14,6 @@ width: auto; display: flex; color: $ix-text-default; - text-transform: uppercase; margin-bottom: $ix-marg-a; font-family: $ix-text-font; font-weight: 500; From 59ada00bc90d5475a76afcde6add52817be2dab0 Mon Sep 17 00:00:00 2001 From: ebb-tide Date: Fri, 27 Apr 2018 16:36:02 -0700 Subject: [PATCH 37/48] Put decimal places with isenforced and digits on backend --- bolt/change_interval_to_duration.go | 8 - bolt/internal/internal.go | 49 +++-- bolt/internal/internal.pb.go | 323 +++++++++++++++------------- bolt/internal/internal.proto | 9 +- chronograf.go | 36 ++-- 5 files changed, 234 insertions(+), 191 deletions(-) diff --git a/bolt/change_interval_to_duration.go b/bolt/change_interval_to_duration.go index 1ab06be3a0..d2801b32fe 100644 --- a/bolt/change_interval_to_duration.go +++ b/bolt/change_interval_to_duration.go @@ -344,7 +344,6 @@ func (m *DashboardCell) GetTableOptions() *TableOptions { } type TableOptions struct { - TimeFormat string `protobuf:"bytes,1,opt,name=timeFormat,proto3" json:"timeFormat,omitempty"` VerticalTimeAxis bool `protobuf:"varint,2,opt,name=verticalTimeAxis,proto3" json:"verticalTimeAxis,omitempty"` SortBy *RenamableField `protobuf:"bytes,3,opt,name=sortBy" json:"sortBy,omitempty"` Wrapping string `protobuf:"bytes,4,opt,name=wrapping,proto3" json:"wrapping,omitempty"` @@ -357,13 +356,6 @@ func (m *TableOptions) String() string { return proto.CompactTextStri func (*TableOptions) ProtoMessage() {} func (*TableOptions) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{3} } -func (m *TableOptions) GetTimeFormat() string { - if m != nil { - return m.TimeFormat - } - return "" -} - func (m *TableOptions) GetVerticalTimeAxis() bool { if m != nil { return m.VerticalTimeAxis diff --git a/bolt/internal/internal.go b/bolt/internal/internal.go index 51722f2e4b..e20af1bd1d 100644 --- a/bolt/internal/internal.go +++ b/bolt/internal/internal.go @@ -280,13 +280,17 @@ func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) { FixFirstColumn: c.TableOptions.FixFirstColumn, } + decimalPlaces := &DecimalPlaces{ + IsEnforced: c.DecimalPlaces.IsEnforced, + Digits: c.DecimalPlaces.Digits, + } + fieldOptions := make([]*RenamableField, len(c.FieldOptions)) for i, field := range c.FieldOptions { fieldOptions[i] = &RenamableField{ InternalName: field.InternalName, DisplayName: field.DisplayName, Visible: field.Visible, - Precision: field.Precision, } } @@ -305,9 +309,10 @@ func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) { Type: c.Legend.Type, Orientation: c.Legend.Orientation, }, - TableOptions: tableOptions, - FieldOptions: fieldOptions, - TimeFormat: c.TimeFormat, + TableOptions: tableOptions, + FieldOptions: fieldOptions, + TimeFormat: c.TimeFormat, + DecimalPlaces: decimalPlaces, } } templates := make([]*Template, len(d.Templates)) @@ -454,7 +459,12 @@ func UnmarshalDashboard(data []byte, d *chronograf.Dashboard) error { fieldOptions[i].InternalName = field.InternalName fieldOptions[i].DisplayName = field.DisplayName fieldOptions[i].Visible = field.Visible - fieldOptions[i].Precision = field.Precision + } + + decimalPlaces := chronograf.DecimalPlaces{} + if c.DecimalPlaces != nil { + decimalPlaces.IsEnforced = c.DecimalPlaces.IsEnforced + decimalPlaces.Digits = c.DecimalPlaces.Digits } // FIXME: this is merely for legacy cells and @@ -465,20 +475,21 @@ func UnmarshalDashboard(data []byte, d *chronograf.Dashboard) error { } cells[i] = chronograf.DashboardCell{ - ID: c.ID, - X: c.X, - Y: c.Y, - W: c.W, - H: c.H, - Name: c.Name, - Queries: queries, - Type: cellType, - Axes: axes, - CellColors: colors, - Legend: legend, - TableOptions: tableOptions, - FieldOptions: fieldOptions, - TimeFormat: c.TimeFormat, + ID: c.ID, + X: c.X, + Y: c.Y, + W: c.W, + H: c.H, + Name: c.Name, + Queries: queries, + Type: cellType, + Axes: axes, + CellColors: colors, + Legend: legend, + TableOptions: tableOptions, + FieldOptions: fieldOptions, + TimeFormat: c.TimeFormat, + DecimalPlaces: decimalPlaces, } } diff --git a/bolt/internal/internal.pb.go b/bolt/internal/internal.pb.go index f4edc8b351..48177f7e10 100644 --- a/bolt/internal/internal.pb.go +++ b/bolt/internal/internal.pb.go @@ -11,6 +11,7 @@ It has these top-level messages: Source Dashboard DashboardCell + DecimalPlaces TableOptions RenamableField Color @@ -220,20 +221,21 @@ func (m *Dashboard) GetOrganization() string { } type DashboardCell struct { - X int32 `protobuf:"varint,1,opt,name=x,proto3" json:"x,omitempty"` - Y int32 `protobuf:"varint,2,opt,name=y,proto3" json:"y,omitempty"` - W int32 `protobuf:"varint,3,opt,name=w,proto3" json:"w,omitempty"` - H int32 `protobuf:"varint,4,opt,name=h,proto3" json:"h,omitempty"` - Queries []*Query `protobuf:"bytes,5,rep,name=queries" json:"queries,omitempty"` - Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` - Type string `protobuf:"bytes,7,opt,name=type,proto3" json:"type,omitempty"` - ID string `protobuf:"bytes,8,opt,name=ID,proto3" json:"ID,omitempty"` - Axes map[string]*Axis `protobuf:"bytes,9,rep,name=axes" json:"axes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"` - Colors []*Color `protobuf:"bytes,10,rep,name=colors" json:"colors,omitempty"` - Legend *Legend `protobuf:"bytes,11,opt,name=legend" json:"legend,omitempty"` - TableOptions *TableOptions `protobuf:"bytes,12,opt,name=tableOptions" json:"tableOptions,omitempty"` - FieldOptions []*RenamableField `protobuf:"bytes,13,rep,name=fieldOptions" json:"fieldOptions,omitempty"` - TimeFormat string `protobuf:"bytes,14,opt,name=timeFormat,proto3" json:"timeFormat,omitempty"` + X int32 `protobuf:"varint,1,opt,name=x,proto3" json:"x,omitempty"` + Y int32 `protobuf:"varint,2,opt,name=y,proto3" json:"y,omitempty"` + W int32 `protobuf:"varint,3,opt,name=w,proto3" json:"w,omitempty"` + H int32 `protobuf:"varint,4,opt,name=h,proto3" json:"h,omitempty"` + Queries []*Query `protobuf:"bytes,5,rep,name=queries" json:"queries,omitempty"` + Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` + Type string `protobuf:"bytes,7,opt,name=type,proto3" json:"type,omitempty"` + ID string `protobuf:"bytes,8,opt,name=ID,proto3" json:"ID,omitempty"` + Axes map[string]*Axis `protobuf:"bytes,9,rep,name=axes" json:"axes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"` + Colors []*Color `protobuf:"bytes,10,rep,name=colors" json:"colors,omitempty"` + Legend *Legend `protobuf:"bytes,11,opt,name=legend" json:"legend,omitempty"` + TableOptions *TableOptions `protobuf:"bytes,12,opt,name=tableOptions" json:"tableOptions,omitempty"` + FieldOptions []*RenamableField `protobuf:"bytes,13,rep,name=fieldOptions" json:"fieldOptions,omitempty"` + TimeFormat string `protobuf:"bytes,14,opt,name=timeFormat,proto3" json:"timeFormat,omitempty"` + DecimalPlaces *DecimalPlaces `protobuf:"bytes,15,opt,name=decimalPlaces" json:"decimalPlaces,omitempty"` } func (m *DashboardCell) Reset() { *m = DashboardCell{} } @@ -339,6 +341,37 @@ func (m *DashboardCell) GetTimeFormat() string { return "" } +func (m *DashboardCell) GetDecimalPlaces() *DecimalPlaces { + if m != nil { + return m.DecimalPlaces + } + return nil +} + +type DecimalPlaces struct { + IsEnforced bool `protobuf:"varint,1,opt,name=isEnforced,proto3" json:"isEnforced,omitempty"` + Digits int32 `protobuf:"varint,2,opt,name=digits,proto3" json:"digits,omitempty"` +} + +func (m *DecimalPlaces) Reset() { *m = DecimalPlaces{} } +func (m *DecimalPlaces) String() string { return proto.CompactTextString(m) } +func (*DecimalPlaces) ProtoMessage() {} +func (*DecimalPlaces) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{3} } + +func (m *DecimalPlaces) GetIsEnforced() bool { + if m != nil { + return m.IsEnforced + } + return false +} + +func (m *DecimalPlaces) GetDigits() int32 { + if m != nil { + return m.Digits + } + return 0 +} + type TableOptions struct { VerticalTimeAxis bool `protobuf:"varint,2,opt,name=verticalTimeAxis,proto3" json:"verticalTimeAxis,omitempty"` SortBy *RenamableField `protobuf:"bytes,3,opt,name=sortBy" json:"sortBy,omitempty"` @@ -349,7 +382,7 @@ type TableOptions struct { func (m *TableOptions) Reset() { *m = TableOptions{} } func (m *TableOptions) String() string { return proto.CompactTextString(m) } func (*TableOptions) ProtoMessage() {} -func (*TableOptions) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{3} } +func (*TableOptions) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{4} } func (m *TableOptions) GetVerticalTimeAxis() bool { if m != nil { @@ -383,13 +416,12 @@ type RenamableField struct { InternalName string `protobuf:"bytes,1,opt,name=internalName,proto3" json:"internalName,omitempty"` DisplayName string `protobuf:"bytes,2,opt,name=displayName,proto3" json:"displayName,omitempty"` Visible bool `protobuf:"varint,3,opt,name=visible,proto3" json:"visible,omitempty"` - Precision int32 `protobuf:"varint,4,opt,name=precision,proto3" json:"precision,omitempty"` } func (m *RenamableField) Reset() { *m = RenamableField{} } func (m *RenamableField) String() string { return proto.CompactTextString(m) } func (*RenamableField) ProtoMessage() {} -func (*RenamableField) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{4} } +func (*RenamableField) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{5} } func (m *RenamableField) GetInternalName() string { if m != nil { @@ -412,13 +444,6 @@ func (m *RenamableField) GetVisible() bool { return false } -func (m *RenamableField) GetPrecision() int32 { - if m != nil { - return m.Precision - } - return 0 -} - type Color struct { ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` Type string `protobuf:"bytes,2,opt,name=Type,proto3" json:"Type,omitempty"` @@ -430,7 +455,7 @@ type Color struct { func (m *Color) Reset() { *m = Color{} } func (m *Color) String() string { return proto.CompactTextString(m) } func (*Color) ProtoMessage() {} -func (*Color) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{5} } +func (*Color) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{6} } func (m *Color) GetID() string { if m != nil { @@ -475,7 +500,7 @@ type Legend struct { func (m *Legend) Reset() { *m = Legend{} } func (m *Legend) String() string { return proto.CompactTextString(m) } func (*Legend) ProtoMessage() {} -func (*Legend) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{6} } +func (*Legend) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{7} } func (m *Legend) GetType() string { if m != nil { @@ -504,7 +529,7 @@ type Axis struct { func (m *Axis) Reset() { *m = Axis{} } func (m *Axis) String() string { return proto.CompactTextString(m) } func (*Axis) ProtoMessage() {} -func (*Axis) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{7} } +func (*Axis) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{8} } func (m *Axis) GetLegacyBounds() []int64 { if m != nil { @@ -567,7 +592,7 @@ type Template struct { func (m *Template) Reset() { *m = Template{} } func (m *Template) String() string { return proto.CompactTextString(m) } func (*Template) ProtoMessage() {} -func (*Template) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{8} } +func (*Template) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{9} } func (m *Template) GetID() string { if m != nil { @@ -620,7 +645,7 @@ type TemplateValue struct { func (m *TemplateValue) Reset() { *m = TemplateValue{} } func (m *TemplateValue) String() string { return proto.CompactTextString(m) } func (*TemplateValue) ProtoMessage() {} -func (*TemplateValue) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{9} } +func (*TemplateValue) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{10} } func (m *TemplateValue) GetType() string { if m != nil { @@ -655,7 +680,7 @@ type TemplateQuery struct { func (m *TemplateQuery) Reset() { *m = TemplateQuery{} } func (m *TemplateQuery) String() string { return proto.CompactTextString(m) } func (*TemplateQuery) ProtoMessage() {} -func (*TemplateQuery) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{10} } +func (*TemplateQuery) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{11} } func (m *TemplateQuery) GetCommand() string { if m != nil { @@ -714,7 +739,7 @@ type Server struct { func (m *Server) Reset() { *m = Server{} } func (m *Server) String() string { return proto.CompactTextString(m) } func (*Server) ProtoMessage() {} -func (*Server) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{11} } +func (*Server) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{12} } func (m *Server) GetID() int64 { if m != nil { @@ -790,7 +815,7 @@ type Layout struct { func (m *Layout) Reset() { *m = Layout{} } func (m *Layout) String() string { return proto.CompactTextString(m) } func (*Layout) ProtoMessage() {} -func (*Layout) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{12} } +func (*Layout) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{13} } func (m *Layout) GetID() string { if m != nil { @@ -844,7 +869,7 @@ type Cell struct { func (m *Cell) Reset() { *m = Cell{} } func (m *Cell) String() string { return proto.CompactTextString(m) } func (*Cell) ProtoMessage() {} -func (*Cell) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{13} } +func (*Cell) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{14} } func (m *Cell) GetX() int32 { if m != nil { @@ -938,7 +963,7 @@ type Query struct { func (m *Query) Reset() { *m = Query{} } func (m *Query) String() string { return proto.CompactTextString(m) } func (*Query) ProtoMessage() {} -func (*Query) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{14} } +func (*Query) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{15} } func (m *Query) GetCommand() string { if m != nil { @@ -1012,7 +1037,7 @@ type TimeShift struct { func (m *TimeShift) Reset() { *m = TimeShift{} } func (m *TimeShift) String() string { return proto.CompactTextString(m) } func (*TimeShift) ProtoMessage() {} -func (*TimeShift) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{15} } +func (*TimeShift) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{16} } func (m *TimeShift) GetLabel() string { if m != nil { @@ -1043,7 +1068,7 @@ type Range struct { func (m *Range) Reset() { *m = Range{} } func (m *Range) String() string { return proto.CompactTextString(m) } func (*Range) ProtoMessage() {} -func (*Range) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{16} } +func (*Range) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{17} } func (m *Range) GetUpper() int64 { if m != nil { @@ -1069,7 +1094,7 @@ type AlertRule struct { func (m *AlertRule) Reset() { *m = AlertRule{} } func (m *AlertRule) String() string { return proto.CompactTextString(m) } func (*AlertRule) ProtoMessage() {} -func (*AlertRule) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{17} } +func (*AlertRule) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{18} } func (m *AlertRule) GetID() string { if m != nil { @@ -1111,7 +1136,7 @@ type User struct { func (m *User) Reset() { *m = User{} } func (m *User) String() string { return proto.CompactTextString(m) } func (*User) ProtoMessage() {} -func (*User) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{18} } +func (*User) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{19} } func (m *User) GetID() uint64 { if m != nil { @@ -1163,7 +1188,7 @@ type Role struct { func (m *Role) Reset() { *m = Role{} } func (m *Role) String() string { return proto.CompactTextString(m) } func (*Role) ProtoMessage() {} -func (*Role) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{19} } +func (*Role) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{20} } func (m *Role) GetOrganization() string { if m != nil { @@ -1190,7 +1215,7 @@ type Mapping struct { func (m *Mapping) Reset() { *m = Mapping{} } func (m *Mapping) String() string { return proto.CompactTextString(m) } func (*Mapping) ProtoMessage() {} -func (*Mapping) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{20} } +func (*Mapping) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{21} } func (m *Mapping) GetProvider() string { if m != nil { @@ -1236,7 +1261,7 @@ type Organization struct { func (m *Organization) Reset() { *m = Organization{} } func (m *Organization) String() string { return proto.CompactTextString(m) } func (*Organization) ProtoMessage() {} -func (*Organization) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{21} } +func (*Organization) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{22} } func (m *Organization) GetID() string { if m != nil { @@ -1266,7 +1291,7 @@ type Config struct { func (m *Config) Reset() { *m = Config{} } func (m *Config) String() string { return proto.CompactTextString(m) } func (*Config) ProtoMessage() {} -func (*Config) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{22} } +func (*Config) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{23} } func (m *Config) GetAuth() *AuthConfig { if m != nil { @@ -1282,7 +1307,7 @@ type AuthConfig struct { func (m *AuthConfig) Reset() { *m = AuthConfig{} } func (m *AuthConfig) String() string { return proto.CompactTextString(m) } func (*AuthConfig) ProtoMessage() {} -func (*AuthConfig) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{23} } +func (*AuthConfig) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{24} } func (m *AuthConfig) GetSuperAdminNewUsers() bool { if m != nil { @@ -1299,7 +1324,7 @@ type BuildInfo struct { func (m *BuildInfo) Reset() { *m = BuildInfo{} } func (m *BuildInfo) String() string { return proto.CompactTextString(m) } func (*BuildInfo) ProtoMessage() {} -func (*BuildInfo) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{24} } +func (*BuildInfo) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{25} } func (m *BuildInfo) GetVersion() string { if m != nil { @@ -1319,6 +1344,7 @@ func init() { proto.RegisterType((*Source)(nil), "internal.Source") proto.RegisterType((*Dashboard)(nil), "internal.Dashboard") proto.RegisterType((*DashboardCell)(nil), "internal.DashboardCell") + proto.RegisterType((*DecimalPlaces)(nil), "internal.DecimalPlaces") proto.RegisterType((*TableOptions)(nil), "internal.TableOptions") proto.RegisterType((*RenamableField)(nil), "internal.RenamableField") proto.RegisterType((*Color)(nil), "internal.Color") @@ -1346,107 +1372,110 @@ func init() { func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) } var fileDescriptorInternal = []byte{ - // 1627 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xdd, 0x8f, 0xe3, 0x48, - 0x11, 0x97, 0x13, 0x3b, 0x89, 0x2b, 0xd9, 0x61, 0xd4, 0xac, 0xee, 0xcc, 0x81, 0x50, 0xb0, 0xf8, - 0x08, 0x1f, 0x37, 0x9c, 0xe6, 0x84, 0x84, 0x4e, 0xc7, 0x49, 0x99, 0x09, 0x7b, 0xcc, 0xee, 0xec, - 0xce, 0x6c, 0x67, 0x66, 0x78, 0x42, 0xa7, 0x4e, 0xd2, 0x49, 0x5a, 0xe7, 0xd8, 0xa6, 0x6d, 0xcf, - 0xc4, 0x3c, 0xf3, 0xcc, 0x2b, 0x6f, 0x48, 0x48, 0xf0, 0x0f, 0x20, 0x1e, 0x91, 0x78, 0xe7, 0x1f, - 0x82, 0x47, 0x54, 0xfd, 0x61, 0x3b, 0x93, 0xec, 0x6a, 0x91, 0xd0, 0xbd, 0xf5, 0xaf, 0xaa, 0x52, - 0xdd, 0x55, 0x5d, 0xf5, 0xeb, 0x72, 0xe0, 0x48, 0xc4, 0x39, 0x97, 0x31, 0x8b, 0x4e, 0x52, 0x99, - 0xe4, 0x09, 0xe9, 0x59, 0x1c, 0xfe, 0xbe, 0x0d, 0x9d, 0x69, 0x52, 0xc8, 0x39, 0x27, 0x47, 0xd0, - 0xba, 0x98, 0x04, 0xce, 0xd0, 0x19, 0xb5, 0x69, 0xeb, 0x62, 0x42, 0x08, 0xb8, 0xaf, 0xd8, 0x86, - 0x07, 0xad, 0xa1, 0x33, 0xf2, 0xa9, 0x5a, 0xa3, 0xec, 0xa6, 0x4c, 0x79, 0xd0, 0xd6, 0x32, 0x5c, - 0x93, 0x0f, 0xa0, 0x77, 0x9b, 0xa1, 0xb7, 0x0d, 0x0f, 0x5c, 0x25, 0xaf, 0x30, 0xea, 0xae, 0x59, - 0x96, 0x3d, 0x24, 0x72, 0x11, 0x78, 0x5a, 0x67, 0x31, 0x39, 0x86, 0xf6, 0x2d, 0xbd, 0x0c, 0x3a, - 0x4a, 0x8c, 0x4b, 0x12, 0x40, 0x77, 0xc2, 0x97, 0xac, 0x88, 0xf2, 0xa0, 0x3b, 0x74, 0x46, 0x3d, - 0x6a, 0x21, 0xfa, 0xb9, 0xe1, 0x11, 0x5f, 0x49, 0xb6, 0x0c, 0x7a, 0xda, 0x8f, 0xc5, 0xe4, 0x04, - 0xc8, 0x45, 0x9c, 0xf1, 0x79, 0x21, 0xf9, 0xf4, 0x4b, 0x91, 0xde, 0x71, 0x29, 0x96, 0x65, 0xe0, - 0x2b, 0x07, 0x07, 0x34, 0xb8, 0xcb, 0x4b, 0x9e, 0x33, 0xdc, 0x1b, 0x94, 0x2b, 0x0b, 0x49, 0x08, - 0x83, 0xe9, 0x9a, 0x49, 0xbe, 0x98, 0xf2, 0xb9, 0xe4, 0x79, 0xd0, 0x57, 0xea, 0x1d, 0x19, 0xda, - 0x5c, 0xc9, 0x15, 0x8b, 0xc5, 0xef, 0x58, 0x2e, 0x92, 0x38, 0x18, 0x68, 0x9b, 0xa6, 0x0c, 0xb3, - 0x44, 0x93, 0x88, 0x07, 0x4f, 0x74, 0x96, 0x70, 0x4d, 0xbe, 0x05, 0xbe, 0x09, 0x86, 0x5e, 0x07, - 0x47, 0x4a, 0x51, 0x0b, 0xc2, 0xbf, 0x3b, 0xe0, 0x4f, 0x58, 0xb6, 0x9e, 0x25, 0x4c, 0x2e, 0xde, - 0xe9, 0x26, 0x3e, 0x04, 0x6f, 0xce, 0xa3, 0x28, 0x0b, 0xda, 0xc3, 0xf6, 0xa8, 0x7f, 0xfa, 0xfe, - 0x49, 0x75, 0xc5, 0x95, 0x9f, 0x73, 0x1e, 0x45, 0x54, 0x5b, 0x91, 0x8f, 0xc0, 0xcf, 0xf9, 0x26, - 0x8d, 0x58, 0xce, 0xb3, 0xc0, 0x55, 0x3f, 0x21, 0xf5, 0x4f, 0x6e, 0x8c, 0x8a, 0xd6, 0x46, 0x7b, - 0x81, 0x7a, 0xfb, 0x81, 0x86, 0x7f, 0x74, 0xe1, 0xc9, 0xce, 0x76, 0x64, 0x00, 0xce, 0x56, 0x9d, - 0xdc, 0xa3, 0xce, 0x16, 0x51, 0xa9, 0x4e, 0xed, 0x51, 0xa7, 0x44, 0xf4, 0xa0, 0x2a, 0xc7, 0xa3, - 0xce, 0x03, 0xa2, 0xb5, 0xaa, 0x17, 0x8f, 0x3a, 0x6b, 0xf2, 0x43, 0xe8, 0xfe, 0xb6, 0xe0, 0x52, - 0xf0, 0x2c, 0xf0, 0xd4, 0xe9, 0xbe, 0x56, 0x9f, 0xee, 0x75, 0xc1, 0x65, 0x49, 0xad, 0x1e, 0xb3, - 0xa1, 0x6a, 0x4d, 0x17, 0x8e, 0x5a, 0xa3, 0x2c, 0xc7, 0xba, 0xec, 0x6a, 0x19, 0xae, 0x4d, 0x16, - 0x75, 0xb5, 0x60, 0x16, 0x7f, 0x06, 0x2e, 0xdb, 0xf2, 0x2c, 0xf0, 0x95, 0xff, 0xef, 0xbc, 0x21, - 0x61, 0x27, 0xe3, 0x2d, 0xcf, 0x7e, 0x19, 0xe7, 0xb2, 0xa4, 0xca, 0x9c, 0xfc, 0x00, 0x3a, 0xf3, - 0x24, 0x4a, 0x64, 0x16, 0xc0, 0xe3, 0x83, 0x9d, 0xa3, 0x9c, 0x1a, 0x35, 0x19, 0x41, 0x27, 0xe2, - 0x2b, 0x1e, 0x2f, 0x54, 0xdd, 0xf4, 0x4f, 0x8f, 0x6b, 0xc3, 0x4b, 0x25, 0xa7, 0x46, 0x4f, 0x3e, - 0x81, 0x41, 0xce, 0x66, 0x11, 0xbf, 0x4a, 0x31, 0x8b, 0x99, 0xaa, 0xa1, 0xfe, 0xe9, 0x7b, 0x8d, - 0xfb, 0x68, 0x68, 0xe9, 0x8e, 0x2d, 0xf9, 0x14, 0x06, 0x4b, 0xc1, 0xa3, 0x85, 0xfd, 0xed, 0x13, - 0x75, 0xa8, 0xa0, 0xfe, 0x2d, 0xe5, 0x31, 0xdb, 0xe0, 0x2f, 0x9e, 0xa1, 0x19, 0xdd, 0xb1, 0x26, - 0xdf, 0x06, 0xc8, 0xc5, 0x86, 0x3f, 0x4b, 0xe4, 0x86, 0xe5, 0xa6, 0x0c, 0x1b, 0x92, 0x0f, 0x3e, - 0x07, 0xbf, 0x8a, 0x1f, 0x1b, 0xf4, 0x4b, 0x5e, 0xaa, 0xdb, 0xf4, 0x29, 0x2e, 0xc9, 0x77, 0xc1, - 0xbb, 0x67, 0x51, 0xa1, 0x2b, 0xb1, 0x7f, 0x7a, 0x54, 0xef, 0x3a, 0xde, 0x8a, 0x8c, 0x6a, 0xe5, - 0x27, 0xad, 0x9f, 0x3b, 0xe1, 0x3f, 0x1c, 0x18, 0x34, 0xa3, 0x20, 0x3f, 0x82, 0xe3, 0x7b, 0x2e, - 0x73, 0x31, 0x67, 0xd1, 0x8d, 0xd8, 0x70, 0xb4, 0x57, 0x5e, 0x7a, 0x74, 0x4f, 0x4e, 0x3e, 0x82, - 0x4e, 0x96, 0xc8, 0xfc, 0xac, 0x54, 0xd5, 0xf2, 0xb6, 0xe8, 0x8c, 0x1d, 0xf2, 0xc3, 0x83, 0x64, - 0x69, 0x2a, 0xe2, 0x95, 0xe5, 0x20, 0x8b, 0xc9, 0xf7, 0xe1, 0x68, 0x29, 0xb6, 0xcf, 0x84, 0xcc, - 0xf2, 0xf3, 0x24, 0x2a, 0x36, 0xb1, 0xaa, 0x9c, 0x1e, 0x7d, 0x24, 0x7d, 0xee, 0xf6, 0x9c, 0xe3, - 0xd6, 0x73, 0xb7, 0xe7, 0x1d, 0x77, 0xc2, 0x3f, 0x38, 0x70, 0xb4, 0xbb, 0x15, 0xf6, 0x83, 0x3d, - 0x85, 0x6a, 0x46, 0x9d, 0x96, 0x1d, 0x19, 0x19, 0x42, 0x7f, 0x21, 0xb2, 0x34, 0x62, 0x65, 0xa3, - 0x5f, 0x9b, 0x22, 0x24, 0x9f, 0x7b, 0x91, 0x89, 0x59, 0xa4, 0x39, 0xb4, 0x47, 0x2d, 0x44, 0x82, - 0x48, 0x25, 0x9f, 0x8b, 0x0c, 0x9b, 0x4d, 0xf7, 0x45, 0x2d, 0x08, 0x57, 0xe0, 0xa9, 0x6a, 0x6b, - 0x70, 0x83, 0x6f, 0xb9, 0x41, 0x31, 0x72, 0xab, 0xc1, 0xc8, 0xc7, 0xd0, 0xfe, 0x15, 0xdf, 0x1a, - 0x92, 0xc6, 0x65, 0xc5, 0x20, 0x6e, 0x83, 0x41, 0x9e, 0x82, 0x77, 0xa7, 0x2e, 0x53, 0x77, 0xb6, - 0x06, 0xe1, 0x67, 0xd0, 0xd1, 0xd5, 0x5a, 0x79, 0x76, 0x1a, 0x9e, 0x87, 0xd0, 0xbf, 0x92, 0x82, - 0xc7, 0xb9, 0xe6, 0x04, 0x13, 0x60, 0x43, 0x14, 0xfe, 0xcd, 0x01, 0x57, 0x5d, 0x62, 0x08, 0x83, - 0x88, 0xaf, 0xd8, 0xbc, 0x3c, 0x4b, 0x8a, 0x78, 0x91, 0x05, 0xce, 0xb0, 0x3d, 0x6a, 0xd3, 0x1d, - 0x19, 0x79, 0x0f, 0x3a, 0x33, 0xad, 0x6d, 0x0d, 0xdb, 0x23, 0x9f, 0x1a, 0x84, 0x47, 0x8b, 0xd8, - 0x8c, 0x47, 0x26, 0x04, 0x0d, 0xd0, 0x3a, 0x95, 0x7c, 0x29, 0xb6, 0x26, 0x0c, 0x83, 0x50, 0x9e, - 0x15, 0x4b, 0x94, 0xeb, 0x48, 0x0c, 0xc2, 0x00, 0x66, 0x2c, 0xab, 0x88, 0x02, 0xd7, 0xe8, 0x39, - 0x9b, 0xb3, 0xc8, 0x32, 0x85, 0x06, 0xe1, 0x3f, 0x1d, 0x7c, 0x5f, 0x34, 0xf3, 0xed, 0x65, 0xf8, - 0x1b, 0xd0, 0x43, 0x56, 0xfc, 0xe2, 0x9e, 0x49, 0x13, 0x70, 0x17, 0xf1, 0x1d, 0x93, 0xe4, 0xa7, - 0xd0, 0x51, 0x25, 0x7f, 0x80, 0x85, 0xad, 0x3b, 0x95, 0x55, 0x6a, 0xcc, 0x2a, 0x9e, 0x72, 0x1b, - 0x3c, 0x55, 0x05, 0xeb, 0x35, 0x83, 0xfd, 0x10, 0x3c, 0x24, 0xbc, 0x52, 0x9d, 0xfe, 0xa0, 0x67, - 0x4d, 0x8b, 0xda, 0x2a, 0xbc, 0x85, 0x27, 0x3b, 0x3b, 0x56, 0x3b, 0x39, 0xbb, 0x3b, 0xd5, 0xed, - 0xeb, 0x9b, 0x76, 0xc5, 0xde, 0xc9, 0x78, 0xc4, 0xe7, 0x39, 0x5f, 0x98, 0x9a, 0xac, 0x70, 0xf8, - 0x67, 0xa7, 0xf6, 0xab, 0xf6, 0xc3, 0x02, 0x9e, 0x27, 0x9b, 0x0d, 0x8b, 0x17, 0xc6, 0xb5, 0x85, - 0x98, 0xb7, 0xc5, 0xcc, 0xb8, 0x6e, 0x2d, 0x66, 0x88, 0x65, 0x6a, 0x6e, 0xb0, 0x25, 0x53, 0xac, - 0x9d, 0x0d, 0x67, 0x59, 0x21, 0xf9, 0x86, 0xc7, 0xb9, 0x49, 0x41, 0x53, 0x44, 0xde, 0x87, 0x6e, - 0xce, 0x56, 0x5f, 0x20, 0xe9, 0x98, 0x9b, 0xcc, 0xd9, 0xea, 0x05, 0x2f, 0xc9, 0x37, 0xc1, 0x57, - 0x34, 0xa6, 0x54, 0xfa, 0x3a, 0x7b, 0x4a, 0xf0, 0x82, 0x97, 0xe1, 0x7f, 0x1c, 0xe8, 0x4c, 0xb9, - 0xbc, 0xe7, 0xf2, 0x9d, 0x1e, 0xce, 0xe6, 0xb8, 0xd2, 0x7e, 0xcb, 0xb8, 0xe2, 0x1e, 0x1e, 0x57, - 0xbc, 0x7a, 0x5c, 0x79, 0x0a, 0xde, 0x54, 0xce, 0x2f, 0x26, 0xea, 0x44, 0x6d, 0xaa, 0x01, 0x56, - 0xe3, 0x78, 0x9e, 0x8b, 0x7b, 0x6e, 0x66, 0x18, 0x83, 0xf6, 0xde, 0xd3, 0xde, 0x81, 0xc1, 0xe1, - 0x7f, 0x1c, 0x65, 0xc2, 0x3f, 0x39, 0xd0, 0xb9, 0x64, 0x65, 0x52, 0xe4, 0x7b, 0x55, 0x3b, 0x84, - 0xfe, 0x38, 0x4d, 0x23, 0x31, 0xdf, 0xe9, 0xd4, 0x86, 0x08, 0x2d, 0x5e, 0x36, 0xee, 0x43, 0xe7, - 0xa2, 0x29, 0x42, 0xba, 0x3f, 0x57, 0x33, 0x86, 0x1e, 0x18, 0x1a, 0x74, 0xaf, 0x47, 0x0b, 0xa5, - 0xc4, 0xa4, 0x8d, 0x8b, 0x3c, 0x59, 0x46, 0xc9, 0x83, 0xca, 0x4e, 0x8f, 0x56, 0x38, 0xfc, 0x57, - 0x0b, 0xdc, 0xaf, 0x6a, 0x2e, 0x18, 0x80, 0x23, 0x4c, 0x71, 0x38, 0xa2, 0x9a, 0x12, 0xba, 0x8d, - 0x29, 0x21, 0x80, 0x6e, 0x29, 0x59, 0xbc, 0xe2, 0x59, 0xd0, 0x53, 0x6c, 0x64, 0xa1, 0xd2, 0xa8, - 0xbe, 0xd3, 0xe3, 0x81, 0x4f, 0x2d, 0xac, 0xfa, 0x08, 0x1a, 0x7d, 0xf4, 0x13, 0x33, 0x49, 0xf4, - 0x1f, 0xbf, 0xbd, 0x87, 0x06, 0x88, 0xff, 0xdf, 0x9b, 0xfa, 0x6f, 0x07, 0xbc, 0xaa, 0x09, 0xcf, - 0x77, 0x9b, 0xf0, 0xbc, 0x6e, 0xc2, 0xc9, 0x99, 0x6d, 0xc2, 0xc9, 0x19, 0x62, 0x7a, 0x6d, 0x9b, - 0x90, 0x5e, 0xe3, 0x65, 0x7d, 0x2e, 0x93, 0x22, 0x3d, 0x2b, 0xf5, 0xad, 0xfa, 0xb4, 0xc2, 0x58, - 0xb9, 0xbf, 0x5e, 0x73, 0x69, 0x52, 0xed, 0x53, 0x83, 0xb0, 0xce, 0x2f, 0x15, 0x41, 0xe9, 0xe4, - 0x6a, 0x40, 0xbe, 0x07, 0x1e, 0xc5, 0xe4, 0xa9, 0x0c, 0xef, 0xdc, 0x8b, 0x12, 0x53, 0xad, 0x45, - 0xa7, 0xfa, 0xfb, 0xc2, 0x14, 0xbc, 0xfd, 0xda, 0xf8, 0x31, 0x74, 0xa6, 0x6b, 0xb1, 0xcc, 0xed, - 0x3c, 0xf6, 0xf5, 0x06, 0xc1, 0x89, 0x0d, 0x57, 0x3a, 0x6a, 0x4c, 0xc2, 0xd7, 0xe0, 0x57, 0xc2, - 0xfa, 0x38, 0x4e, 0xf3, 0x38, 0x04, 0xdc, 0xdb, 0x58, 0xe4, 0xb6, 0xd5, 0x71, 0x8d, 0xc1, 0xbe, - 0x2e, 0x58, 0x9c, 0x8b, 0xbc, 0xb4, 0xad, 0x6e, 0x71, 0xf8, 0xb1, 0x39, 0x3e, 0xba, 0xbb, 0x4d, - 0x53, 0x2e, 0x0d, 0x6d, 0x68, 0xa0, 0x36, 0x49, 0x1e, 0xb8, 0x66, 0xfc, 0x36, 0xd5, 0x20, 0xfc, - 0x0d, 0xf8, 0xe3, 0x88, 0xcb, 0x9c, 0x16, 0x11, 0x3f, 0xf4, 0x12, 0x3f, 0x9f, 0x5e, 0xbd, 0xb2, - 0x27, 0xc0, 0x75, 0x4d, 0x11, 0xed, 0x47, 0x14, 0xf1, 0x82, 0xa5, 0xec, 0x62, 0xa2, 0xea, 0xbc, - 0x4d, 0x0d, 0x0a, 0xff, 0xe2, 0x80, 0x8b, 0x5c, 0xd4, 0x70, 0xed, 0xbe, 0x8d, 0xc7, 0xae, 0x65, - 0x72, 0x2f, 0x16, 0x5c, 0xda, 0xe0, 0x2c, 0x56, 0x49, 0x9f, 0xaf, 0x79, 0xf5, 0xe0, 0x1b, 0x84, - 0xb5, 0x86, 0x1f, 0x23, 0xb6, 0x97, 0x1a, 0xb5, 0x86, 0x62, 0xaa, 0x95, 0x38, 0x24, 0x4e, 0x8b, - 0x94, 0xcb, 0xf1, 0x62, 0x23, 0xec, 0xb0, 0xd4, 0x90, 0x84, 0x9f, 0xe9, 0xcf, 0x9b, 0x3d, 0x46, - 0x73, 0x0e, 0x7f, 0x0a, 0x3d, 0x3e, 0x79, 0xf8, 0x57, 0x07, 0xba, 0x2f, 0xcd, 0x70, 0xd6, 0x8c, - 0xc2, 0x79, 0x63, 0x14, 0xad, 0x9d, 0x28, 0x4e, 0xe1, 0xa9, 0xb5, 0xd9, 0xd9, 0x5f, 0x67, 0xe1, - 0xa0, 0xce, 0x64, 0xd4, 0xad, 0x2e, 0xeb, 0x5d, 0xbe, 0x6e, 0x6e, 0x76, 0x6d, 0x0e, 0x5d, 0xf8, - 0xde, 0xad, 0x0c, 0xa1, 0x6f, 0xbf, 0xea, 0x92, 0xc8, 0x3e, 0x30, 0x4d, 0x51, 0x78, 0x0a, 0x9d, - 0xf3, 0x24, 0x5e, 0x8a, 0x15, 0x19, 0x81, 0x3b, 0x2e, 0xf2, 0xb5, 0xf2, 0xd8, 0x3f, 0x7d, 0xda, - 0x68, 0xfc, 0x22, 0x5f, 0x6b, 0x1b, 0xaa, 0x2c, 0xc2, 0x4f, 0x01, 0x6a, 0x19, 0xbe, 0x12, 0xf5, - 0x6d, 0xbc, 0xe2, 0x0f, 0x58, 0x32, 0x99, 0xf2, 0xd2, 0xa3, 0x07, 0x34, 0xe1, 0x2f, 0xc0, 0x3f, - 0x2b, 0x44, 0xb4, 0xb8, 0x88, 0x97, 0x09, 0x52, 0xc7, 0x1d, 0x97, 0x59, 0x7d, 0x5f, 0x16, 0x62, - 0xba, 0x91, 0x45, 0xaa, 0x1e, 0x32, 0x68, 0xd6, 0x51, 0xff, 0x19, 0x7c, 0xfc, 0xdf, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x54, 0x72, 0x77, 0x46, 0x45, 0x10, 0x00, 0x00, + // 1667 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x5b, 0x6f, 0xe4, 0x48, + 0x15, 0x96, 0xbb, 0xed, 0x4e, 0xfb, 0x74, 0x92, 0x8d, 0x8a, 0xd1, 0xae, 0x59, 0x10, 0x6a, 0x2c, + 0x2e, 0xe1, 0xb2, 0xc3, 0x2a, 0x2b, 0x24, 0xb4, 0xda, 0x5d, 0x29, 0x97, 0x9d, 0x21, 0x73, 0xcd, + 0x54, 0x27, 0xc3, 0x13, 0x5a, 0x55, 0xdb, 0xd5, 0xdd, 0xa5, 0x75, 0xdb, 0xa6, 0x6c, 0x27, 0x31, + 0xcf, 0xfc, 0x0e, 0x24, 0x24, 0xf8, 0x03, 0x88, 0x47, 0x24, 0xde, 0xf9, 0x01, 0xfc, 0x15, 0x78, + 0x44, 0xa7, 0x2e, 0xee, 0x72, 0xd2, 0x33, 0x1a, 0x24, 0xb4, 0x6f, 0xf5, 0x9d, 0x73, 0xfa, 0x54, + 0xd5, 0xb9, 0x7c, 0x75, 0xdc, 0xb0, 0x2f, 0xf2, 0x9a, 0xcb, 0x9c, 0x65, 0x0f, 0x4b, 0x59, 0xd4, + 0x05, 0x19, 0x5b, 0x1c, 0xff, 0x61, 0x08, 0xa3, 0x59, 0xd1, 0xc8, 0x84, 0x93, 0x7d, 0x18, 0x9c, + 0x9f, 0x45, 0xde, 0xd4, 0x3b, 0x1c, 0xd2, 0xc1, 0xf9, 0x19, 0x21, 0xe0, 0xbf, 0x60, 0x6b, 0x1e, + 0x0d, 0xa6, 0xde, 0x61, 0x48, 0xd5, 0x1a, 0x65, 0x97, 0x6d, 0xc9, 0xa3, 0xa1, 0x96, 0xe1, 0x9a, + 0x7c, 0x08, 0xe3, 0xab, 0x0a, 0xbd, 0xad, 0x79, 0xe4, 0x2b, 0x79, 0x87, 0x51, 0x77, 0xc1, 0xaa, + 0xea, 0xa6, 0x90, 0x69, 0x14, 0x68, 0x9d, 0xc5, 0xe4, 0x00, 0x86, 0x57, 0xf4, 0x59, 0x34, 0x52, + 0x62, 0x5c, 0x92, 0x08, 0x76, 0xce, 0xf8, 0x82, 0x35, 0x59, 0x1d, 0xed, 0x4c, 0xbd, 0xc3, 0x31, + 0xb5, 0x10, 0xfd, 0x5c, 0xf2, 0x8c, 0x2f, 0x25, 0x5b, 0x44, 0x63, 0xed, 0xc7, 0x62, 0xf2, 0x10, + 0xc8, 0x79, 0x5e, 0xf1, 0xa4, 0x91, 0x7c, 0xf6, 0xb5, 0x28, 0x5f, 0x73, 0x29, 0x16, 0x6d, 0x14, + 0x2a, 0x07, 0x5b, 0x34, 0xb8, 0xcb, 0x73, 0x5e, 0x33, 0xdc, 0x1b, 0x94, 0x2b, 0x0b, 0x49, 0x0c, + 0xbb, 0xb3, 0x15, 0x93, 0x3c, 0x9d, 0xf1, 0x44, 0xf2, 0x3a, 0x9a, 0x28, 0x75, 0x4f, 0x86, 0x36, + 0x2f, 0xe5, 0x92, 0xe5, 0xe2, 0xf7, 0xac, 0x16, 0x45, 0x1e, 0xed, 0x6a, 0x1b, 0x57, 0x86, 0x51, + 0xa2, 0x45, 0xc6, 0xa3, 0x3d, 0x1d, 0x25, 0x5c, 0x93, 0xef, 0x42, 0x68, 0x2e, 0x43, 0x2f, 0xa2, + 0x7d, 0xa5, 0xd8, 0x08, 0xe2, 0xbf, 0x79, 0x10, 0x9e, 0xb1, 0x6a, 0x35, 0x2f, 0x98, 0x4c, 0xdf, + 0x29, 0x13, 0x1f, 0x41, 0x90, 0xf0, 0x2c, 0xab, 0xa2, 0xe1, 0x74, 0x78, 0x38, 0x39, 0xfa, 0xe0, + 0x61, 0x97, 0xe2, 0xce, 0xcf, 0x29, 0xcf, 0x32, 0xaa, 0xad, 0xc8, 0xc7, 0x10, 0xd6, 0x7c, 0x5d, + 0x66, 0xac, 0xe6, 0x55, 0xe4, 0xab, 0x9f, 0x90, 0xcd, 0x4f, 0x2e, 0x8d, 0x8a, 0x6e, 0x8c, 0xee, + 0x5d, 0x34, 0xb8, 0x7f, 0xd1, 0xf8, 0x5f, 0x3e, 0xec, 0xf5, 0xb6, 0x23, 0xbb, 0xe0, 0xdd, 0xaa, + 0x93, 0x07, 0xd4, 0xbb, 0x45, 0xd4, 0xaa, 0x53, 0x07, 0xd4, 0x6b, 0x11, 0xdd, 0xa8, 0xca, 0x09, + 0xa8, 0x77, 0x83, 0x68, 0xa5, 0xea, 0x25, 0xa0, 0xde, 0x8a, 0xfc, 0x04, 0x76, 0x7e, 0xd7, 0x70, + 0x29, 0x78, 0x15, 0x05, 0xea, 0x74, 0xef, 0x6d, 0x4e, 0xf7, 0xaa, 0xe1, 0xb2, 0xa5, 0x56, 0x8f, + 0xd1, 0x50, 0xb5, 0xa6, 0x0b, 0x47, 0xad, 0x51, 0x56, 0x63, 0x5d, 0xee, 0x68, 0x19, 0xae, 0x4d, + 0x14, 0x75, 0xb5, 0x60, 0x14, 0x7f, 0x09, 0x3e, 0xbb, 0xe5, 0x55, 0x14, 0x2a, 0xff, 0xdf, 0x7f, + 0x43, 0xc0, 0x1e, 0x1e, 0xdf, 0xf2, 0xea, 0xcb, 0xbc, 0x96, 0x2d, 0x55, 0xe6, 0xe4, 0xc7, 0x30, + 0x4a, 0x8a, 0xac, 0x90, 0x55, 0x04, 0x77, 0x0f, 0x76, 0x8a, 0x72, 0x6a, 0xd4, 0xe4, 0x10, 0x46, + 0x19, 0x5f, 0xf2, 0x3c, 0x55, 0x75, 0x33, 0x39, 0x3a, 0xd8, 0x18, 0x3e, 0x53, 0x72, 0x6a, 0xf4, + 0xe4, 0x53, 0xd8, 0xad, 0xd9, 0x3c, 0xe3, 0x2f, 0x4b, 0x8c, 0x62, 0xa5, 0x6a, 0x68, 0x72, 0xf4, + 0xbe, 0x93, 0x0f, 0x47, 0x4b, 0x7b, 0xb6, 0xe4, 0x33, 0xd8, 0x5d, 0x08, 0x9e, 0xa5, 0xf6, 0xb7, + 0x7b, 0xea, 0x50, 0xd1, 0xe6, 0xb7, 0x94, 0xe7, 0x6c, 0x8d, 0xbf, 0x78, 0x84, 0x66, 0xb4, 0x67, + 0x4d, 0xbe, 0x07, 0x50, 0x8b, 0x35, 0x7f, 0x54, 0xc8, 0x35, 0xab, 0x4d, 0x19, 0x3a, 0x12, 0xf2, + 0x39, 0xec, 0xa5, 0x3c, 0x11, 0x6b, 0x96, 0x5d, 0x64, 0x2c, 0xe1, 0x55, 0xf4, 0x9e, 0x3a, 0x9a, + 0x5b, 0x5d, 0xae, 0x9a, 0xf6, 0xad, 0x3f, 0x7c, 0x0c, 0x61, 0x17, 0x3e, 0xec, 0xef, 0xaf, 0x79, + 0xab, 0x8a, 0x21, 0xa4, 0xb8, 0x24, 0x3f, 0x80, 0xe0, 0x9a, 0x65, 0x8d, 0x2e, 0xe4, 0xc9, 0xd1, + 0xfe, 0xc6, 0xeb, 0xf1, 0xad, 0xa8, 0xa8, 0x56, 0x7e, 0x3a, 0xf8, 0x95, 0x17, 0x3f, 0x86, 0xbd, + 0xde, 0x46, 0x78, 0x70, 0x51, 0x7d, 0x99, 0x2f, 0x0a, 0x99, 0xf0, 0x54, 0xf9, 0x1c, 0x53, 0x47, + 0x42, 0xde, 0x87, 0x51, 0x2a, 0x96, 0xa2, 0xae, 0x4c, 0xb9, 0x19, 0x14, 0xff, 0xdd, 0x83, 0x5d, + 0x37, 0x9a, 0xe4, 0xa7, 0x70, 0x70, 0xcd, 0x65, 0x2d, 0x12, 0x96, 0x5d, 0x8a, 0x35, 0xc7, 0x8d, + 0xd5, 0x4f, 0xc6, 0xf4, 0x9e, 0x9c, 0x7c, 0x0c, 0xa3, 0xaa, 0x90, 0xf5, 0x49, 0xab, 0xaa, 0xf6, + 0x6d, 0x51, 0x36, 0x76, 0xc8, 0x53, 0x37, 0x92, 0x95, 0xa5, 0xc8, 0x97, 0x96, 0x0b, 0x2d, 0x26, + 0x3f, 0x82, 0xfd, 0x85, 0xb8, 0x7d, 0x24, 0x64, 0x55, 0x9f, 0x16, 0x59, 0xb3, 0xce, 0x55, 0x05, + 0x8f, 0xe9, 0x1d, 0xe9, 0x13, 0x7f, 0xec, 0x1d, 0x0c, 0x9e, 0xf8, 0xe3, 0xe0, 0x60, 0x14, 0x97, + 0xb0, 0xdf, 0xdf, 0x09, 0xdb, 0xd2, 0x1e, 0x42, 0x71, 0x82, 0x0e, 0x6f, 0x4f, 0x46, 0xa6, 0x30, + 0x49, 0x45, 0x55, 0x66, 0xac, 0x75, 0x68, 0xc3, 0x15, 0x21, 0x07, 0x5e, 0x8b, 0x4a, 0xcc, 0x33, + 0x4d, 0xe5, 0x63, 0x6a, 0x61, 0xbc, 0x84, 0x40, 0x95, 0xb5, 0x43, 0x42, 0xa1, 0x25, 0x21, 0x45, + 0xfd, 0x03, 0x87, 0xfa, 0x0f, 0x60, 0xf8, 0x6b, 0x7e, 0x6b, 0x5e, 0x03, 0x5c, 0x76, 0x54, 0xe5, + 0x3b, 0x54, 0xf5, 0x00, 0x82, 0xd7, 0x2a, 0xed, 0x9a, 0x42, 0x34, 0x88, 0xbf, 0x80, 0x91, 0x6e, + 0x8b, 0xce, 0xb3, 0xe7, 0x78, 0x9e, 0xc2, 0xe4, 0xa5, 0x14, 0x3c, 0xaf, 0x35, 0xf9, 0x98, 0x2b, + 0x38, 0xa2, 0xf8, 0xaf, 0x1e, 0xf8, 0x2a, 0x4b, 0x31, 0xec, 0x66, 0x7c, 0xc9, 0x92, 0xf6, 0xa4, + 0x68, 0xf2, 0xb4, 0x8a, 0xbc, 0xe9, 0xf0, 0x70, 0x48, 0x7b, 0x32, 0x2c, 0x8f, 0xb9, 0xd6, 0x0e, + 0xa6, 0xc3, 0xc3, 0x90, 0x1a, 0x84, 0x47, 0xcb, 0xd8, 0x9c, 0x67, 0xe6, 0x0a, 0x1a, 0xa0, 0x75, + 0x29, 0xf9, 0x42, 0xdc, 0x9a, 0x6b, 0x18, 0x84, 0xf2, 0xaa, 0x59, 0xa0, 0x5c, 0xdf, 0xc4, 0x20, + 0xbc, 0xc0, 0x9c, 0x55, 0x1d, 0x23, 0xe1, 0x1a, 0x3d, 0x57, 0x09, 0xcb, 0x2c, 0x25, 0x69, 0x10, + 0xff, 0xc3, 0xc3, 0x87, 0x4c, 0x53, 0xec, 0xbd, 0x08, 0x7f, 0x1b, 0xc6, 0x48, 0xbf, 0x5f, 0x5d, + 0x33, 0x69, 0x2e, 0xbc, 0x83, 0xf8, 0x35, 0x93, 0xe4, 0x17, 0x30, 0x52, 0xcd, 0xb1, 0x85, 0xee, + 0xad, 0x3b, 0x15, 0x55, 0x6a, 0xcc, 0x3a, 0x42, 0xf4, 0x1d, 0x42, 0xec, 0x2e, 0x1b, 0xb8, 0x97, + 0xfd, 0x08, 0x02, 0x64, 0xd6, 0x56, 0x9d, 0x7e, 0xab, 0x67, 0xcd, 0xbf, 0xda, 0x2a, 0xbe, 0x82, + 0xbd, 0xde, 0x8e, 0xdd, 0x4e, 0x5e, 0x7f, 0xa7, 0x4d, 0xa3, 0x87, 0xa6, 0xb1, 0xb1, 0x39, 0x2a, + 0x9e, 0xf1, 0xa4, 0xe6, 0xa9, 0xa9, 0xba, 0x0e, 0xc7, 0x7f, 0xf2, 0x36, 0x7e, 0xd5, 0x7e, 0x58, + 0xa2, 0x49, 0xb1, 0x5e, 0xb3, 0x3c, 0x35, 0xae, 0x2d, 0xc4, 0xb8, 0xa5, 0x73, 0xe3, 0x7a, 0x90, + 0xce, 0x11, 0xcb, 0xd2, 0x64, 0x70, 0x20, 0x4b, 0xac, 0x9d, 0x35, 0x67, 0x55, 0x23, 0xf9, 0x9a, + 0xe7, 0xb5, 0x09, 0x81, 0x2b, 0x22, 0x1f, 0xc0, 0x4e, 0xcd, 0x96, 0x5f, 0x21, 0x3d, 0x99, 0x4c, + 0xd6, 0x6c, 0xf9, 0x94, 0xb7, 0xe4, 0x3b, 0x10, 0x2a, 0xbe, 0x54, 0x2a, 0x9d, 0xce, 0xb1, 0x12, + 0x3c, 0xe5, 0x6d, 0xfc, 0x1f, 0x0f, 0x46, 0x33, 0x2e, 0xaf, 0xb9, 0x7c, 0xa7, 0x17, 0xda, 0x9d, + 0x8b, 0x86, 0x6f, 0x99, 0x8b, 0xfc, 0xed, 0x73, 0x51, 0xb0, 0x99, 0x8b, 0x1e, 0x40, 0x30, 0x93, + 0xc9, 0xf9, 0x99, 0x3a, 0xd1, 0x90, 0x6a, 0x80, 0xd5, 0x78, 0x9c, 0xd4, 0xe2, 0x9a, 0x9b, 0x61, + 0xc9, 0xa0, 0x7b, 0x0f, 0xf7, 0x78, 0xcb, 0x84, 0xf2, 0x3f, 0xce, 0x4c, 0xf1, 0x1f, 0x3d, 0x18, + 0x3d, 0x63, 0x6d, 0xd1, 0xd4, 0xf7, 0xaa, 0x76, 0x0a, 0x93, 0xe3, 0xb2, 0xcc, 0x44, 0xd2, 0xeb, + 0x54, 0x47, 0x84, 0x16, 0xcf, 0x9d, 0x7c, 0xe8, 0x58, 0xb8, 0x22, 0x7c, 0x18, 0x4e, 0xd5, 0x30, + 0xa3, 0x27, 0x13, 0xe7, 0x61, 0xd0, 0x33, 0x8c, 0x52, 0x62, 0xd0, 0x8e, 0x9b, 0xba, 0x58, 0x64, + 0xc5, 0x8d, 0x8a, 0xce, 0x98, 0x76, 0x38, 0xfe, 0xe7, 0x00, 0xfc, 0x6f, 0x6a, 0x00, 0xd9, 0x05, + 0x4f, 0x98, 0xe2, 0xf0, 0x44, 0x37, 0x8e, 0xec, 0x38, 0xe3, 0x48, 0x04, 0x3b, 0xad, 0x64, 0xf9, + 0x92, 0x57, 0xd1, 0x58, 0xb1, 0x91, 0x85, 0x4a, 0xa3, 0xfa, 0x4e, 0xcf, 0x21, 0x21, 0xb5, 0xb0, + 0xeb, 0x23, 0x70, 0xfa, 0xe8, 0xe7, 0x66, 0x64, 0x99, 0xdc, 0x7d, 0xe4, 0xb7, 0x4d, 0x2a, 0xff, + 0xbf, 0xd7, 0xf7, 0xdf, 0x1e, 0x04, 0x5d, 0x13, 0x9e, 0xf6, 0x9b, 0xf0, 0x74, 0xd3, 0x84, 0x67, + 0x27, 0xb6, 0x09, 0xcf, 0x4e, 0x10, 0xd3, 0x0b, 0xdb, 0x84, 0xf4, 0x02, 0x93, 0xf5, 0x58, 0x16, + 0x4d, 0x79, 0xd2, 0xea, 0xac, 0x86, 0xb4, 0xc3, 0x58, 0xb9, 0xbf, 0x59, 0x71, 0x69, 0x42, 0x1d, + 0x52, 0x83, 0xb0, 0xce, 0x9f, 0x29, 0x82, 0xd2, 0xc1, 0xd5, 0x80, 0xfc, 0x10, 0x02, 0x8a, 0xc1, + 0x53, 0x11, 0xee, 0xe5, 0x45, 0x89, 0xa9, 0xd6, 0xa2, 0x53, 0xfd, 0x21, 0x63, 0x0a, 0xde, 0x7e, + 0xd6, 0xfc, 0x0c, 0x46, 0xb3, 0x95, 0x58, 0xd4, 0x76, 0xf0, 0xfb, 0x96, 0x43, 0x70, 0x62, 0xcd, + 0x95, 0x8e, 0x1a, 0x93, 0xf8, 0x15, 0x84, 0x9d, 0x70, 0x73, 0x1c, 0xcf, 0x3d, 0x0e, 0x01, 0xff, + 0x2a, 0x17, 0xb5, 0x6d, 0x75, 0x5c, 0xe3, 0x65, 0x5f, 0x35, 0x2c, 0xaf, 0x45, 0xdd, 0xda, 0x56, + 0xb7, 0x38, 0xfe, 0xc4, 0x1c, 0x1f, 0xdd, 0x5d, 0x95, 0x25, 0x97, 0x86, 0x36, 0x34, 0x50, 0x9b, + 0x14, 0x37, 0x5c, 0x33, 0xfe, 0x90, 0x6a, 0x10, 0xff, 0x16, 0xc2, 0xe3, 0x8c, 0xcb, 0x9a, 0x36, + 0x19, 0xdf, 0xf6, 0x12, 0x3f, 0x99, 0xbd, 0x7c, 0x61, 0x4f, 0x80, 0xeb, 0x0d, 0x45, 0x0c, 0xef, + 0x50, 0xc4, 0x53, 0x56, 0xb2, 0xf3, 0x33, 0x55, 0xe7, 0x43, 0x6a, 0x50, 0xfc, 0x67, 0x0f, 0x7c, + 0xe4, 0x22, 0xc7, 0xb5, 0xff, 0x36, 0x1e, 0xbb, 0x90, 0xc5, 0xb5, 0x48, 0xb9, 0xb4, 0x97, 0xb3, + 0x58, 0x05, 0x3d, 0x59, 0xf1, 0xee, 0xc1, 0x37, 0x08, 0x6b, 0x0d, 0xbf, 0x7a, 0x6c, 0x2f, 0x39, + 0xb5, 0x86, 0x62, 0xaa, 0x95, 0x38, 0xd4, 0xcd, 0x9a, 0x92, 0xcb, 0xe3, 0x74, 0x2d, 0xec, 0x34, + 0xe4, 0x48, 0xe2, 0x2f, 0xf4, 0x77, 0xd4, 0x3d, 0x46, 0xf3, 0xb6, 0x7f, 0x73, 0xdd, 0x3d, 0x79, + 0xfc, 0x17, 0x0f, 0x76, 0x9e, 0x9b, 0xe9, 0xcb, 0xbd, 0x85, 0xf7, 0xc6, 0x5b, 0x0c, 0x7a, 0xb7, + 0x38, 0x82, 0x07, 0xd6, 0xa6, 0xb7, 0xbf, 0x8e, 0xc2, 0x56, 0x9d, 0x89, 0xa8, 0xdf, 0x25, 0xeb, + 0x5d, 0x3e, 0xa3, 0x2e, 0xfb, 0x36, 0xdb, 0x12, 0x7e, 0x2f, 0x2b, 0x53, 0x98, 0xd8, 0xcf, 0xc7, + 0x22, 0xb3, 0x0f, 0x8c, 0x2b, 0x8a, 0x8f, 0x60, 0x74, 0x5a, 0xe4, 0x0b, 0xb1, 0x24, 0x87, 0xe0, + 0x1f, 0x37, 0xf5, 0x4a, 0x79, 0x9c, 0x1c, 0x3d, 0x70, 0x1a, 0xbf, 0xa9, 0x57, 0xda, 0x86, 0x2a, + 0x8b, 0xf8, 0x33, 0x80, 0x8d, 0x0c, 0x5f, 0x89, 0x4d, 0x36, 0x5e, 0xf0, 0x1b, 0x2c, 0x99, 0xca, + 0x0c, 0xdf, 0x5b, 0x34, 0xf1, 0xe7, 0x10, 0x9e, 0x34, 0x22, 0x4b, 0xcf, 0xf3, 0x45, 0x81, 0xd4, + 0xf1, 0x9a, 0xcb, 0x6a, 0x93, 0x2f, 0x0b, 0x31, 0xdc, 0xc8, 0x22, 0x5d, 0x0f, 0x19, 0x34, 0x1f, + 0xa9, 0x3f, 0x27, 0x3e, 0xf9, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x77, 0xc4, 0xaa, 0x16, 0xae, + 0x10, 0x00, 0x00, } diff --git a/bolt/internal/internal.proto b/bolt/internal/internal.proto index 9373e54c85..7633ed3af6 100644 --- a/bolt/internal/internal.proto +++ b/bolt/internal/internal.proto @@ -41,6 +41,12 @@ message DashboardCell { TableOptions tableOptions = 12; // TableOptions for visualization of cell with type 'table' repeated RenamableField fieldOptions = 13; // Options for each of the fields returned in a cell string timeFormat = 14; // format for time + DecimalPlaces decimalPlaces = 15; // Represents how precise the values of this field should be +} + +message DecimalPlaces { + bool isEnforced = 1; // whether decimal places should be enforced + int32 digits = 2; // the number of digits to display after decical point } message TableOptions { @@ -55,8 +61,7 @@ message TableOptions { message RenamableField { string internalName = 1; // name of column string displayName = 2; // what column is renamed to - bool visible = 3; // Represents whether RenamableField is visible - int32 precision = 4; // Represents how precise the values of this field should be + bool visible = 3; // Represents whether RenamableField is visible } message Color { diff --git a/chronograf.go b/chronograf.go index 9259f0e480..47ece6d953 100644 --- a/chronograf.go +++ b/chronograf.go @@ -563,20 +563,21 @@ type Legend struct { // DashboardCell holds visual and query information for a cell type DashboardCell struct { - ID string `json:"i"` - X int32 `json:"x"` - Y int32 `json:"y"` - W int32 `json:"w"` - H int32 `json:"h"` - Name string `json:"name"` - Queries []DashboardQuery `json:"queries"` - Axes map[string]Axis `json:"axes"` - Type string `json:"type"` - CellColors []CellColor `json:"colors"` - Legend Legend `json:"legend"` - TableOptions TableOptions `json:"tableOptions,omitempty"` - FieldOptions []RenamableField `json:"fieldOptions"` - TimeFormat string `json:"timeFormat"` + ID string `json:"i"` + X int32 `json:"x"` + Y int32 `json:"y"` + W int32 `json:"w"` + H int32 `json:"h"` + Name string `json:"name"` + Queries []DashboardQuery `json:"queries"` + Axes map[string]Axis `json:"axes"` + Type string `json:"type"` + CellColors []CellColor `json:"colors"` + Legend Legend `json:"legend"` + TableOptions TableOptions `json:"tableOptions,omitempty"` + FieldOptions []RenamableField `json:"fieldOptions"` + TimeFormat string `json:"timeFormat"` + DecimalPlaces DecimalPlaces `json:"decimalPlaces"` } // RenamableField is a column/row field in a DashboardCell of type Table @@ -584,7 +585,6 @@ type RenamableField struct { InternalName string `json:"internalName"` DisplayName string `json:"displayName"` Visible bool `json:"visible"` - Precision int32 `json:"precision"` } // TableOptions is a type of options for a DashboardCell with type Table @@ -595,6 +595,12 @@ type TableOptions struct { FixFirstColumn bool `json:"fixFirstColumn"` } +// DecimalPlaces indicates whether decimal places should be enforced, and how many digits it should show. +type DecimalPlaces struct { + IsEnforced bool `json:"isEnforced"` + Digits int32 `json:"digits"` +} + // DashboardsStore is the storage and retrieval of dashboards type DashboardsStore interface { // All lists all dashboards from the DashboardStore From 844d860cd9ae9d2b6201219c387b130f110b456c Mon Sep 17 00:00:00 2001 From: Brandon Farmer Date: Fri, 27 Apr 2018 13:52:07 -0700 Subject: [PATCH 38/48] Convert and refactor AutoRefresh --- ui/src/shared/apis/query.ts | 74 ++++++ ui/src/shared/components/AutoRefresh.js | 294 ----------------------- ui/src/shared/components/AutoRefresh.tsx | 294 +++++++++++++++++++++++ ui/src/shared/components/Crosshair.tsx | 3 +- ui/src/shared/constants/series.ts | 7 + 5 files changed, 377 insertions(+), 295 deletions(-) create mode 100644 ui/src/shared/apis/query.ts delete mode 100644 ui/src/shared/components/AutoRefresh.js create mode 100644 ui/src/shared/components/AutoRefresh.tsx create mode 100644 ui/src/shared/constants/series.ts diff --git a/ui/src/shared/apis/query.ts b/ui/src/shared/apis/query.ts new file mode 100644 index 0000000000..03eab77837 --- /dev/null +++ b/ui/src/shared/apis/query.ts @@ -0,0 +1,74 @@ +import _ from 'lodash' +import {fetchTimeSeriesAsync} from 'src/shared/actions/timeSeries' +import {removeUnselectedTemplateValues} from 'src/dashboards/constants' + +import {intervalValuesPoints} from 'src/shared/constants' + +interface TemplateQuery { + db: string + rp: string + influxql: string +} + +interface TemplateValue { + type: string + value: string + selected: boolean +} + +interface Template { + type: string + tempVar: string + query: TemplateQuery + values: TemplateValue[] +} + +interface Query { + host: string | string[] + text: string + database: string + db: string + rp: string +} + +export const fetchTimeSeries = async ( + queries: Query[], + resolution: number, + templates: Template[], + editQueryStatus: () => void +) => { + const timeSeriesPromises = queries.map(query => { + const {host, database, rp} = query + // the key `database` was used upstream in HostPage.js, and since as of this writing + // the codebase has not been fully converted to TypeScript, it's not clear where else + // it may be used, but this slight modification is intended to allow for the use of + // `database` while moving over to `db` for consistency over time + const db = _.get(query, 'db', database) + + const templatesWithIntervalVals = templates.map(temp => { + if (temp.tempVar === ':interval:') { + if (resolution) { + const values = temp.values.map(v => ({ + ...v, + value: `${_.toInteger(Number(resolution) / 3)}`, + })) + + return {...temp, values} + } + + return {...temp, values: intervalValuesPoints} + } + return temp + }) + + const tempVars = removeUnselectedTemplateValues(templatesWithIntervalVals) + + const source = host + return fetchTimeSeriesAsync( + {source, db, rp, query, tempVars, resolution}, + editQueryStatus + ) + }) + + return Promise.all(timeSeriesPromises) +} diff --git a/ui/src/shared/components/AutoRefresh.js b/ui/src/shared/components/AutoRefresh.js deleted file mode 100644 index dda8bc5d00..0000000000 --- a/ui/src/shared/components/AutoRefresh.js +++ /dev/null @@ -1,294 +0,0 @@ -import React, {Component} from 'react' -import PropTypes from 'prop-types' -import _ from 'lodash' - -import {fetchTimeSeriesAsync} from 'shared/actions/timeSeries' -import {removeUnselectedTemplateValues} from 'src/dashboards/constants' -import {intervalValuesPoints} from 'src/shared/constants' -import {getQueryConfig} from 'shared/apis' - -const AutoRefresh = ComposedComponent => { - class wrapper extends Component { - constructor() { - super() - this.state = { - lastQuerySuccessful: true, - timeSeries: [], - resolution: null, - queryASTs: [], - } - } - - async componentDidMount() { - const {queries, templates, autoRefresh, type} = this.props - this.executeQueries(queries, templates) - if (type === 'table') { - const queryASTs = await this.getQueryASTs(queries, templates) - this.setState({queryASTs}) - } - if (autoRefresh) { - this.intervalID = setInterval( - () => this.executeQueries(queries, templates), - autoRefresh - ) - } - } - - getQueryASTs = async (queries, templates) => { - return await Promise.all( - queries.map(async q => { - const host = _.isArray(q.host) ? q.host[0] : q.host - const url = host.replace('proxy', 'queries') - const text = q.text - const {data} = await getQueryConfig(url, [{query: text}], templates) - return data.queries[0].queryAST - }) - ) - } - - async componentWillReceiveProps(nextProps) { - const inViewDidUpdate = this.props.inView !== nextProps.inView - - const queriesDidUpdate = this.queryDifference( - this.props.queries, - nextProps.queries - ).length - - const tempVarsDidUpdate = !_.isEqual( - this.props.templates, - nextProps.templates - ) - - const shouldRefetch = - queriesDidUpdate || tempVarsDidUpdate || inViewDidUpdate - - if (shouldRefetch) { - if (this.props.type === 'table') { - const queryASTs = await this.getQueryASTs( - nextProps.queries, - nextProps.templates - ) - this.setState({queryASTs}) - } - - this.executeQueries( - nextProps.queries, - nextProps.templates, - nextProps.inView - ) - } - - if (this.props.autoRefresh !== nextProps.autoRefresh || shouldRefetch) { - clearInterval(this.intervalID) - - if (nextProps.autoRefresh) { - this.intervalID = setInterval( - () => - this.executeQueries( - nextProps.queries, - nextProps.templates, - nextProps.inView - ), - nextProps.autoRefresh - ) - } - } - } - - queryDifference = (left, right) => { - const leftStrs = left.map(q => `${q.host}${q.text}`) - const rightStrs = right.map(q => `${q.host}${q.text}`) - return _.difference( - _.union(leftStrs, rightStrs), - _.intersection(leftStrs, rightStrs) - ) - } - - executeQueries = async ( - queries, - templates = [], - inView = this.props.inView - ) => { - const {editQueryStatus, grabDataForDownload} = this.props - const {resolution} = this.state - if (!inView) { - return - } - if (!queries.length) { - this.setState({timeSeries: []}) - return - } - - this.setState({isFetching: true}) - - const timeSeriesPromises = queries.map(query => { - const {host, database, rp} = query - // the key `database` was used upstream in HostPage.js, and since as of this writing - // the codebase has not been fully converted to TypeScript, it's not clear where else - // it may be used, but this slight modification is intended to allow for the use of - // `database` while moving over to `db` for consistency over time - const db = _.get(query, 'db', database) - - const templatesWithIntervalVals = templates.map(temp => { - if (temp.tempVar === ':interval:') { - if (resolution) { - // resize event - return { - ...temp, - values: temp.values.map(v => ({ - ...v, - value: `${_.toInteger(Number(resolution) / 3)}`, - })), - } - } - - return { - ...temp, - values: intervalValuesPoints, - } - } - return temp - }) - - const tempVars = removeUnselectedTemplateValues( - templatesWithIntervalVals - ) - return fetchTimeSeriesAsync( - { - source: host, - db, - rp, - query, - tempVars, - resolution, - }, - editQueryStatus - ) - }) - - try { - const timeSeries = await Promise.all(timeSeriesPromises) - const newSeries = timeSeries.map(response => ({response})) - const lastQuerySuccessful = this._resultsForQuery(newSeries) - - this.setState({ - timeSeries: newSeries, - lastQuerySuccessful, - isFetching: false, - }) - - if (grabDataForDownload) { - grabDataForDownload(timeSeries) - } - } catch (err) { - console.error(err) - } - } - - componentWillUnmount() { - clearInterval(this.intervalID) - this.intervalID = false - } - - setResolution = resolution => { - if (resolution !== this.state.resolution) { - this.setState({resolution}) - } - } - - render() { - const {timeSeries, queryASTs} = this.state - if (this.state.isFetching && this.state.lastQuerySuccessful) { - return ( - - ) - } - - return ( - - ) - } - - _resultsForQuery = data => - data.length - ? data.every(({response}) => - _.get(response, 'results', []).every( - result => - Object.keys(result).filter(k => k !== 'statement_id').length !== - 0 - ) - ) - : false - } - - wrapper.defaultProps = { - inView: true, - } - - const { - array, - arrayOf, - bool, - element, - func, - number, - oneOfType, - shape, - string, - } = PropTypes - - wrapper.propTypes = { - type: string.isRequired, - children: element, - autoRefresh: number.isRequired, - inView: bool, - templates: arrayOf( - shape({ - type: string.isRequired, - tempVar: string.isRequired, - query: shape({ - db: string, - rp: string, - influxql: string, - }), - values: arrayOf( - shape({ - type: string.isRequired, - value: string.isRequired, - selected: bool, - }) - ).isRequired, - }) - ), - queries: arrayOf( - shape({ - host: oneOfType([string, arrayOf(string)]), - text: string, - }).isRequired - ).isRequired, - axes: shape({ - bounds: shape({ - y: array, - y2: array, - }), - }), - editQueryStatus: func, - grabDataForDownload: func, - } - - return wrapper -} - -export default AutoRefresh diff --git a/ui/src/shared/components/AutoRefresh.tsx b/ui/src/shared/components/AutoRefresh.tsx new file mode 100644 index 0000000000..833cb00d9a --- /dev/null +++ b/ui/src/shared/components/AutoRefresh.tsx @@ -0,0 +1,294 @@ +import React, {Component, ComponentClass} from 'react' +import _ from 'lodash' + +import {getQueryConfig} from 'src/shared/apis' +import {fetchTimeSeries} from 'src/shared/apis/query' +import {DEFAULT_TIME_SERIES} from 'src/shared/constants/series' + +interface Axes { + bounds: { + y: number[] + y2: number[] + } +} + +interface Query { + host: string | string[] + text: string + database: string + db: string + rp: string +} + +interface TemplateQuery { + db: string + rp: string + influxql: string +} + +interface TemplateValue { + type: string + value: string + selected: boolean +} + +interface Template { + type: string + tempVar: string + query: TemplateQuery + values: TemplateValue[] +} + +interface Props { + type: string + autoRefresh: number + inView: boolean + templates: Template[] + queries: Query[] + axes: Axes + editQueryStatus: () => void + grabDataForDownload: (timeSeries: TimeSeriesServerResponse[]) => void +} + +type TimeSeriesValue = string | number | Date | null + +interface Series { + name: string + columns: string[] + values: TimeSeriesValue[] +} + +interface Result { + series: Series[] + statement_id: number +} + +interface TimeSeriesResponse { + results: Result[] +} + +interface TimeSeriesServerResponse { + response: TimeSeriesResponse +} + +interface QueryAST { + groupBy?: { + tags: string[] + } +} + +interface State { + isFetching: boolean + isLastQuerySuccessful: boolean + timeSeries: TimeSeriesServerResponse[] + resolution: number | null + queryASTs?: QueryAST[] +} + +interface OriginalProps { + data: TimeSeriesServerResponse[] + setResolution: (resolution: number) => void + isFetchingInitially?: boolean + isRefreshing?: boolean + queryASTs?: any[] +} + +const AutoRefresh = ( + ComposedComponent: ComponentClass +) => { + class Wrapper extends Component { + public static defaultProps = { + inView: true, + } + + private intervalID: NodeJS.Timer | null + + constructor(props: Props) { + super(props) + this.state = { + isFetching: false, + isLastQuerySuccessful: true, + timeSeries: DEFAULT_TIME_SERIES, + resolution: null, + queryASTs: [], + } + } + + public async componentDidMount() { + if (this.isTable) { + const queryASTs = await this.getQueryASTs() + this.setState({queryASTs}) + } + + this.startNewPolling() + } + + public async componentDidUpdate(prevProps: Props) { + if (!this.isPropsDifferent(prevProps)) { + return + } + + if (this.isTable) { + const queryASTs = await this.getQueryASTs() + this.setState({queryASTs}) + } + + this.startNewPolling() + } + + public executeQueries = async () => { + const {editQueryStatus, grabDataForDownload, inView, queries} = this.props + const {resolution} = this.state + + if (!inView) { + return + } + + if (!queries.length) { + this.setState({timeSeries: DEFAULT_TIME_SERIES}) + return + } + + this.setState({isFetching: true}) + const templates: Template[] = _.get(this.props, 'templates', []) + + try { + const timeSeries = await fetchTimeSeries( + queries, + resolution, + templates, + editQueryStatus + ) + const newSeries = timeSeries.map((response: TimeSeriesResponse) => ({ + response, + })) + const isLastQuerySuccessful = this.resultsForQuery(newSeries) + + this.setState({ + timeSeries: newSeries, + isLastQuerySuccessful, + isFetching: false, + }) + + if (grabDataForDownload) { + grabDataForDownload(newSeries) + } + } catch (err) { + console.error(err) + } + } + + public componentWillUnmount() { + this.clearInterval() + } + + public render() { + const { + timeSeries, + queryASTs, + isFetching, + isLastQuerySuccessful, + } = this.state + + if (isFetching && isLastQuerySuccessful) { + return ( + + ) + } + + return ( + + ) + } + + private setResolution = resolution => { + if (resolution !== this.state.resolution) { + this.setState({resolution}) + } + } + + private clearInterval() { + if (!this.intervalID) { + return + } + + clearInterval(this.intervalID) + this.intervalID = null + } + + private isPropsDifferent(nextProps: Props) { + return ( + this.props.inView !== nextProps.inView || + !!this.queryDifference(this.props.queries, nextProps.queries).length || + !_.isEqual(this.props.templates, nextProps.templates) || + this.props.autoRefresh !== nextProps.autoRefresh + ) + } + + private startNewPolling() { + this.clearInterval() + + const {autoRefresh} = this.props + + this.executeQueries() + + if (autoRefresh) { + this.intervalID = setInterval(this.executeQueries, autoRefresh) + } + } + + private queryDifference = (left, right) => { + const mapper = q => `${q.host}${q.text}` + const leftStrs = left.map(mapper) + const rightStrs = right.map(mapper) + return _.difference( + _.union(leftStrs, rightStrs), + _.intersection(leftStrs, rightStrs) + ) + } + + private get isTable(): boolean { + return this.props.type === 'table' + } + + private getQueryASTs = async (): Promise => { + const {queries, templates} = this.props + + return await Promise.all( + queries.map(async q => { + const host = _.isArray(q.host) ? q.host[0] : q.host + const url = host.replace('proxy', 'queries') + const text = q.text + const {data} = await getQueryConfig(url, [{query: text}], templates) + return data.queries[0].queryAST + }) + ) + } + + private resultsForQuery = data => { + if (!data.length) { + return false + } + + data.every(({resp}) => + _.get(resp, 'results', []).every(r => Object.keys(r).length > 1) + ) + } + } + + return Wrapper +} + +export default AutoRefresh diff --git a/ui/src/shared/components/Crosshair.tsx b/ui/src/shared/components/Crosshair.tsx index fbd972a262..79b63af286 100644 --- a/ui/src/shared/components/Crosshair.tsx +++ b/ui/src/shared/components/Crosshair.tsx @@ -1,3 +1,4 @@ +import _ from 'lodash' import React, {PureComponent} from 'react' import Dygraph from 'dygraphs' import {connect} from 'react-redux' @@ -35,7 +36,7 @@ class Crosshair extends PureComponent { private get isVisible() { const {hoverTime} = this.props - return hoverTime !== 0 + return hoverTime !== 0 && _.isFinite(hoverTime) } private get crosshairLeft(): number { diff --git a/ui/src/shared/constants/series.ts b/ui/src/shared/constants/series.ts new file mode 100644 index 0000000000..3177b6d3e3 --- /dev/null +++ b/ui/src/shared/constants/series.ts @@ -0,0 +1,7 @@ +export const DEFAULT_TIME_SERIES = [ + { + response: { + results: [], + }, + }, +] From bb5e6232732925c7eee8a654adc747abf2584162 Mon Sep 17 00:00:00 2001 From: Brandon Farmer Date: Fri, 27 Apr 2018 17:05:13 -0700 Subject: [PATCH 39/48] Show message when there are no results --- ui/src/shared/components/AutoRefresh.tsx | 41 +++++++++++------------- ui/src/types/series.ts | 20 ++++++++++++ 2 files changed, 38 insertions(+), 23 deletions(-) create mode 100644 ui/src/types/series.ts diff --git a/ui/src/shared/components/AutoRefresh.tsx b/ui/src/shared/components/AutoRefresh.tsx index 833cb00d9a..ce5a37b7f5 100644 --- a/ui/src/shared/components/AutoRefresh.tsx +++ b/ui/src/shared/components/AutoRefresh.tsx @@ -4,6 +4,7 @@ import _ from 'lodash' import {getQueryConfig} from 'src/shared/apis' import {fetchTimeSeries} from 'src/shared/apis/query' import {DEFAULT_TIME_SERIES} from 'src/shared/constants/series' +import {TimeSeriesServerResponse, TimeSeriesResponse} from 'src/types/series' interface Axes { bounds: { @@ -50,27 +51,6 @@ interface Props { grabDataForDownload: (timeSeries: TimeSeriesServerResponse[]) => void } -type TimeSeriesValue = string | number | Date | null - -interface Series { - name: string - columns: string[] - values: TimeSeriesValue[] -} - -interface Result { - series: Series[] - statement_id: number -} - -interface TimeSeriesResponse { - results: Result[] -} - -interface TimeSeriesServerResponse { - response: TimeSeriesResponse -} - interface QueryAST { groupBy?: { tags: string[] @@ -162,7 +142,7 @@ const AutoRefresh = ( const newSeries = timeSeries.map((response: TimeSeriesResponse) => ({ response, })) - const isLastQuerySuccessful = this.resultsForQuery(newSeries) + const isLastQuerySuccessful = this.hasResultsForQuery(newSeries) this.setState({ timeSeries: newSeries, @@ -190,6 +170,21 @@ const AutoRefresh = ( isLastQuerySuccessful, } = this.state + const hasValues = _.some(timeSeries, s => { + const results = _.get(s, 'response.results', []) + const v = _.some(results, r => r.series) + console.error(results, v) + return v + }) + + if (!hasValues) { + return ( +
    +

    No Results

    +
    + ) + } + if (isFetching && isLastQuerySuccessful) { return ( { + private hasResultsForQuery = (data): boolean => { if (!data.length) { return false } diff --git a/ui/src/types/series.ts b/ui/src/types/series.ts new file mode 100644 index 0000000000..3293f9a95e --- /dev/null +++ b/ui/src/types/series.ts @@ -0,0 +1,20 @@ +export type TimeSeriesValue = string | number | Date | null + +export interface Series { + name: string + columns: string[] + values: TimeSeriesValue[] +} + +export interface Result { + series: Series[] + statement_id: number +} + +export interface TimeSeriesResponse { + results: Result[] +} + +export interface TimeSeriesServerResponse { + response: TimeSeriesResponse +} From b47b14f746a383880ed2bbe1f302670348a5fdee Mon Sep 17 00:00:00 2001 From: Brandon Farmer Date: Sun, 29 Apr 2018 19:43:00 -0700 Subject: [PATCH 40/48] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c5ee12d3d..0c2b230a69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ 1. [#3215](https://github.com/influxdata/chronograf/pull/3215): Fix Template Variables Control Bar to top of dashboard page 1. [#3214](https://github.com/influxdata/chronograf/pull/3214): Remove extra click when creating dashboard cell 1. [#3256](https://github.com/influxdata/chronograf/pull/3256): Reduce font sizes in dashboards for increased space efficiency +1. [#3245](https://github.com/influxdata/chronograf/pull/3245): Display 'no results' on cells without results ### Bug Fixes From 39af4a0244cd90268d5ec2f0ef1bc6c446d017a5 Mon Sep 17 00:00:00 2001 From: Brandon Farmer Date: Sun, 29 Apr 2018 20:34:50 -0700 Subject: [PATCH 41/48] Add tests for missing 'No Results' --- ui/src/shared/components/AutoRefresh.tsx | 7 +- .../shared/components/AutoRefresh.test.tsx | 74 +++++++++++++++++++ 2 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 ui/test/shared/components/AutoRefresh.test.tsx diff --git a/ui/src/shared/components/AutoRefresh.tsx b/ui/src/shared/components/AutoRefresh.tsx index ce5a37b7f5..b1df696c09 100644 --- a/ui/src/shared/components/AutoRefresh.tsx +++ b/ui/src/shared/components/AutoRefresh.tsx @@ -40,7 +40,7 @@ interface Template { values: TemplateValue[] } -interface Props { +export interface Props { type: string autoRefresh: number inView: boolean @@ -65,12 +65,12 @@ interface State { queryASTs?: QueryAST[] } -interface OriginalProps { +export interface OriginalProps { data: TimeSeriesServerResponse[] setResolution: (resolution: number) => void isFetchingInitially?: boolean isRefreshing?: boolean - queryASTs?: any[] + queryASTs?: QueryAST[] } const AutoRefresh = ( @@ -173,7 +173,6 @@ const AutoRefresh = ( const hasValues = _.some(timeSeries, s => { const results = _.get(s, 'response.results', []) const v = _.some(results, r => r.series) - console.error(results, v) return v }) diff --git a/ui/test/shared/components/AutoRefresh.test.tsx b/ui/test/shared/components/AutoRefresh.test.tsx new file mode 100644 index 0000000000..bf750e6684 --- /dev/null +++ b/ui/test/shared/components/AutoRefresh.test.tsx @@ -0,0 +1,74 @@ +import AutoRefresh, { + Props, + OriginalProps, +} from 'src/shared/components/AutoRefresh' +import React, {Component} from 'react' +import {shallow} from 'enzyme' + +type ComponentProps = Props & OriginalProps + +class MyComponent extends Component { + public render(): JSX.Element { + return

    Here

    + } +} + +const axes = { + bounds: { + y: [1], + y2: [2], + }, +} + +const defaultProps = { + type: 'table', + autoRefresh: 1, + inView: true, + templates: [], + queries: [], + axes, + editQueryStatus: () => {}, + grabDataForDownload: () => {}, + data: [], + setResolution: () => {}, + isFetchingInitially: false, + isRefreshing: false, + queryASTs: [], +} + +const setup = (overrides: Partial = {}) => { + const ARComponent = AutoRefresh(MyComponent) + + const props = {...defaultProps, ...overrides} + + return shallow() +} + +describe('Shared.Components.AutoRefresh', () => { + describe('render', () => { + describe('when there are no results', () => { + it('renders the no results component', () => { + const wrapped = setup() + expect(wrapped.find('.graph-empty').exists()).toBe(true) + }) + }) + + describe('when there are results', () => { + it('renderes the wrapped component', () => { + const wrapped = setup() + const timeSeries = [ + { + response: { + results: [{series: [1]}], + }, + }, + ] + wrapped.update() + wrapped.setState({timeSeries}) + process.nextTick(() => { + expect(wrapped.find(MyComponent).exists()).toBe(true) + }) + }) + }) + }) +}) From 9b1cf60a7c9a52b989b91b22e10d9c5eb9a18972 Mon Sep 17 00:00:00 2001 From: ebb-tide Date: Mon, 30 Apr 2018 11:55:12 -0700 Subject: [PATCH 42/48] Implement Decimal Place Setting --- server/swagger.json | 21 +++++-- .../dashboards/actions/cellEditorOverlay.js | 7 +++ .../GraphOptionsCustomizableField.tsx | 8 +-- .../components/GraphOptionsDecimalPlaces.tsx | 59 +++++++++++++++++++ .../components/GraphOptionsTimeFormat.tsx | 2 +- ui/src/dashboards/components/TableOptions.tsx | 25 +++++++- ui/src/dashboards/components/Visualization.js | 11 +++- ui/src/dashboards/constants/index.js | 7 ++- .../dashboards/reducers/cellEditorOverlay.js | 5 ++ ui/src/dashboards/utils/tableGraph.ts | 9 +-- ui/src/shared/components/Layout.js | 6 ++ ui/src/shared/components/RefreshingGraph.js | 7 ++- ui/src/shared/components/TableGraph.js | 48 +++++++++++---- ui/src/types/dashboard.ts | 9 ++- .../components/TableOptions.test.tsx | 9 ++- ui/test/utils/timeSeriesTransformers.test.js | 43 +++++++------- 16 files changed, 215 insertions(+), 61 deletions(-) create mode 100644 ui/src/dashboards/components/GraphOptionsDecimalPlaces.tsx diff --git a/server/swagger.json b/server/swagger.json index 140ae39ca9..8f2188cf16 100644 --- a/server/swagger.json +++ b/server/swagger.json @@ -4689,6 +4689,22 @@ "timeFormat describes the display format for time values according to moment.js date formatting", "type": "string" }, + "decimalPoints": { + "description": + "decimal points indicates whether and how many digits to show after decimal point", + "type": "object", + "properties": { + "isEnforced": { + "description": + "Indicates whether decimal point setting should be enforced", + "type": "bool" + }, + "digits": { + "description": "The number of digits after decimal to display", + "type": "integer" + } + } + }, "links": { "type": "object", "properties": { @@ -5025,11 +5041,6 @@ "description": "visible indicates whether this field should be visible on the table", "type": "boolean" - }, - "precision": { - "description": - "precision indicates how precise each number value should be", - "type": "integer" } } }, diff --git a/ui/src/dashboards/actions/cellEditorOverlay.js b/ui/src/dashboards/actions/cellEditorOverlay.js index 8038ff6b98..3e2d847c07 100644 --- a/ui/src/dashboards/actions/cellEditorOverlay.js +++ b/ui/src/dashboards/actions/cellEditorOverlay.js @@ -72,6 +72,13 @@ export const changeTimeFormat = timeFormat => ({ }, }) +export const changeDecimalPlaces = decimalPlaces => ({ + type: 'CHANGE_DECIMAL_PLACES', + payload: { + decimalPlaces, + }, +}) + export const updateFieldOptions = fieldOptions => ({ type: 'UPDATE_FIELD_OPTIONS', payload: { diff --git a/ui/src/dashboards/components/GraphOptionsCustomizableField.tsx b/ui/src/dashboards/components/GraphOptionsCustomizableField.tsx index bda8f30da6..9a5eec35c0 100644 --- a/ui/src/dashboards/components/GraphOptionsCustomizableField.tsx +++ b/ui/src/dashboards/components/GraphOptionsCustomizableField.tsx @@ -21,7 +21,7 @@ interface RenamableField { visible: boolean } -interface GraphOptionsCustomizableFieldProps { +interface Props { internalName: string displayName: string visible: boolean @@ -36,7 +36,7 @@ interface GraphOptionsCustomizableFieldProps { moveField: (dragIndex: number, hoverIndex: number) => void } -const fieldSource: DragSourceSpec = { +const fieldSource: DragSourceSpec = { beginDrag(props) { return { id: props.id, @@ -112,9 +112,7 @@ function MyDragSource(dragv1, dragv2, dragfunc1) { isDragging: monitor.isDragging(), }) ) -export default class GraphOptionsCustomizableField extends Component< - GraphOptionsCustomizableFieldProps -> { +export default class GraphOptionsCustomizableField extends Component { constructor(props) { super(props) diff --git a/ui/src/dashboards/components/GraphOptionsDecimalPlaces.tsx b/ui/src/dashboards/components/GraphOptionsDecimalPlaces.tsx new file mode 100644 index 0000000000..06d952da29 --- /dev/null +++ b/ui/src/dashboards/components/GraphOptionsDecimalPlaces.tsx @@ -0,0 +1,59 @@ +import React, {PureComponent} from 'react' +import {} from 'src/dashboards/constants' +import {ErrorHandling} from 'src/shared/decorators/errors' +import OptIn from 'src/shared/components/OptIn' + +interface DecimalPlaces { + isEnforced: boolean + digits: number +} + +interface Props extends DecimalPlaces { + onDecimalPlacesChange: (decimalPlaces: DecimalPlaces) => void +} + +const fixedValueString = 'fixed' + +@ErrorHandling +class GraphOptionsDecimalPlaces extends PureComponent { + constructor(props: Props) { + super(props) + } + public onSetValue = valueFromSelector => { + let digits + let isEnforced + if (valueFromSelector === fixedValueString) { + digits = this.props.digits + isEnforced = false + } else if (valueFromSelector === '') { + digits = this.props.digits + isEnforced = true + } else { + digits = Number(valueFromSelector) + if (digits < 0) { + digits = 0 + } + isEnforced = true + } + this.props.onDecimalPlacesChange({digits, isEnforced}) + } + public render() { + const {digits, isEnforced} = this.props + return ( +
    + + +
    + ) + } +} + +export default GraphOptionsDecimalPlaces diff --git a/ui/src/dashboards/components/GraphOptionsTimeFormat.tsx b/ui/src/dashboards/components/GraphOptionsTimeFormat.tsx index 3709df855d..582ffecd3b 100644 --- a/ui/src/dashboards/components/GraphOptionsTimeFormat.tsx +++ b/ui/src/dashboards/components/GraphOptionsTimeFormat.tsx @@ -60,7 +60,7 @@ class GraphOptionsTimeFormat extends PureComponent { const showCustom = !formatOption || customFormat return ( -
    +