Merge branch 'master' into style/table-thresholds-polish
commit
0a8ac81c02
|
@ -265,16 +265,18 @@ func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sortBy := &TableColumn{
|
sortBy := &RenamableField{
|
||||||
InternalName: c.TableOptions.SortBy.InternalName,
|
InternalName: c.TableOptions.SortBy.InternalName,
|
||||||
DisplayName: c.TableOptions.SortBy.DisplayName,
|
DisplayName: c.TableOptions.SortBy.DisplayName,
|
||||||
|
Visible: c.TableOptions.SortBy.Visible,
|
||||||
}
|
}
|
||||||
|
|
||||||
columnNames := make([]*TableColumn, len(c.TableOptions.ColumnNames))
|
fieldNames := make([]*RenamableField, len(c.TableOptions.FieldNames))
|
||||||
for i, column := range c.TableOptions.ColumnNames {
|
for i, field := range c.TableOptions.FieldNames {
|
||||||
columnNames[i] = &TableColumn{
|
fieldNames[i] = &RenamableField{
|
||||||
InternalName: column.InternalName,
|
InternalName: field.InternalName,
|
||||||
DisplayName: column.DisplayName,
|
DisplayName: field.DisplayName,
|
||||||
|
Visible: field.Visible,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,7 +285,7 @@ func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) {
|
||||||
VerticalTimeAxis: c.TableOptions.VerticalTimeAxis,
|
VerticalTimeAxis: c.TableOptions.VerticalTimeAxis,
|
||||||
SortBy: sortBy,
|
SortBy: sortBy,
|
||||||
Wrapping: c.TableOptions.Wrapping,
|
Wrapping: c.TableOptions.Wrapping,
|
||||||
ColumnNames: columnNames,
|
FieldNames: fieldNames,
|
||||||
FixFirstColumn: c.TableOptions.FixFirstColumn,
|
FixFirstColumn: c.TableOptions.FixFirstColumn,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,20 +433,22 @@ func UnmarshalDashboard(data []byte, d *chronograf.Dashboard) error {
|
||||||
|
|
||||||
tableOptions := chronograf.TableOptions{}
|
tableOptions := chronograf.TableOptions{}
|
||||||
if c.TableOptions != nil {
|
if c.TableOptions != nil {
|
||||||
sortBy := chronograf.TableColumn{}
|
sortBy := chronograf.RenamableField{}
|
||||||
if c.TableOptions.SortBy != nil {
|
if c.TableOptions.SortBy != nil {
|
||||||
sortBy.InternalName = c.TableOptions.SortBy.InternalName
|
sortBy.InternalName = c.TableOptions.SortBy.InternalName
|
||||||
sortBy.DisplayName = c.TableOptions.SortBy.DisplayName
|
sortBy.DisplayName = c.TableOptions.SortBy.DisplayName
|
||||||
|
sortBy.Visible = c.TableOptions.SortBy.Visible
|
||||||
}
|
}
|
||||||
tableOptions.SortBy = sortBy
|
tableOptions.SortBy = sortBy
|
||||||
|
|
||||||
columnNames := make([]chronograf.TableColumn, len(c.TableOptions.ColumnNames))
|
fieldNames := make([]chronograf.RenamableField, len(c.TableOptions.FieldNames))
|
||||||
for i, column := range c.TableOptions.ColumnNames {
|
for i, field := range c.TableOptions.FieldNames {
|
||||||
columnNames[i] = chronograf.TableColumn{}
|
fieldNames[i] = chronograf.RenamableField{}
|
||||||
columnNames[i].InternalName = column.InternalName
|
fieldNames[i].InternalName = field.InternalName
|
||||||
columnNames[i].DisplayName = column.DisplayName
|
fieldNames[i].DisplayName = field.DisplayName
|
||||||
|
fieldNames[i].Visible = field.Visible
|
||||||
}
|
}
|
||||||
tableOptions.ColumnNames = columnNames
|
tableOptions.FieldNames = fieldNames
|
||||||
tableOptions.TimeFormat = c.TableOptions.TimeFormat
|
tableOptions.TimeFormat = c.TableOptions.TimeFormat
|
||||||
tableOptions.VerticalTimeAxis = c.TableOptions.VerticalTimeAxis
|
tableOptions.VerticalTimeAxis = c.TableOptions.VerticalTimeAxis
|
||||||
tableOptions.Wrapping = c.TableOptions.Wrapping
|
tableOptions.Wrapping = c.TableOptions.Wrapping
|
||||||
|
|
|
@ -12,7 +12,7 @@ It has these top-level messages:
|
||||||
Dashboard
|
Dashboard
|
||||||
DashboardCell
|
DashboardCell
|
||||||
TableOptions
|
TableOptions
|
||||||
TableColumn
|
RenamableField
|
||||||
Color
|
Color
|
||||||
Legend
|
Legend
|
||||||
Axis
|
Axis
|
||||||
|
@ -316,12 +316,12 @@ func (m *DashboardCell) GetTableOptions() *TableOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
type TableOptions struct {
|
type TableOptions struct {
|
||||||
TimeFormat string `protobuf:"bytes,1,opt,name=timeFormat,proto3" json:"timeFormat,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"`
|
VerticalTimeAxis bool `protobuf:"varint,2,opt,name=verticalTimeAxis,proto3" json:"verticalTimeAxis,omitempty"`
|
||||||
SortBy *TableColumn `protobuf:"bytes,3,opt,name=sortBy" json:"sortBy,omitempty"`
|
SortBy *RenamableField `protobuf:"bytes,3,opt,name=sortBy" json:"sortBy,omitempty"`
|
||||||
Wrapping string `protobuf:"bytes,4,opt,name=wrapping,proto3" json:"wrapping,omitempty"`
|
Wrapping string `protobuf:"bytes,4,opt,name=wrapping,proto3" json:"wrapping,omitempty"`
|
||||||
ColumnNames []*TableColumn `protobuf:"bytes,5,rep,name=columnNames" json:"columnNames,omitempty"`
|
FieldNames []*RenamableField `protobuf:"bytes,5,rep,name=fieldNames" json:"fieldNames,omitempty"`
|
||||||
FixFirstColumn bool `protobuf:"varint,6,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{} }
|
func (m *TableOptions) Reset() { *m = TableOptions{} }
|
||||||
|
@ -343,7 +343,7 @@ func (m *TableOptions) GetVerticalTimeAxis() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *TableOptions) GetSortBy() *TableColumn {
|
func (m *TableOptions) GetSortBy() *RenamableField {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
return m.SortBy
|
return m.SortBy
|
||||||
}
|
}
|
||||||
|
@ -357,9 +357,9 @@ func (m *TableOptions) GetWrapping() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *TableOptions) GetColumnNames() []*TableColumn {
|
func (m *TableOptions) GetFieldNames() []*RenamableField {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
return m.ColumnNames
|
return m.FieldNames
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -371,30 +371,38 @@ func (m *TableOptions) GetFixFirstColumn() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
type TableColumn struct {
|
type RenamableField struct {
|
||||||
InternalName string `protobuf:"bytes,1,opt,name=internalName,proto3" json:"internalName,omitempty"`
|
InternalName string `protobuf:"bytes,1,opt,name=internalName,proto3" json:"internalName,omitempty"`
|
||||||
DisplayName string `protobuf:"bytes,2,opt,name=displayName,proto3" json:"displayName,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"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *TableColumn) Reset() { *m = TableColumn{} }
|
func (m *RenamableField) Reset() { *m = RenamableField{} }
|
||||||
func (m *TableColumn) String() string { return proto.CompactTextString(m) }
|
func (m *RenamableField) String() string { return proto.CompactTextString(m) }
|
||||||
func (*TableColumn) ProtoMessage() {}
|
func (*RenamableField) ProtoMessage() {}
|
||||||
func (*TableColumn) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{4} }
|
func (*RenamableField) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{4} }
|
||||||
|
|
||||||
func (m *TableColumn) GetInternalName() string {
|
func (m *RenamableField) GetInternalName() string {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
return m.InternalName
|
return m.InternalName
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *TableColumn) GetDisplayName() string {
|
func (m *RenamableField) GetDisplayName() string {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
return m.DisplayName
|
return m.DisplayName
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *RenamableField) GetVisible() bool {
|
||||||
|
if m != nil {
|
||||||
|
return m.Visible
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type Color struct {
|
type Color struct {
|
||||||
ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
|
ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||||
Type string `protobuf:"bytes,2,opt,name=Type,proto3" json:"Type,omitempty"`
|
Type string `protobuf:"bytes,2,opt,name=Type,proto3" json:"Type,omitempty"`
|
||||||
|
@ -1296,7 +1304,7 @@ func init() {
|
||||||
proto.RegisterType((*Dashboard)(nil), "internal.Dashboard")
|
proto.RegisterType((*Dashboard)(nil), "internal.Dashboard")
|
||||||
proto.RegisterType((*DashboardCell)(nil), "internal.DashboardCell")
|
proto.RegisterType((*DashboardCell)(nil), "internal.DashboardCell")
|
||||||
proto.RegisterType((*TableOptions)(nil), "internal.TableOptions")
|
proto.RegisterType((*TableOptions)(nil), "internal.TableOptions")
|
||||||
proto.RegisterType((*TableColumn)(nil), "internal.TableColumn")
|
proto.RegisterType((*RenamableField)(nil), "internal.RenamableField")
|
||||||
proto.RegisterType((*Color)(nil), "internal.Color")
|
proto.RegisterType((*Color)(nil), "internal.Color")
|
||||||
proto.RegisterType((*Legend)(nil), "internal.Legend")
|
proto.RegisterType((*Legend)(nil), "internal.Legend")
|
||||||
proto.RegisterType((*Axis)(nil), "internal.Axis")
|
proto.RegisterType((*Axis)(nil), "internal.Axis")
|
||||||
|
@ -1322,104 +1330,105 @@ func init() {
|
||||||
func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) }
|
func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) }
|
||||||
|
|
||||||
var fileDescriptorInternal = []byte{
|
var fileDescriptorInternal = []byte{
|
||||||
// 1573 bytes of a gzipped FileDescriptorProto
|
// 1586 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0x5f, 0x8f, 0xdb, 0x44,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0x5f, 0x8f, 0xdb, 0x44,
|
||||||
0x10, 0x97, 0x93, 0x38, 0x89, 0x27, 0xd7, 0xe3, 0x64, 0x8e, 0xd6, 0x14, 0x09, 0x05, 0x8b, 0x3f,
|
0x10, 0x97, 0x93, 0x38, 0x89, 0x27, 0xd7, 0xe3, 0x64, 0x4e, 0xad, 0x29, 0x12, 0x0a, 0x16, 0x7f,
|
||||||
0xe1, 0x4f, 0x0f, 0x94, 0x0a, 0x81, 0x2a, 0xa8, 0x94, 0xbb, 0xd0, 0x72, 0xf4, 0xda, 0xbb, 0x6e,
|
0xc2, 0x9f, 0x1e, 0x55, 0x2a, 0xa4, 0xaa, 0x82, 0x4a, 0xb9, 0x0b, 0x2d, 0x47, 0xaf, 0xbd, 0xeb,
|
||||||
0xee, 0x8e, 0x27, 0x54, 0x6d, 0x92, 0x4d, 0x62, 0xd5, 0xb1, 0xcd, 0x7a, 0x7d, 0x17, 0xf3, 0x01,
|
0xe6, 0xee, 0x78, 0x42, 0xd5, 0x26, 0x99, 0x24, 0x56, 0x1d, 0xdb, 0xac, 0xed, 0xbb, 0x98, 0x8f,
|
||||||
0xf8, 0x18, 0x48, 0x48, 0xf0, 0x05, 0x10, 0x2f, 0x3c, 0xf1, 0xce, 0x07, 0xe1, 0x2b, 0xc0, 0x23,
|
0xc0, 0x87, 0x40, 0x42, 0x82, 0x2f, 0x80, 0x78, 0xe1, 0x89, 0x77, 0x3e, 0x08, 0x5f, 0x01, 0x1e,
|
||||||
0x9a, 0xdd, 0xb5, 0xb3, 0xb9, 0xa4, 0x55, 0x91, 0x10, 0x6f, 0xfb, 0x9b, 0x19, 0xcf, 0xce, 0xce,
|
0xd1, 0xec, 0xae, 0x1d, 0xe7, 0x92, 0x56, 0x45, 0x42, 0xbc, 0xed, 0x6f, 0x66, 0x3c, 0xbb, 0xf3,
|
||||||
0xcc, 0x6f, 0x76, 0x0d, 0xdb, 0x41, 0x24, 0x18, 0x8f, 0x68, 0xb8, 0x97, 0xf0, 0x58, 0xc4, 0x6e,
|
0x7f, 0x0c, 0xdb, 0x5e, 0x90, 0xa0, 0x08, 0xb8, 0xbf, 0x17, 0x89, 0x30, 0x09, 0xed, 0x66, 0x8e,
|
||||||
0xb3, 0xc0, 0xfe, 0x9f, 0x15, 0xa8, 0x0f, 0xe2, 0x8c, 0x8f, 0x98, 0xbb, 0x0d, 0x95, 0xc3, 0xbe,
|
0xdd, 0x3f, 0x2b, 0x50, 0x1f, 0x84, 0xa9, 0x18, 0xa1, 0xbd, 0x0d, 0x95, 0xc3, 0xbe, 0x63, 0xb4,
|
||||||
0x67, 0xb5, 0xad, 0x4e, 0x95, 0x54, 0x0e, 0xfb, 0xae, 0x0b, 0xb5, 0x47, 0x74, 0xce, 0xbc, 0x4a,
|
0x8d, 0x4e, 0x95, 0x55, 0x0e, 0xfb, 0xb6, 0x0d, 0xb5, 0x27, 0x7c, 0x8e, 0x4e, 0xa5, 0x6d, 0x74,
|
||||||
0xdb, 0xea, 0x38, 0x44, 0xae, 0x51, 0x76, 0x9a, 0x27, 0xcc, 0xab, 0x2a, 0x19, 0xae, 0xdd, 0x9b,
|
0x2c, 0x26, 0xcf, 0x44, 0x3b, 0xcd, 0x22, 0x74, 0xaa, 0x8a, 0x46, 0x67, 0xfb, 0x26, 0x34, 0xcf,
|
||||||
0xd0, 0x3c, 0x4b, 0xd1, 0xdb, 0x9c, 0x79, 0x35, 0x29, 0x2f, 0x31, 0xea, 0x4e, 0x68, 0x9a, 0x5e,
|
0x62, 0xd2, 0x36, 0x47, 0xa7, 0x26, 0xe9, 0x05, 0x26, 0xde, 0x09, 0x8f, 0xe3, 0xcb, 0x50, 0x8c,
|
||||||
0xc6, 0x7c, 0xec, 0xd9, 0x4a, 0x57, 0x60, 0x77, 0x07, 0xaa, 0x67, 0xe4, 0xc8, 0xab, 0x4b, 0x31,
|
0x1d, 0x53, 0xf1, 0x72, 0x6c, 0xef, 0x40, 0xf5, 0x8c, 0x1d, 0x39, 0x75, 0x49, 0xa6, 0xa3, 0xed,
|
||||||
0x2e, 0x5d, 0x0f, 0x1a, 0x7d, 0x36, 0xa1, 0x59, 0x28, 0xbc, 0x46, 0xdb, 0xea, 0x34, 0x49, 0x01,
|
0x40, 0xa3, 0x8f, 0x13, 0x9e, 0xfa, 0x89, 0xd3, 0x68, 0x1b, 0x9d, 0x26, 0xcb, 0x21, 0xe9, 0x39,
|
||||||
0xd1, 0xcf, 0x29, 0x0b, 0xd9, 0x94, 0xd3, 0x89, 0xd7, 0x54, 0x7e, 0x0a, 0xec, 0xee, 0x81, 0x7b,
|
0x45, 0x1f, 0xa7, 0x82, 0x4f, 0x9c, 0xa6, 0xd2, 0x93, 0x63, 0x7b, 0x0f, 0xec, 0xc3, 0x20, 0xc6,
|
||||||
0x18, 0xa5, 0x6c, 0x94, 0x71, 0x36, 0x78, 0x1a, 0x24, 0xe7, 0x8c, 0x07, 0x93, 0xdc, 0x73, 0xa4,
|
0x51, 0x2a, 0x70, 0xf0, 0xdc, 0x8b, 0xce, 0x51, 0x78, 0x93, 0xcc, 0xb1, 0xa4, 0x82, 0x0d, 0x1c,
|
||||||
0x83, 0x0d, 0x1a, 0xdc, 0xe5, 0x21, 0x13, 0x14, 0xf7, 0x06, 0xe9, 0xaa, 0x80, 0xae, 0x0f, 0x5b,
|
0xba, 0xe5, 0x31, 0x26, 0x9c, 0xee, 0x06, 0xa9, 0x2a, 0x87, 0xb6, 0x0b, 0x5b, 0x83, 0x19, 0x17,
|
||||||
0x83, 0x19, 0xe5, 0x6c, 0x3c, 0x60, 0x23, 0xce, 0x84, 0xd7, 0x92, 0xea, 0x15, 0x19, 0xda, 0x1c,
|
0x38, 0x1e, 0xe0, 0x48, 0x60, 0xe2, 0xb4, 0x24, 0x7b, 0x85, 0x46, 0x32, 0xc7, 0x62, 0xca, 0x03,
|
||||||
0xf3, 0x29, 0x8d, 0x82, 0xef, 0xa8, 0x08, 0xe2, 0xc8, 0xdb, 0x52, 0x36, 0xa6, 0x0c, 0xb3, 0x44,
|
0xef, 0x3b, 0x9e, 0x78, 0x61, 0xe0, 0x6c, 0x29, 0x99, 0x32, 0x8d, 0xbc, 0xc4, 0x42, 0x1f, 0x9d,
|
||||||
0xe2, 0x90, 0x79, 0xd7, 0x54, 0x96, 0x70, 0xed, 0xff, 0x6a, 0x81, 0xd3, 0xa7, 0xe9, 0x6c, 0x18,
|
0x6b, 0xca, 0x4b, 0x74, 0x76, 0x7f, 0x35, 0xc0, 0xea, 0xf3, 0x78, 0x36, 0x0c, 0xb9, 0x18, 0xbf,
|
||||||
0x53, 0x3e, 0x7e, 0xa1, 0x5c, 0xdf, 0x02, 0x7b, 0xc4, 0xc2, 0x30, 0xf5, 0xaa, 0xed, 0x6a, 0xa7,
|
0x92, 0xaf, 0x6f, 0x81, 0x39, 0x42, 0xdf, 0x8f, 0x9d, 0x6a, 0xbb, 0xda, 0x69, 0x75, 0x6f, 0xec,
|
||||||
0xd5, 0xbd, 0xb1, 0x57, 0x16, 0xb1, 0xf4, 0x73, 0xc0, 0xc2, 0x90, 0x28, 0x2b, 0xf7, 0x23, 0x70,
|
0x15, 0x41, 0x2c, 0xf4, 0x1c, 0xa0, 0xef, 0x33, 0x25, 0x65, 0xdf, 0x06, 0x2b, 0xc1, 0x79, 0xe4,
|
||||||
0x04, 0x9b, 0x27, 0x21, 0x15, 0x2c, 0xf5, 0x6a, 0xf2, 0x13, 0x77, 0xf9, 0xc9, 0xa9, 0x56, 0x91,
|
0xf3, 0x04, 0x63, 0xa7, 0x26, 0x3f, 0xb1, 0x97, 0x9f, 0x9c, 0x6a, 0x16, 0x5b, 0x0a, 0xad, 0x99,
|
||||||
0xa5, 0xd1, 0xda, 0x51, 0xec, 0xf5, 0xa3, 0xf8, 0xbf, 0x55, 0xe1, 0xda, 0xca, 0x76, 0xee, 0x16,
|
0x62, 0xae, 0x9b, 0xe2, 0xfe, 0x56, 0x85, 0x6b, 0x2b, 0xd7, 0xd9, 0x5b, 0x60, 0x2c, 0xe4, 0xcb,
|
||||||
0x58, 0x0b, 0x19, 0xb9, 0x4d, 0xac, 0x05, 0xa2, 0x5c, 0x46, 0x6d, 0x13, 0x2b, 0x47, 0x74, 0x29,
|
0x4d, 0x66, 0x2c, 0x08, 0x65, 0xf2, 0xd5, 0x26, 0x33, 0x32, 0x42, 0x97, 0x32, 0x37, 0x4c, 0x66,
|
||||||
0x7b, 0xc3, 0x26, 0xd6, 0x25, 0xa2, 0x99, 0xec, 0x08, 0x9b, 0x58, 0x33, 0xf7, 0x5d, 0x68, 0x7c,
|
0x5c, 0x12, 0x9a, 0xc9, 0x8c, 0x30, 0x99, 0x31, 0xb3, 0x3f, 0x80, 0xc6, 0xb7, 0x29, 0x0a, 0x0f,
|
||||||
0x9b, 0x31, 0x1e, 0xb0, 0xd4, 0xb3, 0x65, 0x74, 0x2f, 0x2d, 0xa3, 0x7b, 0x9c, 0x31, 0x9e, 0x93,
|
0x63, 0xc7, 0x94, 0xaf, 0x7b, 0x6d, 0xf9, 0xba, 0xa7, 0x29, 0x8a, 0x8c, 0xe5, 0x7c, 0xf2, 0x86,
|
||||||
0x42, 0x8f, 0xd9, 0x90, 0xdd, 0xa4, 0x5a, 0x43, 0xae, 0x51, 0x26, 0xb0, 0xf3, 0x1a, 0x4a, 0x86,
|
0xcc, 0x26, 0x95, 0x1a, 0xf2, 0x4c, 0xb4, 0x84, 0x32, 0xaf, 0xa1, 0x68, 0x74, 0xd6, 0x5e, 0x54,
|
||||||
0x6b, 0x9d, 0x45, 0xd5, 0x0f, 0x98, 0xc5, 0x8f, 0xa1, 0x46, 0x17, 0x2c, 0xf5, 0x1c, 0xe9, 0xff,
|
0xf9, 0x40, 0x5e, 0xfc, 0x14, 0x6a, 0x7c, 0x81, 0xb1, 0x63, 0x49, 0xfd, 0x6f, 0xbf, 0xc0, 0x61,
|
||||||
0x8d, 0x67, 0x24, 0x6c, 0xaf, 0xb7, 0x60, 0xe9, 0x17, 0x91, 0xe0, 0x39, 0x91, 0xe6, 0xee, 0x3b,
|
0x7b, 0xbd, 0x05, 0xc6, 0x5f, 0x04, 0x89, 0xc8, 0x98, 0x14, 0xb7, 0xdf, 0x87, 0xfa, 0x28, 0xf4,
|
||||||
0x50, 0x1f, 0xc5, 0x61, 0xcc, 0x53, 0x0f, 0xae, 0x06, 0x76, 0x80, 0x72, 0xa2, 0xd5, 0x6e, 0x07,
|
0x43, 0x11, 0x3b, 0x70, 0xf5, 0x61, 0x07, 0x44, 0x67, 0x9a, 0x6d, 0x77, 0xa0, 0xee, 0xe3, 0x14,
|
||||||
0xea, 0x21, 0x9b, 0xb2, 0x68, 0x2c, 0x3b, 0xa3, 0xd5, 0xdd, 0x59, 0x1a, 0x1e, 0x49, 0x39, 0xd1,
|
0x83, 0xb1, 0xcc, 0x8c, 0x56, 0x77, 0x67, 0x29, 0x78, 0x24, 0xe9, 0x4c, 0xf3, 0xed, 0x7b, 0xb0,
|
||||||
0x7a, 0xf7, 0x0e, 0x6c, 0x09, 0x3a, 0x0c, 0xd9, 0x71, 0x82, 0x59, 0x4c, 0x65, 0x97, 0xb4, 0xba,
|
0x95, 0xf0, 0xa1, 0x8f, 0xc7, 0x11, 0x79, 0x31, 0x96, 0x59, 0xd2, 0xea, 0x5e, 0x2f, 0xc5, 0xa3,
|
||||||
0xd7, 0x8d, 0x7a, 0x18, 0x5a, 0xb2, 0x62, 0x7b, 0xf3, 0x3e, 0x38, 0x65, 0x84, 0x48, 0x92, 0xa7,
|
0xc4, 0x65, 0x2b, 0xb2, 0x37, 0x1f, 0x82, 0x55, 0xbc, 0x90, 0x8a, 0xe4, 0x39, 0x66, 0xd2, 0xdf,
|
||||||
0x2c, 0x97, 0xf9, 0x76, 0x08, 0x2e, 0xdd, 0x37, 0xc1, 0xbe, 0xa0, 0x61, 0xa6, 0x7a, 0xa5, 0xd5,
|
0x16, 0xa3, 0xa3, 0xfd, 0x0e, 0x98, 0x17, 0xdc, 0x4f, 0x55, 0xae, 0xb4, 0xba, 0xdb, 0x4b, 0x9d,
|
||||||
0xdd, 0x5e, 0xfa, 0xec, 0x2d, 0x82, 0x94, 0x28, 0xe5, 0x9d, 0xca, 0xa7, 0x96, 0xff, 0x7d, 0x05,
|
0xbd, 0x85, 0x17, 0x33, 0xc5, 0xbc, 0x57, 0xb9, 0x6b, 0xb8, 0xdf, 0x57, 0x60, 0xab, 0x7c, 0x8f,
|
||||||
0xb6, 0xcc, 0x7d, 0xdc, 0xd7, 0x01, 0x44, 0x30, 0x67, 0xf7, 0x62, 0x3e, 0xa7, 0x42, 0xfb, 0x34,
|
0xfd, 0x16, 0x40, 0xe2, 0xcd, 0xf1, 0x41, 0x28, 0xe6, 0x3c, 0xd1, 0x3a, 0x4b, 0x14, 0xfb, 0x43,
|
||||||
0x24, 0xee, 0x7b, 0xb0, 0x73, 0xc1, 0xb8, 0x08, 0x46, 0x34, 0x3c, 0x0d, 0xe6, 0x0c, 0xfd, 0xc9,
|
0xd8, 0xb9, 0x40, 0x91, 0x78, 0x23, 0xee, 0x9f, 0x7a, 0x73, 0x24, 0x7d, 0xf2, 0x96, 0x26, 0x5b,
|
||||||
0x5d, 0x9a, 0x64, 0x4d, 0xee, 0xde, 0x82, 0x7a, 0x1a, 0x73, 0xb1, 0x9f, 0xcb, 0x7a, 0xb7, 0xba,
|
0xa3, 0xdb, 0xb7, 0xa1, 0x1e, 0x87, 0x22, 0xd9, 0xcf, 0x64, 0xbc, 0x5b, 0x5d, 0x67, 0xf9, 0x0e,
|
||||||
0xaf, 0x5c, 0x39, 0xdb, 0x41, 0x1c, 0x66, 0xf3, 0x88, 0x68, 0x23, 0x24, 0xf0, 0x25, 0xa7, 0x49,
|
0x86, 0x01, 0x9f, 0xd3, 0xbd, 0x0f, 0x3c, 0xf4, 0xc7, 0x4c, 0xcb, 0x51, 0x0d, 0x5f, 0x0a, 0x1e,
|
||||||
0x12, 0x44, 0xd3, 0x62, 0x48, 0x14, 0xd8, 0xfd, 0x04, 0x5a, 0x23, 0x69, 0x8d, 0x6d, 0x5f, 0x74,
|
0x45, 0x5e, 0x30, 0xcd, 0xfb, 0x44, 0x8e, 0xed, 0xbb, 0x00, 0x13, 0x12, 0xa6, 0xc4, 0xcf, 0xf3,
|
||||||
0xc7, 0x33, 0xfc, 0x99, 0x96, 0xee, 0xdb, 0xb0, 0x3d, 0x09, 0x16, 0xf7, 0x02, 0x9e, 0x0a, 0xa5,
|
0xe3, 0xc5, 0x1a, 0x4b, 0xb2, 0xf6, 0x7b, 0xb0, 0x3d, 0xf1, 0x16, 0x0f, 0x3c, 0x11, 0x27, 0x07,
|
||||||
0x96, 0x1d, 0xd3, 0x24, 0x57, 0xa4, 0xfe, 0x00, 0x5a, 0x86, 0x0f, 0xec, 0xfb, 0xc2, 0xb7, 0x24,
|
0xa1, 0x9f, 0xce, 0x03, 0x99, 0x35, 0x4d, 0x76, 0x85, 0xea, 0x46, 0xb0, 0xbd, 0xaa, 0x85, 0xd2,
|
||||||
0x9d, 0x4a, 0xc4, 0x8a, 0xcc, 0x6d, 0x43, 0x6b, 0x1c, 0xa4, 0x49, 0x48, 0x73, 0x83, 0x97, 0xa6,
|
0x3f, 0xbf, 0x40, 0xd6, 0x9e, 0xf2, 0xc7, 0x0a, 0xcd, 0x6e, 0x43, 0x6b, 0xec, 0xc5, 0x91, 0xcf,
|
||||||
0xc8, 0x9f, 0x82, 0x2d, 0xbb, 0xc3, 0xe0, 0xb2, 0x53, 0x70, 0x59, 0xce, 0xc8, 0x8a, 0x31, 0x23,
|
0xb3, 0x52, 0x79, 0x96, 0x49, 0xd4, 0x4d, 0x2e, 0xbc, 0xd8, 0x1b, 0xfa, 0xaa, 0x29, 0x36, 0x59,
|
||||||
0x77, 0xa0, 0xfa, 0x25, 0x5b, 0xe8, 0xb1, 0x89, 0xcb, 0x92, 0xf1, 0x35, 0x83, 0xf1, 0xbb, 0x60,
|
0x0e, 0xdd, 0x29, 0x98, 0x32, 0x7d, 0x4a, 0xc5, 0x6e, 0xe5, 0xc5, 0x2e, 0x9b, 0x68, 0xa5, 0xd4,
|
||||||
0x9f, 0xcb, 0xd2, 0x2a, 0x26, 0x2a, 0xe0, 0xdf, 0x85, 0xba, 0xea, 0xae, 0xd2, 0xb3, 0x65, 0x78,
|
0x44, 0x77, 0xa0, 0xfa, 0x25, 0x2e, 0x74, 0x5f, 0xa5, 0x63, 0xd1, 0x12, 0x6a, 0xa5, 0x96, 0xb0,
|
||||||
0x6e, 0x43, 0xeb, 0x98, 0x07, 0x2c, 0x12, 0x8a, 0xc3, 0x3a, 0x50, 0x43, 0xe4, 0xff, 0x62, 0x41,
|
0x0b, 0xe6, 0xb9, 0x8c, 0xbd, 0x2a, 0x55, 0x05, 0xdc, 0xfb, 0x50, 0x57, 0xe9, 0x57, 0x68, 0x36,
|
||||||
0x4d, 0x96, 0xcc, 0x87, 0xad, 0x90, 0x4d, 0xe9, 0x28, 0xdf, 0x8f, 0xb3, 0x68, 0x9c, 0x7a, 0x56,
|
0x4a, 0x9a, 0xdb, 0xd0, 0x3a, 0x16, 0x1e, 0x06, 0x89, 0x2a, 0x72, 0x6d, 0x42, 0x89, 0xe4, 0xfe,
|
||||||
0xbb, 0xda, 0xa9, 0x92, 0x15, 0x99, 0x7b, 0x1d, 0xea, 0x43, 0xa5, 0xad, 0xb4, 0xab, 0x1d, 0x87,
|
0x62, 0x40, 0x4d, 0xc6, 0xd4, 0x85, 0x2d, 0x1f, 0xa7, 0x7c, 0x94, 0xed, 0x87, 0x69, 0x30, 0x8e,
|
||||||
0x68, 0x84, 0xa1, 0x85, 0x74, 0xc8, 0x42, 0x7d, 0x04, 0x05, 0xd0, 0x3a, 0xe1, 0x6c, 0x12, 0x2c,
|
0x1d, 0xa3, 0x5d, 0xed, 0x54, 0xd9, 0x0a, 0xcd, 0xbe, 0x0e, 0xf5, 0xa1, 0xe2, 0x56, 0xda, 0xd5,
|
||||||
0xf4, 0x31, 0x34, 0x42, 0x79, 0x9a, 0x4d, 0x50, 0xae, 0x4e, 0xa2, 0x11, 0x1e, 0x60, 0x48, 0xd3,
|
0x8e, 0xc5, 0x34, 0xa2, 0xa7, 0xf9, 0x7c, 0x88, 0xbe, 0x36, 0x41, 0x01, 0x92, 0x8e, 0x04, 0x4e,
|
||||||
0x92, 0xd8, 0xb8, 0x46, 0xcf, 0xe9, 0x88, 0x86, 0x05, 0xb3, 0x15, 0xf0, 0x7f, 0xb7, 0x70, 0xe2,
|
0xbc, 0x85, 0x36, 0x43, 0x23, 0xa2, 0xc7, 0xe9, 0x84, 0xe8, 0xca, 0x12, 0x8d, 0xc8, 0x80, 0x21,
|
||||||
0xab, 0x49, 0xb5, 0x96, 0xe1, 0x57, 0xa1, 0x89, 0x53, 0xec, 0xc9, 0x05, 0xe5, 0xfa, 0xc0, 0x0d,
|
0x8f, 0x8b, 0xca, 0xa7, 0x33, 0x69, 0x8e, 0x47, 0xdc, 0xcf, 0x4b, 0x5f, 0x01, 0xf7, 0x77, 0x83,
|
||||||
0xc4, 0xe7, 0x94, 0xbb, 0x1f, 0x42, 0x5d, 0x12, 0x60, 0xc3, 0xd4, 0x2c, 0xdc, 0xc9, 0xac, 0x12,
|
0x46, 0x82, 0x6a, 0x65, 0x6b, 0x1e, 0x7e, 0x03, 0x9a, 0xd4, 0xe6, 0x9e, 0x5d, 0x70, 0xa1, 0x0d,
|
||||||
0x6d, 0x56, 0xce, 0x95, 0x9a, 0x31, 0x57, 0xca, 0xc3, 0xda, 0xe6, 0x61, 0x6f, 0x81, 0x8d, 0x03,
|
0x6e, 0x10, 0x3e, 0xe7, 0xc2, 0xfe, 0x04, 0xea, 0xb2, 0x42, 0x36, 0xb4, 0xd5, 0x5c, 0x9d, 0xf4,
|
||||||
0x2a, 0x97, 0xd1, 0x6f, 0xf4, 0xac, 0xc6, 0x98, 0xb2, 0xf2, 0xcf, 0xe0, 0xda, 0xca, 0x8e, 0xe5,
|
0x2a, 0xd3, 0x62, 0x45, 0xe3, 0xa9, 0x95, 0x1a, 0x4f, 0x61, 0xac, 0x59, 0x36, 0xf6, 0x16, 0x98,
|
||||||
0x4e, 0xd6, 0xea, 0x4e, 0x4b, 0x32, 0x3b, 0x9a, 0xbc, 0x48, 0x96, 0x94, 0x85, 0x6c, 0x24, 0xd8,
|
0xd4, 0xc1, 0x32, 0xf9, 0xfa, 0x8d, 0x9a, 0x55, 0x9f, 0x53, 0x52, 0xee, 0x19, 0x5c, 0x5b, 0xb9,
|
||||||
0x58, 0xe6, 0xbb, 0x49, 0x4a, 0xec, 0xff, 0x68, 0x2d, 0xfd, 0xca, 0xfd, 0xf0, 0x3e, 0x1b, 0xc5,
|
0xb1, 0xb8, 0xc9, 0x58, 0xbd, 0x69, 0x59, 0xed, 0x96, 0xae, 0x6e, 0x2a, 0xa5, 0x18, 0x7d, 0x1c,
|
||||||
0xf3, 0x39, 0x8d, 0xc6, 0xda, 0x75, 0x01, 0x31, 0x6f, 0xe3, 0xa1, 0x76, 0x5d, 0x19, 0x0f, 0x11,
|
0x25, 0x38, 0xd6, 0x59, 0x57, 0x60, 0xf7, 0x47, 0x63, 0xa9, 0x57, 0xde, 0x47, 0x29, 0x3a, 0x0a,
|
||||||
0xf3, 0x44, 0x57, 0xb0, 0xc2, 0x13, 0xec, 0x9d, 0x39, 0xa3, 0x69, 0xc6, 0xd9, 0x9c, 0x45, 0x42,
|
0xe7, 0x73, 0x1e, 0x8c, 0xb5, 0xea, 0x1c, 0x92, 0xdf, 0xc6, 0x43, 0xad, 0xba, 0x32, 0x1e, 0x12,
|
||||||
0xa7, 0xc0, 0x14, 0xb9, 0x37, 0xa0, 0x21, 0xe8, 0xf4, 0x09, 0x8e, 0x20, 0x5d, 0x49, 0x41, 0xa7,
|
0x16, 0x91, 0x8e, 0x60, 0x45, 0x44, 0x94, 0x3b, 0x73, 0xe4, 0x71, 0x2a, 0x70, 0x8e, 0x41, 0xa2,
|
||||||
0x0f, 0x58, 0xee, 0xbe, 0x06, 0xce, 0x24, 0x60, 0xe1, 0x58, 0xaa, 0x54, 0x39, 0x9b, 0x52, 0xf0,
|
0x5d, 0x50, 0x26, 0xd9, 0x37, 0xa0, 0x91, 0xf0, 0xe9, 0x33, 0xea, 0x51, 0x3a, 0x92, 0x09, 0x9f,
|
||||||
0x80, 0xe5, 0xfe, 0xdf, 0x16, 0xd4, 0x07, 0x8c, 0x5f, 0x30, 0xfe, 0x42, 0x17, 0x9d, 0xf9, 0x80,
|
0x3e, 0xc2, 0xcc, 0x7e, 0x13, 0x2c, 0x59, 0xa5, 0x92, 0xa5, 0xc2, 0xd9, 0x94, 0x84, 0x47, 0x98,
|
||||||
0xa8, 0x3e, 0xe7, 0x01, 0x51, 0xdb, 0xfc, 0x80, 0xb0, 0x97, 0x0f, 0x88, 0x5d, 0xb0, 0x07, 0x7c,
|
0xb9, 0x7f, 0x1b, 0x50, 0x1f, 0xa0, 0xb8, 0x40, 0xf1, 0x4a, 0x93, 0xb0, 0xbc, 0x61, 0x54, 0x5f,
|
||||||
0x74, 0xd8, 0x97, 0x11, 0x55, 0x89, 0x02, 0xd8, 0x8d, 0xbd, 0x91, 0x08, 0x2e, 0x98, 0x7e, 0x55,
|
0xb2, 0x61, 0xd4, 0x36, 0x6f, 0x18, 0xe6, 0x72, 0xc3, 0xd8, 0x05, 0x73, 0x20, 0x46, 0x87, 0x7d,
|
||||||
0x68, 0xb4, 0x76, 0xff, 0x35, 0x37, 0x5c, 0xe5, 0xff, 0xf2, 0x71, 0xe1, 0xff, 0x60, 0x41, 0xfd,
|
0xf9, 0xa2, 0x2a, 0x53, 0x80, 0xb2, 0xb1, 0x37, 0x4a, 0xbc, 0x0b, 0xd4, 0x6b, 0x87, 0x46, 0x6b,
|
||||||
0x88, 0xe6, 0x71, 0x26, 0xd6, 0xba, 0xb6, 0x0d, 0xad, 0x5e, 0x92, 0x84, 0xc1, 0x68, 0x85, 0xa9,
|
0x03, 0xb2, 0xb9, 0x61, 0xd6, 0xff, 0xcb, 0xed, 0xc3, 0xfd, 0xc1, 0x80, 0xfa, 0x11, 0xcf, 0xc2,
|
||||||
0x86, 0x08, 0x2d, 0x1e, 0x1a, 0xf5, 0x50, 0xb9, 0x30, 0x45, 0x38, 0xfc, 0x0f, 0xe4, 0x9b, 0x40,
|
0x34, 0x59, 0xcb, 0xda, 0x36, 0xb4, 0x7a, 0x51, 0xe4, 0x7b, 0xa3, 0x95, 0x4a, 0x2d, 0x91, 0x48,
|
||||||
0x5d, 0xf0, 0xc6, 0xf0, 0x57, 0x4f, 0x01, 0xa9, 0xc4, 0xa4, 0xf5, 0x32, 0x11, 0x4f, 0xc2, 0xf8,
|
0xe2, 0x71, 0x29, 0x1e, 0xca, 0x17, 0x65, 0x12, 0x4d, 0x87, 0x03, 0xb9, 0x34, 0xa8, 0x0d, 0xa0,
|
||||||
0x52, 0x66, 0xa7, 0x49, 0x4a, 0xec, 0xff, 0x51, 0x81, 0xda, 0xff, 0x75, 0x8f, 0x6f, 0x81, 0x15,
|
0x34, 0x1d, 0xd4, 0xae, 0x20, 0x99, 0xe4, 0xb4, 0x5e, 0x9a, 0x84, 0x13, 0x3f, 0xbc, 0x94, 0xde,
|
||||||
0xe8, 0xe6, 0xb0, 0x82, 0xf2, 0x56, 0x6f, 0x18, 0xb7, 0xba, 0x07, 0x8d, 0x9c, 0xd3, 0x68, 0xca,
|
0x69, 0xb2, 0x02, 0xbb, 0x7f, 0x54, 0xa0, 0xf6, 0x7f, 0x0d, 0xfa, 0x2d, 0x30, 0x3c, 0x9d, 0x1c,
|
||||||
0x52, 0xaf, 0x29, 0xa7, 0x51, 0x01, 0xa5, 0x46, 0xf2, 0x4e, 0x5d, 0xe7, 0x0e, 0x29, 0x60, 0xc9,
|
0x86, 0x57, 0x8c, 0xfd, 0x46, 0x69, 0xec, 0x3b, 0xd0, 0xc8, 0x04, 0x0f, 0xa6, 0x18, 0x3b, 0x4d,
|
||||||
0x23, 0x30, 0x78, 0xf4, 0x81, 0xbe, 0xf9, 0x5b, 0x32, 0x22, 0x6f, 0x35, 0x2d, 0x57, 0x2f, 0xfc,
|
0xd9, 0x8d, 0x72, 0x28, 0x39, 0xb2, 0xee, 0xd4, 0xbc, 0xb7, 0x58, 0x0e, 0x8b, 0x3a, 0x82, 0x52,
|
||||||
0xff, 0xee, 0x86, 0xfd, 0xcb, 0x02, 0xbb, 0x24, 0xe1, 0xc1, 0x2a, 0x09, 0x0f, 0x96, 0x24, 0xec,
|
0x1d, 0x7d, 0xac, 0x57, 0x83, 0xd6, 0xd5, 0xd1, 0xb2, 0x69, 0x23, 0xf8, 0xef, 0x46, 0xf0, 0x5f,
|
||||||
0xef, 0x17, 0x24, 0xec, 0xef, 0x23, 0x26, 0x27, 0x05, 0x09, 0xc9, 0x09, 0x16, 0xeb, 0x3e, 0x8f,
|
0x06, 0x98, 0x45, 0x11, 0x1e, 0xac, 0x16, 0xe1, 0xc1, 0xb2, 0x08, 0xfb, 0xfb, 0x79, 0x11, 0xf6,
|
||||||
0xb3, 0x64, 0x3f, 0x57, 0x55, 0x75, 0x48, 0x89, 0xb1, 0x73, 0xbf, 0x9e, 0x31, 0xae, 0x53, 0xed,
|
0xf7, 0x09, 0xb3, 0x93, 0xbc, 0x08, 0xd9, 0x09, 0x05, 0xeb, 0xa1, 0x08, 0xd3, 0x68, 0x3f, 0x53,
|
||||||
0x10, 0x8d, 0xb0, 0xcf, 0x8f, 0xe4, 0x80, 0x52, 0xc9, 0x55, 0xc0, 0x7d, 0x0b, 0x6c, 0x82, 0xc9,
|
0x51, 0xb5, 0x58, 0x81, 0x29, 0x73, 0xbf, 0x9e, 0xa1, 0xd0, 0xae, 0xb6, 0x98, 0x46, 0x94, 0xe7,
|
||||||
0x93, 0x19, 0x5e, 0xa9, 0x8b, 0x14, 0x13, 0xa5, 0x45, 0xa7, 0xea, 0xc5, 0xaf, 0x1b, 0xbe, 0x78,
|
0x47, 0xb2, 0x41, 0x29, 0xe7, 0x2a, 0x60, 0xbf, 0x0b, 0x26, 0x23, 0xe7, 0x49, 0x0f, 0xaf, 0xc4,
|
||||||
0xff, 0xbf, 0x0f, 0xf5, 0xc1, 0x2c, 0x98, 0x88, 0xe2, 0xfd, 0xf4, 0xb2, 0x31, 0xe0, 0x82, 0x39,
|
0x45, 0x92, 0x99, 0xe2, 0x92, 0x52, 0xf5, 0x4b, 0xa0, 0x13, 0x3e, 0xff, 0x41, 0xf8, 0x08, 0xea,
|
||||||
0x93, 0x3a, 0xa2, 0x4d, 0xfc, 0xc7, 0xe0, 0x94, 0xc2, 0x65, 0x38, 0x96, 0x19, 0x8e, 0x0b, 0xb5,
|
0x83, 0x99, 0x37, 0x49, 0xf2, 0x05, 0xeb, 0xf5, 0x52, 0x83, 0xf3, 0xe6, 0x28, 0x79, 0x4c, 0x8b,
|
||||||
0xb3, 0x28, 0x10, 0x05, 0xd5, 0x71, 0x8d, 0x87, 0x7d, 0x9c, 0xd1, 0x48, 0x04, 0x22, 0x2f, 0xa8,
|
0xb8, 0x4f, 0xc1, 0x2a, 0x88, 0xcb, 0xe7, 0x18, 0xe5, 0xe7, 0xd8, 0x50, 0x3b, 0x0b, 0xbc, 0x24,
|
||||||
0x5e, 0x60, 0xff, 0xb6, 0x0e, 0x1f, 0xdd, 0x9d, 0x25, 0x09, 0xe3, 0x7a, 0x6c, 0x28, 0x20, 0x37,
|
0x2f, 0x75, 0x3a, 0x93, 0xb1, 0x4f, 0x53, 0x1e, 0x24, 0x5e, 0x92, 0xe5, 0xa5, 0x9e, 0x63, 0xf7,
|
||||||
0x89, 0x2f, 0x99, 0x9a, 0xf8, 0x55, 0xa2, 0x80, 0xff, 0x0d, 0x38, 0xbd, 0x90, 0x71, 0x41, 0xb2,
|
0x8e, 0x7e, 0x3e, 0xa9, 0x3b, 0x8b, 0x22, 0x14, 0xba, 0x6d, 0x28, 0x20, 0x2f, 0x09, 0x2f, 0x51,
|
||||||
0x90, 0x6d, 0xba, 0x89, 0xbf, 0x1a, 0x1c, 0x3f, 0x2a, 0x22, 0xc0, 0xf5, 0x72, 0x44, 0x54, 0xaf,
|
0x75, 0xfc, 0x2a, 0x53, 0xc0, 0xfd, 0x06, 0xac, 0x9e, 0x8f, 0x22, 0x61, 0xa9, 0x8f, 0x9b, 0x26,
|
||||||
0x8c, 0x88, 0x07, 0x34, 0xa1, 0x87, 0x7d, 0xd9, 0xe7, 0x55, 0xa2, 0x91, 0xff, 0x93, 0x05, 0x35,
|
0xf1, 0x57, 0x83, 0xe3, 0x27, 0xf9, 0x0b, 0xe8, 0xbc, 0x6c, 0x11, 0xd5, 0x2b, 0x2d, 0xe2, 0x11,
|
||||||
0x9c, 0x45, 0x86, 0xeb, 0xda, 0xf3, 0xe6, 0xd8, 0x09, 0x8f, 0x2f, 0x82, 0x31, 0xe3, 0xc5, 0xe1,
|
0x8f, 0xf8, 0x61, 0x5f, 0xe6, 0x79, 0x95, 0x69, 0xe4, 0xfe, 0x64, 0x40, 0x8d, 0x7a, 0x51, 0x49,
|
||||||
0x0a, 0x2c, 0x93, 0x3e, 0x9a, 0xb1, 0xf2, 0xc2, 0xd7, 0x08, 0x7b, 0x0d, 0x7f, 0x0f, 0x0a, 0x2e,
|
0x75, 0xed, 0x65, 0x7d, 0xec, 0x44, 0x84, 0x17, 0xde, 0x18, 0x45, 0x6e, 0x5c, 0x8e, 0xa5, 0xd3,
|
||||||
0x19, 0xbd, 0x86, 0x62, 0xa2, 0x94, 0xf8, 0x70, 0x1b, 0x64, 0x09, 0xe3, 0xbd, 0xf1, 0x3c, 0x28,
|
0x47, 0x33, 0x2c, 0x06, 0xbe, 0x46, 0x94, 0x6b, 0xf4, 0xff, 0x90, 0xd7, 0x52, 0x29, 0xd7, 0x88,
|
||||||
0x1e, 0x39, 0x86, 0xc4, 0xbf, 0xab, 0x7e, 0x38, 0xd6, 0x26, 0x9a, 0xb5, 0xf9, 0xe7, 0xe4, 0x6a,
|
0xcc, 0x14, 0x93, 0x36, 0xbb, 0x41, 0x1a, 0xa1, 0xe8, 0x8d, 0xe7, 0x5e, 0xbe, 0x01, 0x95, 0x28,
|
||||||
0xe4, 0xfe, 0xcf, 0x16, 0x34, 0x1e, 0xea, 0xd7, 0x98, 0x79, 0x0a, 0xeb, 0x99, 0xa7, 0xa8, 0xac,
|
0xee, 0x7d, 0xf5, 0x47, 0xb2, 0xd6, 0xd1, 0x8c, 0xcd, 0x7f, 0x2f, 0x57, 0x5f, 0xee, 0xfe, 0x6c,
|
||||||
0x9c, 0xa2, 0x0b, 0xbb, 0x85, 0xcd, 0xca, 0xfe, 0x2a, 0x0b, 0x1b, 0x75, 0x3a, 0xa3, 0xb5, 0xb2,
|
0x40, 0xe3, 0xb1, 0xde, 0xd5, 0xca, 0x56, 0x18, 0x2f, 0xb4, 0xa2, 0xb2, 0x62, 0x45, 0x17, 0x76,
|
||||||
0x58, 0x2f, 0xf2, 0x37, 0x72, 0xba, 0x6a, 0xb3, 0xa9, 0xe0, 0x6b, 0x55, 0x69, 0x43, 0x4b, 0xff,
|
0x73, 0x99, 0x95, 0xfb, 0x95, 0x17, 0x36, 0xf2, 0xb4, 0x47, 0x6b, 0x45, 0xb0, 0x5e, 0xe5, 0x77,
|
||||||
0x45, 0xca, 0x7f, 0x32, 0x3d, 0x54, 0x0d, 0x91, 0xdf, 0x85, 0xfa, 0x41, 0x1c, 0x4d, 0x82, 0xa9,
|
0xe5, 0x74, 0x55, 0x66, 0x53, 0xc0, 0xd7, 0xa2, 0xd2, 0x86, 0x96, 0xfe, 0xcd, 0x94, 0x3f, 0x6d,
|
||||||
0xdb, 0x81, 0x5a, 0x2f, 0x13, 0x33, 0xe9, 0xb1, 0xd5, 0xdd, 0x35, 0x88, 0x9f, 0x89, 0x99, 0xb2,
|
0xba, 0xa9, 0x96, 0x48, 0x6e, 0x17, 0xea, 0x07, 0x61, 0x30, 0xf1, 0xa6, 0x76, 0x07, 0x6a, 0xbd,
|
||||||
0x21, 0xd2, 0xc2, 0xff, 0x0c, 0x60, 0x29, 0xc3, 0x5b, 0x62, 0x59, 0x8d, 0x47, 0xec, 0x12, 0x5b,
|
0x34, 0x99, 0x49, 0x8d, 0xad, 0xee, 0x6e, 0xa9, 0xf0, 0xd3, 0x64, 0xa6, 0x64, 0x98, 0x94, 0x70,
|
||||||
0x26, 0x95, 0x5e, 0x9a, 0x64, 0x83, 0xc6, 0xff, 0x1c, 0x9c, 0xfd, 0x2c, 0x08, 0xc7, 0x87, 0xd1,
|
0x3f, 0x03, 0x58, 0xd2, 0x68, 0x4a, 0x2c, 0xa3, 0xf1, 0x04, 0x2f, 0x29, 0x65, 0x62, 0xa9, 0xa5,
|
||||||
0x24, 0xc6, 0xd1, 0x71, 0xce, 0x78, 0xba, 0xac, 0x57, 0x01, 0x31, 0xdd, 0x38, 0x45, 0x4a, 0x0e,
|
0xc9, 0x36, 0x70, 0xdc, 0xcf, 0xc1, 0xda, 0x4f, 0x3d, 0x7f, 0x7c, 0x18, 0x4c, 0x42, 0x6a, 0x1d,
|
||||||
0x69, 0x34, 0xac, 0xcb, 0xbf, 0xf8, 0xdb, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0xc4, 0x7e, 0x5e,
|
0xe7, 0x28, 0xe2, 0x65, 0xbc, 0x72, 0x48, 0xee, 0xa6, 0x2e, 0x52, 0xd4, 0x90, 0x46, 0xc3, 0xba,
|
||||||
0x7e, 0xd7, 0x0f, 0x00, 0x00,
|
0xfc, 0xcd, 0xbf, 0xf3, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xda, 0x7c, 0x0d, 0xab, 0xf8, 0x0f,
|
||||||
|
0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,15 +43,16 @@ message DashboardCell {
|
||||||
message TableOptions {
|
message TableOptions {
|
||||||
string timeFormat = 1; // format for time
|
string timeFormat = 1; // format for time
|
||||||
bool verticalTimeAxis = 2; // time axis should be a column not row
|
bool verticalTimeAxis = 2; // time axis should be a column not row
|
||||||
TableColumn sortBy = 3; // which column should a table be sorted by
|
RenamableField sortBy = 3; // which column should a table be sorted by
|
||||||
string wrapping = 4; // option for text wrapping
|
string wrapping = 4; // option for text wrapping
|
||||||
repeated TableColumn columnNames = 5; // names and renames for columns
|
repeated RenamableField fieldNames = 5; // names and renames for column/row fields
|
||||||
bool fixFirstColumn = 6; // first column should be fixed/frozen
|
bool fixFirstColumn = 6; // first column should be fixed/frozen
|
||||||
}
|
}
|
||||||
|
|
||||||
message TableColumn {
|
message RenamableField {
|
||||||
string internalName = 1; // name of column
|
string internalName = 1; // name of column
|
||||||
string displayName = 2; // what column is renamed to
|
string displayName = 2; // what column is renamed to
|
||||||
|
bool visible = 3; // Represents whether RenamableField is visible
|
||||||
}
|
}
|
||||||
|
|
||||||
message Color {
|
message Color {
|
||||||
|
|
|
@ -195,8 +195,8 @@ func Test_MarshalDashboard(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
TableOptions: chronograf.TableOptions{
|
TableOptions: chronograf.TableOptions{
|
||||||
TimeFormat: "",
|
TimeFormat: "",
|
||||||
ColumnNames: []chronograf.TableColumn{},
|
FieldNames: []chronograf.RenamableField{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -318,8 +318,8 @@ func Test_MarshalDashboard_WithLegacyBounds(t *testing.T) {
|
||||||
Orientation: "bottom",
|
Orientation: "bottom",
|
||||||
},
|
},
|
||||||
TableOptions: chronograf.TableOptions{
|
TableOptions: chronograf.TableOptions{
|
||||||
TimeFormat: "MM:DD:YYYY",
|
TimeFormat: "MM:DD:YYYY",
|
||||||
ColumnNames: []chronograf.TableColumn{},
|
FieldNames: []chronograf.RenamableField{},
|
||||||
},
|
},
|
||||||
Type: "line",
|
Type: "line",
|
||||||
},
|
},
|
||||||
|
@ -434,8 +434,8 @@ func Test_MarshalDashboard_WithEmptyLegacyBounds(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
TableOptions: chronograf.TableOptions{
|
TableOptions: chronograf.TableOptions{
|
||||||
TimeFormat: "MM:DD:YYYY",
|
TimeFormat: "MM:DD:YYYY",
|
||||||
ColumnNames: []chronograf.TableColumn{},
|
FieldNames: []chronograf.RenamableField{},
|
||||||
},
|
},
|
||||||
Type: "line",
|
Type: "line",
|
||||||
},
|
},
|
||||||
|
@ -474,7 +474,7 @@ func Test_MarshalDashboard_WithEmptyCellType(t *testing.T) {
|
||||||
Axes: map[string]chronograf.Axis{},
|
Axes: map[string]chronograf.Axis{},
|
||||||
CellColors: []chronograf.CellColor{},
|
CellColors: []chronograf.CellColor{},
|
||||||
TableOptions: chronograf.TableOptions{
|
TableOptions: chronograf.TableOptions{
|
||||||
ColumnNames: []chronograf.TableColumn{},
|
FieldNames: []chronograf.RenamableField{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -560,20 +560,21 @@ type DashboardCell struct {
|
||||||
TableOptions TableOptions `json:"tableOptions,omitempty"`
|
TableOptions TableOptions `json:"tableOptions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableColumn is a column in a DashboardCell of type Table
|
// RenamableField is a column/row field in a DashboardCell of type Table
|
||||||
type TableColumn struct {
|
type RenamableField struct {
|
||||||
InternalName string `json:"internalName"`
|
InternalName string `json:"internalName"`
|
||||||
DisplayName string `json:"displayName"`
|
DisplayName string `json:"displayName"`
|
||||||
|
Visible bool `json:"visible"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableOptions is a type of options for a DashboardCell with type Table
|
// TableOptions is a type of options for a DashboardCell with type Table
|
||||||
type TableOptions struct {
|
type TableOptions struct {
|
||||||
TimeFormat string `json:"timeFormat"`
|
TimeFormat string `json:"timeFormat"`
|
||||||
VerticalTimeAxis bool `json:"verticalTimeAxis"`
|
VerticalTimeAxis bool `json:"verticalTimeAxis"`
|
||||||
SortBy TableColumn `json:"sortBy"`
|
SortBy RenamableField `json:"sortBy"`
|
||||||
Wrapping string `json:"wrapping"`
|
Wrapping string `json:"wrapping"`
|
||||||
ColumnNames []TableColumn `json:"columnNames"`
|
FieldNames []RenamableField `json:"fieldNames"`
|
||||||
FixFirstColumn bool `json:"fixFirstColumn"`
|
FixFirstColumn bool `json:"fixFirstColumn"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DashboardsStore is the storage and retrieval of dashboards
|
// DashboardsStore is the storage and retrieval of dashboards
|
||||||
|
|
|
@ -548,9 +548,11 @@ func TestServer(t *testing.T) {
|
||||||
"verticalTimeAxis": false,
|
"verticalTimeAxis": false,
|
||||||
"sortBy":{
|
"sortBy":{
|
||||||
"internalName": "",
|
"internalName": "",
|
||||||
"displayName": ""},
|
"displayName": "",
|
||||||
|
"visible": false
|
||||||
|
},
|
||||||
"wrapping": "",
|
"wrapping": "",
|
||||||
"columnNames": null,
|
"fieldNames": null,
|
||||||
"fixFirstColumn": false
|
"fixFirstColumn": false
|
||||||
},
|
},
|
||||||
"links": {
|
"links": {
|
||||||
|
@ -797,10 +799,11 @@ func TestServer(t *testing.T) {
|
||||||
"verticalTimeAxis":false,
|
"verticalTimeAxis":false,
|
||||||
"sortBy":{
|
"sortBy":{
|
||||||
"internalName":"",
|
"internalName":"",
|
||||||
"displayName":""
|
"displayName":"",
|
||||||
|
"visible":false
|
||||||
},
|
},
|
||||||
"wrapping":"",
|
"wrapping":"",
|
||||||
"columnNames":null,
|
"fieldNames":null,
|
||||||
"fixFirstColumn":false
|
"fixFirstColumn":false
|
||||||
},
|
},
|
||||||
"legend":{
|
"legend":{
|
||||||
|
|
|
@ -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":""},"wrapping":"","columnNames":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},"wrapping":"","fieldNames":null,"fixFirstColumn":false},"links":{"self":"/chronograf/v1/dashboards/1/cells/3c5c4102-fa40-4585-a8f9-917c77e37192"}}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,6 +48,7 @@ class CellEditorOverlay extends Component {
|
||||||
activeQueryIndex: 0,
|
activeQueryIndex: 0,
|
||||||
isDisplayOptionsTabActive: false,
|
isDisplayOptionsTabActive: false,
|
||||||
staticLegend: IS_STATIC_LEGEND(legend),
|
staticLegend: IS_STATIC_LEGEND(legend),
|
||||||
|
dataLabels: [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,6 +260,10 @@ class CellEditorOverlay extends Component {
|
||||||
this.overlayRef.focus()
|
this.overlayRef.focus()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setDataLabels = dataLabels => {
|
||||||
|
this.setState({dataLabels})
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
onCancel,
|
onCancel,
|
||||||
|
@ -273,6 +278,7 @@ class CellEditorOverlay extends Component {
|
||||||
isDisplayOptionsTabActive,
|
isDisplayOptionsTabActive,
|
||||||
queriesWorkingDraft,
|
queriesWorkingDraft,
|
||||||
staticLegend,
|
staticLegend,
|
||||||
|
dataLabels,
|
||||||
} = this.state
|
} = this.state
|
||||||
|
|
||||||
const queryActions = {
|
const queryActions = {
|
||||||
|
@ -305,6 +311,7 @@ class CellEditorOverlay extends Component {
|
||||||
queryConfigs={queriesWorkingDraft}
|
queryConfigs={queriesWorkingDraft}
|
||||||
editQueryStatus={editQueryStatus}
|
editQueryStatus={editQueryStatus}
|
||||||
staticLegend={staticLegend}
|
staticLegend={staticLegend}
|
||||||
|
setDataLabels={this.setDataLabels}
|
||||||
/>
|
/>
|
||||||
<CEOBottom>
|
<CEOBottom>
|
||||||
<OverlayControls
|
<OverlayControls
|
||||||
|
@ -324,6 +331,7 @@ class CellEditorOverlay extends Component {
|
||||||
onToggleStaticLegend={this.handleToggleStaticLegend}
|
onToggleStaticLegend={this.handleToggleStaticLegend}
|
||||||
staticLegend={staticLegend}
|
staticLegend={staticLegend}
|
||||||
onResetFocus={this.handleResetFocus}
|
onResetFocus={this.handleResetFocus}
|
||||||
|
dataLabels={dataLabels}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<QueryMaker
|
<QueryMaker
|
||||||
|
|
|
@ -42,7 +42,7 @@ class DisplayOptions extends Component {
|
||||||
staticLegend,
|
staticLegend,
|
||||||
onToggleStaticLegend,
|
onToggleStaticLegend,
|
||||||
onResetFocus,
|
onResetFocus,
|
||||||
queryConfigs,
|
dataLabels,
|
||||||
} = this.props
|
} = this.props
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'gauge':
|
case 'gauge':
|
||||||
|
@ -51,10 +51,7 @@ class DisplayOptions extends Component {
|
||||||
return <SingleStatOptions onResetFocus={onResetFocus} />
|
return <SingleStatOptions onResetFocus={onResetFocus} />
|
||||||
case 'table':
|
case 'table':
|
||||||
return (
|
return (
|
||||||
<TableOptions
|
<TableOptions onResetFocus={onResetFocus} dataLabels={dataLabels} />
|
||||||
onResetFocus={onResetFocus}
|
|
||||||
queryConfigs={queryConfigs}
|
|
||||||
/>
|
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
|
@ -93,6 +90,7 @@ DisplayOptions.propTypes = {
|
||||||
onToggleStaticLegend: func.isRequired,
|
onToggleStaticLegend: func.isRequired,
|
||||||
staticLegend: bool,
|
staticLegend: bool,
|
||||||
onResetFocus: func.isRequired,
|
onResetFocus: func.isRequired,
|
||||||
|
dataLabels: arrayOf(string),
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = ({cellEditorOverlay: {cell, cell: {axes}}}) => ({
|
const mapStateToProps = ({cellEditorOverlay: {cell, cell: {axes}}}) => ({
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
import React, {PureComponent} from 'react'
|
|
||||||
|
|
||||||
import InputClickToEdit from 'src/shared/components/InputClickToEdit'
|
|
||||||
|
|
||||||
interface Column {
|
|
||||||
internalName: string
|
|
||||||
displayName: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
internalName: string
|
|
||||||
displayName: string
|
|
||||||
onColumnRename: (column: Column) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
class GraphOptionsCustomizableColumn extends PureComponent<Props, {}> {
|
|
||||||
constructor(props) {
|
|
||||||
super(props)
|
|
||||||
|
|
||||||
this.handleColumnRename = this.handleColumnRename.bind(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
public handleColumnRename(rename) {
|
|
||||||
const {onColumnRename, internalName} = this.props
|
|
||||||
onColumnRename({internalName, displayName: rename})
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const {internalName, displayName} = this.props
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="column-controls--section">
|
|
||||||
<div className="column-controls--label">{internalName}</div>
|
|
||||||
<InputClickToEdit
|
|
||||||
value={displayName}
|
|
||||||
wrapperClass="column-controls-input"
|
|
||||||
onBlur={this.handleColumnRename}
|
|
||||||
placeholder="Rename..."
|
|
||||||
appearAsNormalInput={true}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default GraphOptionsCustomizableColumn
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
import React, {PureComponent} from 'react'
|
||||||
|
|
||||||
|
import InputClickToEdit from 'src/shared/components/InputClickToEdit'
|
||||||
|
|
||||||
|
interface Field {
|
||||||
|
internalName: string
|
||||||
|
displayName: string
|
||||||
|
visible: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
internalName: string
|
||||||
|
displayName: string
|
||||||
|
visible: boolean
|
||||||
|
onFieldUpdate: (field: Field) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
class GraphOptionsCustomizableField extends PureComponent<Props, {}> {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.handleFieldRename = this.handleFieldRename.bind(this)
|
||||||
|
this.handleToggleVisible = this.handleToggleVisible.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
public handleFieldRename(rename: string) {
|
||||||
|
const {onFieldUpdate, internalName, visible} = this.props
|
||||||
|
onFieldUpdate({internalName, displayName: rename, visible})
|
||||||
|
}
|
||||||
|
|
||||||
|
public handleToggleVisible() {
|
||||||
|
const {onFieldUpdate, internalName, displayName, visible} = this.props
|
||||||
|
onFieldUpdate({internalName, displayName, visible: !visible})
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
const {internalName, displayName, visible} = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="field-controls--section">
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
visible ? 'field-controls--label' : 'field-controls--label-hidden'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={visible ? 'icon eye-open' : 'icon eye-closed'}
|
||||||
|
onClick={this.handleToggleVisible}
|
||||||
|
/>
|
||||||
|
{internalName}
|
||||||
|
</div>
|
||||||
|
<InputClickToEdit
|
||||||
|
value={displayName}
|
||||||
|
wrapperClass="field-controls-input"
|
||||||
|
onBlur={this.handleFieldRename}
|
||||||
|
placeholder="Rename..."
|
||||||
|
appearAsNormalInput={true}
|
||||||
|
disabled={!visible}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GraphOptionsCustomizableField
|
|
@ -1,37 +0,0 @@
|
||||||
import React, {SFC} from 'react'
|
|
||||||
|
|
||||||
import GraphOptionsCustomizableColumn from 'src/dashboards/components/GraphOptionsCustomizableColumn'
|
|
||||||
import uuid from 'uuid'
|
|
||||||
|
|
||||||
interface Column {
|
|
||||||
internalName: string
|
|
||||||
displayName: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
columns: Column[]
|
|
||||||
onColumnRename: (column: Column) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
const GraphOptionsCustomizeColumns: SFC<Props> = ({
|
|
||||||
columns,
|
|
||||||
onColumnRename,
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<div className="graph-options-group">
|
|
||||||
<label className="form-label">Customize Columns</label>
|
|
||||||
{columns.map(col => {
|
|
||||||
return (
|
|
||||||
<GraphOptionsCustomizableColumn
|
|
||||||
key={uuid.v4()}
|
|
||||||
internalName={col.internalName}
|
|
||||||
displayName={col.displayName}
|
|
||||||
onColumnRename={onColumnRename}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default GraphOptionsCustomizeColumns
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
import React, {SFC} from 'react'
|
||||||
|
|
||||||
|
import GraphOptionsCustomizableField from 'src/dashboards/components/GraphOptionsCustomizableField'
|
||||||
|
import uuid from 'uuid'
|
||||||
|
|
||||||
|
interface Field {
|
||||||
|
internalName: string
|
||||||
|
displayName: string
|
||||||
|
visible: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
fields: Field[]
|
||||||
|
onFieldUpdate: (field: Field) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const GraphOptionsCustomizeFields: SFC<Props> = ({fields, onFieldUpdate}) => {
|
||||||
|
return (
|
||||||
|
<div className="graph-options-group">
|
||||||
|
<label className="form-label">Customize Fields</label>
|
||||||
|
<div className="field-controls--group">
|
||||||
|
{fields.map(field => {
|
||||||
|
return (
|
||||||
|
<GraphOptionsCustomizableField
|
||||||
|
key={uuid.v4()}
|
||||||
|
internalName={field.internalName}
|
||||||
|
displayName={field.displayName}
|
||||||
|
visible={field.visible}
|
||||||
|
onFieldUpdate={onFieldUpdate}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GraphOptionsCustomizeFields
|
|
@ -23,10 +23,9 @@ const GraphOptionsSortBy = ({
|
||||||
selected,
|
selected,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const selectedValue = selected.displayName || selected.internalName
|
const selectedValue = selected.displayName || selected.internalName
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="form-group col-xs-6">
|
<div className="form-group col-xs-6">
|
||||||
<label>Sort By</label>
|
<label>Default Sort By</label>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
items={sortByOptions}
|
items={sortByOptions}
|
||||||
selected={selectedValue}
|
selected={selectedValue}
|
||||||
|
|
|
@ -35,18 +35,22 @@ class GraphOptionsTimeFormat extends PureComponent<Props, State> {
|
||||||
return this.props.onTimeFormatChange
|
return this.props.onTimeFormatChange
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public handleChangeFormat = format => {
|
||||||
|
this.onTimeFormatChange(format)
|
||||||
|
this.setState({format})
|
||||||
|
}
|
||||||
|
|
||||||
public handleChooseFormat = (formatOption: TimeFormatOptions) => {
|
public handleChooseFormat = (formatOption: TimeFormatOptions) => {
|
||||||
if (formatOption.text === TIME_FORMAT_CUSTOM) {
|
if (formatOption.text === TIME_FORMAT_CUSTOM) {
|
||||||
this.setState({customFormat: true})
|
this.setState({customFormat: true})
|
||||||
} else {
|
} else {
|
||||||
this.setState({format: formatOption.text, customFormat: false})
|
|
||||||
this.onTimeFormatChange(formatOption.text)
|
this.onTimeFormatChange(formatOption.text)
|
||||||
|
this.setState({format: formatOption.text, customFormat: false})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const {format, customFormat} = this.state
|
const {format, customFormat} = this.state
|
||||||
const {onTimeFormatChange} = this.props
|
|
||||||
const tipContent =
|
const tipContent =
|
||||||
'For information on formatting, see http://momentjs.com/docs/#/parsing/string-format/'
|
'For information on formatting, see http://momentjs.com/docs/#/parsing/string-format/'
|
||||||
|
|
||||||
|
@ -57,7 +61,7 @@ class GraphOptionsTimeFormat extends PureComponent<Props, State> {
|
||||||
<div className="form-group col-xs-12">
|
<div className="form-group col-xs-12">
|
||||||
<label>
|
<label>
|
||||||
Time Format
|
Time Format
|
||||||
{customFormat && (
|
{showCustom && (
|
||||||
<QuestionMarkTooltip
|
<QuestionMarkTooltip
|
||||||
tipID="Time Axis Format"
|
tipID="Time Axis Format"
|
||||||
tipContent={tipContent}
|
tipContent={tipContent}
|
||||||
|
@ -75,10 +79,10 @@ class GraphOptionsTimeFormat extends PureComponent<Props, State> {
|
||||||
{showCustom && (
|
{showCustom && (
|
||||||
<div className="column-controls--section">
|
<div className="column-controls--section">
|
||||||
<InputClickToEdit
|
<InputClickToEdit
|
||||||
wrapperClass="column-controls-input "
|
wrapperClass="field-controls-input "
|
||||||
value={format}
|
value={format}
|
||||||
onBlur={onTimeFormatChange}
|
onBlur={this.handleChangeFormat}
|
||||||
onChange={onTimeFormatChange}
|
onChange={this.handleChangeFormat}
|
||||||
placeholder="Enter custom format..."
|
placeholder="Enter custom format..."
|
||||||
appearAsNormalInput={true}
|
appearAsNormalInput={true}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -2,54 +2,45 @@ import React, {PureComponent} from 'react'
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
import {bindActionCreators} from 'redux'
|
import {bindActionCreators} from 'redux'
|
||||||
|
|
||||||
import _ from 'lodash'
|
import GraphOptionsCustomizeFields from 'src/dashboards/components/GraphOptionsCustomizeFields'
|
||||||
|
|
||||||
import GraphOptionsCustomizeColumns from 'src/dashboards/components/GraphOptionsCustomizeColumns'
|
|
||||||
import GraphOptionsFixFirstColumn from 'src/dashboards/components/GraphOptionsFixFirstColumn'
|
import GraphOptionsFixFirstColumn from 'src/dashboards/components/GraphOptionsFixFirstColumn'
|
||||||
import GraphOptionsSortBy from 'src/dashboards/components/GraphOptionsSortBy'
|
import GraphOptionsSortBy from 'src/dashboards/components/GraphOptionsSortBy'
|
||||||
import GraphOptionsTextWrapping from 'src/dashboards/components/GraphOptionsTextWrapping'
|
|
||||||
import GraphOptionsTimeAxis from 'src/dashboards/components/GraphOptionsTimeAxis'
|
import GraphOptionsTimeAxis from 'src/dashboards/components/GraphOptionsTimeAxis'
|
||||||
import GraphOptionsTimeFormat from 'src/dashboards/components/GraphOptionsTimeFormat'
|
import GraphOptionsTimeFormat from 'src/dashboards/components/GraphOptionsTimeFormat'
|
||||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||||
|
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
import ThresholdsList from 'src/shared/components/ThresholdsList'
|
import ThresholdsList from 'src/shared/components/ThresholdsList'
|
||||||
import ThresholdsListTypeToggle from 'src/shared/components/ThresholdsListTypeToggle'
|
import ThresholdsListTypeToggle from 'src/shared/components/ThresholdsListTypeToggle'
|
||||||
|
|
||||||
import {updateTableOptions} from 'src/dashboards/actions/cellEditorOverlay'
|
import {updateTableOptions} from 'src/dashboards/actions/cellEditorOverlay'
|
||||||
import {TIME_COLUMN_DEFAULT} from 'src/shared/constants/tableGraph'
|
import {TIME_FIELD_DEFAULT} from 'src/shared/constants/tableGraph'
|
||||||
|
|
||||||
interface Option {
|
interface Option {
|
||||||
text: string
|
text: string
|
||||||
key: string
|
key: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TableColumn {
|
interface RenamableField {
|
||||||
internalName: string
|
internalName: string
|
||||||
displayName: string
|
displayName: string
|
||||||
|
visible: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Options {
|
interface Options {
|
||||||
timeFormat: string
|
timeFormat: string
|
||||||
verticalTimeAxis: boolean
|
verticalTimeAxis: boolean
|
||||||
sortBy: TableColumn
|
sortBy: RenamableField
|
||||||
wrapping: string
|
fieldNames: RenamableField[]
|
||||||
columnNames: TableColumn[]
|
|
||||||
fixFirstColumn: boolean
|
fixFirstColumn: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface QueryConfig {
|
|
||||||
measurement: string
|
|
||||||
fields: Array<{
|
|
||||||
alias: string
|
|
||||||
value: string
|
|
||||||
}>
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
queryConfigs: QueryConfig[]
|
|
||||||
handleUpdateTableOptions: (options: Options) => void
|
handleUpdateTableOptions: (options: Options) => void
|
||||||
tableOptions: Options
|
tableOptions: Options
|
||||||
onResetFocus: () => void
|
onResetFocus: () => void
|
||||||
|
dataLabels: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TableOptions extends PureComponent<Props, {}> {
|
export class TableOptions extends PureComponent<Props, {}> {
|
||||||
|
@ -57,47 +48,33 @@ export class TableOptions extends PureComponent<Props, {}> {
|
||||||
super(props)
|
super(props)
|
||||||
}
|
}
|
||||||
|
|
||||||
get columnNames() {
|
get fieldNames() {
|
||||||
const {tableOptions: {columnNames}} = this.props
|
const {tableOptions: {fieldNames}} = this.props
|
||||||
return columnNames || []
|
return fieldNames || []
|
||||||
}
|
}
|
||||||
|
|
||||||
get timeColumn() {
|
get timeColumn() {
|
||||||
return (
|
return (
|
||||||
this.columnNames.find(c => c.internalName === 'time') ||
|
this.fieldNames.find(f => f.internalName === 'time') || TIME_FIELD_DEFAULT
|
||||||
TIME_COLUMN_DEFAULT
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
get computedColumnNames() {
|
get computedFieldNames() {
|
||||||
const {queryConfigs} = this.props
|
const {dataLabels} = this.props
|
||||||
|
|
||||||
const queryFields = _.flatten(
|
return dataLabels.map(label => {
|
||||||
queryConfigs.map(({measurement, fields}) => {
|
const existing = this.fieldNames.find(f => f.internalName === label)
|
||||||
return fields.map(({alias}) => {
|
return existing || {internalName: label, displayName: '', visible: true}
|
||||||
const internalName = `${measurement}.${alias}`
|
|
||||||
const existing = this.columnNames.find(
|
|
||||||
c => c.internalName === internalName
|
|
||||||
)
|
|
||||||
return existing || {internalName, displayName: ''}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
return [this.timeColumn, ...queryFields]
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentWillMount() {
|
|
||||||
const {handleUpdateTableOptions, tableOptions} = this.props
|
|
||||||
handleUpdateTableOptions({
|
|
||||||
...tableOptions,
|
|
||||||
columnNames: this.computedColumnNames,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public handleChooseSortBy = (option: Option) => {
|
public handleChooseSortBy = (option: Option) => {
|
||||||
const {tableOptions, handleUpdateTableOptions} = this.props
|
const {tableOptions, handleUpdateTableOptions} = this.props
|
||||||
const sortBy = {displayName: option.text, internalName: option.key}
|
const sortBy = {
|
||||||
|
displayName: option.text === option.key ? '' : option.text,
|
||||||
|
internalName: option.key,
|
||||||
|
visible: true,
|
||||||
|
}
|
||||||
|
|
||||||
handleUpdateTableOptions({...tableOptions, sortBy})
|
handleUpdateTableOptions({...tableOptions, sortBy})
|
||||||
}
|
}
|
||||||
|
@ -118,32 +95,55 @@ export class TableOptions extends PureComponent<Props, {}> {
|
||||||
handleUpdateTableOptions({...tableOptions, fixFirstColumn})
|
handleUpdateTableOptions({...tableOptions, fixFirstColumn})
|
||||||
}
|
}
|
||||||
|
|
||||||
public handleColumnRename = column => {
|
public handleFieldUpdate = field => {
|
||||||
const {handleUpdateTableOptions, tableOptions} = this.props
|
const {handleUpdateTableOptions, tableOptions} = this.props
|
||||||
const {columnNames} = tableOptions
|
const {fieldNames, sortBy} = tableOptions
|
||||||
const updatedColumns = columnNames.map(
|
const updatedFields = fieldNames.map(
|
||||||
op => (op.internalName === column.internalName ? column : op)
|
f => (f.internalName === field.internalName ? field : f)
|
||||||
)
|
)
|
||||||
handleUpdateTableOptions({...tableOptions, columnNames: updatedColumns})
|
const updatedSortBy =
|
||||||
|
sortBy.internalName === field.internalName
|
||||||
|
? {...sortBy, displayName: field.displayName}
|
||||||
|
: sortBy
|
||||||
|
|
||||||
|
handleUpdateTableOptions({
|
||||||
|
...tableOptions,
|
||||||
|
fieldNames: updatedFields,
|
||||||
|
sortBy: updatedSortBy,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentWillMount() {
|
||||||
|
const {handleUpdateTableOptions, tableOptions} = this.props
|
||||||
|
handleUpdateTableOptions({
|
||||||
|
...tableOptions,
|
||||||
|
fieldNames: this.computedFieldNames,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public shouldComponentUpdate(nextProps) {
|
||||||
|
const {tableOptions, dataLabels} = this.props
|
||||||
|
const tableOptionsDifferent = !_.isEqual(
|
||||||
|
tableOptions,
|
||||||
|
nextProps.tableOptions
|
||||||
|
)
|
||||||
|
const dataLabelsDifferent = !_.isEqual(dataLabels, nextProps.dataLabels)
|
||||||
|
|
||||||
|
return tableOptionsDifferent || dataLabelsDifferent
|
||||||
}
|
}
|
||||||
|
|
||||||
public handleToggleTextWrapping = () => {}
|
public handleToggleTextWrapping = () => {}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const {
|
const {
|
||||||
tableOptions: {
|
tableOptions: {timeFormat, fieldNames, verticalTimeAxis, fixFirstColumn},
|
||||||
timeFormat,
|
|
||||||
columnNames: columns,
|
|
||||||
verticalTimeAxis,
|
|
||||||
fixFirstColumn,
|
|
||||||
},
|
|
||||||
onResetFocus,
|
onResetFocus,
|
||||||
tableOptions,
|
tableOptions,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
const tableSortByOptions = this.computedColumnNames.map(col => ({
|
const tableSortByOptions = this.computedFieldNames.map(field => ({
|
||||||
key: col.internalName,
|
key: field.internalName,
|
||||||
text: col.displayName || col.internalName,
|
text: field.displayName || field.internalName,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -163,22 +163,18 @@ export class TableOptions extends PureComponent<Props, {}> {
|
||||||
onToggleVerticalTimeAxis={this.handleToggleVerticalTimeAxis}
|
onToggleVerticalTimeAxis={this.handleToggleVerticalTimeAxis}
|
||||||
/>
|
/>
|
||||||
<GraphOptionsSortBy
|
<GraphOptionsSortBy
|
||||||
selected={tableOptions.sortBy || TIME_COLUMN_DEFAULT}
|
selected={tableOptions.sortBy || TIME_FIELD_DEFAULT}
|
||||||
sortByOptions={tableSortByOptions}
|
sortByOptions={tableSortByOptions}
|
||||||
onChooseSortBy={this.handleChooseSortBy}
|
onChooseSortBy={this.handleChooseSortBy}
|
||||||
/>
|
/>
|
||||||
<GraphOptionsTextWrapping
|
|
||||||
thresholdsListType="background"
|
|
||||||
onToggleTextWrapping={this.handleToggleTextWrapping}
|
|
||||||
/>
|
|
||||||
<GraphOptionsFixFirstColumn
|
<GraphOptionsFixFirstColumn
|
||||||
fixed={fixFirstColumn}
|
fixed={fixFirstColumn}
|
||||||
onToggleFixFirstColumn={this.handleToggleFixFirstColumn}
|
onToggleFixFirstColumn={this.handleToggleFixFirstColumn}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<GraphOptionsCustomizeColumns
|
<GraphOptionsCustomizeFields
|
||||||
columns={columns}
|
fields={fieldNames}
|
||||||
onColumnRename={this.handleColumnRename}
|
onFieldUpdate={this.handleFieldUpdate}
|
||||||
/>
|
/>
|
||||||
<ThresholdsList showListHeading={true} onResetFocus={onResetFocus} />
|
<ThresholdsList showListHeading={true} onResetFocus={onResetFocus} />
|
||||||
<div className="form-group-wrapper graph-options-group">
|
<div className="form-group-wrapper graph-options-group">
|
||||||
|
|
|
@ -22,6 +22,7 @@ const DashVisualization = (
|
||||||
staticLegend,
|
staticLegend,
|
||||||
thresholdsListColors,
|
thresholdsListColors,
|
||||||
tableOptions,
|
tableOptions,
|
||||||
|
setDataLabels,
|
||||||
},
|
},
|
||||||
{source: {links: {proxy}}}
|
{source: {links: {proxy}}}
|
||||||
) => {
|
) => {
|
||||||
|
@ -42,6 +43,7 @@ const DashVisualization = (
|
||||||
editQueryStatus={editQueryStatus}
|
editQueryStatus={editQueryStatus}
|
||||||
resizerTopHeight={resizerTopHeight}
|
resizerTopHeight={resizerTopHeight}
|
||||||
staticLegend={staticLegend}
|
staticLegend={staticLegend}
|
||||||
|
setDataLabels={setDataLabels}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -86,6 +88,7 @@ DashVisualization.propTypes = {
|
||||||
}).isRequired
|
}).isRequired
|
||||||
),
|
),
|
||||||
staticLegend: bool,
|
staticLegend: bool,
|
||||||
|
setDataLabels: func,
|
||||||
}
|
}
|
||||||
|
|
||||||
DashVisualization.contextTypes = {
|
DashVisualization.contextTypes = {
|
||||||
|
|
|
@ -23,6 +23,7 @@ const RefreshingGraph = ({
|
||||||
cellID,
|
cellID,
|
||||||
queries,
|
queries,
|
||||||
tableOptions,
|
tableOptions,
|
||||||
|
setDataLabels,
|
||||||
templates,
|
templates,
|
||||||
timeRange,
|
timeRange,
|
||||||
cellHeight,
|
cellHeight,
|
||||||
|
@ -98,6 +99,7 @@ const RefreshingGraph = ({
|
||||||
hoverTime={hoverTime}
|
hoverTime={hoverTime}
|
||||||
onSetHoverTime={onSetHoverTime}
|
onSetHoverTime={onSetHoverTime}
|
||||||
inView={inView}
|
inView={inView}
|
||||||
|
setDataLabels={setDataLabels}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -164,6 +166,7 @@ RefreshingGraph.propTypes = {
|
||||||
cellID: string,
|
cellID: string,
|
||||||
inView: bool,
|
inView: bool,
|
||||||
tableOptions: shape({}),
|
tableOptions: shape({}),
|
||||||
|
setDataLabels: func,
|
||||||
}
|
}
|
||||||
|
|
||||||
RefreshingGraph.defaultProps = {
|
RefreshingGraph.defaultProps = {
|
||||||
|
|
|
@ -2,91 +2,130 @@ import React, {Component} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import isEmpty from 'lodash/isEmpty'
|
|
||||||
|
|
||||||
import {MultiGrid, ColumnSizer} from 'react-virtualized'
|
import {MultiGrid, ColumnSizer} from 'react-virtualized'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
|
||||||
import {timeSeriesToTableGraph} from 'src/utils/timeSeriesToDygraph'
|
import {timeSeriesToTableGraph} from 'src/utils/timeSeriesToDygraph'
|
||||||
import {
|
import {
|
||||||
NULL_COLUMN_INDEX,
|
NULL_ARRAY_INDEX,
|
||||||
NULL_ROW_INDEX,
|
|
||||||
NULL_HOVER_TIME,
|
NULL_HOVER_TIME,
|
||||||
TIME_FORMAT_DEFAULT,
|
TIME_FORMAT_DEFAULT,
|
||||||
TIME_COLUMN_DEFAULT,
|
TIME_FIELD_DEFAULT,
|
||||||
ASCENDING,
|
ASCENDING,
|
||||||
DESCENDING,
|
DESCENDING,
|
||||||
FIX_FIRST_COLUMN_DEFAULT,
|
FIX_FIRST_COLUMN_DEFAULT,
|
||||||
|
VERTICAL_TIME_AXIS_DEFAULT,
|
||||||
calculateTimeColumnWidth,
|
calculateTimeColumnWidth,
|
||||||
} from 'src/shared/constants/tableGraph'
|
} from 'src/shared/constants/tableGraph'
|
||||||
const DEFAULT_SORT = ASCENDING
|
const DEFAULT_SORT = ASCENDING
|
||||||
|
|
||||||
import {generateThresholdsListHexs} from 'shared/constants/colorOperations'
|
import {generateThresholdsListHexs} from 'shared/constants/colorOperations'
|
||||||
|
|
||||||
|
const filterInvisibleColumns = (data, fieldNames) => {
|
||||||
|
const visibility = {}
|
||||||
|
const filteredData = data.map((row, i) => {
|
||||||
|
return row.filter((col, j) => {
|
||||||
|
if (i === 0) {
|
||||||
|
const foundField = fieldNames.find(field => field.internalName === col)
|
||||||
|
visibility[j] = foundField ? foundField.visible : true
|
||||||
|
}
|
||||||
|
return visibility[j]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return filteredData[0].length ? filteredData : [[]]
|
||||||
|
}
|
||||||
|
|
||||||
|
const processData = (
|
||||||
|
data,
|
||||||
|
sortFieldName,
|
||||||
|
direction,
|
||||||
|
verticalTimeAxis,
|
||||||
|
fieldNames
|
||||||
|
) => {
|
||||||
|
const sortIndex = _.indexOf(data[0], sortFieldName)
|
||||||
|
const sortedData = [
|
||||||
|
data[0],
|
||||||
|
..._.orderBy(_.drop(data, 1), sortIndex, [direction]),
|
||||||
|
]
|
||||||
|
const filteredData = filterInvisibleColumns(sortedData, fieldNames)
|
||||||
|
const processedData = verticalTimeAxis ? filteredData : _.unzip(filteredData)
|
||||||
|
|
||||||
|
return {processedData}
|
||||||
|
}
|
||||||
|
|
||||||
class TableGraph extends Component {
|
class TableGraph extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
data: [[]],
|
data: [[]],
|
||||||
unzippedData: [[]],
|
|
||||||
hoveredColumnIndex: NULL_COLUMN_INDEX,
|
|
||||||
hoveredRowIndex: NULL_ROW_INDEX,
|
|
||||||
sortByColumnIndex: NULL_COLUMN_INDEX,
|
|
||||||
clickToSortFieldIndex: NULL_COLUMN_INDEX,
|
|
||||||
clicktoSortDirection: DEFAULT_SORT,
|
|
||||||
timeColumnWidth: calculateTimeColumnWidth(props.tableOptions.timeFormat),
|
timeColumnWidth: calculateTimeColumnWidth(props.tableOptions.timeFormat),
|
||||||
|
processedData: [[]],
|
||||||
|
hoveredColumnIndex: NULL_ARRAY_INDEX,
|
||||||
|
hoveredRowIndex: NULL_ARRAY_INDEX,
|
||||||
|
sortField: '',
|
||||||
|
sortDirection: DEFAULT_SORT,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
const {data} = timeSeriesToTableGraph(nextProps.data)
|
const {labels, data} = timeSeriesToTableGraph(nextProps.data)
|
||||||
|
if (_.isEmpty(data[0])) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const {sortField, sortDirection} = this.state
|
||||||
const {
|
const {
|
||||||
clickToSortFieldIndex,
|
tableOptions: {
|
||||||
clicktoSortDirection,
|
sortBy: {internalName},
|
||||||
sortByColumnIndex,
|
fieldNames,
|
||||||
} = this.state
|
verticalTimeAxis,
|
||||||
const {tableOptions: {sortBy: {internalName}, timeFormat}} = nextProps
|
timeFormat,
|
||||||
|
},
|
||||||
|
setDataLabels,
|
||||||
|
} = nextProps
|
||||||
|
|
||||||
if (timeFormat !== this.props.tableOptions.timeFormat) {
|
if (timeFormat !== this.props.tableOptions.timeFormat) {
|
||||||
this.setState({
|
this.setState({
|
||||||
timeColumnWidth: calculateTimeColumnWidth(timeFormat),
|
timeColumnWidth: calculateTimeColumnWidth(timeFormat),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (
|
|
||||||
sortByColumnIndex === NULL_COLUMN_INDEX ||
|
if (setDataLabels) {
|
||||||
_.get(this.props, ['tableOptions', 'sortBy', 'internalName'], '') !==
|
setDataLabels(labels)
|
||||||
internalName
|
|
||||||
) {
|
|
||||||
const newSortByColumnIndex = _.indexOf(data[0], internalName)
|
|
||||||
const sortedData = [
|
|
||||||
data[0],
|
|
||||||
..._.orderBy(_.drop(data, 1), newSortByColumnIndex, [DEFAULT_SORT]),
|
|
||||||
]
|
|
||||||
this.setState({
|
|
||||||
data: sortedData,
|
|
||||||
unzippedData: _.unzip(sortedData),
|
|
||||||
sortByColumnIndex: newSortByColumnIndex,
|
|
||||||
clickToSortFieldIndex: NULL_COLUMN_INDEX,
|
|
||||||
clicktoSortDirection: DEFAULT_SORT,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const clicked = clickToSortFieldIndex !== NULL_COLUMN_INDEX
|
let direction, sortFieldName
|
||||||
const sortIndex = clicked ? clickToSortFieldIndex : sortByColumnIndex
|
if (
|
||||||
const direction = clicked ? clicktoSortDirection : DEFAULT_SORT
|
_.isEmpty(sortField) ||
|
||||||
const sortedData = [
|
_.get(this.props, ['tableOptions', 'sortBy', 'internalName'], '') !==
|
||||||
data[0],
|
_.get(nextProps, ['tableOptions', 'sortBy', 'internalName'], '')
|
||||||
..._.orderBy(_.drop(data, 1), sortIndex, [direction]),
|
) {
|
||||||
]
|
direction = DEFAULT_SORT
|
||||||
|
sortFieldName = internalName
|
||||||
|
} else {
|
||||||
|
direction = sortDirection
|
||||||
|
sortFieldName = sortField
|
||||||
|
}
|
||||||
|
|
||||||
|
const {processedData} = processData(
|
||||||
|
data,
|
||||||
|
sortFieldName,
|
||||||
|
direction,
|
||||||
|
verticalTimeAxis,
|
||||||
|
fieldNames
|
||||||
|
)
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
data: sortedData,
|
data,
|
||||||
unzippedData: _.unzip(sortedData),
|
processedData,
|
||||||
|
sortField: sortFieldName,
|
||||||
|
sortDirection: direction,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
calcHoverTimeIndex = (data, hoverTime, verticalTimeAxis) => {
|
calcHoverTimeIndex = (data, hoverTime, verticalTimeAxis) => {
|
||||||
if (isEmpty(data) || hoverTime === NULL_HOVER_TIME) {
|
if (_.isEmpty(data) || hoverTime === NULL_HOVER_TIME) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
if (verticalTimeAxis) {
|
if (verticalTimeAxis) {
|
||||||
|
@ -99,11 +138,14 @@ class TableGraph extends Component {
|
||||||
|
|
||||||
handleHover = (columnIndex, rowIndex) => () => {
|
handleHover = (columnIndex, rowIndex) => () => {
|
||||||
const {onSetHoverTime, tableOptions: {verticalTimeAxis}} = this.props
|
const {onSetHoverTime, tableOptions: {verticalTimeAxis}} = this.props
|
||||||
const data = verticalTimeAxis ? this.state.data : this.state.unzippedData
|
const {data} = this.state
|
||||||
|
if (rowIndex === 0 && verticalTimeAxis) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (onSetHoverTime) {
|
if (onSetHoverTime) {
|
||||||
const hoverTime = verticalTimeAxis
|
const hoverTime = verticalTimeAxis
|
||||||
? data[rowIndex][0]
|
? data[rowIndex][0]
|
||||||
: data[0][columnIndex]
|
: data[columnIndex][0]
|
||||||
onSetHoverTime(hoverTime.toString())
|
onSetHoverTime(hoverTime.toString())
|
||||||
}
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -116,42 +158,37 @@ class TableGraph extends Component {
|
||||||
if (this.props.onSetHoverTime) {
|
if (this.props.onSetHoverTime) {
|
||||||
this.props.onSetHoverTime(NULL_HOVER_TIME)
|
this.props.onSetHoverTime(NULL_HOVER_TIME)
|
||||||
this.setState({
|
this.setState({
|
||||||
hoveredColumnIndex: NULL_COLUMN_INDEX,
|
hoveredColumnIndex: NULL_ARRAY_INDEX,
|
||||||
hoveredRowIndex: NULL_ROW_INDEX,
|
hoveredRowIndex: NULL_ARRAY_INDEX,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClickFieldName = (columnIndex, rowIndex) => () => {
|
handleClickFieldName = fieldName => () => {
|
||||||
const {tableOptions} = this.props
|
const {tableOptions} = this.props
|
||||||
const {clickToSortFieldIndex, clicktoSortDirection, data} = this.state
|
const {data, sortField, sortDirection} = this.state
|
||||||
const verticalTimeAxis = _.get(tableOptions, 'verticalTimeAxis', true)
|
const verticalTimeAxis = _.get(tableOptions, 'verticalTimeAxis', true)
|
||||||
const newIndex = verticalTimeAxis ? columnIndex : rowIndex
|
const fieldNames = _.get(tableOptions, 'fieldNames', [TIME_FIELD_DEFAULT])
|
||||||
|
|
||||||
if (clickToSortFieldIndex === newIndex) {
|
let direction
|
||||||
const direction =
|
if (fieldName === sortField) {
|
||||||
clicktoSortDirection === ASCENDING ? DESCENDING : ASCENDING
|
direction = sortDirection === ASCENDING ? DESCENDING : ASCENDING
|
||||||
const sortedData = [
|
} else {
|
||||||
data[0],
|
direction = DEFAULT_SORT
|
||||||
..._.orderBy(_.drop(data, 1), clickToSortFieldIndex, [direction]),
|
|
||||||
]
|
|
||||||
this.setState({
|
|
||||||
data: sortedData,
|
|
||||||
unzippedData: _.unzip(sortedData),
|
|
||||||
clicktoSortDirection: direction,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const sortedData = [
|
const {processedData} = processData(
|
||||||
data[0],
|
data,
|
||||||
..._.orderBy(_.drop(data, 1), clickToSortFieldIndex, [DEFAULT_SORT]),
|
fieldName,
|
||||||
]
|
direction,
|
||||||
|
verticalTimeAxis,
|
||||||
|
fieldNames
|
||||||
|
)
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
data: sortedData,
|
processedData,
|
||||||
unzippedData: _.unzip(sortedData),
|
sortField: fieldName,
|
||||||
clickToSortFieldIndex: newIndex,
|
sortDirection: direction,
|
||||||
clicktoSortDirection: DEFAULT_SORT,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,9 +196,8 @@ class TableGraph extends Component {
|
||||||
const {index} = column
|
const {index} = column
|
||||||
const {tableOptions, tableOptions: {verticalTimeAxis}} = this.props
|
const {tableOptions, tableOptions: {verticalTimeAxis}} = this.props
|
||||||
const {timeColumnWidth} = this.state
|
const {timeColumnWidth} = this.state
|
||||||
const columnNames = _.get(tableOptions, 'columnNames', [
|
|
||||||
TIME_COLUMN_DEFAULT,
|
const columnNames = _.get(tableOptions, 'columnNames', [TIME_FIELD_DEFAULT])
|
||||||
])
|
|
||||||
|
|
||||||
return verticalTimeAxis && columnNames[index].internalName === 'time'
|
return verticalTimeAxis && columnNames[index].internalName === 'time'
|
||||||
? timeColumnWidth
|
? timeColumnWidth
|
||||||
|
@ -169,28 +205,31 @@ class TableGraph extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
cellRenderer = ({columnIndex, rowIndex, key, parent, style}) => {
|
cellRenderer = ({columnIndex, rowIndex, key, parent, style}) => {
|
||||||
const {hoveredColumnIndex, hoveredRowIndex} = this.state
|
const {hoveredColumnIndex, hoveredRowIndex, processedData} = this.state
|
||||||
const {tableOptions, colors} = this.props
|
const {tableOptions, colors} = this.props
|
||||||
const verticalTimeAxis = _.get(tableOptions, 'verticalTimeAxis', true)
|
|
||||||
const data = verticalTimeAxis ? this.state.data : this.state.unzippedData
|
const {
|
||||||
const timeFormat = _.get(tableOptions, 'timeFormat', TIME_FORMAT_DEFAULT)
|
timeFormat = TIME_FORMAT_DEFAULT,
|
||||||
const columnNames = _.get(tableOptions, 'columnNames', [
|
verticalTimeAxis = VERTICAL_TIME_AXIS_DEFAULT,
|
||||||
TIME_COLUMN_DEFAULT,
|
fixFirstColumn = FIX_FIRST_COLUMN_DEFAULT,
|
||||||
])
|
fieldNames = [TIME_FIELD_DEFAULT],
|
||||||
const fixFirstColumn = _.get(
|
} = tableOptions
|
||||||
tableOptions,
|
|
||||||
'fixFirstColumn',
|
const cellData = processedData[rowIndex][columnIndex]
|
||||||
FIX_FIRST_COLUMN_DEFAULT
|
|
||||||
|
const timeField = fieldNames.find(
|
||||||
|
field => field.internalName === TIME_FIELD_DEFAULT.internalName
|
||||||
)
|
)
|
||||||
|
const visibleTime = _.get(timeField, 'visible', true)
|
||||||
|
|
||||||
const isFixedRow = rowIndex === 0 && columnIndex > 0
|
const isFixedRow = rowIndex === 0 && columnIndex > 0
|
||||||
const isFixedColumn = fixFirstColumn && rowIndex > 0 && columnIndex === 0
|
const isFixedColumn = fixFirstColumn && rowIndex > 0 && columnIndex === 0
|
||||||
const isTimeData = verticalTimeAxis
|
const isTimeData =
|
||||||
? rowIndex > 0 && columnIndex === 0
|
visibleTime &&
|
||||||
: isFixedRow
|
(verticalTimeAxis ? rowIndex > 0 && columnIndex === 0 : isFixedRow)
|
||||||
const isFieldName = verticalTimeAxis ? rowIndex === 0 : columnIndex === 0
|
const isFieldName = verticalTimeAxis ? rowIndex === 0 : columnIndex === 0
|
||||||
const isFixedCorner = rowIndex === 0 && columnIndex === 0
|
const isFixedCorner = rowIndex === 0 && columnIndex === 0
|
||||||
const dataIsNumerical = _.isNumber(data[rowIndex][columnIndex])
|
const dataIsNumerical = _.isNumber(cellData)
|
||||||
const isHighlightedRow =
|
const isHighlightedRow =
|
||||||
rowIndex === parent.props.scrollToRow ||
|
rowIndex === parent.props.scrollToRow ||
|
||||||
(rowIndex === hoveredRowIndex && hoveredRowIndex !== 0)
|
(rowIndex === hoveredRowIndex && hoveredRowIndex !== 0)
|
||||||
|
@ -203,7 +242,7 @@ class TableGraph extends Component {
|
||||||
if (!isFixedRow && !isFixedColumn && !isFixedCorner) {
|
if (!isFixedRow && !isFixedColumn && !isFixedCorner) {
|
||||||
const {bgColor, textColor} = generateThresholdsListHexs({
|
const {bgColor, textColor} = generateThresholdsListHexs({
|
||||||
colors,
|
colors,
|
||||||
lastValue: data[rowIndex][columnIndex],
|
lastValue: cellData,
|
||||||
cellType: 'table',
|
cellType: 'table',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -224,25 +263,21 @@ class TableGraph extends Component {
|
||||||
'table-graph-cell__isFieldName': isFieldName,
|
'table-graph-cell__isFieldName': isFieldName,
|
||||||
})
|
})
|
||||||
|
|
||||||
const cellData = data[rowIndex][columnIndex]
|
const foundField =
|
||||||
const foundColumn = columnNames.find(
|
isFieldName && fieldNames.find(field => field.internalName === cellData)
|
||||||
column => column.internalName === cellData
|
const fieldName =
|
||||||
)
|
foundField && (foundField.displayName || foundField.internalName)
|
||||||
const columnName =
|
|
||||||
foundColumn && (foundColumn.displayName || foundColumn.internalName)
|
|
||||||
|
|
||||||
const cellContents = isTimeData
|
const cellContents = isTimeData
|
||||||
? `${moment(cellData).format(timeFormat)}`
|
? `${moment(cellData).format(timeFormat)}`
|
||||||
: columnName || `${cellData}`
|
: fieldName || `${cellData}`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={key}
|
key={key}
|
||||||
style={cellStyle}
|
style={cellStyle}
|
||||||
className={cellClass}
|
className={cellClass}
|
||||||
onClick={
|
onClick={isFieldName ? this.handleClickFieldName(cellData) : null}
|
||||||
isFieldName ? this.handleClickFieldName(columnIndex, rowIndex) : null
|
|
||||||
}
|
|
||||||
onMouseOver={this.handleHover(columnIndex, rowIndex)}
|
onMouseOver={this.handleHover(columnIndex, rowIndex)}
|
||||||
title={cellContents}
|
title={cellContents}
|
||||||
>
|
>
|
||||||
|
@ -253,33 +288,41 @@ class TableGraph extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
sortByColumnIndex,
|
|
||||||
clickToSortFieldIndex,
|
|
||||||
clicktoSortDirection,
|
|
||||||
hoveredColumnIndex,
|
hoveredColumnIndex,
|
||||||
hoveredRowIndex,
|
hoveredRowIndex,
|
||||||
|
sortField,
|
||||||
|
sortDirection,
|
||||||
|
processedData,
|
||||||
|
data,
|
||||||
} = this.state
|
} = this.state
|
||||||
const {hoverTime, tableOptions, colors} = this.props
|
const {hoverTime, tableOptions, colors} = this.props
|
||||||
const verticalTimeAxis = _.get(tableOptions, 'verticalTimeAxis', true)
|
const {
|
||||||
const data = verticalTimeAxis ? this.state.data : this.state.unzippedData
|
verticalTimeAxis = VERTICAL_TIME_AXIS_DEFAULT,
|
||||||
|
fixFirstColumn = FIX_FIRST_COLUMN_DEFAULT,
|
||||||
|
} = tableOptions
|
||||||
|
|
||||||
|
const columnCount = _.get(processedData, ['0', 'length'], 0)
|
||||||
|
const rowCount = columnCount === 0 ? 0 : processedData.length
|
||||||
|
|
||||||
const columnCount = _.get(data, ['0', 'length'], 0)
|
|
||||||
const rowCount = data.length
|
|
||||||
const COLUMN_MIN_WIDTH = 98
|
const COLUMN_MIN_WIDTH = 98
|
||||||
const COLUMN_MAX_WIDTH = 1000
|
const COLUMN_MAX_WIDTH = 1000
|
||||||
const ROW_HEIGHT = 30
|
const ROW_HEIGHT = 30
|
||||||
|
|
||||||
|
const fixedColumnCount = fixFirstColumn && columnCount > 1 ? 1 : undefined
|
||||||
|
|
||||||
const tableWidth = _.get(this, ['gridContainer', 'clientWidth'], 0)
|
const tableWidth = _.get(this, ['gridContainer', 'clientWidth'], 0)
|
||||||
const tableHeight = _.get(this, ['gridContainer', 'clientHeight'], 0)
|
const tableHeight = _.get(this, ['gridContainer', 'clientHeight'], 0)
|
||||||
|
|
||||||
const hoverTimeIndex =
|
const hoverTimeIndex =
|
||||||
hoveredRowIndex === NULL_ROW_INDEX
|
hoveredRowIndex === NULL_ARRAY_INDEX
|
||||||
? this.calcHoverTimeIndex(data, hoverTime, verticalTimeAxis)
|
? this.calcHoverTimeIndex(data, hoverTime, verticalTimeAxis)
|
||||||
: hoveredRowIndex
|
: hoveredRowIndex
|
||||||
const fixedColumnCount = tableOptions.fixFirstColumn ? 1 : undefined
|
const hoveringThisTable = hoveredColumnIndex !== NULL_ARRAY_INDEX
|
||||||
const hoveringThisTable = hoveredColumnIndex !== NULL_COLUMN_INDEX
|
|
||||||
const scrollToRow =
|
|
||||||
!hoveringThisTable && verticalTimeAxis ? hoverTimeIndex : undefined
|
|
||||||
const scrollToColumn =
|
const scrollToColumn =
|
||||||
!hoveringThisTable && !verticalTimeAxis ? hoverTimeIndex : undefined
|
!hoveringThisTable && !verticalTimeAxis ? hoverTimeIndex : undefined
|
||||||
|
const scrollToRow =
|
||||||
|
!hoveringThisTable && verticalTimeAxis ? hoverTimeIndex : undefined
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -287,14 +330,14 @@ class TableGraph extends Component {
|
||||||
ref={gridContainer => (this.gridContainer = gridContainer)}
|
ref={gridContainer => (this.gridContainer = gridContainer)}
|
||||||
onMouseOut={this.handleMouseOut}
|
onMouseOut={this.handleMouseOut}
|
||||||
>
|
>
|
||||||
{!isEmpty(data) && (
|
{rowCount > 0 &&
|
||||||
<ColumnSizer
|
<ColumnSizer
|
||||||
columnCount={columnCount}
|
columnCount={columnCount}
|
||||||
columnMaxWidth={COLUMN_MAX_WIDTH}
|
columnMaxWidth={COLUMN_MAX_WIDTH}
|
||||||
columnMinWidth={COLUMN_MIN_WIDTH}
|
columnMinWidth={COLUMN_MIN_WIDTH}
|
||||||
width={tableWidth}
|
width={tableWidth}
|
||||||
>
|
>
|
||||||
{({getColumnWidth, registerChild}) => (
|
{({getColumnWidth, registerChild}) =>
|
||||||
<MultiGrid
|
<MultiGrid
|
||||||
ref={registerChild}
|
ref={registerChild}
|
||||||
columnCount={columnCount}
|
columnCount={columnCount}
|
||||||
|
@ -307,41 +350,47 @@ class TableGraph extends Component {
|
||||||
fixedRowCount={1}
|
fixedRowCount={1}
|
||||||
enableFixedColumnScroll={true}
|
enableFixedColumnScroll={true}
|
||||||
enableFixedRowScroll={true}
|
enableFixedRowScroll={true}
|
||||||
timeFormat={
|
|
||||||
tableOptions ? tableOptions.timeFormat : TIME_FORMAT_DEFAULT
|
|
||||||
}
|
|
||||||
columnNames={
|
|
||||||
tableOptions
|
|
||||||
? tableOptions.columnNames
|
|
||||||
: [TIME_COLUMN_DEFAULT]
|
|
||||||
}
|
|
||||||
scrollToRow={scrollToRow}
|
scrollToRow={scrollToRow}
|
||||||
scrollToColumn={scrollToColumn}
|
scrollToColumn={scrollToColumn}
|
||||||
verticalTimeAxis={verticalTimeAxis}
|
sortField={sortField}
|
||||||
sortByColumnIndex={sortByColumnIndex}
|
sortDirection={sortDirection}
|
||||||
clickToSortFieldIndex={clickToSortFieldIndex}
|
|
||||||
clicktoSortDirection={clicktoSortDirection}
|
|
||||||
cellRenderer={this.cellRenderer}
|
cellRenderer={this.cellRenderer}
|
||||||
hoveredColumnIndex={hoveredColumnIndex}
|
hoveredColumnIndex={hoveredColumnIndex}
|
||||||
hoveredRowIndex={hoveredRowIndex}
|
hoveredRowIndex={hoveredRowIndex}
|
||||||
hoverTime={hoverTime}
|
hoverTime={hoverTime}
|
||||||
colors={colors}
|
colors={colors}
|
||||||
|
tableOptions={tableOptions}
|
||||||
classNameBottomRightGrid="table-graph--scroll-window"
|
classNameBottomRightGrid="table-graph--scroll-window"
|
||||||
/>
|
/>}
|
||||||
)}
|
</ColumnSizer>}
|
||||||
</ColumnSizer>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const {arrayOf, number, shape, string, func} = PropTypes
|
const {arrayOf, bool, number, shape, string, func} = PropTypes
|
||||||
|
|
||||||
TableGraph.propTypes = {
|
TableGraph.propTypes = {
|
||||||
cellHeight: number,
|
cellHeight: number,
|
||||||
data: arrayOf(shape()),
|
data: arrayOf(shape()),
|
||||||
tableOptions: shape({}),
|
tableOptions: shape({
|
||||||
|
timeFormat: string.isRequired,
|
||||||
|
verticalTimeAxis: bool.isRequired,
|
||||||
|
sortBy: shape({
|
||||||
|
internalName: string.isRequired,
|
||||||
|
displayName: string.isRequired,
|
||||||
|
visible: bool.isRequired,
|
||||||
|
}).isRequired,
|
||||||
|
wrapping: string.isRequired,
|
||||||
|
fieldNames: arrayOf(
|
||||||
|
shape({
|
||||||
|
internalName: string.isRequired,
|
||||||
|
displayName: string.isRequired,
|
||||||
|
visible: bool.isRequired,
|
||||||
|
})
|
||||||
|
).isRequired,
|
||||||
|
fixFirstColumn: bool,
|
||||||
|
}),
|
||||||
hoverTime: string,
|
hoverTime: string,
|
||||||
onSetHoverTime: func,
|
onSetHoverTime: func,
|
||||||
colors: arrayOf(
|
colors: arrayOf(
|
||||||
|
@ -353,6 +402,7 @@ TableGraph.propTypes = {
|
||||||
value: string.isRequired,
|
value: string.isRequired,
|
||||||
}).isRequired
|
}).isRequired
|
||||||
),
|
),
|
||||||
|
setDataLabels: func,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TableGraph
|
export default TableGraph
|
||||||
|
|
|
@ -3,17 +3,23 @@ import _ from 'lodash'
|
||||||
|
|
||||||
export const NULL_COLUMN_INDEX = -1
|
export const NULL_COLUMN_INDEX = -1
|
||||||
export const NULL_ROW_INDEX = -1
|
export const NULL_ROW_INDEX = -1
|
||||||
|
export const NULL_ARRAY_INDEX = -1
|
||||||
|
|
||||||
export const NULL_HOVER_TIME = '0'
|
export const NULL_HOVER_TIME = '0'
|
||||||
|
|
||||||
export const TIME_FORMAT_DEFAULT = 'MM/DD/YYYY HH:mm:ss.ss'
|
export const TIME_FORMAT_DEFAULT = 'MM/DD/YYYY HH:mm:ss.ss'
|
||||||
export const TIME_FORMAT_CUSTOM = 'Custom'
|
export const TIME_FORMAT_CUSTOM = 'Custom'
|
||||||
|
|
||||||
export const TIME_COLUMN_DEFAULT = {internalName: 'time', displayName: ''}
|
export const TIME_FIELD_DEFAULT = {
|
||||||
|
internalName: 'time',
|
||||||
|
displayName: '',
|
||||||
|
visible: true,
|
||||||
|
}
|
||||||
|
|
||||||
export const ASCENDING = 'asc'
|
export const ASCENDING = 'asc'
|
||||||
export const DESCENDING = 'desc'
|
export const DESCENDING = 'desc'
|
||||||
export const FIX_FIRST_COLUMN_DEFAULT = true
|
export const FIX_FIRST_COLUMN_DEFAULT = true
|
||||||
|
export const VERTICAL_TIME_AXIS_DEFAULT = true
|
||||||
|
|
||||||
export const CELL_HORIZONTAL_PADDING = 18
|
export const CELL_HORIZONTAL_PADDING = 18
|
||||||
|
|
||||||
|
@ -30,11 +36,11 @@ export const FORMAT_OPTIONS = [
|
||||||
]
|
]
|
||||||
|
|
||||||
export const DEFAULT_TABLE_OPTIONS = {
|
export const DEFAULT_TABLE_OPTIONS = {
|
||||||
verticalTimeAxis: true,
|
verticalTimeAxis: VERTICAL_TIME_AXIS_DEFAULT,
|
||||||
timeFormat: TIME_FORMAT_DEFAULT,
|
timeFormat: TIME_FORMAT_DEFAULT,
|
||||||
sortBy: TIME_COLUMN_DEFAULT,
|
sortBy: TIME_FIELD_DEFAULT,
|
||||||
wrapping: 'truncate',
|
wrapping: 'truncate',
|
||||||
columnNames: [TIME_COLUMN_DEFAULT],
|
fieldNames: [TIME_FIELD_DEFAULT],
|
||||||
fixFirstColumn: FIX_FIRST_COLUMN_DEFAULT,
|
fixFirstColumn: FIX_FIRST_COLUMN_DEFAULT,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,6 @@ export const THRESHOLD_TYPE_TEXT = 'text'
|
||||||
export const THRESHOLD_TYPE_BG = 'background'
|
export const THRESHOLD_TYPE_BG = 'background'
|
||||||
export const THRESHOLD_TYPE_BASE = 'base'
|
export const THRESHOLD_TYPE_BASE = 'base'
|
||||||
|
|
||||||
export const TIME_FORMAT_DEFAULT = 'MM/DD/YYYY HH:mm:ss.ss'
|
|
||||||
|
|
||||||
export const THRESHOLD_COLORS = [
|
export const THRESHOLD_COLORS = [
|
||||||
{
|
{
|
||||||
hex: '#BF3D5E',
|
hex: '#BF3D5E',
|
||||||
|
@ -121,16 +119,6 @@ export const DEFAULT_THRESHOLDS_LIST_COLORS = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const DEFAULT_TABLE_COLORS = [
|
|
||||||
{
|
|
||||||
type: THRESHOLD_TYPE_BG,
|
|
||||||
hex: THRESHOLD_COLORS[18].hex,
|
|
||||||
id: THRESHOLD_TYPE_BASE,
|
|
||||||
name: THRESHOLD_COLORS[18].name,
|
|
||||||
value: 0,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
export const validateThresholdsListColors = (colors, type) => {
|
export const validateThresholdsListColors = (colors, type) => {
|
||||||
if (!colors || colors.length === 0) {
|
if (!colors || colors.length === 0) {
|
||||||
return DEFAULT_THRESHOLDS_LIST_COLORS
|
return DEFAULT_THRESHOLDS_LIST_COLORS
|
||||||
|
|
|
@ -207,7 +207,7 @@ $graph-type--gutter: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gauge-controls--section,
|
.gauge-controls--section,
|
||||||
.column-controls--section {
|
.field-controls--section {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
|
@ -256,18 +256,34 @@ button.btn.btn-primary.btn-sm.gauge-controls--add-threshold {
|
||||||
flex: 1 0 0;
|
flex: 1 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.field-controls--group {
|
||||||
.column-controls--label {
|
max-height: 235px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
.field-controls--label, .field-controls--label-hidden {
|
||||||
@extend %gauge-controls-label-styles;
|
@extend %gauge-controls-label-styles;
|
||||||
color: $g16-pearl;
|
color: $g16-pearl;
|
||||||
background-color: $g4-onyx;
|
background-color: $g4-onyx;
|
||||||
flex: 2 0 0;
|
flex: 2 0 0;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
padding-right: 5px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.column-controls-input {
|
.field-controls--label-hidden {
|
||||||
|
color: $g0-obsidian;
|
||||||
|
}
|
||||||
|
.field-controls-input {
|
||||||
flex: 1 0 0;
|
flex: 1 0 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Cell Editor Overlay - Single-Stat Controls
|
Cell Editor Overlay - Single-Stat Controls
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
|
|
@ -178,8 +178,10 @@ export const timeSeriesToTableGraph = raw => {
|
||||||
|
|
||||||
const tableData = map(sortedTimeSeries, ({time, values}) => [time, ...values])
|
const tableData = map(sortedTimeSeries, ({time, values}) => [time, ...values])
|
||||||
const data = tableData.length ? [labels, ...tableData] : [[]]
|
const data = tableData.length ? [labels, ...tableData] : [[]]
|
||||||
|
return {
|
||||||
return {data}
|
labels,
|
||||||
|
data,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default timeSeriesToDygraph
|
export default timeSeriesToDygraph
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import GraphOptionsCustomizableColumn from 'src/dashboards/components/GraphOptionsCustomizableColumn'
|
|
||||||
import InputClickToEdit from 'src/shared/components/InputClickToEdit'
|
|
||||||
|
|
||||||
import {shallow} from 'enzyme'
|
|
||||||
|
|
||||||
const setup = (override = {}) => {
|
|
||||||
const props = {
|
|
||||||
displayName: '',
|
|
||||||
internalName: '',
|
|
||||||
onColumnRename: () => {},
|
|
||||||
...override,
|
|
||||||
}
|
|
||||||
|
|
||||||
const wrapper = shallow(<GraphOptionsCustomizableColumn {...props} />)
|
|
||||||
const instance = wrapper.instance() as GraphOptionsCustomizableColumn
|
|
||||||
|
|
||||||
return {wrapper, props, instance}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('Dashboards.Components.GraphOptionsCustomizableColumn', () => {
|
|
||||||
describe('rendering', () => {
|
|
||||||
it('displays both label div and InputClickToEdit', () => {
|
|
||||||
const {wrapper} = setup()
|
|
||||||
const label = wrapper.find('div').last()
|
|
||||||
const input = wrapper.find(InputClickToEdit)
|
|
||||||
|
|
||||||
expect(label.exists()).toBe(true)
|
|
||||||
expect(input.exists()).toBe(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('when there is an internalName', () => {
|
|
||||||
it('displays the value', () => {
|
|
||||||
const internalName = 'test'
|
|
||||||
const {wrapper} = setup({internalName})
|
|
||||||
const label = wrapper.find('div').last()
|
|
||||||
expect(label.exists()).toBe(true)
|
|
||||||
expect(label.children().contains(internalName)).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('instance methods', () => {
|
|
||||||
describe('#handleColumnRename', () => {
|
|
||||||
it('calls onColumnRename once', () => {
|
|
||||||
const onColumnRename = jest.fn()
|
|
||||||
const internalName = 'test'
|
|
||||||
const {instance} = setup({onColumnRename, internalName})
|
|
||||||
const rename = 'TEST'
|
|
||||||
|
|
||||||
instance.handleColumnRename(rename)
|
|
||||||
|
|
||||||
expect(onColumnRename).toHaveBeenCalledTimes(1)
|
|
||||||
expect(onColumnRename).toHaveBeenCalledWith({
|
|
||||||
displayName: rename,
|
|
||||||
internalName,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
import {shallow} from 'enzyme'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import GraphOptionsCustomizableField from 'src/dashboards/components/GraphOptionsCustomizableField'
|
||||||
|
import InputClickToEdit from 'src/shared/components/InputClickToEdit'
|
||||||
|
|
||||||
|
const setup = (override = {}) => {
|
||||||
|
const props = {
|
||||||
|
displayName: '',
|
||||||
|
internalName: '',
|
||||||
|
onFieldUpdate: () => {},
|
||||||
|
visible: true,
|
||||||
|
...override,
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrapper = shallow(<GraphOptionsCustomizableField {...props} />)
|
||||||
|
const instance = wrapper.instance() as GraphOptionsCustomizableField
|
||||||
|
|
||||||
|
return {wrapper, props, instance}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Dashboards.Components.GraphOptionsCustomizableField', () => {
|
||||||
|
describe('rendering', () => {
|
||||||
|
it('displays both label div and InputClickToEdit', () => {
|
||||||
|
const {wrapper} = setup()
|
||||||
|
const label = wrapper.find('div').last()
|
||||||
|
const input = wrapper.find(InputClickToEdit)
|
||||||
|
const icon = wrapper.find('span')
|
||||||
|
|
||||||
|
expect(label.exists()).toBe(true)
|
||||||
|
expect(icon.exists()).toBe(true)
|
||||||
|
expect(input.exists()).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when there is an internalName', () => {
|
||||||
|
it('displays the value', () => {
|
||||||
|
const internalName = 'test'
|
||||||
|
const {wrapper} = setup({internalName})
|
||||||
|
const label = wrapper.find('div').last()
|
||||||
|
const icon = wrapper.find('span')
|
||||||
|
|
||||||
|
expect(label.exists()).toBe(true)
|
||||||
|
expect(label.children().contains(internalName)).toBe(true)
|
||||||
|
expect(icon.exists()).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when visible is false', () => {
|
||||||
|
it('displays disabled inputClickToEdit', () => {
|
||||||
|
const visible = false
|
||||||
|
const {wrapper} = setup({visible})
|
||||||
|
const input = wrapper.find(InputClickToEdit)
|
||||||
|
|
||||||
|
expect(input.prop('disabled')).toBe(!visible)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('instance methods', () => {
|
||||||
|
describe('#handleFieldUpdate', () => {
|
||||||
|
it('calls onFieldUpdate once with internalName, new name, and visible', () => {
|
||||||
|
const onFieldUpdate = jest.fn()
|
||||||
|
const internalName = 'test'
|
||||||
|
const {instance, props: {visible}} = setup({
|
||||||
|
internalName,
|
||||||
|
onFieldUpdate,
|
||||||
|
})
|
||||||
|
const rename = 'TEST'
|
||||||
|
|
||||||
|
instance.handleFieldRename(rename)
|
||||||
|
|
||||||
|
expect(onFieldUpdate).toHaveBeenCalledTimes(1)
|
||||||
|
expect(onFieldUpdate).toHaveBeenCalledWith({
|
||||||
|
displayName: rename,
|
||||||
|
internalName,
|
||||||
|
visible,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#handleToggleVisible', () => {
|
||||||
|
it('calls onFieldUpdate once with !visible, internalName, and displayName', () => {
|
||||||
|
const onFieldUpdate = jest.fn()
|
||||||
|
const visible = true
|
||||||
|
const {instance, props: {internalName, displayName}} = setup({
|
||||||
|
onFieldUpdate,
|
||||||
|
visible,
|
||||||
|
})
|
||||||
|
|
||||||
|
instance.handleToggleVisible()
|
||||||
|
|
||||||
|
expect(onFieldUpdate).toHaveBeenCalledTimes(1)
|
||||||
|
expect(onFieldUpdate).toHaveBeenCalledWith({
|
||||||
|
displayName,
|
||||||
|
internalName,
|
||||||
|
visible: !visible,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -1,34 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import GraphOptionsCustomizableColumn from 'src/dashboards/components/GraphOptionsCustomizableColumn'
|
|
||||||
import GraphOptionsCustomizeColumns from 'src/dashboards/components/GraphOptionsCustomizeColumns'
|
|
||||||
import {TIME_COLUMN_DEFAULT} from 'src/shared/constants/tableGraph'
|
|
||||||
|
|
||||||
import {shallow} from 'enzyme'
|
|
||||||
|
|
||||||
const setup = (override = {}) => {
|
|
||||||
const props = {
|
|
||||||
columns: [],
|
|
||||||
onColumnRename: () => {},
|
|
||||||
...override,
|
|
||||||
}
|
|
||||||
|
|
||||||
const wrapper = shallow(<GraphOptionsCustomizeColumns {...props} />)
|
|
||||||
|
|
||||||
return {wrapper, props}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('Dashboards.Components.GraphOptionsCustomizeColumns', () => {
|
|
||||||
describe('rendering', () => {
|
|
||||||
it('displays label and all columns passed in', () => {
|
|
||||||
const columns = [TIME_COLUMN_DEFAULT]
|
|
||||||
const {wrapper} = setup({columns})
|
|
||||||
const label = wrapper.find('label')
|
|
||||||
const customizableColumns = wrapper.find(GraphOptionsCustomizableColumn)
|
|
||||||
|
|
||||||
expect(label.exists()).toBe(true)
|
|
||||||
expect(customizableColumns.exists()).toBe(true)
|
|
||||||
expect(customizableColumns.length).toBe(columns.length)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import {shallow} from 'enzyme'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import GraphOptionsCustomizableField from 'src/dashboards/components/GraphOptionsCustomizableField'
|
||||||
|
import GraphOptionsCustomizeFields from 'src/dashboards/components/GraphOptionsCustomizeFields'
|
||||||
|
import {TIME_FIELD_DEFAULT} from 'src/shared/constants/tableGraph'
|
||||||
|
|
||||||
|
const setup = (override = {}) => {
|
||||||
|
const props = {
|
||||||
|
fields: [],
|
||||||
|
onFieldUpdate: () => {},
|
||||||
|
...override,
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrapper = shallow(<GraphOptionsCustomizeFields {...props} />)
|
||||||
|
|
||||||
|
return {wrapper, props}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Dashboards.Components.GraphOptionsCustomizableField', () => {
|
||||||
|
describe('rendering', () => {
|
||||||
|
it('displays label and all fields passed in', () => {
|
||||||
|
const fields = [TIME_FIELD_DEFAULT]
|
||||||
|
const {wrapper} = setup({fields})
|
||||||
|
const label = wrapper.find('label')
|
||||||
|
const CustomizableFields = wrapper.find(GraphOptionsCustomizableField)
|
||||||
|
|
||||||
|
expect(label.exists()).toBe(true)
|
||||||
|
expect(CustomizableFields.exists()).toBe(true)
|
||||||
|
expect(CustomizableFields.length).toBe(fields.length)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -1,59 +1,26 @@
|
||||||
|
import {shallow} from 'enzyme'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import GraphOptionsCustomizeFields from 'src/dashboards/components/GraphOptionsCustomizeFields'
|
||||||
import {TableOptions} from 'src/dashboards/components/TableOptions'
|
|
||||||
|
|
||||||
import GraphOptionsCustomizeColumns from 'src/dashboards/components/GraphOptionsCustomizeColumns'
|
|
||||||
import GraphOptionsFixFirstColumn from 'src/dashboards/components/GraphOptionsFixFirstColumn'
|
import GraphOptionsFixFirstColumn from 'src/dashboards/components/GraphOptionsFixFirstColumn'
|
||||||
import GraphOptionsSortBy from 'src/dashboards/components/GraphOptionsSortBy'
|
import GraphOptionsSortBy from 'src/dashboards/components/GraphOptionsSortBy'
|
||||||
import GraphOptionsTextWrapping from 'src/dashboards/components/GraphOptionsTextWrapping'
|
|
||||||
import GraphOptionsTimeAxis from 'src/dashboards/components/GraphOptionsTimeAxis'
|
import GraphOptionsTimeAxis from 'src/dashboards/components/GraphOptionsTimeAxis'
|
||||||
import GraphOptionsTimeFormat from 'src/dashboards/components/GraphOptionsTimeFormat'
|
import GraphOptionsTimeFormat from 'src/dashboards/components/GraphOptionsTimeFormat'
|
||||||
|
import {TableOptions} from 'src/dashboards/components/TableOptions'
|
||||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||||
import ThresholdsList from 'src/shared/components/ThresholdsList'
|
import ThresholdsList from 'src/shared/components/ThresholdsList'
|
||||||
import ThresholdsListTypeToggle from 'src/shared/components/ThresholdsListTypeToggle'
|
import ThresholdsListTypeToggle from 'src/shared/components/ThresholdsListTypeToggle'
|
||||||
|
|
||||||
import {shallow} from 'enzyme'
|
|
||||||
|
|
||||||
const queryConfigs = [
|
|
||||||
{
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
alias: 'boom',
|
|
||||||
value: 'test',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
alias: 'again',
|
|
||||||
value: 'again',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
measurement: 'dev',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
alias: 'boom',
|
|
||||||
value: 'test',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
alias: 'again',
|
|
||||||
value: 'again',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
measurement: 'prod',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
|
dataLabels: [],
|
||||||
handleUpdateTableOptions: () => {},
|
handleUpdateTableOptions: () => {},
|
||||||
onResetFocus: () => {},
|
onResetFocus: () => {},
|
||||||
queryConfigs,
|
|
||||||
tableOptions: {
|
tableOptions: {
|
||||||
columnNames: [],
|
columnNames: [],
|
||||||
|
fieldNames: [],
|
||||||
fixFirstColumn: true,
|
fixFirstColumn: true,
|
||||||
sortBy: {internalName: '', displayName: ''},
|
sortBy: {displayName: '', internalName: '', visible: true},
|
||||||
timeFormat: '',
|
timeFormat: '',
|
||||||
verticalTimeAxis: true,
|
verticalTimeAxis: true,
|
||||||
wrapping: '',
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,89 +37,31 @@ const setup = (override = {}) => {
|
||||||
|
|
||||||
describe('Dashboards.Components.TableOptions', () => {
|
describe('Dashboards.Components.TableOptions', () => {
|
||||||
describe('getters', () => {
|
describe('getters', () => {
|
||||||
describe('computedColumnNames', () => {
|
describe('computedColumnNames', () => {})
|
||||||
it('returns the correct column names', () => {
|
|
||||||
const instance = new TableOptions(defaultProps)
|
|
||||||
|
|
||||||
const expected = [
|
|
||||||
{
|
|
||||||
displayName: '',
|
|
||||||
internalName: 'time',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayName: '',
|
|
||||||
internalName: 'dev.boom',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayName: '',
|
|
||||||
internalName: 'dev.again',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayName: '',
|
|
||||||
internalName: 'prod.boom',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayName: '',
|
|
||||||
internalName: 'prod.again',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
expect(instance.computedColumnNames).toEqual(expected)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('rendering', () => {
|
describe('rendering', () => {
|
||||||
it('should render all components', () => {
|
it('should render all components', () => {
|
||||||
const qc = [
|
const {wrapper} = setup()
|
||||||
{
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
alias: 'boom',
|
|
||||||
value: 'test',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
measurement: 'dev',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const expectedSortOptions = [
|
|
||||||
{
|
|
||||||
key: 'time',
|
|
||||||
text: 'time',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'dev.boom',
|
|
||||||
text: 'dev.boom',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const {wrapper} = setup({queryConfigs: qc})
|
|
||||||
const fancyScrollbar = wrapper.find(FancyScrollbar)
|
const fancyScrollbar = wrapper.find(FancyScrollbar)
|
||||||
const graphOptionsTimeFormat = wrapper.find(GraphOptionsTimeFormat)
|
const graphOptionsTimeFormat = wrapper.find(GraphOptionsTimeFormat)
|
||||||
const graphOptionsTimeAxis = wrapper.find(GraphOptionsTimeAxis)
|
const graphOptionsTimeAxis = wrapper.find(GraphOptionsTimeAxis)
|
||||||
const graphOptionsSortBy = wrapper.find(GraphOptionsSortBy)
|
const graphOptionsSortBy = wrapper.find(GraphOptionsSortBy)
|
||||||
const graphOptionsTextWrapping = wrapper.find(GraphOptionsTextWrapping)
|
|
||||||
const graphOptionsFixFirstColumn = wrapper.find(
|
const graphOptionsFixFirstColumn = wrapper.find(
|
||||||
GraphOptionsFixFirstColumn
|
GraphOptionsFixFirstColumn
|
||||||
)
|
)
|
||||||
const graphOptionsCustomizeColumns = wrapper.find(
|
const graphOptionsCustomizeFields = wrapper.find(
|
||||||
GraphOptionsCustomizeColumns
|
GraphOptionsCustomizeFields
|
||||||
)
|
)
|
||||||
const thresholdsList = wrapper.find(ThresholdsList)
|
const thresholdsList = wrapper.find(ThresholdsList)
|
||||||
const thresholdsListTypeToggle = wrapper.find(ThresholdsListTypeToggle)
|
const thresholdsListTypeToggle = wrapper.find(ThresholdsListTypeToggle)
|
||||||
|
|
||||||
expect(graphOptionsSortBy.props().sortByOptions).toEqual(
|
|
||||||
expectedSortOptions
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(fancyScrollbar.exists()).toBe(true)
|
expect(fancyScrollbar.exists()).toBe(true)
|
||||||
expect(graphOptionsTimeFormat.exists()).toBe(true)
|
expect(graphOptionsTimeFormat.exists()).toBe(true)
|
||||||
expect(graphOptionsTimeAxis.exists()).toBe(true)
|
expect(graphOptionsTimeAxis.exists()).toBe(true)
|
||||||
expect(graphOptionsSortBy.exists()).toBe(true)
|
expect(graphOptionsSortBy.exists()).toBe(true)
|
||||||
expect(graphOptionsTextWrapping.exists()).toBe(true)
|
|
||||||
expect(graphOptionsFixFirstColumn.exists()).toBe(true)
|
expect(graphOptionsFixFirstColumn.exists()).toBe(true)
|
||||||
expect(graphOptionsCustomizeColumns.exists()).toBe(true)
|
expect(graphOptionsCustomizeFields.exists()).toBe(true)
|
||||||
expect(thresholdsList.exists()).toBe(true)
|
expect(thresholdsList.exists()).toBe(true)
|
||||||
expect(thresholdsListTypeToggle.exists()).toBe(true)
|
expect(thresholdsListTypeToggle.exists()).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue