Merge pull request #297 from influxdata/feature/tr-layouts

Render layouts from API
pull/295/head
Timothy J. Raymond 2016-10-28 19:26:10 -04:00 committed by GitHub
commit b74b704820
13 changed files with 221 additions and 123 deletions

View File

@ -115,6 +115,8 @@ func MarshalLayout(l chronograf.Layout) ([]byte, error) {
Y: c.Y,
W: c.W,
H: c.H,
I: c.I,
Name: c.Name,
Queries: queries,
}
}
@ -151,6 +153,8 @@ func UnmarshalLayout(data []byte, l *chronograf.Layout) error {
Y: c.Y,
W: c.W,
H: c.H,
I: c.I,
Name: c.Name,
Queries: queries,
}
}

View File

@ -34,13 +34,13 @@ var _ = math.Inf
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
type Exploration struct {
ID int64 `protobuf:"varint,1,opt,name=ID,json=iD,proto3" json:"ID,omitempty"`
Name string `protobuf:"bytes,2,opt,name=Name,json=name,proto3" json:"Name,omitempty"`
UserID int64 `protobuf:"varint,3,opt,name=UserID,json=userID,proto3" json:"UserID,omitempty"`
Data string `protobuf:"bytes,4,opt,name=Data,json=data,proto3" json:"Data,omitempty"`
CreatedAt int64 `protobuf:"varint,5,opt,name=CreatedAt,json=createdAt,proto3" json:"CreatedAt,omitempty"`
UpdatedAt int64 `protobuf:"varint,6,opt,name=UpdatedAt,json=updatedAt,proto3" json:"UpdatedAt,omitempty"`
Default bool `protobuf:"varint,7,opt,name=Default,json=default,proto3" json:"Default,omitempty"`
ID int64 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"`
Name string `protobuf:"bytes,2,opt,name=Name,proto3" json:"Name,omitempty"`
UserID int64 `protobuf:"varint,3,opt,name=UserID,proto3" json:"UserID,omitempty"`
Data string `protobuf:"bytes,4,opt,name=Data,proto3" json:"Data,omitempty"`
CreatedAt int64 `protobuf:"varint,5,opt,name=CreatedAt,proto3" json:"CreatedAt,omitempty"`
UpdatedAt int64 `protobuf:"varint,6,opt,name=UpdatedAt,proto3" json:"UpdatedAt,omitempty"`
Default bool `protobuf:"varint,7,opt,name=Default,proto3" json:"Default,omitempty"`
}
func (m *Exploration) Reset() { *m = Exploration{} }
@ -49,13 +49,13 @@ func (*Exploration) ProtoMessage() {}
func (*Exploration) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{0} }
type Source struct {
ID int64 `protobuf:"varint,1,opt,name=ID,json=iD,proto3" json:"ID,omitempty"`
Name string `protobuf:"bytes,2,opt,name=Name,json=name,proto3" json:"Name,omitempty"`
Type string `protobuf:"bytes,3,opt,name=Type,json=type,proto3" json:"Type,omitempty"`
Username string `protobuf:"bytes,4,opt,name=Username,json=username,proto3" json:"Username,omitempty"`
Password string `protobuf:"bytes,5,opt,name=Password,json=password,proto3" json:"Password,omitempty"`
URL string `protobuf:"bytes,6,opt,name=URL,json=uRL,proto3" json:"URL,omitempty"`
Default bool `protobuf:"varint,7,opt,name=Default,json=default,proto3" json:"Default,omitempty"`
ID int64 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"`
Name string `protobuf:"bytes,2,opt,name=Name,proto3" json:"Name,omitempty"`
Type string `protobuf:"bytes,3,opt,name=Type,proto3" json:"Type,omitempty"`
Username string `protobuf:"bytes,4,opt,name=Username,proto3" json:"Username,omitempty"`
Password string `protobuf:"bytes,5,opt,name=Password,proto3" json:"Password,omitempty"`
URL string `protobuf:"bytes,6,opt,name=URL,proto3" json:"URL,omitempty"`
Default bool `protobuf:"varint,7,opt,name=Default,proto3" json:"Default,omitempty"`
}
func (m *Source) Reset() { *m = Source{} }
@ -64,12 +64,12 @@ func (*Source) ProtoMessage() {}
func (*Source) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{1} }
type Server struct {
ID int64 `protobuf:"varint,1,opt,name=ID,json=iD,proto3" json:"ID,omitempty"`
Name string `protobuf:"bytes,2,opt,name=Name,json=name,proto3" json:"Name,omitempty"`
Username string `protobuf:"bytes,3,opt,name=Username,json=username,proto3" json:"Username,omitempty"`
Password string `protobuf:"bytes,4,opt,name=Password,json=password,proto3" json:"Password,omitempty"`
URL string `protobuf:"bytes,5,opt,name=URL,json=uRL,proto3" json:"URL,omitempty"`
SrcID int64 `protobuf:"varint,6,opt,name=SrcID,json=srcID,proto3" json:"SrcID,omitempty"`
ID int64 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"`
Name string `protobuf:"bytes,2,opt,name=Name,proto3" json:"Name,omitempty"`
Username string `protobuf:"bytes,3,opt,name=Username,proto3" json:"Username,omitempty"`
Password string `protobuf:"bytes,4,opt,name=Password,proto3" json:"Password,omitempty"`
URL string `protobuf:"bytes,5,opt,name=URL,proto3" json:"URL,omitempty"`
SrcID int64 `protobuf:"varint,6,opt,name=SrcID,proto3" json:"SrcID,omitempty"`
}
func (m *Server) Reset() { *m = Server{} }
@ -78,10 +78,10 @@ func (*Server) ProtoMessage() {}
func (*Server) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{2} }
type Layout struct {
ID string `protobuf:"bytes,1,opt,name=ID,json=iD,proto3" json:"ID,omitempty"`
Application string `protobuf:"bytes,2,opt,name=Application,json=application,proto3" json:"Application,omitempty"`
Measurement string `protobuf:"bytes,3,opt,name=Measurement,json=measurement,proto3" json:"Measurement,omitempty"`
Cells []*Cell `protobuf:"bytes,4,rep,name=Cells,json=cells" json:"Cells,omitempty"`
ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
Application string `protobuf:"bytes,2,opt,name=Application,proto3" json:"Application,omitempty"`
Measurement string `protobuf:"bytes,3,opt,name=Measurement,proto3" json:"Measurement,omitempty"`
Cells []*Cell `protobuf:"bytes,4,rep,name=Cells" json:"Cells,omitempty"`
}
func (m *Layout) Reset() { *m = Layout{} }
@ -102,6 +102,8 @@ type Cell struct {
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"`
I string `protobuf:"bytes,6,opt,name=i,proto3" json:"i,omitempty"`
Name string `protobuf:"bytes,7,opt,name=name,proto3" json:"name,omitempty"`
}
func (m *Cell) Reset() { *m = Cell{} }
@ -117,9 +119,9 @@ func (m *Cell) GetQueries() []*Query {
}
type Query struct {
Command string `protobuf:"bytes,1,opt,name=Command,json=command,proto3" json:"Command,omitempty"`
DB string `protobuf:"bytes,2,opt,name=DB,json=dB,proto3" json:"DB,omitempty"`
RP string `protobuf:"bytes,3,opt,name=RP,json=rP,proto3" json:"RP,omitempty"`
Command string `protobuf:"bytes,1,opt,name=Command,proto3" json:"Command,omitempty"`
DB string `protobuf:"bytes,2,opt,name=DB,proto3" json:"DB,omitempty"`
RP string `protobuf:"bytes,3,opt,name=RP,proto3" json:"RP,omitempty"`
}
func (m *Query) Reset() { *m = Query{} }
@ -139,33 +141,33 @@ func init() {
func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) }
var fileDescriptorInternal = []byte{
// 444 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x93, 0xcb, 0x8e, 0xd3, 0x30,
0x14, 0x86, 0xe5, 0x24, 0xce, 0xe5, 0x04, 0x15, 0x64, 0x21, 0x14, 0x21, 0x16, 0x51, 0xc4, 0xa2,
0x6c, 0x66, 0x01, 0x4f, 0xd0, 0x69, 0x58, 0x54, 0x2a, 0xa8, 0x78, 0xe8, 0x03, 0x98, 0xe4, 0xa0,
0x89, 0x94, 0x1b, 0x8e, 0x4d, 0x9b, 0x2d, 0x6b, 0x1e, 0x83, 0x37, 0xe0, 0x05, 0x91, 0x5d, 0x97,
0xce, 0x62, 0x34, 0xea, 0xf2, 0xfb, 0xff, 0x23, 0x9d, 0xef, 0xa4, 0x2e, 0x2c, 0x9a, 0x5e, 0xa1,
0xec, 0x45, 0x7b, 0x33, 0xca, 0x41, 0x0d, 0x2c, 0x3e, 0x73, 0xf1, 0x97, 0x40, 0xfa, 0xf1, 0x38,
0xb6, 0x83, 0x14, 0xaa, 0x19, 0x7a, 0xb6, 0x00, 0x6f, 0x53, 0x66, 0x24, 0x27, 0x4b, 0x9f, 0x7b,
0x4d, 0xc9, 0x18, 0x04, 0x9f, 0x45, 0x87, 0x99, 0x97, 0x93, 0x65, 0xc2, 0x83, 0x5e, 0x74, 0xc8,
0x5e, 0x41, 0xb8, 0x9f, 0x50, 0x6e, 0xca, 0xcc, 0xb7, 0x73, 0xa1, 0xb6, 0x64, 0x66, 0x4b, 0xa1,
0x44, 0x16, 0x9c, 0x66, 0x6b, 0xa1, 0x04, 0x7b, 0x03, 0xc9, 0x5a, 0xa2, 0x50, 0x58, 0xaf, 0x54,
0x46, 0xed, 0x78, 0x52, 0x9d, 0x03, 0xd3, 0xee, 0xc7, 0xda, 0xb5, 0xe1, 0xa9, 0xd5, 0xe7, 0x80,
0x65, 0x10, 0x95, 0xf8, 0x5d, 0xe8, 0x56, 0x65, 0x51, 0x4e, 0x96, 0x31, 0x8f, 0xea, 0x13, 0x16,
0x7f, 0x08, 0x84, 0x77, 0x83, 0x96, 0x15, 0x5e, 0x25, 0xcc, 0x20, 0xf8, 0x3a, 0x8f, 0x68, 0x75,
0x13, 0x1e, 0xa8, 0x79, 0x44, 0xf6, 0x1a, 0x62, 0x73, 0x84, 0xe9, 0x9d, 0x70, 0xac, 0x1d, 0x9b,
0x6e, 0x27, 0xa6, 0xe9, 0x30, 0xc8, 0xda, 0x3a, 0x27, 0x3c, 0x1e, 0x1d, 0xb3, 0x17, 0xe0, 0xef,
0xf9, 0xd6, 0xca, 0x26, 0xdc, 0xd7, 0x7c, 0xfb, 0x84, 0xe6, 0x6f, 0xa3, 0x89, 0xf2, 0x27, 0xca,
0xab, 0x34, 0x1f, 0x2a, 0xf9, 0x4f, 0x28, 0x05, 0x8f, 0x2b, 0xd1, 0x8b, 0xd2, 0x4b, 0xa0, 0x77,
0xb2, 0xda, 0x94, 0xee, 0x9b, 0xd2, 0xc9, 0x40, 0xf1, 0x8b, 0x40, 0xb8, 0x15, 0xf3, 0xa0, 0xd5,
0x03, 0x9d, 0xc4, 0xea, 0xe4, 0x90, 0xae, 0xc6, 0xb1, 0x6d, 0x2a, 0xfb, 0x0a, 0x9c, 0x55, 0x2a,
0x2e, 0x91, 0x99, 0xf8, 0x84, 0x62, 0xd2, 0x12, 0x3b, 0xec, 0x95, 0xf3, 0x4b, 0xbb, 0x4b, 0xc4,
0xde, 0x02, 0x5d, 0x63, 0xdb, 0x4e, 0x59, 0x90, 0xfb, 0xcb, 0xf4, 0xfd, 0xe2, 0xe6, 0xff, 0xa3,
0x33, 0x31, 0xa7, 0x95, 0x29, 0x8b, 0x06, 0x02, 0x83, 0xec, 0x19, 0x90, 0xa3, 0x15, 0xa0, 0x9c,
0x1c, 0x0d, 0xcd, 0x76, 0x2b, 0xe5, 0x64, 0x36, 0x74, 0xb0, 0x1b, 0x28, 0x27, 0x07, 0x43, 0xf7,
0xf6, 0x66, 0xca, 0xc9, 0x3d, 0x7b, 0x07, 0xd1, 0x0f, 0x8d, 0xb2, 0xc1, 0x29, 0xa3, 0x76, 0xcf,
0xf3, 0xcb, 0x9e, 0x2f, 0x1a, 0xe5, 0xcc, 0xcf, 0x7d, 0xb1, 0x02, 0x6a, 0x13, 0xf3, 0x0b, 0xad,
0x87, 0xae, 0x13, 0x7d, 0xed, 0x4e, 0x8e, 0xaa, 0x13, 0x9a, 0xef, 0x50, 0xde, 0xba, 0x73, 0xbd,
0xfa, 0xd6, 0x30, 0xdf, 0xb9, 0xe3, 0x3c, 0xb9, 0xfb, 0x16, 0xda, 0xff, 0xcb, 0x87, 0x7f, 0x01,
0x00, 0x00, 0xff, 0xff, 0x0d, 0xab, 0x03, 0x3b, 0x41, 0x03, 0x00, 0x00,
// 442 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x93, 0xcf, 0x8e, 0xd3, 0x30,
0x10, 0xc6, 0xe5, 0x24, 0x4e, 0x9b, 0x29, 0x2a, 0xc8, 0x42, 0xc8, 0x42, 0x1c, 0xa2, 0x88, 0x43,
0xb9, 0xec, 0x01, 0x9e, 0xa0, 0xdb, 0x70, 0xa8, 0xb4, 0xa0, 0xe2, 0xa5, 0x0f, 0x60, 0x5a, 0xa3,
0x8d, 0x94, 0x26, 0xc1, 0x71, 0x68, 0x73, 0xe5, 0x0a, 0x8f, 0xc1, 0x1b, 0xf0, 0x82, 0x68, 0x26,
0xee, 0x9f, 0xc3, 0x6a, 0xd5, 0xdb, 0x7c, 0x33, 0x5f, 0x34, 0x3f, 0x7f, 0x76, 0x60, 0x5a, 0x54,
0xce, 0xd8, 0x4a, 0x97, 0x37, 0x8d, 0xad, 0x5d, 0x2d, 0xc6, 0x47, 0x9d, 0xfd, 0x63, 0x30, 0xf9,
0x78, 0x68, 0xca, 0xda, 0x6a, 0x57, 0xd4, 0x95, 0x98, 0x42, 0xb0, 0xcc, 0x25, 0x4b, 0xd9, 0x2c,
0x54, 0xc1, 0x32, 0x17, 0x02, 0xa2, 0xcf, 0x7a, 0x67, 0x64, 0x90, 0xb2, 0x59, 0xa2, 0xa8, 0x16,
0xaf, 0x20, 0x5e, 0xb7, 0xc6, 0x2e, 0x73, 0x19, 0x92, 0xcf, 0x2b, 0xf4, 0xe6, 0xda, 0x69, 0x19,
0x0d, 0x5e, 0xac, 0xc5, 0x1b, 0x48, 0x16, 0xd6, 0x68, 0x67, 0xb6, 0x73, 0x27, 0x39, 0xd9, 0xcf,
0x0d, 0x9c, 0xae, 0x9b, 0xad, 0x9f, 0xc6, 0xc3, 0xf4, 0xd4, 0x10, 0x12, 0x46, 0xb9, 0xf9, 0xae,
0xbb, 0xd2, 0xc9, 0x51, 0xca, 0x66, 0x63, 0x75, 0x94, 0xd9, 0x5f, 0x06, 0xf1, 0x7d, 0xdd, 0xd9,
0x8d, 0xb9, 0x0a, 0x58, 0x40, 0xf4, 0xb5, 0x6f, 0x0c, 0xe1, 0x26, 0x8a, 0x6a, 0xf1, 0x1a, 0xc6,
0x88, 0x5d, 0xa1, 0x77, 0x00, 0x3e, 0x69, 0x9c, 0xad, 0x74, 0xdb, 0xee, 0x6b, 0xbb, 0x25, 0xe6,
0x44, 0x9d, 0xb4, 0x78, 0x01, 0xe1, 0x5a, 0xdd, 0x11, 0x6c, 0xa2, 0xb0, 0x7c, 0x02, 0xf3, 0x0f,
0x62, 0x1a, 0xfb, 0xd3, 0xd8, 0xab, 0x30, 0x2f, 0x91, 0xc2, 0x27, 0x90, 0xa2, 0xc7, 0x91, 0xf8,
0x19, 0xe9, 0x25, 0xf0, 0x7b, 0xbb, 0x59, 0xe6, 0x3e, 0xd3, 0x41, 0x64, 0xbf, 0x18, 0xc4, 0x77,
0xba, 0xaf, 0x3b, 0x77, 0x81, 0x93, 0x10, 0x4e, 0x0a, 0x93, 0x79, 0xd3, 0x94, 0xc5, 0x86, 0x5e,
0x81, 0xa7, 0xba, 0x6c, 0xa1, 0xe3, 0x93, 0xd1, 0x6d, 0x67, 0xcd, 0xce, 0x54, 0xce, 0xf3, 0x5d,
0xb6, 0xc4, 0x5b, 0xe0, 0x0b, 0x53, 0x96, 0xad, 0x8c, 0xd2, 0x70, 0x36, 0x79, 0x3f, 0xbd, 0x39,
0x3d, 0x3a, 0x6c, 0xab, 0x61, 0x98, 0xfd, 0x66, 0x10, 0x61, 0x25, 0x9e, 0x01, 0x3b, 0x10, 0x01,
0x57, 0xec, 0x80, 0xaa, 0xa7, 0xb5, 0x5c, 0xb1, 0x1e, 0xd5, 0x9e, 0x56, 0x70, 0xc5, 0xf6, 0xa8,
0x1e, 0xe8, 0xd0, 0x5c, 0xb1, 0x07, 0xf1, 0x0e, 0x46, 0x3f, 0x3a, 0x63, 0x0b, 0xd3, 0x4a, 0x4e,
0x8b, 0x9e, 0x9f, 0x17, 0x7d, 0xe9, 0x8c, 0xed, 0xd5, 0x71, 0x8e, 0x1f, 0x16, 0xfe, 0xa6, 0x58,
0x81, 0x91, 0x53, 0xb4, 0xa3, 0x21, 0x72, 0xac, 0xb3, 0x39, 0x70, 0xfa, 0x06, 0x2f, 0x71, 0x51,
0xef, 0x76, 0xba, 0xda, 0xfa, 0x54, 0x8e, 0x12, 0xa3, 0xca, 0x6f, 0x7d, 0x22, 0x41, 0x7e, 0x8b,
0x5a, 0xad, 0xfc, 0xf9, 0x03, 0xb5, 0xfa, 0x16, 0xd3, 0x2f, 0xf5, 0xe1, 0x7f, 0x00, 0x00, 0x00,
0xff, 0xff, 0x85, 0xa7, 0xa7, 0xb1, 0x64, 0x03, 0x00, 0x00,
}

