|
@@ -56,6 +56,7 @@ var ZeroTierNode = React.createClass({
|
|
|
cache: false,
|
|
|
type: 'GET',
|
|
|
success: function(data) {
|
|
|
+ this.alertedToFailure = false;
|
|
|
if (data) {
|
|
|
var status = JSON.parse(data);
|
|
|
this.setState(status);
|
|
@@ -65,7 +66,11 @@ var ZeroTierNode = React.createClass({
|
|
|
this.updatePeers();
|
|
|
}.bind(this),
|
|
|
error: function() {
|
|
|
- this.setState({online: false});
|
|
|
+ this.setState(this.getInitialState());
|
|
|
+ if (!this.alertedToFailure) {
|
|
|
+ this.alertedToFailure = true;
|
|
|
+ alert('Authorization token invalid or ZeroTier One service not running.');
|
|
|
+ }
|
|
|
}.bind(this)
|
|
|
});
|
|
|
},
|
|
@@ -77,13 +82,20 @@ var ZeroTierNode = React.createClass({
|
|
|
cache: false,
|
|
|
type: 'POST',
|
|
|
success: function(data) {
|
|
|
+ this.networkToJoin = '';
|
|
|
+ if (this.networkInputElement)
|
|
|
+ this.networkInputElement.value = '';
|
|
|
+ this.updateNetworks();
|
|
|
}.bind(this),
|
|
|
error: function() {
|
|
|
}.bind(this)
|
|
|
});
|
|
|
+ } else {
|
|
|
+ alert('To join a network, enter its 16-digit network ID.');
|
|
|
}
|
|
|
},
|
|
|
handleNetworkIdEntry: function(event) {
|
|
|
+ this.networkInputElement = event.target;
|
|
|
var nid = event.target.value;
|
|
|
if (nid) {
|
|
|
nid = nid.toLowerCase();
|
|
@@ -100,6 +112,15 @@ var ZeroTierNode = React.createClass({
|
|
|
}
|
|
|
},
|
|
|
|
|
|
+ handleNetworkDelete: function(nwid) {
|
|
|
+ var networks = [];
|
|
|
+ for(var i=0;i<this.state._networks.length;++i) {
|
|
|
+ if (this.state._networks[i].nwid !== nwid)
|
|
|
+ networks.push(this.state._networks[i]);
|
|
|
+ }
|
|
|
+ this.setState({_networks: networks});
|
|
|
+ },
|
|
|
+
|
|
|
componentDidMount: function() {
|
|
|
this.tabIndex = 0;
|
|
|
this.updateAll();
|
|
@@ -109,11 +130,15 @@ var ZeroTierNode = React.createClass({
|
|
|
clearInterval(this.updateIntervalId);
|
|
|
},
|
|
|
render: function() {
|
|
|
+ /* We implement tabs in a very simple way here with a React JSX conditional. The tabIndex
|
|
|
+ * local variable indicates the tab, and switching it determines which set of things we
|
|
|
+ * render in the main middle portion. On tab switch calls forceUpdate(). */
|
|
|
return (
|
|
|
<div className="zeroTierNode">
|
|
|
<div className="top">
|
|
|
<button disabled={this.tabIndex === 0} onClick={function() {this.tabIndex = 0; this.forceUpdate();}.bind(this)}>Networks</button>
|
|
|
<button disabled={this.tabIndex === 1} onClick={function() {this.tabIndex = 1; this.forceUpdate();}.bind(this)}>Peers</button>
|
|
|
+ <div className="logo">⏁ </div>
|
|
|
</div>
|
|
|
<div className="middle">
|
|
|
<div className="middleScroll">
|
|
@@ -124,7 +149,8 @@ var ZeroTierNode = React.createClass({
|
|
|
<div className="f">Address</div>
|
|
|
<div className="f">Version</div>
|
|
|
<div className="f">Latency</div>
|
|
|
- <div className="f">Direct Paths</div>
|
|
|
+ <div className="f">Data Paths</div>
|
|
|
+ <div className="f">Last Frame</div>
|
|
|
<div className="f">Role</div>
|
|
|
</div>
|
|
|
{
|
|
@@ -137,26 +163,22 @@ var ZeroTierNode = React.createClass({
|
|
|
<div className="f">
|
|
|
{
|
|
|
(peer['paths'].length === 0) ? (
|
|
|
- <div className="peerPath"><i>(none)</i></div>
|
|
|
+ <div className="peerPath"></div>
|
|
|
) : (
|
|
|
<div>
|
|
|
{
|
|
|
peer['paths'].map(function(path) {
|
|
|
- if ((path.active)||(path.fixed)) {
|
|
|
- return (
|
|
|
- <div className="peerPath">{path.address} {this.ago(path.lastSend)} {this.ago(path.lastReceive)}{path.preferred ? ' *' : ''}</div>
|
|
|
- );
|
|
|
- } else {
|
|
|
- return (
|
|
|
- <div className="peerPathInactive">{path.address} {this.ago(path.lastSend)} {this.ago(path.lastReceive)}</div>
|
|
|
- );
|
|
|
- }
|
|
|
+ var cn = ((path.active)||(path.fixed)) ? (path.preferred ? 'peerPathPreferred' : 'peerPathActive') : 'peerPathInactive';
|
|
|
+ return (
|
|
|
+ <div className={cn}>{path.address} {this.ago(path.lastSend)}/{this.ago(path.lastReceive)}</div>
|
|
|
+ );
|
|
|
}.bind(this))
|
|
|
}
|
|
|
</div>
|
|
|
)
|
|
|
}
|
|
|
</div>
|
|
|
+ <div className="f">{this.ago(peer['lastUnicastFrame'])}</div>
|
|
|
<div className="f">{peer['role']}</div>
|
|
|
</div>
|
|
|
);
|
|
@@ -168,6 +190,7 @@ var ZeroTierNode = React.createClass({
|
|
|
{
|
|
|
this.state._networks.map(function(network) {
|
|
|
network['authToken'] = this.props.authToken;
|
|
|
+ network['onNetworkDeleted'] = this.handleNetworkDelete;
|
|
|
return React.createElement('div',{className: 'network'},React.createElement(ZeroTierNetwork,network));
|
|
|
}.bind(this))
|
|
|
}
|
|
@@ -181,7 +204,7 @@ var ZeroTierNode = React.createClass({
|
|
|
<span className="statusLine"><span className="zeroTierAddress">{this.state.address}</span> {this.state.online ? 'ONLINE' : 'OFFLINE'} {this.state.version}</span>
|
|
|
</div>
|
|
|
<div className="right">
|
|
|
- <form onSubmit={this.joinNetwork}><input type="text" placeholder="################" onChange={this.handleNetworkIdEntry} size="16"/><button type="submit">Join</button></form>
|
|
|
+ <form onSubmit={this.joinNetwork}><input type="text" placeholder=" [ Network ID ]" onChange={this.handleNetworkIdEntry} size="16"/><button type="submit">Join</button></form>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|