diff --git a/cmd/geth/config.go b/cmd/geth/config.go index d3600f1416..3037a3f5ba 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/contracts/release" + "github.com/ethereum/go-ethereum/dashboard" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" @@ -76,10 +77,11 @@ type ethstatsConfig struct { } type gethConfig struct { - Eth eth.Config - Shh whisper.Config - Node node.Config - Ethstats ethstatsConfig + Eth eth.Config + Shh whisper.Config + Node node.Config + Ethstats ethstatsConfig + Dashboard dashboard.Config } func loadConfig(file string, cfg *gethConfig) error { @@ -110,9 +112,10 @@ func defaultNodeConfig() node.Config { func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { // Load defaults. cfg := gethConfig{ - Eth: eth.DefaultConfig, - Shh: whisper.DefaultConfig, - Node: defaultNodeConfig(), + Eth: eth.DefaultConfig, + Shh: whisper.DefaultConfig, + Node: defaultNodeConfig(), + Dashboard: dashboard.DefaultConfig, } // Load config file. @@ -134,6 +137,7 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { } utils.SetShhConfig(ctx, stack, &cfg.Shh) + utils.SetDashboardConfig(ctx, &cfg.Dashboard) return stack, cfg } @@ -153,6 +157,9 @@ func makeFullNode(ctx *cli.Context) *node.Node { utils.RegisterEthService(stack, &cfg.Eth) + if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) { + utils.RegisterDashboardService(stack, &cfg.Dashboard) + } // Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode shhEnabled := enableWhisper(ctx) shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DevModeFlag.Name) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 8166c9ce80..a0b15497dd 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -61,6 +61,11 @@ var ( utils.DataDirFlag, utils.KeyStoreDirFlag, utils.NoUSBFlag, + utils.DashboardEnabledFlag, + utils.DashboardAddrFlag, + utils.DashboardPortFlag, + utils.DashboardRefreshFlag, + utils.DashboardAssetsFlag, utils.EthashCacheDirFlag, utils.EthashCachesInMemoryFlag, utils.EthashCachesOnDiskFlag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 80861d8525..85720fa774 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -92,6 +92,16 @@ var AppHelpFlagGroups = []flagGroup{ utils.EthashDatasetsOnDiskFlag, }, }, + { + Name: "DASHBOARD", + Flags: []cli.Flag{ + utils.DashboardEnabledFlag, + utils.DashboardAddrFlag, + utils.DashboardPortFlag, + utils.DashboardRefreshFlag, + utils.DashboardAssetsFlag, + }, + }, { Name: "TRANSACTION POOL", Flags: []cli.Flag{ diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 5ab6047e83..40049e1a9b 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -36,6 +36,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/dashboard" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" @@ -177,6 +178,31 @@ var ( Name: "lightkdf", Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", } + // Dashboard settings + DashboardEnabledFlag = cli.BoolFlag{ + Name: "dashboard", + Usage: "Enable the dashboard", + } + DashboardAddrFlag = cli.StringFlag{ + Name: "dashboard.addr", + Usage: "Dashboard listening interface", + Value: dashboard.DefaultConfig.Host, + } + DashboardPortFlag = cli.IntFlag{ + Name: "dashboard.host", + Usage: "Dashboard listening port", + Value: dashboard.DefaultConfig.Port, + } + DashboardRefreshFlag = cli.DurationFlag{ + Name: "dashboard.refresh", + Usage: "Dashboard metrics collection refresh rate", + Value: dashboard.DefaultConfig.Refresh, + } + DashboardAssetsFlag = cli.StringFlag{ + Name: "dashboard.assets", + Usage: "Developer flag to serve the dashboard from the local file system (default: \"\")", + Value: dashboard.DefaultConfig.Assets, + } // Ethash settings EthashCacheDirFlag = DirectoryFlag{ Name: "ethash.cachedir", @@ -997,6 +1023,14 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { } } +// SetDashboardConfig applies dashboard related command line flags to the config. +func SetDashboardConfig(ctx *cli.Context, cfg *dashboard.Config) { + cfg.Host = ctx.GlobalString(DashboardAddrFlag.Name) + cfg.Port = ctx.GlobalInt(DashboardPortFlag.Name) + cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name) + cfg.Assets = ctx.GlobalString(DashboardAssetsFlag.Name) +} + // RegisterEthService adds an Ethereum client to the stack. func RegisterEthService(stack *node.Node, cfg *eth.Config) { var err error @@ -1019,6 +1053,13 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) { } } +// RegisterDashboardService adds a dashboard to the stack. +func RegisterDashboardService(stack *node.Node, cfg *dashboard.Config) { + stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { + return dashboard.New(cfg) + }) +} + // RegisterShhService configures Whisper and adds it to the given node. func RegisterShhService(stack *node.Node, cfg *whisper.Config) { if err := stack.Register(func(n *node.ServiceContext) (node.Service, error) { diff --git a/dashboard/assets.go b/dashboard/assets.go new file mode 100644 index 0000000000..b10ac86507 --- /dev/null +++ b/dashboard/assets.go @@ -0,0 +1,260 @@ +// Code generated by go-bindata. +// sources: +// assets/components/dashboard.js +// assets/dashboard.html +// DO NOT EDIT! + +package dashboard + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "time" +) + +func bindataRead(data []byte, name string) ([]byte, error) { + gz, err := gzip.NewReader(bytes.NewBuffer(data)) + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + + var buf bytes.Buffer + _, err = io.Copy(&buf, gz) + clErr := gz.Close() + + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + if clErr != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +type asset struct { + bytes []byte + info os.FileInfo +} + +type bindataFileInfo struct { + name string + size int64 + mode os.FileMode + modTime time.Time +} + +func (fi bindataFileInfo) Name() string { + return fi.name +} +func (fi bindataFileInfo) Size() int64 { + return fi.size +} +func (fi bindataFileInfo) Mode() os.FileMode { + return fi.mode +} +func (fi bindataFileInfo) ModTime() time.Time { + return fi.modTime +} +func (fi bindataFileInfo) IsDir() bool { + return false +} +func (fi bindataFileInfo) Sys() interface{} { + return nil +} + +var _componentsDashboardJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x5a\x7b\x6f\x1b\x37\x12\xff\xdf\x80\xbf\xc3\x9c\x7a\x68\x65\x54\xd2\xca\xf6\xa5\x0d\xf4\x02\x12\x27\x69\x7d\x88\x93\x22\x36\x50\x1c\x8c\xc0\xa5\x76\x47\xbb\x84\xb9\xe4\x82\xe4\xca\x36\x02\x7d\xf7\x03\xb9\x0f\xed\x53\x5a\x3b\x76\x51\x01\x41\x24\x92\xf3\xe3\x0c\x39\x6f\xfa\x2c\x20\x52\x8f\x3c\x5c\x91\x98\x69\x35\xf2\x99\x58\x12\x36\x62\xe8\x23\xf7\x60\x0e\xdf\x0e\x0f\x00\x00\x90\x93\x25\x43\x6f\x02\x2b\xc2\x14\x1e\x1e\x6c\xa6\x87\x07\x87\x07\xae\xe0\x4a\xc3\x99\x08\x23\xc1\x91\x6b\x98\xc3\x17\x24\xae\x1e\xe5\x23\xd3\xc3\x03\xc7\x81\xfa\xb2\x73\xbe\x42\xc9\x45\x69\xe1\xe1\x81\xcb\x88\x52\x70\xc6\x90\xc8\x15\xbd\x07\xbc\xd7\xc8\x3d\x55\x20\x4c\x99\x91\xc8\x3d\x94\xfd\xa3\xec\x77\x32\xa6\x63\xc9\xa1\xbf\x1d\x31\x9f\x99\x47\xd7\x60\x61\x3f\x91\x10\xe7\x3d\x37\xc5\xee\x39\x8b\xed\xc2\xa3\x69\xf2\x7d\x73\x78\xb0\xd9\xb2\x71\x81\x3c\x3e\xd7\x18\x3e\x0b\x1b\x8c\x2e\x66\x64\x31\xa3\x05\x5e\xbe\xfd\xb5\x22\xf0\xef\x6f\x3a\xa0\x6a\x14\x49\x11\xa9\x51\x3e\xb7\xf9\x0b\x36\xce\xa2\x38\xa5\xf1\x5e\x6f\xaa\xc2\xac\x08\xac\xc8\xd0\x0d\x70\x2d\x05\x1f\x7a\xe2\x8e\xf7\x9c\xc5\xcc\x21\x8b\xf2\xe6\x96\x81\x98\x15\x29\x39\x59\x83\x1b\x50\xe6\xdd\x84\xc8\xe3\x5e\x03\x81\xf9\x94\x78\x33\xab\x25\xf2\x4d\x03\xb6\x13\xb3\x0a\xc2\xcc\x61\xb4\xd3\x01\x9f\x19\xd8\xe7\x3b\x61\x08\x24\xae\xe6\x45\xbe\xcd\xc0\xa6\xe1\x28\x1d\xb2\xe8\xcc\xe4\x25\x32\x74\xf5\xb3\x70\x59\xbf\x06\x45\x3d\x1c\xb6\xdd\xc2\x2c\x57\xc2\xd2\xb5\x0f\x03\x11\x62\x0f\x8c\x24\xf3\xde\xef\xe6\x7b\xcb\x0d\xce\xb6\x67\x6c\x4f\xa6\xe7\x11\x15\x2c\x05\x91\xde\x28\xd0\x21\xcb\x20\xde\x65\xa3\xc7\x25\xbb\xf8\x1e\xa4\x93\x46\xa4\x99\x93\x09\xf4\x08\x61\xd1\xa3\x3a\xc3\xff\x84\xfa\x4e\xc8\x5b\xca\xfd\xef\x14\x79\x0b\xd4\x2c\xf3\x93\x38\xf5\x50\xdd\x6a\x11\x65\x7b\x5c\xdd\x47\x42\xb0\xef\x64\x34\x01\x79\x46\x26\xb5\x71\xe4\x19\xfa\x47\xe1\xab\x7f\x1a\x83\x4b\x22\x87\xae\x09\x4a\x43\x91\xed\x71\xf9\xa0\x34\x86\xcd\x5b\xb4\xa0\xb8\x4c\xf0\x5c\xcc\xb7\x4c\xb8\xb7\x6e\x40\x28\xff\x4e\x61\x0b\x40\x8f\x92\xb7\xe2\x23\x9b\x7d\xcd\x25\xf5\xf0\x2d\x91\x2f\x12\xf7\x04\x1b\x86\xde\xf0\x14\x18\xae\xf4\x8d\xdb\xac\x95\x55\xa2\x6c\x2d\x28\x57\x0a\xc6\x86\x6b\x8a\x77\xad\xe7\x57\xa1\xe5\x64\xbd\x24\x12\x38\x59\xdf\x68\xaa\x8d\xc2\x29\xfd\xc0\x70\xfe\xed\xdb\x52\x48\x0f\xe5\x04\xc6\x9b\x4d\x0b\x96\xc5\x23\x2d\xf7\x50\xd8\x43\x51\x8d\x29\x7a\x39\xb4\xa6\x91\x31\x22\x77\x3d\x67\x01\x33\x15\x11\xbe\xf8\x4d\xc0\x7b\x1d\xa0\xc4\x38\x84\xdc\x4b\xcd\x1c\x3b\xd7\x1c\x33\x93\x7b\xf3\xe8\xba\x6d\x2e\x4b\x54\x5a\x7d\xa6\x39\x13\xea\x19\x46\x3d\x34\x5a\x6d\xdd\x7c\x91\xcf\x90\x50\x6e\x43\xf0\x8d\x59\x02\x01\xf5\x3c\xe4\xc3\x48\x52\xae\x21\x9f\x6b\x3b\xf2\xa6\x63\x4f\xb0\xd0\xd5\x54\xb4\xaa\x7a\x4e\xbb\x8d\x6d\x6d\x12\xec\x3d\x82\x96\xb9\xa6\xf1\xea\x58\xb3\x0d\x5c\x89\xe8\x13\x59\x53\x9f\x18\x09\x5e\xc2\x12\xb4\x88\x6e\x38\x59\x77\xd1\x7f\xa3\xbc\xbb\x2e\x60\x66\xd3\xa8\xed\xfa\x1e\x48\xc1\x12\xba\x54\x80\xc7\x5c\x9d\x01\xd3\xc2\xf7\x59\x6b\x34\xcf\x29\x89\xd5\x2a\x7b\xd7\xdd\x28\x2c\x55\x83\x85\x2c\x89\x54\xad\x21\x3f\x27\x6c\xb5\x0e\xd8\xab\x1e\x9c\x3c\xaf\x7a\xec\x4e\xc8\x6d\x9d\x21\x63\x57\x0b\xd9\xb7\xc9\x5e\x49\x3f\x54\x1c\x61\x36\x3e\xdd\x0e\xdb\xd4\x50\x69\xa2\x71\x5b\xed\x64\x1f\x1b\x86\x26\xc0\x63\xc6\x06\xdb\x99\x4d\xce\x59\xb6\x6d\xca\xc7\x3b\xea\x5d\x88\x98\xeb\xb2\x5e\x6e\x37\x18\x59\x3c\x98\x03\xc7\x3b\xb0\x75\x57\xdf\x4e\x7a\x44\x93\x41\x75\x6f\xfd\x10\xe1\x04\x7e\x62\x94\xe3\x4f\x83\xf2\x94\x59\x3f\x81\x52\x76\x4e\xa4\x7e\x67\x50\x0a\x5c\x16\x4e\xb0\xdd\x68\xe8\xaa\x5f\xe3\xef\x5f\xf3\xb9\x15\xf9\xa8\xc6\x52\x65\xe5\x28\x8e\x3c\xa2\xb1\x5f\x3c\xce\x7c\x37\xe8\x6a\x92\xcd\x25\x50\x07\xfb\xbc\xbf\x89\x08\xc7\xf6\x04\xab\xb6\x3c\x8d\x15\x3b\x94\x39\x38\xa9\xd7\x0a\x30\x73\x82\x93\x5d\x44\xf5\xa4\x3e\x89\x7e\x43\x49\xfd\x40\x83\x65\xf2\x46\x0b\xc1\x96\xe2\x7e\xaf\x6d\x27\x75\x4c\x39\x74\x33\x12\x29\x1c\x32\xca\x6f\x9b\x03\x5d\x56\x02\xc6\x51\x6b\x01\x58\xda\xa3\x5c\xf8\xb4\xb0\x51\xdc\xc6\x93\x22\xb2\xf5\x65\x17\x3f\x93\x45\xee\x1f\x7a\x4d\x10\xc3\xd4\x63\x59\x25\x4e\x7f\x14\x36\x48\x5d\xe8\x32\xd6\x5a\xf0\x1e\x10\x49\xc9\x10\xef\x23\xc2\x3d\xf4\x8c\xb8\x4c\xb5\x04\xfb\x3b\x89\xdc\x0d\x3a\xc9\x0f\xf5\x4b\xcb\xb9\x4b\x42\x74\xc2\xc4\xbe\xe0\x5b\x39\xb0\x45\x41\xf2\xc5\x25\x6a\x4d\xb9\xaf\xe0\xb8\x1b\x3f\xd0\xed\x5e\xf6\x6e\x77\xf2\xec\xdb\x35\x94\xf7\x4f\x40\x6a\xd0\x6b\x26\x76\x2b\xb5\x99\x7f\x0e\x7d\xde\x23\xc0\xfe\x34\x6e\x57\x84\xab\xf9\x18\x57\x70\x8d\x5c\xef\xf4\x32\x2e\xe1\x6b\xa2\xc0\xf6\x2a\xfa\xc6\x0e\x8e\x60\xbe\x48\xdb\x2d\xe6\x27\xcc\xad\x75\x6c\x36\x8f\x65\xe9\xe9\x81\xf5\x8b\xb8\x7b\x89\x6c\x4b\x8a\xc6\x8a\x61\x66\xe2\x78\xb3\x68\xf5\xa2\xe5\x17\x30\x5f\x54\x98\x7e\xb9\x57\xc3\xe3\x93\x5e\x33\x71\x52\xa4\x5d\x60\x28\xe4\x03\xc4\x8a\xf8\x08\xca\x96\x8e\x4e\x68\xc7\x1c\xca\x63\x85\x2d\xc4\x79\x10\x2d\x47\x24\x33\xaa\x46\x09\x7d\x43\xf7\xab\xb1\x0c\x7c\x51\xf1\xce\xf9\x52\xc4\xdc\x03\x2d\xc9\x6a\x45\x5d\x88\x4e\x22\x27\x1d\xbb\x4a\x86\x9e\x22\x60\x8a\xd6\x41\xc2\x6e\x0a\xf5\x07\xf1\xf1\x2c\xb1\x85\x17\x51\x2c\x13\x5a\x6d\x21\x9b\x39\xeb\x96\xe2\xbe\x4a\xd8\x35\x5b\x88\x88\x8f\xc3\xfd\x09\x43\xb5\xba\x30\x04\x37\xa6\x70\xde\x1b\xe8\x83\xd3\xe6\x9a\x14\x66\x2a\x24\x8c\x2d\x2e\x35\xd1\x54\x69\xea\xaa\x99\x93\x8c\xcc\x9c\xe0\xf4\x99\x0b\x35\xe8\xe4\x00\x8d\x73\x48\xd4\xa4\x41\x73\xda\x9d\xd4\x2e\xdc\x27\x79\x2a\xfb\x8c\x70\xf1\xfe\xe2\xf3\x97\xff\xdd\x5c\xbe\xb9\xf8\xe3\xe3\xfb\x9b\x8f\xe7\x17\xe7\x57\x30\x87\x93\xf1\x78\x0a\x8e\x03\x17\xe4\x9e\x86\x71\x08\x3c\x0e\x97\x28\x41\xac\x20\xb1\x5c\xeb\x50\x41\x91\x30\x62\xa8\x32\xa8\xab\x2f\x6f\x3e\x7c\x38\x3f\xeb\x8e\x95\x99\x5c\x19\x2c\x53\xf9\xed\x15\xfe\xcd\x15\x8a\x9a\x54\x87\xcd\x27\x11\xbc\x71\xca\x7c\x18\x59\x22\x53\x13\xb8\xfe\x3a\x68\x5e\x60\x84\x54\x68\xc0\xaf\x5b\x20\x72\x98\x09\xf4\x9a\xfc\x6c\x0b\xb0\xf9\x2c\x89\x7b\xeb\x4b\xe3\xb3\xce\x04\x13\x72\x02\x3d\xe9\x2f\x49\xff\xf4\xf5\x00\x8e\x5f\xbf\x1a\xc0\xf1\xab\xff\x0c\x60\x3c\x3a\x3d\x3e\xda\x89\x62\x7b\x49\x3b\x11\x7e\xdd\x09\x10\x09\xca\xf5\xdb\xe7\x41\xe9\x26\x51\x07\xa4\xdf\xc5\x1a\x65\x1d\xee\x87\xd5\x6a\xd5\x91\xb6\x2e\xd0\xc9\xc9\x78\x90\xfd\xdb\x7d\xa6\x85\x23\xf9\x93\x7a\x3a\x98\xc0\xf1\x8e\xd5\x49\x29\x7a\xfd\xb5\x79\xc5\xa6\x61\x7c\xd3\x80\x96\xda\xd5\xdf\xa5\xab\x0d\x11\xf3\x09\xaa\x3a\x80\xd7\xe6\x6e\xc7\xbf\x58\x45\x7d\xb4\x9e\x96\xc8\x7f\x1d\x3f\x4d\x4d\x1f\x0f\xd2\x45\x98\x2e\x40\x2f\xa1\xa4\xc7\xaf\x8e\x07\xc7\xaf\x7f\x1d\x9c\x8c\x5f\xfd\xc3\x94\xb4\xf8\x7b\x53\xec\xab\x24\x5f\x93\x3e\x88\xed\xe8\x28\x98\x43\x3f\x54\x7e\x92\xd2\x6f\xa9\x18\xea\x2c\x14\xcd\x6b\x8d\x94\x2c\xbf\x9c\x96\xd7\x67\xe1\xa6\x89\x20\x9d\x9b\x16\xdb\x2d\x8e\x03\x1f\x28\x63\xa0\x03\x84\xbc\x6f\x0e\x77\x54\x07\x10\x11\xa5\xed\x39\x94\x5a\x3f\xa1\xf2\x47\x21\x6a\x49\x5d\x65\xbb\x3e\x31\xf7\x70\x45\x39\x7a\xb5\xd6\x8f\xe3\x24\xef\xf2\x40\x39\xb8\x44\x61\x75\x0f\xa2\x40\x44\xc8\xd1\x83\x25\xae\x84\xc4\x32\x75\x22\xdd\x28\x31\x63\x98\xc3\xf5\xd7\x69\xa5\xb3\x94\x48\xb3\x63\x45\x0a\x91\x19\xfa\xf5\xf8\x6b\x56\x2a\xb5\x82\xb5\xad\x2d\xaf\x4e\x2f\x06\xe6\x50\x38\x8d\xfa\x7d\x64\x4b\x23\x29\x5c\x54\x4a\xc8\x0a\x41\x3e\x3e\xad\x1d\xdc\xb9\x06\xaa\x20\x12\x4a\xd1\x25\x43\xd0\x02\x7c\xd4\x40\xb8\x30\xb9\x1f\x84\xa8\x6c\xa1\x72\x17\x50\x86\xb0\xa2\x8c\x51\xee\xdb\xe3\x25\x52\x92\x07\x05\xcb\x07\x88\x62\x15\xf4\x8f\x06\xa0\x04\x50\xae\x34\x12\xaf\xb6\x49\x14\x6b\x4b\x14\x50\xa5\x8d\x92\x69\x61\x7f\x2e\xd1\xa7\x9c\x1b\x44\x93\xbe\xe4\xa0\x65\xf2\x95\x90\xd0\x37\xc2\x51\x23\x14\x86\x23\x86\xdc\xd7\x01\x0c\xe1\x78\x0a\x14\x16\x73\x18\xc3\x8f\x3f\x36\x66\x5e\x8b\xf2\xdd\xa6\x94\x53\x18\x0e\x69\x4d\x87\x6a\x9a\x30\x8a\xb9\x0a\xe8\x4a\xf7\x43\x0c\xaf\xe9\xd7\x91\xa6\x21\x8e\x54\xbc\x54\x5a\x52\xee\x97\x46\x73\x8e\x5e\x1d\x1d\x4d\x5b\x03\xc8\xb3\xe3\xb6\x68\x5d\x75\x83\x35\x61\x31\xee\xe2\xab\x15\x20\x57\x9b\x56\x98\x4d\x53\x0f\x16\xb5\x29\x0f\xb0\x5f\x3f\xe1\x1d\x09\x61\x21\x27\x4c\xfe\x6f\x76\x99\x79\x30\x4e\xbf\xd4\x57\x55\x58\xda\x54\x59\x4e\x4a\xb8\xb6\xa6\xb0\xe3\xa4\xfe\xb2\xc1\x15\x59\xff\xb8\xdb\x13\x99\xb5\x0d\x2a\x07\xf3\xf9\xbc\x49\x43\x3b\x68\x61\x72\x13\x1d\xd4\xaa\x7d\x61\x9b\x9e\xec\x87\xee\x48\xb2\xd9\xe1\x50\x47\xd6\x3d\x6c\x0f\xb0\xa6\xef\x95\x99\x1d\x3a\x5f\x11\xf8\xf9\x80\xdb\x0e\xa8\xba\x43\xa3\x09\xb4\x9e\x55\x4e\x9d\x9b\x51\x0b\xc0\x1e\xa3\xd9\x63\x35\x9d\xcc\xa6\x83\xdd\xec\x34\x9c\x92\x8d\x98\x3a\x51\x30\x1c\x31\xe1\x17\xde\x67\xf2\x82\x78\xba\x7d\xd2\x71\x05\xe7\xe8\x6a\x93\x75\x34\xa5\x1c\x0a\xe5\x1a\x65\xfa\xe4\xf4\x27\x2e\x2f\x85\x7b\x8b\xba\xdf\xbb\x53\x13\xc7\xe9\xc1\xcf\xc0\x84\x6b\x9f\x2a\x47\x81\x50\x1a\x7e\x86\x9e\x43\x22\xda\x2b\x32\xe6\x38\x70\xf5\xf9\xdd\x67\xe8\xdf\xc6\xf2\x56\x84\x54\xd1\xa3\x09\x7c\x41\x25\xd8\x1a\xed\xc9\x26\x19\xc6\x92\x72\xaf\x92\xbe\x04\x44\xa7\xb9\x4b\x01\x2e\xe1\x68\x24\x78\x16\xf8\xe6\xd0\xc7\x35\x72\x5d\x65\x3f\x83\x09\x95\x0f\x73\xf8\xef\xe5\xe7\x4f\xa3\x88\x48\x85\xc9\x6a\xab\x00\xd5\x7b\xa6\x2b\x9b\x7b\x59\x5f\xd0\xf8\x82\x05\x4d\xde\xa9\x76\xfa\xf6\x36\x03\x92\xbd\x6f\x25\x79\x9d\x4d\xea\xa6\xe5\x34\xb0\x41\x2a\xdb\xb6\xde\xde\x06\x28\xd4\x57\x34\x44\x11\xeb\xbe\x85\xcc\x6f\x6c\x00\xa7\xe3\xf1\xf8\x68\xba\xcd\x27\xa7\x8f\x79\x50\xcc\x71\xfa\x9d\xde\xf9\xba\xfe\x99\x08\xd7\x84\x72\x94\xb0\x14\xde\x43\x97\x76\x9a\xfd\x2b\x85\x9c\xac\xb5\xb9\x96\xfe\x69\x4b\x6b\xab\xa8\xf4\xec\xdf\xba\xaa\xd8\x53\x2c\xf5\xa3\x8a\x99\x71\x7b\x3f\x6a\x25\x84\x46\xf9\x88\x6e\x5e\x14\x33\x96\x3c\xe2\xed\xeb\xe6\xfd\x86\x5c\x23\x43\xc6\x08\x0c\xe1\xad\x10\x5a\x69\x49\x22\x78\xe3\x85\x94\xc3\x15\x86\x11\x23\x1a\x4d\x26\x97\x3f\xda\x04\x5a\x47\xc6\x06\x5d\x53\x00\x31\xba\x1c\xb9\x22\xec\x2d\xce\xd2\x5f\x4f\x7f\x73\x87\x6e\x4f\x1a\xad\x67\xf1\xd8\xc6\xdc\xff\x03\x00\x00\xff\xff\x72\x1b\xde\x84\x3f\x2c\x00\x00") + +func componentsDashboardJsBytes() ([]byte, error) { + return bindataRead( + _componentsDashboardJs, + "components/dashboard.js", + ) +} + +func componentsDashboardJs() (*asset, error) { + bytes, err := componentsDashboardJsBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "components/dashboard.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _dashboardHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x96\xdf\x6f\x23\x27\x10\xc7\xdf\x4f\xba\xff\x81\xf0\x92\x44\x3a\xc0\x8e\xd3\xdc\xe9\xba\x6b\xb5\x4d\xd2\x2a\x0f\x55\xaa\x36\x27\xb5\x4f\x15\x86\xf1\x2e\x36\x0b\x7b\x30\x6b\xc7\xff\x7d\xb5\x3f\xec\xee\xd6\x76\xdb\xbb\x38\x7e\x31\x0c\xf0\xfd\xcc\x30\x30\x6c\x72\x76\xf7\x78\xfb\xf4\xc7\x2f\xf7\x24\xc7\xc2\x4e\xdf\xbe\x49\xea\x7f\x62\xa5\xcb\x52\x0a\x8e\x4e\xdf\xbe\x21\x84\x90\x24\x07\xa9\xbb\x76\xd3\x2f\x00\x25\x51\xb9\x0c\x11\x30\xa5\x9f\x9e\x7e\x64\x1f\xe8\xde\x78\x8e\x58\x32\xf8\x5c\x99\x55\x4a\x7f\x67\x9f\xbe\x67\xb7\xbe\x28\x25\x9a\x99\x05\x4a\x94\x77\x08\x0e\x53\xfa\x70\x9f\x82\xce\x60\x7f\xb9\x93\x05\xa4\x74\x65\x60\x5d\xfa\x80\xbd\x15\x6b\xa3\x31\x4f\x35\xac\x8c\x02\xd6\x74\xde\x11\xe3\x0c\x1a\x69\x59\x54\xd2\x42\x3a\xae\xd5\x7a\x7a\x68\xd0\xc2\xf4\x27\x4f\xee\x31\x87\x00\x55\x41\xee\x64\xcc\x67\x5e\x06\x9d\x88\x76\xb0\x37\xdb\x1a\xb7\x24\x01\x6c\x4a\x63\xee\x03\xaa\x0a\x89\x51\xde\x51\x82\x9b\x12\x52\x6a\x0a\x99\x81\x30\xca\x53\x92\x07\x98\xa7\xb4\x8e\x33\x7e\x14\x02\x3a\x71\xee\x43\x26\xe6\x72\x55\x2f\xe2\xf5\x3c\x31\xf4\xa6\xd1\x1f\x2e\x55\xda\x2d\x22\x57\xd6\x57\x7a\x6e\x65\x00\xae\x7c\x21\xe4\x42\x3e\x0b\x6b\x66\x51\xe0\xda\x20\x42\x60\x33\xef\x31\x62\x90\xa5\x98\xf0\x09\x7f\x2f\x54\x8c\x62\x67\xe3\x85\x71\x5c\xc5\x48\x3b\xdf\x71\x63\x21\xe6\x00\x48\x89\xd8\x0b\xef\x8b\xf0\x73\xef\x90\xc9\x35\x44\x5f\x80\xb8\xe6\xef\xf9\xa8\x21\xf7\xcd\xaf\x07\xcf\xc0\x21\x58\xb0\x56\x8a\x31\x9f\x74\x68\x55\x45\xf4\xc5\x71\xe8\x70\xc3\xa3\x0a\xa6\x44\x12\x83\xfa\xdf\xd4\x99\x9c\x81\x65\x11\xa5\xd3\xd2\x7a\x07\xe2\x86\x5f\xdd\xf0\x51\x6b\x6f\xb8\x8b\x48\xa7\x89\x68\xa5\xa7\x2f\x83\x05\x90\x0a\xc5\xf8\x1b\x7e\xc3\xc7\x6d\xe7\xf5\x09\x4c\x77\xfb\x77\x6a\x0a\x0b\xbe\x42\x08\xe2\x9a\x8f\xf9\xd5\xc0\x74\x08\xf7\x32\xe0\xe2\x73\x05\x61\x23\xae\xf8\x98\x5f\x77\x9d\x53\xc7\xd4\xaa\x32\xe7\xb1\xe6\x5c\xf3\xb1\x28\xa5\x5a\xca\x0c\xf4\x16\x58\x0f\xf1\xad\xf1\xd4\xf8\xdb\x5c\x06\xe4\x8b\x28\xae\xf8\x88\x8f\x76\xdd\x93\xe9\x1f\xab\x2c\x8b\x7f\x16\x96\x13\x32\xe7\xd6\xa3\x18\xf1\x0f\x7c\xb2\xdd\xc2\xda\x72\xf8\x64\x24\xa2\xf7\xf4\x24\x33\xaf\x37\xc3\x43\x73\xc6\xd8\xd6\x85\xb6\x3a\x23\x3c\xa3\x58\xc4\x67\xda\xba\xf4\x9b\x2f\x00\x73\xe3\x32\x12\xa0\xb4\x52\xd5\xad\xe6\x0e\xf7\x58\x8c\x4d\x0f\x2b\x0e\x82\xaa\x5c\xb9\xcc\x9a\x48\x8c\x9b\x43\x70\xfe\xbb\x49\x53\x09\xb5\x89\xb8\x35\x0d\x63\xf8\x4a\x5d\xa6\x7c\x51\x7a\x07\x0e\x0f\x10\xfe\x1e\x3c\x0d\xab\xbd\x99\x87\x40\xc7\xee\x6c\x43\xea\xb1\xb4\x59\x11\xa3\x53\xaa\xb7\x2f\x2a\x25\xca\xca\x18\x53\xea\xe4\x8a\x15\xba\x5e\xaa\xcd\xea\xe0\x5d\xef\xa5\xac\x4d\x4a\xeb\xee\x2e\xc6\x28\x76\xaa\xff\x75\x00\xf7\xa4\x7a\x73\xea\xdf\xaf\x75\x21\xba\x7b\xfc\x99\x07\x70\x1a\xc2\x45\xb2\xfb\x02\x10\xd3\x77\x44\x7b\x55\x15\xf5\xa6\x66\x80\xf7\x16\xea\xe6\x0f\x9b\x07\x7d\x71\xbe\xe3\x9f\x5f\x5e\x7e\xdb\xa3\x1e\xac\x60\x87\x0f\x63\xe7\xce\x20\x43\xdb\xe9\x0f\xdd\xb9\x79\x81\x53\xfb\x99\x3f\x96\xa9\x33\xc6\x9e\x1e\xef\x1e\xc9\xc5\xb2\x0a\x4b\x5f\x98\x68\x2e\x3f\x92\x02\x5c\xf5\x27\xfa\x2c\xb3\x40\xb4\x87\xe8\xce\x91\xac\x7d\x58\x92\x32\xf8\x12\x82\xdd\x0c\xf5\xff\x3d\x71\x5f\xfb\xa4\x2f\x06\x2f\xfa\x91\x42\xd0\x5d\xfe\x44\x34\x9f\xaa\x7f\x05\x00\x00\xff\xff\x4d\x62\xae\x61\xba\x0a\x00\x00") + +func dashboardHtmlBytes() ([]byte, error) { + return bindataRead( + _dashboardHtml, + "dashboard.html", + ) +} + +func dashboardHtml() (*asset, error) { + bytes, err := dashboardHtmlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "dashboard.html", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +// Asset loads and returns the asset for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func Asset(name string) ([]byte, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) + } + return a.bytes, nil + } + return nil, fmt.Errorf("Asset %s not found", name) +} + +// MustAsset is like Asset but panics when Asset would return an error. +// It simplifies safe initialization of global variables. +func MustAsset(name string) []byte { + a, err := Asset(name) + if err != nil { + panic("asset: Asset(" + name + "): " + err.Error()) + } + + return a +} + +// AssetInfo loads and returns the asset info for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func AssetInfo(name string) (os.FileInfo, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) + } + return a.info, nil + } + return nil, fmt.Errorf("AssetInfo %s not found", name) +} + +// AssetNames returns the names of the assets. +func AssetNames() []string { + names := make([]string, 0, len(_bindata)) + for name := range _bindata { + names = append(names, name) + } + return names +} + +// _bindata is a table, holding each asset generator, mapped to its name. +var _bindata = map[string]func() (*asset, error){ + "components/dashboard.js": componentsDashboardJs, + "dashboard.html": dashboardHtml, +} + +// AssetDir returns the file names below a certain +// directory embedded in the file by go-bindata. +// For example if you run go-bindata on data/... and data contains the +// following hierarchy: +// data/ +// foo.txt +// img/ +// a.png +// b.png +// then AssetDir("data") would return []string{"foo.txt", "img"} +// AssetDir("data/img") would return []string{"a.png", "b.png"} +// AssetDir("foo.txt") and AssetDir("notexist") would return an error +// AssetDir("") will return []string{"data"}. +func AssetDir(name string) ([]string, error) { + node := _bintree + if len(name) != 0 { + cannonicalName := strings.Replace(name, "\\", "/", -1) + pathList := strings.Split(cannonicalName, "/") + for _, p := range pathList { + node = node.Children[p] + if node == nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + } + } + if node.Func != nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + rv := make([]string, 0, len(node.Children)) + for childName := range node.Children { + rv = append(rv, childName) + } + return rv, nil +} + +type bintree struct { + Func func() (*asset, error) + Children map[string]*bintree +} +var _bintree = &bintree{nil, map[string]*bintree{ + "components": &bintree{nil, map[string]*bintree{ + "dashboard.js": &bintree{componentsDashboardJs, map[string]*bintree{}}, + }}, + "dashboard.html": &bintree{dashboardHtml, map[string]*bintree{}}, +}} + +// RestoreAsset restores an asset under the given directory +func RestoreAsset(dir, name string) error { + data, err := Asset(name) + if err != nil { + return err + } + info, err := AssetInfo(name) + if err != nil { + return err + } + err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) + if err != nil { + return err + } + err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) + if err != nil { + return err + } + err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) + if err != nil { + return err + } + return nil +} + +// RestoreAssets restores an asset under the given directory recursively +func RestoreAssets(dir, name string) error { + children, err := AssetDir(name) + // File + if err != nil { + return RestoreAsset(dir, name) + } + // Dir + for _, child := range children { + err = RestoreAssets(dir, filepath.Join(name, child)) + if err != nil { + return err + } + } + return nil +} + +func _filePath(dir, name string) string { + cannonicalName := strings.Replace(name, "\\", "/", -1) + return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) +} + diff --git a/dashboard/assets/components/dashboard.js b/dashboard/assets/components/dashboard.js new file mode 100644 index 0000000000..956b5d4e79 --- /dev/null +++ b/dashboard/assets/components/dashboard.js @@ -0,0 +1,282 @@ +Chart.defaults.global.legend = { enabled: false }; + +const Component = React.Component; +// const Component = Inferno.Component; + +// isNullOrUndefined returns true if a variable is null or undefined. +let isNullOrUndefined = variable => variable === null || typeof variable === 'undefined'; + +// MenuItem renders an item for a Menu component and the belonging submenu items, if there is any. +class MenuItem extends Component { + render = () =>