mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-14 07:24:52 +09:00
Serve interface on all routes for the interface
Add all routes the web interface is served on to the express app and serve the index.html file on. Due to the index html not knowing which path it's hosted under, a path to the root of the web interface is replaced using string substitution from the master server.
This commit is contained in:
1 parent
392a7655c4
commit
94200433cc
9 files changed
+173
-162
No files matched your search
@@ -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);
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
];
|
||||
@@ -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;
|
||||
@@ -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 (
|
||||
<BrowserRouter basename={basename}>
|
||||
<Layout />
|
||||
</BrowserRouter>
|
||||
);
|
||||
}
|
||||
@@ -4,9 +4,13 @@
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Clusterio</title>
|
||||
<script>
|
||||
window.web_root = "__WEB_ROOT__";
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<script src="__WEB_ROOT__bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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(
|
||||
<BrowserRouter>
|
||||
<Layout />
|
||||
</BrowserRouter>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
ReactDOM.render(<App />, document.getElementById("root"));
|
||||
@@ -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 (
|
||||
<Router>
|
||||
<Layout style={{ minHeight: "100vh" }}>
|
||||
{document.location.search !== "?hideExtras" ? (
|
||||
<Sider
|
||||
collapsible
|
||||
collapsed={this.state.collapsed}
|
||||
onCollapse={this.onCollapse.bind(this)}
|
||||
width={250}
|
||||
breakpoint="lg"
|
||||
>
|
||||
<p></p>
|
||||
<div style={{ width: "100%", textAlign: "center" }}>
|
||||
{" "}
|
||||
{this.state.collapsed ? (
|
||||
<Layout style={{ minHeight: "100vh" }}>
|
||||
{document.location.search !== "?hideExtras" ? (
|
||||
<Sider
|
||||
collapsible
|
||||
collapsed={this.state.collapsed}
|
||||
onCollapse={this.onCollapse.bind(this)}
|
||||
width={250}
|
||||
breakpoint="lg"
|
||||
>
|
||||
<p></p>
|
||||
<div style={{ width: "100%", textAlign: "center" }}>
|
||||
{" "}
|
||||
{this.state.collapsed ? (
|
||||
<img
|
||||
alt=""
|
||||
src="/smal_logo.png"
|
||||
style={{ height: "48px", margin: 8 }}
|
||||
/>
|
||||
) : (
|
||||
<img
|
||||
alt=""
|
||||
src="/smal_logo.png"
|
||||
style={{ height: "48px", margin: 8 }}
|
||||
src="/logo.png"
|
||||
style={{ width: "200px", margin: 8 }}
|
||||
/>
|
||||
) : (
|
||||
<img
|
||||
alt=""
|
||||
src="/logo.png"
|
||||
style={{ width: "200px", margin: 8 }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<p></p>
|
||||
<p></p>
|
||||
)}
|
||||
</div>
|
||||
<p></p>
|
||||
<p></p>
|
||||
|
||||
<Menu
|
||||
theme="dark"
|
||||
defaultSelectedKeys={[
|
||||
this.state.location.pathname.split("/")[
|
||||
this.state.location.pathname.split("/").length - 1
|
||||
],
|
||||
]}
|
||||
defaultOpenKeys={(() => {
|
||||
let x = this.state.location.pathname.split("/");
|
||||
x.shift();
|
||||
return x;
|
||||
})()}
|
||||
mode="inline"
|
||||
>
|
||||
<Menu.Item key="slaves">
|
||||
<span>Slaves</span>
|
||||
<Link to="/slaves" />
|
||||
</Menu.Item>
|
||||
<Menu.Item key="instances">
|
||||
<span>Instances</span>
|
||||
<Link to="/instances" />
|
||||
</Menu.Item>
|
||||
<Menu.Item key="users">
|
||||
<span>Users</span>
|
||||
<Link to="/users" />
|
||||
</Menu.Item>
|
||||
<Menu.Item key="roles">
|
||||
<span>Roles</span>
|
||||
<Link to="/roles" />
|
||||
</Menu.Item>
|
||||
<Menu.Item key="permissions">
|
||||
<span>Permissions</span>
|
||||
<Link to="/permissions" />
|
||||
</Menu.Item>
|
||||
<Menu.Item key="settings">
|
||||
<span>Settings</span>
|
||||
<Link to="/settings" />
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
</Sider>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<Layout style={{
|
||||
// background: "#F4F4F4"
|
||||
}}>
|
||||
<Content
|
||||
style={{
|
||||
margin: "24px 16px",
|
||||
padding: 24,
|
||||
// background: "#fff",
|
||||
minHeight: 280,
|
||||
}}
|
||||
<Menu
|
||||
theme="dark"
|
||||
defaultSelectedKeys={[
|
||||
this.state.location.pathname.split("/")[
|
||||
this.state.location.pathname.split("/").length - 1
|
||||
],
|
||||
]}
|
||||
defaultOpenKeys={(() => {
|
||||
let x = this.state.location.pathname.split("/");
|
||||
x.shift();
|
||||
return x;
|
||||
})()}
|
||||
mode="inline"
|
||||
>
|
||||
<Route exact path="/" component={Dashboard} />
|
||||
<Route
|
||||
exact
|
||||
path="/instances"
|
||||
component={InstancesTable}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/instances/:id/view"
|
||||
component={InstanceView}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/slaves"
|
||||
component={SlavesTable}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/slaves/:id/view"
|
||||
component={SlavesTable}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/users"
|
||||
component={UsersTable}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/users/:id/view"
|
||||
component={UserView}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/roles"
|
||||
component={RolesTable}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/roles/:id/view"
|
||||
component={RoleView}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/permissions"
|
||||
component={PermissionsTable}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/permissions/:id/view"
|
||||
component={PermissionsTable}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/settings"
|
||||
component={Settings}
|
||||
/>
|
||||
</Content>
|
||||
<Footer style={{
|
||||
// background: "#F4F4F4",
|
||||
textAlign: "center"
|
||||
}}>
|
||||
Clusterio 2.0 web interface https://github.com/clusterio
|
||||
</Footer>
|
||||
</Layout>
|
||||
<Menu.Item key="slaves">
|
||||
<span>Slaves</span>
|
||||
<Link to="/slaves" />
|
||||
</Menu.Item>
|
||||
<Menu.Item key="instances">
|
||||
<span>Instances</span>
|
||||
<Link to="/instances" />
|
||||
</Menu.Item>
|
||||
<Menu.Item key="users">
|
||||
<span>Users</span>
|
||||
<Link to="/users" />
|
||||
</Menu.Item>
|
||||
<Menu.Item key="roles">
|
||||
<span>Roles</span>
|
||||
<Link to="/roles" />
|
||||
</Menu.Item>
|
||||
<Menu.Item key="permissions">
|
||||
<span>Permissions</span>
|
||||
<Link to="/permissions" />
|
||||
</Menu.Item>
|
||||
<Menu.Item key="settings">
|
||||
<span>Settings</span>
|
||||
<Link to="/settings" />
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
</Sider>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<Layout style={{
|
||||
// background: "#F4F4F4"
|
||||
}}>
|
||||
<Content
|
||||
style={{
|
||||
margin: "24px 16px",
|
||||
padding: 24,
|
||||
// background: "#fff",
|
||||
minHeight: 280,
|
||||
}}
|
||||
>
|
||||
<Route exact path="/" component={Dashboard} />
|
||||
<Route exact path="/instances" component={InstancesTable} />
|
||||
<Route exact path="/instances/:id/view" component={InstanceView} />
|
||||
<Route exact path="/slaves" component={SlavesTable} />
|
||||
<Route exact path="/slaves/:id/view" component={SlavesTable} />
|
||||
<Route exact path="/users" component={UsersTable} />
|
||||
<Route exact path="/users/:id/view" component={UserView} />
|
||||
<Route exact path="/roles" component={RolesTable} />
|
||||
<Route exact path="/roles/:id/view" component={RoleView} />
|
||||
<Route exact path="/permissions" component={PermissionsTable} />
|
||||
<Route exact path="/permissions/:id/view" component={PermissionsTable} />
|
||||
<Route exact path="/settings" component={Settings} />
|
||||
</Content>
|
||||
<Footer style={{
|
||||
// background: "#F4F4F4",
|
||||
textAlign: "center"
|
||||
}}>
|
||||
Clusterio 2.0 web interface https://github.com/clusterio
|
||||
</Footer>
|
||||
</Layout>
|
||||
</Router>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in new issue
Block a user