Merge branch 'master' into enhancement/introduce-overlay-layer
commit
bb37a872e9
|
@ -12,6 +12,7 @@
|
|||
1. [#3214](https://github.com/influxdata/chronograf/pull/3214): Remove extra click when creating dashboard cell
|
||||
1. [#3256](https://github.com/influxdata/chronograf/pull/3256): Reduce font sizes in dashboards for increased space efficiency
|
||||
1. [#3320](https://github.com/influxdata/chronograf/pull/3320): Add overlay animation to Template Variables Manager
|
||||
1. [#3245](https://github.com/influxdata/chronograf/pull/3245): Display 'no results' on cells without results
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
|
|
|
@ -344,7 +344,6 @@ func (m *DashboardCell) GetTableOptions() *TableOptions {
|
|||
}
|
||||
|
||||
type TableOptions struct {
|
||||
TimeFormat string `protobuf:"bytes,1,opt,name=timeFormat,proto3" json:"timeFormat,omitempty"`
|
||||
VerticalTimeAxis bool `protobuf:"varint,2,opt,name=verticalTimeAxis,proto3" json:"verticalTimeAxis,omitempty"`
|
||||
SortBy *RenamableField `protobuf:"bytes,3,opt,name=sortBy" json:"sortBy,omitempty"`
|
||||
Wrapping string `protobuf:"bytes,4,opt,name=wrapping,proto3" json:"wrapping,omitempty"`
|
||||
|
@ -357,13 +356,6 @@ func (m *TableOptions) String() string { return proto.CompactTextStri
|
|||
func (*TableOptions) ProtoMessage() {}
|
||||
func (*TableOptions) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{3} }
|
||||
|
||||
func (m *TableOptions) GetTimeFormat() string {
|
||||
if m != nil {
|
||||
return m.TimeFormat
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *TableOptions) GetVerticalTimeAxis() bool {
|
||||
if m != nil {
|
||||
return m.VerticalTimeAxis
|
||||
|
|
|
@ -273,24 +273,27 @@ func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) {
|
|||
Visible: c.TableOptions.SortBy.Visible,
|
||||
}
|
||||
|
||||
fieldNames := make([]*RenamableField, len(c.TableOptions.FieldNames))
|
||||
for i, field := range c.TableOptions.FieldNames {
|
||||
fieldNames[i] = &RenamableField{
|
||||
tableOptions := &TableOptions{
|
||||
VerticalTimeAxis: c.TableOptions.VerticalTimeAxis,
|
||||
SortBy: sortBy,
|
||||
Wrapping: c.TableOptions.Wrapping,
|
||||
FixFirstColumn: c.TableOptions.FixFirstColumn,
|
||||
}
|
||||
|
||||
decimalPlaces := &DecimalPlaces{
|
||||
IsEnforced: c.DecimalPlaces.IsEnforced,
|
||||
Digits: c.DecimalPlaces.Digits,
|
||||
}
|
||||
|
||||
fieldOptions := make([]*RenamableField, len(c.FieldOptions))
|
||||
for i, field := range c.FieldOptions {
|
||||
fieldOptions[i] = &RenamableField{
|
||||
InternalName: field.InternalName,
|
||||
DisplayName: field.DisplayName,
|
||||
Visible: field.Visible,
|
||||
}
|
||||
}
|
||||
|
||||
tableOptions := &TableOptions{
|
||||
TimeFormat: c.TableOptions.TimeFormat,
|
||||
VerticalTimeAxis: c.TableOptions.VerticalTimeAxis,
|
||||
SortBy: sortBy,
|
||||
Wrapping: c.TableOptions.Wrapping,
|
||||
FieldNames: fieldNames,
|
||||
FixFirstColumn: c.TableOptions.FixFirstColumn,
|
||||
}
|
||||
|
||||
cells[i] = &DashboardCell{
|
||||
ID: c.ID,
|
||||
X: c.X,
|
||||
|
@ -306,7 +309,10 @@ func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) {
|
|||
Type: c.Legend.Type,
|
||||
Orientation: c.Legend.Orientation,
|
||||
},
|
||||
TableOptions: tableOptions,
|
||||
TableOptions: tableOptions,
|
||||
FieldOptions: fieldOptions,
|
||||
TimeFormat: c.TimeFormat,
|
||||
DecimalPlaces: decimalPlaces,
|
||||
}
|
||||
}
|
||||
templates := make([]*Template, len(d.Templates))
|
||||
|
@ -442,20 +448,26 @@ func UnmarshalDashboard(data []byte, d *chronograf.Dashboard) error {
|
|||
sortBy.Visible = c.TableOptions.SortBy.Visible
|
||||
}
|
||||
tableOptions.SortBy = sortBy
|
||||
|
||||
fieldNames := make([]chronograf.RenamableField, len(c.TableOptions.FieldNames))
|
||||
for i, field := range c.TableOptions.FieldNames {
|
||||
fieldNames[i] = chronograf.RenamableField{}
|
||||
fieldNames[i].InternalName = field.InternalName
|
||||
fieldNames[i].DisplayName = field.DisplayName
|
||||
fieldNames[i].Visible = field.Visible
|
||||
}
|
||||
tableOptions.FieldNames = fieldNames
|
||||
tableOptions.TimeFormat = c.TableOptions.TimeFormat
|
||||
tableOptions.VerticalTimeAxis = c.TableOptions.VerticalTimeAxis
|
||||
tableOptions.Wrapping = c.TableOptions.Wrapping
|
||||
tableOptions.FixFirstColumn = c.TableOptions.FixFirstColumn
|
||||
}
|
||||
|
||||
fieldOptions := make([]chronograf.RenamableField, len(c.FieldOptions))
|
||||
for i, field := range c.FieldOptions {
|
||||
fieldOptions[i] = chronograf.RenamableField{}
|
||||
fieldOptions[i].InternalName = field.InternalName
|
||||
fieldOptions[i].DisplayName = field.DisplayName
|
||||
fieldOptions[i].Visible = field.Visible
|
||||
}
|
||||
|
||||
decimalPlaces := chronograf.DecimalPlaces{}
|
||||
if c.DecimalPlaces != nil {
|
||||
decimalPlaces.IsEnforced = c.DecimalPlaces.IsEnforced
|
||||
decimalPlaces.Digits = c.DecimalPlaces.Digits
|
||||
} else {
|
||||
decimalPlaces.IsEnforced = false
|
||||
decimalPlaces.Digits = 3
|
||||
}
|
||||
|
||||
// FIXME: this is merely for legacy cells and
|
||||
|
@ -466,18 +478,21 @@ func UnmarshalDashboard(data []byte, d *chronograf.Dashboard) error {
|
|||
}
|
||||
|
||||
cells[i] = chronograf.DashboardCell{
|
||||
ID: c.ID,
|
||||
X: c.X,
|
||||
Y: c.Y,
|
||||
W: c.W,
|
||||
H: c.H,
|
||||
Name: c.Name,
|
||||
Queries: queries,
|
||||
Type: cellType,
|
||||
Axes: axes,
|
||||
CellColors: colors,
|
||||
Legend: legend,
|
||||
TableOptions: tableOptions,
|
||||
ID: c.ID,
|
||||
X: c.X,
|
||||
Y: c.Y,
|
||||
W: c.W,
|
||||
H: c.H,
|
||||
Name: c.Name,
|
||||
Queries: queries,
|
||||
Type: cellType,
|
||||
Axes: axes,
|
||||
CellColors: colors,
|
||||
Legend: legend,
|
||||
TableOptions: tableOptions,
|
||||
FieldOptions: fieldOptions,
|
||||
TimeFormat: c.TimeFormat,
|
||||
DecimalPlaces: decimalPlaces,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ It has these top-level messages:
|
|||
Source
|
||||
Dashboard
|
||||
DashboardCell
|
||||
DecimalPlaces
|
||||
TableOptions
|
||||
RenamableField
|
||||
Color
|
||||
|
@ -220,18 +221,21 @@ func (m *Dashboard) GetOrganization() string {
|
|||
}
|
||||
|
||||
type DashboardCell struct {
|
||||
X int32 `protobuf:"varint,1,opt,name=x,proto3" json:"x,omitempty"`
|
||||
Y int32 `protobuf:"varint,2,opt,name=y,proto3" json:"y,omitempty"`
|
||||
W int32 `protobuf:"varint,3,opt,name=w,proto3" json:"w,omitempty"`
|
||||
H int32 `protobuf:"varint,4,opt,name=h,proto3" json:"h,omitempty"`
|
||||
Queries []*Query `protobuf:"bytes,5,rep,name=queries" json:"queries,omitempty"`
|
||||
Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Type string `protobuf:"bytes,7,opt,name=type,proto3" json:"type,omitempty"`
|
||||
ID string `protobuf:"bytes,8,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||
Axes map[string]*Axis `protobuf:"bytes,9,rep,name=axes" json:"axes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"`
|
||||
Colors []*Color `protobuf:"bytes,10,rep,name=colors" json:"colors,omitempty"`
|
||||
Legend *Legend `protobuf:"bytes,11,opt,name=legend" json:"legend,omitempty"`
|
||||
TableOptions *TableOptions `protobuf:"bytes,12,opt,name=tableOptions" json:"tableOptions,omitempty"`
|
||||
X int32 `protobuf:"varint,1,opt,name=x,proto3" json:"x,omitempty"`
|
||||
Y int32 `protobuf:"varint,2,opt,name=y,proto3" json:"y,omitempty"`
|
||||
W int32 `protobuf:"varint,3,opt,name=w,proto3" json:"w,omitempty"`
|
||||
H int32 `protobuf:"varint,4,opt,name=h,proto3" json:"h,omitempty"`
|
||||
Queries []*Query `protobuf:"bytes,5,rep,name=queries" json:"queries,omitempty"`
|
||||
Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Type string `protobuf:"bytes,7,opt,name=type,proto3" json:"type,omitempty"`
|
||||
ID string `protobuf:"bytes,8,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||
Axes map[string]*Axis `protobuf:"bytes,9,rep,name=axes" json:"axes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"`
|
||||
Colors []*Color `protobuf:"bytes,10,rep,name=colors" json:"colors,omitempty"`
|
||||
Legend *Legend `protobuf:"bytes,11,opt,name=legend" json:"legend,omitempty"`
|
||||
TableOptions *TableOptions `protobuf:"bytes,12,opt,name=tableOptions" json:"tableOptions,omitempty"`
|
||||
FieldOptions []*RenamableField `protobuf:"bytes,13,rep,name=fieldOptions" json:"fieldOptions,omitempty"`
|
||||
TimeFormat string `protobuf:"bytes,14,opt,name=timeFormat,proto3" json:"timeFormat,omitempty"`
|
||||
DecimalPlaces *DecimalPlaces `protobuf:"bytes,15,opt,name=decimalPlaces" json:"decimalPlaces,omitempty"`
|
||||
}
|
||||
|
||||
func (m *DashboardCell) Reset() { *m = DashboardCell{} }
|
||||
|
@ -323,27 +327,63 @@ func (m *DashboardCell) GetTableOptions() *TableOptions {
|
|||
return nil
|
||||
}
|
||||
|
||||
type TableOptions struct {
|
||||
TimeFormat string `protobuf:"bytes,1,opt,name=timeFormat,proto3" json:"timeFormat,omitempty"`
|
||||
VerticalTimeAxis bool `protobuf:"varint,2,opt,name=verticalTimeAxis,proto3" json:"verticalTimeAxis,omitempty"`
|
||||
SortBy *RenamableField `protobuf:"bytes,3,opt,name=sortBy" json:"sortBy,omitempty"`
|
||||
Wrapping string `protobuf:"bytes,4,opt,name=wrapping,proto3" json:"wrapping,omitempty"`
|
||||
FieldNames []*RenamableField `protobuf:"bytes,5,rep,name=fieldNames" json:"fieldNames,omitempty"`
|
||||
FixFirstColumn bool `protobuf:"varint,6,opt,name=fixFirstColumn,proto3" json:"fixFirstColumn,omitempty"`
|
||||
func (m *DashboardCell) GetFieldOptions() []*RenamableField {
|
||||
if m != nil {
|
||||
return m.FieldOptions
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *TableOptions) Reset() { *m = TableOptions{} }
|
||||
func (m *TableOptions) String() string { return proto.CompactTextString(m) }
|
||||
func (*TableOptions) ProtoMessage() {}
|
||||
func (*TableOptions) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{3} }
|
||||
|
||||
func (m *TableOptions) GetTimeFormat() string {
|
||||
func (m *DashboardCell) GetTimeFormat() string {
|
||||
if m != nil {
|
||||
return m.TimeFormat
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *DashboardCell) GetDecimalPlaces() *DecimalPlaces {
|
||||
if m != nil {
|
||||
return m.DecimalPlaces
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DecimalPlaces struct {
|
||||
IsEnforced bool `protobuf:"varint,1,opt,name=isEnforced,proto3" json:"isEnforced,omitempty"`
|
||||
Digits int32 `protobuf:"varint,2,opt,name=digits,proto3" json:"digits,omitempty"`
|
||||
}
|
||||
|
||||
func (m *DecimalPlaces) Reset() { *m = DecimalPlaces{} }
|
||||
func (m *DecimalPlaces) String() string { return proto.CompactTextString(m) }
|
||||
func (*DecimalPlaces) ProtoMessage() {}
|
||||
func (*DecimalPlaces) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{3} }
|
||||
|
||||
func (m *DecimalPlaces) GetIsEnforced() bool {
|
||||
if m != nil {
|
||||
return m.IsEnforced
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *DecimalPlaces) GetDigits() int32 {
|
||||
if m != nil {
|
||||
return m.Digits
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type TableOptions struct {
|
||||
VerticalTimeAxis bool `protobuf:"varint,2,opt,name=verticalTimeAxis,proto3" json:"verticalTimeAxis,omitempty"`
|
||||
SortBy *RenamableField `protobuf:"bytes,3,opt,name=sortBy" json:"sortBy,omitempty"`
|
||||
Wrapping string `protobuf:"bytes,4,opt,name=wrapping,proto3" json:"wrapping,omitempty"`
|
||||
FixFirstColumn bool `protobuf:"varint,6,opt,name=fixFirstColumn,proto3" json:"fixFirstColumn,omitempty"`
|
||||
}
|
||||
|
||||
func (m *TableOptions) Reset() { *m = TableOptions{} }
|
||||
func (m *TableOptions) String() string { return proto.CompactTextString(m) }
|
||||
func (*TableOptions) ProtoMessage() {}
|
||||
func (*TableOptions) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{4} }
|
||||
|
||||
func (m *TableOptions) GetVerticalTimeAxis() bool {
|
||||
if m != nil {
|
||||
return m.VerticalTimeAxis
|
||||
|
@ -365,13 +405,6 @@ func (m *TableOptions) GetWrapping() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (m *TableOptions) GetFieldNames() []*RenamableField {
|
||||
if m != nil {
|
||||
return m.FieldNames
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *TableOptions) GetFixFirstColumn() bool {
|
||||
if m != nil {
|
||||
return m.FixFirstColumn
|
||||
|
@ -388,7 +421,7 @@ type RenamableField struct {
|
|||
func (m *RenamableField) Reset() { *m = RenamableField{} }
|
||||
func (m *RenamableField) String() string { return proto.CompactTextString(m) }
|
||||
func (*RenamableField) ProtoMessage() {}
|
||||
func (*RenamableField) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{4} }
|
||||
func (*RenamableField) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{5} }
|
||||
|
||||
func (m *RenamableField) GetInternalName() string {
|
||||
if m != nil {
|
||||
|
@ -422,7 +455,7 @@ type Color struct {
|
|||
func (m *Color) Reset() { *m = Color{} }
|
||||
func (m *Color) String() string { return proto.CompactTextString(m) }
|
||||
func (*Color) ProtoMessage() {}
|
||||
func (*Color) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{5} }
|
||||
func (*Color) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{6} }
|
||||
|
||||
func (m *Color) GetID() string {
|
||||
if m != nil {
|
||||
|
@ -467,7 +500,7 @@ type Legend struct {
|
|||
func (m *Legend) Reset() { *m = Legend{} }
|
||||
func (m *Legend) String() string { return proto.CompactTextString(m) }
|
||||
func (*Legend) ProtoMessage() {}
|
||||
func (*Legend) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{6} }
|
||||
func (*Legend) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{7} }
|
||||
|
||||
func (m *Legend) GetType() string {
|
||||
if m != nil {
|
||||
|
@ -496,7 +529,7 @@ type Axis struct {
|
|||
func (m *Axis) Reset() { *m = Axis{} }
|
||||
func (m *Axis) String() string { return proto.CompactTextString(m) }
|
||||
func (*Axis) ProtoMessage() {}
|
||||
func (*Axis) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{7} }
|
||||
func (*Axis) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{8} }
|
||||
|
||||
func (m *Axis) GetLegacyBounds() []int64 {
|
||||
if m != nil {
|
||||
|
@ -559,7 +592,7 @@ type Template struct {
|
|||
func (m *Template) Reset() { *m = Template{} }
|
||||
func (m *Template) String() string { return proto.CompactTextString(m) }
|
||||
func (*Template) ProtoMessage() {}
|
||||
func (*Template) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{8} }
|
||||
func (*Template) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{9} }
|
||||
|
||||
func (m *Template) GetID() string {
|
||||
if m != nil {
|
||||
|
@ -612,7 +645,7 @@ type TemplateValue struct {
|
|||
func (m *TemplateValue) Reset() { *m = TemplateValue{} }
|
||||
func (m *TemplateValue) String() string { return proto.CompactTextString(m) }
|
||||
func (*TemplateValue) ProtoMessage() {}
|
||||
func (*TemplateValue) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{9} }
|
||||
func (*TemplateValue) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{10} }
|
||||
|
||||
func (m *TemplateValue) GetType() string {
|
||||
if m != nil {
|
||||
|
@ -647,7 +680,7 @@ type TemplateQuery struct {
|
|||
func (m *TemplateQuery) Reset() { *m = TemplateQuery{} }
|
||||
func (m *TemplateQuery) String() string { return proto.CompactTextString(m) }
|
||||
func (*TemplateQuery) ProtoMessage() {}
|
||||
func (*TemplateQuery) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{10} }
|
||||
func (*TemplateQuery) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{11} }
|
||||
|
||||
func (m *TemplateQuery) GetCommand() string {
|
||||
if m != nil {
|
||||
|
@ -706,7 +739,7 @@ type Server struct {
|
|||
func (m *Server) Reset() { *m = Server{} }
|
||||
func (m *Server) String() string { return proto.CompactTextString(m) }
|
||||
func (*Server) ProtoMessage() {}
|
||||
func (*Server) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{11} }
|
||||
func (*Server) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{12} }
|
||||
|
||||
func (m *Server) GetID() int64 {
|
||||
if m != nil {
|
||||
|
@ -782,7 +815,7 @@ type Layout struct {
|
|||
func (m *Layout) Reset() { *m = Layout{} }
|
||||
func (m *Layout) String() string { return proto.CompactTextString(m) }
|
||||
func (*Layout) ProtoMessage() {}
|
||||
func (*Layout) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{12} }
|
||||
func (*Layout) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{13} }
|
||||
|
||||
func (m *Layout) GetID() string {
|
||||
if m != nil {
|
||||
|
@ -836,7 +869,7 @@ type Cell struct {
|
|||
func (m *Cell) Reset() { *m = Cell{} }
|
||||
func (m *Cell) String() string { return proto.CompactTextString(m) }
|
||||
func (*Cell) ProtoMessage() {}
|
||||
func (*Cell) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{13} }
|
||||
func (*Cell) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{14} }
|
||||
|
||||
func (m *Cell) GetX() int32 {
|
||||
if m != nil {
|
||||
|
@ -930,7 +963,7 @@ type Query struct {
|
|||
func (m *Query) Reset() { *m = Query{} }
|
||||
func (m *Query) String() string { return proto.CompactTextString(m) }
|
||||
func (*Query) ProtoMessage() {}
|
||||
func (*Query) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{14} }
|
||||
func (*Query) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{15} }
|
||||
|
||||
func (m *Query) GetCommand() string {
|
||||
if m != nil {
|
||||
|
@ -1004,7 +1037,7 @@ type TimeShift struct {
|
|||
func (m *TimeShift) Reset() { *m = TimeShift{} }
|
||||
func (m *TimeShift) String() string { return proto.CompactTextString(m) }
|
||||
func (*TimeShift) ProtoMessage() {}
|
||||
func (*TimeShift) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{15} }
|
||||
func (*TimeShift) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{16} }
|
||||
|
||||
func (m *TimeShift) GetLabel() string {
|
||||
if m != nil {
|
||||
|
@ -1035,7 +1068,7 @@ type Range struct {
|
|||
func (m *Range) Reset() { *m = Range{} }
|
||||
func (m *Range) String() string { return proto.CompactTextString(m) }
|
||||
func (*Range) ProtoMessage() {}
|
||||
func (*Range) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{16} }
|
||||
func (*Range) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{17} }
|
||||
|
||||
func (m *Range) GetUpper() int64 {
|
||||
if m != nil {
|
||||
|
@ -1061,7 +1094,7 @@ type AlertRule struct {
|
|||
func (m *AlertRule) Reset() { *m = AlertRule{} }
|
||||
func (m *AlertRule) String() string { return proto.CompactTextString(m) }
|
||||
func (*AlertRule) ProtoMessage() {}
|
||||
func (*AlertRule) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{17} }
|
||||
func (*AlertRule) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{18} }
|
||||
|
||||
func (m *AlertRule) GetID() string {
|
||||
if m != nil {
|
||||
|
@ -1103,7 +1136,7 @@ type User struct {
|
|||
func (m *User) Reset() { *m = User{} }
|
||||
func (m *User) String() string { return proto.CompactTextString(m) }
|
||||
func (*User) ProtoMessage() {}
|
||||
func (*User) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{18} }
|
||||
func (*User) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{19} }
|
||||
|
||||
func (m *User) GetID() uint64 {
|
||||
if m != nil {
|
||||
|
@ -1155,7 +1188,7 @@ type Role struct {
|
|||
func (m *Role) Reset() { *m = Role{} }
|
||||
func (m *Role) String() string { return proto.CompactTextString(m) }
|
||||
func (*Role) ProtoMessage() {}
|
||||
func (*Role) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{19} }
|
||||
func (*Role) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{20} }
|
||||
|
||||
func (m *Role) GetOrganization() string {
|
||||
if m != nil {
|
||||
|
@ -1182,7 +1215,7 @@ type Mapping struct {
|
|||
func (m *Mapping) Reset() { *m = Mapping{} }
|
||||
func (m *Mapping) String() string { return proto.CompactTextString(m) }
|
||||
func (*Mapping) ProtoMessage() {}
|
||||
func (*Mapping) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{20} }
|
||||
func (*Mapping) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{21} }
|
||||
|
||||
func (m *Mapping) GetProvider() string {
|
||||
if m != nil {
|
||||
|
@ -1228,7 +1261,7 @@ type Organization struct {
|
|||
func (m *Organization) Reset() { *m = Organization{} }
|
||||
func (m *Organization) String() string { return proto.CompactTextString(m) }
|
||||
func (*Organization) ProtoMessage() {}
|
||||
func (*Organization) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{21} }
|
||||
func (*Organization) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{22} }
|
||||
|
||||
func (m *Organization) GetID() string {
|
||||
if m != nil {
|
||||
|
@ -1258,7 +1291,7 @@ type Config struct {
|
|||
func (m *Config) Reset() { *m = Config{} }
|
||||
func (m *Config) String() string { return proto.CompactTextString(m) }
|
||||
func (*Config) ProtoMessage() {}
|
||||
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{22} }
|
||||
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{23} }
|
||||
|
||||
func (m *Config) GetAuth() *AuthConfig {
|
||||
if m != nil {
|
||||
|
@ -1274,7 +1307,7 @@ type AuthConfig struct {
|
|||
func (m *AuthConfig) Reset() { *m = AuthConfig{} }
|
||||
func (m *AuthConfig) String() string { return proto.CompactTextString(m) }
|
||||
func (*AuthConfig) ProtoMessage() {}
|
||||
func (*AuthConfig) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{23} }
|
||||
func (*AuthConfig) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{24} }
|
||||
|
||||
func (m *AuthConfig) GetSuperAdminNewUsers() bool {
|
||||
if m != nil {
|
||||
|
@ -1291,7 +1324,7 @@ type BuildInfo struct {
|
|||
func (m *BuildInfo) Reset() { *m = BuildInfo{} }
|
||||
func (m *BuildInfo) String() string { return proto.CompactTextString(m) }
|
||||
func (*BuildInfo) ProtoMessage() {}
|
||||
func (*BuildInfo) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{24} }
|
||||
func (*BuildInfo) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{25} }
|
||||
|
||||
func (m *BuildInfo) GetVersion() string {
|
||||
if m != nil {
|
||||
|
@ -1311,6 +1344,7 @@ func init() {
|
|||
proto.RegisterType((*Source)(nil), "internal.Source")
|
||||
proto.RegisterType((*Dashboard)(nil), "internal.Dashboard")
|
||||
proto.RegisterType((*DashboardCell)(nil), "internal.DashboardCell")
|
||||
proto.RegisterType((*DecimalPlaces)(nil), "internal.DecimalPlaces")
|
||||
proto.RegisterType((*TableOptions)(nil), "internal.TableOptions")
|
||||
proto.RegisterType((*RenamableField)(nil), "internal.RenamableField")
|
||||
proto.RegisterType((*Color)(nil), "internal.Color")
|
||||
|
@ -1338,105 +1372,110 @@ func init() {
|
|||
func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) }
|
||||
|
||||
var fileDescriptorInternal = []byte{
|
||||
// 1599 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xcd, 0x6f, 0xdb, 0xc8,
|
||||
0x15, 0x07, 0x45, 0x51, 0x12, 0x9f, 0x1c, 0xd7, 0x98, 0x1a, 0x09, 0x9b, 0x16, 0x85, 0x4a, 0xf4,
|
||||
0x43, 0xfd, 0x88, 0x1b, 0x28, 0x28, 0x10, 0x04, 0x6d, 0x00, 0xd9, 0x6a, 0x52, 0x37, 0x4e, 0xec,
|
||||
0x8c, 0x6c, 0xf7, 0x54, 0x04, 0x23, 0x69, 0x24, 0x11, 0xa1, 0x48, 0x76, 0x48, 0xda, 0x62, 0xcf,
|
||||
0x3d, 0xf5, 0x8f, 0x28, 0x50, 0xa0, 0xfd, 0x07, 0x8a, 0x5e, 0xf6, 0xb4, 0xf7, 0xfd, 0x87, 0x76,
|
||||
0x8f, 0x8b, 0x37, 0x1f, 0x24, 0x65, 0x29, 0x41, 0x16, 0x58, 0xec, 0x6d, 0x7e, 0xef, 0x3d, 0xbd,
|
||||
0x99, 0xf7, 0xfd, 0x28, 0xd8, 0x0f, 0xa2, 0x8c, 0x8b, 0x88, 0x85, 0x47, 0x89, 0x88, 0xb3, 0x98,
|
||||
0x74, 0x0c, 0xf6, 0xff, 0x61, 0x43, 0x6b, 0x1c, 0xe7, 0x62, 0xca, 0xc9, 0x3e, 0x34, 0x4e, 0x47,
|
||||
0x9e, 0xd5, 0xb3, 0xfa, 0x36, 0x6d, 0x9c, 0x8e, 0x08, 0x81, 0xe6, 0x1b, 0xb6, 0xe2, 0x5e, 0xa3,
|
||||
0x67, 0xf5, 0x5d, 0x2a, 0xcf, 0x48, 0xbb, 0x2c, 0x12, 0xee, 0xd9, 0x8a, 0x86, 0x67, 0xf2, 0x10,
|
||||
0x3a, 0x57, 0x29, 0x6a, 0x5b, 0x71, 0xaf, 0x29, 0xe9, 0x25, 0x46, 0xde, 0x05, 0x4b, 0xd3, 0xdb,
|
||||
0x58, 0xcc, 0x3c, 0x47, 0xf1, 0x0c, 0x26, 0x07, 0x60, 0x5f, 0xd1, 0x33, 0xaf, 0x25, 0xc9, 0x78,
|
||||
0x24, 0x1e, 0xb4, 0x47, 0x7c, 0xce, 0xf2, 0x30, 0xf3, 0xda, 0x3d, 0xab, 0xdf, 0xa1, 0x06, 0xa2,
|
||||
0x9e, 0x4b, 0x1e, 0xf2, 0x85, 0x60, 0x73, 0xaf, 0xa3, 0xf4, 0x18, 0x4c, 0x8e, 0x80, 0x9c, 0x46,
|
||||
0x29, 0x9f, 0xe6, 0x82, 0x8f, 0xdf, 0x07, 0xc9, 0x35, 0x17, 0xc1, 0xbc, 0xf0, 0x5c, 0xa9, 0x60,
|
||||
0x07, 0x07, 0x6f, 0x79, 0xcd, 0x33, 0x86, 0x77, 0x83, 0x54, 0x65, 0x20, 0xf1, 0x61, 0x6f, 0xbc,
|
||||
0x64, 0x82, 0xcf, 0xc6, 0x7c, 0x2a, 0x78, 0xe6, 0x75, 0x25, 0x7b, 0x83, 0x86, 0x32, 0xe7, 0x62,
|
||||
0xc1, 0xa2, 0xe0, 0xef, 0x2c, 0x0b, 0xe2, 0xc8, 0xdb, 0x53, 0x32, 0x75, 0x1a, 0x7a, 0x89, 0xc6,
|
||||
0x21, 0xf7, 0xee, 0x29, 0x2f, 0xe1, 0x99, 0xfc, 0x08, 0x5c, 0x6d, 0x0c, 0xbd, 0xf0, 0xf6, 0x25,
|
||||
0xa3, 0x22, 0xf8, 0xff, 0xb7, 0xc0, 0x1d, 0xb1, 0x74, 0x39, 0x89, 0x99, 0x98, 0x7d, 0x52, 0x24,
|
||||
0x1e, 0x81, 0x33, 0xe5, 0x61, 0x98, 0x7a, 0x76, 0xcf, 0xee, 0x77, 0x07, 0x0f, 0x8e, 0xca, 0x10,
|
||||
0x97, 0x7a, 0x4e, 0x78, 0x18, 0x52, 0x25, 0x45, 0x1e, 0x83, 0x9b, 0xf1, 0x55, 0x12, 0xb2, 0x8c,
|
||||
0xa7, 0x5e, 0x53, 0xfe, 0x84, 0x54, 0x3f, 0xb9, 0xd4, 0x2c, 0x5a, 0x09, 0x6d, 0x19, 0xea, 0x6c,
|
||||
0x1b, 0xea, 0x7f, 0x66, 0xc3, 0xbd, 0x8d, 0xeb, 0xc8, 0x1e, 0x58, 0x6b, 0xf9, 0x72, 0x87, 0x5a,
|
||||
0x6b, 0x44, 0x85, 0x7c, 0xb5, 0x43, 0xad, 0x02, 0xd1, 0xad, 0xcc, 0x1c, 0x87, 0x5a, 0xb7, 0x88,
|
||||
0x96, 0x32, 0x5f, 0x1c, 0x6a, 0x2d, 0xc9, 0x2f, 0xa1, 0xfd, 0xb7, 0x9c, 0x8b, 0x80, 0xa7, 0x9e,
|
||||
0x23, 0x5f, 0xf7, 0xbd, 0xea, 0x75, 0x6f, 0x73, 0x2e, 0x0a, 0x6a, 0xf8, 0xe8, 0x0d, 0x99, 0x6b,
|
||||
0x2a, 0x71, 0xe4, 0x19, 0x69, 0x19, 0xe6, 0x65, 0x5b, 0xd1, 0xf0, 0xac, 0xbd, 0xa8, 0xb2, 0x05,
|
||||
0xbd, 0xf8, 0x3b, 0x68, 0xb2, 0x35, 0x4f, 0x3d, 0x57, 0xea, 0xff, 0xc9, 0x07, 0x1c, 0x76, 0x34,
|
||||
0x5c, 0xf3, 0xf4, 0x8f, 0x51, 0x26, 0x0a, 0x2a, 0xc5, 0xc9, 0x2f, 0xa0, 0x35, 0x8d, 0xc3, 0x58,
|
||||
0xa4, 0x1e, 0xdc, 0x7d, 0xd8, 0x09, 0xd2, 0xa9, 0x66, 0x93, 0x3e, 0xb4, 0x42, 0xbe, 0xe0, 0xd1,
|
||||
0x4c, 0xe6, 0x4d, 0x77, 0x70, 0x50, 0x09, 0x9e, 0x49, 0x3a, 0xd5, 0x7c, 0xf2, 0x0c, 0xf6, 0x32,
|
||||
0x36, 0x09, 0xf9, 0x79, 0x82, 0x5e, 0x4c, 0x65, 0x0e, 0x75, 0x07, 0xf7, 0x6b, 0xf1, 0xa8, 0x71,
|
||||
0xe9, 0x86, 0xec, 0xc3, 0x97, 0xe0, 0x96, 0x2f, 0xc4, 0x12, 0x7a, 0xcf, 0x0b, 0xe9, 0x6f, 0x97,
|
||||
0xe2, 0x91, 0xfc, 0x14, 0x9c, 0x1b, 0x16, 0xe6, 0x2a, 0x57, 0xba, 0x83, 0xfd, 0x4a, 0xe7, 0x70,
|
||||
0x1d, 0xa4, 0x54, 0x31, 0x9f, 0x35, 0x9e, 0x5a, 0xfe, 0x3f, 0x1b, 0xb0, 0x57, 0xbf, 0x87, 0xfc,
|
||||
0x18, 0x20, 0x0b, 0x56, 0xfc, 0x45, 0x2c, 0x56, 0x2c, 0xd3, 0x3a, 0x6b, 0x14, 0xf2, 0x2b, 0x38,
|
||||
0xb8, 0xe1, 0x22, 0x0b, 0xa6, 0x2c, 0xbc, 0x0c, 0x56, 0x1c, 0xf5, 0xc9, 0x5b, 0x3a, 0x74, 0x8b,
|
||||
0x4e, 0x1e, 0x43, 0x2b, 0x8d, 0x45, 0x76, 0x5c, 0xc8, 0x78, 0x77, 0x07, 0x5e, 0xf5, 0x0e, 0xca,
|
||||
0x23, 0xb6, 0xc2, 0x7b, 0x5f, 0x04, 0x3c, 0x9c, 0x51, 0x2d, 0x87, 0x15, 0x7e, 0x2b, 0x58, 0x92,
|
||||
0x04, 0xd1, 0xc2, 0x74, 0x11, 0x83, 0xc9, 0x53, 0x80, 0x39, 0x0a, 0x63, 0xe2, 0x9b, 0xfc, 0xf8,
|
||||
0xb0, 0xc6, 0x9a, 0x2c, 0xf9, 0x39, 0xec, 0xcf, 0x83, 0xf5, 0x8b, 0x40, 0xa4, 0xd9, 0x49, 0x1c,
|
||||
0xe6, 0xab, 0x48, 0x66, 0x4d, 0x87, 0xde, 0xa1, 0xfa, 0x09, 0xec, 0x6f, 0x6a, 0xc1, 0xf4, 0x37,
|
||||
0x17, 0xc8, 0xda, 0x53, 0xfe, 0xd8, 0xa0, 0x91, 0x1e, 0x74, 0x67, 0x41, 0x9a, 0x84, 0xac, 0xa8,
|
||||
0x95, 0x67, 0x9d, 0x84, 0xbd, 0xe6, 0x26, 0x48, 0x83, 0x49, 0xa8, 0x5a, 0x66, 0x87, 0x1a, 0xe8,
|
||||
0x2f, 0xc0, 0x91, 0xe9, 0x53, 0x2b, 0x76, 0xd7, 0x14, 0xbb, 0x6c, 0xb1, 0x8d, 0x5a, 0x8b, 0x3d,
|
||||
0x00, 0xfb, 0x4f, 0x7c, 0xad, 0xbb, 0x2e, 0x1e, 0xcb, 0x96, 0xd0, 0xac, 0xb5, 0x84, 0x43, 0x70,
|
||||
0xae, 0x65, 0xec, 0x55, 0xa9, 0x2a, 0xe0, 0x3f, 0x87, 0x96, 0x4a, 0xbf, 0x52, 0xb3, 0x55, 0xd3,
|
||||
0xdc, 0x83, 0xee, 0xb9, 0x08, 0x78, 0x94, 0xa9, 0x22, 0xd7, 0x26, 0xd4, 0x48, 0xfe, 0xff, 0x2c,
|
||||
0x68, 0xca, 0x98, 0xfa, 0xb0, 0x17, 0xf2, 0x05, 0x9b, 0x16, 0xc7, 0x71, 0x1e, 0xcd, 0x52, 0xcf,
|
||||
0xea, 0xd9, 0x7d, 0x9b, 0x6e, 0xd0, 0xc8, 0x7d, 0x68, 0x4d, 0x14, 0xb7, 0xd1, 0xb3, 0xfb, 0x2e,
|
||||
0xd5, 0x08, 0x9f, 0x16, 0xb2, 0x09, 0x0f, 0xb5, 0x09, 0x0a, 0xa0, 0x74, 0x22, 0xf8, 0x3c, 0x58,
|
||||
0x6b, 0x33, 0x34, 0x42, 0x7a, 0x9a, 0xcf, 0x91, 0xae, 0x2c, 0xd1, 0x08, 0x0d, 0x98, 0xb0, 0xb4,
|
||||
0xac, 0x7c, 0x3c, 0xa3, 0xe6, 0x74, 0xca, 0x42, 0x53, 0xfa, 0x0a, 0xf8, 0x9f, 0x5b, 0x38, 0x30,
|
||||
0x54, 0x2b, 0xdb, 0xf2, 0xf0, 0x0f, 0xa0, 0x83, 0x6d, 0xee, 0xdd, 0x0d, 0x13, 0xda, 0xe0, 0x36,
|
||||
0xe2, 0x6b, 0x26, 0xc8, 0x6f, 0xa1, 0x25, 0x2b, 0x64, 0x47, 0x5b, 0x35, 0xea, 0xa4, 0x57, 0xa9,
|
||||
0x16, 0x2b, 0x1b, 0x4f, 0xb3, 0xd6, 0x78, 0x4a, 0x63, 0x9d, 0xba, 0xb1, 0x8f, 0xc0, 0xc1, 0x0e,
|
||||
0x56, 0xc8, 0xd7, 0xef, 0xd4, 0xac, 0xfa, 0x9c, 0x92, 0xf2, 0xaf, 0xe0, 0xde, 0xc6, 0x8d, 0xe5,
|
||||
0x4d, 0xd6, 0xe6, 0x4d, 0x55, 0xb5, 0xbb, 0xba, 0xba, 0xb1, 0x94, 0x52, 0x1e, 0xf2, 0x69, 0xc6,
|
||||
0x67, 0x3a, 0xeb, 0x4a, 0xec, 0xff, 0xdb, 0xaa, 0xf4, 0xca, 0xfb, 0x30, 0x45, 0xa7, 0xf1, 0x6a,
|
||||
0xc5, 0xa2, 0x99, 0x56, 0x6d, 0x20, 0xfa, 0x6d, 0x36, 0xd1, 0xaa, 0x1b, 0xb3, 0x09, 0x62, 0x91,
|
||||
0xe8, 0x08, 0x36, 0x44, 0x82, 0xb9, 0xb3, 0xe2, 0x2c, 0xcd, 0x05, 0x5f, 0xf1, 0x28, 0xd3, 0x2e,
|
||||
0xa8, 0x93, 0xc8, 0x03, 0x68, 0x67, 0x6c, 0xf1, 0x0e, 0x7b, 0x94, 0x8e, 0x64, 0xc6, 0x16, 0xaf,
|
||||
0x78, 0x41, 0x7e, 0x08, 0xae, 0xac, 0x52, 0xc9, 0x52, 0xe1, 0xec, 0x48, 0xc2, 0x2b, 0x5e, 0xf8,
|
||||
0x5f, 0x59, 0xd0, 0x1a, 0x73, 0x71, 0xc3, 0xc5, 0x27, 0x4d, 0xc2, 0xfa, 0xfe, 0x61, 0x7f, 0x64,
|
||||
0xff, 0x68, 0xee, 0xde, 0x3f, 0x9c, 0x6a, 0xff, 0x38, 0x04, 0x67, 0x2c, 0xa6, 0xa7, 0x23, 0xf9,
|
||||
0x22, 0x9b, 0x2a, 0x80, 0xd9, 0x38, 0x9c, 0x66, 0xc1, 0x0d, 0xd7, 0x4b, 0x89, 0x46, 0x5b, 0x03,
|
||||
0xb2, 0xb3, 0x63, 0x13, 0xf8, 0x86, 0xbb, 0x89, 0xff, 0x2f, 0x0b, 0x5a, 0x67, 0xac, 0x88, 0xf3,
|
||||
0x6c, 0x2b, 0x6b, 0x7b, 0xd0, 0x1d, 0x26, 0x49, 0x18, 0x4c, 0x37, 0x2a, 0xb5, 0x46, 0x42, 0x89,
|
||||
0xd7, 0xb5, 0x78, 0x28, 0x5f, 0xd4, 0x49, 0x38, 0x1d, 0x4e, 0xe4, 0xd2, 0xa0, 0x36, 0x80, 0xda,
|
||||
0x74, 0x50, 0xbb, 0x82, 0x64, 0xa2, 0xd3, 0x86, 0x79, 0x16, 0xcf, 0xc3, 0xf8, 0x56, 0x7a, 0xa7,
|
||||
0x43, 0x4b, 0xec, 0x7f, 0xd1, 0x80, 0xe6, 0x77, 0x35, 0xe8, 0xf7, 0xc0, 0x0a, 0x74, 0x72, 0x58,
|
||||
0x41, 0x39, 0xf6, 0xdb, 0xb5, 0xb1, 0xef, 0x41, 0xbb, 0x10, 0x2c, 0x5a, 0xf0, 0xd4, 0xeb, 0xc8,
|
||||
0x6e, 0x64, 0xa0, 0xe4, 0xc8, 0xba, 0x53, 0xf3, 0xde, 0xa5, 0x06, 0x96, 0x75, 0x04, 0xb5, 0x3a,
|
||||
0xfa, 0x8d, 0x5e, 0x0d, 0xba, 0x77, 0x47, 0xcb, 0xae, 0x8d, 0xe0, 0xdb, 0x1b, 0xc1, 0x5f, 0x5a,
|
||||
0xe0, 0x94, 0x45, 0x78, 0xb2, 0x59, 0x84, 0x27, 0x55, 0x11, 0x8e, 0x8e, 0x4d, 0x11, 0x8e, 0x8e,
|
||||
0x11, 0xd3, 0x0b, 0x53, 0x84, 0xf4, 0x02, 0x83, 0xf5, 0x52, 0xc4, 0x79, 0x72, 0x5c, 0xa8, 0xa8,
|
||||
0xba, 0xb4, 0xc4, 0x98, 0xb9, 0x7f, 0x59, 0x72, 0xa1, 0x5d, 0xed, 0x52, 0x8d, 0x30, 0xcf, 0xcf,
|
||||
0x64, 0x83, 0x52, 0xce, 0x55, 0x80, 0xfc, 0x0c, 0x1c, 0x8a, 0xce, 0x93, 0x1e, 0xde, 0x88, 0x8b,
|
||||
0x24, 0x53, 0xc5, 0x45, 0xa5, 0xea, 0x83, 0x41, 0x27, 0xbc, 0xf9, 0x7c, 0xf8, 0x35, 0xb4, 0xc6,
|
||||
0xcb, 0x60, 0x9e, 0x99, 0x05, 0xeb, 0xfb, 0xb5, 0x06, 0x17, 0xac, 0xb8, 0xe4, 0x51, 0x2d, 0xe2,
|
||||
0xbf, 0x05, 0xb7, 0x24, 0x56, 0xcf, 0xb1, 0xea, 0xcf, 0x21, 0xd0, 0xbc, 0x8a, 0x82, 0xcc, 0x94,
|
||||
0x3a, 0x9e, 0xd1, 0xd8, 0xb7, 0x39, 0x8b, 0xb2, 0x20, 0x2b, 0x4c, 0xa9, 0x1b, 0xec, 0x3f, 0xd1,
|
||||
0xcf, 0x47, 0x75, 0x57, 0x49, 0xc2, 0x85, 0x6e, 0x1b, 0x0a, 0xc8, 0x4b, 0xe2, 0x5b, 0xae, 0x3a,
|
||||
0xbe, 0x4d, 0x15, 0xf0, 0xff, 0x0a, 0xee, 0x30, 0xe4, 0x22, 0xa3, 0x79, 0xc8, 0x77, 0x4d, 0xe2,
|
||||
0x3f, 0x8f, 0xcf, 0xdf, 0x98, 0x17, 0xe0, 0xb9, 0x6a, 0x11, 0xf6, 0x9d, 0x16, 0xf1, 0x8a, 0x25,
|
||||
0xec, 0x74, 0x24, 0xf3, 0xdc, 0xa6, 0x1a, 0xf9, 0xff, 0xb1, 0xa0, 0x89, 0xbd, 0xa8, 0xa6, 0xba,
|
||||
0xf9, 0xb1, 0x3e, 0x76, 0x21, 0xe2, 0x9b, 0x60, 0xc6, 0x85, 0x31, 0xce, 0x60, 0xe9, 0xf4, 0xe9,
|
||||
0x92, 0x97, 0x03, 0x5f, 0x23, 0xcc, 0x35, 0xfc, 0xba, 0x30, 0xb5, 0x54, 0xcb, 0x35, 0x24, 0x53,
|
||||
0xc5, 0xc4, 0xcd, 0x6e, 0x9c, 0x27, 0x5c, 0x0c, 0x67, 0xab, 0xc0, 0x6c, 0x40, 0x35, 0x8a, 0xff,
|
||||
0x5c, 0x7d, 0xaf, 0x6c, 0x75, 0x34, 0x6b, 0xf7, 0xb7, 0xcd, 0xdd, 0x97, 0xfb, 0xff, 0xb5, 0xa0,
|
||||
0xfd, 0x5a, 0xef, 0x6a, 0x75, 0x2b, 0xac, 0x0f, 0x5a, 0xd1, 0xd8, 0xb0, 0x62, 0x00, 0x87, 0x46,
|
||||
0x66, 0xe3, 0x7e, 0xe5, 0x85, 0x9d, 0x3c, 0xed, 0xd1, 0x66, 0x19, 0xac, 0x4f, 0xf9, 0x5c, 0xb9,
|
||||
0xdc, 0x94, 0xd9, 0x15, 0xf0, 0xad, 0xa8, 0xf4, 0xa0, 0x6b, 0x3e, 0xd3, 0xe2, 0xd0, 0x0c, 0x98,
|
||||
0x3a, 0xc9, 0x1f, 0x40, 0xeb, 0x24, 0x8e, 0xe6, 0xc1, 0x82, 0xf4, 0xa1, 0x39, 0xcc, 0xb3, 0xa5,
|
||||
0xd4, 0xd8, 0x1d, 0x1c, 0xd6, 0x0a, 0x3f, 0xcf, 0x96, 0x4a, 0x86, 0x4a, 0x09, 0xff, 0xf7, 0x00,
|
||||
0x15, 0x0d, 0xa7, 0x44, 0x15, 0x8d, 0x37, 0xfc, 0x16, 0x53, 0x26, 0x95, 0x5a, 0x3a, 0x74, 0x07,
|
||||
0xc7, 0xff, 0x03, 0xb8, 0xc7, 0x79, 0x10, 0xce, 0x4e, 0xa3, 0x79, 0x8c, 0xad, 0xe3, 0x9a, 0x8b,
|
||||
0xb4, 0x8a, 0x97, 0x81, 0xe8, 0x6e, 0xec, 0x22, 0x65, 0x0d, 0x69, 0x34, 0x69, 0xc9, 0x3f, 0x01,
|
||||
0x9e, 0x7c, 0x1d, 0x00, 0x00, 0xff, 0xff, 0xb6, 0xb2, 0x98, 0x60, 0x16, 0x10, 0x00, 0x00,
|
||||
// 1667 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x5b, 0x6f, 0xe4, 0x48,
|
||||
0x15, 0x96, 0xbb, 0xed, 0x4e, 0xfb, 0x74, 0x92, 0x8d, 0x8a, 0xd1, 0xae, 0x59, 0x10, 0x6a, 0x2c,
|
||||
0x2e, 0xe1, 0xb2, 0xc3, 0x2a, 0x2b, 0x24, 0xb4, 0xda, 0x5d, 0x29, 0x97, 0x9d, 0x21, 0x73, 0xcd,
|
||||
0x54, 0x27, 0xc3, 0x13, 0x5a, 0x55, 0xdb, 0xd5, 0xdd, 0xa5, 0x75, 0xdb, 0xa6, 0x6c, 0x27, 0x31,
|
||||
0xcf, 0xfc, 0x0e, 0x24, 0x24, 0xf8, 0x03, 0x88, 0x47, 0x24, 0xde, 0xf9, 0x01, 0xfc, 0x15, 0x78,
|
||||
0x44, 0xa7, 0x2e, 0xee, 0x72, 0xd2, 0x33, 0x1a, 0x24, 0xb4, 0x6f, 0xf5, 0x9d, 0x73, 0xfa, 0x54,
|
||||
0xd5, 0xb9, 0x7c, 0x75, 0xdc, 0xb0, 0x2f, 0xf2, 0x9a, 0xcb, 0x9c, 0x65, 0x0f, 0x4b, 0x59, 0xd4,
|
||||
0x05, 0x19, 0x5b, 0x1c, 0xff, 0x61, 0x08, 0xa3, 0x59, 0xd1, 0xc8, 0x84, 0x93, 0x7d, 0x18, 0x9c,
|
||||
0x9f, 0x45, 0xde, 0xd4, 0x3b, 0x1c, 0xd2, 0xc1, 0xf9, 0x19, 0x21, 0xe0, 0xbf, 0x60, 0x6b, 0x1e,
|
||||
0x0d, 0xa6, 0xde, 0x61, 0x48, 0xd5, 0x1a, 0x65, 0x97, 0x6d, 0xc9, 0xa3, 0xa1, 0x96, 0xe1, 0x9a,
|
||||
0x7c, 0x08, 0xe3, 0xab, 0x0a, 0xbd, 0xad, 0x79, 0xe4, 0x2b, 0x79, 0x87, 0x51, 0x77, 0xc1, 0xaa,
|
||||
0xea, 0xa6, 0x90, 0x69, 0x14, 0x68, 0x9d, 0xc5, 0xe4, 0x00, 0x86, 0x57, 0xf4, 0x59, 0x34, 0x52,
|
||||
0x62, 0x5c, 0x92, 0x08, 0x76, 0xce, 0xf8, 0x82, 0x35, 0x59, 0x1d, 0xed, 0x4c, 0xbd, 0xc3, 0x31,
|
||||
0xb5, 0x10, 0xfd, 0x5c, 0xf2, 0x8c, 0x2f, 0x25, 0x5b, 0x44, 0x63, 0xed, 0xc7, 0x62, 0xf2, 0x10,
|
||||
0xc8, 0x79, 0x5e, 0xf1, 0xa4, 0x91, 0x7c, 0xf6, 0xb5, 0x28, 0x5f, 0x73, 0x29, 0x16, 0x6d, 0x14,
|
||||
0x2a, 0x07, 0x5b, 0x34, 0xb8, 0xcb, 0x73, 0x5e, 0x33, 0xdc, 0x1b, 0x94, 0x2b, 0x0b, 0x49, 0x0c,
|
||||
0xbb, 0xb3, 0x15, 0x93, 0x3c, 0x9d, 0xf1, 0x44, 0xf2, 0x3a, 0x9a, 0x28, 0x75, 0x4f, 0x86, 0x36,
|
||||
0x2f, 0xe5, 0x92, 0xe5, 0xe2, 0xf7, 0xac, 0x16, 0x45, 0x1e, 0xed, 0x6a, 0x1b, 0x57, 0x86, 0x51,
|
||||
0xa2, 0x45, 0xc6, 0xa3, 0x3d, 0x1d, 0x25, 0x5c, 0x93, 0xef, 0x42, 0x68, 0x2e, 0x43, 0x2f, 0xa2,
|
||||
0x7d, 0xa5, 0xd8, 0x08, 0xe2, 0xbf, 0x79, 0x10, 0x9e, 0xb1, 0x6a, 0x35, 0x2f, 0x98, 0x4c, 0xdf,
|
||||
0x29, 0x13, 0x1f, 0x41, 0x90, 0xf0, 0x2c, 0xab, 0xa2, 0xe1, 0x74, 0x78, 0x38, 0x39, 0xfa, 0xe0,
|
||||
0x61, 0x97, 0xe2, 0xce, 0xcf, 0x29, 0xcf, 0x32, 0xaa, 0xad, 0xc8, 0xc7, 0x10, 0xd6, 0x7c, 0x5d,
|
||||
0x66, 0xac, 0xe6, 0x55, 0xe4, 0xab, 0x9f, 0x90, 0xcd, 0x4f, 0x2e, 0x8d, 0x8a, 0x6e, 0x8c, 0xee,
|
||||
0x5d, 0x34, 0xb8, 0x7f, 0xd1, 0xf8, 0x5f, 0x3e, 0xec, 0xf5, 0xb6, 0x23, 0xbb, 0xe0, 0xdd, 0xaa,
|
||||
0x93, 0x07, 0xd4, 0xbb, 0x45, 0xd4, 0xaa, 0x53, 0x07, 0xd4, 0x6b, 0x11, 0xdd, 0xa8, 0xca, 0x09,
|
||||
0xa8, 0x77, 0x83, 0x68, 0xa5, 0xea, 0x25, 0xa0, 0xde, 0x8a, 0xfc, 0x04, 0x76, 0x7e, 0xd7, 0x70,
|
||||
0x29, 0x78, 0x15, 0x05, 0xea, 0x74, 0xef, 0x6d, 0x4e, 0xf7, 0xaa, 0xe1, 0xb2, 0xa5, 0x56, 0x8f,
|
||||
0xd1, 0x50, 0xb5, 0xa6, 0x0b, 0x47, 0xad, 0x51, 0x56, 0x63, 0x5d, 0xee, 0x68, 0x19, 0xae, 0x4d,
|
||||
0x14, 0x75, 0xb5, 0x60, 0x14, 0x7f, 0x09, 0x3e, 0xbb, 0xe5, 0x55, 0x14, 0x2a, 0xff, 0xdf, 0x7f,
|
||||
0x43, 0xc0, 0x1e, 0x1e, 0xdf, 0xf2, 0xea, 0xcb, 0xbc, 0x96, 0x2d, 0x55, 0xe6, 0xe4, 0xc7, 0x30,
|
||||
0x4a, 0x8a, 0xac, 0x90, 0x55, 0x04, 0x77, 0x0f, 0x76, 0x8a, 0x72, 0x6a, 0xd4, 0xe4, 0x10, 0x46,
|
||||
0x19, 0x5f, 0xf2, 0x3c, 0x55, 0x75, 0x33, 0x39, 0x3a, 0xd8, 0x18, 0x3e, 0x53, 0x72, 0x6a, 0xf4,
|
||||
0xe4, 0x53, 0xd8, 0xad, 0xd9, 0x3c, 0xe3, 0x2f, 0x4b, 0x8c, 0x62, 0xa5, 0x6a, 0x68, 0x72, 0xf4,
|
||||
0xbe, 0x93, 0x0f, 0x47, 0x4b, 0x7b, 0xb6, 0xe4, 0x33, 0xd8, 0x5d, 0x08, 0x9e, 0xa5, 0xf6, 0xb7,
|
||||
0x7b, 0xea, 0x50, 0xd1, 0xe6, 0xb7, 0x94, 0xe7, 0x6c, 0x8d, 0xbf, 0x78, 0x84, 0x66, 0xb4, 0x67,
|
||||
0x4d, 0xbe, 0x07, 0x50, 0x8b, 0x35, 0x7f, 0x54, 0xc8, 0x35, 0xab, 0x4d, 0x19, 0x3a, 0x12, 0xf2,
|
||||
0x39, 0xec, 0xa5, 0x3c, 0x11, 0x6b, 0x96, 0x5d, 0x64, 0x2c, 0xe1, 0x55, 0xf4, 0x9e, 0x3a, 0x9a,
|
||||
0x5b, 0x5d, 0xae, 0x9a, 0xf6, 0xad, 0x3f, 0x7c, 0x0c, 0x61, 0x17, 0x3e, 0xec, 0xef, 0xaf, 0x79,
|
||||
0xab, 0x8a, 0x21, 0xa4, 0xb8, 0x24, 0x3f, 0x80, 0xe0, 0x9a, 0x65, 0x8d, 0x2e, 0xe4, 0xc9, 0xd1,
|
||||
0xfe, 0xc6, 0xeb, 0xf1, 0xad, 0xa8, 0xa8, 0x56, 0x7e, 0x3a, 0xf8, 0x95, 0x17, 0x3f, 0x86, 0xbd,
|
||||
0xde, 0x46, 0x78, 0x70, 0x51, 0x7d, 0x99, 0x2f, 0x0a, 0x99, 0xf0, 0x54, 0xf9, 0x1c, 0x53, 0x47,
|
||||
0x42, 0xde, 0x87, 0x51, 0x2a, 0x96, 0xa2, 0xae, 0x4c, 0xb9, 0x19, 0x14, 0xff, 0xdd, 0x83, 0x5d,
|
||||
0x37, 0x9a, 0xe4, 0xa7, 0x70, 0x70, 0xcd, 0x65, 0x2d, 0x12, 0x96, 0x5d, 0x8a, 0x35, 0xc7, 0x8d,
|
||||
0xd5, 0x4f, 0xc6, 0xf4, 0x9e, 0x9c, 0x7c, 0x0c, 0xa3, 0xaa, 0x90, 0xf5, 0x49, 0xab, 0xaa, 0xf6,
|
||||
0x6d, 0x51, 0x36, 0x76, 0xc8, 0x53, 0x37, 0x92, 0x95, 0xa5, 0xc8, 0x97, 0x96, 0x0b, 0x2d, 0x26,
|
||||
0x3f, 0x82, 0xfd, 0x85, 0xb8, 0x7d, 0x24, 0x64, 0x55, 0x9f, 0x16, 0x59, 0xb3, 0xce, 0x55, 0x05,
|
||||
0x8f, 0xe9, 0x1d, 0xe9, 0x13, 0x7f, 0xec, 0x1d, 0x0c, 0x9e, 0xf8, 0xe3, 0xe0, 0x60, 0x14, 0x97,
|
||||
0xb0, 0xdf, 0xdf, 0x09, 0xdb, 0xd2, 0x1e, 0x42, 0x71, 0x82, 0x0e, 0x6f, 0x4f, 0x46, 0xa6, 0x30,
|
||||
0x49, 0x45, 0x55, 0x66, 0xac, 0x75, 0x68, 0xc3, 0x15, 0x21, 0x07, 0x5e, 0x8b, 0x4a, 0xcc, 0x33,
|
||||
0x4d, 0xe5, 0x63, 0x6a, 0x61, 0xbc, 0x84, 0x40, 0x95, 0xb5, 0x43, 0x42, 0xa1, 0x25, 0x21, 0x45,
|
||||
0xfd, 0x03, 0x87, 0xfa, 0x0f, 0x60, 0xf8, 0x6b, 0x7e, 0x6b, 0x5e, 0x03, 0x5c, 0x76, 0x54, 0xe5,
|
||||
0x3b, 0x54, 0xf5, 0x00, 0x82, 0xd7, 0x2a, 0xed, 0x9a, 0x42, 0x34, 0x88, 0xbf, 0x80, 0x91, 0x6e,
|
||||
0x8b, 0xce, 0xb3, 0xe7, 0x78, 0x9e, 0xc2, 0xe4, 0xa5, 0x14, 0x3c, 0xaf, 0x35, 0xf9, 0x98, 0x2b,
|
||||
0x38, 0xa2, 0xf8, 0xaf, 0x1e, 0xf8, 0x2a, 0x4b, 0x31, 0xec, 0x66, 0x7c, 0xc9, 0x92, 0xf6, 0xa4,
|
||||
0x68, 0xf2, 0xb4, 0x8a, 0xbc, 0xe9, 0xf0, 0x70, 0x48, 0x7b, 0x32, 0x2c, 0x8f, 0xb9, 0xd6, 0x0e,
|
||||
0xa6, 0xc3, 0xc3, 0x90, 0x1a, 0x84, 0x47, 0xcb, 0xd8, 0x9c, 0x67, 0xe6, 0x0a, 0x1a, 0xa0, 0x75,
|
||||
0x29, 0xf9, 0x42, 0xdc, 0x9a, 0x6b, 0x18, 0x84, 0xf2, 0xaa, 0x59, 0xa0, 0x5c, 0xdf, 0xc4, 0x20,
|
||||
0xbc, 0xc0, 0x9c, 0x55, 0x1d, 0x23, 0xe1, 0x1a, 0x3d, 0x57, 0x09, 0xcb, 0x2c, 0x25, 0x69, 0x10,
|
||||
0xff, 0xc3, 0xc3, 0x87, 0x4c, 0x53, 0xec, 0xbd, 0x08, 0x7f, 0x1b, 0xc6, 0x48, 0xbf, 0x5f, 0x5d,
|
||||
0x33, 0x69, 0x2e, 0xbc, 0x83, 0xf8, 0x35, 0x93, 0xe4, 0x17, 0x30, 0x52, 0xcd, 0xb1, 0x85, 0xee,
|
||||
0xad, 0x3b, 0x15, 0x55, 0x6a, 0xcc, 0x3a, 0x42, 0xf4, 0x1d, 0x42, 0xec, 0x2e, 0x1b, 0xb8, 0x97,
|
||||
0xfd, 0x08, 0x02, 0x64, 0xd6, 0x56, 0x9d, 0x7e, 0xab, 0x67, 0xcd, 0xbf, 0xda, 0x2a, 0xbe, 0x82,
|
||||
0xbd, 0xde, 0x8e, 0xdd, 0x4e, 0x5e, 0x7f, 0xa7, 0x4d, 0xa3, 0x87, 0xa6, 0xb1, 0xb1, 0x39, 0x2a,
|
||||
0x9e, 0xf1, 0xa4, 0xe6, 0xa9, 0xa9, 0xba, 0x0e, 0xc7, 0x7f, 0xf2, 0x36, 0x7e, 0xd5, 0x7e, 0x58,
|
||||
0xa2, 0x49, 0xb1, 0x5e, 0xb3, 0x3c, 0x35, 0xae, 0x2d, 0xc4, 0xb8, 0xa5, 0x73, 0xe3, 0x7a, 0x90,
|
||||
0xce, 0x11, 0xcb, 0xd2, 0x64, 0x70, 0x20, 0x4b, 0xac, 0x9d, 0x35, 0x67, 0x55, 0x23, 0xf9, 0x9a,
|
||||
0xe7, 0xb5, 0x09, 0x81, 0x2b, 0x22, 0x1f, 0xc0, 0x4e, 0xcd, 0x96, 0x5f, 0x21, 0x3d, 0x99, 0x4c,
|
||||
0xd6, 0x6c, 0xf9, 0x94, 0xb7, 0xe4, 0x3b, 0x10, 0x2a, 0xbe, 0x54, 0x2a, 0x9d, 0xce, 0xb1, 0x12,
|
||||
0x3c, 0xe5, 0x6d, 0xfc, 0x1f, 0x0f, 0x46, 0x33, 0x2e, 0xaf, 0xb9, 0x7c, 0xa7, 0x17, 0xda, 0x9d,
|
||||
0x8b, 0x86, 0x6f, 0x99, 0x8b, 0xfc, 0xed, 0x73, 0x51, 0xb0, 0x99, 0x8b, 0x1e, 0x40, 0x30, 0x93,
|
||||
0xc9, 0xf9, 0x99, 0x3a, 0xd1, 0x90, 0x6a, 0x80, 0xd5, 0x78, 0x9c, 0xd4, 0xe2, 0x9a, 0x9b, 0x61,
|
||||
0xc9, 0xa0, 0x7b, 0x0f, 0xf7, 0x78, 0xcb, 0x84, 0xf2, 0x3f, 0xce, 0x4c, 0xf1, 0x1f, 0x3d, 0x18,
|
||||
0x3d, 0x63, 0x6d, 0xd1, 0xd4, 0xf7, 0xaa, 0x76, 0x0a, 0x93, 0xe3, 0xb2, 0xcc, 0x44, 0xd2, 0xeb,
|
||||
0x54, 0x47, 0x84, 0x16, 0xcf, 0x9d, 0x7c, 0xe8, 0x58, 0xb8, 0x22, 0x7c, 0x18, 0x4e, 0xd5, 0x30,
|
||||
0xa3, 0x27, 0x13, 0xe7, 0x61, 0xd0, 0x33, 0x8c, 0x52, 0x62, 0xd0, 0x8e, 0x9b, 0xba, 0x58, 0x64,
|
||||
0xc5, 0x8d, 0x8a, 0xce, 0x98, 0x76, 0x38, 0xfe, 0xe7, 0x00, 0xfc, 0x6f, 0x6a, 0x00, 0xd9, 0x05,
|
||||
0x4f, 0x98, 0xe2, 0xf0, 0x44, 0x37, 0x8e, 0xec, 0x38, 0xe3, 0x48, 0x04, 0x3b, 0xad, 0x64, 0xf9,
|
||||
0x92, 0x57, 0xd1, 0x58, 0xb1, 0x91, 0x85, 0x4a, 0xa3, 0xfa, 0x4e, 0xcf, 0x21, 0x21, 0xb5, 0xb0,
|
||||
0xeb, 0x23, 0x70, 0xfa, 0xe8, 0xe7, 0x66, 0x64, 0x99, 0xdc, 0x7d, 0xe4, 0xb7, 0x4d, 0x2a, 0xff,
|
||||
0xbf, 0xd7, 0xf7, 0xdf, 0x1e, 0x04, 0x5d, 0x13, 0x9e, 0xf6, 0x9b, 0xf0, 0x74, 0xd3, 0x84, 0x67,
|
||||
0x27, 0xb6, 0x09, 0xcf, 0x4e, 0x10, 0xd3, 0x0b, 0xdb, 0x84, 0xf4, 0x02, 0x93, 0xf5, 0x58, 0x16,
|
||||
0x4d, 0x79, 0xd2, 0xea, 0xac, 0x86, 0xb4, 0xc3, 0x58, 0xb9, 0xbf, 0x59, 0x71, 0x69, 0x42, 0x1d,
|
||||
0x52, 0x83, 0xb0, 0xce, 0x9f, 0x29, 0x82, 0xd2, 0xc1, 0xd5, 0x80, 0xfc, 0x10, 0x02, 0x8a, 0xc1,
|
||||
0x53, 0x11, 0xee, 0xe5, 0x45, 0x89, 0xa9, 0xd6, 0xa2, 0x53, 0xfd, 0x21, 0x63, 0x0a, 0xde, 0x7e,
|
||||
0xd6, 0xfc, 0x0c, 0x46, 0xb3, 0x95, 0x58, 0xd4, 0x76, 0xf0, 0xfb, 0x96, 0x43, 0x70, 0x62, 0xcd,
|
||||
0x95, 0x8e, 0x1a, 0x93, 0xf8, 0x15, 0x84, 0x9d, 0x70, 0x73, 0x1c, 0xcf, 0x3d, 0x0e, 0x01, 0xff,
|
||||
0x2a, 0x17, 0xb5, 0x6d, 0x75, 0x5c, 0xe3, 0x65, 0x5f, 0x35, 0x2c, 0xaf, 0x45, 0xdd, 0xda, 0x56,
|
||||
0xb7, 0x38, 0xfe, 0xc4, 0x1c, 0x1f, 0xdd, 0x5d, 0x95, 0x25, 0x97, 0x86, 0x36, 0x34, 0x50, 0x9b,
|
||||
0x14, 0x37, 0x5c, 0x33, 0xfe, 0x90, 0x6a, 0x10, 0xff, 0x16, 0xc2, 0xe3, 0x8c, 0xcb, 0x9a, 0x36,
|
||||
0x19, 0xdf, 0xf6, 0x12, 0x3f, 0x99, 0xbd, 0x7c, 0x61, 0x4f, 0x80, 0xeb, 0x0d, 0x45, 0x0c, 0xef,
|
||||
0x50, 0xc4, 0x53, 0x56, 0xb2, 0xf3, 0x33, 0x55, 0xe7, 0x43, 0x6a, 0x50, 0xfc, 0x67, 0x0f, 0x7c,
|
||||
0xe4, 0x22, 0xc7, 0xb5, 0xff, 0x36, 0x1e, 0xbb, 0x90, 0xc5, 0xb5, 0x48, 0xb9, 0xb4, 0x97, 0xb3,
|
||||
0x58, 0x05, 0x3d, 0x59, 0xf1, 0xee, 0xc1, 0x37, 0x08, 0x6b, 0x0d, 0xbf, 0x7a, 0x6c, 0x2f, 0x39,
|
||||
0xb5, 0x86, 0x62, 0xaa, 0x95, 0x38, 0xd4, 0xcd, 0x9a, 0x92, 0xcb, 0xe3, 0x74, 0x2d, 0xec, 0x34,
|
||||
0xe4, 0x48, 0xe2, 0x2f, 0xf4, 0x77, 0xd4, 0x3d, 0x46, 0xf3, 0xb6, 0x7f, 0x73, 0xdd, 0x3d, 0x79,
|
||||
0xfc, 0x17, 0x0f, 0x76, 0x9e, 0x9b, 0xe9, 0xcb, 0xbd, 0x85, 0xf7, 0xc6, 0x5b, 0x0c, 0x7a, 0xb7,
|
||||
0x38, 0x82, 0x07, 0xd6, 0xa6, 0xb7, 0xbf, 0x8e, 0xc2, 0x56, 0x9d, 0x89, 0xa8, 0xdf, 0x25, 0xeb,
|
||||
0x5d, 0x3e, 0xa3, 0x2e, 0xfb, 0x36, 0xdb, 0x12, 0x7e, 0x2f, 0x2b, 0x53, 0x98, 0xd8, 0xcf, 0xc7,
|
||||
0x22, 0xb3, 0x0f, 0x8c, 0x2b, 0x8a, 0x8f, 0x60, 0x74, 0x5a, 0xe4, 0x0b, 0xb1, 0x24, 0x87, 0xe0,
|
||||
0x1f, 0x37, 0xf5, 0x4a, 0x79, 0x9c, 0x1c, 0x3d, 0x70, 0x1a, 0xbf, 0xa9, 0x57, 0xda, 0x86, 0x2a,
|
||||
0x8b, 0xf8, 0x33, 0x80, 0x8d, 0x0c, 0x5f, 0x89, 0x4d, 0x36, 0x5e, 0xf0, 0x1b, 0x2c, 0x99, 0xca,
|
||||
0x0c, 0xdf, 0x5b, 0x34, 0xf1, 0xe7, 0x10, 0x9e, 0x34, 0x22, 0x4b, 0xcf, 0xf3, 0x45, 0x81, 0xd4,
|
||||
0xf1, 0x9a, 0xcb, 0x6a, 0x93, 0x2f, 0x0b, 0x31, 0xdc, 0xc8, 0x22, 0x5d, 0x0f, 0x19, 0x34, 0x1f,
|
||||
0xa9, 0x3f, 0x27, 0x3e, 0xf9, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x77, 0xc4, 0xaa, 0x16, 0xae,
|
||||
0x10, 0x00, 0x00,
|
||||
}
|
||||
|
|
|
@ -27,33 +27,41 @@ message Dashboard {
|
|||
}
|
||||
|
||||
message DashboardCell {
|
||||
int32 x = 1; // X-coordinate of Cell in the Dashboard
|
||||
int32 y = 2; // Y-coordinate of Cell in the Dashboard
|
||||
int32 w = 3; // Width of Cell in the Dashboard
|
||||
int32 h = 4; // Height of Cell in the Dashboard
|
||||
repeated Query queries = 5; // Time-series data queries for Dashboard
|
||||
string name = 6; // User-facing name for this Dashboard
|
||||
string type = 7; // Dashboard visualization type
|
||||
string ID = 8; // id is the unique id of the dashboard. MIGRATED FIELD added in 1.2.0-beta6
|
||||
map<string, Axis> axes = 9; // Axes represent the graphical viewport for a cell's visualizations
|
||||
repeated Color colors = 10; // Colors represent encoding data values to color
|
||||
Legend legend = 11; // Legend is summary information for a cell
|
||||
TableOptions tableOptions = 12; // TableOptions for visualization of cell with type 'table'
|
||||
int32 x = 1; // X-coordinate of Cell in the Dashboard
|
||||
int32 y = 2; // Y-coordinate of Cell in the Dashboard
|
||||
int32 w = 3; // Width of Cell in the Dashboard
|
||||
int32 h = 4; // Height of Cell in the Dashboard
|
||||
repeated Query queries = 5; // Time-series data queries for Dashboard
|
||||
string name = 6; // User-facing name for this Dashboard
|
||||
string type = 7; // Dashboard visualization type
|
||||
string ID = 8; // id is the unique id of the dashboard. MIGRATED FIELD added in 1.2.0-beta6
|
||||
map<string, Axis> axes = 9; // Axes represent the graphical viewport for a cell's visualizations
|
||||
repeated Color colors = 10; // Colors represent encoding data values to color
|
||||
Legend legend = 11; // Legend is summary information for a cell
|
||||
TableOptions tableOptions = 12; // TableOptions for visualization of cell with type 'table'
|
||||
repeated RenamableField fieldOptions = 13; // Options for each of the fields returned in a cell
|
||||
string timeFormat = 14; // format for time
|
||||
DecimalPlaces decimalPlaces = 15; // Represents how precise the values of this field should be
|
||||
}
|
||||
|
||||
message DecimalPlaces {
|
||||
bool isEnforced = 1; // whether decimal places should be enforced
|
||||
int32 digits = 2; // the number of digits to display after decical point
|
||||
}
|
||||
|
||||
message TableOptions {
|
||||
string timeFormat = 1; // format for time
|
||||
reserved 1;
|
||||
bool verticalTimeAxis = 2; // time axis should be a column not row
|
||||
RenamableField sortBy = 3; // which column should a table be sorted by
|
||||
string wrapping = 4; // option for text wrapping
|
||||
repeated RenamableField fieldNames = 5; // names and renames for column/row fields
|
||||
reserved 5;
|
||||
bool fixFirstColumn = 6; // first column should be fixed/frozen
|
||||
}
|
||||
|
||||
message RenamableField {
|
||||
string internalName = 1; // name of column
|
||||
string displayName = 2; // what column is renamed to
|
||||
bool visible = 3; // Represents whether RenamableField is visible
|
||||
bool visible = 3; // Represents whether RenamableField is visible
|
||||
}
|
||||
|
||||
message Color {
|
||||
|
|
|
@ -194,10 +194,9 @@ func Test_MarshalDashboard(t *testing.T) {
|
|||
Value: "100",
|
||||
},
|
||||
},
|
||||
TableOptions: chronograf.TableOptions{
|
||||
TimeFormat: "",
|
||||
FieldNames: []chronograf.RenamableField{},
|
||||
},
|
||||
TableOptions: chronograf.TableOptions{},
|
||||
FieldOptions: []chronograf.RenamableField{},
|
||||
TimeFormat: "",
|
||||
},
|
||||
},
|
||||
Templates: []chronograf.Template{},
|
||||
|
@ -260,10 +259,10 @@ func Test_MarshalDashboard_WithLegacyBounds(t *testing.T) {
|
|||
Type: "static",
|
||||
Orientation: "bottom",
|
||||
},
|
||||
TableOptions: chronograf.TableOptions{
|
||||
TimeFormat: "MM:DD:YYYY",
|
||||
},
|
||||
Type: "line",
|
||||
TableOptions: chronograf.TableOptions{},
|
||||
TimeFormat: "MM:DD:YYYY",
|
||||
FieldOptions: []chronograf.RenamableField{},
|
||||
Type: "line",
|
||||
},
|
||||
},
|
||||
Templates: []chronograf.Template{},
|
||||
|
@ -317,11 +316,10 @@ func Test_MarshalDashboard_WithLegacyBounds(t *testing.T) {
|
|||
Type: "static",
|
||||
Orientation: "bottom",
|
||||
},
|
||||
TableOptions: chronograf.TableOptions{
|
||||
TimeFormat: "MM:DD:YYYY",
|
||||
FieldNames: []chronograf.RenamableField{},
|
||||
},
|
||||
Type: "line",
|
||||
TableOptions: chronograf.TableOptions{},
|
||||
FieldOptions: []chronograf.RenamableField{},
|
||||
TimeFormat: "MM:DD:YYYY",
|
||||
Type: "line",
|
||||
},
|
||||
},
|
||||
Templates: []chronograf.Template{},
|
||||
|
@ -380,10 +378,10 @@ func Test_MarshalDashboard_WithEmptyLegacyBounds(t *testing.T) {
|
|||
Value: "100",
|
||||
},
|
||||
},
|
||||
Type: "line",
|
||||
TableOptions: chronograf.TableOptions{
|
||||
TimeFormat: "MM:DD:YYYY",
|
||||
},
|
||||
Type: "line",
|
||||
TableOptions: chronograf.TableOptions{},
|
||||
FieldOptions: []chronograf.RenamableField{},
|
||||
TimeFormat: "MM:DD:YYYY",
|
||||
},
|
||||
},
|
||||
Templates: []chronograf.Template{},
|
||||
|
@ -433,11 +431,10 @@ func Test_MarshalDashboard_WithEmptyLegacyBounds(t *testing.T) {
|
|||
Value: "100",
|
||||
},
|
||||
},
|
||||
TableOptions: chronograf.TableOptions{
|
||||
TimeFormat: "MM:DD:YYYY",
|
||||
FieldNames: []chronograf.RenamableField{},
|
||||
},
|
||||
Type: "line",
|
||||
TableOptions: chronograf.TableOptions{},
|
||||
FieldOptions: []chronograf.RenamableField{},
|
||||
TimeFormat: "MM:DD:YYYY",
|
||||
Type: "line",
|
||||
},
|
||||
},
|
||||
Templates: []chronograf.Template{},
|
||||
|
@ -468,14 +465,13 @@ func Test_MarshalDashboard_WithEmptyCellType(t *testing.T) {
|
|||
ID: 1,
|
||||
Cells: []chronograf.DashboardCell{
|
||||
{
|
||||
ID: "9b5367de-c552-4322-a9e8-7f384cbd235c",
|
||||
Type: "line",
|
||||
Queries: []chronograf.DashboardQuery{},
|
||||
Axes: map[string]chronograf.Axis{},
|
||||
CellColors: []chronograf.CellColor{},
|
||||
TableOptions: chronograf.TableOptions{
|
||||
FieldNames: []chronograf.RenamableField{},
|
||||
},
|
||||
ID: "9b5367de-c552-4322-a9e8-7f384cbd235c",
|
||||
Type: "line",
|
||||
Queries: []chronograf.DashboardQuery{},
|
||||
Axes: map[string]chronograf.Axis{},
|
||||
CellColors: []chronograf.CellColor{},
|
||||
TableOptions: chronograf.TableOptions{},
|
||||
FieldOptions: []chronograf.RenamableField{},
|
||||
},
|
||||
},
|
||||
Templates: []chronograf.Template{},
|
||||
|
|
|
@ -563,18 +563,21 @@ type Legend struct {
|
|||
|
||||
// DashboardCell holds visual and query information for a cell
|
||||
type DashboardCell struct {
|
||||
ID string `json:"i"`
|
||||
X int32 `json:"x"`
|
||||
Y int32 `json:"y"`
|
||||
W int32 `json:"w"`
|
||||
H int32 `json:"h"`
|
||||
Name string `json:"name"`
|
||||
Queries []DashboardQuery `json:"queries"`
|
||||
Axes map[string]Axis `json:"axes"`
|
||||
Type string `json:"type"`
|
||||
CellColors []CellColor `json:"colors"`
|
||||
Legend Legend `json:"legend"`
|
||||
TableOptions TableOptions `json:"tableOptions,omitempty"`
|
||||
ID string `json:"i"`
|
||||
X int32 `json:"x"`
|
||||
Y int32 `json:"y"`
|
||||
W int32 `json:"w"`
|
||||
H int32 `json:"h"`
|
||||
Name string `json:"name"`
|
||||
Queries []DashboardQuery `json:"queries"`
|
||||
Axes map[string]Axis `json:"axes"`
|
||||
Type string `json:"type"`
|
||||
CellColors []CellColor `json:"colors"`
|
||||
Legend Legend `json:"legend"`
|
||||
TableOptions TableOptions `json:"tableOptions,omitempty"`
|
||||
FieldOptions []RenamableField `json:"fieldOptions"`
|
||||
TimeFormat string `json:"timeFormat"`
|
||||
DecimalPlaces DecimalPlaces `json:"decimalPlaces"`
|
||||
}
|
||||
|
||||
// RenamableField is a column/row field in a DashboardCell of type Table
|
||||
|
@ -586,12 +589,16 @@ type RenamableField struct {
|
|||
|
||||
// TableOptions is a type of options for a DashboardCell with type Table
|
||||
type TableOptions struct {
|
||||
TimeFormat string `json:"timeFormat"`
|
||||
VerticalTimeAxis bool `json:"verticalTimeAxis"`
|
||||
SortBy RenamableField `json:"sortBy"`
|
||||
Wrapping string `json:"wrapping"`
|
||||
FieldNames []RenamableField `json:"fieldNames"`
|
||||
FixFirstColumn bool `json:"fixFirstColumn"`
|
||||
VerticalTimeAxis bool `json:"verticalTimeAxis"`
|
||||
SortBy RenamableField `json:"sortBy"`
|
||||
Wrapping string `json:"wrapping"`
|
||||
FixFirstColumn bool `json:"fixFirstColumn"`
|
||||
}
|
||||
|
||||
// DecimalPlaces indicates whether decimal places should be enforced, and how many digits it should show.
|
||||
type DecimalPlaces struct {
|
||||
IsEnforced bool `json:"isEnforced"`
|
||||
Digits int32 `json:"digits"`
|
||||
}
|
||||
|
||||
// DashboardsStore is the storage and retrieval of dashboards
|
||||
|
|
|
@ -166,8 +166,8 @@ func TestServer(t *testing.T) {
|
|||
"id": "5000",
|
||||
"name": "Kapa 1",
|
||||
"url": "http://localhost:9092",
|
||||
"active": true,
|
||||
"insecureSkipVerify": false,
|
||||
"active": true,
|
||||
"insecureSkipVerify": false,
|
||||
"links": {
|
||||
"proxy": "/chronograf/v1/sources/5000/kapacitors/5000/proxy",
|
||||
"self": "/chronograf/v1/sources/5000/kapacitors/5000",
|
||||
|
@ -225,8 +225,8 @@ func TestServer(t *testing.T) {
|
|||
"id": "5000",
|
||||
"name": "Kapa 1",
|
||||
"url": "http://localhost:9092",
|
||||
"active": true,
|
||||
"insecureSkipVerify": false,
|
||||
"active": true,
|
||||
"insecureSkipVerify": false,
|
||||
"links": {
|
||||
"proxy": "/chronograf/v1/sources/5000/kapacitors/5000/proxy",
|
||||
"self": "/chronograf/v1/sources/5000/kapacitors/5000",
|
||||
|
@ -292,7 +292,7 @@ func TestServer(t *testing.T) {
|
|||
"default": true,
|
||||
"telegraf": "telegraf",
|
||||
"organization": "howdy",
|
||||
"defaultRP": "",
|
||||
"defaultRP": "",
|
||||
"links": {
|
||||
"self": "/chronograf/v1/sources/5000",
|
||||
"kapacitors": "/chronograf/v1/sources/5000/kapacitors",
|
||||
|
@ -304,7 +304,7 @@ func TestServer(t *testing.T) {
|
|||
"roles": "/chronograf/v1/sources/5000/roles",
|
||||
"databases": "/chronograf/v1/sources/5000/dbs",
|
||||
"annotations": "/chronograf/v1/sources/5000/annotations",
|
||||
"health": "/chronograf/v1/sources/5000/health"
|
||||
"health": "/chronograf/v1/sources/5000/health"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -546,19 +546,23 @@ func TestServer(t *testing.T) {
|
|||
"legend":{
|
||||
"type": "static",
|
||||
"orientation": "bottom"
|
||||
},
|
||||
"tableOptions":{
|
||||
"timeFormat": "",
|
||||
"verticalTimeAxis": false,
|
||||
"sortBy":{
|
||||
"internalName": "",
|
||||
"displayName": "",
|
||||
"visible": false
|
||||
},
|
||||
"wrapping": "",
|
||||
"fieldNames": null,
|
||||
"fixFirstColumn": false
|
||||
},
|
||||
},
|
||||
"tableOptions":{
|
||||
"verticalTimeAxis": false,
|
||||
"sortBy":{
|
||||
"internalName": "",
|
||||
"displayName": "",
|
||||
"visible": false
|
||||
},
|
||||
"wrapping": "",
|
||||
"fixFirstColumn": false
|
||||
},
|
||||
"fieldOptions": null,
|
||||
"timeFormat": "",
|
||||
"decimalPlaces":{
|
||||
"isEnforced": false,
|
||||
"digits": 0
|
||||
},
|
||||
"links": {
|
||||
"self": "/chronograf/v1/dashboards/1000/cells/8f61c619-dd9b-4761-8aa8-577f27247093"
|
||||
}
|
||||
|
@ -797,22 +801,26 @@ func TestServer(t *testing.T) {
|
|||
"name": "comet",
|
||||
"value": "100"
|
||||
}
|
||||
],
|
||||
"tableOptions":{
|
||||
"timeFormat":"",
|
||||
"verticalTimeAxis":false,
|
||||
"sortBy":{
|
||||
"internalName":"",
|
||||
"displayName":"",
|
||||
"visible":false
|
||||
},
|
||||
"wrapping":"",
|
||||
"fieldNames":null,
|
||||
"fixFirstColumn":false
|
||||
},
|
||||
"legend":{
|
||||
"type": "static",
|
||||
"orientation": "bottom"
|
||||
],
|
||||
"legend": {
|
||||
"type": "static",
|
||||
"orientation": "bottom"
|
||||
},
|
||||
"tableOptions":{
|
||||
"verticalTimeAxis": false,
|
||||
"sortBy":{
|
||||
"internalName": "",
|
||||
"displayName": "",
|
||||
"visible": false
|
||||
},
|
||||
"wrapping": "",
|
||||
"fixFirstColumn": false
|
||||
},
|
||||
"fieldOptions": null,
|
||||
"timeFormat": "",
|
||||
"decimalPlaces":{
|
||||
"isEnforced": false,
|
||||
"digits": 0
|
||||
},
|
||||
"links": {
|
||||
"self": "/chronograf/v1/dashboards/1000/cells/8f61c619-dd9b-4761-8aa8-577f27247093"
|
||||
|
@ -2143,7 +2151,7 @@ func TestServer(t *testing.T) {
|
|||
wants: wants{
|
||||
statusCode: 403,
|
||||
body: `
|
||||
{
|
||||
{
|
||||
"code": 403,
|
||||
"message": "user not found"
|
||||
}`,
|
||||
|
@ -2363,61 +2371,61 @@ func TestServer(t *testing.T) {
|
|||
statusCode: 200,
|
||||
body: `
|
||||
{
|
||||
"links": {
|
||||
"self": "/chronograf/v1/mappings"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"links": {
|
||||
"self": "/chronograf/v1/mappings/1"
|
||||
},
|
||||
"id": "1",
|
||||
"organizationId": "1",
|
||||
"provider": "*",
|
||||
"scheme": "*",
|
||||
"providerOrganization": "influxdata"
|
||||
},
|
||||
{
|
||||
"links": {
|
||||
"self": "/chronograf/v1/mappings/2"
|
||||
},
|
||||
"id": "2",
|
||||
"organizationId": "1",
|
||||
"provider": "*",
|
||||
"scheme": "*",
|
||||
"providerOrganization": "*"
|
||||
},
|
||||
{
|
||||
"links": {
|
||||
"self": "/chronograf/v1/mappings/3"
|
||||
},
|
||||
"id": "3",
|
||||
"organizationId": "2",
|
||||
"provider": "github",
|
||||
"scheme": "*",
|
||||
"providerOrganization": "*"
|
||||
},
|
||||
{
|
||||
"links": {
|
||||
"self": "/chronograf/v1/mappings/4"
|
||||
},
|
||||
"id": "4",
|
||||
"organizationId": "3",
|
||||
"provider": "auth0",
|
||||
"scheme": "ldap",
|
||||
"providerOrganization": "*"
|
||||
},
|
||||
{
|
||||
"links": {
|
||||
"self": "/chronograf/v1/mappings/default"
|
||||
},
|
||||
"id": "default",
|
||||
"organizationId": "default",
|
||||
"provider": "*",
|
||||
"scheme": "*",
|
||||
"providerOrganization": "*"
|
||||
}
|
||||
]
|
||||
"links": {
|
||||
"self": "/chronograf/v1/mappings"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"links": {
|
||||
"self": "/chronograf/v1/mappings/1"
|
||||
},
|
||||
"id": "1",
|
||||
"organizationId": "1",
|
||||
"provider": "*",
|
||||
"scheme": "*",
|
||||
"providerOrganization": "influxdata"
|
||||
},
|
||||
{
|
||||
"links": {
|
||||
"self": "/chronograf/v1/mappings/2"
|
||||
},
|
||||
"id": "2",
|
||||
"organizationId": "1",
|
||||
"provider": "*",
|
||||
"scheme": "*",
|
||||
"providerOrganization": "*"
|
||||
},
|
||||
{
|
||||
"links": {
|
||||
"self": "/chronograf/v1/mappings/3"
|
||||
},
|
||||
"id": "3",
|
||||
"organizationId": "2",
|
||||
"provider": "github",
|
||||
"scheme": "*",
|
||||
"providerOrganization": "*"
|
||||
},
|
||||
{
|
||||
"links": {
|
||||
"self": "/chronograf/v1/mappings/4"
|
||||
},
|
||||
"id": "4",
|
||||
"organizationId": "3",
|
||||
"provider": "auth0",
|
||||
"scheme": "ldap",
|
||||
"providerOrganization": "*"
|
||||
},
|
||||
{
|
||||
"links": {
|
||||
"self": "/chronograf/v1/mappings/default"
|
||||
},
|
||||
"id": "default",
|
||||
"organizationId": "default",
|
||||
"provider": "*",
|
||||
"scheme": "*",
|
||||
"providerOrganization": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
`,
|
||||
},
|
||||
|
@ -2693,40 +2701,40 @@ func TestServer(t *testing.T) {
|
|||
wants: wants{
|
||||
statusCode: 200,
|
||||
body: `
|
||||
{
|
||||
"layouts": "/chronograf/v1/layouts",
|
||||
"users": "/chronograf/v1/organizations/default/users",
|
||||
"allUsers": "/chronograf/v1/users",
|
||||
"organizations": "/chronograf/v1/organizations",
|
||||
"mappings": "/chronograf/v1/mappings",
|
||||
"sources": "/chronograf/v1/sources",
|
||||
"me": "/chronograf/v1/me",
|
||||
"environment": "/chronograf/v1/env",
|
||||
"dashboards": "/chronograf/v1/dashboards",
|
||||
"config": {
|
||||
"self": "/chronograf/v1/config",
|
||||
"auth": "/chronograf/v1/config/auth"
|
||||
},
|
||||
"auth": [
|
||||
{
|
||||
"name": "github",
|
||||
"label": "Github",
|
||||
"login": "/oauth/github/login",
|
||||
"logout": "/oauth/github/logout",
|
||||
"callback": "/oauth/github/callback"
|
||||
}
|
||||
],
|
||||
"logout": "/oauth/logout",
|
||||
"external": {
|
||||
"statusFeed": ""
|
||||
},
|
||||
"ifql": {
|
||||
"ast": "/chronograf/v1/ifql/ast",
|
||||
"self": "/chronograf/v1/ifql",
|
||||
"suggestions": "/chronograf/v1/ifql/suggestions"
|
||||
}
|
||||
}
|
||||
`,
|
||||
{
|
||||
"layouts": "/chronograf/v1/layouts",
|
||||
"users": "/chronograf/v1/organizations/default/users",
|
||||
"allUsers": "/chronograf/v1/users",
|
||||
"organizations": "/chronograf/v1/organizations",
|
||||
"mappings": "/chronograf/v1/mappings",
|
||||
"sources": "/chronograf/v1/sources",
|
||||
"me": "/chronograf/v1/me",
|
||||
"environment": "/chronograf/v1/env",
|
||||
"dashboards": "/chronograf/v1/dashboards",
|
||||
"config": {
|
||||
"self": "/chronograf/v1/config",
|
||||
"auth": "/chronograf/v1/config/auth"
|
||||
},
|
||||
"auth": [
|
||||
{
|
||||
"name": "github",
|
||||
"label": "Github",
|
||||
"login": "/oauth/github/login",
|
||||
"logout": "/oauth/github/logout",
|
||||
"callback": "/oauth/github/callback"
|
||||
}
|
||||
],
|
||||
"logout": "/oauth/logout",
|
||||
"external": {
|
||||
"statusFeed": ""
|
||||
},
|
||||
"ifql": {
|
||||
"ast": "/chronograf/v1/ifql/ast",
|
||||
"self": "/chronograf/v1/ifql",
|
||||
"suggestions": "/chronograf/v1/ifql/suggestions"
|
||||
}
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -2781,40 +2789,40 @@ func TestServer(t *testing.T) {
|
|||
wants: wants{
|
||||
statusCode: 200,
|
||||
body: `
|
||||
{
|
||||
"layouts": "/chronograf/v1/layouts",
|
||||
"users": "/chronograf/v1/organizations/1/users",
|
||||
"allUsers": "/chronograf/v1/users",
|
||||
"organizations": "/chronograf/v1/organizations",
|
||||
"mappings": "/chronograf/v1/mappings",
|
||||
"sources": "/chronograf/v1/sources",
|
||||
"me": "/chronograf/v1/me",
|
||||
"environment": "/chronograf/v1/env",
|
||||
"dashboards": "/chronograf/v1/dashboards",
|
||||
"config": {
|
||||
"self": "/chronograf/v1/config",
|
||||
"auth": "/chronograf/v1/config/auth"
|
||||
},
|
||||
"auth": [
|
||||
{
|
||||
"name": "github",
|
||||
"label": "Github",
|
||||
"login": "/oauth/github/login",
|
||||
"logout": "/oauth/github/logout",
|
||||
"callback": "/oauth/github/callback"
|
||||
}
|
||||
],
|
||||
"logout": "/oauth/logout",
|
||||
"external": {
|
||||
"statusFeed": ""
|
||||
},
|
||||
"ifql": {
|
||||
"ast": "/chronograf/v1/ifql/ast",
|
||||
"self": "/chronograf/v1/ifql",
|
||||
"suggestions": "/chronograf/v1/ifql/suggestions"
|
||||
}
|
||||
}
|
||||
`,
|
||||
{
|
||||
"layouts": "/chronograf/v1/layouts",
|
||||
"users": "/chronograf/v1/organizations/1/users",
|
||||
"allUsers": "/chronograf/v1/users",
|
||||
"organizations": "/chronograf/v1/organizations",
|
||||
"mappings": "/chronograf/v1/mappings",
|
||||
"sources": "/chronograf/v1/sources",
|
||||
"me": "/chronograf/v1/me",
|
||||
"environment": "/chronograf/v1/env",
|
||||
"dashboards": "/chronograf/v1/dashboards",
|
||||
"config": {
|
||||
"self": "/chronograf/v1/config",
|
||||
"auth": "/chronograf/v1/config/auth"
|
||||
},
|
||||
"auth": [
|
||||
{
|
||||
"name": "github",
|
||||
"label": "Github",
|
||||
"login": "/oauth/github/login",
|
||||
"logout": "/oauth/github/logout",
|
||||
"callback": "/oauth/github/callback"
|
||||
}
|
||||
],
|
||||
"logout": "/oauth/logout",
|
||||
"external": {
|
||||
"statusFeed": ""
|
||||
},
|
||||
"ifql": {
|
||||
"ast": "/chronograf/v1/ifql/ast",
|
||||
"self": "/chronograf/v1/ifql",
|
||||
"suggestions": "/chronograf/v1/ifql/suggestions"
|
||||
}
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -532,7 +532,7 @@ func TestService_ReplaceDashboardCell(t *testing.T) {
|
|||
}
|
||||
}
|
||||
`))),
|
||||
want: `{"i":"3c5c4102-fa40-4585-a8f9-917c77e37192","x":0,"y":0,"w":4,"h":4,"name":"Untitled Cell","queries":[{"query":"SELECT mean(\"usage_user\") AS \"mean_usage_user\" FROM \"telegraf\".\"autogen\".\"cpu\" WHERE time \u003e :dashboardTime: AND \"cpu\"=:cpu: GROUP BY :interval: FILL(null)","queryConfig":{"id":"3cd3eaa4-a4b8-44b3-b69e-0c7bf6b91d9e","database":"telegraf","measurement":"cpu","retentionPolicy":"autogen","fields":[{"value":"mean","type":"func","alias":"mean_usage_user","args":[{"value":"usage_user","type":"field","alias":""}]}],"tags":{"cpu":["ChristohersMBP2.lan"]},"groupBy":{"time":"2s","tags":[]},"areTagsAccepted":true,"fill":"null","rawText":"SELECT mean(\"usage_user\") AS \"mean_usage_user\" FROM \"telegraf\".\"autogen\".\"cpu\" WHERE time \u003e :dashboardTime: AND \"cpu\"=:cpu: GROUP BY :interval: FILL(null)","range":{"upper":"","lower":"now() - 15m"},"shifts":[]},"source":""}],"axes":{"x":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""},"y":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""},"y2":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""}},"type":"line","colors":[{"id":"0","type":"min","hex":"#00C9FF","name":"laser","value":"0"},{"id":"1","type":"max","hex":"#9394FF","name":"comet","value":"100"}],"legend":{},"tableOptions":{"timeFormat":"","verticalTimeAxis":false,"sortBy":{"internalName":"","displayName":"","visible":false},"wrapping":"","fieldNames":null,"fixFirstColumn":false},"links":{"self":"/chronograf/v1/dashboards/1/cells/3c5c4102-fa40-4585-a8f9-917c77e37192"}}
|
||||
want: `{"i":"3c5c4102-fa40-4585-a8f9-917c77e37192","x":0,"y":0,"w":4,"h":4,"name":"Untitled Cell","queries":[{"query":"SELECT mean(\"usage_user\") AS \"mean_usage_user\" FROM \"telegraf\".\"autogen\".\"cpu\" WHERE time \u003e :dashboardTime: AND \"cpu\"=:cpu: GROUP BY :interval: FILL(null)","queryConfig":{"id":"3cd3eaa4-a4b8-44b3-b69e-0c7bf6b91d9e","database":"telegraf","measurement":"cpu","retentionPolicy":"autogen","fields":[{"value":"mean","type":"func","alias":"mean_usage_user","args":[{"value":"usage_user","type":"field","alias":""}]}],"tags":{"cpu":["ChristohersMBP2.lan"]},"groupBy":{"time":"2s","tags":[]},"areTagsAccepted":true,"fill":"null","rawText":"SELECT mean(\"usage_user\") AS \"mean_usage_user\" FROM \"telegraf\".\"autogen\".\"cpu\" WHERE time \u003e :dashboardTime: AND \"cpu\"=:cpu: GROUP BY :interval: FILL(null)","range":{"upper":"","lower":"now() - 15m"},"shifts":[]},"source":""}],"axes":{"x":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""},"y":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""},"y2":{"bounds":["",""],"label":"","prefix":"","suffix":"","base":"","scale":""}},"type":"line","colors":[{"id":"0","type":"min","hex":"#00C9FF","name":"laser","value":"0"},{"id":"1","type":"max","hex":"#9394FF","name":"comet","value":"100"}],"legend":{},"tableOptions":{"verticalTimeAxis":false,"sortBy":{"internalName":"","displayName":"","visible":false},"wrapping":"","fixFirstColumn":false},"fieldOptions":null,"timeFormat":"","decimalPlaces":{"isEnforced":false,"digits":0},"links":{"self":"/chronograf/v1/dashboards/1/cells/3c5c4102-fa40-4585-a8f9-917c77e37192"}}
|
||||
`,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -4653,11 +4653,6 @@
|
|||
}
|
||||
},
|
||||
"tableOptions": {
|
||||
"timeFormat": {
|
||||
"description":
|
||||
"timeFormat describes the display format for time values according to moment.js date formatting",
|
||||
"type": "string"
|
||||
},
|
||||
"verticalTimeAxis": {
|
||||
"description":
|
||||
"verticalTimeAxis describes the orientation of the table by indicating whether the time axis will be displayed vertically",
|
||||
|
@ -4675,20 +4670,41 @@
|
|||
"type": "string",
|
||||
"enum": ["truncate", "wrap", "single-line"]
|
||||
},
|
||||
"fieldNames": {
|
||||
"description":
|
||||
"fieldNames represent the fields retrieved by the query with customization options",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/RenamableField"
|
||||
}
|
||||
},
|
||||
"fixFirstColumn": {
|
||||
"description":
|
||||
"fixFirstColumn indicates whether the first column of the table should be locked",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"fieldOptions": {
|
||||
"description":
|
||||
"fieldOptions represent the fields retrieved by the query with customization options",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/RenamableField"
|
||||
}
|
||||
},
|
||||
"timeFormat": {
|
||||
"description":
|
||||
"timeFormat describes the display format for time values according to moment.js date formatting",
|
||||
"type": "string"
|
||||
},
|
||||
"decimalPoints": {
|
||||
"description":
|
||||
"decimal points indicates whether and how many digits to show after decimal point",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"isEnforced": {
|
||||
"description":
|
||||
"Indicates whether decimal point setting should be enforced",
|
||||
"type": "bool"
|
||||
},
|
||||
"digits": {
|
||||
"description": "The number of digits after decimal to display",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import {
|
||||
isUserAuthorized,
|
||||
ADMIN_ROLE,
|
||||
SUPERADMIN_ROLE,
|
||||
} from 'src/auth/Authorized'
|
||||
|
||||
import {Tab, Tabs, TabPanel, TabPanels, TabList} from 'shared/components/Tabs'
|
||||
import OrganizationsPage from 'src/admin/containers/chronograf/OrganizationsPage'
|
||||
import UsersPage from 'src/admin/containers/chronograf/UsersPage'
|
||||
import ProvidersPage from 'src/admin/containers/ProvidersPage'
|
||||
import AllUsersPage from 'src/admin/containers/chronograf/AllUsersPage'
|
||||
|
||||
const ORGANIZATIONS_TAB_NAME = 'All Orgs'
|
||||
const PROVIDERS_TAB_NAME = 'Org Mappings'
|
||||
const CURRENT_ORG_USERS_TAB_NAME = 'Current Org'
|
||||
const ALL_USERS_TAB_NAME = 'All Users'
|
||||
|
||||
const AdminTabs = ({
|
||||
me: {currentOrganization: meCurrentOrganization, role: meRole, id: meID},
|
||||
}) => {
|
||||
const tabs = [
|
||||
{
|
||||
requiredRole: ADMIN_ROLE,
|
||||
type: CURRENT_ORG_USERS_TAB_NAME,
|
||||
component: (
|
||||
<UsersPage meID={meID} meCurrentOrganization={meCurrentOrganization} />
|
||||
),
|
||||
},
|
||||
{
|
||||
requiredRole: SUPERADMIN_ROLE,
|
||||
type: ALL_USERS_TAB_NAME,
|
||||
component: <AllUsersPage meID={meID} />,
|
||||
},
|
||||
{
|
||||
requiredRole: SUPERADMIN_ROLE,
|
||||
type: ORGANIZATIONS_TAB_NAME,
|
||||
component: (
|
||||
<OrganizationsPage meCurrentOrganization={meCurrentOrganization} />
|
||||
),
|
||||
},
|
||||
{
|
||||
requiredRole: SUPERADMIN_ROLE,
|
||||
type: PROVIDERS_TAB_NAME,
|
||||
component: <ProvidersPage />,
|
||||
},
|
||||
].filter(t => isUserAuthorized(meRole, t.requiredRole))
|
||||
|
||||
return (
|
||||
<Tabs className="row">
|
||||
<TabList customClass="col-md-2 admin-tabs">
|
||||
{tabs.map((t, i) => <Tab key={tabs[i].type}>{tabs[i].type}</Tab>)}
|
||||
</TabList>
|
||||
<TabPanels customClass="col-md-10 admin-tabs--content">
|
||||
{tabs.map((t, i) => (
|
||||
<TabPanel key={tabs[i].type}>{t.component}</TabPanel>
|
||||
))}
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
)
|
||||
}
|
||||
|
||||
const {shape, string} = PropTypes
|
||||
|
||||
AdminTabs.propTypes = {
|
||||
me: shape({
|
||||
id: string.isRequired,
|
||||
role: string.isRequired,
|
||||
currentOrganization: shape({
|
||||
name: string.isRequired,
|
||||
id: string.isRequired,
|
||||
}),
|
||||
}).isRequired,
|
||||
}
|
||||
|
||||
export default AdminTabs
|
|
@ -2,10 +2,52 @@ import React from 'react'
|
|||
import PropTypes from 'prop-types'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
import AdminTabs from 'src/admin/components/chronograf/AdminTabs'
|
||||
import SubSections from 'src/shared/components/SubSections'
|
||||
import FancyScrollbar from 'shared/components/FancyScrollbar'
|
||||
|
||||
const AdminChronografPage = ({me}) => (
|
||||
import UsersPage from 'src/admin/containers/chronograf/UsersPage'
|
||||
import AllUsersPage from 'src/admin/containers/chronograf/AllUsersPage'
|
||||
import OrganizationsPage from 'src/admin/containers/chronograf/OrganizationsPage'
|
||||
import ProvidersPage from 'src/admin/containers/ProvidersPage'
|
||||
|
||||
import {
|
||||
isUserAuthorized,
|
||||
ADMIN_ROLE,
|
||||
SUPERADMIN_ROLE,
|
||||
} from 'src/auth/Authorized'
|
||||
|
||||
const sections = me => [
|
||||
{
|
||||
url: 'current-organization',
|
||||
name: 'Current Org',
|
||||
enabled: isUserAuthorized(me.role, ADMIN_ROLE),
|
||||
component: (
|
||||
<UsersPage meID={me.id} meCurrentOrganization={me.currentOrganization} />
|
||||
),
|
||||
},
|
||||
{
|
||||
url: 'all-users',
|
||||
name: 'All Users',
|
||||
enabled: isUserAuthorized(me.role, SUPERADMIN_ROLE),
|
||||
component: <AllUsersPage meID={me.id} />,
|
||||
},
|
||||
{
|
||||
url: 'all-organizations',
|
||||
name: 'All Orgs',
|
||||
enabled: isUserAuthorized(me.role, SUPERADMIN_ROLE),
|
||||
component: (
|
||||
<OrganizationsPage meCurrentOrganization={me.currentOrganization} />
|
||||
),
|
||||
},
|
||||
{
|
||||
url: 'organization-mappings',
|
||||
name: 'Org Mappings',
|
||||
enabled: isUserAuthorized(me.role, SUPERADMIN_ROLE),
|
||||
component: <ProvidersPage />,
|
||||
},
|
||||
]
|
||||
|
||||
const AdminChronografPage = ({me, source, params: {tab}}) => (
|
||||
<div className="page">
|
||||
<div className="page-header">
|
||||
<div className="page-header__container">
|
||||
|
@ -16,9 +58,12 @@ const AdminChronografPage = ({me}) => (
|
|||
</div>
|
||||
<FancyScrollbar className="page-contents">
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
<AdminTabs me={me} />
|
||||
</div>
|
||||
<SubSections
|
||||
sections={sections(me)}
|
||||
activeSection={tab}
|
||||
parentUrl="admin-chronograf"
|
||||
sourceID={source.id}
|
||||
/>
|
||||
</div>
|
||||
</FancyScrollbar>
|
||||
</div>
|
||||
|
@ -35,6 +80,15 @@ AdminChronografPage.propTypes = {
|
|||
id: string.isRequired,
|
||||
}),
|
||||
}).isRequired,
|
||||
params: shape({
|
||||
tab: string,
|
||||
}).isRequired,
|
||||
source: shape({
|
||||
id: string.isRequired,
|
||||
links: shape({
|
||||
users: string.isRequired,
|
||||
}),
|
||||
}).isRequired,
|
||||
}
|
||||
|
||||
const mapStateToProps = ({auth: {me}}) => ({
|
||||
|
|
|
@ -64,3 +64,24 @@ export const updateLineColors = lineColors => ({
|
|||
lineColors,
|
||||
},
|
||||
})
|
||||
|
||||
export const changeTimeFormat = timeFormat => ({
|
||||
type: 'CHANGE_TIME_FORMAT',
|
||||
payload: {
|
||||
timeFormat,
|
||||
},
|
||||
})
|
||||
|
||||
export const changeDecimalPlaces = decimalPlaces => ({
|
||||
type: 'CHANGE_DECIMAL_PLACES',
|
||||
payload: {
|
||||
decimalPlaces,
|
||||
},
|
||||
})
|
||||
|
||||
export const updateFieldOptions = fieldOptions => ({
|
||||
type: 'UPDATE_FIELD_OPTIONS',
|
||||
payload: {
|
||||
fieldOptions,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -21,7 +21,7 @@ interface RenamableField {
|
|||
visible: boolean
|
||||
}
|
||||
|
||||
interface GraphOptionsCustomizableFieldProps {
|
||||
interface Props {
|
||||
internalName: string
|
||||
displayName: string
|
||||
visible: boolean
|
||||
|
@ -36,7 +36,7 @@ interface GraphOptionsCustomizableFieldProps {
|
|||
moveField: (dragIndex: number, hoverIndex: number) => void
|
||||
}
|
||||
|
||||
const fieldSource: DragSourceSpec<GraphOptionsCustomizableFieldProps> = {
|
||||
const fieldSource: DragSourceSpec<Props> = {
|
||||
beginDrag(props) {
|
||||
return {
|
||||
id: props.id,
|
||||
|
@ -112,9 +112,7 @@ function MyDragSource(dragv1, dragv2, dragfunc1) {
|
|||
isDragging: monitor.isDragging(),
|
||||
})
|
||||
)
|
||||
export default class GraphOptionsCustomizableField extends Component<
|
||||
GraphOptionsCustomizableFieldProps
|
||||
> {
|
||||
export default class GraphOptionsCustomizableField extends Component<Props> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import OptIn from 'src/shared/components/OptIn'
|
||||
|
||||
interface DecimalPlaces {
|
||||
isEnforced: boolean
|
||||
digits: number
|
||||
}
|
||||
|
||||
interface Props extends DecimalPlaces {
|
||||
onDecimalPlacesChange: (decimalPlaces: DecimalPlaces) => void
|
||||
}
|
||||
|
||||
const fixedValueString = 'fixed'
|
||||
|
||||
@ErrorHandling
|
||||
class GraphOptionsDecimalPlaces extends PureComponent<Props> {
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
public onSetValue = (valueFromSelector: string): void => {
|
||||
let digits
|
||||
let isEnforced
|
||||
if (valueFromSelector === fixedValueString) {
|
||||
digits = this.props.digits
|
||||
isEnforced = false
|
||||
} else if (valueFromSelector === '') {
|
||||
digits = this.props.digits
|
||||
isEnforced = true
|
||||
} else {
|
||||
digits = Number(valueFromSelector)
|
||||
if (digits < 0) {
|
||||
digits = 0
|
||||
}
|
||||
isEnforced = true
|
||||
}
|
||||
this.props.onDecimalPlacesChange({digits, isEnforced})
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {digits, isEnforced} = this.props
|
||||
return (
|
||||
<div className="form-group col-xs-6">
|
||||
<label> Decimal Places </label>
|
||||
<OptIn
|
||||
customPlaceholder={isEnforced ? digits.toString() : 'unlimited'}
|
||||
customValue={isEnforced ? digits.toString() : ''}
|
||||
onSetValue={this.onSetValue}
|
||||
fixedPlaceholder={''}
|
||||
fixedValue={fixedValueString}
|
||||
type="number"
|
||||
min={'0'}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default GraphOptionsDecimalPlaces
|
|
@ -25,7 +25,7 @@ const GraphOptionsSortBy = ({
|
|||
const selectedValue = selected.displayName || selected.internalName
|
||||
return (
|
||||
<div className="form-group col-xs-6">
|
||||
<label>Default Sort By</label>
|
||||
<label>Default Sort Field</label>
|
||||
<Dropdown
|
||||
items={sortByOptions}
|
||||
selected={selectedValue}
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
TIME_FORMAT_CUSTOM,
|
||||
DEFAULT_TIME_FORMAT,
|
||||
TIME_FORMAT_TOOLTIP_LINK,
|
||||
} from 'src/shared/constants/tableGraph'
|
||||
} from 'src/dashboards/constants'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface TimeFormatOptions {
|
||||
|
@ -60,7 +60,7 @@ class GraphOptionsTimeFormat extends PureComponent<Props, State> {
|
|||
const showCustom = !formatOption || customFormat
|
||||
|
||||
return (
|
||||
<div className="form-group col-xs-12">
|
||||
<div className="form-group col-xs-6">
|
||||
<label>
|
||||
Time Format
|
||||
{showCustom && (
|
||||
|
|
|
@ -7,6 +7,7 @@ import GraphOptionsFixFirstColumn from 'src/dashboards/components/GraphOptionsFi
|
|||
import GraphOptionsSortBy from 'src/dashboards/components/GraphOptionsSortBy'
|
||||
import GraphOptionsTimeAxis from 'src/dashboards/components/GraphOptionsTimeAxis'
|
||||
import GraphOptionsTimeFormat from 'src/dashboards/components/GraphOptionsTimeFormat'
|
||||
import GraphOptionsDecimalPlaces from 'src/dashboards/components/GraphOptionsDecimalPlaces'
|
||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||
|
||||
import _ from 'lodash'
|
||||
|
@ -14,12 +15,17 @@ import _ from 'lodash'
|
|||
import ThresholdsList from 'src/shared/components/ThresholdsList'
|
||||
import ThresholdsListTypeToggle from 'src/shared/components/ThresholdsListTypeToggle'
|
||||
|
||||
import {updateTableOptions} from 'src/dashboards/actions/cellEditorOverlay'
|
||||
import {TIME_FIELD_DEFAULT} from 'src/shared/constants/tableGraph'
|
||||
import {
|
||||
updateTableOptions,
|
||||
updateFieldOptions,
|
||||
changeTimeFormat,
|
||||
changeDecimalPlaces,
|
||||
} from 'src/dashboards/actions/cellEditorOverlay'
|
||||
import {DEFAULT_TIME_FIELD} from 'src/dashboards/constants'
|
||||
import {QueryConfig} from 'src/types/query'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface Option {
|
||||
interface DropdownOption {
|
||||
text: string
|
||||
key: string
|
||||
}
|
||||
|
@ -30,18 +36,27 @@ interface RenamableField {
|
|||
visible: boolean
|
||||
}
|
||||
|
||||
interface Options {
|
||||
timeFormat: string
|
||||
interface TableOptionsInterface {
|
||||
verticalTimeAxis: boolean
|
||||
sortBy: RenamableField
|
||||
fieldNames: RenamableField[]
|
||||
fixFirstColumn: boolean
|
||||
}
|
||||
|
||||
interface DecimalPlaces {
|
||||
isEnforced: boolean
|
||||
digits: number
|
||||
}
|
||||
|
||||
interface Props {
|
||||
queryConfigs: QueryConfig[]
|
||||
handleUpdateTableOptions: (options: Options) => void
|
||||
tableOptions: Options
|
||||
handleUpdateTableOptions: (options: TableOptionsInterface) => void
|
||||
handleUpdateFieldOptions: (fieldOptions: RenamableField[]) => void
|
||||
handleChangeTimeFormat: (timeFormat: string) => void
|
||||
handleChangeDecimalPlaces: (decimalPlaces: number) => void
|
||||
tableOptions: TableOptionsInterface
|
||||
fieldOptions: RenamableField[]
|
||||
timeFormat: string
|
||||
decimalPlaces: DecimalPlaces
|
||||
onResetFocus: () => void
|
||||
}
|
||||
|
||||
|
@ -54,12 +69,15 @@ export class TableOptions extends Component<Props, {}> {
|
|||
|
||||
public render() {
|
||||
const {
|
||||
tableOptions: {timeFormat, fieldNames, verticalTimeAxis, fixFirstColumn},
|
||||
tableOptions: {verticalTimeAxis, fixFirstColumn},
|
||||
fieldOptions,
|
||||
timeFormat,
|
||||
onResetFocus,
|
||||
tableOptions,
|
||||
decimalPlaces,
|
||||
} = this.props
|
||||
|
||||
const tableSortByOptions = fieldNames.map(field => ({
|
||||
const tableSortByOptions = fieldOptions.map(field => ({
|
||||
key: field.internalName,
|
||||
text: field.displayName || field.internalName,
|
||||
}))
|
||||
|
@ -72,18 +90,23 @@ export class TableOptions extends Component<Props, {}> {
|
|||
<div className="display-options--cell-wrapper">
|
||||
<h5 className="display-options--header">Table Controls</h5>
|
||||
<div className="form-group-wrapper">
|
||||
<GraphOptionsTimeFormat
|
||||
timeFormat={timeFormat}
|
||||
onTimeFormatChange={this.handleTimeFormatChange}
|
||||
<GraphOptionsSortBy
|
||||
selected={tableOptions.sortBy || DEFAULT_TIME_FIELD}
|
||||
sortByOptions={tableSortByOptions}
|
||||
onChooseSortBy={this.handleChooseSortBy}
|
||||
/>
|
||||
<GraphOptionsDecimalPlaces
|
||||
digits={decimalPlaces.digits}
|
||||
isEnforced={decimalPlaces.isEnforced}
|
||||
onDecimalPlacesChange={this.handleDecimalPlacesChange}
|
||||
/>
|
||||
<GraphOptionsTimeAxis
|
||||
verticalTimeAxis={verticalTimeAxis}
|
||||
onToggleVerticalTimeAxis={this.handleToggleVerticalTimeAxis}
|
||||
/>
|
||||
<GraphOptionsSortBy
|
||||
selected={tableOptions.sortBy || TIME_FIELD_DEFAULT}
|
||||
sortByOptions={tableSortByOptions}
|
||||
onChooseSortBy={this.handleChooseSortBy}
|
||||
<GraphOptionsTimeFormat
|
||||
timeFormat={timeFormat}
|
||||
onTimeFormatChange={this.handleTimeFormatChange}
|
||||
/>
|
||||
<GraphOptionsFixFirstColumn
|
||||
fixed={fixFirstColumn}
|
||||
|
@ -91,7 +114,7 @@ export class TableOptions extends Component<Props, {}> {
|
|||
/>
|
||||
</div>
|
||||
<GraphOptionsCustomizeFields
|
||||
fields={fieldNames}
|
||||
fields={fieldOptions}
|
||||
onFieldUpdate={this.handleFieldUpdate}
|
||||
moveField={this.moveField}
|
||||
/>
|
||||
|
@ -105,39 +128,38 @@ export class TableOptions extends Component<Props, {}> {
|
|||
}
|
||||
|
||||
private moveField(dragIndex, hoverIndex) {
|
||||
const {handleUpdateTableOptions, tableOptions} = this.props
|
||||
const {fieldNames} = tableOptions
|
||||
const {handleUpdateFieldOptions, fieldOptions} = this.props
|
||||
|
||||
const dragField = fieldNames[dragIndex]
|
||||
const removedFields = _.concat(
|
||||
_.slice(fieldNames, 0, dragIndex),
|
||||
_.slice(fieldNames, dragIndex + 1)
|
||||
const draggedField = fieldOptions[dragIndex]
|
||||
|
||||
const fieldOptionsRemoved = _.concat(
|
||||
_.slice(fieldOptions, 0, dragIndex),
|
||||
_.slice(fieldOptions, dragIndex + 1)
|
||||
)
|
||||
const addedFields = _.concat(
|
||||
_.slice(removedFields, 0, hoverIndex),
|
||||
[dragField],
|
||||
_.slice(removedFields, hoverIndex)
|
||||
|
||||
const fieldOptionsAdded = _.concat(
|
||||
_.slice(fieldOptionsRemoved, 0, hoverIndex),
|
||||
[draggedField],
|
||||
_.slice(fieldOptionsRemoved, hoverIndex)
|
||||
)
|
||||
handleUpdateTableOptions({
|
||||
...tableOptions,
|
||||
fieldNames: addedFields,
|
||||
})
|
||||
|
||||
handleUpdateFieldOptions(fieldOptionsAdded)
|
||||
}
|
||||
|
||||
private handleChooseSortBy = (option: Option) => {
|
||||
const {tableOptions, handleUpdateTableOptions} = this.props
|
||||
const sortBy = {
|
||||
displayName: option.text === option.key ? '' : option.text,
|
||||
internalName: option.key,
|
||||
visible: true,
|
||||
}
|
||||
|
||||
private handleChooseSortBy = (option: DropdownOption) => {
|
||||
const {tableOptions, handleUpdateTableOptions, fieldOptions} = this.props
|
||||
const sortBy = fieldOptions.find(f => f.internalName === option.key)
|
||||
handleUpdateTableOptions({...tableOptions, sortBy})
|
||||
}
|
||||
|
||||
private handleTimeFormatChange = timeFormat => {
|
||||
const {tableOptions, handleUpdateTableOptions} = this.props
|
||||
handleUpdateTableOptions({...tableOptions, timeFormat})
|
||||
const {handleChangeTimeFormat} = this.props
|
||||
handleChangeTimeFormat(timeFormat)
|
||||
}
|
||||
|
||||
private handleDecimalPlacesChange = decimalPlaces => {
|
||||
const {handleChangeDecimalPlaces} = this.props
|
||||
handleChangeDecimalPlaces(decimalPlaces)
|
||||
}
|
||||
|
||||
private handleToggleVerticalTimeAxis = verticalTimeAxis => () => {
|
||||
|
@ -152,34 +174,46 @@ export class TableOptions extends Component<Props, {}> {
|
|||
}
|
||||
|
||||
private handleFieldUpdate = field => {
|
||||
const {handleUpdateTableOptions, tableOptions} = this.props
|
||||
const {sortBy, fieldNames} = tableOptions
|
||||
const updatedFields = fieldNames.map(
|
||||
const {
|
||||
handleUpdateTableOptions,
|
||||
handleUpdateFieldOptions,
|
||||
tableOptions,
|
||||
fieldOptions,
|
||||
} = this.props
|
||||
const {sortBy} = tableOptions
|
||||
|
||||
const updatedFieldOptions = fieldOptions.map(
|
||||
f => (f.internalName === field.internalName ? field : f)
|
||||
)
|
||||
const updatedSortBy =
|
||||
sortBy.internalName === field.internalName
|
||||
? {...sortBy, displayName: field.displayName}
|
||||
: sortBy
|
||||
|
||||
handleUpdateTableOptions({
|
||||
...tableOptions,
|
||||
fieldNames: updatedFields,
|
||||
sortBy: updatedSortBy,
|
||||
})
|
||||
if (sortBy.internalName === field.internalName) {
|
||||
const updatedSortBy = {...sortBy, displayName: field.displayName}
|
||||
handleUpdateTableOptions({
|
||||
...tableOptions,
|
||||
sortBy: updatedSortBy,
|
||||
})
|
||||
}
|
||||
|
||||
handleUpdateFieldOptions(updatedFieldOptions)
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = ({
|
||||
cellEditorOverlay: {
|
||||
cell: {tableOptions},
|
||||
cell: {tableOptions, timeFormat, fieldOptions, decimalPlaces},
|
||||
},
|
||||
}) => ({
|
||||
tableOptions,
|
||||
timeFormat,
|
||||
fieldOptions,
|
||||
decimalPlaces,
|
||||
})
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
handleUpdateTableOptions: bindActionCreators(updateTableOptions, dispatch),
|
||||
handleUpdateFieldOptions: bindActionCreators(updateFieldOptions, dispatch),
|
||||
handleChangeTimeFormat: bindActionCreators(changeTimeFormat, dispatch),
|
||||
handleChangeDecimalPlaces: bindActionCreators(changeDecimalPlaces, dispatch),
|
||||
})
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TableOptions)
|
||||
|
|
|
@ -24,6 +24,9 @@ const DashVisualization = (
|
|||
staticLegend,
|
||||
thresholdsListColors,
|
||||
tableOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
fieldOptions,
|
||||
isInCEO,
|
||||
},
|
||||
{
|
||||
|
@ -54,6 +57,9 @@ const DashVisualization = (
|
|||
editQueryStatus={editQueryStatus}
|
||||
resizerTopHeight={resizerTopHeight}
|
||||
staticLegend={staticLegend}
|
||||
timeFormat={timeFormat}
|
||||
decimalPlaces={decimalPlaces}
|
||||
fieldOptions={fieldOptions}
|
||||
isInCEO={isInCEO}
|
||||
/>
|
||||
</div>
|
||||
|
@ -79,6 +85,18 @@ DashVisualization.propTypes = {
|
|||
}),
|
||||
}),
|
||||
tableOptions: shape({}),
|
||||
timeFormat: string.isRequired,
|
||||
decimalPlaces: shape({
|
||||
isEnforced: bool,
|
||||
digits: number,
|
||||
}),
|
||||
fieldOptions: arrayOf(
|
||||
shape({
|
||||
internalName: string.isRequired,
|
||||
displayName: string.isRequired,
|
||||
visible: bool.isRequired,
|
||||
})
|
||||
),
|
||||
resizerTopHeight: number,
|
||||
thresholdsListColors: colorsNumberSchema,
|
||||
gaugeColors: colorsNumberSchema,
|
||||
|
@ -100,7 +118,7 @@ const mapStateToProps = ({
|
|||
thresholdsListColors,
|
||||
gaugeColors,
|
||||
lineColors,
|
||||
cell: {type, axes, tableOptions},
|
||||
cell: {type, axes, tableOptions, fieldOptions, timeFormat, decimalPlaces},
|
||||
},
|
||||
}) => ({
|
||||
gaugeColors,
|
||||
|
@ -109,6 +127,9 @@ const mapStateToProps = ({
|
|||
type,
|
||||
axes,
|
||||
tableOptions,
|
||||
fieldOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
})
|
||||
|
||||
export default connect(mapStateToProps, null)(DashVisualization)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {DEFAULT_TABLE_OPTIONS} from 'src/shared/constants/tableGraph'
|
||||
import {DEFAULT_TABLE_OPTIONS} from 'src/dashboards/constants'
|
||||
import {stringifyColorValues} from 'src/shared/constants/colorOperations'
|
||||
import {
|
||||
CELL_TYPE_LINE,
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import {DEFAULT_TABLE_OPTIONS} from 'src/shared/constants/tableGraph'
|
||||
import {
|
||||
DEFAULT_VERTICAL_TIME_AXIS,
|
||||
DEFAULT_FIX_FIRST_COLUMN,
|
||||
} from 'src/shared/constants/tableGraph'
|
||||
import {CELL_TYPE_LINE} from 'src/dashboards/graphics/graph'
|
||||
|
||||
export const UNTITLED_CELL_LINE = 'Untitled Line Graph'
|
||||
|
@ -11,6 +14,41 @@ export const UNTITLED_CELL_SINGLE_STAT = 'Untitled Single Stat'
|
|||
export const UNTITLED_CELL_GAUGE = 'Untitled Gauge'
|
||||
export const UNTITLED_CELL_TABLE = 'Untitled Table'
|
||||
|
||||
export const TIME_FORMAT_TOOLTIP_LINK =
|
||||
'http://momentjs.com/docs/#/parsing/string-format/'
|
||||
|
||||
export const DEFAULT_DECIMAL_PLACES = {
|
||||
isEnforced: false,
|
||||
digits: 3,
|
||||
}
|
||||
|
||||
export const DEFAULT_TIME_FIELD = {
|
||||
internalName: 'time',
|
||||
displayName: '',
|
||||
visible: true,
|
||||
}
|
||||
|
||||
export const DEFAULT_TABLE_OPTIONS = {
|
||||
verticalTimeAxis: DEFAULT_VERTICAL_TIME_AXIS,
|
||||
sortBy: DEFAULT_TIME_FIELD,
|
||||
wrapping: 'truncate',
|
||||
fixFirstColumn: DEFAULT_FIX_FIRST_COLUMN,
|
||||
}
|
||||
|
||||
export const DEFAULT_TIME_FORMAT = 'MM/DD/YYYY HH:mm:ss'
|
||||
export const TIME_FORMAT_CUSTOM = 'Custom'
|
||||
|
||||
export const FORMAT_OPTIONS = [
|
||||
{text: DEFAULT_TIME_FORMAT},
|
||||
{text: 'MM/DD/YYYY HH:mm:ss.SSS'},
|
||||
{text: 'YYYY-MM-DD HH:mm:ss'},
|
||||
{text: 'HH:mm:ss'},
|
||||
{text: 'HH:mm:ss.SSS'},
|
||||
{text: 'MMMM D, YYYY HH:mm:ss'},
|
||||
{text: 'dddd, MMMM D, YYYY HH:mm:ss'},
|
||||
{text: TIME_FORMAT_CUSTOM},
|
||||
]
|
||||
|
||||
export const NEW_DEFAULT_DASHBOARD_CELL = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
|
@ -20,6 +58,9 @@ export const NEW_DEFAULT_DASHBOARD_CELL = {
|
|||
type: CELL_TYPE_LINE,
|
||||
queries: [],
|
||||
tableOptions: DEFAULT_TABLE_OPTIONS,
|
||||
timeFormat: DEFAULT_TIME_FORMAT,
|
||||
decimalPlaces: DEFAULT_DECIMAL_PLACES,
|
||||
fieldOptions: [DEFAULT_TIME_FIELD],
|
||||
}
|
||||
|
||||
export const EMPTY_DASHBOARD = {
|
||||
|
|
|
@ -114,6 +114,25 @@ export default function cellEditorOverlay(state = initialState, action) {
|
|||
return {...state, cell}
|
||||
}
|
||||
|
||||
case 'CHANGE_TIME_FORMAT': {
|
||||
const {timeFormat} = action.payload
|
||||
const cell = {...state.cell, timeFormat}
|
||||
|
||||
return {...state, cell}
|
||||
}
|
||||
case 'CHANGE_DECIMAL_PLACES': {
|
||||
const {decimalPlaces} = action.payload
|
||||
const cell = {...state.cell, decimalPlaces}
|
||||
|
||||
return {...state, cell}
|
||||
}
|
||||
case 'UPDATE_FIELD_OPTIONS': {
|
||||
const {fieldOptions} = action.payload
|
||||
const cell = {...state.cell, fieldOptions}
|
||||
|
||||
return {...state, cell}
|
||||
}
|
||||
|
||||
case 'UPDATE_LINE_COLORS': {
|
||||
const {lineColors} = action.payload
|
||||
|
||||
|
|
|
@ -2,11 +2,8 @@ import calculateSize from 'calculate-size'
|
|||
import _ from 'lodash'
|
||||
import {map, reduce, filter} from 'fast.js'
|
||||
|
||||
import {
|
||||
CELL_HORIZONTAL_PADDING,
|
||||
TIME_FIELD_DEFAULT,
|
||||
DEFAULT_TIME_FORMAT,
|
||||
} from 'src/shared/constants/tableGraph'
|
||||
import {CELL_HORIZONTAL_PADDING} from 'src/shared/constants/tableGraph'
|
||||
import {DEFAULT_TIME_FIELD, DEFAULT_TIME_FORMAT} from 'src/dashboards/constants'
|
||||
|
||||
const calculateTimeColumnWidth = timeFormat => {
|
||||
// Force usage of longest format names for ideal measurement
|
||||
|
@ -30,9 +27,10 @@ const updateMaxWidths = (
|
|||
maxColumnWidths,
|
||||
topRow,
|
||||
isTopRow,
|
||||
fieldNames,
|
||||
fieldOptions,
|
||||
timeFormatWidth,
|
||||
verticalTimeAxis
|
||||
verticalTimeAxis,
|
||||
decimalPlaces
|
||||
) => {
|
||||
return reduce(
|
||||
row,
|
||||
|
@ -41,21 +39,27 @@ const updateMaxWidths = (
|
|||
(verticalTimeAxis && isTopRow) || (!verticalTimeAxis && c === 0)
|
||||
|
||||
const foundField = isLabel
|
||||
? fieldNames.find(field => field.internalName === col)
|
||||
? fieldOptions.find(field => field.internalName === col)
|
||||
: undefined
|
||||
const colValue =
|
||||
foundField && foundField.displayName ? foundField.displayName : `${col}`
|
||||
const isNumerical = _.isNumber(col)
|
||||
|
||||
let colValue = `${col}`
|
||||
if (foundField && foundField.displayName) {
|
||||
colValue = foundField.displayName
|
||||
} else if (isNumerical && decimalPlaces.isEnforced) {
|
||||
colValue = col.toFixed(decimalPlaces.digits)
|
||||
}
|
||||
|
||||
const columnLabel = topRow[c]
|
||||
|
||||
const useTimeWidth =
|
||||
(columnLabel === TIME_FIELD_DEFAULT.internalName &&
|
||||
(columnLabel === DEFAULT_TIME_FIELD.internalName &&
|
||||
verticalTimeAxis &&
|
||||
!isTopRow) ||
|
||||
(!verticalTimeAxis &&
|
||||
isTopRow &&
|
||||
topRow[0] === TIME_FIELD_DEFAULT.internalName &&
|
||||
topRow[0] === DEFAULT_TIME_FIELD.internalName &&
|
||||
c !== 0)
|
||||
|
||||
const currentWidth = useTimeWidth
|
||||
? timeFormatWidth
|
||||
: calculateSize(colValue, {
|
||||
|
@ -77,23 +81,27 @@ const updateMaxWidths = (
|
|||
)
|
||||
}
|
||||
|
||||
export const computeFieldNames = (existingFieldNames, sortedLabels) => {
|
||||
export const computeFieldOptions = (existingFieldOptions, sortedLabels) => {
|
||||
const timeField =
|
||||
existingFieldNames.find(f => f.internalName === 'time') ||
|
||||
TIME_FIELD_DEFAULT
|
||||
existingFieldOptions.find(f => f.internalName === 'time') ||
|
||||
DEFAULT_TIME_FIELD
|
||||
let astNames = [timeField]
|
||||
|
||||
sortedLabels.forEach(({label}) => {
|
||||
const field = {internalName: label, displayName: '', visible: true}
|
||||
const field = {
|
||||
internalName: label,
|
||||
displayName: '',
|
||||
visible: true,
|
||||
}
|
||||
astNames = [...astNames, field]
|
||||
})
|
||||
|
||||
const intersection = existingFieldNames.filter(f => {
|
||||
const intersection = existingFieldOptions.filter(f => {
|
||||
return astNames.find(a => a.internalName === f.internalName)
|
||||
})
|
||||
|
||||
const newFields = astNames.filter(a => {
|
||||
return !existingFieldNames.find(f => f.internalName === a.internalName)
|
||||
return !existingFieldOptions.find(f => f.internalName === a.internalName)
|
||||
})
|
||||
|
||||
return [...intersection, ...newFields]
|
||||
|
@ -101,9 +109,10 @@ export const computeFieldNames = (existingFieldNames, sortedLabels) => {
|
|||
|
||||
export const calculateColumnWidths = (
|
||||
data,
|
||||
fieldNames,
|
||||
fieldOptions,
|
||||
timeFormat,
|
||||
verticalTimeAxis
|
||||
verticalTimeAxis,
|
||||
decimalPlaces
|
||||
) => {
|
||||
const timeFormatWidth = calculateTimeColumnWidth(
|
||||
timeFormat === '' ? DEFAULT_TIME_FORMAT : timeFormat
|
||||
|
@ -116,21 +125,24 @@ export const calculateColumnWidths = (
|
|||
acc,
|
||||
data[0],
|
||||
r === 0,
|
||||
fieldNames,
|
||||
fieldOptions,
|
||||
timeFormatWidth,
|
||||
verticalTimeAxis
|
||||
verticalTimeAxis,
|
||||
decimalPlaces
|
||||
)
|
||||
},
|
||||
{widths: {}, totalWidths: 0}
|
||||
)
|
||||
}
|
||||
|
||||
export const filterTableColumns = (data, fieldNames) => {
|
||||
export const filterTableColumns = (data, fieldOptions) => {
|
||||
const visibility = {}
|
||||
const filteredData = map(data, (row, i) => {
|
||||
return filter(row, (col, j) => {
|
||||
if (i === 0) {
|
||||
const foundField = fieldNames.find(field => field.internalName === col)
|
||||
const foundField = fieldOptions.find(
|
||||
field => field.internalName === col
|
||||
)
|
||||
visibility[j] = foundField ? foundField.visible : true
|
||||
}
|
||||
return visibility[j]
|
||||
|
@ -139,35 +151,43 @@ export const filterTableColumns = (data, fieldNames) => {
|
|||
return filteredData[0].length ? filteredData : [[]]
|
||||
}
|
||||
|
||||
export const orderTableColumns = (data, fieldNames) => {
|
||||
const fieldsSortOrder = fieldNames.map(fieldName => {
|
||||
export const orderTableColumns = (data, fieldOptions) => {
|
||||
const fieldsSortOrder = fieldOptions.map(fieldOption => {
|
||||
return _.findIndex(data[0], dataLabel => {
|
||||
return dataLabel === fieldName.internalName
|
||||
return dataLabel === fieldOption.internalName
|
||||
})
|
||||
})
|
||||
const filteredFieldSortOrder = filter(fieldsSortOrder, f => f !== -1)
|
||||
const orderedData = map(data, row => {
|
||||
return row.map((v, j, arr) => arr[filteredFieldSortOrder[j]] || v)
|
||||
return row.map((__, j, arr) => arr[filteredFieldSortOrder[j]])
|
||||
})
|
||||
return orderedData[0].length ? orderedData : [[]]
|
||||
}
|
||||
|
||||
export const transformTableData = (data, sort, fieldNames, tableOptions) => {
|
||||
const {verticalTimeAxis, timeFormat} = tableOptions
|
||||
export const transformTableData = (
|
||||
data,
|
||||
sort,
|
||||
fieldOptions,
|
||||
tableOptions,
|
||||
timeFormat,
|
||||
decimalPlaces
|
||||
) => {
|
||||
const {verticalTimeAxis} = tableOptions
|
||||
const sortIndex = _.indexOf(data[0], sort.field)
|
||||
const sortedData = [
|
||||
data[0],
|
||||
..._.orderBy(_.drop(data, 1), sortIndex, [sort.direction]),
|
||||
]
|
||||
const sortedTimeVals = map(sortedData, r => r[0])
|
||||
const filteredData = filterTableColumns(sortedData, fieldNames)
|
||||
const orderedData = orderTableColumns(filteredData, fieldNames)
|
||||
const filteredData = filterTableColumns(sortedData, fieldOptions)
|
||||
const orderedData = orderTableColumns(filteredData, fieldOptions)
|
||||
const transformedData = verticalTimeAxis ? orderedData : _.unzip(orderedData)
|
||||
const {widths: columnWidths, totalWidths} = calculateColumnWidths(
|
||||
transformedData,
|
||||
fieldNames,
|
||||
fieldOptions,
|
||||
timeFormat,
|
||||
verticalTimeAxis
|
||||
verticalTimeAxis,
|
||||
decimalPlaces
|
||||
)
|
||||
return {transformedData, sortedTimeVals, columnWidths, totalWidths}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {connect} from 'react-redux'
|
||||
import {bindActionCreators} from 'redux'
|
||||
import {withRouter, InjectedRouter} from 'react-router'
|
||||
|
@ -52,15 +51,6 @@ interface State {
|
|||
|
||||
@ErrorHandling
|
||||
export class DataExplorer extends PureComponent<Props, State> {
|
||||
public static childContextTypes = {
|
||||
source: PropTypes.shape({
|
||||
links: PropTypes.shape({
|
||||
proxy: PropTypes.string.isRequired,
|
||||
self: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
}).isRequired,
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
|
|
|
@ -21,25 +21,33 @@ class BodyBuilder extends PureComponent<Props> {
|
|||
return b.declarations.map(d => {
|
||||
if (d.funcs) {
|
||||
return (
|
||||
<ExpressionNode
|
||||
id={d.id}
|
||||
key={d.id}
|
||||
funcNames={this.funcNames}
|
||||
funcs={d.funcs}
|
||||
/>
|
||||
<div key={b.id}>
|
||||
<div className="func-node--name">{d.name} =</div>
|
||||
<ExpressionNode
|
||||
key={b.id}
|
||||
bodyID={b.id}
|
||||
declarationID={d.id}
|
||||
funcNames={this.funcNames}
|
||||
funcs={d.funcs}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return <div key={b.id}>{b.source}</div>
|
||||
return (
|
||||
<div className="func-node--name" key={b.id}>
|
||||
{b.source}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<ExpressionNode
|
||||
id={b.id}
|
||||
key={b.id}
|
||||
funcNames={this.funcNames}
|
||||
bodyID={b.id}
|
||||
funcs={b.funcs}
|
||||
funcNames={this.funcNames}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
|
|
@ -8,36 +8,37 @@ import {Func} from 'src/types/ifql'
|
|||
|
||||
interface Props {
|
||||
funcNames: any[]
|
||||
id: string
|
||||
bodyID: string
|
||||
funcs: Func[]
|
||||
declarationID?: string
|
||||
}
|
||||
|
||||
// an Expression is a group of one or more functions
|
||||
class ExpressionNode extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {id, funcNames, funcs} = this.props
|
||||
const {declarationID, bodyID, funcNames, funcs} = this.props
|
||||
return (
|
||||
<IFQLContext.Consumer>
|
||||
{({onDeleteFuncNode, onAddNode, onChangeArg, onGenerateScript}) => {
|
||||
return (
|
||||
<div className="func-nodes-container">
|
||||
<h4>
|
||||
<FuncSelector
|
||||
expressionID={id}
|
||||
funcs={funcNames}
|
||||
onAddNode={onAddNode}
|
||||
/>
|
||||
</h4>
|
||||
{funcs.map(func => (
|
||||
<FuncNode
|
||||
key={func.id}
|
||||
func={func}
|
||||
expressionID={func.id}
|
||||
bodyID={bodyID}
|
||||
onChangeArg={onChangeArg}
|
||||
onDelete={onDeleteFuncNode}
|
||||
declarationID={declarationID}
|
||||
onGenerateScript={onGenerateScript}
|
||||
/>
|
||||
))}
|
||||
<FuncSelector
|
||||
bodyID={bodyID}
|
||||
funcs={funcNames}
|
||||
onAddNode={onAddNode}
|
||||
declarationID={declarationID}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
|
|
|
@ -9,7 +9,8 @@ interface Props {
|
|||
funcID: string
|
||||
argKey: string
|
||||
value: string
|
||||
expressionID: string
|
||||
bodyID: string
|
||||
declarationID: string
|
||||
onChangeArg: OnChangeArg
|
||||
}
|
||||
|
||||
|
@ -56,12 +57,13 @@ class From extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private handleChooseDatabase = (item: DropdownItem): void => {
|
||||
const {argKey, funcID, onChangeArg, expressionID} = this.props
|
||||
const {argKey, funcID, onChangeArg, bodyID, declarationID} = this.props
|
||||
onChangeArg({
|
||||
funcID,
|
||||
key: argKey,
|
||||
value: item.text,
|
||||
expressionID,
|
||||
bodyID,
|
||||
declarationID,
|
||||
generate: true,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -14,7 +14,8 @@ interface Props {
|
|||
argKey: string
|
||||
value: string | boolean
|
||||
type: string
|
||||
expressionID: string
|
||||
bodyID: string
|
||||
declarationID: string
|
||||
onChangeArg: OnChangeArg
|
||||
onGenerateScript: () => void
|
||||
}
|
||||
|
@ -26,10 +27,11 @@ class FuncArg extends PureComponent<Props> {
|
|||
argKey,
|
||||
value,
|
||||
type,
|
||||
funcName,
|
||||
bodyID,
|
||||
funcID,
|
||||
funcName,
|
||||
onChangeArg,
|
||||
expressionID,
|
||||
declarationID,
|
||||
onGenerateScript,
|
||||
} = this.props
|
||||
|
||||
|
@ -39,7 +41,8 @@ class FuncArg extends PureComponent<Props> {
|
|||
argKey={argKey}
|
||||
funcID={funcID}
|
||||
value={this.value}
|
||||
expressionID={expressionID}
|
||||
bodyID={bodyID}
|
||||
declarationID={declarationID}
|
||||
onChangeArg={onChangeArg}
|
||||
/>
|
||||
)
|
||||
|
@ -60,8 +63,9 @@ class FuncArg extends PureComponent<Props> {
|
|||
value={this.value}
|
||||
argKey={argKey}
|
||||
funcID={funcID}
|
||||
expressionID={expressionID}
|
||||
bodyID={bodyID}
|
||||
onChangeArg={onChangeArg}
|
||||
declarationID={declarationID}
|
||||
onGenerateScript={onGenerateScript}
|
||||
/>
|
||||
)
|
||||
|
@ -72,9 +76,10 @@ class FuncArg extends PureComponent<Props> {
|
|||
<FuncArgBool
|
||||
value={this.boolValue}
|
||||
argKey={argKey}
|
||||
bodyID={bodyID}
|
||||
funcID={funcID}
|
||||
onChangeArg={onChangeArg}
|
||||
expressionID={expressionID}
|
||||
declarationID={declarationID}
|
||||
onGenerateScript={onGenerateScript}
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -7,7 +7,8 @@ interface Props {
|
|||
argKey: string
|
||||
value: boolean
|
||||
funcID: string
|
||||
expressionID: string
|
||||
bodyID: string
|
||||
declarationID: string
|
||||
onChangeArg: OnChangeArg
|
||||
onGenerateScript: () => void
|
||||
}
|
||||
|
@ -23,8 +24,15 @@ class FuncArgBool extends PureComponent<Props> {
|
|||
}
|
||||
|
||||
private handleToggle = (value: boolean): void => {
|
||||
const {argKey, funcID, expressionID, onChangeArg} = this.props
|
||||
onChangeArg({funcID, key: argKey, value, generate: true, expressionID})
|
||||
const {argKey, funcID, bodyID, onChangeArg, declarationID} = this.props
|
||||
onChangeArg({
|
||||
key: argKey,
|
||||
value,
|
||||
funcID,
|
||||
bodyID,
|
||||
declarationID,
|
||||
generate: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,8 @@ interface Props {
|
|||
argKey: string
|
||||
value: string
|
||||
type: string
|
||||
expressionID: string
|
||||
bodyID: string
|
||||
declarationID: string
|
||||
onChangeArg: OnChangeArg
|
||||
onGenerateScript: () => void
|
||||
}
|
||||
|
@ -44,13 +45,14 @@ class FuncArgInput extends PureComponent<Props> {
|
|||
}
|
||||
|
||||
private handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const {funcID, argKey, expressionID} = this.props
|
||||
const {funcID, argKey, bodyID, declarationID} = this.props
|
||||
|
||||
this.props.onChangeArg({
|
||||
funcID,
|
||||
key: argKey,
|
||||
value: e.target.value,
|
||||
expressionID,
|
||||
declarationID,
|
||||
bodyID,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,15 +6,22 @@ import {Func} from 'src/types/ifql'
|
|||
|
||||
interface Props {
|
||||
func: Func
|
||||
expressionID: string
|
||||
bodyID: string
|
||||
onChangeArg: OnChangeArg
|
||||
declarationID: string
|
||||
onGenerateScript: () => void
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
export default class FuncArgs extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {expressionID, func, onChangeArg, onGenerateScript} = this.props
|
||||
const {
|
||||
func,
|
||||
bodyID,
|
||||
onChangeArg,
|
||||
declarationID,
|
||||
onGenerateScript,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<div className="func-args">
|
||||
|
@ -25,10 +32,11 @@ export default class FuncArgs extends PureComponent<Props> {
|
|||
type={type}
|
||||
argKey={key}
|
||||
value={value}
|
||||
bodyID={bodyID}
|
||||
funcID={func.id}
|
||||
funcName={func.name}
|
||||
onChangeArg={onChangeArg}
|
||||
expressionID={expressionID}
|
||||
declarationID={declarationID}
|
||||
onGenerateScript={onGenerateScript}
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import React, {PureComponent, MouseEvent} from 'react'
|
||||
import FuncArgs from 'src/ifql/components/FuncArgs'
|
||||
import {OnChangeArg, Func} from 'src/types/ifql'
|
||||
import {OnDeleteFuncNode, OnChangeArg, Func} from 'src/types/ifql'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface Props {
|
||||
func: Func
|
||||
expressionID: string
|
||||
onDelete: (funcID: string, expressionID: string) => void
|
||||
bodyID: string
|
||||
declarationID?: string
|
||||
onDelete: OnDeleteFuncNode
|
||||
onChangeArg: OnChangeArg
|
||||
onGenerateScript: () => void
|
||||
}
|
||||
|
@ -17,6 +18,10 @@ interface State {
|
|||
|
||||
@ErrorHandling
|
||||
export default class FuncNode extends PureComponent<Props, State> {
|
||||
public static defaultProps: Partial<Props> = {
|
||||
declarationID: '',
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
|
@ -25,7 +30,13 @@ export default class FuncNode extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
public render() {
|
||||
const {expressionID, func, onChangeArg, onGenerateScript} = this.props
|
||||
const {
|
||||
func,
|
||||
bodyID,
|
||||
onChangeArg,
|
||||
declarationID,
|
||||
onGenerateScript,
|
||||
} = this.props
|
||||
const {isOpen} = this.state
|
||||
|
||||
return (
|
||||
|
@ -36,8 +47,9 @@ export default class FuncNode extends PureComponent<Props, State> {
|
|||
{isOpen && (
|
||||
<FuncArgs
|
||||
func={func}
|
||||
bodyID={bodyID}
|
||||
onChangeArg={onChangeArg}
|
||||
expressionID={expressionID}
|
||||
declarationID={declarationID}
|
||||
onGenerateScript={onGenerateScript}
|
||||
/>
|
||||
)}
|
||||
|
@ -49,7 +61,9 @@ export default class FuncNode extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private handleDelete = (): void => {
|
||||
this.props.onDelete(this.props.func.id, this.props.expressionID)
|
||||
const {func, bodyID, declarationID} = this.props
|
||||
|
||||
this.props.onDelete({funcID: func.id, bodyID, declarationID})
|
||||
}
|
||||
|
||||
private handleClick = (e: MouseEvent<HTMLElement>): void => {
|
||||
|
|
|
@ -14,7 +14,8 @@ interface State {
|
|||
|
||||
interface Props {
|
||||
funcs: string[]
|
||||
expressionID: string
|
||||
bodyID: string
|
||||
declarationID: string
|
||||
onAddNode: OnAddNode
|
||||
}
|
||||
|
||||
|
@ -65,8 +66,9 @@ export class FuncSelector extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private handleAddNode = (name: string) => {
|
||||
const {bodyID, declarationID} = this.props
|
||||
this.handleCloseList()
|
||||
this.props.onAddNode(name, this.props.expressionID)
|
||||
this.props.onAddNode(name, bodyID, declarationID)
|
||||
}
|
||||
|
||||
private get availableFuncs() {
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
|
||||
import {connect} from 'react-redux'
|
||||
import _ from 'lodash'
|
||||
|
||||
import TimeMachine from 'src/ifql/components/TimeMachine'
|
||||
import KeyboardShortcuts from 'src/shared/components/KeyboardShortcuts'
|
||||
import {Suggestion, FlatBody} from 'src/types/ifql'
|
||||
import {InputArg, Handlers} from 'src/types/ifql'
|
||||
import {InputArg, Handlers, DeleteFuncNodeArgs, Func} from 'src/types/ifql'
|
||||
|
||||
import {bodyNodes} from 'src/ifql/helpers'
|
||||
import {getSuggestions, getAST} from 'src/ifql/apis'
|
||||
|
@ -44,7 +45,7 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
ast: null,
|
||||
suggestions: [],
|
||||
script:
|
||||
'foo = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\nfrom(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\n',
|
||||
'baz = "baz"\n\nfoo = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\nbar = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\n',
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +109,7 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private handleGenerateScript = (): void => {
|
||||
this.getASTResponse(this.expressionsToScript)
|
||||
this.getASTResponse(this.bodyToScript)
|
||||
}
|
||||
|
||||
private handleChangeArg = ({
|
||||
|
@ -116,30 +117,41 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
value,
|
||||
generate,
|
||||
funcID,
|
||||
expressionID,
|
||||
declarationID = '',
|
||||
bodyID,
|
||||
}: InputArg): void => {
|
||||
const body = this.state.body.map(expression => {
|
||||
if (expression.id !== expressionID) {
|
||||
return expression
|
||||
const body = this.state.body.map(b => {
|
||||
if (b.id !== bodyID) {
|
||||
return b
|
||||
}
|
||||
|
||||
const funcs = expression.funcs.map(f => {
|
||||
if (f.id !== funcID) {
|
||||
return f
|
||||
}
|
||||
|
||||
const args = f.args.map(a => {
|
||||
if (a.key === key) {
|
||||
return {...a, value}
|
||||
if (declarationID) {
|
||||
const declarations = b.declarations.map(d => {
|
||||
if (d.id !== declarationID) {
|
||||
return d
|
||||
}
|
||||
|
||||
return a
|
||||
const functions = this.editFuncArgs({
|
||||
funcs: d.funcs,
|
||||
funcID,
|
||||
key,
|
||||
value,
|
||||
})
|
||||
|
||||
return {...d, funcs: functions}
|
||||
})
|
||||
|
||||
return {...f, args}
|
||||
return {...b, declarations}
|
||||
}
|
||||
|
||||
const funcs = this.editFuncArgs({
|
||||
funcs: b.funcs,
|
||||
funcID,
|
||||
key,
|
||||
value,
|
||||
})
|
||||
|
||||
return {...expression, funcs}
|
||||
return {...b, funcs}
|
||||
})
|
||||
|
||||
this.setState({body}, () => {
|
||||
|
@ -149,9 +161,42 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
})
|
||||
}
|
||||
|
||||
private get expressionsToScript(): string {
|
||||
return this.state.body.reduce((acc, expression) => {
|
||||
return `${acc + this.funcsToScript(expression.funcs)}\n\n`
|
||||
private editFuncArgs = ({funcs, funcID, key, value}): Func[] => {
|
||||
return funcs.map(f => {
|
||||
if (f.id !== funcID) {
|
||||
return f
|
||||
}
|
||||
|
||||
const args = f.args.map(a => {
|
||||
if (a.key === key) {
|
||||
return {...a, value}
|
||||
}
|
||||
|
||||
return a
|
||||
})
|
||||
|
||||
return {...f, args}
|
||||
})
|
||||
}
|
||||
|
||||
private get bodyToScript(): string {
|
||||
return this.state.body.reduce((acc, b) => {
|
||||
if (b.declarations.length) {
|
||||
const declaration = _.get(b, 'declarations.0', false)
|
||||
if (!declaration) {
|
||||
return acc
|
||||
}
|
||||
|
||||
if (!declaration.funcs) {
|
||||
return `${acc}${b.source}\n\n`
|
||||
}
|
||||
|
||||
return `${acc}${declaration.name} = ${this.funcsToScript(
|
||||
declaration.funcs
|
||||
)}\n\n`
|
||||
}
|
||||
|
||||
return `${acc}${this.funcsToScript(b.funcs)}\n\n`
|
||||
}, '')
|
||||
}
|
||||
|
||||
|
@ -183,51 +228,104 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
this.setState({script})
|
||||
}
|
||||
|
||||
private handleAddNode = (name: string, expressionID: string): void => {
|
||||
const script = this.state.body.reduce((acc, expression) => {
|
||||
if (expression.id === expressionID) {
|
||||
const {funcs} = expression
|
||||
return `${acc}${this.funcsToScript(funcs)}\n\t|> ${name}()\n\n`
|
||||
private handleAddNode = (
|
||||
name: string,
|
||||
bodyID: string,
|
||||
declarationID: string
|
||||
): void => {
|
||||
const script = this.state.body.reduce((acc, body) => {
|
||||
const {id, source, funcs} = body
|
||||
|
||||
if (id === bodyID) {
|
||||
const declaration = body.declarations.find(d => d.id === declarationID)
|
||||
if (declaration) {
|
||||
return `${acc}${declaration.name} = ${this.appendFunc(
|
||||
declaration.funcs,
|
||||
name
|
||||
)}`
|
||||
}
|
||||
|
||||
return `${acc}${this.appendFunc(funcs, name)}`
|
||||
}
|
||||
|
||||
return acc + expression.source
|
||||
return `${acc}${this.formatSource(source)}`
|
||||
}, '')
|
||||
|
||||
this.getASTResponse(script)
|
||||
}
|
||||
|
||||
private handleDeleteFuncNode = (
|
||||
funcID: string,
|
||||
expressionID: string
|
||||
): void => {
|
||||
// TODO: export this and test functionality
|
||||
private appendFunc = (funcs, name): string => {
|
||||
return `${this.funcsToScript(funcs)}\n\t|> ${name}()\n\n`
|
||||
}
|
||||
|
||||
private handleDeleteFuncNode = (ids: DeleteFuncNodeArgs): void => {
|
||||
const {funcID, declarationID = '', bodyID} = ids
|
||||
|
||||
const script = this.state.body
|
||||
.map((expression, expressionIndex) => {
|
||||
if (expression.id !== expressionID) {
|
||||
return expression.source
|
||||
.map((body, bodyIndex) => {
|
||||
if (body.id !== bodyID) {
|
||||
return this.formatSource(body.source)
|
||||
}
|
||||
|
||||
const funcs = expression.funcs.filter(f => f.id !== funcID)
|
||||
const source = funcs.reduce((acc, f, i) => {
|
||||
if (i === 0) {
|
||||
return `${f.source}`
|
||||
const isLast = bodyIndex === this.state.body.length - 1
|
||||
|
||||
if (declarationID) {
|
||||
const declaration = body.declarations.find(
|
||||
d => d.id === declarationID
|
||||
)
|
||||
|
||||
if (!declaration) {
|
||||
return
|
||||
}
|
||||
|
||||
return `${acc}\n\t${f.source}`
|
||||
}, '')
|
||||
|
||||
const isLast = expressionIndex === this.state.body.length - 1
|
||||
if (isLast) {
|
||||
return `${source}`
|
||||
const functions = declaration.funcs.filter(f => f.id !== funcID)
|
||||
const s = this.funcsToSource(functions)
|
||||
return `${declaration.name} = ${this.formatLastSource(s, isLast)}`
|
||||
}
|
||||
|
||||
return `${source}\n\n`
|
||||
const funcs = body.funcs.filter(f => f.id !== funcID)
|
||||
const source = this.funcsToSource(funcs)
|
||||
return this.formatLastSource(source, isLast)
|
||||
})
|
||||
.join('')
|
||||
|
||||
this.getASTResponse(script)
|
||||
}
|
||||
|
||||
private formatSource = (source: string): string => {
|
||||
// currently a bug in the AST which does not add newlines to literal variable assignment bodies
|
||||
if (!source.match(/\n\n/)) {
|
||||
return `${source}\n\n`
|
||||
}
|
||||
|
||||
return `${source}`
|
||||
}
|
||||
|
||||
// formats the last line of a body string to include two new lines
|
||||
private formatLastSource = (source: string, isLast: boolean): string => {
|
||||
if (isLast) {
|
||||
return `${source}`
|
||||
}
|
||||
|
||||
// currently a bug in the AST which does not add newlines to literal variable assignment bodies
|
||||
if (!source.match(/\n\n/)) {
|
||||
return `${source}\n\n`
|
||||
}
|
||||
|
||||
return `${source}\n\n`
|
||||
}
|
||||
|
||||
// funcsToSource takes a list of funtion nodes and returns an ifql script
|
||||
private funcsToSource = (funcs): string => {
|
||||
return funcs.reduce((acc, f, i) => {
|
||||
if (i === 0) {
|
||||
return `${f.source}`
|
||||
}
|
||||
|
||||
return `${acc}\n\t${f.source}`
|
||||
}, '')
|
||||
}
|
||||
|
||||
private getASTResponse = async (script: string) => {
|
||||
const {links} = this.props
|
||||
|
||||
|
|
|
@ -146,7 +146,10 @@ class Root extends PureComponent<{}, State> {
|
|||
path="kapacitors/:id/edit:hash"
|
||||
component={KapacitorPage}
|
||||
/>
|
||||
<Route path="admin-chronograf" component={AdminChronografPage} />
|
||||
<Route
|
||||
path="admin-chronograf/:tab"
|
||||
component={AdminChronografPage}
|
||||
/>
|
||||
<Route path="admin-influxdb/:tab" component={AdminInfluxDBPage} />
|
||||
<Route path="manage-sources" component={ManageSources} />
|
||||
<Route path="manage-sources/new" component={SourcePage} />
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
import _ from 'lodash'
|
||||
import {fetchTimeSeriesAsync} from 'src/shared/actions/timeSeries'
|
||||
import {removeUnselectedTemplateValues} from 'src/dashboards/constants'
|
||||
|
||||
import {intervalValuesPoints} from 'src/shared/constants'
|
||||
|
||||
interface TemplateQuery {
|
||||
db: string
|
||||
rp: string
|
||||
influxql: string
|
||||
}
|
||||
|
||||
interface TemplateValue {
|
||||
type: string
|
||||
value: string
|
||||
selected: boolean
|
||||
}
|
||||
|
||||
interface Template {
|
||||
type: string
|
||||
tempVar: string
|
||||
query: TemplateQuery
|
||||
values: TemplateValue[]
|
||||
}
|
||||
|
||||
interface Query {
|
||||
host: string | string[]
|
||||
text: string
|
||||
database: string
|
||||
db: string
|
||||
rp: string
|
||||
}
|
||||
|
||||
export const fetchTimeSeries = async (
|
||||
queries: Query[],
|
||||
resolution: number,
|
||||
templates: Template[],
|
||||
editQueryStatus: () => void
|
||||
) => {
|
||||
const timeSeriesPromises = queries.map(query => {
|
||||
const {host, database, rp} = query
|
||||
// the key `database` was used upstream in HostPage.js, and since as of this writing
|
||||
// the codebase has not been fully converted to TypeScript, it's not clear where else
|
||||
// it may be used, but this slight modification is intended to allow for the use of
|
||||
// `database` while moving over to `db` for consistency over time
|
||||
const db = _.get(query, 'db', database)
|
||||
|
||||
const templatesWithIntervalVals = templates.map(temp => {
|
||||
if (temp.tempVar === ':interval:') {
|
||||
if (resolution) {
|
||||
const values = temp.values.map(v => ({
|
||||
...v,
|
||||
value: `${_.toInteger(Number(resolution) / 3)}`,
|
||||
}))
|
||||
|
||||
return {...temp, values}
|
||||
}
|
||||
|
||||
return {...temp, values: intervalValuesPoints}
|
||||
}
|
||||
return temp
|
||||
})
|
||||
|
||||
const tempVars = removeUnselectedTemplateValues(templatesWithIntervalVals)
|
||||
|
||||
const source = host
|
||||
return fetchTimeSeriesAsync(
|
||||
{source, db, rp, query, tempVars, resolution},
|
||||
editQueryStatus
|
||||
)
|
||||
})
|
||||
|
||||
return Promise.all(timeSeriesPromises)
|
||||
}
|
|
@ -1,294 +0,0 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import _ from 'lodash'
|
||||
|
||||
import {fetchTimeSeriesAsync} from 'shared/actions/timeSeries'
|
||||
import {removeUnselectedTemplateValues} from 'src/dashboards/constants'
|
||||
import {intervalValuesPoints} from 'src/shared/constants'
|
||||
import {getQueryConfig} from 'shared/apis'
|
||||
|
||||
const AutoRefresh = ComposedComponent => {
|
||||
class wrapper extends Component {
|
||||
constructor() {
|
||||
super()
|
||||
this.state = {
|
||||
lastQuerySuccessful: true,
|
||||
timeSeries: [],
|
||||
resolution: null,
|
||||
queryASTs: [],
|
||||
}
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const {queries, templates, autoRefresh, type} = this.props
|
||||
this.executeQueries(queries, templates)
|
||||
if (type === 'table') {
|
||||
const queryASTs = await this.getQueryASTs(queries, templates)
|
||||
this.setState({queryASTs})
|
||||
}
|
||||
if (autoRefresh) {
|
||||
this.intervalID = setInterval(
|
||||
() => this.executeQueries(queries, templates),
|
||||
autoRefresh
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
getQueryASTs = async (queries, templates) => {
|
||||
return await Promise.all(
|
||||
queries.map(async q => {
|
||||
const host = _.isArray(q.host) ? q.host[0] : q.host
|
||||
const url = host.replace('proxy', 'queries')
|
||||
const text = q.text
|
||||
const {data} = await getQueryConfig(url, [{query: text}], templates)
|
||||
return data.queries[0].queryAST
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
async componentWillReceiveProps(nextProps) {
|
||||
const inViewDidUpdate = this.props.inView !== nextProps.inView
|
||||
|
||||
const queriesDidUpdate = this.queryDifference(
|
||||
this.props.queries,
|
||||
nextProps.queries
|
||||
).length
|
||||
|
||||
const tempVarsDidUpdate = !_.isEqual(
|
||||
this.props.templates,
|
||||
nextProps.templates
|
||||
)
|
||||
|
||||
const shouldRefetch =
|
||||
queriesDidUpdate || tempVarsDidUpdate || inViewDidUpdate
|
||||
|
||||
if (shouldRefetch) {
|
||||
if (this.props.type === 'table') {
|
||||
const queryASTs = await this.getQueryASTs(
|
||||
nextProps.queries,
|
||||
nextProps.templates
|
||||
)
|
||||
this.setState({queryASTs})
|
||||
}
|
||||
|
||||
this.executeQueries(
|
||||
nextProps.queries,
|
||||
nextProps.templates,
|
||||
nextProps.inView
|
||||
)
|
||||
}
|
||||
|
||||
if (this.props.autoRefresh !== nextProps.autoRefresh || shouldRefetch) {
|
||||
clearInterval(this.intervalID)
|
||||
|
||||
if (nextProps.autoRefresh) {
|
||||
this.intervalID = setInterval(
|
||||
() =>
|
||||
this.executeQueries(
|
||||
nextProps.queries,
|
||||
nextProps.templates,
|
||||
nextProps.inView
|
||||
),
|
||||
nextProps.autoRefresh
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
queryDifference = (left, right) => {
|
||||
const leftStrs = left.map(q => `${q.host}${q.text}`)
|
||||
const rightStrs = right.map(q => `${q.host}${q.text}`)
|
||||
return _.difference(
|
||||
_.union(leftStrs, rightStrs),
|
||||
_.intersection(leftStrs, rightStrs)
|
||||
)
|
||||
}
|
||||
|
||||
executeQueries = async (
|
||||
queries,
|
||||
templates = [],
|
||||
inView = this.props.inView
|
||||
) => {
|
||||
const {editQueryStatus, grabDataForDownload} = this.props
|
||||
const {resolution} = this.state
|
||||
if (!inView) {
|
||||
return
|
||||
}
|
||||
if (!queries.length) {
|
||||
this.setState({timeSeries: []})
|
||||
return
|
||||
}
|
||||
|
||||
this.setState({isFetching: true})
|
||||
|
||||
const timeSeriesPromises = queries.map(query => {
|
||||
const {host, database, rp} = query
|
||||
// the key `database` was used upstream in HostPage.js, and since as of this writing
|
||||
// the codebase has not been fully converted to TypeScript, it's not clear where else
|
||||
// it may be used, but this slight modification is intended to allow for the use of
|
||||
// `database` while moving over to `db` for consistency over time
|
||||
const db = _.get(query, 'db', database)
|
||||
|
||||
const templatesWithIntervalVals = templates.map(temp => {
|
||||
if (temp.tempVar === ':interval:') {
|
||||
if (resolution) {
|
||||
// resize event
|
||||
return {
|
||||
...temp,
|
||||
values: temp.values.map(v => ({
|
||||
...v,
|
||||
value: `${_.toInteger(Number(resolution) / 3)}`,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...temp,
|
||||
values: intervalValuesPoints,
|
||||
}
|
||||
}
|
||||
return temp
|
||||
})
|
||||
|
||||
const tempVars = removeUnselectedTemplateValues(
|
||||
templatesWithIntervalVals
|
||||
)
|
||||
return fetchTimeSeriesAsync(
|
||||
{
|
||||
source: host,
|
||||
db,
|
||||
rp,
|
||||
query,
|
||||
tempVars,
|
||||
resolution,
|
||||
},
|
||||
editQueryStatus
|
||||
)
|
||||
})
|
||||
|
||||
try {
|
||||
const timeSeries = await Promise.all(timeSeriesPromises)
|
||||
const newSeries = timeSeries.map(response => ({response}))
|
||||
const lastQuerySuccessful = this._resultsForQuery(newSeries)
|
||||
|
||||
this.setState({
|
||||
timeSeries: newSeries,
|
||||
lastQuerySuccessful,
|
||||
isFetching: false,
|
||||
})
|
||||
|
||||
if (grabDataForDownload) {
|
||||
grabDataForDownload(timeSeries)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.intervalID)
|
||||
this.intervalID = false
|
||||
}
|
||||
|
||||
setResolution = resolution => {
|
||||
if (resolution !== this.state.resolution) {
|
||||
this.setState({resolution})
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {timeSeries, queryASTs} = this.state
|
||||
if (this.state.isFetching && this.state.lastQuerySuccessful) {
|
||||
return (
|
||||
<ComposedComponent
|
||||
{...this.props}
|
||||
data={timeSeries}
|
||||
setResolution={this.setResolution}
|
||||
isFetchingInitially={false}
|
||||
isRefreshing={true}
|
||||
queryASTs={queryASTs}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<ComposedComponent
|
||||
{...this.props}
|
||||
data={timeSeries}
|
||||
setResolution={this.setResolution}
|
||||
queryASTs={queryASTs}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
_resultsForQuery = data =>
|
||||
data.length
|
||||
? data.every(({response}) =>
|
||||
_.get(response, 'results', []).every(
|
||||
result =>
|
||||
Object.keys(result).filter(k => k !== 'statement_id').length !==
|
||||
0
|
||||
)
|
||||
)
|
||||
: false
|
||||
}
|
||||
|
||||
wrapper.defaultProps = {
|
||||
inView: true,
|
||||
}
|
||||
|
||||
const {
|
||||
array,
|
||||
arrayOf,
|
||||
bool,
|
||||
element,
|
||||
func,
|
||||
number,
|
||||
oneOfType,
|
||||
shape,
|
||||
string,
|
||||
} = PropTypes
|
||||
|
||||
wrapper.propTypes = {
|
||||
type: string.isRequired,
|
||||
children: element,
|
||||
autoRefresh: number.isRequired,
|
||||
inView: bool,
|
||||
templates: arrayOf(
|
||||
shape({
|
||||
type: string.isRequired,
|
||||
tempVar: string.isRequired,
|
||||
query: shape({
|
||||
db: string,
|
||||
rp: string,
|
||||
influxql: string,
|
||||
}),
|
||||
values: arrayOf(
|
||||
shape({
|
||||
type: string.isRequired,
|
||||
value: string.isRequired,
|
||||
selected: bool,
|
||||
})
|
||||
).isRequired,
|
||||
})
|
||||
),
|
||||
queries: arrayOf(
|
||||
shape({
|
||||
host: oneOfType([string, arrayOf(string)]),
|
||||
text: string,
|
||||
}).isRequired
|
||||
).isRequired,
|
||||
axes: shape({
|
||||
bounds: shape({
|
||||
y: array,
|
||||
y2: array,
|
||||
}),
|
||||
}),
|
||||
editQueryStatus: func,
|
||||
grabDataForDownload: func,
|
||||
}
|
||||
|
||||
return wrapper
|
||||
}
|
||||
|
||||
export default AutoRefresh
|
|
@ -0,0 +1,288 @@
|
|||
import React, {Component, ComponentClass} from 'react'
|
||||
import _ from 'lodash'
|
||||
|
||||
import {getQueryConfig} from 'src/shared/apis'
|
||||
import {fetchTimeSeries} from 'src/shared/apis/query'
|
||||
import {DEFAULT_TIME_SERIES} from 'src/shared/constants/series'
|
||||
import {TimeSeriesServerResponse, TimeSeriesResponse} from 'src/types/series'
|
||||
|
||||
interface Axes {
|
||||
bounds: {
|
||||
y: number[]
|
||||
y2: number[]
|
||||
}
|
||||
}
|
||||
|
||||
interface Query {
|
||||
host: string | string[]
|
||||
text: string
|
||||
database: string
|
||||
db: string
|
||||
rp: string
|
||||
}
|
||||
|
||||
interface TemplateQuery {
|
||||
db: string
|
||||
rp: string
|
||||
influxql: string
|
||||
}
|
||||
|
||||
interface TemplateValue {
|
||||
type: string
|
||||
value: string
|
||||
selected: boolean
|
||||
}
|
||||
|
||||
interface Template {
|
||||
type: string
|
||||
tempVar: string
|
||||
query: TemplateQuery
|
||||
values: TemplateValue[]
|
||||
}
|
||||
|
||||
export interface Props {
|
||||
type: string
|
||||
autoRefresh: number
|
||||
inView: boolean
|
||||
templates: Template[]
|
||||
queries: Query[]
|
||||
axes: Axes
|
||||
editQueryStatus: () => void
|
||||
grabDataForDownload: (timeSeries: TimeSeriesServerResponse[]) => void
|
||||
}
|
||||
|
||||
interface QueryAST {
|
||||
groupBy?: {
|
||||
tags: string[]
|
||||
}
|
||||
}
|
||||
|
||||
interface State {
|
||||
isFetching: boolean
|
||||
isLastQuerySuccessful: boolean
|
||||
timeSeries: TimeSeriesServerResponse[]
|
||||
resolution: number | null
|
||||
queryASTs?: QueryAST[]
|
||||
}
|
||||
|
||||
export interface OriginalProps {
|
||||
data: TimeSeriesServerResponse[]
|
||||
setResolution: (resolution: number) => void
|
||||
isFetchingInitially?: boolean
|
||||
isRefreshing?: boolean
|
||||
queryASTs?: QueryAST[]
|
||||
}
|
||||
|
||||
const AutoRefresh = (
|
||||
ComposedComponent: ComponentClass<OriginalProps & Props>
|
||||
) => {
|
||||
class Wrapper extends Component<Props, State> {
|
||||
public static defaultProps = {
|
||||
inView: true,
|
||||
}
|
||||
|
||||
private intervalID: NodeJS.Timer | null
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
isFetching: false,
|
||||
isLastQuerySuccessful: true,
|
||||
timeSeries: DEFAULT_TIME_SERIES,
|
||||
resolution: null,
|
||||
queryASTs: [],
|
||||
}
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
if (this.isTable) {
|
||||
const queryASTs = await this.getQueryASTs()
|
||||
this.setState({queryASTs})
|
||||
}
|
||||
|
||||
this.startNewPolling()
|
||||
}
|
||||
|
||||
public async componentDidUpdate(prevProps: Props) {
|
||||
if (!this.isPropsDifferent(prevProps)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.isTable) {
|
||||
const queryASTs = await this.getQueryASTs()
|
||||
this.setState({queryASTs})
|
||||
}
|
||||
|
||||
this.startNewPolling()
|
||||
}
|
||||
|
||||
public executeQueries = async () => {
|
||||
const {editQueryStatus, grabDataForDownload, inView, queries} = this.props
|
||||
const {resolution} = this.state
|
||||
|
||||
if (!inView) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!queries.length) {
|
||||
this.setState({timeSeries: DEFAULT_TIME_SERIES})
|
||||
return
|
||||
}
|
||||
|
||||
this.setState({isFetching: true})
|
||||
const templates: Template[] = _.get(this.props, 'templates', [])
|
||||
|
||||
try {
|
||||
const timeSeries = await fetchTimeSeries(
|
||||
queries,
|
||||
resolution,
|
||||
templates,
|
||||
editQueryStatus
|
||||
)
|
||||
const newSeries = timeSeries.map((response: TimeSeriesResponse) => ({
|
||||
response,
|
||||
}))
|
||||
const isLastQuerySuccessful = this.hasResultsForQuery(newSeries)
|
||||
|
||||
this.setState({
|
||||
timeSeries: newSeries,
|
||||
isLastQuerySuccessful,
|
||||
isFetching: false,
|
||||
})
|
||||
|
||||
if (grabDataForDownload) {
|
||||
grabDataForDownload(newSeries)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.clearInterval()
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {
|
||||
timeSeries,
|
||||
queryASTs,
|
||||
isFetching,
|
||||
isLastQuerySuccessful,
|
||||
} = this.state
|
||||
|
||||
const hasValues = _.some(timeSeries, s => {
|
||||
const results = _.get(s, 'response.results', [])
|
||||
const v = _.some(results, r => r.series)
|
||||
return v
|
||||
})
|
||||
|
||||
if (!hasValues) {
|
||||
return (
|
||||
<div className="graph-empty">
|
||||
<p>No Results</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (isFetching && isLastQuerySuccessful) {
|
||||
return (
|
||||
<ComposedComponent
|
||||
{...this.props}
|
||||
data={timeSeries}
|
||||
setResolution={this.setResolution}
|
||||
isFetchingInitially={false}
|
||||
isRefreshing={true}
|
||||
queryASTs={queryASTs}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<ComposedComponent
|
||||
{...this.props}
|
||||
data={timeSeries}
|
||||
setResolution={this.setResolution}
|
||||
queryASTs={queryASTs}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private setResolution = resolution => {
|
||||
if (resolution !== this.state.resolution) {
|
||||
this.setState({resolution})
|
||||
}
|
||||
}
|
||||
|
||||
private clearInterval() {
|
||||
if (!this.intervalID) {
|
||||
return
|
||||
}
|
||||
|
||||
clearInterval(this.intervalID)
|
||||
this.intervalID = null
|
||||
}
|
||||
|
||||
private isPropsDifferent(nextProps: Props) {
|
||||
return (
|
||||
this.props.inView !== nextProps.inView ||
|
||||
!!this.queryDifference(this.props.queries, nextProps.queries).length ||
|
||||
!_.isEqual(this.props.templates, nextProps.templates) ||
|
||||
this.props.autoRefresh !== nextProps.autoRefresh
|
||||
)
|
||||
}
|
||||
|
||||
private startNewPolling() {
|
||||
this.clearInterval()
|
||||
|
||||
const {autoRefresh} = this.props
|
||||
|
||||
this.executeQueries()
|
||||
|
||||
if (autoRefresh) {
|
||||
this.intervalID = setInterval(this.executeQueries, autoRefresh)
|
||||
}
|
||||
}
|
||||
|
||||
private queryDifference = (left, right) => {
|
||||
const mapper = q => `${q.host}${q.text}`
|
||||
const leftStrs = left.map(mapper)
|
||||
const rightStrs = right.map(mapper)
|
||||
return _.difference(
|
||||
_.union(leftStrs, rightStrs),
|
||||
_.intersection(leftStrs, rightStrs)
|
||||
)
|
||||
}
|
||||
|
||||
private get isTable(): boolean {
|
||||
return this.props.type === 'table'
|
||||
}
|
||||
|
||||
private getQueryASTs = async (): Promise<QueryAST[]> => {
|
||||
const {queries, templates} = this.props
|
||||
|
||||
return await Promise.all(
|
||||
queries.map(async q => {
|
||||
const host = _.isArray(q.host) ? q.host[0] : q.host
|
||||
const url = host.replace('proxy', 'queries')
|
||||
const text = q.text
|
||||
const {data} = await getQueryConfig(url, [{query: text}], templates)
|
||||
return data.queries[0].queryAST
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
private hasResultsForQuery = (data): boolean => {
|
||||
if (!data.length) {
|
||||
return false
|
||||
}
|
||||
|
||||
data.every(({resp}) =>
|
||||
_.get(resp, 'results', []).every(r => Object.keys(r).length > 1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return Wrapper
|
||||
}
|
||||
|
||||
export default AutoRefresh
|
|
@ -41,7 +41,7 @@ class AutoRefreshDropdown extends Component {
|
|||
paused: +milliseconds === 0,
|
||||
})}
|
||||
>
|
||||
<div className={classnames('dropdown dropdown-160', {open: isOpen})}>
|
||||
<div className={classnames('dropdown dropdown-120', {open: isOpen})}>
|
||||
<div
|
||||
className="btn btn-sm btn-default dropdown-toggle"
|
||||
onClick={this.toggleMenu}
|
||||
|
@ -56,7 +56,7 @@ class AutoRefreshDropdown extends Component {
|
|||
<span className="caret" />
|
||||
</div>
|
||||
<ul className="dropdown-menu">
|
||||
<li className="dropdown-header">AutoRefresh Interval</li>
|
||||
<li className="dropdown-header">AutoRefresh</li>
|
||||
{autoRefreshItems.map(item => (
|
||||
<li className="dropdown-item" key={item.menuOption}>
|
||||
<a href="#" onClick={this.handleSelection(item.milliseconds)}>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import _ from 'lodash'
|
||||
import React, {PureComponent} from 'react'
|
||||
import Dygraph from 'dygraphs'
|
||||
import {connect} from 'react-redux'
|
||||
|
@ -35,7 +36,7 @@ class Crosshair extends PureComponent<Props> {
|
|||
private get isVisible() {
|
||||
const {hoverTime} = this.props
|
||||
|
||||
return hoverTime !== 0
|
||||
return hoverTime !== 0 && _.isFinite(hoverTime)
|
||||
}
|
||||
|
||||
private get crosshairLeft(): number {
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
|
||||
class InvalidData extends PureComponent<{}> {
|
||||
public render() {
|
||||
return (
|
||||
<div className="graph-empty">
|
||||
<p>
|
||||
The data returned from the query can't be visualized with this graph
|
||||
type.<br />Try updating the query or selecting a different graph type.
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default InvalidData
|
|
@ -45,7 +45,17 @@ const Layout = (
|
|||
{
|
||||
host,
|
||||
cell,
|
||||
cell: {h, axes, type, colors, legend, tableOptions},
|
||||
cell: {
|
||||
h,
|
||||
axes,
|
||||
type,
|
||||
colors,
|
||||
legend,
|
||||
timeFormat,
|
||||
fieldOptions,
|
||||
tableOptions,
|
||||
decimalPlaces,
|
||||
},
|
||||
source,
|
||||
sources,
|
||||
onZoom,
|
||||
|
@ -87,6 +97,9 @@ const Layout = (
|
|||
type={type}
|
||||
isDragging={isDragging}
|
||||
tableOptions={tableOptions}
|
||||
fieldOptions={fieldOptions}
|
||||
timeFormat={timeFormat}
|
||||
decimalPlaces={decimalPlaces}
|
||||
staticLegend={IS_STATIC_LEGEND(legend)}
|
||||
cellHeight={h}
|
||||
onZoom={onZoom}
|
||||
|
@ -140,6 +153,28 @@ const propTypes = {
|
|||
name: string.isRequired,
|
||||
type: string.isRequired,
|
||||
colors: colorsStringSchema,
|
||||
tableOptions: shape({
|
||||
verticalTimeAxis: bool.isRequired,
|
||||
sortBy: shape({
|
||||
internalName: string.isRequired,
|
||||
displayName: string.isRequired,
|
||||
visible: bool.isRequired,
|
||||
}).isRequired,
|
||||
wrapping: string.isRequired,
|
||||
fixFirstColumn: bool.isRequired,
|
||||
}),
|
||||
timeFormat: string,
|
||||
decimalPlaces: shape({
|
||||
isEnforced: bool.isRequired,
|
||||
digits: number.isRequired,
|
||||
}),
|
||||
fieldOptions: arrayOf(
|
||||
shape({
|
||||
internalName: string.isRequired,
|
||||
displayName: string.isRequired,
|
||||
visible: bool.isRequired,
|
||||
}).isRequired
|
||||
),
|
||||
}).isRequired,
|
||||
templates: arrayOf(shape()),
|
||||
host: string,
|
||||
|
|
|
@ -173,6 +173,24 @@ LayoutRenderer.propTypes = {
|
|||
i: string.isRequired,
|
||||
name: string.isRequired,
|
||||
type: string.isRequired,
|
||||
timeFormat: string,
|
||||
tableOptions: shape({
|
||||
verticalTimeAxis: bool.isRequired,
|
||||
sortBy: shape({
|
||||
internalName: string.isRequired,
|
||||
displayName: string.isRequired,
|
||||
visible: bool.isRequired,
|
||||
}).isRequired,
|
||||
wrapping: string.isRequired,
|
||||
fixFirstColumn: bool.isRequired,
|
||||
}),
|
||||
fieldOptions: arrayOf(
|
||||
shape({
|
||||
internalName: string.isRequired,
|
||||
displayName: string.isRequired,
|
||||
visible: bool.isRequired,
|
||||
}).isRequired
|
||||
),
|
||||
}).isRequired
|
||||
),
|
||||
templates: arrayOf(shape()),
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import _ from 'lodash'
|
||||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Dygraph from 'shared/components/Dygraph'
|
||||
|
@ -6,17 +7,34 @@ import SingleStat from 'src/shared/components/SingleStat'
|
|||
import {timeSeriesToDygraph} from 'utils/timeSeriesTransformers'
|
||||
|
||||
import {colorsStringSchema} from 'shared/schemas'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import {ErrorHandlingWith} from 'src/shared/decorators/errors'
|
||||
import InvalidData from 'src/shared/components/InvalidData'
|
||||
|
||||
@ErrorHandling
|
||||
const validateTimeSeries = timeseries => {
|
||||
return _.every(timeseries, r =>
|
||||
_.every(
|
||||
r,
|
||||
(v, i) => (i === 0 && Date.parse(v)) || _.isNumber(v) || _.isNull(v)
|
||||
)
|
||||
)
|
||||
}
|
||||
@ErrorHandlingWith(InvalidData)
|
||||
class LineGraph extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.isValidData = true
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
const {data, isInDataExplorer} = this.props
|
||||
this.parseTimeSeries(data, isInDataExplorer)
|
||||
}
|
||||
|
||||
parseTimeSeries(data, isInDataExplorer) {
|
||||
this._timeSeries = timeSeriesToDygraph(data, isInDataExplorer)
|
||||
this.isValidData = validateTimeSeries(
|
||||
_.get(this._timeSeries, 'timeSeries', [])
|
||||
)
|
||||
}
|
||||
|
||||
componentWillUpdate(nextProps) {
|
||||
|
@ -25,14 +43,15 @@ class LineGraph extends Component {
|
|||
data !== nextProps.data ||
|
||||
activeQueryIndex !== nextProps.activeQueryIndex
|
||||
) {
|
||||
this._timeSeries = timeSeriesToDygraph(
|
||||
nextProps.data,
|
||||
nextProps.isInDataExplorer
|
||||
)
|
||||
this.parseTimeSeries(nextProps.data, nextProps.isInDataExplorer)
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.isValidData) {
|
||||
return <InvalidData />
|
||||
}
|
||||
|
||||
const {
|
||||
data,
|
||||
axes,
|
||||
|
|
|
@ -13,6 +13,10 @@ import TableGraph from 'shared/components/TableGraph'
|
|||
|
||||
import {colorsStringSchema} from 'shared/schemas'
|
||||
import {setHoverTime} from 'src/dashboards/actions'
|
||||
import {
|
||||
DEFAULT_TIME_FORMAT,
|
||||
DEFAULT_DECIMAL_PLACES,
|
||||
} from 'src/dashboards/constants'
|
||||
|
||||
const RefreshingLineGraph = AutoRefresh(LineGraph)
|
||||
const RefreshingSingleStat = AutoRefresh(SingleStat)
|
||||
|
@ -33,6 +37,9 @@ const RefreshingGraph = ({
|
|||
timeRange,
|
||||
cellHeight,
|
||||
autoRefresh,
|
||||
fieldOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
resizerTopHeight,
|
||||
staticLegend,
|
||||
manualRefresh, // when changed, re-mounts the component
|
||||
|
@ -44,7 +51,6 @@ const RefreshingGraph = ({
|
|||
}) => {
|
||||
const prefix = (axes && axes.y.prefix) || ''
|
||||
const suffix = (axes && axes.y.suffix) || ''
|
||||
|
||||
if (!queries.length) {
|
||||
return (
|
||||
<div className="graph-empty">
|
||||
|
@ -63,6 +69,7 @@ const RefreshingGraph = ({
|
|||
templates={templates}
|
||||
autoRefresh={autoRefresh}
|
||||
cellHeight={cellHeight}
|
||||
editQueryStatus={editQueryStatus}
|
||||
prefix={prefix}
|
||||
suffix={suffix}
|
||||
inView={inView}
|
||||
|
@ -81,6 +88,7 @@ const RefreshingGraph = ({
|
|||
autoRefresh={autoRefresh}
|
||||
cellHeight={cellHeight}
|
||||
resizerTopHeight={resizerTopHeight}
|
||||
editQueryStatus={editQueryStatus}
|
||||
resizeCoords={resizeCoords}
|
||||
cellID={cellID}
|
||||
prefix={prefix}
|
||||
|
@ -105,6 +113,10 @@ const RefreshingGraph = ({
|
|||
cellHeight={cellHeight}
|
||||
resizeCoords={resizeCoords}
|
||||
tableOptions={tableOptions}
|
||||
fieldOptions={fieldOptions}
|
||||
timeFormat={timeFormat}
|
||||
decimalPlaces={decimalPlaces}
|
||||
editQueryStatus={editQueryStatus}
|
||||
resizerTopHeight={resizerTopHeight}
|
||||
handleSetHoverTime={handleSetHoverTime}
|
||||
isInCEO={isInCEO}
|
||||
|
@ -164,7 +176,28 @@ RefreshingGraph.propTypes = {
|
|||
colors: colorsStringSchema,
|
||||
cellID: string,
|
||||
inView: bool,
|
||||
tableOptions: shape({}),
|
||||
tableOptions: shape({
|
||||
verticalTimeAxis: bool.isRequired,
|
||||
sortBy: shape({
|
||||
internalName: string.isRequired,
|
||||
displayName: string.isRequired,
|
||||
visible: bool.isRequired,
|
||||
}).isRequired,
|
||||
wrapping: string.isRequired,
|
||||
fixFirstColumn: bool.isRequired,
|
||||
}),
|
||||
fieldOptions: arrayOf(
|
||||
shape({
|
||||
internalName: string.isRequired,
|
||||
displayName: string.isRequired,
|
||||
visible: bool.isRequired,
|
||||
}).isRequired
|
||||
),
|
||||
timeFormat: string.isRequired,
|
||||
decimalPlaces: shape({
|
||||
isEnforced: bool.isRequired,
|
||||
digits: number.isRequired,
|
||||
}).isRequired,
|
||||
hoverTime: string.isRequired,
|
||||
handleSetHoverTime: func.isRequired,
|
||||
isInCEO: bool,
|
||||
|
@ -174,6 +207,8 @@ RefreshingGraph.defaultProps = {
|
|||
manualRefresh: 0,
|
||||
staticLegend: false,
|
||||
inView: true,
|
||||
timeFormat: DEFAULT_TIME_FORMAT,
|
||||
decimalPlaces: DEFAULT_DECIMAL_PLACES,
|
||||
}
|
||||
|
||||
const mapStateToProps = ({dashboardUI, annotations: {mode}}) => ({
|
||||
|
|
|
@ -9,27 +9,22 @@ import {bindActionCreators} from 'redux'
|
|||
import moment from 'moment'
|
||||
import {reduce} from 'fast.js'
|
||||
|
||||
const {arrayOf, bool, shape, string, func} = PropTypes
|
||||
|
||||
import {timeSeriesToTableGraph} from 'src/utils/timeSeriesTransformers'
|
||||
import {
|
||||
computeFieldNames,
|
||||
computeFieldOptions,
|
||||
transformTableData,
|
||||
} from 'src/dashboards/utils/tableGraph'
|
||||
import {updateTableOptions} from 'src/dashboards/actions/cellEditorOverlay'
|
||||
|
||||
import {updateFieldOptions} from 'src/dashboards/actions/cellEditorOverlay'
|
||||
import {DEFAULT_TIME_FIELD} from 'src/dashboards/constants'
|
||||
import {
|
||||
NULL_ARRAY_INDEX,
|
||||
NULL_HOVER_TIME,
|
||||
DEFAULT_TIME_FORMAT,
|
||||
TIME_FIELD_DEFAULT,
|
||||
ASCENDING,
|
||||
DESCENDING,
|
||||
NULL_HOVER_TIME,
|
||||
NULL_ARRAY_INDEX,
|
||||
DEFAULT_FIX_FIRST_COLUMN,
|
||||
DEFAULT_VERTICAL_TIME_AXIS,
|
||||
DEFAULT_SORT_DIRECTION,
|
||||
FIX_FIRST_COLUMN_DEFAULT,
|
||||
VERTICAL_TIME_AXIS_DEFAULT,
|
||||
} from 'src/shared/constants/tableGraph'
|
||||
|
||||
import {generateThresholdsListHexs} from 'shared/constants/colorOperations'
|
||||
import {colorsStringSchema} from 'shared/schemas'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
@ -42,7 +37,7 @@ class TableGraph extends Component {
|
|||
const sortField = _.get(
|
||||
this.props,
|
||||
['tableOptions', 'sortBy', 'internalName'],
|
||||
TIME_FIELD_DEFAULT.internalName
|
||||
DEFAULT_TIME_FIELD.internalName
|
||||
)
|
||||
|
||||
this.state = {
|
||||
|
@ -58,19 +53,19 @@ class TableGraph extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
handleUpdateTableOptions = (fieldNames, tableOptions) => {
|
||||
handleUpdateFieldOptions = fieldOptions => {
|
||||
const {isInCEO} = this.props
|
||||
if (!isInCEO) {
|
||||
return
|
||||
}
|
||||
this.props.handleUpdateTableOptions({...tableOptions, fieldNames})
|
||||
this.props.handleUpdateFieldOptions(fieldOptions)
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const updatedProps = _.keys(nextProps).filter(
|
||||
k => !_.isEqual(this.props[k], nextProps[k])
|
||||
)
|
||||
const {tableOptions} = nextProps
|
||||
const {tableOptions, fieldOptions, timeFormat, decimalPlaces} = nextProps
|
||||
|
||||
let result = {}
|
||||
|
||||
|
@ -80,10 +75,11 @@ class TableGraph extends Component {
|
|||
|
||||
const data = _.get(result, 'data', this.state.data)
|
||||
const sortedLabels = _.get(result, 'sortedLabels', this.state.sortedLabels)
|
||||
const fieldNames = computeFieldNames(tableOptions.fieldNames, sortedLabels)
|
||||
|
||||
const computedFieldOptions = computeFieldOptions(fieldOptions, sortedLabels)
|
||||
|
||||
if (_.includes(updatedProps, 'data')) {
|
||||
this.handleUpdateTableOptions(fieldNames, tableOptions)
|
||||
this.handleUpdateFieldOptions(computedFieldOptions)
|
||||
}
|
||||
|
||||
if (_.isEmpty(data[0])) {
|
||||
|
@ -106,14 +102,23 @@ class TableGraph extends Component {
|
|||
|
||||
if (
|
||||
_.includes(updatedProps, 'data') ||
|
||||
_.includes(updatedProps, 'tableOptions')
|
||||
_.includes(updatedProps, 'tableOptions') ||
|
||||
_.includes(updatedProps, 'fieldOptions') ||
|
||||
_.includes(updatedProps, 'timeFormat')
|
||||
) {
|
||||
const {
|
||||
transformedData,
|
||||
sortedTimeVals,
|
||||
columnWidths,
|
||||
totalWidths,
|
||||
} = transformTableData(data, sort, fieldNames, tableOptions)
|
||||
} = transformTableData(
|
||||
data,
|
||||
sort,
|
||||
computedFieldOptions,
|
||||
tableOptions,
|
||||
timeFormat,
|
||||
decimalPlaces
|
||||
)
|
||||
|
||||
this.setState({
|
||||
data,
|
||||
|
@ -186,34 +191,30 @@ class TableGraph extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
handleClickFieldName = fieldName => () => {
|
||||
const {tableOptions} = this.props
|
||||
const {timeFormat} = tableOptions
|
||||
const {data, sortField, sortDirection} = this.state
|
||||
const verticalTimeAxis = _.get(tableOptions, 'verticalTimeAxis', true)
|
||||
const fieldNames = _.get(tableOptions, 'fieldNames', [TIME_FIELD_DEFAULT])
|
||||
handleClickFieldName = clickedFieldName => () => {
|
||||
const {tableOptions, fieldOptions, timeFormat, decimalPlaces} = this.props
|
||||
const {data, sort} = this.state
|
||||
|
||||
let direction
|
||||
if (fieldName === sortField) {
|
||||
direction = sortDirection === ASCENDING ? DESCENDING : ASCENDING
|
||||
if (clickedFieldName === sort.field) {
|
||||
sort.direction = sort.direction === ASCENDING ? DESCENDING : ASCENDING
|
||||
} else {
|
||||
direction = DEFAULT_SORT_DIRECTION
|
||||
sort.field = clickedFieldName
|
||||
sort.direction = DEFAULT_SORT_DIRECTION
|
||||
}
|
||||
|
||||
const {transformedData, sortedTimeVals} = transformTableData(
|
||||
data,
|
||||
fieldName,
|
||||
direction,
|
||||
verticalTimeAxis,
|
||||
fieldNames,
|
||||
timeFormat
|
||||
sort,
|
||||
fieldOptions,
|
||||
tableOptions,
|
||||
timeFormat,
|
||||
decimalPlaces
|
||||
)
|
||||
|
||||
this.setState({
|
||||
transformedData,
|
||||
sortedTimeVals,
|
||||
sortField: fieldName,
|
||||
sortDirection: direction,
|
||||
sort,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -246,30 +247,52 @@ class TableGraph extends Component {
|
|||
return adjustedColumnSizerWidth
|
||||
}
|
||||
|
||||
createCellContents = (
|
||||
cellData,
|
||||
fieldName,
|
||||
isTimeData,
|
||||
isFieldName,
|
||||
isNumerical
|
||||
) => {
|
||||
const {timeFormat, decimalPlaces} = this.props
|
||||
if (isTimeData) {
|
||||
return `${moment(cellData).format(timeFormat)}`
|
||||
}
|
||||
if (isFieldName) {
|
||||
return fieldName
|
||||
}
|
||||
if (isNumerical && decimalPlaces.isEnforced) {
|
||||
return cellData.toFixed(decimalPlaces.digits)
|
||||
}
|
||||
return `${cellData}`
|
||||
}
|
||||
|
||||
cellRenderer = ({columnIndex, rowIndex, key, parent, style}) => {
|
||||
const {
|
||||
hoveredColumnIndex,
|
||||
hoveredRowIndex,
|
||||
transformedData,
|
||||
sortField,
|
||||
sortDirection,
|
||||
sort,
|
||||
} = this.state
|
||||
const {tableOptions, colors} = parent.props
|
||||
|
||||
const {
|
||||
timeFormat = DEFAULT_TIME_FORMAT,
|
||||
verticalTimeAxis = VERTICAL_TIME_AXIS_DEFAULT,
|
||||
fixFirstColumn = FIX_FIRST_COLUMN_DEFAULT,
|
||||
fieldNames = [TIME_FIELD_DEFAULT],
|
||||
fieldOptions = [DEFAULT_TIME_FIELD],
|
||||
tableOptions,
|
||||
colors,
|
||||
} = parent.props
|
||||
|
||||
const {
|
||||
verticalTimeAxis = DEFAULT_VERTICAL_TIME_AXIS,
|
||||
fixFirstColumn = DEFAULT_FIX_FIRST_COLUMN,
|
||||
} = tableOptions
|
||||
|
||||
const cellData = transformedData[rowIndex][columnIndex]
|
||||
|
||||
const timeFieldIndex = fieldNames.findIndex(
|
||||
field => field.internalName === TIME_FIELD_DEFAULT.internalName
|
||||
const timeFieldIndex = fieldOptions.findIndex(
|
||||
field => field.internalName === DEFAULT_TIME_FIELD.internalName
|
||||
)
|
||||
|
||||
const visibleTime = _.get(fieldNames, [timeFieldIndex, 'visible'], true)
|
||||
const visibleTime = _.get(fieldOptions, [timeFieldIndex, 'visible'], true)
|
||||
|
||||
const isFixedRow = rowIndex === 0 && columnIndex > 0
|
||||
const isFixedColumn = fixFirstColumn && rowIndex > 0 && columnIndex === 0
|
||||
|
@ -280,7 +303,7 @@ class TableGraph extends Component {
|
|||
: rowIndex === timeFieldIndex && columnIndex !== 0)
|
||||
const isFieldName = verticalTimeAxis ? rowIndex === 0 : columnIndex === 0
|
||||
const isFixedCorner = rowIndex === 0 && columnIndex === 0
|
||||
const dataIsNumerical = _.isNumber(cellData)
|
||||
const isNumerical = _.isNumber(cellData)
|
||||
const isHighlightedRow =
|
||||
rowIndex === parent.props.scrollToRow ||
|
||||
(rowIndex === hoveredRowIndex && hoveredRowIndex !== 0)
|
||||
|
@ -305,7 +328,7 @@ class TableGraph extends Component {
|
|||
}
|
||||
|
||||
const foundField =
|
||||
isFieldName && fieldNames.find(field => field.internalName === cellData)
|
||||
isFieldName && fieldOptions.find(field => field.internalName === cellData)
|
||||
const fieldName =
|
||||
foundField && (foundField.displayName || foundField.internalName)
|
||||
|
||||
|
@ -315,19 +338,21 @@ class TableGraph extends Component {
|
|||
'table-graph-cell__fixed-corner': isFixedCorner,
|
||||
'table-graph-cell__highlight-row': isHighlightedRow,
|
||||
'table-graph-cell__highlight-column': isHighlightedColumn,
|
||||
'table-graph-cell__numerical': dataIsNumerical,
|
||||
'table-graph-cell__numerical': isNumerical,
|
||||
'table-graph-cell__field-name': isFieldName,
|
||||
'table-graph-cell__sort-asc':
|
||||
isFieldName && sortField === cellData && sortDirection === ASCENDING,
|
||||
isFieldName && sort.field === cellData && sort.direction === ASCENDING,
|
||||
'table-graph-cell__sort-desc':
|
||||
isFieldName && sortField === cellData && sortDirection === DESCENDING,
|
||||
isFieldName && sort.field === cellData && sort.direction === DESCENDING,
|
||||
})
|
||||
|
||||
const cellContents = isTimeData
|
||||
? `${moment(cellData).format(
|
||||
timeFormat === '' ? DEFAULT_TIME_FORMAT : timeFormat
|
||||
)}`
|
||||
: fieldName || `${cellData}`
|
||||
const cellContents = this.createCellContents(
|
||||
cellData,
|
||||
fieldName,
|
||||
isTimeData,
|
||||
isFieldName,
|
||||
isNumerical
|
||||
)
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -353,12 +378,18 @@ class TableGraph extends Component {
|
|||
hoveredColumnIndex,
|
||||
hoveredRowIndex,
|
||||
timeColumnWidth,
|
||||
sortField,
|
||||
sortDirection,
|
||||
sort,
|
||||
transformedData,
|
||||
} = this.state
|
||||
const {hoverTime, tableOptions, colors} = this.props
|
||||
const {fixFirstColumn = FIX_FIRST_COLUMN_DEFAULT} = tableOptions
|
||||
const {
|
||||
hoverTime,
|
||||
tableOptions,
|
||||
colors,
|
||||
fieldOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
} = this.props
|
||||
const {fixFirstColumn = DEFAULT_FIX_FIRST_COLUMN} = tableOptions
|
||||
const columnCount = _.get(transformedData, ['0', 'length'], 0)
|
||||
const rowCount = columnCount === 0 ? 0 : transformedData.length
|
||||
|
||||
|
@ -399,14 +430,16 @@ class TableGraph extends Component {
|
|||
enableFixedRowScroll={true}
|
||||
scrollToRow={scrollToRow}
|
||||
scrollToColumn={scrollToColumn}
|
||||
sortField={sortField}
|
||||
sortDirection={sortDirection}
|
||||
sort={sort}
|
||||
cellRenderer={this.cellRenderer}
|
||||
hoveredColumnIndex={hoveredColumnIndex}
|
||||
hoveredRowIndex={hoveredRowIndex}
|
||||
hoverTime={hoverTime}
|
||||
colors={colors}
|
||||
fieldOptions={fieldOptions}
|
||||
tableOptions={tableOptions}
|
||||
timeFormat={timeFormat}
|
||||
decimalPlaces={decimalPlaces}
|
||||
timeColumnWidth={timeColumnWidth}
|
||||
classNameBottomRightGrid="table-graph--scroll-window"
|
||||
/>
|
||||
|
@ -417,11 +450,11 @@ class TableGraph extends Component {
|
|||
)
|
||||
}
|
||||
}
|
||||
const {arrayOf, bool, number, shape, string, func} = PropTypes
|
||||
|
||||
TableGraph.propTypes = {
|
||||
data: arrayOf(shape()),
|
||||
tableOptions: shape({
|
||||
timeFormat: string.isRequired,
|
||||
verticalTimeAxis: bool.isRequired,
|
||||
sortBy: shape({
|
||||
internalName: string.isRequired,
|
||||
|
@ -429,17 +462,22 @@ TableGraph.propTypes = {
|
|||
visible: bool.isRequired,
|
||||
}).isRequired,
|
||||
wrapping: string.isRequired,
|
||||
fieldNames: arrayOf(
|
||||
shape({
|
||||
internalName: string.isRequired,
|
||||
displayName: string.isRequired,
|
||||
visible: bool.isRequired,
|
||||
})
|
||||
).isRequired,
|
||||
fixFirstColumn: bool,
|
||||
fixFirstColumn: bool.isRequired,
|
||||
}),
|
||||
timeFormat: string.isRequired,
|
||||
decimalPlaces: shape({
|
||||
isEnforced: bool.isRequired,
|
||||
digits: number.isRequired,
|
||||
}).isRequired,
|
||||
fieldOptions: arrayOf(
|
||||
shape({
|
||||
internalName: string.isRequired,
|
||||
displayName: string.isRequired,
|
||||
visible: bool.isRequired,
|
||||
})
|
||||
).isRequired,
|
||||
hoverTime: string,
|
||||
handleUpdateTableOptions: func,
|
||||
handleUpdateFieldOptions: func,
|
||||
handleSetHoverTime: func,
|
||||
colors: colorsStringSchema,
|
||||
queryASTs: arrayOf(shape()),
|
||||
|
@ -447,7 +485,7 @@ TableGraph.propTypes = {
|
|||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
handleUpdateTableOptions: bindActionCreators(updateTableOptions, dispatch),
|
||||
handleUpdateFieldOptions: bindActionCreators(updateFieldOptions, dispatch),
|
||||
})
|
||||
|
||||
export default connect(null, mapDispatchToProps)(TableGraph)
|
||||
|
|
|
@ -85,7 +85,7 @@ class TimeRangeDropdown extends Component {
|
|||
<div className="time-range-dropdown">
|
||||
<div
|
||||
className={classnames('dropdown', {
|
||||
'dropdown-160': isRelativeTimeRange,
|
||||
'dropdown-120': isRelativeTimeRange,
|
||||
'dropdown-210': isNow,
|
||||
'dropdown-290': !isRelativeTimeRange && !isNow,
|
||||
open: isOpen,
|
||||
|
@ -109,7 +109,7 @@ class TimeRangeDropdown extends Component {
|
|||
>
|
||||
{preventCustomTimeRange ? null : (
|
||||
<div>
|
||||
<li className="dropdown-header">Absolute Time Ranges</li>
|
||||
<li className="dropdown-header">Absolute Time</li>
|
||||
<li
|
||||
className={
|
||||
isCustomTimeRangeOpen
|
||||
|
@ -118,13 +118,13 @@ class TimeRangeDropdown extends Component {
|
|||
}
|
||||
>
|
||||
<a href="#" onClick={this.showCustomTimeRange}>
|
||||
Custom Date Picker
|
||||
Date Picker
|
||||
</a>
|
||||
</li>
|
||||
</div>
|
||||
)}
|
||||
<li className="dropdown-header">
|
||||
{preventCustomTimeRange ? '' : 'Relative '}Time Ranges
|
||||
{preventCustomTimeRange ? '' : 'Relative '}Time
|
||||
</li>
|
||||
{timeRanges.map(item => {
|
||||
return (
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
export const DEFAULT_TIME_SERIES = [
|
||||
{
|
||||
response: {
|
||||
results: [],
|
||||
},
|
||||
},
|
||||
]
|
|
@ -2,43 +2,11 @@ export const NULL_ARRAY_INDEX = -1
|
|||
|
||||
export const NULL_HOVER_TIME = '0'
|
||||
|
||||
export const TIME_FORMAT_TOOLTIP_LINK =
|
||||
'http://momentjs.com/docs/#/parsing/string-format/'
|
||||
|
||||
export const TIME_FIELD_DEFAULT = {
|
||||
internalName: 'time',
|
||||
displayName: '',
|
||||
visible: true,
|
||||
}
|
||||
|
||||
export const ASCENDING = 'asc'
|
||||
export const DESCENDING = 'desc'
|
||||
export const DEFAULT_SORT_DIRECTION = ASCENDING
|
||||
|
||||
export const FIX_FIRST_COLUMN_DEFAULT = true
|
||||
export const VERTICAL_TIME_AXIS_DEFAULT = true
|
||||
export const DEFAULT_FIX_FIRST_COLUMN = true
|
||||
export const DEFAULT_VERTICAL_TIME_AXIS = true
|
||||
|
||||
export const CELL_HORIZONTAL_PADDING = 30
|
||||
|
||||
export const DEFAULT_TIME_FORMAT = 'MM/DD/YYYY HH:mm:ss'
|
||||
export const TIME_FORMAT_CUSTOM = 'Custom'
|
||||
|
||||
export const FORMAT_OPTIONS = [
|
||||
{text: DEFAULT_TIME_FORMAT},
|
||||
{text: 'MM/DD/YYYY HH:mm:ss.SSS'},
|
||||
{text: 'YYYY-MM-DD HH:mm:ss'},
|
||||
{text: 'HH:mm:ss'},
|
||||
{text: 'HH:mm:ss.SSS'},
|
||||
{text: 'MMMM D, YYYY HH:mm:ss'},
|
||||
{text: 'dddd, MMMM D, YYYY HH:mm:ss'},
|
||||
{text: TIME_FORMAT_CUSTOM},
|
||||
]
|
||||
|
||||
export const DEFAULT_TABLE_OPTIONS = {
|
||||
verticalTimeAxis: VERTICAL_TIME_AXIS_DEFAULT,
|
||||
timeFormat: DEFAULT_TIME_FORMAT,
|
||||
sortBy: TIME_FIELD_DEFAULT,
|
||||
wrapping: 'truncate',
|
||||
fieldNames: [TIME_FIELD_DEFAULT],
|
||||
fixFirstColumn: FIX_FIRST_COLUMN_DEFAULT,
|
||||
}
|
||||
|
|
|
@ -2,28 +2,28 @@ const autoRefreshItems = [
|
|||
{milliseconds: 0, inputValue: 'Paused', menuOption: 'Paused'},
|
||||
{
|
||||
milliseconds: 5000,
|
||||
inputValue: 'Every 5 seconds',
|
||||
menuOption: 'Every 5 seconds',
|
||||
inputValue: 'Every 5s',
|
||||
menuOption: 'Every 5s',
|
||||
},
|
||||
{
|
||||
milliseconds: 10000,
|
||||
inputValue: 'Every 10 seconds',
|
||||
menuOption: 'Every 10 seconds',
|
||||
inputValue: 'Every 10s',
|
||||
menuOption: 'Every 10s',
|
||||
},
|
||||
{
|
||||
milliseconds: 15000,
|
||||
inputValue: 'Every 15 seconds',
|
||||
menuOption: 'Every 15 seconds',
|
||||
inputValue: 'Every 15s',
|
||||
menuOption: 'Every 15s',
|
||||
},
|
||||
{
|
||||
milliseconds: 30000,
|
||||
inputValue: 'Every 30 seconds',
|
||||
menuOption: 'Every 30 seconds',
|
||||
inputValue: 'Every 30s',
|
||||
menuOption: 'Every 30s',
|
||||
},
|
||||
{
|
||||
milliseconds: 60000,
|
||||
inputValue: 'Every 60 seconds',
|
||||
menuOption: 'Every 60 seconds',
|
||||
inputValue: 'Every 60s',
|
||||
menuOption: 'Every 60s',
|
||||
},
|
||||
]
|
||||
|
||||
|
|
|
@ -2,73 +2,73 @@ export const timeRanges = [
|
|||
{
|
||||
defaultGroupBy: '10s',
|
||||
seconds: 300,
|
||||
inputValue: 'Past 5 minutes',
|
||||
inputValue: 'Past 5m',
|
||||
lower: 'now() - 5m',
|
||||
upper: null,
|
||||
menuOption: 'Past 5 minutes',
|
||||
menuOption: 'Past 5m',
|
||||
},
|
||||
{
|
||||
defaultGroupBy: '1m',
|
||||
seconds: 900,
|
||||
inputValue: 'Past 15 minutes',
|
||||
inputValue: 'Past 15m',
|
||||
lower: 'now() - 15m',
|
||||
upper: null,
|
||||
menuOption: 'Past 15 minutes',
|
||||
menuOption: 'Past 15m',
|
||||
},
|
||||
{
|
||||
defaultGroupBy: '1m',
|
||||
seconds: 3600,
|
||||
inputValue: 'Past hour',
|
||||
inputValue: 'Past 1h',
|
||||
lower: 'now() - 1h',
|
||||
upper: null,
|
||||
menuOption: 'Past hour',
|
||||
menuOption: 'Past 1h',
|
||||
},
|
||||
{
|
||||
defaultGroupBy: '1m',
|
||||
seconds: 21600,
|
||||
inputValue: 'Past 6 hours',
|
||||
inputValue: 'Past 6h',
|
||||
lower: 'now() - 6h',
|
||||
upper: null,
|
||||
menuOption: 'Past 6 hours',
|
||||
menuOption: 'Past 6h',
|
||||
},
|
||||
{
|
||||
defaultGroupBy: '5m',
|
||||
seconds: 43200,
|
||||
inputValue: 'Past 12 hours',
|
||||
inputValue: 'Past 12h',
|
||||
lower: 'now() - 12h',
|
||||
upper: null,
|
||||
menuOption: 'Past 12 hours',
|
||||
menuOption: 'Past 12h',
|
||||
},
|
||||
{
|
||||
defaultGroupBy: '10m',
|
||||
seconds: 86400,
|
||||
inputValue: 'Past 24 hours',
|
||||
inputValue: 'Past 24h',
|
||||
lower: 'now() - 24h',
|
||||
upper: null,
|
||||
menuOption: 'Past 24 hours',
|
||||
menuOption: 'Past 24h',
|
||||
},
|
||||
{
|
||||
defaultGroupBy: '30m',
|
||||
seconds: 172800,
|
||||
inputValue: 'Past 2 days',
|
||||
inputValue: 'Past 2d',
|
||||
lower: 'now() - 2d',
|
||||
upper: null,
|
||||
menuOption: 'Past 2 days',
|
||||
menuOption: 'Past 2d',
|
||||
},
|
||||
{
|
||||
defaultGroupBy: '1h',
|
||||
seconds: 604800,
|
||||
inputValue: 'Past 7 days',
|
||||
inputValue: 'Past 7d',
|
||||
lower: 'now() - 7d',
|
||||
upper: null,
|
||||
menuOption: 'Past 7 days',
|
||||
menuOption: 'Past 7d',
|
||||
},
|
||||
{
|
||||
defaultGroupBy: '6h',
|
||||
seconds: 2592000,
|
||||
inputValue: 'Past 30 days',
|
||||
inputValue: 'Past 30d',
|
||||
lower: 'now() - 30d',
|
||||
upper: null,
|
||||
menuOption: 'Past 30 days',
|
||||
menuOption: 'Past 30d',
|
||||
},
|
||||
]
|
||||
|
|
|
@ -122,14 +122,16 @@ class SideNav extends PureComponent<Props> {
|
|||
<NavBlock
|
||||
highlightWhen={['admin-chronograf', 'admin-influxdb']}
|
||||
icon="crown2"
|
||||
link={`${sourcePrefix}/admin-chronograf`}
|
||||
link={`${sourcePrefix}/admin-chronograf/current-organization`}
|
||||
location={location}
|
||||
>
|
||||
<NavHeader
|
||||
link={`${sourcePrefix}/admin-chronograf`}
|
||||
link={`${sourcePrefix}/admin-chronograf/current-organization`}
|
||||
title="Admin"
|
||||
/>
|
||||
<NavListItem link={`${sourcePrefix}/admin-chronograf`}>
|
||||
<NavListItem
|
||||
link={`${sourcePrefix}/admin-chronograf/current-organization`}
|
||||
>
|
||||
Chronograf
|
||||
</NavListItem>
|
||||
<NavListItem link={`${sourcePrefix}/admin-influxdb/databases`}>
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
width: auto;
|
||||
display: flex;
|
||||
color: $ix-text-default;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: $ix-marg-a;
|
||||
font-family: $ix-text-font;
|
||||
font-weight: 500;
|
||||
|
|
|
@ -21,12 +21,10 @@ interface FieldName {
|
|||
}
|
||||
|
||||
interface TableOptions {
|
||||
timeFormat: string
|
||||
verticalTimeAxis: boolean
|
||||
sortBy: FieldName
|
||||
wrapping: string
|
||||
fixFirstColumn: boolean
|
||||
fieldNames: FieldName[]
|
||||
}
|
||||
|
||||
interface CellLinks {
|
||||
|
@ -43,6 +41,11 @@ export interface Legend {
|
|||
orientation?: string
|
||||
}
|
||||
|
||||
interface DecimalPlaces {
|
||||
isEnforced: boolean
|
||||
digits: number
|
||||
}
|
||||
|
||||
export interface Cell {
|
||||
id: string
|
||||
x: number
|
||||
|
@ -55,6 +58,9 @@ export interface Cell {
|
|||
axes: Axes
|
||||
colors: ColorString[]
|
||||
tableOptions: TableOptions
|
||||
fieldOptions: FieldName[]
|
||||
timeFormat: string
|
||||
decimalPlaces: DecimalPlaces
|
||||
links: CellLinks
|
||||
legend: Legend
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
// function definitions
|
||||
export type OnDeleteFuncNode = (funcID: string, expressionID: string) => void
|
||||
export type OnDeleteFuncNode = (ids: DeleteFuncNodeArgs) => void
|
||||
export type OnChangeArg = (inputArg: InputArg) => void
|
||||
export type OnAddNode = (expressionID: string, funcName: string) => void
|
||||
export type OnAddNode = (
|
||||
bodyID: string,
|
||||
funcName: string,
|
||||
declarationID: string
|
||||
) => void
|
||||
export type OnGenerateScript = (script: string) => void
|
||||
export type OnChangeScript = (script: string) => void
|
||||
export type OnSubmitScript = () => void
|
||||
|
@ -15,9 +19,16 @@ export interface Handlers {
|
|||
onGenerateScript: OnGenerateScript
|
||||
}
|
||||
|
||||
export interface DeleteFuncNodeArgs {
|
||||
funcID: string
|
||||
bodyID: string
|
||||
declarationID?: string
|
||||
}
|
||||
|
||||
export interface InputArg {
|
||||
funcID: string
|
||||
expressionID: string
|
||||
bodyID: string
|
||||
declarationID?: string
|
||||
key: string
|
||||
value: string | boolean
|
||||
generate?: boolean
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
export type TimeSeriesValue = string | number | Date | null
|
||||
|
||||
export interface Series {
|
||||
name: string
|
||||
columns: string[]
|
||||
values: TimeSeriesValue[]
|
||||
}
|
||||
|
||||
export interface Result {
|
||||
series: Series[]
|
||||
statement_id: number
|
||||
}
|
||||
|
||||
export interface TimeSeriesResponse {
|
||||
results: Result[]
|
||||
}
|
||||
|
||||
export interface TimeSeriesServerResponse {
|
||||
response: TimeSeriesResponse
|
||||
}
|
|
@ -2,8 +2,11 @@ import _ from 'lodash'
|
|||
import {shiftDate} from 'shared/query/helpers'
|
||||
import {map, reduce, forEach, concat, clone} from 'fast.js'
|
||||
|
||||
const groupByMap = (responses, responseIndex, groupByColumns) => {
|
||||
const firstColumns = _.get(responses, [0, 'series', 0, 'columns'])
|
||||
const groupByMap = (results, responseIndex, groupByColumns) => {
|
||||
if (_.isEmpty(results)) {
|
||||
return []
|
||||
}
|
||||
const firstColumns = _.get(results, [0, 'series', 0, 'columns'])
|
||||
const accum = [
|
||||
{
|
||||
responseIndex,
|
||||
|
@ -15,14 +18,14 @@ const groupByMap = (responses, responseIndex, groupByColumns) => {
|
|||
...firstColumns.slice(1),
|
||||
],
|
||||
groupByColumns,
|
||||
name: _.get(responses, [0, 'series', 0, 'name']),
|
||||
name: _.get(results, [0, 'series', 0, 'name'], ''),
|
||||
values: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
const seriesArray = _.get(responses, [0, 'series'])
|
||||
const seriesArray = _.get(results, [0, 'series'])
|
||||
seriesArray.forEach(s => {
|
||||
const prevValues = accum[0].series[0].values
|
||||
const tagsToAdd = groupByColumns.map(gb => s.tags[gb])
|
||||
|
@ -35,13 +38,14 @@ const groupByMap = (responses, responseIndex, groupByColumns) => {
|
|||
const constructResults = (raw, groupBys) => {
|
||||
return _.flatten(
|
||||
map(raw, (response, index) => {
|
||||
const responses = _.get(response, 'response.results', [])
|
||||
const results = _.get(response, 'response.results', [])
|
||||
|
||||
const successfulResults = _.filter(results, r => _.isNil(r.error))
|
||||
|
||||
if (groupBys[index]) {
|
||||
return groupByMap(responses, index, groupBys[index])
|
||||
return groupByMap(successfulResults, index, groupBys[index])
|
||||
}
|
||||
|
||||
return map(responses, r => ({...r, responseIndex: index}))
|
||||
return map(successfulResults, r => ({...r, responseIndex: index}))
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -81,22 +85,24 @@ const constructCells = serieses => {
|
|||
name: measurement,
|
||||
columns,
|
||||
groupByColumns,
|
||||
values,
|
||||
values = [],
|
||||
seriesIndex,
|
||||
responseIndex,
|
||||
tags = {},
|
||||
},
|
||||
ind
|
||||
) => {
|
||||
const rows = map(values || [], vals => ({
|
||||
vals,
|
||||
}))
|
||||
const rows = map(values, vals => ({vals}))
|
||||
|
||||
const tagSet = map(Object.keys(tags), tag => `[${tag}=${tags[tag]}]`)
|
||||
.sort()
|
||||
.join('')
|
||||
|
||||
const unsortedLabels = map(columns.slice(1), (field, i) => ({
|
||||
label:
|
||||
groupByColumns && i <= groupByColumns.length - 1
|
||||
? `${field}`
|
||||
: `${measurement}.${field}`,
|
||||
: `${measurement}.${field}${tagSet}`,
|
||||
responseIndex,
|
||||
seriesIndex,
|
||||
}))
|
||||
|
@ -221,8 +227,8 @@ export const groupByTimeSeriesTransform = (raw, groupBys) => {
|
|||
if (!groupBys) {
|
||||
groupBys = Array(raw.length).fill(false)
|
||||
}
|
||||
const results = constructResults(raw, groupBys)
|
||||
|
||||
const results = constructResults(raw, groupBys)
|
||||
const serieses = constructSerieses(results)
|
||||
|
||||
const {cells, sortedLabels, seriesLabels} = constructCells(serieses)
|
||||
|
|
|
@ -8,7 +8,7 @@ import QuestionMarkTooltip from 'src/shared/components/QuestionMarkTooltip'
|
|||
import {
|
||||
TIME_FORMAT_CUSTOM,
|
||||
TIME_FORMAT_TOOLTIP_LINK,
|
||||
} from 'src/shared/constants/tableGraph'
|
||||
} from 'src/dashboards/constants'
|
||||
|
||||
const setup = (override = {}) => {
|
||||
const props = {
|
||||
|
|
|
@ -12,17 +12,22 @@ import ThresholdsListTypeToggle from 'src/shared/components/ThresholdsListTypeTo
|
|||
|
||||
const defaultProps = {
|
||||
handleUpdateTableOptions: () => {},
|
||||
handleUpdateFieldOptions: () => {},
|
||||
handleChangeTimeFormat: () => {},
|
||||
handleChangeDecimalPlaces: () => {},
|
||||
onResetFocus: () => {},
|
||||
queryConfigs: [],
|
||||
tableOptions: {
|
||||
columnNames: [],
|
||||
fieldNames: [],
|
||||
fixFirstColumn: true,
|
||||
sortBy: {displayName: '', internalName: '', visible: true},
|
||||
timeFormat: '',
|
||||
verticalTimeAxis: true,
|
||||
},
|
||||
queryASTs: [],
|
||||
fieldOptions: [],
|
||||
timeFormat: '',
|
||||
decimalPlaces: {
|
||||
isEnforced: true,
|
||||
digits: 2,
|
||||
},
|
||||
}
|
||||
|
||||
const setup = (override = {}) => {
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
updateLineColors,
|
||||
updateAxes,
|
||||
} from 'src/dashboards/actions/cellEditorOverlay'
|
||||
import {DEFAULT_TABLE_OPTIONS} from 'src/shared/constants/tableGraph'
|
||||
import {DEFAULT_TABLE_OPTIONS} from 'src/dashboards/constants'
|
||||
|
||||
import {
|
||||
validateGaugeColors,
|
||||
|
|
|
@ -9,7 +9,8 @@ const setup = () => {
|
|||
funcID: '1',
|
||||
argKey: 'db',
|
||||
value: 'db1',
|
||||
expressionID: '2',
|
||||
bodyID: '2',
|
||||
declarationID: '1',
|
||||
onChangeArg: () => {},
|
||||
}
|
||||
|
||||
|
|
|
@ -5,8 +5,9 @@ import FuncArg from 'src/ifql/components/FuncArg'
|
|||
const setup = () => {
|
||||
const props = {
|
||||
funcID: '',
|
||||
expressionID: '',
|
||||
bodyID: '',
|
||||
funcName: '',
|
||||
declarationID: '',
|
||||
argKey: '',
|
||||
value: '',
|
||||
type: '',
|
||||
|
|
|
@ -8,7 +8,8 @@ import FuncList from 'src/ifql/components/FuncList'
|
|||
const setup = (override = {}) => {
|
||||
const props = {
|
||||
funcs: ['count', 'range'],
|
||||
expressionID: '1',
|
||||
bodyID: '1',
|
||||
declarationID: '2',
|
||||
onAddNode: () => {},
|
||||
...override,
|
||||
}
|
||||
|
@ -133,7 +134,7 @@ describe('IFQL.Components.FuncsButton', () => {
|
|||
const onAddNode = jest.fn()
|
||||
const {wrapper, props} = setup({onAddNode})
|
||||
const [, func2] = props.funcs
|
||||
const {expressionID} = props
|
||||
const {bodyID, declarationID} = props
|
||||
|
||||
const dropdownButton = wrapper.find('button')
|
||||
dropdownButton.simulate('click')
|
||||
|
@ -148,7 +149,7 @@ describe('IFQL.Components.FuncsButton', () => {
|
|||
input.simulate('keyDown', {key: 'ArrowDown'})
|
||||
input.simulate('keyDown', {key: 'Enter'})
|
||||
|
||||
expect(onAddNode).toHaveBeenCalledWith(func2, expressionID)
|
||||
expect(onAddNode).toHaveBeenCalledWith(func2, bodyID, declarationID)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
import AutoRefresh, {
|
||||
Props,
|
||||
OriginalProps,
|
||||
} from 'src/shared/components/AutoRefresh'
|
||||
import React, {Component} from 'react'
|
||||
import {shallow} from 'enzyme'
|
||||
|
||||
type ComponentProps = Props & OriginalProps
|
||||
|
||||
class MyComponent extends Component<ComponentProps> {
|
||||
public render(): JSX.Element {
|
||||
return <p>Here</p>
|
||||
}
|
||||
}
|
||||
|
||||
const axes = {
|
||||
bounds: {
|
||||
y: [1],
|
||||
y2: [2],
|
||||
},
|
||||
}
|
||||
|
||||
const defaultProps = {
|
||||
type: 'table',
|
||||
autoRefresh: 1,
|
||||
inView: true,
|
||||
templates: [],
|
||||
queries: [],
|
||||
axes,
|
||||
editQueryStatus: () => {},
|
||||
grabDataForDownload: () => {},
|
||||
data: [],
|
||||
setResolution: () => {},
|
||||
isFetchingInitially: false,
|
||||
isRefreshing: false,
|
||||
queryASTs: [],
|
||||
}
|
||||
|
||||
const setup = (overrides: Partial<ComponentProps> = {}) => {
|
||||
const ARComponent = AutoRefresh(MyComponent)
|
||||
|
||||
const props = {...defaultProps, ...overrides}
|
||||
|
||||
return shallow(<ARComponent {...props} />)
|
||||
}
|
||||
|
||||
describe('Shared.Components.AutoRefresh', () => {
|
||||
describe('render', () => {
|
||||
describe('when there are no results', () => {
|
||||
it('renders the no results component', () => {
|
||||
const wrapped = setup()
|
||||
expect(wrapped.find('.graph-empty').exists()).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when there are results', () => {
|
||||
it('renderes the wrapped component', () => {
|
||||
const wrapped = setup()
|
||||
const timeSeries = [
|
||||
{
|
||||
response: {
|
||||
results: [{series: [1]}],
|
||||
},
|
||||
},
|
||||
]
|
||||
wrapped.update()
|
||||
wrapped.setState({timeSeries})
|
||||
process.nextTick(() => {
|
||||
expect(wrapped.find(MyComponent).exists()).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -8,10 +8,11 @@ import {
|
|||
transformTableData,
|
||||
} from 'src/dashboards/utils/tableGraph'
|
||||
|
||||
import {DEFAULT_SORT_DIRECTION} from 'src/shared/constants/tableGraph'
|
||||
import {
|
||||
DEFAULT_SORT_DIRECTION,
|
||||
DEFAULT_TIME_FORMAT,
|
||||
} from 'src/shared/constants/tableGraph'
|
||||
DEFAULT_DECIMAL_PLACES,
|
||||
} from 'src/dashboards/constants'
|
||||
|
||||
describe('timeSeriesToDygraph', () => {
|
||||
it('parses a raw InfluxDB response into a dygraph friendly data format', () => {
|
||||
|
@ -494,18 +495,18 @@ describe('filterTableColumns', () => {
|
|||
[3000, 2000, 1000],
|
||||
]
|
||||
|
||||
const fieldNames = [
|
||||
const fieldOptions = [
|
||||
{internalName: 'time', displayName: 'Time', visible: true},
|
||||
{internalName: 'f1', displayName: '', visible: false},
|
||||
{internalName: 'f2', displayName: 'F2', visible: false},
|
||||
]
|
||||
|
||||
const actual = filterTableColumns(data, fieldNames)
|
||||
const actual = filterTableColumns(data, fieldOptions)
|
||||
const expected = [['time'], [1000], [2000], [3000]]
|
||||
expect(actual).toEqual(expected)
|
||||
})
|
||||
|
||||
it('returns an array of an empty array if all fieldNames are not visible', () => {
|
||||
it('returns an array of an empty array if all fieldOptions are not visible', () => {
|
||||
const data = [
|
||||
['time', 'f1', 'f2'],
|
||||
[1000, 3000, 2000],
|
||||
|
@ -513,13 +514,13 @@ describe('filterTableColumns', () => {
|
|||
[3000, 2000, 1000],
|
||||
]
|
||||
|
||||
const fieldNames = [
|
||||
const fieldOptions = [
|
||||
{internalName: 'time', displayName: 'Time', visible: false},
|
||||
{internalName: 'f1', displayName: '', visible: false},
|
||||
{internalName: 'f2', displayName: 'F2', visible: false},
|
||||
]
|
||||
|
||||
const actual = filterTableColumns(data, fieldNames)
|
||||
const actual = filterTableColumns(data, fieldOptions)
|
||||
const expected = [[]]
|
||||
expect(actual).toEqual(expected)
|
||||
})
|
||||
|
@ -534,18 +535,23 @@ describe('transformTableData', () => {
|
|||
[3000, 2000, 1000],
|
||||
]
|
||||
const sort = {field: 'f1', direction: DEFAULT_SORT_DIRECTION}
|
||||
const tableOptions = {
|
||||
verticalTimeAxis: true,
|
||||
timeFormat: DEFAULT_TIME_FORMAT,
|
||||
}
|
||||
|
||||
const fieldNames = [
|
||||
const tableOptions = {verticalTimeAxis: true}
|
||||
const timeFormat = DEFAULT_TIME_FORMAT
|
||||
const decimalPlaces = DEFAULT_DECIMAL_PLACES
|
||||
const fieldOptions = [
|
||||
{internalName: 'time', displayName: 'Time', visible: true},
|
||||
{internalName: 'f1', displayName: '', visible: true},
|
||||
{internalName: 'f2', displayName: 'F2', visible: true},
|
||||
]
|
||||
|
||||
const actual = transformTableData(data, sort, fieldNames, tableOptions)
|
||||
const actual = transformTableData(
|
||||
data,
|
||||
sort,
|
||||
fieldOptions,
|
||||
tableOptions,
|
||||
timeFormat,
|
||||
decimalPlaces
|
||||
)
|
||||
const expected = [
|
||||
['time', 'f1', 'f2'],
|
||||
[2000, 1000, 3000],
|
||||
|
@ -563,21 +569,24 @@ describe('transformTableData', () => {
|
|||
[2000, 1000, 3000],
|
||||
[3000, 2000, 1000],
|
||||
]
|
||||
|
||||
const sort = {field: 'time', direction: DEFAULT_SORT_DIRECTION}
|
||||
|
||||
const tableOptions = {
|
||||
verticalTimeAxis: true,
|
||||
timeFormat: DEFAULT_TIME_FORMAT,
|
||||
}
|
||||
|
||||
const fieldNames = [
|
||||
const tableOptions = {verticalTimeAxis: true}
|
||||
const timeFormat = DEFAULT_TIME_FORMAT
|
||||
const decimalPlaces = DEFAULT_DECIMAL_PLACES
|
||||
const fieldOptions = [
|
||||
{internalName: 'time', displayName: 'Time', visible: true},
|
||||
{internalName: 'f1', displayName: '', visible: false},
|
||||
{internalName: 'f2', displayName: 'F2', visible: true},
|
||||
]
|
||||
|
||||
const actual = transformTableData(data, sort, fieldNames, tableOptions)
|
||||
const actual = transformTableData(
|
||||
data,
|
||||
sort,
|
||||
fieldOptions,
|
||||
tableOptions,
|
||||
timeFormat,
|
||||
decimalPlaces
|
||||
)
|
||||
|
||||
const expected = [['time', 'f2'], [1000, 2000], [2000, 3000], [3000, 1000]]
|
||||
|
||||
|
@ -593,19 +602,23 @@ describe('transformTableData', () => {
|
|||
]
|
||||
|
||||
const sort = {field: 'f1', direction: DEFAULT_SORT_DIRECTION}
|
||||
|
||||
const tableOptions = {
|
||||
verticalTimeAxis: true,
|
||||
timeFormat: DEFAULT_TIME_FORMAT,
|
||||
}
|
||||
|
||||
const fieldNames = [
|
||||
const tableOptions = {verticalTimeAxis: true}
|
||||
const timeFormat = DEFAULT_TIME_FORMAT
|
||||
const decimalPlaces = DEFAULT_DECIMAL_PLACES
|
||||
const fieldOptions = [
|
||||
{internalName: 'time', displayName: 'Time', visible: true},
|
||||
{internalName: 'f1', displayName: '', visible: false},
|
||||
{internalName: 'f2', displayName: 'F2', visible: true},
|
||||
]
|
||||
|
||||
const actual = transformTableData(data, sort, fieldNames, tableOptions)
|
||||
const actual = transformTableData(
|
||||
data,
|
||||
sort,
|
||||
fieldOptions,
|
||||
tableOptions,
|
||||
timeFormat,
|
||||
decimalPlaces
|
||||
)
|
||||
|
||||
const expected = [['time', 'f2'], [2000, 3000], [3000, 1000], [1000, 2000]]
|
||||
|
||||
|
@ -623,19 +636,23 @@ describe('if verticalTimeAxis is false', () => {
|
|||
]
|
||||
|
||||
const sort = {field: 'time', direction: DEFAULT_SORT_DIRECTION}
|
||||
|
||||
const tableOptions = {
|
||||
verticalTimeAxis: false,
|
||||
timeFormat: DEFAULT_TIME_FORMAT,
|
||||
}
|
||||
|
||||
const fieldNames = [
|
||||
const tableOptions = {verticalTimeAxis: false}
|
||||
const timeFormat = DEFAULT_TIME_FORMAT
|
||||
const decimalPlaces = DEFAULT_DECIMAL_PLACES
|
||||
const fieldOptions = [
|
||||
{internalName: 'time', displayName: 'Time', visible: true},
|
||||
{internalName: 'f1', displayName: '', visible: true},
|
||||
{internalName: 'f2', displayName: 'F2', visible: true},
|
||||
]
|
||||
|
||||
const actual = transformTableData(data, sort, fieldNames, tableOptions)
|
||||
const actual = transformTableData(
|
||||
data,
|
||||
sort,
|
||||
fieldOptions,
|
||||
tableOptions,
|
||||
timeFormat,
|
||||
decimalPlaces
|
||||
)
|
||||
|
||||
const expected = [
|
||||
['time', 1000, 2000, 3000],
|
||||
|
@ -655,19 +672,23 @@ describe('if verticalTimeAxis is false', () => {
|
|||
]
|
||||
|
||||
const sort = {field: 'f1', direction: DEFAULT_SORT_DIRECTION}
|
||||
|
||||
const tableOptions = {
|
||||
verticalTimeAxis: false,
|
||||
timeFormat: DEFAULT_TIME_FORMAT,
|
||||
}
|
||||
|
||||
const fieldNames = [
|
||||
const tableOptions = {verticalTimeAxis: false}
|
||||
const timeFormat = DEFAULT_TIME_FORMAT
|
||||
const decimalPlaces = DEFAULT_DECIMAL_PLACES
|
||||
const fieldOptions = [
|
||||
{internalName: 'time', displayName: 'Time', visible: true},
|
||||
{internalName: 'f1', displayName: '', visible: false},
|
||||
{internalName: 'f2', displayName: 'F2', visible: true},
|
||||
]
|
||||
|
||||
const actual = transformTableData(data, sort, fieldNames, tableOptions)
|
||||
const actual = transformTableData(
|
||||
data,
|
||||
sort,
|
||||
fieldOptions,
|
||||
tableOptions,
|
||||
timeFormat,
|
||||
decimalPlaces
|
||||
)
|
||||
|
||||
const expected = [['time', 2000, 3000, 1000], ['f2', 3000, 1000, 2000]]
|
||||
|
||||
|
|
Loading…
Reference in New Issue