View File

@ -43,6 +43,8 @@ message Cell {
int32 w = 3; // Width of Cell in the Layout
int32 h = 4; // Height of Cell in the Layout
repeated Query queries = 5; // Time-series data queries for Cell.
string i = 6; // Unique identifier for the cell
string name = 7; // User-facing name for this cell
}
message Query {

View File

@ -1,16 +1,31 @@
{
"id": "18aed9a7-dc83-406e-a4dc-40d53049541a",
"measurement": "disk",
"app": "User Facing Application Name",
"cells": [{
"x": 0,
"y": 0,
"w": 10,
"h": 10,
"queries": [{
"query": "select used_percent from disk",
"db": "telegraf",
"rp": "autogen"
}]
}]
}
{
"id": "18aed9a7-dc83-406e-a4dc-40d53049541a",
"measurement": "disk",
"app": "User Facing Application Name",
"cells": [{
"x": 0,
"y": 0,
"w": 5,
"h": 5,
"i": "used_percent",
"name": "Used Percent",
"queries": [{
"query": "select used_percent from disk",
"db": "telegraf",
"rp": "autogen"
}]
},
{
"x": 5,
"y": 1,
"w": 5,
"h": 5,
"i": "cpu_usage",
"name": "CPU Usage",
"queries": [{
"query": "select 100 - usage_idle from cpu",
"db": "telegraf",
"rp": "autogen"
}]
}]
}

View File

@ -175,12 +175,14 @@ type Cell struct {
Y int32 `json:"y"`
W int32 `json:"w"`
H int32 `json:"h"`
I string `json:"i"`
Name string `json:"name"`
Queries []Query `json:"queries"`
}
// Layout is a collection of Cells for visualization
type Layout struct {
ID string `json:"id,string"`
ID string `json:"id"`
Application string `json:"app"`
Measurement string `json:"measurement"`
Cells []Cell `json:"cells"`

View File

@ -96,6 +96,7 @@
"react-addons-update": "^15.1.0",
"react-dimensions": "^1.2.0",
"react-dom": "^15.0.2",
"react-grid-layout": "^0.13.9",
"react-onclickoutside": "^5.2.0",
"react-redux": "^4.4.0",
"react-router": "^2.4.1",

View File

@ -65,3 +65,10 @@ export function getAppsForHosts(proxyLink, hosts, supportedApps) {
return newHosts;
});
}
export function fetchLayouts() {
return AJAX({
url: `/chronograf/v1/layouts`,
method: 'GET',
});
}

