diff --git a/packages/master/master.js b/packages/master/master.js index 53ac5d90..c8efaa2b 100755 --- a/packages/master/master.js +++ b/packages/master/master.js @@ -40,6 +40,7 @@ let devMiddleware; // homebrew modules const generateSSLcert = require("./src/generate_ssl_cert"); +const routes = require("./src/routes"); const database = require("@clusterio/lib/database"); const schema = require("@clusterio/lib/schema"); const link = require("@clusterio/lib/link"); @@ -71,6 +72,26 @@ app.use(bodyParser.urlencoded({ app.use(fileUpload()); app.use(compression()); + +// Servers the web interface with the root path set apropriately. +function serveWeb(route) { + // The depth is is the number of slashes in the route minus one, but due + // to lenient matching on trailing slashes in the route we need to + // compensate if the request path contains a slash but not the route, + // and vice versa. + let routeDepth = (route.match(/\//g) || []).length - 1 - (route.slice(-1) === "/"); + return function(req, res, next) { + let depth = routeDepth + (req.path.slice(-1) === "/"); + let webRoot = "../".repeat(depth) || "./"; + fs.readFile(path.join(__dirname, "web", "index.html"), "utf8").then((content) => { + res.type("text/html"); + res.send(content.replace(/__WEB_ROOT__/g, webRoot)); + }).catch(err => { + next(err); + }); + }; +} + // Set folder to serve static content from (the website) app.use(express.static(path.join(__dirname, "static"))); app.use(express.static("static")); // Used for data export files @@ -1698,6 +1719,16 @@ async function startServer() { }); } + // Add routes for the web interface + for (let route of routes) { + app.get(route, serveWeb(route)); + } + for (let pluginInfo of pluginInfos) { + for (let route of pluginInfo.routes || []) { + app.get(route, serveWeb(route)); + } + } + // Load plugins await pluginManagement(pluginInfos); diff --git a/packages/master/package.json b/packages/master/package.json index a18ea824..2827404d 100644 --- a/packages/master/package.json +++ b/packages/master/package.json @@ -43,7 +43,6 @@ "clean-webpack-plugin": "^3.0.0", "css-loader": "^4.3.0", "fast-deep-equal": "^3.1.3", - "html-webpack-plugin": "^4.5.0", "null-loader": "^4.0.0", "react": "^16.13.1", "react-dom": "^16.13.1", diff --git a/packages/master/src/routes.js b/packages/master/src/routes.js new file mode 100644 index 00000000..7e0ca52a --- /dev/null +++ b/packages/master/src/routes.js @@ -0,0 +1,16 @@ +"use strict"; +// Routes used in the web interface and served by the master server +module.exports = [ + "/", + "/instances", + "/instances/:id/view", + "/slaves", + "/slaves/:id/view", + "/users", + "/users/:id/view", + "/roles", + "/roles/:id/view", + "/permissions", + "/permissions/:id/view", + "/settings", +]; diff --git a/packages/master/web/basename.jsx b/packages/master/web/basename.jsx new file mode 100644 index 00000000..99b8468a --- /dev/null +++ b/packages/master/web/basename.jsx @@ -0,0 +1,6 @@ +// Calculate basedir of application based on current location and +// the provided web_root from master server. +const location = new URL(window.web_root, document.location) +const basename = location.pathname !== "/" ? location.pathname : ""; + +export default basename; diff --git a/packages/master/web/components/App.jsx b/packages/master/web/components/App.jsx new file mode 100644 index 00000000..b1db4c6e --- /dev/null +++ b/packages/master/web/components/App.jsx @@ -0,0 +1,13 @@ +import React from "react"; +import { BrowserRouter } from "react-router-dom"; + +import basename from "../basename"; +import Layout from "../layout"; + +export default function App() { + return ( + + + + ); +} diff --git a/packages/master/web/index.html b/packages/master/web/index.html index 7f77d875..b7a280f7 100644 --- a/packages/master/web/index.html +++ b/packages/master/web/index.html @@ -4,9 +4,13 @@ Clusterio +
+ diff --git a/packages/master/web/index.jsx b/packages/master/web/index.jsx index 5c2828e2..0cb7c8c5 100644 --- a/packages/master/web/index.jsx +++ b/packages/master/web/index.jsx @@ -1,13 +1,8 @@ +import "./index.css" + import React from "react" import ReactDOM from "react-dom" -import { BrowserRouter } from "react-router-dom" -import "./index.css" -import Layout from "./layout" +import App from "./components/App"; -ReactDOM.render( - - - , - document.getElementById('root') -); +ReactDOM.render(, document.getElementById("root")); diff --git a/packages/master/web/layout/index.jsx b/packages/master/web/layout/index.jsx index 58e8b1be..4893ccd9 100644 --- a/packages/master/web/layout/index.jsx +++ b/packages/master/web/layout/index.jsx @@ -1,7 +1,6 @@ import { Layout, Menu } from "antd"; -import { withRouter } from "react-router-dom"; -import { BrowserRouter as Router, Route, Link } from "react-router-dom"; +import { Route, Link, withRouter } from "react-router-dom"; import React, { Component } from "react"; import { Dashboard } from "../pages/dashboard"; @@ -24,8 +23,6 @@ class SiteLayout extends Component { super(props); const { location } = props; - // this.history = useHistory(); - this.state = { collapsed: false, setcollapsed: false, @@ -58,156 +55,110 @@ class SiteLayout extends Component { render() { return ( - - - {document.location.search !== "?hideExtras" ? ( - -

-
- {" "} - {this.state.collapsed ? ( + + {document.location.search !== "?hideExtras" ? ( + +

+
+ {" "} + {this.state.collapsed ? ( + + ) : ( - ) : ( - - )} -
-

-

+ )} +
+

+

- { - let x = this.state.location.pathname.split("/"); - x.shift(); - return x; - })()} - mode="inline" - > - - Slaves - - - - Instances - - - - Users - - - - Roles - - - - Permissions - - - - Settings - - - -
- ) : ( - "" - )} - - { + let x = this.state.location.pathname.split("/"); + x.shift(); + return x; + })()} + mode="inline" > - - - - - - - - - - - - - -
- Clusterio 2.0 web interface https://github.com/clusterio -
-
+ + Slaves + + + + Instances + + + + Users + + + + Roles + + + + Permissions + + + + Settings + + + + + ) : ( + "" + )} + + + + + + + + + + + + + + + + -
+ ); } } diff --git a/packages/master/webpack.config.js b/packages/master/webpack.config.js index ebd45171..4e2dc702 100644 --- a/packages/master/webpack.config.js +++ b/packages/master/webpack.config.js @@ -1,7 +1,6 @@ "use strict"; const path = require("path"); const webpack = require("webpack"); -const HtmlWebpackPlugin = require("html-webpack-plugin"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); module.exports = (env = {}) => ({ @@ -20,9 +19,6 @@ module.exports = (env = {}) => ({ new webpack.DefinePlugin({ "process.env.APP_ENV": JSON.stringify("browser"), }), - new HtmlWebpackPlugin({ - template: "web/index.html", - }), // Make sure ant-design icons use the ES variant new webpack.NormalModuleReplacementPlugin(