mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 15:14:52 +09:00
Hide or disable controls in the web interface that the user for the control connection it's connected as don't have the requisite permissions to use.
190 lines
4.3 KiB
React
190 lines
4.3 KiB
React
import React, { useContext, useEffect, useState } from "react";
|
|
import { Input, Table, Typography } from "antd";
|
|
|
|
import { libPlugin } from "@clusterio/lib";
|
|
import { notifyErrorHandler, useItemMetadata, useLocale, PageLayout, ControlContext } from "@clusterio/web_ui";
|
|
import info from "../info";
|
|
|
|
import "./index.css";
|
|
|
|
const { Paragraph } = Typography;
|
|
|
|
|
|
function useStorage(control) {
|
|
let plugin = control.plugins.get("subspace_storage");
|
|
let [storage, setStorage] = useState([...plugin.storage]);
|
|
|
|
useEffect(() => {
|
|
function update() {
|
|
setStorage([...plugin.storage]);
|
|
}
|
|
|
|
plugin.onUpdate(update);
|
|
return () => {
|
|
plugin.offUpdate(update);
|
|
};
|
|
}, []);
|
|
return storage;
|
|
}
|
|
|
|
function StoragePage() {
|
|
let control = useContext(ControlContext);
|
|
let locale = useLocale();
|
|
let itemMetadata = useItemMetadata();
|
|
let storage = useStorage(control);
|
|
let [filter, setFilter] = useState(null);
|
|
|
|
function getLocaleName(itemName) {
|
|
let localeName = itemName;
|
|
let meta = itemMetadata.get(itemName);
|
|
if (meta && meta.localized_name) {
|
|
// TODO: implement the locale to name conversion.
|
|
localeName = locale.get(meta.localized_name[0]);
|
|
} else {
|
|
for (let section of ["item-name", "entity-name", "fluid-name", "equipment-name"]) {
|
|
let name = locale.get(`${section}.${itemName}`);
|
|
if (name) {
|
|
localeName = name;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return localeName;
|
|
}
|
|
|
|
let numberFormat = new Intl.NumberFormat("en-US");
|
|
|
|
return <PageLayout nav={[{ name: "Storage" }]}>
|
|
<h2>Storage</h2>
|
|
<Paragraph>
|
|
<Input
|
|
placeholder="Search"
|
|
onChange={(event) => {
|
|
let search = event.target.value.trim();
|
|
if (!search) {
|
|
setFilter(null);
|
|
return;
|
|
}
|
|
search = search.replace(/(^| )(\w)/g, "$1\\b$2");
|
|
search = search.replace(/ +/g, ".*");
|
|
let filterExpr = new RegExp(search, "i");
|
|
setFilter(() => (item => {
|
|
let name = getLocaleName(item[0]);
|
|
return filterExpr.test(name) || filterExpr.test(item[0]);
|
|
}));
|
|
}}
|
|
/>
|
|
</Paragraph>
|
|
<Table
|
|
columns={[
|
|
{
|
|
title: "Resource",
|
|
key: "resource",
|
|
sorter: (a, b) => {
|
|
let aName = getLocaleName(a[0]);
|
|
let bName = getLocaleName(b[0]);
|
|
if (aName < bName) { return -1; }
|
|
if (aName > bName) { return 1; }
|
|
return 0;
|
|
},
|
|
render: item => {
|
|
let localeName = getLocaleName(item[0]);
|
|
let hasMeta = itemMetadata.get(item[0]);
|
|
|
|
return <>
|
|
<span className={`factorio-icon item-${hasMeta ? item[0] : "unknown-item"}`}/>
|
|
{localeName}
|
|
</>;
|
|
},
|
|
},
|
|
{
|
|
title: "Quantity",
|
|
key: "quantity",
|
|
align: "right",
|
|
defaultSortOrder: "descend",
|
|
sorter: (a, b) => a[1] - b[1],
|
|
render: item => numberFormat.format(item[1]),
|
|
},
|
|
]}
|
|
dataSource={filter ? storage.filter(filter) : storage}
|
|
rowKey={item => item[0]}
|
|
pagination={false}
|
|
/>
|
|
</PageLayout>;
|
|
}
|
|
|
|
export class WebPlugin extends libPlugin.BaseWebPlugin {
|
|
async init() {
|
|
this.pages = [
|
|
{
|
|
path: "/storage",
|
|
sidebarName: "Storage",
|
|
permission: "subspace_storage.storage.view",
|
|
content: <StoragePage/>,
|
|
},
|
|
];
|
|
|
|
this.storage = new Map();
|
|
this.callbacks = [];
|
|
}
|
|
|
|
onMasterConnectionEvent(event) {
|
|
if (event === "connect") {
|
|
this.updateSubscription();
|
|
}
|
|
}
|
|
|
|
async updateStorageEventHandler(message) {
|
|
this.updateStorage(message.data.items);
|
|
}
|
|
|
|
onUpdate(callback) {
|
|
this.callbacks.push(callback);
|
|
if (this.callbacks.length) {
|
|
this.updateSubscription();
|
|
}
|
|
}
|
|
|
|
offUpdate(callback) {
|
|
let index = this.callbacks.lastIndexOf(callback);
|
|
if (index === -1) {
|
|
throw new Error("callback is not registered");
|
|
}
|
|
|
|
this.callbacks.splice(index, 1);
|
|
if (!this.callbacks.length) {
|
|
this.updateSubscription();
|
|
}
|
|
}
|
|
|
|
updateStorage(items) {
|
|
for (let [name, amount] of items) {
|
|
this.storage.set(name, amount);
|
|
}
|
|
for (let callback of this.callbacks) {
|
|
callback();
|
|
}
|
|
}
|
|
|
|
updateSubscription() {
|
|
if (!this.control.connector.connected) {
|
|
return;
|
|
}
|
|
|
|
info.messages.setStorageSubscription.send(
|
|
this.control, { storage: Boolean(this.callbacks.length) }
|
|
).catch(notifyErrorHandler("Error subscribing to storage"));
|
|
|
|
if (this.callbacks.length) {
|
|
info.messages.getStorage.send(this.control).then(
|
|
result => {
|
|
this.updateStorage(result.items);
|
|
}
|
|
).catch(notifyErrorHandler("Error updating storage"));
|
|
} else {
|
|
this.storage.clear();
|
|
}
|
|
}
|
|
}
|