Browse Source

Merge branch 'adamierymenko-dev' into android-jni

Grant Limberg 10 years ago
parent
commit
8130b2a0de
8 changed files with 1133 additions and 2655 deletions
  1. 0 2606
      ui/JSXTransformer.js
  2. 654 0
      ui/JSXTransformer.min.js
  3. 80 0
      ui/ZeroTierNetwork.jsx
  4. 156 17
      ui/ZeroTierNode.jsx
  5. 0 4
      ui/bootstrap-theme.min.css
  6. 0 4
      ui/bootstrap.min.css
  7. 4 1
      ui/index.html
  8. 239 23
      ui/zerotier.css

File diff suppressed because it is too large
+ 0 - 2606
ui/JSXTransformer.js


File diff suppressed because it is too large
+ 654 - 0
ui/JSXTransformer.min.js


+ 80 - 0
ui/ZeroTierNetwork.jsx

@@ -0,0 +1,80 @@
+var ZeroTierNetwork = React.createClass({
+	getInitialState: function() {
+		return {
+			deleted: false
+		};
+	},
+
+	leaveNetwork: function(event) {
+		Ajax.call({
+			url: 'network/'+this.props.nwid+'?auth='+this.props.authToken,
+			cache: false,
+			type: 'DELETE',
+			success: function(data) {
+				this.setState({deleted: true});
+			}.bind(this),
+			error: function(error) {
+			}.bind(this)
+		});
+		event.preventDefault();
+	},
+
+	render: function() {
+		return (
+			<div className="zeroTierNetwork">
+				{
+					(this.state.deleted) ? (
+						<div className="deletedOverlay">&nbsp;</div>
+					) : (null)
+				}
+				<div className="networkInfo">
+					<span className="networkId">{this.props.nwid}</span>
+					<span className="networkName">{this.props.name}</span>
+				</div>
+				<div className="networkProps">
+					<div className="row">
+						<div className="name">Status</div>
+						<div className="value">{this.props['status']}</div>
+					</div>
+					<div className="row">
+						<div className="name">Type</div>
+						<div className="value">{this.props['type']}</div>
+					</div>
+					<div className="row">
+						<div className="name">MAC</div>
+						<div className="value zeroTierAddress">{this.props['mac']}</div>
+					</div>
+					<div className="row">
+						<div className="name">MTU</div>
+						<div className="value">{this.props['mtu']}</div>
+					</div>
+					<div className="row">
+						<div className="name">Broadcast</div>
+						<div className="value">{(this.props['broadcastEnabled']) ? 'ENABLED' : 'DISABLED'}</div>
+					</div>
+					<div className="row">
+						<div className="name">Bridging</div>
+						<div className="value">{(this.props['bridge']) ? 'ACTIVE' : 'DISABLED'}</div>
+					</div>
+					<div className="row">
+						<div className="name">Device</div>
+						<div className="value">{(this.props['portDeviceName']) ? this.props['portDeviceName'] : '(none)'}</div>
+					</div>
+					<div className="row">
+						<div className="name">Managed&nbsp;IPs</div>
+						<div className="value ipList">
+							{
+								this.props['assignedAddresses'].map(function(ipAssignment) {
+									return (
+										<div className="ipAddress">{ipAssignment}</div>
+									);
+								})
+							}
+						</div>
+					</div>
+				</div>
+				<button className="leaveNetworkButton" onClick={this.leaveNetwork}>Leave&nbsp;Network</button>
+			</div>
+		);
+	}
+});

+ 156 - 17
ui/ZeroTierNode.jsx

@@ -3,46 +3,185 @@ var ZeroTierNode = React.createClass({
 		return {
 		return {
 			address: '----------',
 			address: '----------',
 			online: false,
 			online: false,
-			version: '_._._'
+			version: '_._._',
+			_networks: [],
+			_peers: []
 		};
 		};
 	},
 	},
 
 
