瀏覽代碼

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 年之前
父節點
當前提交
b2b32e5969
共有 12 個文件被更改,包括 2777 次插入31 次删除
  1. 32 29
      service/ControlPlane.cpp
  2. 2 1
      service/ControlPlane.hpp
  3. 1 1
      service/OneService.cpp
  4. 2606 0
      ui/JSXTransformer.js
  5. 51 0
      ui/ZeroTierNode.jsx
  6. 4 0
      ui/bootstrap-theme.min.css
  7. 4 0
      ui/bootstrap.min.css
  8. 22 0
      ui/index.html
  9. 4 0
      ui/main.jsx
  10. 11 0
      ui/react.min.js
  11. 1 0
      ui/simpleajax.min.js
  12. 39 0
      ui/zerotier.css

+ 32 - 29
service/ControlPlane.cpp

@@ -37,8 +37,7 @@
 #include "../node/InetAddress.hpp"
 #include "../node/Node.hpp"
 #include "../node/Utils.hpp"
-
-#define ZT_BUILD_IN_WEB_UI
+#include "../osdep/OSUtils.hpp"
 
 namespace ZeroTier {
 
@@ -242,9 +241,10 @@ static void _jsonAppend(unsigned int depth,std::string &buf,const ZT1_Peer *peer
 	buf.append(json);
 }
 
-ControlPlane::ControlPlane(OneService *svc,Node *n) :
+ControlPlane::ControlPlane(OneService *svc,Node *n,const char *uiStaticPath) :
 	_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,
 			 * 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) {
 			/* 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
 {
 public:
-	ControlPlane(OneService *svc,Node *n);
+	ControlPlane(OneService *svc,Node *n,const char *uiStaticPath);
 	~ControlPlane();
 
 	/**
@@ -102,6 +102,7 @@ public:
 private:
 	OneService *const _svc;
 	Node *const _node;
+	std::string _uiStaticPath;
 	std::set<std::string> _authTokens;
 	std::map<std::string,ControlPlaneSubsystem *> _subsystems;
 	Mutex _lock;

+ 1 - 1
service/OneService.cpp

@@ -226,7 +226,7 @@ public:
 			if (_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());
 			if (_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