forked from clusterio/clusterio
-
Notifications
You must be signed in to change notification settings - Fork 0
/
UsersPage.tsx
140 lines (128 loc) · 3.78 KB
/
UsersPage.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import React, { useEffect, useContext, useState } from "react";
import { useNavigate } from "react-router-dom";
import { Button, Form, Input, Modal, Space, Table, Tag } from "antd";
import * as lib from "@clusterio/lib";
import { useAccount } from "../model/account";
import ControlContext from "./ControlContext";
import { notifyErrorHandler } from "../util/notify";
import { formatDuration } from "../util/time_format";
import PageHeader from "./PageHeader";
import PageLayout from "./PageLayout";
import PluginExtra from "./PluginExtra";
import { formatFirstSeen, formatLastSeen, sortFirstSeen, sortLastSeen, useUsers } from "../model/user";
import Link from "./Link";
const strcmp = new Intl.Collator(undefined, { numeric: true, sensitivity: "base" }).compare;
function CreateUserButton() {
let control = useContext(ControlContext);
let navigate = useNavigate();
let [open, setOpen] = useState(false);
let [form] = Form.useForm();
async function createUser() {
let values = form.getFieldsValue();
if (!values.userName) {
form.setFields([{ name: "userName", errors: ["Name is required"] }]);
return;
}
await control.send(new lib.UserCreateRequest(values.userName));
setOpen(false);
navigate(`/users/${values.userName}/view`);
}
return <>
<Button
type="primary"
onClick={() => { setOpen(true); }}
>Create</Button>
<Modal
title="Create User"
okText="Create"
open={open}
onOk={() => { createUser().catch(notifyErrorHandler("Error creating user")); }}
onCancel={() => { setOpen(false); }}
destroyOnClose
>
<Form form={form}>
<Form.Item name="userName" label="Name">
<Input />
</Form.Item>
</Form>
</Modal>
</>;
}
export default function UsersPage() {
let account = useAccount();
let control = useContext(ControlContext);
let navigate = useNavigate();
let [users] = useUsers();
let [roles, setRoles] = useState(new Map());
useEffect(() => {
control.send(new lib.RoleListRequest()).then(newRoles => {
setRoles(new Map(newRoles.map(role => [role.id, role])));
}).catch(() => {
// ignore
});
}, []);
return <PageLayout nav={[{ name: "Users" }]}>
<PageHeader
title="Users"
extra={account.hasPermission("core.user.create") ? <CreateUserButton /> : undefined}
/>
<Table
columns={[
{
title: "Name",
key: "name",
render: (_, user) => <Space>
{user.name}
<span>
{user.isAdmin && <Tag color="gold">Admin</Tag>}
{user.isWhitelisted && <Tag>Whitelisted</Tag>}
{user.isBanned && <Tag color="red">Banned</Tag>}
</span>
</Space>,
defaultSortOrder: "ascend",
sorter: (a, b) => strcmp(a.name, b.name),
},
{
title: "Roles",
key: "roles",
render: (_, user) => (
[...user.roleIds].map(id => <Link to={`/roles/${id}/view`} onClick={e => e.stopPropagation()}>
<Tag key={id}>{(roles.get(id) || { name: id }).name}</Tag>
</Link>)
),
},
{
title: "Online time",
key: "onlineTime",
render: (_, user) => (user.playerStats?.onlineTimeMs
? formatDuration(user.playerStats.onlineTimeMs) : null),
sorter: (a, b) => (a.playerStats?.onlineTimeMs ?? 0) -
(b.playerStats?.onlineTimeMs ?? 0),
responsive: ["lg"],
},
{
title: "First seen",
key: "firstSeen",
render: (_, user) => formatFirstSeen(user),
sorter: (a, b) => sortFirstSeen(a, b),
},
{
title: "Last seen",
key: "lastSeen",
render: (_, user) => formatLastSeen(user),
sorter: (a, b) => sortLastSeen(a, b),
responsive: ["lg"],
},
]}
dataSource={[...users.values()]}
pagination={false}
rowKey={user => user.name}
onRow={(user, rowIndex) => ({
onClick: event => {
navigate(`/users/${user.name}/view`);
},
})}
/>
<PluginExtra component="UsersPage" />
</PageLayout>;
}