View File

@ -0,0 +1,69 @@
import React, {PropTypes} from 'react';
import AutoRefresh from 'shared/components/AutoRefresh';
import LineGraph from 'shared/components/LineGraph';
import ReactGridLayout from 'react-grid-layout';
import _ from 'lodash';
const RefreshingLineGraph = AutoRefresh(LineGraph);
export const LayoutRenderer = React.createClass({
propTypes: {
cells: PropTypes.arrayOf(
PropTypes.shape({
queries: PropTypes.arrayOf(
PropTypes.shape({
rp: PropTypes.string.isRequired,
text: PropTypes.string.isRequired,
database: PropTypes.string.isRequired,
}).isRequired
).isRequired,
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
w: PropTypes.number.isRequired,
h: PropTypes.number.isRequired,
i: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
}).isRequired
),
autoRefreshMs: PropTypes.number.isRequired,
host: PropTypes.string.isRequired,
source: PropTypes.string,
},
getInitialState() {
return ({
layout: _.without(this.props.cells, ['queries']),
});
},
generateGraphs() {
return this.props.cells.map((cell) => {
const qs = cell.queries.map((q) => {
_.merge(q, {host: this.props.source});
q.text += ` where host = '${this.props.host}' and time > now() - 15m`;
return q;
});
return (
<div key={cell.i}>
<h2 className="hosts-graph-heading">{cell.name}</h2>
<div className="hosts-graph graph-panel__graph-container">
<RefreshingLineGraph
queries={qs}
autoRefresh={this.props.autoRefreshMs}
/>
</div>
</div>
);
});
},
render() {
return (
<ReactGridLayout layout={this.state.layout} isDraggable={false} isResizable={false} cols={12} rowHeight={30} width={1200}>
{this.generateGraphs()}
</ReactGridLayout>
);
},
});
export default LayoutRenderer;

