aboutsummaryrefslogtreecommitdiff
path: root/FrontEnd/src/migrating/admin/UserAdmin.tsx
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2023-09-20 20:26:42 +0800
committerGitHub <noreply@github.com>2023-09-20 20:26:42 +0800
commitf836d77e73f3ea0af45c5f71dae7268143d6d86f (patch)
tree573cfafd972106d69bef0d41ff5f270ec3c43ec2 /FrontEnd/src/migrating/admin/UserAdmin.tsx
parent4a069bf1268f393d5467166356f691eb89963152 (diff)
parent901fe3d7c032d284da5c9bce24c4aaee9054c7ac (diff)
downloadtimeline-f836d77e73f3ea0af45c5f71dae7268143d6d86f.tar.gz
timeline-f836d77e73f3ea0af45c5f71dae7268143d6d86f.tar.bz2
timeline-f836d77e73f3ea0af45c5f71dae7268143d6d86f.zip
Merge pull request #1395 from crupest/dev
Refector 2023 v0.1
Diffstat (limited to 'FrontEnd/src/migrating/admin/UserAdmin.tsx')
-rw-r--r--FrontEnd/src/migrating/admin/UserAdmin.tsx301
1 files changed, 301 insertions, 0 deletions
diff --git a/FrontEnd/src/migrating/admin/UserAdmin.tsx b/FrontEnd/src/migrating/admin/UserAdmin.tsx
new file mode 100644
index 00000000..08560c87
--- /dev/null
+++ b/FrontEnd/src/migrating/admin/UserAdmin.tsx
@@ -0,0 +1,301 @@
+// eslint-disable
+// @ts-nocheck
+
+import { useState, useEffect } from "react";
+import * as React from "react";
+import { Trans, useTranslation } from "react-i18next";
+import classnames from "classnames";
+
+import { getHttpUserClient, HttpUser, kUserPermissionList } from "@/http/user";
+
+import OperationDialog from "../common/dialog/OperationDialog";
+import Button from "../common/button/Button";
+import Spinner from "../common/Spinner";
+import FlatButton from "../common/button/FlatButton";
+import IconButton from "../common/button/IconButton";
+
+const CreateUserDialog: React.FC<{
+ open: boolean;
+ close: () => void;
+ onSuccess: (user: HttpUser) => void;
+}> = ({ open, close, onSuccess }) => {
+ return (
+ <OperationDialog
+ title="admin:user.dialog.create.title"
+ inputPrompt="admin:user.dialog.create.prompt"
+ inputs={[
+ { key: "username", type: "text", label: "admin:user.username" },
+ { key: "password", type: "text", label: "admin:user.password" },
+ ]}
+ onProcess={({ username, password }) =>
+ getHttpUserClient().post({
+ username: username as string,
+ password: password as string,
+ })
+ }
+ onClose={close}
+ open={open}
+ onSuccessAndClose={onSuccess}
+ />
+ );
+};
+
+const UsernameLabel: React.FC<{ children: React.ReactNode }> = (props) => {
+ return <span style={{ color: "blue" }}>{props.children}</span>;
+};
+
+const UserDeleteDialog: React.FC<{
+ open: boolean;
+ close: () => void;
+ user: HttpUser;
+ onSuccess: () => void;
+}> = ({ open, close, user, onSuccess }) => {
+ return (
+ <OperationDialog
+ open={open}
+ onClose={close}
+ title="admin:user.dialog.delete.title"
+ themeColor="danger"
+ inputPrompt={() => (
+ <Trans i18nKey="user.dialog.delete.prompt" ns="admin">
+ 0<UsernameLabel>{user.username}</UsernameLabel>2
+ </Trans>
+ )}
+ onProcess={() => getHttpUserClient().delete(user.username)}
+ onSuccessAndClose={onSuccess}
+ />
+ );
+};
+
+const UserModifyDialog: React.FC<{
+ open: boolean;
+ close: () => void;
+ user: HttpUser;
+ onSuccess: () => void;
+}> = ({ open, close, user, onSuccess }) => {
+ return (
+ <OperationDialog
+ open={open}
+ onClose={close}
+ title="admin:user.dialog.modify.title"
+ inputPromptNode={
+ <Trans i18nKey="admin:user.dialog.modify.prompt">
+ 0<UsernameLabel>{user.username}</UsernameLabel>2
+ </Trans>
+ }
+ inputs={
+ [
+ {
+ type: "text",
+ label: "admin:user.username",
+ initValue: user.username,
+ },
+ { type: "text", label: "admin:user.password" },
+ {
+ type: "text",
+ label: "admin:user.nickname",
+ initValue: user.nickname,
+ },
+ ] as const
+ }
+ onProcess={([username, password, nickname]) =>
+ getHttpUserClient().patch(user.username, {
+ username: username !== user.username ? username : undefined,
+ password: password !== "" ? password : undefined,
+ nickname: nickname !== user.nickname ? nickname : undefined,
+ })
+ }
+ onSuccessAndClose={onSuccess}
+ />
+ );
+};
+
+const UserPermissionModifyDialog: React.FC<{
+ open: boolean;
+ close: () => void;
+ user: HttpUser;
+ onSuccess: () => void;
+}> = ({ open, close, user, onSuccess }) => {
+ const oldPermissionBoolList: boolean[] = kUserPermissionList.map(
+ (permission) => user.permissions.includes(permission),
+ );
+
+ return (
+ <OperationDialog
+ open={open}
+ onClose={close}
+ title="admin:user.dialog.modifyPermissions.title"
+ themeColor="danger"
+ inputPrompt={() => (
+ <Trans i18nKey="admin:user.dialog.modifyPermissions.prompt">
+ 0<UsernameLabel>{user.username}</UsernameLabel>2
+ </Trans>
+ )}
+ inputScheme={kUserPermissionList.map<OperationDialogBoolInput>(
+ (permission, index) => ({
+ type: "bool",
+ label: { type: "custom", value: permission },
+ initValue: oldPermissionBoolList[index],
+ }),
+ )}
+ onProcess={async (newPermissionBoolList): Promise<boolean[]> => {
+ for (let index = 0; index < kUserPermissionList.length; index++) {
+ const oldValue = oldPermissionBoolList[index];
+ const newValue = newPermissionBoolList[index];
+ const permission = kUserPermissionList[index];
+ if (oldValue === newValue) continue;
+ if (newValue) {
+ await getHttpUserClient().putUserPermission(
+ user.username,
+ permission,
+ );
+ } else {
+ await getHttpUserClient().deleteUserPermission(
+ user.username,
+ permission,
+ );
+ }
+ }
+ return newPermissionBoolList;
+ }}
+ onSuccessAndClose={onSuccess}
+ />
+ );
+};
+
+interface UserItemProps {
+ user: HttpUser;
+ onChange: () => void;
+}
+
+const UserItem: React.FC<UserItemProps> = ({ user, onChange }) => {
+ const { t } = useTranslation();
+
+ const [dialog, setDialog] = useState<
+ "delete" | "modify" | "permission" | null
+ >(null);
+
+ const [editMaskVisible, setEditMaskVisible] = React.useState<boolean>(false);
+
+ return (
+ <>
+ <div className="admin-user-item">
+ <IconButton
+ icon="pencil-square"
+ className="cru-float-right"
+ onClick={() => setEditMaskVisible(true)}
+ />
+ <h5 className="cru-color-primary">{user.username}</h5>
+ <small className="d-block cru-color-secondary">
+ {t("admin:user.nickname")}
+ {user.nickname}
+ </small>
+ <small className="d-block cru-color-secondary">
+ {t("admin:user.uniqueId")}
+ {user.uniqueId}
+ </small>
+ <small className="d-block cru-color-secondary">
+ {t("admin:user.permissions")}
+ {user.permissions.map((permission) => {
+ return (
+ <span key={permission} className="cru-color-danger">
+ {permission}
+ </span>
+ );
+ })}
+ </small>
+ <div
+ className={classnames("edit-mask", !editMaskVisible && "d-none")}
+ onClick={() => setEditMaskVisible(false)}
+ >
+ <FlatButton
+ text="admin:user.modify"
+ onClick={() => setDialog("modify")}
+ />
+ <FlatButton
+ text="admin:user.modifyPermissions"
+ onClick={() => setDialog("permission")}
+ />
+ <FlatButton
+ text="admin:user.delete"
+ color="danger"
+ onClick={() => setDialog("delete")}
+ />
+ </div>
+ </div>
+ <UserDeleteDialog
+ open={dialog === "delete"}
+ close={() => setDialog(null)}
+ user={user}
+ onSuccess={onChange}
+ />
+ <UserModifyDialog
+ open={dialog === "modify"}
+ close={() => setDialog(null)}
+ user={user}
+ onSuccess={onChange}
+ />
+ <UserPermissionModifyDialog
+ open={dialog === "permission"}
+ close={() => setDialog(null)}
+ user={user}
+ onSuccess={onChange}
+ />
+ </>
+ );
+};
+
+const UserAdmin: React.FC = () => {
+ const [users, setUsers] = useState<HttpUser[] | null>(null);
+ const [dialog, setDialog] = useState<"create" | null>(null);
+ const [usersVersion, setUsersVersion] = useState<number>(0);
+ const updateUsers = (): void => {
+ setUsersVersion(usersVersion + 1);
+ };
+
+ useEffect(() => {
+ let subscribe = true;
+ void getHttpUserClient()
+ .list()
+ .then((us) => {
+ if (subscribe) {
+ setUsers(us.items);
+ }
+ });
+ return () => {
+ subscribe = false;
+ };
+ }, [usersVersion]);
+
+ if (users) {
+ const userComponents = users.map((user) => {
+ return (
+ <UserItem key={user.username} user={user} onChange={updateUsers} />
+ );
+ });
+
+ return (
+ <>
+ <div className="row justify-content-end my-2">
+ <div className="col col-auto">
+ <Button
+ text="admin:create"
+ color="success"
+ onClick={() => setDialog("create")}
+ />
+ </div>
+ </div>
+ {userComponents}
+ <CreateUserDialog
+ open={dialog === "create"}
+ close={() => setDialog(null)}
+ onSuccess={updateUsers}
+ />
+ </>
+ );
+ } else {
+ return <Spinner />;
+ }
+};
+
+export default UserAdmin;