mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-14 23:24:52 +09:00
Move all functions and classes currently available through lib/name and libName to be under a single flat namespace in lib. This make reorganising the lib namespace much simpler as the location of symbols can move without breaking the consumers of lib. The multi-entrypoint design was already problematic for the web plugin system which couldn't effectively use it due to how webpack's shared module system is awkward to set up with multiple entrypoints per package.
147 lines
3.9 KiB
React
147 lines
3.9 KiB
React
import React, { useEffect, useContext, useState } from "react";
|
|
import { useNavigate, useParams } from "react-router-dom";
|
|
import { Button, Checkbox, Form, Input, Popconfirm, Spin } from "antd";
|
|
import DeleteOutlined from "@ant-design/icons/DeleteOutlined";
|
|
|
|
import * as lib from "@clusterio/lib";
|
|
|
|
import { useAccount } from "../model/account";
|
|
import ControlContext from "./ControlContext";
|
|
import PageHeader from "./PageHeader";
|
|
import PageLayout from "./PageLayout";
|
|
import PluginExtra from "./PluginExtra";
|
|
import { notifyErrorHandler } from "../util/notify";
|
|
|
|
|
|
function useRole(id) {
|
|
let control = useContext(ControlContext);
|
|
let [role, setRole] = useState({ loading: true });
|
|
|
|
function updateRole() {
|
|
// XXX optimize by requesting only the role in question
|
|
control.send(new lib.RoleListRequest()).then(roles => {
|
|
let match = roles.find(u => u.id === id);
|
|
if (!match) {
|
|
setRole({ missing: true });
|
|
} else {
|
|
setRole({
|
|
...match,
|
|
present: true,
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
useEffect(() => {
|
|
updateRole();
|
|
}, [id]);
|
|
|
|
return [role, updateRole];
|
|
}
|
|
|
|
export default function RoleViewPage() {
|
|
let params = useParams();
|
|
let roleId = Number(params.id);
|
|
|
|
let navigate = useNavigate();
|
|
|
|
let account = useAccount();
|
|
let control = useContext(ControlContext);
|
|
let [role, updateRole] = useRole(roleId);
|
|
let [edited, setEdited] = useState(false);
|
|
|
|
|
|
let nav = [{ name: "Roles", path: "/roles" }, { name: role["name"] || roleId }];
|
|
if (role.loading) {
|
|
return <PageLayout nav={nav}>
|
|
<PageHeader title={roleId} />
|
|
<Spin size="large" />
|
|
</PageLayout>;
|
|
}
|
|
|
|
if (role.missing) {
|
|
return <PageLayout nav={nav}>
|
|
<PageHeader title="Role not found" />
|
|
<p>Role with id {roleId} was not found on the controller.</p>
|
|
</PageLayout>;
|
|
}
|
|
|
|
let initialValues = {
|
|
name: role["name"],
|
|
description: role["description"],
|
|
permissions: {
|
|
...Object.fromEntries([...lib.permissions.values()].map(perm => [
|
|
perm.name, role["permissions"].includes(perm.name),
|
|
])),
|
|
},
|
|
};
|
|
|
|
let canUpdate = account.hasPermission("core.role.update");
|
|
return <PageLayout nav={nav}>
|
|
<Form
|
|
initialValues={initialValues}
|
|
onValuesChange={() => { setEdited(true); }}
|
|
onFinish={values => {
|
|
let newPermissions = [];
|
|
for (let [name, value] of Object.entries(values.permissions)) {
|
|
if (value) { newPermissions.push(name); }
|
|
}
|
|
|
|
control.send(
|
|
new lib.RoleUpdateRequest(roleId, values.name || "", values.description || "", newPermissions)
|
|
).then(() => {
|
|
setEdited(false);
|
|
updateRole();
|
|
}).catch(notifyErrorHandler("Error applying changes"));
|
|
}}
|
|
>
|
|
<PageHeader
|
|
title={role["name"]}
|
|
extra={<>
|
|
{canUpdate && <Button type={edited ? "primary" : "default"} htmlType="submit">Apply</Button>}
|
|
{account.hasPermission("core.role.delete") && <Popconfirm
|
|
title="Delete role?"
|
|
placement="bottomRight"
|
|
okText="Delete"
|
|
okButtonProps={{ danger: true }}
|
|
onConfirm={() => {
|
|
control.send(
|
|
new lib.RoleDeleteRequest(roleId)
|
|
).then(() => {
|
|
navigate("/roles");
|
|
}).catch(notifyErrorHandler("Error deleting role"));
|
|
}}
|
|
>
|
|
<Button danger >
|
|
<DeleteOutlined />
|
|
</Button>
|
|
</Popconfirm>}
|
|
</>}
|
|
/>
|
|
<Form.Item name="name" label="Name">
|
|
<Input disabled={!canUpdate}/>
|
|
</Form.Item>
|
|
<Form.Item name="description" label="Description">
|
|
<Input disabled={!canUpdate}/>
|
|
</Form.Item>
|
|
<h3>Permissions</h3>
|
|
{[...lib.permissions.values()].map(({name, title, description}) => (
|
|
<Form.Item
|
|
name={["permissions", name]}
|
|
key={name}
|
|
label={title}
|
|
tooltip={description}
|
|
valuePropName="checked"
|
|
labelCol={{ sm: { span: 22, push: 2 }}}
|
|
wrapperCol={{ sm: { span: 2, pull: 22 }}}
|
|
labelAlign="left"
|
|
colon={false}
|
|
>
|
|
<Checkbox disabled={!canUpdate} />
|
|
</Form.Item>
|
|
))}
|
|
</Form>
|
|
<PluginExtra component="RoleViewPage" role={role} />
|
|
</PageLayout>;
|
|
}
|