From de1d582bf2ed7062fd400459f30d463d47ef9982 Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 24 Aug 2020 22:59:45 +0800 Subject: ... --- Timeline/ClientApp/src/app/admin/Admin.tsx | 156 ++--- Timeline/ClientApp/src/app/admin/UserAdmin.tsx | 928 ++++++++++++------------- 2 files changed, 542 insertions(+), 542 deletions(-) (limited to 'Timeline/ClientApp/src/app/admin') diff --git a/Timeline/ClientApp/src/app/admin/Admin.tsx b/Timeline/ClientApp/src/app/admin/Admin.tsx index af07dd2b..2f8b2c05 100644 --- a/Timeline/ClientApp/src/app/admin/Admin.tsx +++ b/Timeline/ClientApp/src/app/admin/Admin.tsx @@ -1,78 +1,78 @@ -import React, { Fragment } from 'react'; -import { Nav, NavItem, NavLink } from 'reactstrap'; -import { - Redirect, - Route, - Switch, - useRouteMatch, - useHistory -} from 'react-router'; -import classnames from 'classnames'; - -import AppBar from '../common/AppBar'; -import UserAdmin from './UserAdmin'; - -import { UserWithToken } from '../data/user'; - -interface AdminProps { - user: UserWithToken; -} - -const Admin: React.FC = props => { - 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 ( - - -
- - {body} - - ); - }; - - return ( - - - - {createRoute('users', )} - {createRoute('more',
More Page Works
)} -
-
- ); -}; - -export default Admin; +import React, { Fragment } from "react"; +import { Nav, NavItem, NavLink } from "reactstrap"; +import { + Redirect, + Route, + Switch, + useRouteMatch, + useHistory, +} from "react-router"; +import classnames from "classnames"; + +import AppBar from "../common/AppBar"; +import UserAdmin from "./UserAdmin"; + +import { UserWithToken } from "../data/user"; + +interface AdminProps { + user: UserWithToken; +} + +const Admin: React.FC = (props) => { + 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 ( + + +
+ + {body} + + ); + }; + + return ( + + + + {createRoute("users", )} + {createRoute("more",
More Page Works
)} +
+
+ ); +}; + +export default Admin; diff --git a/Timeline/ClientApp/src/app/admin/UserAdmin.tsx b/Timeline/ClientApp/src/app/admin/UserAdmin.tsx index a3115073..57eed455 100644 --- a/Timeline/ClientApp/src/app/admin/UserAdmin.tsx +++ b/Timeline/ClientApp/src/app/admin/UserAdmin.tsx @@ -1,464 +1,464 @@ -import React, { useState, useEffect } from 'react'; -import { - ListGroupItem, - Row, - Col, - UncontrolledDropdown, - DropdownToggle, - DropdownMenu, - DropdownItem, - Spinner, - Button, -} from 'reactstrap'; -import axios from 'axios'; - -import OperationDialog from '../common/OperationDialog'; - -import { User, UserWithToken } from '../data/user'; - -const apiBaseUrl = '/api'; - -async function fetchUserList(_token: string): Promise { - const res = await axios.get(`${apiBaseUrl}/users`); - return res.data; -} - -interface CreateUserInfo { - username: string; - password: string; - administrator: boolean; -} - -async function createUser(user: CreateUserInfo, token: string): Promise { - const res = await axios.post( - `${apiBaseUrl}/userop/createuser?token=${token}`, - user - ); - return res.data; -} - -function deleteUser(username: string, token: string): Promise { - return axios.delete(`${apiBaseUrl}/users/${username}?token=${token}`); -} - -function changeUsername( - oldUsername: string, - newUsername: string, - token: string -): Promise { - return axios.patch(`${apiBaseUrl}/users/${oldUsername}?token=${token}`, { - username: newUsername, - }); -} - -function changePassword( - username: string, - newPassword: string, - token: string -): Promise { - return axios.patch(`${apiBaseUrl}/users/${username}?token=${token}`, { - password: newPassword, - }); -} - -function changePermission( - username: string, - newPermission: boolean, - token: string -): Promise { - return axios.patch(`${apiBaseUrl}/users/${username}?token=${token}`, { - administrator: newPermission, - }); -} - -const kChangeUsername = 'changeusername'; -const kChangePassword = 'changepassword'; -const kChangePermission = 'changepermission'; -const kDelete = 'delete'; - -type TChangeUsername = typeof kChangeUsername; -type TChangePassword = typeof kChangePassword; -type TChangePermission = typeof kChangePermission; -type TDelete = typeof kDelete; - -type ContextMenuItem = - | TChangeUsername - | TChangePassword - | TChangePermission - | TDelete; - -interface UserCardProps { - onContextMenu: (item: ContextMenuItem) => void; - user: User; -} - -const UserItem: React.FC = (props) => { - const user = props.user; - - const createClickCallback = (item: ContextMenuItem): (() => void) => { - return () => { - props.onContextMenu(item); - }; - }; - - return ( - - - -

{user.username}

- - {user.administrator ? 'administrator' : 'user'} - - - - - - Manage - - - - Change Username - - - Change Password - - - Change Permission - - - Delete - - - - -
-
- ); -}; - -interface DialogProps { - open: boolean; - close: () => void; -} - -interface CreateUserDialogProps extends DialogProps { - process: (user: CreateUserInfo) => Promise; -} - -const CreateUserDialog: React.FC = (props) => { - return ( - - props.process({ - username: username as string, - password: password as string, - administrator: administrator as boolean, - }) - } - close={props.close} - open={props.open} - /> - ); -}; - -const UsernameLabel: React.FC = (props) => { - return {props.children}; -}; - -interface UserDeleteDialogProps extends DialogProps { - username: string; - process: () => Promise; -} - -const UserDeleteDialog: React.FC = (props) => { - return ( - ( - <> - {'You are deleting user '} - {props.username} - {' !'} - - )} - onProcess={props.process} - /> - ); -}; - -interface UserModifyDialogProps extends DialogProps { - username: string; - process: (value: T) => Promise; -} - -const UserChangeUsernameDialog: React.FC> = ( - props -) => { - return ( - ( - <> - {'You are change the username of user '} - {props.username} - {' !'} - - )} - inputScheme={[{ type: 'text', label: 'New Username' }]} - onProcess={([newUsername]) => { - return props.process(newUsername as string); - }} - /> - ); -}; - -const UserChangePasswordDialog: React.FC> = ( - props -) => { - return ( - ( - <> - {'You are change the password of user '} - {props.username} - {' !'} - - )} - inputScheme={[{ type: 'text', label: 'New Password' }]} - onProcess={([newPassword]) => { - return props.process(newPassword as string); - }} - /> - ); -}; - -interface UserChangePermissionDialogProps extends DialogProps { - username: string; - newPermission: boolean; - process: () => Promise; -} - -const UserChangePermissionDialog: React.FC = ( - props -) => { - return ( - ( - <> - {'You are change user '} - {props.username} - {' to '} - - {props.newPermission ? 'administrator' : 'normal user'} - - {' !'} - - )} - onProcess={props.process} - /> - ); -}; - -interface UserAdminProps { - user: UserWithToken; -} - -const UserAdmin: React.FC = (props) => { - type DialogInfo = - | null - | { - type: 'create'; - } - | { type: TDelete; username: string } - | { - type: TChangeUsername; - username: string; - } - | { - type: TChangePassword; - username: string; - } - | { - type: TChangePermission; - username: string; - newPermission: boolean; - }; - - const [users, setUsers] = useState(null); - const [dialog, setDialog] = useState(null); - - const token = props.user.token; - - useEffect(() => { - let subscribe = true; - void fetchUserList(props.user.token).then((us) => { - if (subscribe) { - setUsers(us); - } - }); - return () => { - subscribe = false; - }; - }, [props.user]); - - let dialogNode: React.ReactNode; - if (dialog) - switch (dialog.type) { - case 'create': - dialogNode = ( - setDialog(null)} - process={async (user) => { - const u = await createUser(user, token); - setUsers((oldUsers) => [...(oldUsers ?? []), u]); - }} - /> - ); - break; - case 'delete': - dialogNode = ( - setDialog(null)} - username={dialog.username} - process={async () => { - await deleteUser(dialog.username, token); - setUsers((oldUsers) => - (oldUsers ?? []).filter((u) => u.username !== dialog.username) - ); - }} - /> - ); - break; - case kChangeUsername: - dialogNode = ( - setDialog(null)} - username={dialog.username} - process={async (newUsername) => { - await changeUsername(dialog.username, newUsername, token); - setUsers((oldUsers) => { - const users = (oldUsers ?? []).slice(); - const findedUser = users.find( - (u) => u.username === dialog.username - ); - if (findedUser) findedUser.username = newUsername; - return users; - }); - }} - /> - ); - break; - case kChangePassword: - dialogNode = ( - setDialog(null)} - username={dialog.username} - process={async (newPassword) => { - await changePassword(dialog.username, newPassword, token); - }} - /> - ); - break; - case kChangePermission: { - const newPermission = dialog.newPermission; - dialogNode = ( - 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; - } - } - - if (users) { - const userComponents = users.map((user) => { - return ( - { - setDialog( - item === kChangePermission - ? { - type: kChangePermission, - username: user.username, - newPermission: !user.administrator, - } - : { - type: item, - username: user.username, - } - ); - }} - /> - ); - }); - - return ( - <> - - {userComponents} - {dialogNode} - - ); - } else { - return ; - } -}; - -export default UserAdmin; +import React, { useState, useEffect } from "react"; +import { + ListGroupItem, + Row, + Col, + UncontrolledDropdown, + DropdownToggle, + DropdownMenu, + DropdownItem, + Spinner, + Button, +} from "reactstrap"; +import axios from "axios"; + +import OperationDialog from "../common/OperationDialog"; + +import { User, UserWithToken } from "../data/user"; + +const apiBaseUrl = "/api"; + +async function fetchUserList(_token: string): Promise { + const res = await axios.get(`${apiBaseUrl}/users`); + return res.data; +} + +interface CreateUserInfo { + username: string; + password: string; + administrator: boolean; +} + +async function createUser(user: CreateUserInfo, token: string): Promise { + const res = await axios.post( + `${apiBaseUrl}/userop/createuser?token=${token}`, + user + ); + return res.data; +} + +function deleteUser(username: string, token: string): Promise { + return axios.delete(`${apiBaseUrl}/users/${username}?token=${token}`); +} + +function changeUsername( + oldUsername: string, + newUsername: string, + token: string +): Promise { + return axios.patch(`${apiBaseUrl}/users/${oldUsername}?token=${token}`, { + username: newUsername, + }); +} + +function changePassword( + username: string, + newPassword: string, + token: string +): Promise { + return axios.patch(`${apiBaseUrl}/users/${username}?token=${token}`, { + password: newPassword, + }); +} + +function changePermission( + username: string, + newPermission: boolean, + token: string +): Promise { + return axios.patch(`${apiBaseUrl}/users/${username}?token=${token}`, { + administrator: newPermission, + }); +} + +const kChangeUsername = "changeusername"; +const kChangePassword = "changepassword"; +const kChangePermission = "changepermission"; +const kDelete = "delete"; + +type TChangeUsername = typeof kChangeUsername; +type TChangePassword = typeof kChangePassword; +type TChangePermission = typeof kChangePermission; +type TDelete = typeof kDelete; + +type ContextMenuItem = + | TChangeUsername + | TChangePassword + | TChangePermission + | TDelete; + +interface UserCardProps { + onContextMenu: (item: ContextMenuItem) => void; + user: User; +} + +const UserItem: React.FC = (props) => { + const user = props.user; + + const createClickCallback = (item: ContextMenuItem): (() => void) => { + return () => { + props.onContextMenu(item); + }; + }; + + return ( + + + +

{user.username}

+ + {user.administrator ? "administrator" : "user"} + + + + + + Manage + + + + Change Username + + + Change Password + + + Change Permission + + + Delete + + + + +
+
+ ); +}; + +interface DialogProps { + open: boolean; + close: () => void; +} + +interface CreateUserDialogProps extends DialogProps { + process: (user: CreateUserInfo) => Promise; +} + +const CreateUserDialog: React.FC = (props) => { + return ( + + props.process({ + username: username as string, + password: password as string, + administrator: administrator as boolean, + }) + } + close={props.close} + open={props.open} + /> + ); +}; + +const UsernameLabel: React.FC = (props) => { + return {props.children}; +}; + +interface UserDeleteDialogProps extends DialogProps { + username: string; + process: () => Promise; +} + +const UserDeleteDialog: React.FC = (props) => { + return ( + ( + <> + {"You are deleting user "} + {props.username} + {" !"} + + )} + onProcess={props.process} + /> + ); +}; + +interface UserModifyDialogProps extends DialogProps { + username: string; + process: (value: T) => Promise; +} + +const UserChangeUsernameDialog: React.FC> = ( + props +) => { + return ( + ( + <> + {"You are change the username of user "} + {props.username} + {" !"} + + )} + inputScheme={[{ type: "text", label: "New Username" }]} + onProcess={([newUsername]) => { + return props.process(newUsername as string); + }} + /> + ); +}; + +const UserChangePasswordDialog: React.FC> = ( + props +) => { + return ( + ( + <> + {"You are change the password of user "} + {props.username} + {" !"} + + )} + inputScheme={[{ type: "text", label: "New Password" }]} + onProcess={([newPassword]) => { + return props.process(newPassword as string); + }} + /> + ); +}; + +interface UserChangePermissionDialogProps extends DialogProps { + username: string; + newPermission: boolean; + process: () => Promise; +} + +const UserChangePermissionDialog: React.FC = ( + props +) => { + return ( + ( + <> + {"You are change user "} + {props.username} + {" to "} + + {props.newPermission ? "administrator" : "normal user"} + + {" !"} + + )} + onProcess={props.process} + /> + ); +}; + +interface UserAdminProps { + user: UserWithToken; +} + +const UserAdmin: React.FC = (props) => { + type DialogInfo = + | null + | { + type: "create"; + } + | { type: TDelete; username: string } + | { + type: TChangeUsername; + username: string; + } + | { + type: TChangePassword; + username: string; + } + | { + type: TChangePermission; + username: string; + newPermission: boolean; + }; + + const [users, setUsers] = useState(null); + const [dialog, setDialog] = useState(null); + + const token = props.user.token; + + useEffect(() => { + let subscribe = true; + void fetchUserList(props.user.token).then((us) => { + if (subscribe) { + setUsers(us); + } + }); + return () => { + subscribe = false; + }; + }, [props.user]); + + let dialogNode: React.ReactNode; + if (dialog) + switch (dialog.type) { + case "create": + dialogNode = ( + setDialog(null)} + process={async (user) => { + const u = await createUser(user, token); + setUsers((oldUsers) => [...(oldUsers ?? []), u]); + }} + /> + ); + break; + case "delete": + dialogNode = ( + setDialog(null)} + username={dialog.username} + process={async () => { + await deleteUser(dialog.username, token); + setUsers((oldUsers) => + (oldUsers ?? []).filter((u) => u.username !== dialog.username) + ); + }} + /> + ); + break; + case kChangeUsername: + dialogNode = ( + setDialog(null)} + username={dialog.username} + process={async (newUsername) => { + await changeUsername(dialog.username, newUsername, token); + setUsers((oldUsers) => { + const users = (oldUsers ?? []).slice(); + const findedUser = users.find( + (u) => u.username === dialog.username + ); + if (findedUser) findedUser.username = newUsername; + return users; + }); + }} + /> + ); + break; + case kChangePassword: + dialogNode = ( + setDialog(null)} + username={dialog.username} + process={async (newPassword) => { + await changePassword(dialog.username, newPassword, token); + }} + /> + ); + break; + case kChangePermission: { + const newPermission = dialog.newPermission; + dialogNode = ( + 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; + } + } + + if (users) { + const userComponents = users.map((user) => { + return ( + { + setDialog( + item === kChangePermission + ? { + type: kChangePermission, + username: user.username, + newPermission: !user.administrator, + } + : { + type: item, + username: user.username, + } + ); + }} + /> + ); + }); + + return ( + <> + + {userComponents} + {dialogNode} + + ); + } else { + return ; + } +}; + +export default UserAdmin; -- cgit v1.2.3 From 42820d6152131b5e2931bba82ab9e2976e2181f3 Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 24 Aug 2020 23:51:20 +0800 Subject: ... --- Timeline/ClientApp/.eslintignore | 1 - Timeline/ClientApp/.eslintrc.js | 58 ++++++++++++++-------- Timeline/ClientApp/package.json | 2 + Timeline/ClientApp/src/app/App.tsx | 1 - Timeline/ClientApp/src/app/about/About.tsx | 4 +- Timeline/ClientApp/src/app/admin/Admin.tsx | 4 +- Timeline/ClientApp/src/app/admin/UserAdmin.tsx | 1 - Timeline/ClientApp/src/app/common/AlertHost.tsx | 4 +- Timeline/ClientApp/src/app/data/timeline.ts | 18 +++---- Timeline/ClientApp/src/app/data/user.ts | 7 ++- Timeline/ClientApp/src/app/home/BoardWithUser.tsx | 1 - .../ClientApp/src/app/home/BoardWithoutUser.tsx | 1 - Timeline/ClientApp/src/app/home/Home.tsx | 2 +- Timeline/ClientApp/src/app/home/OfflineBoard.tsx | 1 - Timeline/ClientApp/src/app/home/TimelineBoard.tsx | 1 - .../src/app/home/TimelineCreateDialog.tsx | 1 - Timeline/ClientApp/src/app/http/mock/user.ts | 1 - Timeline/ClientApp/src/app/http/timeline.ts | 1 + Timeline/ClientApp/src/app/settings/Settings.tsx | 1 - .../src/app/timeline/TimelineInfoCard.tsx | 2 +- .../ClientApp/src/app/timeline/TimelineItem.tsx | 2 - .../ClientApp/src/app/timeline/TimelineMember.tsx | 1 - .../ClientApp/src/app/timeline/TimelinePage.tsx | 3 +- .../src/app/timeline/TimelinePageTemplate.tsx | 2 +- .../src/app/timeline/TimelinePageTemplateUI.tsx | 3 +- .../src/app/timeline/TimelinePostEdit.tsx | 2 - .../app/timeline/TimelinePropertyChangeDialog.tsx | 1 - Timeline/ClientApp/src/app/user/Login.tsx | 7 ++- Timeline/ClientApp/src/app/user/User.tsx | 4 +- Timeline/ClientApp/src/app/user/UserInfoCard.tsx | 1 - Timeline/ClientApp/src/app/user/UserPage.tsx | 2 +- 31 files changed, 68 insertions(+), 72 deletions(-) (limited to 'Timeline/ClientApp/src/app/admin') diff --git a/Timeline/ClientApp/.eslintignore b/Timeline/ClientApp/.eslintignore index 371b5fcb..de5aa4fc 100644 --- a/Timeline/ClientApp/.eslintignore +++ b/Timeline/ClientApp/.eslintignore @@ -1,5 +1,4 @@ .yarn node_modules dist -webpack.*.js .eslintrc.js diff --git a/Timeline/ClientApp/.eslintrc.js b/Timeline/ClientApp/.eslintrc.js index 2013f23d..830a2aa4 100644 --- a/Timeline/ClientApp/.eslintrc.js +++ b/Timeline/ClientApp/.eslintrc.js @@ -1,48 +1,62 @@ +const path = require("path"); + module.exports = { env: { browser: true, - es6: true, + es2020: true, }, extends: [ - 'eslint:recommended', - 'plugin:react/recommended', - 'plugin:@typescript-eslint/eslint-recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - 'plugin:prettier/recommended', - 'prettier/react', - 'prettier/@typescript-eslint', - 'plugin:react-hooks/recommended', + "eslint:recommended", + "plugin:react/recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "plugin:prettier/recommended", + "prettier/react", + "prettier/@typescript-eslint", + "plugin:react-hooks/recommended", + "plugin:import/recommended", + "plugin:import/typescript", ], globals: { - Atomics: 'readonly', - SharedArrayBuffer: 'readonly', + Atomics: "readonly", + SharedArrayBuffer: "readonly", }, - parser: '@typescript-eslint/parser', + parser: "@typescript-eslint/parser", parserOptions: { - project: ['./src/app/tsconfig.json', './src/sw/tsconfig.json'], + project: ["./src/app/tsconfig.json", "./src/sw/tsconfig.json"], ecmaFeatures: { jsx: true, }, - ecmaVersion: 2018, - sourceType: 'module', + sourceType: "module", }, - plugins: ['react', '@typescript-eslint', 'react-hooks'], + plugins: ["react", "@typescript-eslint", "react-hooks", "import"], settings: { react: { - version: 'detect', + version: "detect", + }, + "import/resolver": { + webpack: { + config: path.resolve(__dirname, "webpack.config.dev.js"), + }, }, }, rules: { - 'react/prop-types': 'off', - '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], - '@typescript-eslint/explicit-function-return-type': [ - 'warn', + "react/prop-types": "off", + "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }], + "@typescript-eslint/explicit-function-return-type": [ + "warn", { allowExpressions: true, allowTypedFunctionExpressions: true, allowHigherOrderFunctions: true, }, ], + "import/order": [ + "warn", + { + "newlines-between": "always", + }, + ], }, }; diff --git a/Timeline/ClientApp/package.json b/Timeline/ClientApp/package.json index a2f6e051..b633630b 100644 --- a/Timeline/ClientApp/package.json +++ b/Timeline/ClientApp/package.json @@ -86,6 +86,8 @@ "css-loader": "^4.2.1", "eslint": "^7.7.0", "eslint-config-prettier": "^6.11.0", + "eslint-import-resolver-webpack": "^0.12.2", + "eslint-plugin-import": "^2.22.0", "eslint-plugin-prettier": "^3.1.4", "eslint-plugin-react": "^7.20.6", "eslint-plugin-react-hooks": "^4.1.0", diff --git a/Timeline/ClientApp/src/app/App.tsx b/Timeline/ClientApp/src/app/App.tsx index 7b382c2f..74deddda 100644 --- a/Timeline/ClientApp/src/app/App.tsx +++ b/Timeline/ClientApp/src/app/App.tsx @@ -11,7 +11,6 @@ import About from "./about/About"; import User from "./user/User"; import TimelinePage from "./timeline/TimelinePage"; import AlertHost from "./common/AlertHost"; - import { dataStorage } from "./data/common"; import { userService, useRawUser } from "./data/user"; diff --git a/Timeline/ClientApp/src/app/about/About.tsx b/Timeline/ClientApp/src/app/about/About.tsx index 751fca14..519eef18 100644 --- a/Timeline/ClientApp/src/app/about/About.tsx +++ b/Timeline/ClientApp/src/app/about/About.tsx @@ -1,11 +1,11 @@ import React from "react"; import { useTranslation, Trans } from "react-i18next"; +import AppBar from "../common/AppBar"; + import authorAvatarUrl from "./author-avatar.png"; import githubLogoUrl from "./github.png"; -import AppBar from "../common/AppBar"; - const frontendCredits: { name: string; url: string; diff --git a/Timeline/ClientApp/src/app/admin/Admin.tsx b/Timeline/ClientApp/src/app/admin/Admin.tsx index 2f8b2c05..e2f71091 100644 --- a/Timeline/ClientApp/src/app/admin/Admin.tsx +++ b/Timeline/ClientApp/src/app/admin/Admin.tsx @@ -10,10 +10,10 @@ import { import classnames from "classnames"; import AppBar from "../common/AppBar"; -import UserAdmin from "./UserAdmin"; - import { UserWithToken } from "../data/user"; +import UserAdmin from "./UserAdmin"; + interface AdminProps { user: UserWithToken; } diff --git a/Timeline/ClientApp/src/app/admin/UserAdmin.tsx b/Timeline/ClientApp/src/app/admin/UserAdmin.tsx index 57eed455..1bf3bda1 100644 --- a/Timeline/ClientApp/src/app/admin/UserAdmin.tsx +++ b/Timeline/ClientApp/src/app/admin/UserAdmin.tsx @@ -13,7 +13,6 @@ import { import axios from "axios"; import OperationDialog from "../common/OperationDialog"; - import { User, UserWithToken } from "../data/user"; const apiBaseUrl = "/api"; diff --git a/Timeline/ClientApp/src/app/common/AlertHost.tsx b/Timeline/ClientApp/src/app/common/AlertHost.tsx index e22354fa..bfcf5c00 100644 --- a/Timeline/ClientApp/src/app/common/AlertHost.tsx +++ b/Timeline/ClientApp/src/app/common/AlertHost.tsx @@ -2,6 +2,7 @@ import React, { useCallback } from "react"; import { Alert } from "reactstrap"; import without from "lodash/without"; import concat from "lodash/concat"; +import { useTranslation } from "react-i18next"; import { alertService, @@ -9,7 +10,6 @@ import { kAlertHostId, AlertInfo, } from "./alert-service"; -import { useTranslation } from "react-i18next"; interface AutoCloseAlertProps { alert: AlertInfo; @@ -56,7 +56,7 @@ interface AlertInfoExEx extends AlertInfoEx { close: () => void; } -export const AlertHost: React.FC = () => { +const AlertHost: React.FC = () => { const [alerts, setAlerts] = React.useState([]); // react guarantee that state setters are stable, so we don't need to add it to dependency list diff --git a/Timeline/ClientApp/src/app/data/timeline.ts b/Timeline/ClientApp/src/app/data/timeline.ts index ed6cffd6..8e8860a3 100644 --- a/Timeline/ClientApp/src/app/data/timeline.ts +++ b/Timeline/ClientApp/src/app/data/timeline.ts @@ -5,16 +5,6 @@ import { map, switchMap, startWith } from "rxjs/operators"; import { uniqBy } from "lodash"; import { convertError } from "../utilities/rxjs"; - -import { dataStorage, throwIfNotNetworkError, BlobOrStatus } from "./common"; -import { DataHub, WithSyncStatus } from "./DataHub"; - -import { UserAuthInfo, checkLogin, userService, userInfoService } from "./user"; - -export { kTimelineVisibilities } from "../http/timeline"; - -export type { TimelineVisibility } from "../http/timeline"; - import { TimelineVisibility, HttpTimelineInfo, @@ -32,6 +22,14 @@ import { import { BlobWithEtag, NotModified, HttpForbiddenError } from "../http/common"; import { HttpUser } from "../http/user"; +import { dataStorage, throwIfNotNetworkError, BlobOrStatus } from "./common"; +import { DataHub, WithSyncStatus } from "./DataHub"; +import { UserAuthInfo, checkLogin, userService, userInfoService } from "./user"; + +export { kTimelineVisibilities } from "../http/timeline"; + +export type { TimelineVisibility } from "../http/timeline"; + export type TimelineInfo = HttpTimelineInfo; export type TimelineChangePropertyRequest = HttpTimelinePatchRequest; export type TimelineCreatePostRequest = HttpTimelinePostPostRequest; diff --git a/Timeline/ClientApp/src/app/data/user.ts b/Timeline/ClientApp/src/app/data/user.ts index 8aee0c5f..ceabdbe2 100644 --- a/Timeline/ClientApp/src/app/data/user.ts +++ b/Timeline/ClientApp/src/app/data/user.ts @@ -5,10 +5,6 @@ import { map, filter } from "rxjs/operators"; import { UiLogicError } from "../common"; import { convertError } from "../utilities/rxjs"; import { pushAlert } from "../common/alert-service"; - -import { dataStorage, throwIfNotNetworkError } from "./common"; -import { DataHub } from "./DataHub"; - import { HttpNetworkError, BlobWithEtag, NotModified } from "../http/common"; import { getHttpTokenClient, @@ -20,6 +16,9 @@ import { HttpUser, } from "../http/user"; +import { DataHub } from "./DataHub"; +import { dataStorage, throwIfNotNetworkError } from "./common"; + export type User = HttpUser; export interface UserAuthInfo { diff --git a/Timeline/ClientApp/src/app/home/BoardWithUser.tsx b/Timeline/ClientApp/src/app/home/BoardWithUser.tsx index 4910aebe..22a4667c 100644 --- a/Timeline/ClientApp/src/app/home/BoardWithUser.tsx +++ b/Timeline/ClientApp/src/app/home/BoardWithUser.tsx @@ -4,7 +4,6 @@ import { useTranslation } from "react-i18next"; import { UserWithToken } from "../data/user"; import { TimelineInfo } from "../data/timeline"; - import { getHttpTimelineClient } from "../http/timeline"; import TimelineBoard from "./TimelineBoard"; diff --git a/Timeline/ClientApp/src/app/home/BoardWithoutUser.tsx b/Timeline/ClientApp/src/app/home/BoardWithoutUser.tsx index a7dc36be..972c1b25 100644 --- a/Timeline/ClientApp/src/app/home/BoardWithoutUser.tsx +++ b/Timeline/ClientApp/src/app/home/BoardWithoutUser.tsx @@ -2,7 +2,6 @@ import React from "react"; import { Row, Col } from "reactstrap"; import { TimelineInfo } from "../data/timeline"; - import { getHttpTimelineClient } from "../http/timeline"; import TimelineBoard from "./TimelineBoard"; diff --git a/Timeline/ClientApp/src/app/home/Home.tsx b/Timeline/ClientApp/src/app/home/Home.tsx index 00e6ff5a..910c9a01 100644 --- a/Timeline/ClientApp/src/app/home/Home.tsx +++ b/Timeline/ClientApp/src/app/home/Home.tsx @@ -4,9 +4,9 @@ import { Row, Container, Button, Col } from "reactstrap"; import { useTranslation } from "react-i18next"; import { useUser } from "../data/user"; - import AppBar from "../common/AppBar"; import SearchInput from "../common/SearchInput"; + import BoardWithoutUser from "./BoardWithoutUser"; import BoardWithUser from "./BoardWithUser"; import TimelineCreateDialog from "./TimelineCreateDialog"; diff --git a/Timeline/ClientApp/src/app/home/OfflineBoard.tsx b/Timeline/ClientApp/src/app/home/OfflineBoard.tsx index 458166ac..fbd37efd 100644 --- a/Timeline/ClientApp/src/app/home/OfflineBoard.tsx +++ b/Timeline/ClientApp/src/app/home/OfflineBoard.tsx @@ -3,7 +3,6 @@ import { Link } from "react-router-dom"; import { Trans } from "react-i18next"; import { getAllCachedTimelineNames } from "../data/timeline"; - import UserTimelineLogo from "../common/UserTimelineLogo"; import TimelineLogo from "../common/TimelineLogo"; diff --git a/Timeline/ClientApp/src/app/home/TimelineBoard.tsx b/Timeline/ClientApp/src/app/home/TimelineBoard.tsx index 91bf2b77..21dcac3f 100644 --- a/Timeline/ClientApp/src/app/home/TimelineBoard.tsx +++ b/Timeline/ClientApp/src/app/home/TimelineBoard.tsx @@ -5,7 +5,6 @@ import { Spinner } from "reactstrap"; import { Trans } from "react-i18next"; import { TimelineInfo } from "../data/timeline"; - import TimelineLogo from "../common/TimelineLogo"; import UserTimelineLogo from "../common/UserTimelineLogo"; diff --git a/Timeline/ClientApp/src/app/home/TimelineCreateDialog.tsx b/Timeline/ClientApp/src/app/home/TimelineCreateDialog.tsx index c5ba64e7..911dd60c 100644 --- a/Timeline/ClientApp/src/app/home/TimelineCreateDialog.tsx +++ b/Timeline/ClientApp/src/app/home/TimelineCreateDialog.tsx @@ -2,7 +2,6 @@ import React from "react"; import { useHistory } from "react-router"; import { validateTimelineName, timelineService } from "../data/timeline"; - import OperationDialog from "../common/OperationDialog"; interface TimelineCreateDialogProps { diff --git a/Timeline/ClientApp/src/app/http/mock/user.ts b/Timeline/ClientApp/src/app/http/mock/user.ts index 1ecd7365..7948da11 100644 --- a/Timeline/ClientApp/src/app/http/mock/user.ts +++ b/Timeline/ClientApp/src/app/http/mock/user.ts @@ -10,7 +10,6 @@ import { } from "../user"; import { mockStorage, sha1, mockPrepare } from "./common"; - import defaultAvatarUrl from "./default-avatar.png"; let _defaultAvatar: BlobWithEtag | undefined = undefined; diff --git a/Timeline/ClientApp/src/app/http/timeline.ts b/Timeline/ClientApp/src/app/http/timeline.ts index 4a325bca..a9511c64 100644 --- a/Timeline/ClientApp/src/app/http/timeline.ts +++ b/Timeline/ClientApp/src/app/http/timeline.ts @@ -1,6 +1,7 @@ import axios, { AxiosError } from "axios"; import { updateQueryString, applyQueryParameters } from "../utilities/url"; + import { apiBaseUrl, extractResponseData, diff --git a/Timeline/ClientApp/src/app/settings/Settings.tsx b/Timeline/ClientApp/src/app/settings/Settings.tsx index dd648538..64851ce2 100644 --- a/Timeline/ClientApp/src/app/settings/Settings.tsx +++ b/Timeline/ClientApp/src/app/settings/Settings.tsx @@ -14,7 +14,6 @@ import { } from "reactstrap"; import { useUser, userService } from "../data/user"; - import AppBar from "../common/AppBar"; import OperationDialog, { OperationInputErrorInfo, diff --git a/Timeline/ClientApp/src/app/timeline/TimelineInfoCard.tsx b/Timeline/ClientApp/src/app/timeline/TimelineInfoCard.tsx index 3591b6f9..c11c3376 100644 --- a/Timeline/ClientApp/src/app/timeline/TimelineInfoCard.tsx +++ b/Timeline/ClientApp/src/app/timeline/TimelineInfoCard.tsx @@ -12,9 +12,9 @@ import { fromEvent } from "rxjs"; import { useAvatar } from "../data/user"; import { timelineVisibilityTooltipTranslationMap } from "../data/timeline"; +import BlobImage from "../common/BlobImage"; import { TimelineCardComponentProps } from "./TimelinePageTemplateUI"; -import BlobImage from "../common/BlobImage"; export type OrdinaryTimelineManageItem = "delete"; diff --git a/Timeline/ClientApp/src/app/timeline/TimelineItem.tsx b/Timeline/ClientApp/src/app/timeline/TimelineItem.tsx index 0d62b0e7..33f0741e 100644 --- a/Timeline/ClientApp/src/app/timeline/TimelineItem.tsx +++ b/Timeline/ClientApp/src/app/timeline/TimelineItem.tsx @@ -12,12 +12,10 @@ import { import { Link } from "react-router-dom"; import { useTranslation } from "react-i18next"; import Svg from "react-inlinesvg"; - import chevronDownIcon from "bootstrap-icons/icons/chevron-down.svg"; import trashIcon from "bootstrap-icons/icons/trash.svg"; import BlobImage from "../common/BlobImage"; - import { useAvatar } from "../data/user"; import { TimelinePostInfo } from "../data/timeline"; diff --git a/Timeline/ClientApp/src/app/timeline/TimelineMember.tsx b/Timeline/ClientApp/src/app/timeline/TimelineMember.tsx index 559750d2..f334c6e9 100644 --- a/Timeline/ClientApp/src/app/timeline/TimelineMember.tsx +++ b/Timeline/ClientApp/src/app/timeline/TimelineMember.tsx @@ -11,7 +11,6 @@ import { } from "reactstrap"; import { User, useAvatar } from "../data/user"; - import SearchInput from "../common/SearchInput"; import BlobImage from "../common/BlobImage"; diff --git a/Timeline/ClientApp/src/app/timeline/TimelinePage.tsx b/Timeline/ClientApp/src/app/timeline/TimelinePage.tsx index 0771b40e..21d52db1 100644 --- a/Timeline/ClientApp/src/app/timeline/TimelinePage.tsx +++ b/Timeline/ClientApp/src/app/timeline/TimelinePage.tsx @@ -1,8 +1,9 @@ import React from "react"; import { useParams } from "react-router"; -import TimelinePageUI from "./TimelinePageUI"; import TimelinePageTemplate from "../timeline/TimelinePageTemplate"; + +import TimelinePageUI from "./TimelinePageUI"; import { OrdinaryTimelineManageItem } from "./TimelineInfoCard"; import TimelineDeleteDialog from "./TimelineDeleteDialog"; diff --git a/Timeline/ClientApp/src/app/timeline/TimelinePageTemplate.tsx b/Timeline/ClientApp/src/app/timeline/TimelinePageTemplate.tsx index be96a09e..3f470826 100644 --- a/Timeline/ClientApp/src/app/timeline/TimelinePageTemplate.tsx +++ b/Timeline/ClientApp/src/app/timeline/TimelinePageTemplate.tsx @@ -11,13 +11,13 @@ import { usePostList, useTimelineInfo, } from "../data/timeline"; +import { UiLogicError } from "../common"; import { TimelineDeleteCallback } from "./Timeline"; import { TimelineMemberDialog } from "./TimelineMember"; import TimelinePropertyChangeDialog from "./TimelinePropertyChangeDialog"; import { TimelinePageTemplateUIProps } from "./TimelinePageTemplateUI"; import { TimelinePostSendCallback } from "./TimelinePostEdit"; -import { UiLogicError } from "../common"; export interface TimelinePageTemplateProps { name: string; diff --git a/Timeline/ClientApp/src/app/timeline/TimelinePageTemplateUI.tsx b/Timeline/ClientApp/src/app/timeline/TimelinePageTemplateUI.tsx index 2066ceb1..e6514478 100644 --- a/Timeline/ClientApp/src/app/timeline/TimelinePageTemplateUI.tsx +++ b/Timeline/ClientApp/src/app/timeline/TimelinePageTemplateUI.tsx @@ -4,7 +4,6 @@ import { useTranslation } from "react-i18next"; import { fromEvent } from "rxjs"; import Svg from "react-inlinesvg"; import clsx from "clsx"; - import arrowsAngleContractIcon from "bootstrap-icons/icons/arrows-angle-contract.svg"; import arrowsAngleExpandIcon from "bootstrap-icons/icons/arrows-angle-expand.svg"; @@ -16,12 +15,12 @@ import { timelineService, } from "../data/timeline"; import { userService } from "../data/user"; +import AppBar from "../common/AppBar"; import Timeline, { TimelinePostInfoEx, TimelineDeleteCallback, } from "./Timeline"; -import AppBar from "../common/AppBar"; import TimelinePostEdit, { TimelinePostSendCallback } from "./TimelinePostEdit"; type TimelinePostSyncState = "syncing" | "synced" | "offline"; diff --git a/Timeline/ClientApp/src/app/timeline/TimelinePostEdit.tsx b/Timeline/ClientApp/src/app/timeline/TimelinePostEdit.tsx index 151df40a..b30dc8d3 100644 --- a/Timeline/ClientApp/src/app/timeline/TimelinePostEdit.tsx +++ b/Timeline/ClientApp/src/app/timeline/TimelinePostEdit.tsx @@ -2,13 +2,11 @@ import React from "react"; import { Button, Spinner, Row, Col } from "reactstrap"; import { useTranslation } from "react-i18next"; import Svg from "react-inlinesvg"; - import textIcon from "bootstrap-icons/icons/card-text.svg"; import imageIcon from "bootstrap-icons/icons/image.svg"; import { pushAlert } from "../common/alert-service"; import { TimelineCreatePostRequest } from "../data/timeline"; - import FileInput from "../common/FileInput"; import { UiLogicError } from "../common"; diff --git a/Timeline/ClientApp/src/app/timeline/TimelinePropertyChangeDialog.tsx b/Timeline/ClientApp/src/app/timeline/TimelinePropertyChangeDialog.tsx index a0eea775..bb0e3ea2 100644 --- a/Timeline/ClientApp/src/app/timeline/TimelinePropertyChangeDialog.tsx +++ b/Timeline/ClientApp/src/app/timeline/TimelinePropertyChangeDialog.tsx @@ -5,7 +5,6 @@ import { kTimelineVisibilities, TimelineChangePropertyRequest, } from "../data/timeline"; - import OperationDialog, { OperationSelectInputInfoOption, } from "../common/OperationDialog"; diff --git a/Timeline/ClientApp/src/app/user/Login.tsx b/Timeline/ClientApp/src/app/user/Login.tsx index 4f9cd05d..db6c43c4 100644 --- a/Timeline/ClientApp/src/app/user/Login.tsx +++ b/Timeline/ClientApp/src/app/user/Login.tsx @@ -1,10 +1,6 @@ import React, { Fragment, useState, useEffect } from "react"; import { useHistory } from "react-router"; import { useTranslation } from "react-i18next"; - -import AppBar from "../common/AppBar"; - -import { useUser, userService } from "../data/user"; import { Label, FormGroup, @@ -15,6 +11,9 @@ import { Button, } from "reactstrap"; +import AppBar from "../common/AppBar"; +import { useUser, userService } from "../data/user"; + const Login: React.FC = (_) => { const { t } = useTranslation(); const history = useHistory(); diff --git a/Timeline/ClientApp/src/app/user/User.tsx b/Timeline/ClientApp/src/app/user/User.tsx index 6f61cacf..56058ce7 100644 --- a/Timeline/ClientApp/src/app/user/User.tsx +++ b/Timeline/ClientApp/src/app/user/User.tsx @@ -3,12 +3,12 @@ import { useParams } from "react-router"; import { UiLogicError } from "../common"; import { useUser, userInfoService } from "../data/user"; -import { changeNickname } from "./api"; +import TimelinePageTemplate from "../timeline/TimelinePageTemplate"; +import { changeNickname } from "./api"; import UserPage from "./UserPage"; import ChangeNicknameDialog from "./ChangeNicknameDialog"; import ChangeAvatarDialog from "./ChangeAvatarDialog"; -import TimelinePageTemplate from "../timeline/TimelinePageTemplate"; import { PersonalTimelineManageItem } from "./UserInfoCard"; const User: React.FC = (_) => { diff --git a/Timeline/ClientApp/src/app/user/UserInfoCard.tsx b/Timeline/ClientApp/src/app/user/UserInfoCard.tsx index 9ce46e3c..d6e648cc 100644 --- a/Timeline/ClientApp/src/app/user/UserInfoCard.tsx +++ b/Timeline/ClientApp/src/app/user/UserInfoCard.tsx @@ -12,7 +12,6 @@ import { fromEvent } from "rxjs"; import { timelineVisibilityTooltipTranslationMap } from "../data/timeline"; import { useAvatar } from "../data/user"; - import { TimelineCardComponentProps } from "../timeline/TimelinePageTemplateUI"; import BlobImage from "../common/BlobImage"; diff --git a/Timeline/ClientApp/src/app/user/UserPage.tsx b/Timeline/ClientApp/src/app/user/UserPage.tsx index 42f174d9..ab498f30 100644 --- a/Timeline/ClientApp/src/app/user/UserPage.tsx +++ b/Timeline/ClientApp/src/app/user/UserPage.tsx @@ -1,10 +1,10 @@ import React from "react"; import { ExcludeKey } from "../utilities/type"; - import TimelinePageTemplateUI, { TimelinePageTemplateUIProps, } from "../timeline/TimelinePageTemplateUI"; + import UserInfoCard, { PersonalTimelineManageItem } from "./UserInfoCard"; export type UserPageProps = ExcludeKey< -- cgit v1.2.3