+	ago: function(ms) {
+		if (ms > 0) {
+			var tmp = Math.round((Date.now() - ms) / 1000);
+			return ((tmp > 0) ? tmp : 0);
+		} else return 0;
+	},
+
+	updatePeers: function() {
+		Ajax.call({
+			url: 'peer?auth='+this.props.authToken,
+			cache: false,
+			type: 'GET',
+			success: function(data) {
+				if (data) {
+					var pl = JSON.parse(data);
+					if (Array.isArray(pl)) {
+						this.setState({_peers: pl});
+					}
+				}
+			}.bind(this),
+			error: function() {
+			}.bind(this)
+		});
+	},
+	updateNetworks: function() {
+		Ajax.call({
+			url: 'network?auth='+this.props.authToken,
+			cache: false,
+			type: 'GET',
+			success: function(data) {
+				if (data) {
+					var nwl = JSON.parse(data);
+					if (Array.isArray(nwl)) {
+						this.setState({_networks: nwl});
+					}
+				}
+			}.bind(this),
+			error: function() {
+			}.bind(this)
+		});
+	},
 	updateAll: function() {
 	updateAll: function() {
 		Ajax.call({
 		Ajax.call({
 			url: 'status?auth='+this.props.authToken,
 			url: 'status?auth='+this.props.authToken,
 			cache: false,
 			cache: false,
 			type: 'GET',
 			type: 'GET',
 			success: function(data) {
 			success: function(data) {
-				if (data)
-					this.setState(JSON.parse(data));
+				if (data) {
+					var status = JSON.parse(data);
+					this.setState(status);
+					document.title = 'ZeroTier One [' + status.address + ']';
+				}
+				this.updateNetworks();
+				this.updatePeers();
 			}.bind(this),
 			}.bind(this),
 			error: function() {
 			error: function() {
-				this.setState(this.getInitialState());
+				this.setState({online: false});
 			}.bind(this)
 			}.bind(this)
-		})
+		});
+	},
+	joinNetwork: function(event) {
+		event.preventDefault();
+		if ((this.networkToJoin)&&(this.networkToJoin.length === 16)) {
+			Ajax.call({
+				url: 'network/'+this.networkToJoin+'?auth='+this.props.authToken,
+				cache: false,
+				type: 'POST',
+				success: function(data) {
+				}.bind(this),
+				error: function() {
+				}.bind(this)
+			});
+		}
+	},
+	handleNetworkIdEntry: function(event) {
+		var nid = event.target.value;
+		if (nid) {
+			nid = nid.toLowerCase();
+			var nnid = '';
+			for(var i=0;((i<nid.length)&&(i<16));++i) {
+				if ("0123456789abcdef".indexOf(nid.charAt(i)) >= 0)
+					nnid += nid.charAt(i);
+			}
+			this.networkToJoin = nnid;
+			event.target.value = nnid;
+		} else {
+			this.networkToJoin = '';
+			event.target.value = '';
+		}
 	},
 	},
 
 
 	componentDidMount: function() {
 	componentDidMount: function() {
+		this.tabIndex = 0;
 		this.updateAll();
 		this.updateAll();
-//		this.updateIntervalId = setInterval(this.updateAll,2500);
+		this.updateIntervalId = setInterval(this.updateAll,2500);
 	},
 	},
 	componentWillUnmount: function() {
 	componentWillUnmount: function() {
-//		clearInterval(this.updateIntervalId);
+		clearInterval(this.updateIntervalId);
 	},
 	},
 	render: function() {
 	render: function() {
 		return (
 		return (
-			<div className="container-fluid zeroTierNode">
-				<div className="row">
+			<div className="zeroTierNode">
+				<div className="top">&nbsp;&nbsp;
+					<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>
+				<div className="middle">
+					<div className="middleScroll">
+						{
+							(this.tabIndex === 1) ? (
+								<div className="peers">
+									<div className="peerHeader">
+										<div className="f">Address</div>
+										<div className="f">Version</div>
+										<div className="f">Latency</div>
+										<div className="f">Direct&nbsp;Paths</div>
+										<div className="f">Role</div>
+									</div>
+									{
+										this.state._peers.map(function(peer) {
+											return (
+												<div className="peer">
+													<div className="f zeroTierAddress">{peer['address']}</div>
+													<div className="f">{(peer['version'] === '-1.-1.-1') ? '-' : peer['version']}</div>
+													<div className="f">{peer['latency']}</div>
+													<div className="f">
+														{
+															(peer['paths'].length === 0) ? (
+																<div className="peerPath"><i>(none)</i></div>
+															) : (
+																<div>
+																{
+																	peer['paths'].map(function(path) {
+																		if ((path.active)||(path.fixed)) {
+																			return (
+																				<div className="peerPath">{path.address}&nbsp;{this.ago(path.lastSend)}&nbsp;{this.ago(path.lastReceive)}{path.preferred ? ' *' : ''}</div>
+																			);
+																		} else {
+																			return (
+																				<div className="peerPathInactive">{path.address}&nbsp;{this.ago(path.lastSend)}&nbsp;{this.ago(path.lastReceive)}</div>
+																			);
+																		}
+																	}.bind(this))
+																}
+																</div>
+															)
+														}
+													</div>
+													<div className="f">{peer['role']}</div>
+												</div>
+											);
+										}.bind(this))
+									}
+								</div>
+							) : (
+								<div className="networks">
+									{
+										this.state._networks.map(function(network) {
+											network['authToken'] = this.props.authToken;
+											return React.createElement('div',{className: 'network'},React.createElement(ZeroTierNetwork,network));
+										}.bind(this))
+									}
+								</div>
+							)
+						}
+					</div>
 				</div>
 				</div>
-				<div className="row">
-					<div className="col-xs-8">
-						<span className="zerotier-address">{this.state.address}</span>
-						<span className="zerotier-node-statusline">{this.state.online ? 'ONLINE' : 'OFFLINE'}&nbsp;&nbsp;{this.state.version}</span>
+				<div className="bottom">
+					<div className="left">
+						<span className="statusLine"><span className="zeroTierAddress">{this.state.address}</span>&nbsp;&nbsp;{this.state.online ? 'ONLINE' : 'OFFLINE'}&nbsp;&nbsp;{this.state.version}</span>
 					</div>
 					</div>
-					<div className="col-xs-4">
-						<form>
-							<input type="text"/>
-						</form>
+					<div className="right">
+						<form onSubmit={this.joinNetwork}><input type="text" placeholder="################" onChange={this.handleNetworkIdEntry} size="16"/><button type="submit">Join</button></form>
 					</div>
 					</div>
 				</div>
 				</div>
 			</div>
 			</div>

File diff suppressed because it is too large
+ 0 - 4
ui/bootstrap-theme.min.css


File diff suppressed because it is too large
+ 0 - 4
ui/bootstrap.min.css


+ 4 - 1
ui/index.html

@@ -4,14 +4,17 @@
 	<title>ZeroTier One</title>
 	<title>ZeroTier One</title>
 	<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 	<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 	<meta name="viewport" content="width=device-width, initial-scale=1">
 	<meta name="viewport" content="width=device-width, initial-scale=1">
+	<!--
 	<link rel="stylesheet" href="bootstrap.min.css">
 	<link rel="stylesheet" href="bootstrap.min.css">
 	<link rel="stylesheet" href="bootstrap-theme.min.css">
 	<link rel="stylesheet" href="bootstrap-theme.min.css">
+	-->
 	<link rel="stylesheet" href="zerotier.css">
 	<link rel="stylesheet" href="zerotier.css">
 
 
 	<script src="simpleajax.min.js"></script>
 	<script src="simpleajax.min.js"></script>
 	<script src="react.min.js"></script>
 	<script src="react.min.js"></script>
-	<script src="JSXTransformer.js"></script>
+	<script src="JSXTransformer.min.js"></script>
 
 
+	<script type="text/jsx" src="ZeroTierNetwork.jsx"></script>
 	<script type="text/jsx" src="ZeroTierNode.jsx"></script>
 	<script type="text/jsx" src="ZeroTierNode.jsx"></script>
 
 
 	<script type="text/jsx" src="main.jsx"></script>
 	<script type="text/jsx" src="main.jsx"></script>

+ 239 - 23
ui/zerotier.css

@@ -3,37 +3,253 @@
  * Light yellow: #ffffcc
  * Light yellow: #ffffcc
  * Orange: #ffb354 */
  * Orange: #ffb354 */
 
 
-/*
-@font-face {
-	font-family: 'Clear Sans Thin';
-	src: url('fonts/clearsans_thin/ClearSans-Thin-webfont.eot');
-	src: url('fonts/clearsans_thin/ClearSans-Thin-webfont.eot?#iefix') format('embedded-opentype'), url('fonts/clearsans_thin/ClearSans-Thin-webfont.woff') format('woff'), url('fonts/clearsans_thin/ClearSans-Thin-webfont.ttf') format('truetype'), url('fonts/clearsans_thin/ClearSans-Thin-webfont.svg#clear_sans_thinregular') format('svg');
-	font-weight: normal;
-	font-style: normal;
-}
-*/
-/*
-@font-face {
-	font-family: 'Clear Sans Regular';
-	src: url('ClearSans-Regular-webfont.eot');
-	src: url('ClearSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), url('ClearSans-Regular-webfont.woff') format('woff'), url('ClearSans-Regular-webfont.ttf') format('truetype'), url('ClearSans-Regular-webfont.svg#clear_sansregular') format('svg');
-	font-weight: normal;
-	font-style: normal;
-}
-*/
-
 html,body {
 html,body {
 	font-family: "Helvetica Neue","Lucida Sans Unicode",sans-serif;
 	font-family: "Helvetica Neue","Lucida Sans Unicode",sans-serif;
 	font-size: 12pt;
 	font-size: 12pt;
 	margin: 0;
 	margin: 0;
 	padding: 0;
 	padding: 0;
 	width: 100%;
 	width: 100%;
+	height: 100%;
+	overflow: hidden;
+}
+
+.zeroTierAddress {
+	font-family: monospace;
+}
+
+.zeroTierNode {
+	width: 100%;
+	height: 100%;
+	max-height: 100%;
+	padding: 0;
+	margin: 0;
+	display: table;
+}
+
+.zeroTierNode > .top {
+	width: 100%;
+	overflow: hidden;
+	display: table-row;
+	white-space: nowrap;
+	background: #234447;
+	color: #ffffff;
+	padding: 0;
+	margin: 0;
+}
+.zeroTierNode > .top button {
+	display: inline-block;
+	padding: 0.25rem 0.75rem 0.25rem 0.75rem;
+	color: #ffffff;
+	margin: 0;
+	border: 0;
+	outline: none;
+	background: #234447;
+	font-size: 12pt;
+	cursor: pointer;
+}
+.zeroTierNode > .top button:hover {
+	background: #91a2a3;
+}
+.zeroTierNode > .top button:disabled {
+	background: #91a2a3;
+}
+
+.zeroTierNode > .middle {
+	height: 100%;
+	width: 100%;
+	padding: 0;
+	margin: 0;
+	overflow: hidden;
+	display: table-row;
+}
+.zeroTierNode > .middle > .middleScroll {
+	display: block;
+	width: 100%;
+	height: 100%;
+	padding: 0;
+	margin: 0;
+	overflow-x: hidden;
+	overflow-y: scroll;
+	background: #eeeeee;
+}
+.zeroTierNode > .middle > .middleScroll > .networks {
+	display: block;
+	width: auto;
+	padding: 0;
+	margin: 0;
+	border: 0;
+	border-collapse: collapse;
+}
+.zeroTierNode > .middle > .middleScroll > .networks > .network {
+	padding: 0.5rem;
+	margin: 0.25rem;
+	float: left;
+	display: inline-block;
+	border: 1px solid #234447;
+	background: #ffffff;
+}
+.zeroTierNode > .middle > .middleScroll > .peers {
+	display: table;
+	width: 100%;
+	padding: 0;
+	margin: 0;
+	border-collapse: collapse;
+}
+.zeroTierNode > .middle > .middleScroll > .peers > .peer {
+	width: 100%;
+	display: table-row;
+	background: #ffffff;
+}
+.zeroTierNode > .middle > .middleScroll > .peers > .peer .peerPath {
+	font-size: 10pt;
+	font-family: monospace;
+	white-space: nowrap;
+}
+.zeroTierNode > .middle > .middleScroll > .peers > .peer .peerPathInactive {
+	font-size: 10pt;
+	font-family: monospace;
+	color: #bbbbbb;
+	text-decoration: line-through;
+	white-space: nowrap;
+}
+.zeroTierNode > .middle > .middleScroll > .peers > .peer > .f {
+	display: table-cell;
+	font-size: 10pt;
+}
+.zeroTierNode > .middle > .middleScroll > .peers > .peerHeader {
+	width: 100%;
+	display: table-row;
+	background: #ffffff;
+	border-bottom: 1px solid #000000;
+}
+.zeroTierNode > .middle > .middleScroll > .peers > .peerHeader > .f {
+	display: table-cell;
+	font-size: 10pt;
+	font-weight: bold;
 }
 }
 
 
-.zerotier-address {
+.zeroTierNode > .bottom {
+	width: 100%;
+	overflow: hidden;
+	display: table-row;
+	background: #234447;
+	color: #ffffff;
+}
+.zeroTierNode > .bottom > .left {
+	text-align: left;
+	white-space: nowrap;
+	float: left;
+	padding: 0 0 0 0.5rem;
+}
+.zeroTierNode > .bottom > .left > .statusLine {
 	font-family: monospace;
 	font-family: monospace;
+	white-space: nowrap;
+	font-size: 12pt;
+}
+.zeroTierNode > .bottom > .right {
+	background: #91a2a3;
+	text-align: right;
+	white-space: nowrap;
+	float: right;
+}
+.zeroTierNode > .bottom > .right input {
+	font-family: monospace;
+	font-size: 12pt;
+	background: #91a2a3;
+	color: #ffffff;
+	outline: none;
+	border: 0;
+	margin: 0;
+	padding: 0.05rem 0.25rem 0.05rem 0.25rem;
+	height: 100%;
+	display: inline-block;
+}
+.zeroTierNode > .bottom > .right button {
+	display: inline-block;
+	font-size: 12pt;
+	background: #ffb354;
+	border: 1px solid #ffb354;
+	color: #000000;
+	margin: 0;
+	padding: 0.05rem 0.75rem 0.05rem 0.75rem;
+	height: 100%;
+}
+.zeroTierNode > .bottom > .right button:hover {
+	cursor: pointer;
+	border: 1px solid #000000;
+}
+
+.zeroTierNetwork {
+	padding: 0;
+	margin: 0;
+	display: inline-block;
+	text-align: right;
+	width: 100%;
+	position: relative;
+}
+.zeroTierNetwork .deletedOverlay {
+	width: 100%;
+	height: 100%;
+	position: absolute;
+	background: rgba(255,255,255,0.8);
+	display: block;
+	top: 0;
+	left: 0;
+	z-index: 2;
+}
+.zeroTierNetwork .networkInfo {
+	padding: 0 0 0.5rem 0;
+	text-align: left;
+	font-size: 12pt;
+}
+.zeroTierNetwork .networkInfo .networkId {
+	font-size: 10pt;
+	font-family: monospace;
+	color: #91a2a3;
+}
+.zeroTierNetwork .networkInfo .networkName {
+	padding: 0 0 0 1rem;
+	float: right;
+	font-size: 12pt;
+}
+.zeroTierNetwork .networkProps {
+	width: 100%;
+	display: table;
+	padding: 0;
+	margin: 0 auto 0 auto;
+	border-top: 1px solid #999999;
+	border-bottom: 1px solid #999999;
+}
+.zeroTierNetwork .networkProps > .row {
+	display: table-row;
+}
+.zeroTierNetwork .networkProps > .row > .name {
+	display: table-cell;
+	font-size: 10pt;
+	padding: 0.1rem 0.5rem 0.1rem 0.5rem;
+}
+.zeroTierNetwork .networkProps > .row > .value {
+	font-size: 10pt;
+	display: table-cell;
+	padding: 0.1rem 0.5rem 0.1rem 0.5rem;
+	background: #eeeeee;
+}
+.zeroTierNetwork .ipList {
+}
+.zeroTierNetwork .ipAddress {
+	font-family: monospace;
+	font-size: 10pt;
+}
+.zeroTierNetwork .leaveNetworkButton {
+	padding: 0.25rem 0.5rem 0.25rem 0.5rem;
+	margin: 0.5rem 0 0 0;
+	font-size: 10pt;
+	background: #ffffff;
+	outline: none;
+	background: #ffb354;
+	border: 1px solid #ffb354;
+	cursor: pointer;
 }
 }
-.zerotier-node-statusline {
-	font-size: smaller;
-	padding: 0 0.75rem 0 0.75rem;
+.zeroTierNetwork .leaveNetworkButton:hover {
+	border: 1px solid #000000;
 }
 }

Some files were not shown because too many files changed in this diff