whispervis/widgets/network_selector.go
2018-10-24 22:55:21 +02:00

159 lines
3.6 KiB
Go

package widgets
import (
"bytes"
"fmt"
"github.com/gopherjs/vecty"
"github.com/gopherjs/vecty/elem"
"github.com/gopherjs/vecty/event"
"github.com/status-im/whispervis/network"
"github.com/status-im/whispervis/storage"
)
// NetworkSelector represents widget for choosing or uploading network topology
// to be used for visualization.
type NetworkSelector struct {
vecty.Core
current *network.Network
isCustom bool
networks map[string]*network.Network
upload *UploadWidget
handler func(*network.Network) // executed on network change
}
// NewNetworkSelector creates new NetworkSelector.
func NewNetworkSelector(handler func(*network.Network)) *NetworkSelector {
current := &network.Network{}
networks, err := network.LoadNetworks()
if err != nil {
fmt.Println("No networks loaded:", err)
} else {
current = networks[storage.Network()]
}
ns := &NetworkSelector{
networks: networks,
current: current,
handler: handler,
}
ns.upload = NewUploadWidget(ns.onUpload)
ns.setCurrentNetwork(current)
return ns
}
// Render implements the vecty.Component interface.
func (n *NetworkSelector) Render() vecty.ComponentOrHTML {
return Widget(
Header("Network graph:"),
elem.Div(
vecty.Markup(
vecty.Class("select", "is-fullwidth"),
event.Change(n.onChange),
),
elem.Select(
vecty.Markup(
event.Change(n.onChange),
),
n.networkOptions(),
elem.Option(
vecty.Markup(
vecty.Property("value", "upload"),
vecty.Property("selected", n.isCustom),
),
vecty.Text("Upload custom..."),
),
),
),
n.descriptionBlock(),
vecty.If(n.isCustom, n.upload),
)
}
// descriptionBlock renders the block with network description.
func (n *NetworkSelector) descriptionBlock() *vecty.HTML {
if n.current == nil || n.current.Description == "" {
return elem.Span()
}
return elem.Div(
vecty.Markup(
vecty.Class("is-small", "is-marginless"),
),
elem.Div(
vecty.If(n.isCustom, vecty.Text("Upload custom graph...")),
vecty.If(!n.isCustom, vecty.Text(n.current.Description)),
),
)
}
// networkOptions renders 'option' elements for network 'select' input tag.
func (n *NetworkSelector) networkOptions() vecty.List {
var options vecty.List
for name := range n.networks {
options = append(options, elem.Option(
vecty.Markup(
vecty.Property("value", name),
vecty.Property("selected", n.current.Name == "data/"+name), // TODO(divan): get rid of "data"
),
vecty.Text(name),
))
}
return options
}
// 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)
n.handler(n.current)
// save to localstorage
storage.SetNetwork(value)
vecty.Rerender(n)
}
// onUpload implements callback for "Upload" button clicked event.
func (n *NetworkSelector) onUpload(json []byte) {
r := bytes.NewReader(json)
net, err := network.LoadNetworkFromReader(r)
if err != nil {
fmt.Printf("[ERROR] Load network: %v", err)
}
net.Name = fmt.Sprintf("Uploaded (%d nodes)", net.NodesCount())
n.networks[net.Name] = net
n.setCurrentNetwork(net)
if n.handler != nil {
go n.handler(n.current)
}
vecty.Rerender(n)
}
// Current returns the currently selected network.
func (n *NetworkSelector) Current() *network.Network {
return n.current
}
// setCurrentNetwork changes current network and runs needed update handlers.
func (n *NetworkSelector) setCurrentNetwork(net *network.Network) {
n.current = net
}