diff --git a/.eslintrc.js b/.eslintrc.js
index 14045381..ba9eaec6 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -21,7 +21,7 @@ module.exports = {
},
},
{
- "files": ["packages/master/web/**/*.jsx"],
+ "files": ["packages/web_ui/src/**/*.jsx", "plugins/*/web/**/*.jsx"],
"env": {
"browser": true,
},
diff --git a/packages/web_ui/src/bootstrap.jsx b/packages/web_ui/src/bootstrap.jsx
index f534ccac..4036075c 100644
--- a/packages/web_ui/src/bootstrap.jsx
+++ b/packages/web_ui/src/bootstrap.jsx
@@ -8,6 +8,7 @@ import libConfig from "@clusterio/lib/config";
import App from "./components/App";
import { Control, ControlConnector } from "./util/websocket";
+
async function loadScript(url) {
let script = document.createElement("script");
script.src = url;
@@ -61,17 +62,11 @@ async function load() {
let wsUrl = new URL(window.webRoot, document.location);
wsUrl.protocol = wsUrl.protocol.replace("http", "ws");
- let controlConnector = new ControlConnector(wsUrl, 10, localStorage.getItem("master_token"));
+ let controlConnector = new ControlConnector(wsUrl, 10);
// XXX come up with a better way of sharing this
window.control = new Control(controlConnector, []);
- try {
- await controlConnector.connect();
- } catch (err) {
- // XXX: What now?
- console.log(err);
- }
- ReactDOM.render(, document.getElementById("root"));
+ ReactDOM.render(, document.getElementById("root"));
}
load().catch(console.log);
diff --git a/packages/web_ui/src/components/App.jsx b/packages/web_ui/src/components/App.jsx
index 10c155b0..113cd2cf 100644
--- a/packages/web_ui/src/components/App.jsx
+++ b/packages/web_ui/src/components/App.jsx
@@ -1,13 +1,85 @@
-import React from "react";
+import events from "events";
+import React, { useEffect, useState } from "react";
import { BrowserRouter } from "react-router-dom";
import basename from "../basename";
-import Layout from "../layout";
+import SiteLayout from "../layout";
+import ControlContext from "./ControlContext";
+import LoginForm from "./LoginForm";
+
+import { Card, Spin } from "antd";
+
+
+export default function App(props) {
+ let [connected, setConnected] = useState(false);
+ let [token, setToken] = useState(localStorage.getItem("master_token") || null);
+ let connector = props.control.connector;
+
+ function clearToken() {
+ setToken(null);
+ localStorage.removeItem("master_token");
+ }
+
+ useEffect(() => {
+ console.log("Effect called");
+
+ function onConnect() {
+ localStorage.setItem("master_token", token);
+ setConnected(true);
+ }
+
+ function onClose() {
+ setConnected(false);
+ }
+
+ function onError(err) {
+ console.error("Unexpected error in connector", err);
+ clearToken();
+ setConnected(false);
+ }
+
+ connector.on("connect", onConnect);
+ connector.on("close", onClose);
+ connector.on("error", onError);
+
+ if (token && !connected) {
+ connector.token = token;
+ connector.connect();
+ }
+
+ return () => {
+ connector.off("error", onError);
+ connector.off("close", onClose);
+ connector.off("connect", onConnect);
+ };
+ });
+
+ let page;
+ if (connected) {
+ page = ;
+
+ } else if (token) {
+ page =
+
+ Connecting
+
+
+
;
+
+ } else {
+ page =
+
+ Clusterio
+
+
+
;
+ }
-export default function App() {
return (
-
-
-
+
+
+ {page}
+
+
);
}
diff --git a/packages/web_ui/src/components/ControlContext.jsx b/packages/web_ui/src/components/ControlContext.jsx
new file mode 100644
index 00000000..979faf93
--- /dev/null
+++ b/packages/web_ui/src/components/ControlContext.jsx
@@ -0,0 +1,3 @@
+import React from "react";
+
+export default React.createContext();
diff --git a/packages/web_ui/src/components/LoginForm.jsx b/packages/web_ui/src/components/LoginForm.jsx
new file mode 100644
index 00000000..6a5a13cf
--- /dev/null
+++ b/packages/web_ui/src/components/LoginForm.jsx
@@ -0,0 +1,27 @@
+import React from "react";
+import { Form, Input, Button } from "antd";
+import LockOutlined from "@ant-design/icons/LockOutlined";
+
+export default function LoginForm(props) {
+ return (
+
+ }
+ type="password"
+ placeholder="Authentication Token"
+ />
+
+
+
+ );
+}
+
diff --git a/packages/web_ui/src/index.css b/packages/web_ui/src/index.css
index fa33de59..f79dd7ad 100644
--- a/packages/web_ui/src/index.css
+++ b/packages/web_ui/src/index.css
@@ -23,3 +23,9 @@ code {
cursor: pointer;
}
+.login-container {
+ min-height: 100vh;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
diff --git a/packages/web_ui/src/layout/index.jsx b/packages/web_ui/src/layout/index.jsx
index 76f6ce24..1dd23a73 100644
--- a/packages/web_ui/src/layout/index.jsx
+++ b/packages/web_ui/src/layout/index.jsx
@@ -12,7 +12,6 @@ import { PermissionsTable } from "../pages/permissions/permissionsTable";
import { InstanceView } from "../pages/instances/instance";
import { UserView } from "../pages/users/user";
import { RoleView } from "../pages/roles/role";
-import { Settings } from "../pages/settings/settings";
const { Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;
@@ -118,10 +117,6 @@ class SiteLayout extends Component {
Permissions
-
- Settings
-
-
) : (
@@ -149,7 +144,6 @@ class SiteLayout extends Component {
-