diff --git a/CHANGELOG.md b/CHANGELOG.md index eba715c2..2991fa6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Packaged and uploaded to npm again, greatly simplifying distribution and installation of both Clusterio and plugins. - Added centralized logging for the cluster. All logs from both Clusterio and Factorio is stored in a shared log which can be inspected and queried. +- Added remote save management with the ability to list, create, upload, download, delete and load saves for instances. ### Features diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 6ddc1d09..7d15d6e5 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -137,10 +137,11 @@ slaveCommands.add(new libCommand.Command({ slaveCommands.add(new libCommand.Command({ definition: ["generate-token", "Generate token for a slave", (yargs) => { - yargs.option("id", { type: "number", nargs: 1, describe: "Slave id", demandOption: true }); + yargs.option("id", { type: "number", nargs: 1, describe: "Slave id" }); }], handler: async function(args, control) { - let response = await libLink.messages.generateSlaveToken.send(control, { slave_id: args.id }); + let slaveId = typeof args.id === "number" ? args.id : null; + let response = await libLink.messages.generateSlaveToken.send(control, { slave_id: slaveId }); print(response.token); }, })); diff --git a/packages/lib/link/messages.js b/packages/lib/link/messages.js index 6ba0a8a4..dbb84455 100644 --- a/packages/lib/link/messages.js +++ b/packages/lib/link/messages.js @@ -422,7 +422,7 @@ messages.generateSlaveToken = new Request({ links: ["control-master"], permission: "core.slave.generate_token", requestProperties: { - "slave_id": { type: "integer" }, + "slave_id": { type: ["integer", "null"] }, }, responseProperties: { "token": { type: "string" }, diff --git a/packages/master/src/ControlConnection.js b/packages/master/src/ControlConnection.js index ddf42e83..2792774b 100644 --- a/packages/master/src/ControlConnection.js +++ b/packages/master/src/ControlConnection.js @@ -130,7 +130,11 @@ class ControlConnection extends BaseConnection { } async generateSlaveTokenRequestHandler(message) { - return { token: this.generateSlaveToken(message.data.slave_id) }; + let slaveId = message.data.slave_id; + if (slaveId === null) { + slaveId = Math.random() * 2**31 | 0; + } + return { token: this.generateSlaveToken(slaveId) }; } async createSlaveConfigRequestHandler(message) { diff --git a/packages/web_ui/src/components/InstancesPage.jsx b/packages/web_ui/src/components/InstancesPage.jsx index bab926ba..71fb90a4 100644 --- a/packages/web_ui/src/components/InstancesPage.jsx +++ b/packages/web_ui/src/components/InstancesPage.jsx @@ -21,7 +21,8 @@ function CreateInstanceButton(props) { async function createInstance() { let values = form.getFieldsValue(); if (!values.instanceName) { - form.setFields([{ name: "mapGenSettings", errors: ["Name is required"] }]); + form.setFields([{ name: "instanceName", errors: ["Name is required"] }]); + return; } let instanceConfig = new libConfig.InstanceConfig("control"); diff --git a/packages/web_ui/src/components/SlavesPage.jsx b/packages/web_ui/src/components/SlavesPage.jsx index 0283c8bb..74af789a 100644 --- a/packages/web_ui/src/components/SlavesPage.jsx +++ b/packages/web_ui/src/components/SlavesPage.jsx @@ -1,11 +1,73 @@ -import React, { useContext } from "react"; -import { Table } from "antd"; +import React, { useContext, useRef, useState } from "react"; +import { Button, Form, Input, Modal, PageHeader, Table } from "antd"; import libLink from "@clusterio/lib/link"; import ControlContext from "./ControlContext"; import PageLayout from "./PageLayout"; import { useSlaveList } from "../model/slave"; +import { notifyErrorHandler } from "../util/notify"; + + +function GenerateSlaveTokenButton(props) { + let control = useContext(ControlContext); + let [visible, setVisible] = useState(false); + let [token, setToken] = useState(null); + let [form] = Form.useForm(); + let tokenTextAreaRef = useRef(null); + + async function generateToken() { + let values = form.getFieldsValue(); + let slaveId = null; + if (values.slaveId) { + slaveId = Number.parseInt(values.slaveId, 10); + if (Number.isNaN(slaveId)) { + form.setFields([{ name: "slaveId", errors: ["Must be an integer"] }]); + return; + } + form.setFields([{ name: "slaveId", errors: [] }]); + } + + let result = await libLink.messages.generateSlaveToken.send(control, { slave_id: slaveId }); + setToken(result.token); + } + + return <> + + { + setVisible(false); + setToken(null); + form.resetFields(); + }} + > +
+ + + + + + + + + + +
+
+ ; +} export default function SlavesPage() { @@ -13,7 +75,11 @@ export default function SlavesPage() { let [slaveList] = useSlaveList(); return -

Slaves

+ + />