aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-11-16 17:20:42 +0800
committercrupest <crupest@outlook.com>2020-11-16 17:20:42 +0800
commit8f5ffab46b18eb30dfebeb8407435dd85dc35232 (patch)
tree228c9a4275e5b2ff167d25268444e80c0baeac8b
parente7854c1ed8facc2955ef9ad96f0bb2513041bba9 (diff)
downloadtimeline-8f5ffab46b18eb30dfebeb8407435dd85dc35232.tar.gz
timeline-8f5ffab46b18eb30dfebeb8407435dd85dc35232.tar.bz2
timeline-8f5ffab46b18eb30dfebeb8407435dd85dc35232.zip
...
-rw-r--r--FrontEnd/src/app/http/user.ts8
-rw-r--r--FrontEnd/src/app/views/admin/Admin.tsx64
-rw-r--r--FrontEnd/src/app/views/admin/AdminSubPage.tsx44
-rw-r--r--FrontEnd/src/app/views/admin/UserAdmin.tsx80
4 files changed, 80 insertions, 116 deletions
diff --git a/FrontEnd/src/app/http/user.ts b/FrontEnd/src/app/http/user.ts
index 9ba6508f..92a6433e 100644
--- a/FrontEnd/src/app/http/user.ts
+++ b/FrontEnd/src/app/http/user.ts
@@ -49,6 +49,7 @@ export class HttpChangePasswordBadCredentialError extends Error {
}
export interface IHttpUserClient {
+ list(): Promise<HttpUser[]>;
get(username: string): Promise<HttpUser>;
patch(
username: string,
@@ -75,6 +76,13 @@ export interface IHttpUserClient {
}
export class HttpUserClient implements IHttpUserClient {
+ list(): Promise<HttpUser[]> {
+ return axios
+ .get<HttpUser[]>(`${apiBaseUrl}/users`)
+ .then(extractResponseData)
+ .catch(convertToNetworkError);
+ }
+
get(username: string): Promise<HttpUser> {
return axios
.get<HttpUser>(`${apiBaseUrl}/users/${username}`)
diff --git a/FrontEnd/src/app/views/admin/Admin.tsx b/FrontEnd/src/app/views/admin/Admin.tsx
index a64a9bc0..e17da5bc 100644
--- a/FrontEnd/src/app/views/admin/Admin.tsx
+++ b/FrontEnd/src/app/views/admin/Admin.tsx
@@ -1,12 +1,5 @@
import React, { Fragment } from "react";
-import {
- Redirect,
- Route,
- Switch,
- useRouteMatch,
- useHistory,
-} from "react-router";
-import { Nav } from "react-bootstrap";
+import { Redirect, Route, Switch, useRouteMatch, match } from "react-router";
import { AuthUser } from "@/services/user";
@@ -16,57 +9,22 @@ interface AdminProps {
user: AuthUser;
}
-const Admin: React.FC<AdminProps> = (props) => {
+const Admin: React.FC<AdminProps> = ({ user }) => {
const match = useRouteMatch();
- const history = useHistory();
- type TabNames = "users" | "more";
-
- const tabName = history.location.pathname.replace(match.path + "/", "");
-
- function toggle(newTab: TabNames): void {
- history.push(`${match.url}/${newTab}`);
- }
-
- const createRoute = (
- name: string,
- body: React.ReactNode
- ): React.ReactNode => {
- return (
- <Route path={`${match.path}/${name}`}>
- <div style={{ height: 56 }} className="flex-fix-length" />
- <Nav variant="tabs">
- <Nav.Item>
- <Nav.Link
- active={tabName === "users"}
- onClick={() => {
- toggle("users");
- }}
- >
- Users
- </Nav.Link>
- </Nav.Item>
- <Nav.Item>
- <Nav.Link
- active={tabName === "more"}
- onClick={() => {
- toggle("more");
- }}
- >
- More
- </Nav.Link>
- </Nav.Item>
- </Nav>
- {body}
- </Route>
- );
- };
return (
<Fragment>
<Switch>
<Redirect from={match.path} to={`${match.path}/users`} exact />
- {createRoute("users", <UserAdmin user={props.user} />)}
- {createRoute("more", <div>More Page Works</div>)}
+ <Route path={`${match.path}/:name`}>
+ {(p) => {
+ const match = p.match as match<{ name: string }>;
+ const name = match.params["name"];
+ if (name === "users") {
+ return <UserAdmin user={user} />;
+ }
+ }}
+ </Route>
</Switch>
</Fragment>
);
diff --git a/FrontEnd/src/app/views/admin/AdminSubPage.tsx b/FrontEnd/src/app/views/admin/AdminSubPage.tsx
new file mode 100644
index 00000000..5d2df13c
--- /dev/null
+++ b/FrontEnd/src/app/views/admin/AdminSubPage.tsx
@@ -0,0 +1,44 @@
+import React from "react";
+import { Nav } from "react-bootstrap";
+import { useHistory, useRouteMatch } from "react-router";
+
+const AdminSubPage: React.FC = ({ children }) => {
+ const match = useRouteMatch<{ name: string }>();
+ const history = useHistory();
+
+ const name = match.params.name;
+
+ function toggle(newTab: string): void {
+ history.push(`/admin/${newTab}`);
+ }
+
+ return (
+ <>
+ <Nav variant="tabs">
+ <Nav.Item>
+ <Nav.Link
+ active={name === "users"}
+ onClick={() => {
+ toggle("users");
+ }}
+ >
+ Users
+ </Nav.Link>
+ </Nav.Item>
+ <Nav.Item>
+ <Nav.Link
+ active={name === "more"}
+ onClick={() => {
+ toggle("more");
+ }}
+ >
+ More
+ </Nav.Link>
+ </Nav.Item>
+ </Nav>
+ {children}
+ </>
+ );
+};
+
+export default AdminSubPage;
diff --git a/FrontEnd/src/app/views/admin/UserAdmin.tsx b/FrontEnd/src/app/views/admin/UserAdmin.tsx
index 4ad9ed09..856e6136 100644
--- a/FrontEnd/src/app/views/admin/UserAdmin.tsx
+++ b/FrontEnd/src/app/views/admin/UserAdmin.tsx
@@ -10,19 +10,16 @@ import {
} from "react-bootstrap";
import OperationDialog from "../common/OperationDialog";
+import AdminSubPage from "./AdminSubPage";
+
import { User, AuthUser } from "@/services/user";
+import { getHttpUserClient } from "@/http/user";
const apiBaseUrl = "/api";
-async function fetchUserList(_token: string): Promise<User[]> {
- const res = await axios.get<User[]>(`${apiBaseUrl}/users`);
- return res.data;
-}
-
interface CreateUserInfo {
username: string;
password: string;
- administrator: boolean;
}
async function createUser(user: CreateUserInfo, token: string): Promise<User> {
@@ -57,16 +54,6 @@ function changePassword(
});
}
-function changePermission(
- username: string,
- newPermission: boolean,
- token: string
-): Promise<void> {
- return axios.patch(`${apiBaseUrl}/users/${username}?token=${token}`, {
- administrator: newPermission,
- });
-}
-
const kChangeUsername = "changeusername";
const kChangePassword = "changepassword";
const kChangePermission = "changepermission";
@@ -103,9 +90,9 @@ const UserItem: React.FC<UserCardProps> = (props) => {
<Col>
<p className="mb-0 text-primary">{user.username}</p>
<small
- className={user.administrator ? "text-danger" : "text-secondary"}
+ className={user.permissions ? "text-danger" : "text-secondary"}
>
- {user.administrator ? "administrator" : "user"}
+ {user.permissions ? "administrator" : "user"}
</small>
</Col>
<Col className="col-auto">
@@ -156,14 +143,12 @@ const CreateUserDialog: React.FC<CreateUserDialogProps> = (props) => {
[
{ type: "text", label: "Username" },
{ type: "text", label: "Password" },
- { type: "bool", label: "Administrator" },
] as const
}
- onProcess={([username, password, administrator]) =>
+ onProcess={([username, password]) =>
props.process({
username: username,
password: password,
- administrator: administrator,
})
}
close={props.close}
@@ -316,15 +301,17 @@ const UserAdmin: React.FC<UserAdminProps> = (props) => {
useEffect(() => {
let subscribe = true;
- void fetchUserList(props.user.token).then((us) => {
- if (subscribe) {
- setUsers(us);
- }
- });
+ void getHttpUserClient()
+ .list()
+ .then((us) => {
+ if (subscribe) {
+ setUsers(us);
+ }
+ });
return () => {
subscribe = false;
};
- }, [props.user]);
+ }, []);
let dialogNode: React.ReactNode;
if (dialog)
@@ -389,26 +376,6 @@ const UserAdmin: React.FC<UserAdminProps> = (props) => {
);
break;
case kChangePermission: {
- const newPermission = dialog.newPermission;
- dialogNode = (
- <UserChangePermissionDialog
- open
- close={() => setDialog(null)}
- username={dialog.username}
- newPermission={newPermission}
- process={async () => {
- await changePermission(dialog.username, newPermission, token);
- setUsers((oldUsers) => {
- const users = (oldUsers ?? []).slice();
- const findedUser = users.find(
- (u) => u.username === dialog.username
- );
- if (findedUser) findedUser.administrator = newPermission;
- return users;
- });
- }}
- />
- );
break;
}
}
@@ -419,26 +386,13 @@ const UserAdmin: React.FC<UserAdminProps> = (props) => {
<UserItem
key={user.username}
user={user}
- onContextMenu={(item) => {
- setDialog(
- item === kChangePermission
- ? {
- type: kChangePermission,
- username: user.username,
- newPermission: !user.administrator,
- }
- : {
- type: item,
- username: user.username,
- }
- );
- }}
+ onContextMenu={(item) => {}}
/>
);
});
return (
- <>
+ <AdminSubPage>
<Button
variant="success"
onClick={() =>
@@ -452,7 +406,7 @@ const UserAdmin: React.FC<UserAdminProps> = (props) => {
</Button>
{userComponents}
{dialogNode}
- </>
+ </AdminSubPage>
);
} else {
return <Spinner animation="border" />;