mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 07:04:53 +09:00
Merge pull request #532 from Hornwitser/small-things-12
Small things 12
This commit is contained in:
42 files changed
+104
-85
No files matched your search
+2
-2
@@ -8,8 +8,8 @@
|
||||
"cover": "nyc pnpm test",
|
||||
"fast-cover": "FAST_TEST=y nyc pnpm test",
|
||||
"ci-cover": "nyc --reporter=lcovonly pnpm run-script test",
|
||||
"lint": "eslint \"*.js\" packages plugins test",
|
||||
"lint-fix": "eslint --fix \"*.js\" packages plugins test",
|
||||
"lint": "eslint packages plugins test",
|
||||
"lint-fix": "eslint --fix packages plugins test",
|
||||
"docs": "typedoc",
|
||||
"bundle-dependencies": "bundle-dependencies"
|
||||
},
|
||||
|
||||
@@ -230,10 +230,10 @@ export default class ControlConnection extends BaseConnection {
|
||||
await hostConfig.init();
|
||||
|
||||
hostConfig.set("host.controller_url", this._controller.getControllerUrl());
|
||||
if (request.id !== null) {
|
||||
if (request.id !== undefined) {
|
||||
hostConfig.set("host.id", request.id);
|
||||
}
|
||||
if (request.name !== null) {
|
||||
if (request.name !== undefined) {
|
||||
hostConfig.set("host.name", request.name);
|
||||
}
|
||||
if (request.generateToken) {
|
||||
|
||||
@@ -113,7 +113,7 @@ export default class Controller {
|
||||
|
||||
constructor(
|
||||
clusterLogger: winston.Logger,
|
||||
pluginInfos: any[],
|
||||
pluginInfos: lib.PluginNodeEnvInfo[],
|
||||
configPath: string,
|
||||
config: lib.ControllerConfig,
|
||||
|
||||
@@ -656,7 +656,7 @@ export default class Controller {
|
||||
host.name,
|
||||
host.id,
|
||||
this.wsServer.hostConnections.has(host.id),
|
||||
host.public_address === null ? undefined : host.public_address,
|
||||
host.public_address,
|
||||
host.token_valid_after,
|
||||
);
|
||||
|
||||
@@ -778,7 +778,7 @@ export default class Controller {
|
||||
// Assign to target
|
||||
instance.config.set("instance.assigned_host", hostId);
|
||||
this.instancesDirty = true;
|
||||
if (hostId !== null && newHostConnection) {
|
||||
if (hostId !== undefined && newHostConnection) {
|
||||
await newHostConnection.send(
|
||||
new lib.InstanceAssignInternalRequest(instanceId, instance.config.serialize("host"))
|
||||
);
|
||||
|
||||
@@ -284,9 +284,7 @@ export default class HostConnection extends BaseConnection {
|
||||
this._controller.userManager.notifyLeave(user, instanceId);
|
||||
}
|
||||
|
||||
if (event.stats) {
|
||||
user.instanceStats.set(instanceId, event.stats);
|
||||
}
|
||||
user.instanceStats.set(instanceId, event.stats);
|
||||
|
||||
user.recalculatePlayerStats();
|
||||
this._controller.userUpdated(user);
|
||||
|
||||
@@ -95,7 +95,7 @@ async function getMetrics(req: Request, res: Response, next: any) {
|
||||
|
||||
function getPlugins(req: Request, res: Response) {
|
||||
let plugins: lib.PluginWebApi[] = [];
|
||||
for (let pluginInfo of req.app.locals.controller.pluginInfos) {
|
||||
for (let pluginInfo of (req.app.locals.controller as Controller).pluginInfos) {
|
||||
let name = pluginInfo.name;
|
||||
let loaded = req.app.locals.controller.plugins.has(name);
|
||||
let enabled = loaded && req.app.locals.controller.config.group(pluginInfo.name).get("load_plugin");
|
||||
@@ -115,7 +115,7 @@ function getPlugins(req: Request, res: Response) {
|
||||
if (web.main === "remoteEntry.js") {
|
||||
web.error = "Incompatible old remoteEntry.js entrypoint.";
|
||||
}
|
||||
plugins.push({ name, version: pluginInfo.version, enabled, loaded, web, requirePath: pluginInfo.requirePath });
|
||||
plugins.push({ name, version: pluginInfo.version, enabled, loaded, web, npmPackage: pluginInfo.npmPackage });
|
||||
}
|
||||
res.send(plugins);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"entryPoints": ["controller.ts"],
|
||||
"entryPoints": ["index.ts"],
|
||||
"includeVersion": true
|
||||
}
|
||||
@@ -109,7 +109,7 @@ controllerConfigCommands.add(new lib.Command({
|
||||
"stdin": { describe: "read value from stdin", nargs: 0, type: "boolean" },
|
||||
});
|
||||
}],
|
||||
handler: async function(args: { field: string, value: string, stdin?: boolean }, control: Control) {
|
||||
handler: async function(args: { field: string, value?: string, stdin?: boolean }, control: Control) {
|
||||
if (args.stdin) {
|
||||
args.value = (await lib.readStream(process.stdin)).toString().replace(/\r?\n$/, "");
|
||||
} else if (args.value === undefined) {
|
||||
@@ -128,7 +128,7 @@ controllerConfigCommands.add(new lib.Command({
|
||||
"stdin": { describe: "read value from stdin", nargs: 0, type: "boolean" },
|
||||
});
|
||||
}],
|
||||
handler: async function(args: { field: string, prop: string, value: string, stdin?: boolean }, control: Control) {
|
||||
handler: async function(args: { field: string, prop: string, value?: string, stdin?: boolean }, control: Control) {
|
||||
if (args.stdin) {
|
||||
args.value = (await lib.readStream(process.stdin)).toString().replace(/\r?\n$/, "");
|
||||
}
|
||||
@@ -139,7 +139,7 @@ controllerConfigCommands.add(new lib.Command({
|
||||
}
|
||||
} catch (err: any) {
|
||||
// See note for the instance version of set-prop
|
||||
if (args.stdin || /^(\[.*]|{.*}|".*")$/.test(args.value)) {
|
||||
if (args.stdin || /^(\[.*]|{.*}|".*")$/.test(args.value!)) {
|
||||
throw new lib.CommandError(`In parsing value '${args.value}': ${err.message}`);
|
||||
}
|
||||
value = args.value;
|
||||
@@ -354,7 +354,7 @@ instanceConfigCommands.add(new lib.Command({
|
||||
});
|
||||
}],
|
||||
handler: async function(
|
||||
args: { instance: string, field: string, value: string, stdin?: boolean },
|
||||
args: { instance: string, field: string, value?: string, stdin?: boolean },
|
||||
control: Control,
|
||||
) {
|
||||
let instanceId = await lib.resolveInstance(control, args.instance);
|
||||
@@ -378,7 +378,7 @@ instanceConfigCommands.add(new lib.Command({
|
||||
});
|
||||
}],
|
||||
handler: async function(
|
||||
args: { instance: string, field: string, prop: string, value: string, stdin?: boolean },
|
||||
args: { instance: string, field: string, prop: string, value?: string, stdin?: boolean },
|
||||
control: Control
|
||||
) {
|
||||
let instanceId = await lib.resolveInstance(control, args.instance);
|
||||
@@ -407,7 +407,7 @@ instanceConfigCommands.add(new lib.Command({
|
||||
// bash : '""That'\''s a \" quote""'
|
||||
// bash + npx : '""That'\''s a \" quote""'
|
||||
// bash + npx -s sh : "'\"\"That'\\''s a \\\" quote\"\"'"
|
||||
if (args.stdin || /^(\[.*]|{.*}|".*")$/.test(args.value)) {
|
||||
if (args.stdin || /^(\[.*]|{.*}|".*")$/.test(args.value!)) {
|
||||
throw new lib.CommandError(`In parsing value '${args.value}': ${err.message}`);
|
||||
}
|
||||
value = args.value;
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"entryPoints": ["index.ts"],
|
||||
"includeVersion": true
|
||||
}
|
||||
@@ -446,7 +446,7 @@ rcon.print(game.table_to_json(players))`.replace(/\r?\n/g, " ");
|
||||
new lib.InstanceStatusChangedEvent(
|
||||
this.id,
|
||||
status,
|
||||
this.server && this.server.gamePort || this.config.get("factorio.game_port") || undefined,
|
||||
this.server.gamePort || this.config.get("factorio.game_port") || undefined,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -713,7 +713,7 @@ export class FactorioServer extends events.EventEmitter {
|
||||
async init() {
|
||||
this._check(["new"]);
|
||||
[this._dataDir, this._version] = await findVersion(this._factorioDir, this._targetVersion);
|
||||
this.rconPassword = this.rconPassword ?? await generatePassword(10);
|
||||
this.rconPassword = this.rconPassword as string | undefined ?? await generatePassword(10);
|
||||
this._state = "init";
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"entryPoints": ["index.ts"],
|
||||
"includeVersion": true
|
||||
}
|
||||
@@ -7,5 +7,10 @@ export type PluginWebApi = {
|
||||
main: string;
|
||||
error?: string;
|
||||
};
|
||||
requirePath: string;
|
||||
/**
|
||||
* NPM package this plugin is published as. Not present if the package
|
||||
* is private or the path used to load it does not match the name of the
|
||||
* package.
|
||||
*/
|
||||
npmPackage?: string;
|
||||
}
|
||||
@@ -19,9 +19,7 @@ export default class ExportManifest {
|
||||
* - locale: JSON of flattened Map entries of en locale strings from the game.
|
||||
*/
|
||||
public assets: Record<string, string>
|
||||
) {
|
||||
if (assets) { this.assets = assets; }
|
||||
}
|
||||
) { }
|
||||
|
||||
static jsonSchema = Type.Object({
|
||||
"assets": Type.Record(Type.String(), Type.String()),
|
||||
|
||||
@@ -281,7 +281,7 @@ export default class ModPack {
|
||||
function propertyTreeBytes(element: PropertyType) {
|
||||
let type: number;
|
||||
let dataBytes: Buffer;
|
||||
if (typeof element === null) {
|
||||
if (element === null) {
|
||||
type = 1;
|
||||
dataBytes = Buffer.alloc(0);
|
||||
} else if (typeof element === "boolean") {
|
||||
|
||||
@@ -89,10 +89,10 @@ export class Link {
|
||||
router?: Router = undefined;
|
||||
validateSent = true;
|
||||
|
||||
_requestHandlers = new Map();
|
||||
_requestFallbacks = new Map();
|
||||
_eventHandlers = new Map();
|
||||
_eventSnoopers = new Map();
|
||||
_requestHandlers = new Map<RequestClass<unknown, unknown>, RequestHandler<unknown, unknown>>();
|
||||
_requestFallbacks = new Map<RequestClass<unknown, unknown>, RequestHandler<unknown, unknown>>();
|
||||
_eventHandlers = new Map<EventClass<unknown>, EventHandler<unknown>>();
|
||||
_eventSnoopers = new Map<EventClass<unknown>, EventHandler<unknown>>();
|
||||
_pendingRequests = new Map<number, PendingRequest>();
|
||||
_forwardedRequests = new Map<string, ForwardedRequest>();
|
||||
_nextRequestId = 1;
|
||||
@@ -189,7 +189,7 @@ export class Link {
|
||||
}
|
||||
|
||||
if (message.type === "event" && this._eventSnoopers.has((entry as EventEntry).Event)) {
|
||||
let handler = this._eventSnoopers.get((entry as EventEntry).Event);
|
||||
let handler = this._eventSnoopers.get((entry as EventEntry).Event)!;
|
||||
let event = message as libData.MessageEvent;
|
||||
handler((entry as EventEntry).eventFromJSON(event.data), event.src, event.dst).catch((err: Error) => {
|
||||
logger.error(`Unexpected error snooping ${event.name}:\n${err.stack}`);
|
||||
@@ -350,7 +350,7 @@ export class Link {
|
||||
_processRequest(
|
||||
message: libData.MessageRequest,
|
||||
entry: RequestEntry,
|
||||
handler: RequestHandler<unknown, unknown>,
|
||||
handler?: RequestHandler<unknown, unknown>,
|
||||
spoofedSrc?: libData.Address
|
||||
) {
|
||||
if (!handler) {
|
||||
@@ -579,7 +579,7 @@ export class Link {
|
||||
if (this._requestHandlers.has(Request)) {
|
||||
throw new Error(`Request ${entry.name} is already registered`);
|
||||
}
|
||||
this._requestHandlers.set(Request, handler);
|
||||
this._requestHandlers.set(Request, handler as RequestHandler<unknown, unknown>);
|
||||
}
|
||||
|
||||
fallbackRequest<Req, Res>(Request: RequestClass<Req, Res>, handler: RequestHandler<Req, Res>) {
|
||||
@@ -590,7 +590,7 @@ export class Link {
|
||||
if (this._requestFallbacks.has(Request)) {
|
||||
throw new Error(`Request ${entry.name} is already fallbacked`);
|
||||
}
|
||||
this._requestFallbacks.set(Request, handler);
|
||||
this._requestFallbacks.set(Request, handler as RequestHandler<unknown, unknown>);
|
||||
}
|
||||
|
||||
handleEvent<T>(Event: EventClass<T>, handler: EventHandler<T>) {
|
||||
@@ -601,7 +601,7 @@ export class Link {
|
||||
if (this._eventHandlers.has(Event)) {
|
||||
throw new Error(`Event ${entry.name} is already registered`);
|
||||
}
|
||||
this._eventHandlers.set(Event, handler);
|
||||
this._eventHandlers.set(Event, handler as EventHandler<unknown>);
|
||||
}
|
||||
|
||||
snoopEvent<T>(Event: EventClass<T>, handler: EventHandler<T>) {
|
||||
@@ -612,7 +612,7 @@ export class Link {
|
||||
if (this._eventSnoopers.has(Event)) {
|
||||
throw new Error(`Event ${entry.name} is already snooped`);
|
||||
}
|
||||
this._eventSnoopers.set(Event, handler);
|
||||
this._eventSnoopers.set(Event, handler as EventHandler<unknown>);
|
||||
}
|
||||
|
||||
static register<Req, Res>(Class: RequestClass<Req, Res>): void;
|
||||
@@ -646,7 +646,7 @@ export class Link {
|
||||
return () => new Request();
|
||||
}
|
||||
|
||||
static responseFromJSON<T>(Response: JSONDeserialisable<T>, name: string) {
|
||||
static responseFromJSON<T>(Response: Partial<JSONDeserialisable<T>>, name: string) {
|
||||
if (!Response.jsonSchema) {
|
||||
throw new Error(`Response for Request ${name} is missing static jsonSchema`);
|
||||
}
|
||||
@@ -661,12 +661,12 @@ export class Link {
|
||||
`Response for request ${name} failed validation`, validate.errors
|
||||
);
|
||||
}
|
||||
return Response.fromJSON(json);
|
||||
return Response.fromJSON!(json);
|
||||
};
|
||||
}
|
||||
|
||||
static allowedTypes(
|
||||
types: libData.AddressType | readonly libData.AddressType[],
|
||||
types: libData.AddressType | readonly libData.AddressType[] | undefined,
|
||||
name: string,
|
||||
side: "src" | "dst"
|
||||
) {
|
||||
|
||||
@@ -35,6 +35,12 @@ export type PluginNodeEnvInfo = PluginDeclaration & {
|
||||
requirePath: string;
|
||||
version: string;
|
||||
manifest: any;
|
||||
/**
|
||||
* NPM package this plugin is published as. Not present if the package
|
||||
* is private or the path used to load it does not match the name of the
|
||||
* package.
|
||||
*/
|
||||
npmPackage?: string;
|
||||
};
|
||||
|
||||
export type PluginWebpackEnvInfo = PluginDeclaration & {
|
||||
|
||||
@@ -24,7 +24,7 @@ export async function loadPluginInfos(pluginList: Map<string, string>) {
|
||||
let plugins: libPlugin.PluginNodeEnvInfo[] = [];
|
||||
for (let [pluginName, pluginPath] of pluginList) {
|
||||
let pluginInfo: libPlugin.PluginNodeEnvInfo;
|
||||
let pluginPackage: { version: string, main?: string };
|
||||
let pluginPackage: { name?: string, version: string, main?: string, private?: boolean };
|
||||
|
||||
try {
|
||||
pluginInfo = require(pluginPath).default;
|
||||
@@ -47,6 +47,7 @@ export async function loadPluginInfos(pluginList: Map<string, string>) {
|
||||
|
||||
pluginInfo.requirePath = pluginPath;
|
||||
pluginInfo.version = pluginPackage.version;
|
||||
pluginInfo.npmPackage = !pluginPackage.private && pluginPath === pluginPackage.name ? pluginPath : undefined;
|
||||
plugins.push(pluginInfo);
|
||||
}
|
||||
return plugins;
|
||||
|
||||
@@ -21,7 +21,7 @@ export function compile<T>(schema: JSONSchemaType<T>) {
|
||||
return ajv.compile<T>(schema);
|
||||
}
|
||||
|
||||
let doValidate: ValidateFunction<T>;
|
||||
let doValidate: ValidateFunction<T> | undefined;
|
||||
const validate = <ValidateFunction<T>> function (data) {
|
||||
if (!doValidate) {
|
||||
doValidate = ajv.compile(schema);
|
||||
|
||||
@@ -150,7 +150,7 @@ export async function createReverseReadStream(path: string, options?: ReadStream
|
||||
buffer: Buffer,
|
||||
offset: number,
|
||||
length: number,
|
||||
position: number,
|
||||
position: number | null | undefined,
|
||||
callback: () => void,
|
||||
) {
|
||||
assert(fd === fileFd);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"extends": "../../tsconfig.node.json",
|
||||
"include": ["index.ts", "build_mod.js", "src/**/*.ts", "src/**/*.js"],
|
||||
"include": ["index.ts", "browser.ts", "build_mod.js", "src/**/*.ts", "src/**/*.js"],
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"allowJs": true,
|
||||
|
||||
@@ -74,7 +74,7 @@ export default function AssignInstanceModal(props: AssignInstanceModalProps) {
|
||||
the instance. Note that reassigning an instance from
|
||||
one host to another will not move the server save over.
|
||||
</Paragraph>
|
||||
<Form form={form} initialValues={{ host: props.hostId === null ? "null" : props.hostId }}>
|
||||
<Form form={form} initialValues={{ host: props.hostId ?? "null" }}>
|
||||
<Form.Item name="host" label="Host">
|
||||
<Select>
|
||||
<Select.Option value={"null"}>
|
||||
|
||||
@@ -59,8 +59,7 @@ function GenerateHostTokenButton() {
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
// Only install plugins that aren't filesystem paths. Npm modules have max 1 forward slash in their name.
|
||||
const pluginString = pluginList.map(p => `"${p.requirePath}"`).filter(x => x.split("/").length <= 1).join(" ");
|
||||
const pluginString = pluginList.filter(p => p.npmPackage).map(p => `"${p.npmPackage}"`).join(" ");
|
||||
return <>
|
||||
<Button
|
||||
onClick={() => { setOpen(true); }}
|
||||
@@ -190,7 +189,7 @@ export default function HostsPage() {
|
||||
return <PageLayout nav={[{ name: "Hosts" }]}>
|
||||
<PageHeader
|
||||
title="Hosts"
|
||||
extra={account.hasPermission("core.host.generate_token") && <GenerateHostTokenButton /> || undefined}
|
||||
extra={account.hasPermission("core.host.generate_token") ? <GenerateHostTokenButton /> : undefined}
|
||||
/>
|
||||
<Table
|
||||
columns={[
|
||||
|
||||
@@ -34,7 +34,7 @@ function InstanceDescription(props: InstanceDescriptionProps) {
|
||||
let account = useAccount();
|
||||
|
||||
const { host, instance } = props;
|
||||
let assigned = instance.assignedHost !== null;
|
||||
let assigned = instance.assignedHost !== undefined;
|
||||
return <Descriptions
|
||||
bordered
|
||||
size="small"
|
||||
|
||||
@@ -8,7 +8,7 @@ const { useBreakpoint } = Grid;
|
||||
|
||||
type ModDetailsProps<T> = {
|
||||
mod: T;
|
||||
actions: (mod: T) => React.JSX.Element;
|
||||
actions?: (mod: T) => React.JSX.Element;
|
||||
};
|
||||
export default function ModDetails<T extends lib.ModInfo | lib.ModRecord>(props: ModDetailsProps<T>) {
|
||||
let screens = useBreakpoint();
|
||||
|
||||
@@ -296,13 +296,11 @@ function ModsTable(props: ModsTableProps) {
|
||||
>remove</Typography.Link>}
|
||||
{(deletedMods.has(mod.name) || changedMods.has(mod.name)) && <Typography.Link
|
||||
onClick={() => {
|
||||
if (props.onRevert) {
|
||||
props.onRevert({
|
||||
type: deletedMods.has(mod.name) ? "mods.delete" : "mods.set",
|
||||
name: mod.name,
|
||||
value: mod,
|
||||
});
|
||||
}
|
||||
props.onRevert({
|
||||
type: deletedMods.has(mod.name) ? "mods.delete" : "mods.set",
|
||||
name: mod.name,
|
||||
value: mod,
|
||||
});
|
||||
}}
|
||||
>revert</Typography.Link>}
|
||||
</Space>;
|
||||
@@ -464,7 +462,7 @@ const SettingsTableField = memo((props: SettingsTableFieldProps) => {
|
||||
return Promise.resolve();
|
||||
},
|
||||
}] : []]}
|
||||
className={ props.changed && "changed" || "" }
|
||||
className={props.changed ? "changed" : ""}
|
||||
>
|
||||
{input}
|
||||
</Form.Item>;
|
||||
@@ -669,11 +667,11 @@ function applyModPackChanges(modPack: lib.ModPack, changes: ModChange[]) {
|
||||
} else if (change.type === "mods.delete") {
|
||||
modifiedModPack.mods.delete(change.name!);
|
||||
} else if (change.type === "settings.set") {
|
||||
if (change.scope && change.name) {
|
||||
if (change.name) {
|
||||
modifiedModPack.settings[change.scope].set(change.name, change.value);
|
||||
}
|
||||
} else if (change.type === "settings.delete") {
|
||||
if (change.scope && change.name) {
|
||||
if (change.name) {
|
||||
modifiedModPack.settings[change.scope].delete(change.name);
|
||||
}
|
||||
} else {
|
||||
@@ -828,7 +826,7 @@ export default function ModPackViewPage() {
|
||||
<Descriptions.Item span={3} label="Name">
|
||||
<Form.Item noStyle name="name">
|
||||
<Input
|
||||
className={hasChange(changes, { type: "name" }) && "changed" || ""}
|
||||
className={hasChange(changes, { type: "name" }) ? "changed" : ""}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Descriptions.Item>
|
||||
@@ -836,7 +834,7 @@ export default function ModPackViewPage() {
|
||||
<Form.Item noStyle name="description">
|
||||
<Input.TextArea
|
||||
autoSize={{ minRows: 2 }}
|
||||
className={hasChange(changes, { type: "description" }) && "changed" || ""}
|
||||
className={hasChange(changes, { type: "description" }) ? "changed" : ""}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Descriptions.Item>
|
||||
@@ -853,7 +851,7 @@ export default function ModPackViewPage() {
|
||||
}]}
|
||||
>
|
||||
<Input
|
||||
className={hasChange(changes, { type: "factorioVersion" }) && "changed" || ""}
|
||||
className={hasChange(changes, { type: "factorioVersion" }) ? "changed" : ""}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Descriptions.Item>
|
||||
|
||||
@@ -11,7 +11,7 @@ import notify from "../util/notify";
|
||||
export default function PluginViewPage() {
|
||||
let params = useParams();
|
||||
let plugins = useContext(ControlContext).plugins;
|
||||
let [pluginList, setPluginList] = useState<PluginWebApi[]>([]);
|
||||
let [pluginList, setPluginList] = useState<PluginWebApi[]>();
|
||||
let pluginName = String(params.name);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -74,7 +74,7 @@ export default function RolesPage() {
|
||||
return <PageLayout nav={[{ name: "Roles" }]}>
|
||||
<PageHeader
|
||||
title="Roles"
|
||||
extra={account.hasPermission("core.role.create") && <CreateRoleButton /> || undefined}
|
||||
extra={account.hasPermission("core.role.create") ? <CreateRoleButton /> : undefined}
|
||||
/>
|
||||
<Table
|
||||
columns={[
|
||||
|
||||
@@ -93,7 +93,7 @@ export default function UserViewPage() {
|
||||
return role?.name.toLowerCase().includes(inputValue.toLowerCase()) ?? false;
|
||||
}}
|
||||
>
|
||||
{roles && [...roles.values()].map(r => <Select.Option
|
||||
{[...roles.values()].map(r => <Select.Option
|
||||
key={r.id}
|
||||
value={r.id}
|
||||
>{r.name}</Select.Option>)}
|
||||
@@ -182,7 +182,7 @@ export default function UserViewPage() {
|
||||
{account.hasPermission("core.user.update_roles")
|
||||
? roleSelector
|
||||
: [...user.roleIds!].map(id => <Tag key={id}>{
|
||||
roles ? (roles.get(id) || { name: id }).name : id
|
||||
roles?.get(id)?.name ?? id
|
||||
}</Tag>)
|
||||
}
|
||||
</Col>
|
||||
|
||||
@@ -75,7 +75,7 @@ export default function UsersPage() {
|
||||
return <PageLayout nav={[{ name: "Users" }]}>
|
||||
<PageHeader
|
||||
title="Users"
|
||||
extra={account.hasPermission("core.user.create") && <CreateUserButton /> || undefined}
|
||||
extra={account.hasPermission("core.user.create") ? <CreateUserButton /> : undefined}
|
||||
/>
|
||||
<Table
|
||||
columns={[
|
||||
|
||||
@@ -4,7 +4,7 @@ import * as lib from "@clusterio/lib";
|
||||
import ControlContext from "../components/ControlContext";
|
||||
|
||||
let exportManifestCache: lib.ExportManifest|null = null;
|
||||
let emptyCache: any = {};
|
||||
let emptyCache = { assets: {} };
|
||||
export function useExportManifest(): lib.ExportManifest|null {
|
||||
const control = useContext(ControlContext);
|
||||
let [exportManifest, setExportManifest] = useState<lib.ExportManifest|null>(exportManifestCache || emptyCache);
|
||||
|
||||
@@ -17,7 +17,6 @@ export function useItemMetadata() {
|
||||
async function load() {
|
||||
if (
|
||||
!exportManifest
|
||||
|| !exportManifest.assets
|
||||
|| !exportManifest.assets["item-metadata"]
|
||||
|| !exportManifest.assets["item-spritesheet"]
|
||||
) {
|
||||
|
||||
@@ -9,7 +9,7 @@ export function useLocale(): Map<string, string> {
|
||||
let [locale, setLocale] = useState<Map<string, string>>(localeCache || new Map());
|
||||
useEffect(() => {
|
||||
async function load() {
|
||||
if (!exportManifest?.assets?.["locale"]) {
|
||||
if (!exportManifest?.assets["locale"]) {
|
||||
return;
|
||||
}
|
||||
let response = await fetch(`${staticRoot}static/${exportManifest.assets["locale"]}`);
|
||||
@@ -27,4 +27,3 @@ export function useLocale(): Map<string, string> {
|
||||
|
||||
return locale;
|
||||
}
|
||||
|
||||
@@ -10,12 +10,9 @@ class Permission extends EventEmitter {
|
||||
status => {
|
||||
this.status = status;
|
||||
this.emit("change", this.status.state);
|
||||
|
||||
if (status.addEventListener) {
|
||||
status.addEventListener("change", () => {
|
||||
this.emit("change", this.status.state);
|
||||
});
|
||||
}
|
||||
status.addEventListener("change", () => {
|
||||
this.emit("change", this.status.state);
|
||||
});
|
||||
},
|
||||
// Pretend the clipboard will work if this query fails.
|
||||
() => {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"entryPoints": ["src/index.ts"],
|
||||
"includeVersion": true
|
||||
}
|
||||
@@ -24,7 +24,7 @@ async function loadDatabase(config: lib.ControllerConfig, logger: lib.Logger) {
|
||||
|
||||
async function saveDatabase(
|
||||
controllerConfig: lib.ControllerConfig,
|
||||
playerDatastore: Map<string, IpcPlayerData>,
|
||||
playerDatastore: Map<string, IpcPlayerData> | undefined,
|
||||
logger: lib.Logger,
|
||||
) {
|
||||
if (playerDatastore) {
|
||||
|
||||
@@ -141,6 +141,7 @@ export class ControllerPlugin extends BaseControllerPlugin {
|
||||
let { name, level } = event;
|
||||
let tech = this.technologies.get(name);
|
||||
if (!tech || tech.level <= level) {
|
||||
this.controller.sendTo("allInstances", event);
|
||||
this.progressToBroadcast.delete(name);
|
||||
this.technologies.set(name, { level, progress: null, researched: true });
|
||||
this.technologiesDirty = true;
|
||||
|
||||
@@ -56,7 +56,7 @@ export class InstancePlugin extends BaseInstancePlugin {
|
||||
}
|
||||
|
||||
async researchFinished(tech: IpcFinished) {
|
||||
this.instance.sendTo("allInstances", new FinishedEvent(tech.name, tech.level));
|
||||
this.instance.sendTo("controller", new FinishedEvent(tech.name, tech.level));
|
||||
}
|
||||
|
||||
async handleFinishedEvent(event: FinishedEvent) {
|
||||
|
||||
@@ -69,7 +69,7 @@ export class FinishedEvent {
|
||||
declare ["constructor"]: typeof FinishedEvent;
|
||||
static type = "event" as const;
|
||||
static src = ["instance", "controller"] as const;
|
||||
static dst = "instance" as const;
|
||||
static dst = ["instance", "controller"] as const;
|
||||
static plugin = "research_sync" as const;
|
||||
|
||||
constructor(
|
||||
|
||||
@@ -57,7 +57,7 @@ async function loadDatabase(
|
||||
|
||||
async function saveDatabase(
|
||||
controllerConfig: lib.ControllerConfig,
|
||||
items: lib.ItemDatabase,
|
||||
items: lib.ItemDatabase | undefined,
|
||||
logger: lib.Logger,
|
||||
) {
|
||||
if (items && items.size < 50000) {
|
||||
|
||||
@@ -134,7 +134,7 @@ export function doleDivider(
|
||||
// Update existing items if item name already exists
|
||||
if (itemCount > object.count) {
|
||||
// If successful, increase dole
|
||||
_doleDivisionFactor[object.name] = Math.max((_doleDivisionFactor[object.name] || 0) || 1, 1) - 1;
|
||||
_doleDivisionFactor[object.name] = Math.max(_doleDivisionFactor[object.name] || 1, 1) - 1;
|
||||
items.removeItem(object.name, object.count);
|
||||
|
||||
prometheusDoleFactorGauge.labels(object.name).set(_doleDivisionFactor[object.name] || 0);
|
||||
@@ -143,7 +143,7 @@ export function doleDivider(
|
||||
|
||||
// if we didn't have enough, attempt giving out a smaller amount next time
|
||||
_doleDivisionFactor[object.name] = Math.min(
|
||||
maxDoleDivision, Math.max((_doleDivisionFactor[object.name] || 0) || 1, 1) * 2
|
||||
maxDoleDivision, Math.max(_doleDivisionFactor[object.name] || 1, 1) * 2
|
||||
);
|
||||
prometheusDoleFactorGauge.labels(object.name).set(_doleDivisionFactor[object.name] || 0);
|
||||
return 0;
|
||||
|
||||
@@ -42,7 +42,7 @@ describe("lib/plugin_loader", function() {
|
||||
it("should load test plugin", async function() {
|
||||
assert.deepEqual(
|
||||
await lib.loadPluginInfos(new Map([["test", path.resolve(testPlugin)]])),
|
||||
[{ name: "test", version: "0.0.1", requirePath: path.resolve(testPlugin) }]
|
||||
[{ name: "test", version: "0.0.1", npmPackage: undefined, requirePath: path.resolve(testPlugin) }]
|
||||
);
|
||||
});
|
||||
it("should reject on broken plugin", async function() {
|
||||
|
||||
+7
-1
@@ -1,6 +1,12 @@
|
||||
{
|
||||
"$schema": "https://typedoc.org/schema.json",
|
||||
"entryPoints": ["packages/lib/"],
|
||||
"entryPoints": [
|
||||
"packages/lib/",
|
||||
"packages/controller/",
|
||||
"packages/host/",
|
||||
"packages/ctl/",
|
||||
"packages/web_ui/",
|
||||
],
|
||||
"entryPointStrategy": "packages",
|
||||
"cleanOutputDir": false,
|
||||
"out": "docs/api"
|
||||
|
||||
Reference in new issue
Block a user