Browse Source

Beginning of HTML+Bootstrap+React UI for new desktop client -- looking like it will be easier than retrofitting the old Qt client for the new API.

Adam Ierymenko 10 years ago
parent
commit
b2b32e5969

+ 32 - 29
service/ControlPlane.cpp

@@ -37,8 +37,7 @@
 #include "../node/InetAddress.hpp"
 #include "../node/InetAddress.hpp"
 #include "../node/Node.hpp"
 #include "../node/Node.hpp"
 #include "../node/Utils.hpp"
 #include "../node/Utils.hpp"
-
-#define ZT_BUILD_IN_WEB_UI
+#include "../osdep/OSUtils.hpp"
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
@@ -242,9 +241,10 @@ static void _jsonAppend(unsigned int depth,std::string &buf,const ZT1_Peer *peer
 	buf.append(json);
 	buf.append(json);
 }
 }
 
 
-ControlPlane::ControlPlane(OneService *svc,Node *n) :
+ControlPlane::ControlPlane(OneService *svc,Node *n,const char *uiStaticPath) :
 	_svc(svc),
 	_svc(svc),
-	_node(n)
+	_node(n),
+	_uiStaticPath((uiStaticPath) ? uiStaticPath : "")
 {
 {
 }
 }
 
 
@@ -316,31 +316,34 @@ unsigned int ControlPlane::handleRequest(
 			 * dot in the first path element (e.g. foo.html) is considered a static page,
 			 * dot in the first path element (e.g. foo.html) is considered a static page,
 			 * as nothing in the API is so named. */
 			 * as nothing in the API is so named. */
 
 
-#ifdef ZT_BUILD_IN_WEB_UI
-			if (ext == ".html")
-				responseContentType = "text/html";
-			else if (ext == ".js")
-				responseContentType = "application/javascript";
-			else if (ext == ".json")
-				responseContentType = "application/json";
-			else if (ext == ".css")
-				responseContentType = "text/css";
-			else if (ext == ".png")
-				responseContentType = "image/png";
-			else if (ext == ".jpg")
-				responseContentType = "image/jpeg";
-			else if (ext == ".gif")
-				responseContentType = "image/gif";
-			else if (ext == ".txt")
-				responseContentType = "text/plain";
-			else if (ext == ".xml")
-				responseContentType = "text/xml";
-			else if (ext == ".svg")
-				responseContentType = "image/svg+xml";
-			else responseContentType = "application/octet-stream";
-			responseBody = "<html><body>Hello World!</body></html>";
-			scode = 200;
-#endif // ZT_BUILD_IN_WEB_UI
+			if (_uiStaticPath.length() > 0) {
+				if (ext == ".html")
+					responseContentType = "text/html";
+				else if (ext == ".js")
+					responseContentType = "application/javascript";
+				else if (ext == ".jsx")
+					responseContentType = "text/jsx";
+				else if (ext == ".json")
+					responseContentType = "application/json";
+				else if (ext == ".css")
+					responseContentType = "text/css";
+				else if (ext == ".png")
+					responseContentType = "image/png";
+				else if (ext == ".jpg")
+					responseContentType = "image/jpeg";
+				else if (ext == ".gif")
+					responseContentType = "image/gif";
+				else if (ext == ".txt")
+					responseContentType = "text/plain";
+				else if (ext == ".xml")
+					responseContentType = "text/xml";
+				else if (ext == ".svg")
+					responseContentType = "image/svg+xml";
+				else responseContentType = "application/octet-stream";
+				scode = OSUtils::readFile((_uiStaticPath + ZT_PATH_SEPARATOR_S + ps[0]).c_str(),responseBody) ? 200 : 404;
+			} else {
+				scode = 404;
+			}
 
 
 		} else if (isAuth) {
 		} else if (isAuth) {
 			/* Things that require authentication -- a.k.a. everything but static web app pages. */
 			/* Things that require authentication -- a.k.a. everything but static web app pages. */

+ 2 - 1
service/ControlPlane.hpp

@@ -49,7 +49,7 @@ struct InetAddress;
 class ControlPlane
 class ControlPlane
 {
 {
 public:
 public:
-	ControlPlane(OneService *svc,Node *n);
+	ControlPlane(OneService *svc,Node *n,const char *uiStaticPath);
 	~ControlPlane();
 	~ControlPlane();
 
 
 	/**
 	/**
@@ -102,6 +102,7 @@ public:
 private:
 private:
 	OneService *const _svc;
 	OneService *const _svc;
 	Node *const _node;
 	Node *const _node;
+	std::string _uiStaticPath;
 	std::set<std::string> _authTokens;
 	std::set<std::string> _authTokens;
 	std::map<std::string,ControlPlaneSubsystem *> _subsystems;
 	std::map<std::string,ControlPlaneSubsystem *> _subsystems;
 	Mutex _lock;
 	Mutex _lock;

+ 1 - 1
service/OneService.cpp

@@ -226,7 +226,7 @@ public:
 			if (_master)
 			if (_master)
 				_node->setNetconfMaster((void *)_master);
 				_node->setNetconfMaster((void *)_master);
 
 
-			_controlPlane = new ControlPlane(this,_node);
+			_controlPlane = new ControlPlane(this,_node,(_homePath + ZT_PATH_SEPARATOR_S + "ui").c_str());
 			_controlPlane->addAuthToken(authToken.c_str());
 			_controlPlane->addAuthToken(authToken.c_str());
 			if (_master)
 			if (_master)
 				_controlPlane->mount("controller",reinterpret_cast<ControlPlaneSubsystem *>(_master));
 				_controlPlane->mount("controller",reinterpret_cast<ControlPlaneSubsystem *>(_master));

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


+ 51 - 0
ui/ZeroTierNode.jsx

@@ -0,0 +1,51 @@
+var ZeroTierNode = React.createClass({
+	getInitialState: function() {
+		return {
+			address: '----------',
+			online: false,
+			version: '_._._'
+		};
+	},
+
+	updateAll: function() {
+		Ajax.call({
+			url: 'status?auth='+this.props.authToken,
+			cache: false,
+			type: 'GET',
+			success: function(data) {
+				if (data)
+					this.setState(JSON.parse(data));
+			}.bind(this),
+			error: function() {
+				this.setState(this.getInitialState());
+			}.bind(this)
+		})
+	},
+
+	componentDidMount: function() {
+		this.updateAll();
+//		this.updateIntervalId = setInterval(this.updateAll,2500);
+	},
+	componentWillUnmount: function() {
+//		clearInterval(this.updateIntervalId);
+	},
+	render: function() {
+		return (
+			<div className="container-fluid zeroTierNode">
+				<div className="row">
+				</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>
+					<div className="col-xs-4">
+						<form>
+							<input type="text"/>
+						</form>
+					</div>
+				</div>
+			</div>
+		);
+	}
+});

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


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


+ 22 - 0
ui/index.html

@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+	<title>ZeroTier One</title>
+	<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
+	<meta name="viewport" content="width=device-width, initial-scale=1">
+	<link rel="stylesheet" href="bootstrap.min.css">
+	<link rel="stylesheet" href="bootstrap-theme.min.css">
+	<link rel="stylesheet" href="zerotier.css">
+
+	<script src="simpleajax.min.js"></script>
+	<script src="react.min.js"></script>
+	<script src="JSXTransformer.js"></script>
+
+	<script type="text/jsx" src="ZeroTierNode.jsx"></script>
+
+	<script type="text/jsx" src="main.jsx"></script>
+</head>
+<body>
+<div style="width: 100%; height: 100%;" id="main"></div>
+</body>
+</html>

+ 4 - 0
ui/main.jsx

@@ -0,0 +1,4 @@
+React.render(
+	<ZeroTierNode authToken={'5d6181b71fae2684f9cc64ed'} />,
+	document.getElementById('main')
+);

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


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


+ 39 - 0
ui/zerotier.css

@@ -0,0 +1,39 @@
+/* Dark blue-grey: #234447
+ * Light blue-grey: #91a2a3
+ * Light yellow: #ffffcc
+ * 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 {
+	font-family: "Helvetica Neue","Lucida Sans Unicode",sans-serif;
+	font-size: 12pt;
+	margin: 0;
+	padding: 0;
+	width: 100%;
+}
+
+.zerotier-address {
+	font-family: monospace;
+}
+.zerotier-node-statusline {
+	font-size: smaller;
+	padding: 0 0.75rem 0 0.75rem;
+}

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