From 47587812b809fee2a95c76266d9d0e42fc4ac1ca Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 15 Jun 2021 14:14:28 +0800 Subject: ... --- FrontEnd/src/views/admin/UserAdmin.tsx | 396 +++++++++++++++++++++++++++++++++ 1 file changed, 396 insertions(+) create mode 100644 FrontEnd/src/views/admin/UserAdmin.tsx (limited to 'FrontEnd/src/views/admin/UserAdmin.tsx') diff --git a/FrontEnd/src/views/admin/UserAdmin.tsx b/FrontEnd/src/views/admin/UserAdmin.tsx new file mode 100644 index 00000000..4e9cd600 --- /dev/null +++ b/FrontEnd/src/views/admin/UserAdmin.tsx @@ -0,0 +1,396 @@ +import React, { useState, useEffect } from "react"; +import classnames from "classnames"; +import { ListGroup, Row, Col, Spinner, Button } from "react-bootstrap"; + +import OperationDialog, { + OperationDialogBoolInput, +} from "../common/OperationDialog"; + +import { AuthUser } from "@/services/user"; +import { + getHttpUserClient, + HttpUser, + kUserPermissionList, + UserPermission, +} from "http/user"; +import { Trans, useTranslation } from "react-i18next"; + +interface DialogProps { + open: boolean; + close: () => void; + data: TData; + onSuccess: (data: TReturn) => void; +} + +const CreateUserDialog: React.FC> = ({ + open, + close, + onSuccess, +}) => { + return ( + + getHttpUserClient().post({ + username, + password, + }) + } + close={close} + open={open} + onSuccessAndClose={onSuccess} + /> + ); +}; + +const UsernameLabel: React.FC = (props) => { + return {props.children}; +}; + +const UserDeleteDialog: React.FC> = + ({ open, close, data: { username }, onSuccess }) => { + return ( + ( + + 0{username}2 + + )} + onProcess={() => getHttpUserClient().delete(username)} + onSuccessAndClose={onSuccess} + /> + ); + }; + +const UserModifyDialog: React.FC< + DialogProps< + { + oldUser: HttpUser; + }, + HttpUser + > +> = ({ open, close, data: { oldUser }, onSuccess }) => { + return ( + ( + + 0{oldUser.username}2 + + )} + inputScheme={ + [ + { + type: "text", + label: "admin:user.username", + initValue: oldUser.username, + }, + { type: "text", label: "admin:user.password" }, + { + type: "text", + label: "admin:user.nickname", + initValue: oldUser.nickname, + }, + ] as const + } + onProcess={([username, password, nickname]) => + getHttpUserClient().patch(oldUser.username, { + username: username !== oldUser.username ? username : undefined, + password: password !== "" ? password : undefined, + nickname: nickname !== oldUser.nickname ? nickname : undefined, + }) + } + onSuccessAndClose={onSuccess} + /> + ); +}; + +const UserPermissionModifyDialog: React.FC< + DialogProps< + { + username: string; + permissions: UserPermission[]; + }, + UserPermission[] + > +> = ({ open, close, data: { username, permissions }, onSuccess }) => { + const oldPermissionBoolList: boolean[] = kUserPermissionList.map( + (permission) => permissions.includes(permission) + ); + + return ( + ( + + 0{username}2 + + )} + inputScheme={kUserPermissionList.map( + (permission, index) => ({ + type: "bool", + label: permission, + initValue: oldPermissionBoolList[index], + }) + )} + onProcess={async (newPermissionBoolList): Promise => { + 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(username, permission); + } else { + await getHttpUserClient().deleteUserPermission( + username, + permission + ); + } + } + return newPermissionBoolList; + }} + onSuccessAndClose={(newPermissionBoolList: boolean[]) => { + const permissions: UserPermission[] = []; + for (let index = 0; index < kUserPermissionList.length; index++) { + if (newPermissionBoolList[index]) { + permissions.push(kUserPermissionList[index]); + } + } + onSuccess(permissions); + }} + /> + ); +}; + +const kModify = "modify"; +const kModifyPermission = "permission"; +const kDelete = "delete"; + +type TModify = typeof kModify; +type TModifyPermission = typeof kModifyPermission; +type TDelete = typeof kDelete; + +type ContextMenuItem = TModify | TModifyPermission | TDelete; + +interface UserItemProps { + on: { [key in ContextMenuItem]: () => void }; + user: HttpUser; +} + +const UserItem: React.FC = ({ user, on }) => { + const { t } = useTranslation(); + + const [editMaskVisible, setEditMaskVisible] = React.useState(false); + + return ( + + setEditMaskVisible(true)} + /> +

{user.username}

+
+ {t("admin:user.nickname")} + {user.nickname} +
+
+ {t("admin:user.uniqueId")} + {user.uniqueId} +
+
+ {t("admin:user.permissions")} + {user.permissions.map((permission) => { + return ( + + {permission}{" "} + + ); + })} +
+
setEditMaskVisible(false)} + > + + + +
+
+ ); +}; + +interface UserAdminProps { + user: AuthUser; +} + +const UserAdmin: React.FC = () => { + const { t } = useTranslation(); + + type DialogInfo = + | null + | { + type: "create"; + } + | { + type: TModify; + user: HttpUser; + } + | { + type: TModifyPermission; + username: string; + permissions: UserPermission[]; + } + | { type: TDelete; username: string }; + + const [users, setUsers] = useState(null); + const [dialog, setDialog] = useState(null); + const [usersVersion, setUsersVersion] = useState(0); + const updateUsers = (): void => { + setUsersVersion(usersVersion + 1); + }; + + useEffect(() => { + let subscribe = true; + void getHttpUserClient() + .list() + .then((us) => { + if (subscribe) { + setUsers(us); + } + }); + return () => { + subscribe = false; + }; + }, [usersVersion]); + + let dialogNode: React.ReactNode; + if (dialog) { + switch (dialog.type) { + case "create": + dialogNode = ( + setDialog(null)} + data={undefined} + onSuccess={updateUsers} + /> + ); + break; + case kDelete: + dialogNode = ( + setDialog(null)} + data={{ username: dialog.username }} + onSuccess={updateUsers} + /> + ); + break; + case kModify: + dialogNode = ( + setDialog(null)} + data={{ oldUser: dialog.user }} + onSuccess={updateUsers} + /> + ); + break; + case kModifyPermission: + dialogNode = ( + setDialog(null)} + data={{ + username: dialog.username, + permissions: dialog.permissions, + }} + onSuccess={updateUsers} + /> + ); + break; + } + } + + if (users) { + const userComponents = users.map((user) => { + return ( + { + setDialog({ + type: "modify", + user, + }); + }, + permission: () => { + setDialog({ + type: kModifyPermission, + username: user.username, + permissions: user.permissions, + }); + }, + delete: () => { + setDialog({ + type: "delete", + username: user.username, + }); + }, + }} + /> + ); + }); + + return ( + <> + + + + + + {userComponents} + {dialogNode} + + ); + } else { + return ; + } +}; + +export default UserAdmin; -- cgit v1.2.3