import React, { Component } from "react" import { Card, Button, Popover, Select, Divider, Input, Form, Col, Row, Checkbox, Space } from "antd" import { listSlaves, listInstances, startInstance, stopInstance, setInstanceOutputSubscriptions, deleteInstance, assignInstance, createSave, getInstanceConfig, setInstanceConfigField, sendRcon, } from "../../util/wslink" import DataTable from "../../components/data-table" import notify from "../../util/notify" import DeleteOutlined from "@ant-design/icons/DeleteOutlined" import EditOutlined from "@ant-design/icons/EditOutlined" import PlusOutlined from "@ant-design/icons/PlusOutlined" const { Option } = Select export class InstanceView extends Component { constructor(props) { super(props) this.state = { instance: {}, slaves: [], logLines: [{ message: "Logviewer. Follows the latest logs if you scroll to the bottom. Does not store logs past the lifetime of this tab" }], } this.messagesEndRef = React.createRef() } navigate(url) { this.props.history.push(url); } async componentDidMount() { let id = this.props.match.params.id await this.getData() await setInstanceOutputSubscriptions({ instance_id: Number(id), }) window.instanceOutputEventHandler = ({ instance_id, output }) => { if (instance_id === Number(id)) { this.setState({ logLines: [...this.state.logLines, output], }) } // Automatically scroll to bottom on new line. // this.messagesEndRef.current.scrollIntoView({ behavior: 'smooth' }) } } async getData() { let id = this.props.match.params.id let instances = await listInstances() let slaves = await listSlaves() this.setState({ instance: instances.find(x => x.id === Number(id)), slaves, }) let config = await getInstanceConfig({ instance_id: Number(id) }) console.log(config) this.setState({ config }) } async start() { this.setState({ starting: true, }) try { await startInstance({ instance_id: this.state.instance.id, save: null, }) } catch (e) { notify("Error starting instance", "error", e.message) return this.setState({ starting: false, }) } notify("Instance started") this.setState({ starting: false, }) this.getData() } async stop() { this.setState({ stopping: true, }) try { await stopInstance({ instance_id: this.state.instance.id, }) } catch (e) { notify("Error stopping instance", "error", e.message) return this.setState({ stopping: false, }) } notify("Instance stopped") this.setState({ stopping: false, }) this.getData() } async createSave() { this.setState({ creatingSave: true, }) try { await createSave({ instance_id: this.state.instance.id, }) } catch (e) { notify("Error creating save", "error", e.message) return this.setState({ creatingSave: false, }) } notify("Save created", "success") this.setState({ creatingSave: false, }) } async onConfigEditFinish(values) { console.log("Completed config edit with", values) for (let k in values) { if (values[k] !== this.getInstanceConfigAsKvObject(this.state.config)[k]) { let value = values[k] if (typeof value === "boolean") value = value.toString() console.log("Setting", k, value) await setInstanceConfigField({ instance_id: this.state.instance.id, field: k, value: value, }) } } notify("Set configuration fields", "success") this.setState({ editingConfig: false }) this.getData() } render() { console.log(this.state) let { instance, slaves } = this.state let slave = slaves && slaves.find(x => x.id === instance.assigned_slave); return

{instance.name}

ID: {instance.id}

Slave: {slave && slave.name}

{instance.status !== "running" && } {instance.status !== "stopped" && } {instance.status !== "running" && } { let result = await assignInstance({ instance_id: instance.id, slave_id: newSlaveId }) notify("Assigned to slave", "success") this.getData() }} > {this.state.slaves.map(slave => )} } trigger="click" type={instance.status === "unassigned" ? "primary" : "default"} > { await deleteInstance({ instance_id: instance.id }); notify("Deleted instance " + instance.id, "success") this.navigate("/instances") }} > Delete this instance permanently } trigger="click" >
{this.state.logLines.map(item =>

{item.time} {item.level} {item.file}: {item.message}

)}
{/* rcon input field */}
{ await sendRcon({ instance_id: instance.id, command: values.command }) }} >
{this.state.config && this.renderConfig(this.state.config)}
} getInstanceConfigAsKvObject(config) { let object = {} for (let group of config.serialized_config.groups) { for (let fieldName in group.fields) { object[group.name + "." + fieldName] = group.fields[fieldName] } } return object } renderConfig(config) { const layout = { labelCol: { span: 6, }, wrapperCol: { span: 14, }, }; const tailLayout = { wrapperCol: { offset: 6, span: 14, }, }; return
{this.state.editingConfig ? : } {config && config.serialized_config.groups.map(group => <> {group.name} {/* {Object.keys(group.fields).map(field => <> {field}: {JSON.stringify(group.fields[field])}
)} */} {console.log(group)} {Object.keys(group.fields).map(field => )} )}
} } function renderDisplayField(value) { if (typeof value === "object") { return JSON.stringify(value) } if (typeof value === "boolean") { return } return value.toString() } function renderFormField(value) { if (typeof value === "object") { return } if (typeof value === "boolean") { return } return } class ObjectInput extends Component { constructor(props) { super(props) console.log(this.props) /* value: { auto_pause: false, tags: ["clusterio"] }, id: "factorio.settings", onChange: f() */ this.state = {} } onChange(e, key) { if (e.target.type === "checkbox") { // if (e.target.checked !== undefined) { // Its a checkbox, set value to true/false let value = { ...this.props.value } value[key] = e.target.checked || false this.props.onChange(value) } else if (e.target.type === "text") { // } else if (e.target.value !== undefined) { // its probably a text input let value = { ...this.props.value } value[key] = e.target.value || "" this.props.onChange(value) } } render() { let { value } = this.props let ret = [] for (let key in value) { if (typeof value[key] === "boolean") { ret.push( this.onChange(e, key)} > {key} ) } else if (typeof value[key] === "string") { ret.push(
{key} this.onChange(e, key)} />
) } } ret.push( this.setState({ newInput: e.target.value })} /> } trigger="click" visible={this.state.addPopoverVisible} handleVisibleChange={visible => this.setState({ addPopoverVisible: visible })} > ) return {ret} } } class ConfigFormItem extends Component { constructor(props) { super(props) } render() { let { field, group, editingConfig } = this.props return {editingConfig ? renderFormField(group.fields[field]) : renderDisplayField(group.fields[field]) } } }