View File

@ -1,9 +1,8 @@
import React, {PropTypes} from 'react';
// TODO: move this to a higher level package than chronograf?
import AutoRefresh from 'shared/components/AutoRefresh';
import LineGraph from 'shared/components/LineGraph';
const RefreshingLineGraph = AutoRefresh(LineGraph);
import LayoutRenderer from '../components/LayoutRenderer';
import {fetchLayouts} from '../apis';
import _ from 'lodash';
export const HostPage = React.createClass({
propTypes: {
@ -17,36 +16,43 @@ export const HostPage = React.createClass({
}).isRequired,
},
getInitialState() {
return {layouts: []};
},
componentDidMount() {
fetchLayouts().then((ls) => {
this.setState({layouts: ls.data.layouts});
});
},
render() {
const autoRefreshMs = 15000;
const source = this.props.source.links.proxy;
const hostID = this.props.params.hostID;
const queries = [
{
text: `SELECT "usage_user" FROM "telegraf".."cpu" WHERE host = '${this.props.params.hostID}' AND time > now() - 15m`,
name: 'CPU',
},
{
text: `SELECT "used_percent" FROM "telegraf".."mem" WHERE host = '${this.props.params.hostID}' AND time > now() - 15m`,
name: "Memory",
},
{
text: `SELECT "load1" FROM "telegraf".."system" WHERE host = '${this.props.params.hostID}' AND time > now() - 15m`,
name: "Load",
},
{
text: `SELECT "bytes_recv", "bytes_sent" FROM "telegraf".."net" WHERE host = '${this.props.params.hostID}' AND time > now() - 15m`,
name: "Network",
},
{
text: `SELECT "io_time" FROM "telegraf".."diskio" WHERE host = '${this.props.params.hostID}' AND time > now() - 15m`,
name: "Disk IO",
},
{
text: `SELECT "used_percent" FROM "telegraf".."disk" WHERE host = '${this.props.params.hostID}' AND time > now() - 15m`,
name: "Disk Usage",
},
];
const layout = _.head(this.state.layouts);
let layoutComponent;
if (layout) {
layout.cells.forEach((cell) => {
cell.queries.forEach((q) => {
q.text = q.query;
q.database = q.db;
});
});
layoutComponent = (
<LayoutRenderer
cells={layout.cells}
autoRefreshMs={autoRefreshMs}
source={source}
host={this.props.params.hostID}
/>
);
} else {
layoutComponent = <div />;
}
return (
<div className="host-dashboard hosts-page">
@ -62,22 +68,7 @@ export const HostPage = React.createClass({
</div>
<div className="container-fluid hosts-dashboard">
<div className="row">
{
queries.map((query) => {
const q = Object.assign({}, query, {host: source});
return (
<div className="col-xs-12 col-sm-6 col-lg-4" key={q.name}>
<h2 className="hosts-graph-heading">{q.name}</h2>
<div className="hosts-graph graph-panel__graph-container">
<RefreshingLineGraph
queries={[q]}
autoRefresh={autoRefreshMs}
/>
</div>
</div>
);
})
}
{layoutComponent}
</div>
</div>
</div>

View File

@ -2,8 +2,8 @@ import React, {PropTypes} from 'react';
import _ from 'lodash';
import {proxy} from 'utils/queryUrlGenerator';
function _fetchTimeSeries(source, db, query) {
return proxy({source, db, query});
function _fetchTimeSeries(source, db, rp, query) {
return proxy({source, db, rp, query});
}
export default function AutoRefresh(ComposedComponent) {
@ -58,8 +58,8 @@ export default function AutoRefresh(ComposedComponent) {
this.setState({isFetching: true});
let count = 0;
const newSeries = [];
queries.forEach(({host, database, text}) => {
_fetchTimeSeries(host, database, text).then((resp) => {
queries.forEach(({host, database, rp, text}) => {
_fetchTimeSeries(host, database, rp, text).then((resp) => {
newSeries.push({identifier: host, response: resp.data});
count += 1;
if (count === queries.length) {

View File

@ -17,3 +17,4 @@
@import '../external/fixed-data-table';
@import '../external/fixed-data-table-base';
@import '../external/fixed-data-table-style';
@import '../external/react-grid-layout';

View File

@ -0,0 +1 @@
@import '~react-grid-layout/css/styles.css';

View File

@ -60,6 +60,9 @@ module.exports = {
},
],
},
sassLoader: {
includePaths: [path.resolve(__dirname, "node_modules")],
},
eslint: {
failOnWarning: false,
failOnError: false,