2018-09-18 14:01:13 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2018-09-19 09:02:35 +00:00
|
|
|
"bytes"
|
2018-09-18 16:01:45 +00:00
|
|
|
"fmt"
|
|
|
|
|
2018-09-18 14:01:13 +00:00
|
|
|
"github.com/gopherjs/vecty"
|
|
|
|
"github.com/gopherjs/vecty/elem"
|
|
|
|
"github.com/gopherjs/vecty/event"
|
2018-09-19 09:02:35 +00:00
|
|
|
"github.com/status-im/whispervis/widgets"
|
2018-09-18 14:01:13 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// NetworkSelector represents widget for choosing or uploading network topology
|
|
|
|
// to be used for visualization.
|
|
|
|
type NetworkSelector struct {
|
|
|
|
vecty.Core
|
|
|
|
|
2018-09-18 14:35:16 +00:00
|
|
|
current *Network
|
2018-09-18 16:01:45 +00:00
|
|
|
isCustom bool
|
2018-09-18 14:35:16 +00:00
|
|
|
networks map[string]*Network
|
2018-09-18 16:01:45 +00:00
|
|
|
|
2018-09-19 09:02:35 +00:00
|
|
|
upload *widgets.UploadWidget
|
|
|
|
|
|
|
|
handler func(*Network) // executed on network change
|
2018-09-18 14:01:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewNetworkSelector creates new NetworkSelector.
|
2018-09-18 16:01:45 +00:00
|
|
|
func NewNetworkSelector(handler func(*Network)) *NetworkSelector {
|
|
|
|
current := &Network{}
|
|
|
|
networks, err := LoadNetworks()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println("No networks loaded:", err)
|
|
|
|
} else {
|
|
|
|
current = networks["net100.json"]
|
|
|
|
}
|
|
|
|
|
2018-09-19 09:02:35 +00:00
|
|
|
ns := &NetworkSelector{
|
2018-09-18 16:01:45 +00:00
|
|
|
networks: networks,
|
|
|
|
current: current,
|
|
|
|
handler: handler,
|
|
|
|
}
|
2018-09-19 09:02:35 +00:00
|
|
|
ns.upload = widgets.NewUploadWidget(ns.onUpload)
|
2018-09-19 09:45:54 +00:00
|
|
|
ns.setCurrentNetwork(current)
|
2018-09-19 09:02:35 +00:00
|
|
|
return ns
|
2018-09-18 14:01:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Render implements the vecty.Component interface.
|
|
|
|
func (n *NetworkSelector) Render() vecty.ComponentOrHTML {
|
|
|
|
return elem.Div(
|
|
|
|
elem.Heading3(vecty.Text("Choose network:")),
|
|
|
|
elem.Select(
|
|
|
|
vecty.Markup(
|
|
|
|
event.Change(n.onChange),
|
|
|
|
),
|
2018-09-18 16:01:45 +00:00
|
|
|
n.networkOptions(),
|
2018-09-18 14:01:13 +00:00
|
|
|
elem.Option(
|
|
|
|
vecty.Markup(
|
|
|
|
vecty.Property("value", "upload"),
|
2018-09-18 16:01:45 +00:00
|
|
|
vecty.Property("selected", n.isCustom),
|
2018-09-18 14:01:13 +00:00
|
|
|
),
|
|
|
|
vecty.Text("Upload custom..."),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
n.descriptionBlock(),
|
2018-09-19 09:02:35 +00:00
|
|
|
vecty.If(n.isCustom, n.upload),
|
2018-09-18 14:01:13 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2018-09-19 16:11:02 +00:00
|
|
|
// descriptionBlock renders the block with network description.
|
2018-09-18 14:01:13 +00:00
|
|
|
func (n *NetworkSelector) descriptionBlock() *vecty.HTML {
|
|
|
|
return elem.Div(
|
|
|
|
vecty.Markup(
|
|
|
|
vecty.Style("padding", "7px"),
|
|
|
|
vecty.Style("font-style", "italic"),
|
|
|
|
vecty.Style("color", "blue"),
|
|
|
|
),
|
2018-09-18 14:35:16 +00:00
|
|
|
vecty.Text(n.current.Description),
|
2018-09-18 14:01:13 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2018-09-18 16:01:45 +00:00
|
|
|
// LoadNetworks imports preloaded neworks from the directory with JSON files.
|
|
|
|
func LoadNetworks() (map[string]*Network, error) {
|
|
|
|
files, err := AssetDir("data")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
networks := map[string]*Network{}
|
|
|
|
for _, file := range files {
|
|
|
|
network, err := LoadNetwork("data/" + file)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("load network: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
networks[file] = network
|
|
|
|
}
|
|
|
|
return networks, nil
|
|
|
|
}
|
|
|
|
|
2018-09-19 16:11:02 +00:00
|
|
|
// networkOptions renders 'option' elements for network 'select' input tag.
|
2018-09-18 16:01:45 +00:00
|
|
|
func (n *NetworkSelector) networkOptions() vecty.List {
|
|
|
|
var options vecty.List
|
2018-09-19 09:45:54 +00:00
|
|
|
for name := range n.networks {
|
2018-09-18 16:01:45 +00:00
|
|
|
options = append(options, elem.Option(
|
|
|
|
vecty.Markup(
|
|
|
|
vecty.Property("value", name),
|
2018-09-19 09:45:54 +00:00
|
|
|
vecty.Property("selected", n.current.Name == "data/"+name), // TODO(divan): get rid of "data"
|
2018-09-18 16:01:45 +00:00
|
|
|
),
|
|
|
|
vecty.Text(name),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
return options
|
|
|
|
}
|
2018-09-19 09:02:35 +00:00
|
|
|
|
2018-09-19 09:45:54 +00:00
|
|
|
// onChange implements handler for select input changed value
|
|
|
|
func (n *NetworkSelector) onChange(e *vecty.Event) {
|
|
|
|
value := e.Target.Get("value").String()
|
|
|
|
|
|
|
|
if value == "upload" {
|
|
|
|
n.isCustom = true
|
|
|
|
vecty.Rerender(n)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
n.isCustom = false
|
|
|
|
|
|
|
|
net := n.networks[value]
|
|
|
|
n.setCurrentNetwork(net)
|
|
|
|
|
|
|
|
vecty.Rerender(n)
|
|
|
|
}
|
|
|
|
|
2018-09-19 09:02:35 +00:00
|
|
|
// onUpload implements callback for "Upload" button clicked event.
|
|
|
|
func (n *NetworkSelector) onUpload(json []byte) {
|
|
|
|
r := bytes.NewReader(json)
|
|
|
|
net, err := LoadNetworkFromReader(r)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("[ERROR] Load network: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
net.Name = fmt.Sprintf("Uploaded (%d nodes)", net.NodesCount())
|
2018-09-19 09:45:54 +00:00
|
|
|
|
2018-09-19 09:02:35 +00:00
|
|
|
n.networks[net.Name] = net
|
2018-09-19 09:45:54 +00:00
|
|
|
n.setCurrentNetwork(net)
|
|
|
|
|
|
|
|
vecty.Rerender(n)
|
|
|
|
}
|
|
|
|
|
|
|
|
// setCurrentNetwork changes current network and runs needed update handlers.
|
|
|
|
func (n *NetworkSelector) setCurrentNetwork(net *Network) {
|
2018-09-19 09:02:35 +00:00
|
|
|
n.current = net
|
|
|
|
|
|
|
|
if n.handler != nil {
|
|
|
|
go n.handler(n.current)
|
|
|
|
}
|
|
|
|
}
|