diff --git a/.eslintrc.yaml b/.eslintrc.yaml index fd02379..929e72e 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -1,10 +1,12 @@ extends: - eslint:recommended - plugin:react/recommended + - plugin:@typescript-eslint/recommended +parser: '@typescript-eslint/parser' plugins: - react - react-hooks -parser: babel-eslint + - '@typescript-eslint' parserOptions: sourceType: module ecmaVersion: 2020 @@ -25,4 +27,10 @@ rules: react/prop-types: 0 react-hooks/rules-of-hooks: "error" # TODO: 修改添加deps后出现的死循环 - react-hooks/exhaustive-deps: 0 \ No newline at end of file + react-hooks/exhaustive-deps: 0 + '@typescript-eslint/explicit-function-return-type': 0 + +overrides: + - files: ['*.js', '*.jsx'] + rules: + '@typescript-eslint/camelcase': 0 diff --git a/package.json b/package.json index a2321bb..ca15a04 100644 --- a/package.json +++ b/package.json @@ -9,9 +9,12 @@ "@material-ui/lab": "^4.0.0-alpha.42", "@svgr/webpack": "4.3.2", "@types/invariant": "^2.2.32", - "@types/react-dom": "^16.9.7", - "@typescript-eslint/eslint-plugin": "^2.2.0", - "@typescript-eslint/parser": "^2.2.0", + "@types/jest": "^25.2.2", + "@types/node": "^14.0.1", + "@types/react": "^16.9.35", + "@types/react-dom": "^16.9.8", + "@typescript-eslint/eslint-plugin": "^2.33.0", + "@typescript-eslint/parser": "^2.33.0", "axios": "^0.19.0", "babel-eslint": "10.0.3", "babel-jest": "^24.9.0", @@ -87,7 +90,7 @@ "terser-webpack-plugin": "1.4.1", "timeago-react": "^3.0.0", "ts-pnp": "1.1.4", - "typescript": "^3.8.3", + "typescript": "^3.9.2", "url-loader": "2.1.0", "webpack": "4.41.0", "webpack-dev-server": "3.2.1", @@ -98,7 +101,7 @@ "start": "node scripts/start.js", "build": "node scripts/build.js", "test": "node scripts/test.js", - "eslint": "eslint src/** --fix", + "eslint": "eslint src --fix", "postinstall": "node node_modules/husky/lib/installer/bin install" }, "browserslist": { @@ -174,5 +177,8 @@ "hooks": { "pre-commit": "yarn run eslint" } + }, + "resolutions": { + "@types/react": "^16.9.35" } } diff --git a/src/Admin.js b/src/Admin.js index 7942488..ebb5c47 100644 --- a/src/Admin.js +++ b/src/Admin.js @@ -59,7 +59,7 @@ export default function Admin() { const [show, setShow] = useState(false); useEffect(() => { - let user = Auth.GetUser(); + const user = Auth.GetUser(); if (user && user.group) { if (user.group.id !== 1) { history.push("/home"); diff --git a/src/App.js b/src/App.js index 3a5f5b0..1485aef 100644 --- a/src/App.js +++ b/src/App.js @@ -40,11 +40,11 @@ export default function App() { const theme = React.useMemo(() => { themeConfig.palette.type = prefersDarkMode ? "dark" : "light"; - let prefer = Auth.GetPreference("theme_mode"); + const prefer = Auth.GetPreference("theme_mode"); if (prefer) { themeConfig.palette.type = prefer; } - let theme = createMuiTheme({ + const theme = createMuiTheme({ ...themeConfig, palette: { ...themeConfig.palette, @@ -79,7 +79,7 @@ export default function App() { const classes = useStyles(); - let { path } = useRouteMatch(); + const { path } = useRouteMatch(); return ( diff --git a/src/actions/index.js b/src/actions/index.js index 12e9b7d..7435295 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -1,14 +1,18 @@ export * from './explorer' +export const setNavigator = (path, navigatorLoading) => { + return { + type: 'SET_NAVIGATOR', + path, + navigatorLoading + } +} + export const navigateTo = path => { return (dispatch, getState) => { const state = getState() const navigatorLoading = path !== state.navigator.path - return dispatch({ - type: "NAVIGATOR_TO", - path: path, - navigatorLoading, - }) + dispatch(setNavigator(path, navigatorLoading)) } }; @@ -19,11 +23,7 @@ export const navigateUp = () => { pathSplit.pop(); const newPath = pathSplit.length===1? "/":pathSplit.join("/"); const navigatorLoading = newPath !== state.navigator.path - return dispatch({ - type: "NAVIGATOR_UP", - path: newPath, - navigatorLoading - }) + dispatch(setNavigator(newPath, navigatorLoading)) } }; @@ -55,20 +55,6 @@ export const toggleDaylightMode = ()=>{ }; }; -export const changeSortMethod = method => { - return { - type: "CHANGE_SORT_METHOD", - method: method - }; -}; - -export const updateFileList = list => { - return { - type: "UPDATE_FILE_LIST", - list: list - }; -}; - export const changeContextMenu = (type, open) => { return { type: "CHANGE_CONTEXT_MENU", diff --git a/src/component/Admin/Common/SizeInput.js b/src/component/Admin/Common/SizeInput.js index 8ec578e..665d822 100644 --- a/src/component/Admin/Common/SizeInput.js +++ b/src/component/Admin/Common/SizeInput.js @@ -34,10 +34,10 @@ export default function SizeInput({onChange,min,value,required,label,max,suffix} const [unit,setUnit] = useState(1); - let first = useRef(true); + const first = useRef(true); const transform = useCallback(()=>{ - let res = unitTransform(value); + const res = unitTransform(value); if(first && value !== 0){ setUnit(res[1]); first.current = false; diff --git a/src/component/Admin/Dashboard.js b/src/component/Admin/Dashboard.js index 3dc0a1a..687f6cc 100644 --- a/src/component/Admin/Dashboard.js +++ b/src/component/Admin/Dashboard.js @@ -278,7 +278,7 @@ export default function Dashboard({ content }) { }; }, []); - let { path } = useRouteMatch(); + const { path } = useRouteMatch(); return (
diff --git a/src/component/Admin/Dialogs/AddGroupk.js b/src/component/Admin/Dialogs/AddGroupk.js index fb0c2d4..48aba1d 100644 --- a/src/component/Admin/Dialogs/AddGroupk.js +++ b/src/component/Admin/Dialogs/AddGroupk.js @@ -41,6 +41,7 @@ export default function AddGroup({ open, onClose, onSubmit }) { .then(response => { setGroups(response.data); }) + // eslint-disable-next-line @typescript-eslint/no-empty-function .catch(() => {}); } // eslint-disable-next-line @@ -62,7 +63,7 @@ export default function AddGroup({ open, onClose, onSubmit }) { const submit = e => { e.preventDefault(); - let groupCopy = {...group}; + const groupCopy = {...group}; groupCopy.time = parseInt(groupCopy.time) * 86400; groupCopy.price = parseInt(groupCopy.price) * 100; groupCopy.score = parseInt(groupCopy.score); diff --git a/src/component/Admin/Dialogs/AddPack.js b/src/component/Admin/Dialogs/AddPack.js index 0217158..40cda88 100644 --- a/src/component/Admin/Dialogs/AddPack.js +++ b/src/component/Admin/Dialogs/AddPack.js @@ -38,7 +38,7 @@ export default function AddPack({ open, onClose,onSubmit }) { const submit = e => { e.preventDefault(); - let packCopy = {...pack}; + const packCopy = {...pack}; packCopy.size = parseInt(packCopy.size); packCopy.time = parseInt(packCopy.time) * 86400; packCopy.price = parseInt(packCopy.price) * 100; diff --git a/src/component/Admin/Dialogs/FileFilter.js b/src/component/Admin/Dialogs/FileFilter.js index eb53dbb..224dc78 100644 --- a/src/component/Admin/Dialogs/FileFilter.js +++ b/src/component/Admin/Dialogs/FileFilter.js @@ -48,7 +48,7 @@ export default function FileFilter({setFilter,setSearch,open, onClose }) { },[]) const submit = () => { - let res = {}; + const res = {}; Object.keys(input).forEach(v=>{ if(input[v] !== "all" && input[v] !== ""){ res[v] = input[v]; diff --git a/src/component/Admin/Dialogs/ShareFilter.js b/src/component/Admin/Dialogs/ShareFilter.js index c8d3ba1..7a118a7 100644 --- a/src/component/Admin/Dialogs/ShareFilter.js +++ b/src/component/Admin/Dialogs/ShareFilter.js @@ -22,7 +22,7 @@ export default function ShareFilter({setFilter,setSearch,open, onClose }) { } const submit = () => { - let res = {}; + const res = {}; Object.keys(input).forEach(v=>{ if(input[v] !== "all" && input[v] !== ""){ res[v] = input[v]; diff --git a/src/component/Admin/Dialogs/UserFilter.js b/src/component/Admin/Dialogs/UserFilter.js index 0fc2252..2b548c0 100644 --- a/src/component/Admin/Dialogs/UserFilter.js +++ b/src/component/Admin/Dialogs/UserFilter.js @@ -43,7 +43,7 @@ export default function UserFilter({setFilter,setSearch,open, onClose }) { },[]) const submit = () => { - let res = {}; + const res = {}; Object.keys(input).forEach(v=>{ if(input[v] !== "all"){ res[v] = input[v]; diff --git a/src/component/Admin/File/File.js b/src/component/Admin/File/File.js index a9e8c84..903c0c0 100644 --- a/src/component/Admin/File/File.js +++ b/src/component/Admin/File/File.js @@ -85,7 +85,7 @@ export default function File() { const [selected, setSelected] = useState([]); const [loading,setLoading] = useState(false); - let history = useHistory(); + const history = useHistory(); const dispatch = useDispatch(); const ToggleSnackbar = useCallback( (vertical, horizontal, msg, color) => diff --git a/src/component/Admin/File/Import.js b/src/component/Admin/File/Import.js index 7e7cded..78e44d5 100644 --- a/src/component/Admin/File/Import.js +++ b/src/component/Admin/File/Import.js @@ -94,7 +94,7 @@ export default function Import() { }); }; - let history = useHistory(); + const history = useHistory(); const dispatch = useDispatch(); const ToggleSnackbar = useCallback( (vertical, horizontal, msg, color) => @@ -162,7 +162,7 @@ export default function Import() { conditions: {} }) .then(response => { - let res = {}; + const res = {}; response.data.items.forEach(v => { res[v.ID] = v; }); @@ -183,7 +183,7 @@ export default function Import() { }; const setMoveTarget = setter => folder => { - let path = + const path = folder.path === "/" ? folder.path + folder.name : folder.path + "/" + folder.name; diff --git a/src/component/Admin/Group/EditGroup.js b/src/component/Admin/Group/EditGroup.js index 3721046..4a3d7d9 100644 --- a/src/component/Admin/Group/EditGroup.js +++ b/src/component/Admin/Group/EditGroup.js @@ -8,7 +8,7 @@ import GroupForm from "./GroupForm"; export default function EditGroupPreload( ) { const [group,setGroup] = useState({}); - let {id } = useParams(); + const {id } = useParams(); const dispatch = useDispatch(); const ToggleSnackbar = useCallback( diff --git a/src/component/Admin/Group/Group.js b/src/component/Admin/Group/Group.js index 0f99407..27447b1 100644 --- a/src/component/Admin/Group/Group.js +++ b/src/component/Admin/Group/Group.js @@ -79,9 +79,9 @@ export default function Group() { const [total, setTotal] = useState(0); const [policies, setPolicies] = React.useState({}); - let location = useLocation(); - let history = useHistory(); - let query = useQuery(); + const location = useLocation(); + const history = useHistory(); + const query = useQuery(); const dispatch = useDispatch(); const ToggleSnackbar = useCallback( diff --git a/src/component/Admin/Group/GroupForm.js b/src/component/Admin/Group/GroupForm.js index 6bc8dde..3492edc 100644 --- a/src/component/Admin/Group/GroupForm.js +++ b/src/component/Admin/Group/GroupForm.js @@ -70,7 +70,7 @@ export default function GroupForm(props) { ); const [policies, setPolicies] = useState({}); - let history = useHistory(); + const history = useHistory(); const dispatch = useDispatch(); const ToggleSnackbar = useCallback( @@ -87,7 +87,7 @@ export default function GroupForm(props) { conditions: {} }) .then(response => { - let res = {}; + const res = {}; response.data.items.forEach(v => { res[v.ID] = v.Name; }); @@ -106,7 +106,7 @@ export default function GroupForm(props) { }; const handleCheckChange = name => event => { - let value = event.target.checked ? "true" : "false"; + const value = event.target.checked ? "true" : "false"; setGroup({ ...group, [name]: value @@ -114,7 +114,7 @@ export default function GroupForm(props) { }; const handleOptionCheckChange = name => event => { - let value = event.target.checked ? "true" : "false"; + const value = event.target.checked ? "true" : "false"; setGroup({ ...group, OptionsSerialized: { @@ -136,7 +136,7 @@ export default function GroupForm(props) { const submit = e => { e.preventDefault(); - let groupCopy = { + const groupCopy = { ...group, OptionsSerialized: { ...group.OptionsSerialized } }; diff --git a/src/component/Admin/Index.js b/src/component/Admin/Index.js index a814fca..c6d2dec 100644 --- a/src/component/Admin/Index.js +++ b/src/component/Admin/Index.js @@ -118,7 +118,7 @@ export default function Index() { useEffect(() => { API.get("/admin/summary") .then(response => { - let data = []; + const data = []; response.data.date.forEach((v, k) => { data.push({ name: v, @@ -148,7 +148,7 @@ export default function Index() { .get("/api/v3/admin/news") .then(response => { setNews(response.data.data); - let res = {}; + const res = {}; response.data.included.forEach(v => { if (v.type === "users") { res[v.id] = v.attributes; diff --git a/src/component/Admin/Policy/AddPolicy.js b/src/component/Admin/Policy/AddPolicy.js index 9730451..021df31 100644 --- a/src/component/Admin/Policy/AddPolicy.js +++ b/src/component/Admin/Policy/AddPolicy.js @@ -26,7 +26,7 @@ const useStyles = makeStyles(theme => ({ export default function AddPolicyParent( ) { const classes = useStyles(); - let { type } = useParams(); + const { type } = useParams(); return (
diff --git a/src/component/Admin/Policy/EditPolicy.js b/src/component/Admin/Policy/EditPolicy.js index 3877132..11548e6 100644 --- a/src/component/Admin/Policy/EditPolicy.js +++ b/src/component/Admin/Policy/EditPolicy.js @@ -32,7 +32,7 @@ export default function EditPolicyPreload( ) { const [type,setType] = useState(""); const [policy,setPolicy] = useState({}); - let { mode,id } = useParams(); + const { mode,id } = useParams(); const dispatch = useDispatch(); const ToggleSnackbar = useCallback( diff --git a/src/component/Admin/Policy/Guid/COSGuide.js b/src/component/Admin/Policy/Guid/COSGuide.js index 4e1ae71..8ad0934 100644 --- a/src/component/Admin/Policy/Guid/COSGuide.js +++ b/src/component/Admin/Policy/Guid/COSGuide.js @@ -171,7 +171,7 @@ export default function COSGuide(props) { e.preventDefault(); setLoading(true); - let policyCopy = { ...policy }; + const policyCopy = { ...policy }; policyCopy.OptionsSerialized = { ...policyCopy.OptionsSerialized }; if (useCDN === "false"){ diff --git a/src/component/Admin/Policy/Guid/EditPro.js b/src/component/Admin/Policy/Guid/EditPro.js index 732c76c..b04f2d1 100644 --- a/src/component/Admin/Policy/Guid/EditPro.js +++ b/src/component/Admin/Policy/Guid/EditPro.js @@ -93,7 +93,7 @@ export default function EditPro(props) { e.preventDefault(); setLoading(true); - let policyCopy = { ...policy }; + const policyCopy = { ...policy }; policyCopy.OptionsSerialized = { ...policyCopy.OptionsSerialized }; // 类型转换 diff --git a/src/component/Admin/Policy/Guid/LocalGuide.js b/src/component/Admin/Policy/Guid/LocalGuide.js index 4ce2ee6..0b5307d 100644 --- a/src/component/Admin/Policy/Guid/LocalGuide.js +++ b/src/component/Admin/Policy/Guid/LocalGuide.js @@ -163,7 +163,7 @@ export default function LocalGuide(props) { e.preventDefault(); setLoading(true); - let policyCopy = { ...policy }; + const policyCopy = { ...policy }; policyCopy.OptionsSerialized = { ...policyCopy.OptionsSerialized }; // 处理存储策略 diff --git a/src/component/Admin/Policy/Guid/OSSGuide.js b/src/component/Admin/Policy/Guid/OSSGuide.js index abf3cb8..864f99d 100644 --- a/src/component/Admin/Policy/Guid/OSSGuide.js +++ b/src/component/Admin/Policy/Guid/OSSGuide.js @@ -164,7 +164,7 @@ export default function OSSGuide(props) { e.preventDefault(); setLoading(true); - let policyCopy = { ...policy }; + const policyCopy = { ...policy }; policyCopy.OptionsSerialized = { ...policyCopy.OptionsSerialized }; if (useCDN === "false"){ diff --git a/src/component/Admin/Policy/Guid/OneDriveGuide.js b/src/component/Admin/Policy/Guid/OneDriveGuide.js index 231cc31..d40a45c 100644 --- a/src/component/Admin/Policy/Guid/OneDriveGuide.js +++ b/src/component/Admin/Policy/Guid/OneDriveGuide.js @@ -198,7 +198,7 @@ export default function OneDriveGuide(props) { e.preventDefault(); setLoading(true); - let policyCopy = { ...policy }; + const policyCopy = { ...policy }; policyCopy.OptionsSerialized = { ...policyCopy.OptionsSerialized }; // baseURL处理 diff --git a/src/component/Admin/Policy/Guid/QiniuGuide.js b/src/component/Admin/Policy/Guid/QiniuGuide.js index 0e591af..2b1d8f8 100644 --- a/src/component/Admin/Policy/Guid/QiniuGuide.js +++ b/src/component/Admin/Policy/Guid/QiniuGuide.js @@ -148,7 +148,7 @@ export default function RemoteGuide(props) { e.preventDefault(); setLoading(true); - let policyCopy = { ...policy }; + const policyCopy = { ...policy }; policyCopy.OptionsSerialized = { ...policyCopy.OptionsSerialized }; // 类型转换 diff --git a/src/component/Admin/Policy/Guid/RemoteGuide.js b/src/component/Admin/Policy/Guid/RemoteGuide.js index ac729fd..37a59e8 100644 --- a/src/component/Admin/Policy/Guid/RemoteGuide.js +++ b/src/component/Admin/Policy/Guid/RemoteGuide.js @@ -188,7 +188,7 @@ export default function RemoteGuide(props) { e.preventDefault(); setLoading(true); - let policyCopy = {...policy}; + const policyCopy = {...policy}; policyCopy.OptionsSerialized = {...policyCopy.OptionsSerialized}; // 处理存储策略 diff --git a/src/component/Admin/Policy/Guid/UpyunGuide.js b/src/component/Admin/Policy/Guid/UpyunGuide.js index 85eb41d..fdb8305 100644 --- a/src/component/Admin/Policy/Guid/UpyunGuide.js +++ b/src/component/Admin/Policy/Guid/UpyunGuide.js @@ -146,7 +146,7 @@ export default function UpyunGuide(props) { e.preventDefault(); setLoading(true); - let policyCopy = { ...policy }; + const policyCopy = { ...policy }; policyCopy.OptionsSerialized = { ...policyCopy.OptionsSerialized }; // 类型转换 diff --git a/src/component/Admin/Policy/Policy.js b/src/component/Admin/Policy/Policy.js index 30ff706..bffd98f 100644 --- a/src/component/Admin/Policy/Policy.js +++ b/src/component/Admin/Policy/Policy.js @@ -89,9 +89,9 @@ export default function Policy() { const [anchorEl, setAnchorEl] = React.useState(null); const [editID, setEditID] = React.useState(0); - let location = useLocation(); - let history = useHistory(); - let query = useQuery(); + const location = useLocation(); + const history = useHistory(); + const query = useQuery(); const handleClick = event => { setAnchorEl(event.currentTarget); diff --git a/src/component/Admin/Setting/Access.js b/src/component/Admin/Setting/Access.js index bebfa68..ef1153c 100644 --- a/src/component/Admin/Setting/Access.js +++ b/src/component/Admin/Setting/Access.js @@ -66,7 +66,7 @@ export default function Access() { }; const handleInputChange = name => event => { - let value = event.target.value; + const value = event.target.value; setOptions({ ...options, [name]: value @@ -106,7 +106,7 @@ export default function Access() { const submit = e => { e.preventDefault(); setLoading(true); - let option = []; + const option = []; Object.keys(options).forEach(k => { option.push({ key: k, diff --git a/src/component/Admin/Setting/Aria2.js b/src/component/Admin/Setting/Aria2.js index 3d09f53..ce30bfd 100644 --- a/src/component/Admin/Setting/Aria2.js +++ b/src/component/Admin/Setting/Aria2.js @@ -72,10 +72,12 @@ export default function Aria2() { const reload = () => { API.get("/admin/reload/aria2") + // eslint-disable-next-line @typescript-eslint/no-empty-function .then(() => {}) .catch(error => { ToggleSnackbar("top", "right", error.message, "error"); }) + // eslint-disable-next-line @typescript-eslint/no-empty-function .then(() => {}); }; @@ -98,7 +100,7 @@ export default function Aria2() { const submit = e => { e.preventDefault(); setLoading(true); - let option = []; + const option = []; Object.keys(options).forEach(k=>{ option.push({ key:k, diff --git a/src/component/Admin/Setting/Image.js b/src/component/Admin/Setting/Image.js index 2b6a4dd..13716fa 100644 --- a/src/component/Admin/Setting/Image.js +++ b/src/component/Admin/Setting/Image.js @@ -81,7 +81,7 @@ export default function ImageSetting() { const submit = e => { e.preventDefault(); setLoading(true); - let option = []; + const option = []; Object.keys(options).forEach(k=>{ option.push({ key:k, diff --git a/src/component/Admin/Setting/Mail.js b/src/component/Admin/Setting/Mail.js index c26de5d..e9ec11e 100644 --- a/src/component/Admin/Setting/Mail.js +++ b/src/component/Admin/Setting/Mail.js @@ -115,17 +115,19 @@ export default function Mail() { const reload = () => { API.get("/admin/reload/email") + // eslint-disable-next-line @typescript-eslint/no-empty-function .then(() => {}) .catch(error => { ToggleSnackbar("top", "right", error.message, "error"); }) + // eslint-disable-next-line @typescript-eslint/no-empty-function .then(() => {}); }; const submit = e => { e.preventDefault(); setLoading(true); - let option = []; + const option = []; Object.keys(options).forEach(k => { option.push({ key: k, diff --git a/src/component/Admin/Setting/SiteInformation.js b/src/component/Admin/Setting/SiteInformation.js index 88539ae..86f3ad1 100644 --- a/src/component/Admin/Setting/SiteInformation.js +++ b/src/component/Admin/Setting/SiteInformation.js @@ -78,7 +78,7 @@ export default function SiteInformation() { const submit = e => { e.preventDefault(); setLoading(true); - let option = []; + const option = []; Object.keys(options).forEach(k=>{ option.push({ key:k, diff --git a/src/component/Admin/Setting/Theme.js b/src/component/Admin/Setting/Theme.js index 150fc81..b6a740b 100644 --- a/src/component/Admin/Setting/Theme.js +++ b/src/component/Admin/Setting/Theme.js @@ -64,6 +64,13 @@ export default function Theme() { const [themeConfigError, setThemeConfigError] = useState({}); const [create, setCreate] = useState(false); + const dispatch = useDispatch(); + const ToggleSnackbar = useCallback( + (vertical, horizontal, msg, color) => + dispatch(toggleSnackbar(vertical, horizontal, msg, color)), + [dispatch] + ); + const deleteTheme = color => { if(color === options.defaultTheme){ ToggleSnackbar("top", "right", "不能删除默认配色", "warning"); @@ -73,9 +80,9 @@ export default function Theme() { ToggleSnackbar("top", "right", "请至少保留一个配色方案", "warning"); return } - let themeCopy = {...theme}; + const themeCopy = {...theme}; delete themeCopy[color]; - let resStr = JSON.stringify(themeCopy); + const resStr = JSON.stringify(themeCopy); setOptions({ ...options, themes:resStr, @@ -88,11 +95,11 @@ export default function Theme() { ToggleSnackbar("top", "right", "主色调不能与已有配色重复", "warning"); return } - let res = { + const res = { ...theme, [newTheme.palette.primary.main]:newTheme, }; - let resStr = JSON.stringify(res); + const resStr = JSON.stringify(res); setOptions({ ...options, themes:resStr, @@ -100,8 +107,8 @@ export default function Theme() { } useEffect(() => { - let res = JSON.parse(options.themes); - let themeString = {}; + const res = JSON.parse(options.themes); + const themeString = {}; Object.keys(res).forEach(k => { themeString[k] = JSON.stringify(res[k]); @@ -118,13 +125,6 @@ export default function Theme() { }); }; - const dispatch = useDispatch(); - const ToggleSnackbar = useCallback( - (vertical, horizontal, msg, color) => - dispatch(toggleSnackbar(vertical, horizontal, msg, color)), - [dispatch] - ); - useEffect(() => { API.post("/admin/setting", { keys: Object.keys(options) @@ -141,7 +141,7 @@ export default function Theme() { const submit = e => { e.preventDefault(); setLoading(true); - let option = []; + const option = []; Object.keys(options).forEach(k => { option.push({ key: k, @@ -233,7 +233,7 @@ export default function Theme() { }} onBlur={e => { try { - let res = JSON.parse( + const res = JSON.parse( e.target.value ); if( diff --git a/src/component/Admin/Setting/UploadDownload.js b/src/component/Admin/Setting/UploadDownload.js index 6e04540..7b9600b 100644 --- a/src/component/Admin/Setting/UploadDownload.js +++ b/src/component/Admin/Setting/UploadDownload.js @@ -56,7 +56,7 @@ export default function UploadDownload() { }); const handleCheckChange = name => event => { - let value= event.target.checked ? "1" : "0"; + const value= event.target.checked ? "1" : "0"; setOptions({ ...options, [name]: value @@ -94,7 +94,7 @@ export default function UploadDownload() { const submit = e => { e.preventDefault(); setLoading(true); - let option = []; + const option = []; Object.keys(options).forEach(k=>{ option.push({ key:k, diff --git a/src/component/Admin/Task/Task.js b/src/component/Admin/Task/Task.js index 022abe1..d6390d0 100644 --- a/src/component/Admin/Task/Task.js +++ b/src/component/Admin/Task/Task.js @@ -176,7 +176,7 @@ export default function Task() { return "-" } try { - let res = JSON.parse(error) + const res = JSON.parse(error) return res.msg }catch (e) { return "未知" diff --git a/src/component/Admin/User/EditUser.js b/src/component/Admin/User/EditUser.js index 616c7a1..bc0ab2a 100644 --- a/src/component/Admin/User/EditUser.js +++ b/src/component/Admin/User/EditUser.js @@ -8,7 +8,7 @@ import UserForm from "./UserForm"; export default function EditUserPreload( ) { const [user,setUser] = useState({}); - let {id } = useParams(); + const {id } = useParams(); const dispatch = useDispatch(); const ToggleSnackbar = useCallback( diff --git a/src/component/Admin/User/User.js b/src/component/Admin/User/User.js index 524f360..1b31551 100644 --- a/src/component/Admin/User/User.js +++ b/src/component/Admin/User/User.js @@ -83,8 +83,8 @@ export default function Group() { const [selected, setSelected] = useState([]); const [loading,setLoading] = useState(false); - let history = useHistory(); - let theme = useTheme(); + const history = useHistory(); + const theme = useTheme(); const dispatch = useDispatch(); const ToggleSnackbar = useCallback( @@ -149,7 +149,7 @@ export default function Group() { .then(response => { setUsers(users.map(v=>{ if (v.ID === id){ - let newUser = {...v,Status:response.data} + const newUser = {...v,Status:response.data} return newUser; } return v diff --git a/src/component/Admin/User/UserForm.js b/src/component/Admin/User/UserForm.js index dce71fc..eb2d0da 100644 --- a/src/component/Admin/User/UserForm.js +++ b/src/component/Admin/User/UserForm.js @@ -48,7 +48,7 @@ export default function UserForm(props) { ); const [groups, setGroups] = useState([]); - let history = useHistory(); + const history = useHistory(); const dispatch = useDispatch(); const ToggleSnackbar = useCallback( @@ -76,7 +76,7 @@ export default function UserForm(props) { const submit = e => { e.preventDefault(); - let userCopy = {...user}; + const userCopy = {...user}; // 整型转换 ["Status", "GroupID","Score"].forEach(v => { diff --git a/src/component/Dial/AutoHidden.js b/src/component/Dial/AutoHidden.js index 9d176dd..422b279 100644 --- a/src/component/Dial/AutoHidden.js +++ b/src/component/Dial/AutoHidden.js @@ -10,29 +10,28 @@ function AutoHidden ({ children, enable }){ const show = 50; useEffect(() => { + const handleNavigation = (e) => { + const window = e.currentTarget; + + if (prev > window.scrollY) { + if (lastUpdate - window.scrollY > show){ + lastUpdate = window.scrollY; + setHidden(false); + } + } else if (prev < window.scrollY) { + if (window.scrollY - lastUpdate > show){ + lastUpdate = window.scrollY; + setHidden(true); + } + } + prev = window.scrollY; + }; if (enable){ window.addEventListener('scroll', e => handleNavigation(e)); } // eslint-disable-next-line }, [enable]) - const handleNavigation = (e) => { - const window = e.currentTarget; - - if (prev > window.scrollY) { - if (lastUpdate - window.scrollY > show){ - lastUpdate = window.scrollY; - setHidden(false); - } - } else if (prev < window.scrollY) { - if (window.scrollY - lastUpdate > show){ - lastUpdate = window.scrollY; - setHidden(true); - } - } - prev = window.scrollY; - }; - return ( {children} diff --git a/src/component/Dial/Create.js b/src/component/Dial/Create.js index 9efedf1..a568b29 100644 --- a/src/component/Dial/Create.js +++ b/src/component/Dial/Create.js @@ -63,6 +63,21 @@ export default function UploadButton(props) { setQueued(props.Queued); }, [props.Queued]); + const openUpload = id =>{ + const uploadButton = document.getElementsByClassName( + id + )[0]; + if (document.body.contains(uploadButton)) { + uploadButton.click(); + } else { + ToggleSnackbar( + "top", + "right", + "上传组件还未加载完成", + "warning" + ); + } + }; const uploadClicked = () => { if (open) { if (queued !== 0) { @@ -73,22 +88,6 @@ export default function UploadButton(props) { } }; - const openUpload = id =>{ - let uploadButton = document.getElementsByClassName( - id - )[0]; - if (document.body.contains(uploadButton)) { - uploadButton.click(); - } else { - ToggleSnackbar( - "top", - "right", - "上传组件还未加载完成", - "warning" - ); - } - }; - const handleOpen = () => { setOpen(true); }; diff --git a/src/component/Download/DownloadingCard.js b/src/component/Download/DownloadingCard.js index b434f94..9798c2d 100644 --- a/src/component/Download/DownloadingCard.js +++ b/src/component/Download/DownloadingCard.js @@ -145,7 +145,7 @@ const useStyles = makeStyles(theme => ({ })); export default function DownloadingCard(props) { - let canvasRef = React.createRef(); + const canvasRef = React.createRef(); const classes = useStyles(); const theme = useTheme(); @@ -202,11 +202,16 @@ export default function DownloadingCard(props) { return (completed / total) * 100; }; + + const activeFiles = useCallback(() => { + return task.info.files.filter(v => v.selected === "true"); + }, [task.info.files]); + const deleteFile = index => { setLoading(true); - let current = activeFiles(); - let newIndex = []; - let newFiles = []; + const current = activeFiles(); + const newIndex = []; + const newFiles = []; // eslint-disable-next-line current.map(v => { if (v.index !== index && v.selected) { @@ -250,10 +255,6 @@ export default function DownloadingCard(props) { return task.name === "." ? "[未知]" : task.name; }, [task]); - const activeFiles = useCallback(() => { - return task.info.files.filter(v => v.selected === "true"); - }, [task.info.files]); - const getIcon = useCallback(() => { if (task.info.bittorrent.mode === "multi") { return ( diff --git a/src/component/Download/FinishedCard.js b/src/component/Download/FinishedCard.js index e0e1251..9c36d2f 100644 --- a/src/component/Download/FinishedCard.js +++ b/src/component/Download/FinishedCard.js @@ -187,7 +187,7 @@ export default function FinishedCard(props) { const getTaskError = error =>{ try{ - let res = JSON.parse(error) + const res = JSON.parse(error) return res.msg + ":" + res.error }catch (e) { return "文件转存失败" diff --git a/src/component/FileManager/ContextMenu.js b/src/component/FileManager/ContextMenu.js index a4b9c24..29ee931 100644 --- a/src/component/FileManager/ContextMenu.js +++ b/src/component/FileManager/ContextMenu.js @@ -162,7 +162,7 @@ class ContextMenuCompoment extends Component { clickUpload = id => { this.props.changeContextMenu("empty", false); - let uploadButton = document.getElementsByClassName(id)[0]; + const uploadButton = document.getElementsByClassName(id)[0]; if (document.body.contains(uploadButton)) { uploadButton.click(); } else { @@ -176,9 +176,9 @@ class ContextMenuCompoment extends Component { }; openPreview = () => { - let isShare = pathHelper.isSharePage(this.props.location.pathname); + const isShare = pathHelper.isSharePage(this.props.location.pathname); if (isShare) { - let user = Auth.GetUser(); + const user = Auth.GetUser(); if (!Auth.Check() && user && !user.group.shareDownload) { this.props.toggleSnackbar( "top", @@ -191,7 +191,7 @@ class ContextMenuCompoment extends Component { } } this.props.changeContextMenu("file", false); - let previewPath = + const previewPath = this.props.selected[0].path === "/" ? this.props.selected[0].path + this.props.selected[0].name : this.props.selected[0].path + diff --git a/src/component/FileManager/Explorer.js b/src/component/FileManager/Explorer.js index 45bfc81..19c2c6a 100644 --- a/src/component/FileManager/Explorer.js +++ b/src/component/FileManager/Explorer.js @@ -8,7 +8,8 @@ import React, { Component } from "react"; import { configure, GlobalHotKeys } from "react-hotkeys"; import { connect } from "react-redux"; import { withRouter } from "react-router-dom"; -import { changeContextMenu, changeSortMethod, navigateTo, navigateUp, openRemoveDialog, setSelectedTarget } from "../../actions/index"; +import { changeContextMenu, navigateTo, navigateUp, openRemoveDialog, setSelectedTarget } from "../../actions/index"; +import explorer from "../../redux/explorer" import { isMac } from "../../utils"; import pathHelper from "../../utils/page"; import ContextMenu from "./ContextMenu"; @@ -150,7 +151,7 @@ const mapDispatchToProps = dispatch => { dispatch(openRemoveDialog()); }, changeSort: method => { - dispatch(changeSortMethod(method)); + dispatch(explorer.actions.changeSortMethod(method)); } }; }; @@ -207,7 +208,7 @@ class ExplorerCompoment extends Component { } ClickAway = e => { - let element = e.target; + const element = e.target; if (element.dataset.clickaway) { this.props.setSelectedTarget([]); } diff --git a/src/component/FileManager/FileManager.js b/src/component/FileManager/FileManager.js index 18e1b97..2f63c51 100644 --- a/src/component/FileManager/FileManager.js +++ b/src/component/FileManager/FileManager.js @@ -11,6 +11,7 @@ import Explorer from "./Explorer" import Modals from "./Modals" import Navigator from "./Navigator/Navigator" +// eslint-disable-next-line @typescript-eslint/no-empty-function const mapStateToProps = ()=>{ } diff --git a/src/component/FileManager/ImgPreview.js b/src/component/FileManager/ImgPreview.js index 6d5d7e9..5c3f943 100644 --- a/src/component/FileManager/ImgPreview.js +++ b/src/component/FileManager/ImgPreview.js @@ -35,11 +35,11 @@ class ImagPreviewComponent extends Component { }; UNSAFE_componentWillReceiveProps = nextProps => { - let items = []; + const items = []; let firstOne = 0; if (nextProps.first !== null) { if (pathHelper.isSharePage(this.props.location.pathname) && !nextProps.first.path){ - let newImg = { + const newImg = { intro: nextProps.first.name, src: baseURL + @@ -56,7 +56,7 @@ class ImagPreviewComponent extends Component { } // eslint-disable-next-line nextProps.other.map(value => { - let fileType = value.name + const fileType = value.name .split(".") .pop() .toLowerCase(); @@ -74,7 +74,7 @@ class ImagPreviewComponent extends Component { "/file/preview/" + value.id } - let newImg = { + const newImg = { intro: value.name, src:src, }; diff --git a/src/component/FileManager/ImgPreview_old.js b/src/component/FileManager/ImgPreview_old.js index 8661095..21d7a13 100644 --- a/src/component/FileManager/ImgPreview_old.js +++ b/src/component/FileManager/ImgPreview_old.js @@ -35,11 +35,11 @@ class ImgPreviewCompoment extends Component { }; UNSAFE_componentWillReceiveProps = nextProps => { - let items = []; + const items = []; let firstOne = 0; if (nextProps.first !== null) { if (pathHelper.isSharePage(this.props.location.pathname) && !nextProps.first.path){ - let newImg = { + const newImg = { title: nextProps.first.name, src: baseURL + @@ -56,7 +56,7 @@ class ImgPreviewCompoment extends Component { } // eslint-disable-next-line nextProps.other.map(value => { - let fileType = value.name + const fileType = value.name .split(".") .pop() .toLowerCase(); @@ -74,7 +74,7 @@ class ImgPreviewCompoment extends Component { "/file/preview/" + value.id } - let newImg = { + const newImg = { title: value.name, src:src, }; diff --git a/src/component/FileManager/Modals.js b/src/component/FileManager/Modals.js index 000c6ba..f1e620d 100644 --- a/src/component/FileManager/Modals.js +++ b/src/component/FileManager/Modals.js @@ -137,7 +137,7 @@ class ModalsCompoment extends Component { return; } if (this.props.modalsStatus.rename !== nextProps.modalsStatus.rename) { - let name = nextProps.selected[0].name; + const name = nextProps.selected[0].name; this.setState({ newName: name }); @@ -172,7 +172,7 @@ class ModalsCompoment extends Component { Download = () => { let reqURL = ""; if (this.props.selected[0].key) { - let downloadPath = + const downloadPath = this.props.selected[0].path === "/" ? this.props.selected[0].path + this.props.selected[0].name : this.props.selected[0].path + @@ -205,7 +205,7 @@ class ModalsCompoment extends Component { }; archiveDownload = () => { - let dirs = [], + const dirs = [], items = []; this.props.selected.map(value => { if (value.type === "dir") { @@ -217,7 +217,7 @@ class ModalsCompoment extends Component { }); let reqURL = "/file/archive"; - let postBody = { + const postBody = { items: items, dirs: dirs }; @@ -260,7 +260,7 @@ class ModalsCompoment extends Component { submitRemove = e => { e.preventDefault(); this.props.setModalsLoading(true); - let dirs = [], + const dirs = [], items = []; // eslint-disable-next-line this.props.selected.map(value => { @@ -307,7 +307,7 @@ class ModalsCompoment extends Component { e.preventDefault(); } this.props.setModalsLoading(true); - let dirs = [], + const dirs = [], items = []; // eslint-disable-next-line this.props.selected.map(value => { @@ -386,9 +386,9 @@ class ModalsCompoment extends Component { submitRename = e => { e.preventDefault(); this.props.setModalsLoading(true); - let newName = this.state.newName; + const newName = this.state.newName; - let src = { + const src = { dirs: [], items: [] }; @@ -578,7 +578,7 @@ class ModalsCompoment extends Component { }; setMoveTarget = folder => { - let path = + const path = folder.path === "/" ? folder.path + folder.name : folder.path + "/" + folder.name; diff --git a/src/component/FileManager/Navigator/DropDown.js b/src/component/FileManager/Navigator/DropDown.js index 2b37c97..053aeef 100644 --- a/src/component/FileManager/Navigator/DropDown.js +++ b/src/component/FileManager/Navigator/DropDown.js @@ -6,7 +6,7 @@ export default function DropDown(props) { let timer; let first = props.folders.length; - let status = []; + const status = []; for (let index = 0; index < props.folders.length; index++) { status[index] = false; diff --git a/src/component/FileManager/Navigator/Navigator.js b/src/component/FileManager/Navigator/Navigator.js index 9aaa685..63ecc03 100644 --- a/src/component/FileManager/Navigator/Navigator.js +++ b/src/component/FileManager/Navigator/Navigator.js @@ -14,9 +14,7 @@ import { navigateTo, navigateUp, changeViewMethod, - changeSortMethod, setNavigatorError, - updateFileList, setNavigatorLoadingStatus, refreshFileList, setSelectedTarget, @@ -25,6 +23,7 @@ import { drawerToggleAction, setShareUserPopover, openResaveDialog, openCompressDialog } from "../../../actions/index"; +import explorer from "../../../redux/explorer" import API from "../../../middleware/Api"; import { setCookie, setGetParameter, fixUrlHash } from "../../../utils/index"; import { @@ -69,13 +68,13 @@ const mapDispatchToProps = dispatch => { dispatch(changeViewMethod(method)); }, changeSort: method => { - dispatch(changeSortMethod(method)); + dispatch(explorer.actions.changeSortMethod(method)); }, setNavigatorError: (status, msg) => { dispatch(setNavigatorError(status, msg)); }, updateFileList: list => { - dispatch(updateFileList(list)); + dispatch(explorer.actions.updateFileList(list)); }, setNavigatorLoadingStatus: status => { dispatch(setNavigatorLoadingStatus(status)); @@ -181,8 +180,8 @@ class NavigatorComponent extends Component { } componentDidMount = () => { - var url = new URL(fixUrlHash(window.location.href)); - var c = url.searchParams.get("path"); + const url = new URL(fixUrlHash(window.location.href)); + const c = url.searchParams.get("path"); this.renderPath(c === null ? "/":c); if (!this.props.isShare) { @@ -192,8 +191,8 @@ class NavigatorComponent extends Component { // 后退操作时重新导航 window.onpopstate = () => { - var url = new URL(fixUrlHash(window.location.href)); - var c = url.searchParams.get("path"); + const url = new URL(fixUrlHash(window.location.href)); + const c = url.searchParams.get("path"); if (c !== null && c !== this.props.path) { this.props.navigateToPath(c); } @@ -208,8 +207,8 @@ class NavigatorComponent extends Component { ? path.substr(1).split("/") : this.props.path.substr(1).split("/") }); - var newPath = path !== null ? path : this.props.path; - var apiURL = this.props.share + let newPath = path !== null ? path : this.props.path; + const apiURL = this.props.share ? "/share/list/" + this.props.share.key : this.keywords === null ? "/directory" @@ -221,7 +220,7 @@ class NavigatorComponent extends Component { this.currentID = response.data.parent; this.props.updateFileList(response.data.objects); this.props.setNavigatorLoadingStatus(false); - let pathTemp = (path !== null + const pathTemp = (path !== null ? path.substr(1).split("/") : this.props.path.substr(1).split("/") ).join(","); @@ -328,8 +327,8 @@ class NavigatorComponent extends Component { this.redresh(); return; } - let presentPath = this.props.path.split("/"); - let newTarget = [ + const presentPath = this.props.path.split("/"); + const newTarget = [ { id:this.currentID, type: "dir", @@ -359,7 +358,7 @@ class NavigatorComponent extends Component { }; toggleViewMethod = () => { - let newMethod = + const newMethod = this.props.viewMethod === "icon" ? "list" : this.props.viewMethod === "list" @@ -371,7 +370,7 @@ class NavigatorComponent extends Component { handleMenuItemClick = (e, index) => { this.setState({ selectedIndex: index, anchorEl: null }); - let optionsTable = { + const optionsTable = { 0: "namePos", 1: "nameRev", 2: "timePos", @@ -388,7 +387,7 @@ class NavigatorComponent extends Component { const isHomePage = pathHelper.isHomePage(this.props.location.pathname); const user = Auth.GetUser(); - let presentFolderMenu = ( + const presentFolderMenu = ( state.viewUpdate.explorerViewMethod ); const navigatorPath = useSelector(state => state.navigator.path); - let location = useLocation(); - let history = useHistory(); + const location = useLocation(); + const history = useHistory(); const dispatch = useDispatch(); const ContextMenu = useCallback( @@ -101,7 +101,11 @@ export default function ObjectIcon(props) { const selectFile = e => { dispatch(selectFileAction(props.file, e, props.index)) }; - + const enterFolder = () => { + NavitateTo( + path === "/" ? path + props.file.name : path + "/" + props.file.name + ); + }; const handleClick = e => { if (props.file.type === "up") { NavitateTo(pathBack(navigatorPath)); @@ -128,9 +132,9 @@ export default function ObjectIcon(props) { enterFolder(); return; } - let isShare = statusHelper.isSharePage(location.pathname); + const isShare = statusHelper.isSharePage(location.pathname); if (isShare) { - let user = Auth.GetUser(); + const user = Auth.GetUser(); if (!Auth.Check() && user && !user.group.shareDownload) { ToggleSnackbar("top", "right", "请先登录", "warning"); return; @@ -140,7 +144,7 @@ export default function ObjectIcon(props) { OpenLoadingDialog("获取下载地址..."); return; } - let previewPath = + const previewPath = selected[0].path === "/" ? selected[0].path + selected[0].name : selected[0].path + "/" + selected[0].name; @@ -232,12 +236,6 @@ export default function ObjectIcon(props) { } }; - const enterFolder = () => { - NavitateTo( - path === "/" ? path + props.file.name : path + "/" + props.file.name - ); - }; - const [{ isDragging }, drag, preview] = useDrag({ item: { object: props.file, diff --git a/src/component/FileManager/PathSelector.js b/src/component/FileManager/PathSelector.js index 866b41f..2c6bc8d 100644 --- a/src/component/FileManager/PathSelector.js +++ b/src/component/FileManager/PathSelector.js @@ -67,21 +67,21 @@ class PathSelectorCompoment extends Component { } componentDidMount= ()=>{ - let toBeLoad = this.props.presentPath; + const toBeLoad = this.props.presentPath; this.enterFolder(this.props.keywords === null ? toBeLoad : "/"); } back = ()=>{ - let paths = this.state.presentPath.split("/"); + const paths = this.state.presentPath.split("/"); paths.pop(); - let toBeLoad = paths.join("/"); + const toBeLoad = paths.join("/"); this.enterFolder(toBeLoad===""?"/":toBeLoad); } enterFolder = (toBeLoad)=>{ API.get((this.props.api ? this.props.api : '/directory')+encodeURIComponent(toBeLoad),) .then( (response)=> { - var dirList = response.data.objects.filter( (x)=> { + const dirList = response.data.objects.filter( (x)=> { return (x.type === "dir" && (this.props.selected.findIndex((value)=>{ return (value.name === x.name )&&(value.path === x.path); }))===-1); diff --git a/src/component/FileManager/TypeIcon.js b/src/component/FileManager/TypeIcon.js index 532c7ec..7e8645e 100644 --- a/src/component/FileManager/TypeIcon.js +++ b/src/component/FileManager/TypeIcon.js @@ -106,7 +106,7 @@ let color; const TypeIcon = props => { const theme = useTheme(); - let fileSuffix = props.fileName + const fileSuffix = props.fileName .split(".") .pop() .toLowerCase(); @@ -116,7 +116,7 @@ const TypeIcon = props => { fileType = k; } }); - let IconComponent = icons[fileType].icon; + const IconComponent = icons[fileType].icon; color = getColor(theme, icons[fileType].color); if (props.getColorValue) { props.getColorValue(color); diff --git a/src/component/Login/Activication.js b/src/component/Login/Activication.js index 45e19f0..cd5f5f8 100644 --- a/src/component/Login/Activication.js +++ b/src/component/Login/Activication.js @@ -50,8 +50,8 @@ function useQuery() { } function Activation() { - let query = useQuery(); - let location = useLocation(); + const query = useQuery(); + const location = useLocation(); const [success,setSuccess] = useState(false); const [email,setEmail] = useState(""); diff --git a/src/component/Login/LoginForm.js b/src/component/Login/LoginForm.js index 75dad8b..3238f8a 100644 --- a/src/component/Login/LoginForm.js +++ b/src/component/Login/LoginForm.js @@ -120,9 +120,9 @@ function LoginForm() { [dispatch] ); - let history = useHistory(); - let location = useLocation(); - let query = useQuery(); + const history = useHistory(); + const location = useLocation(); + const query = useQuery(); const classes = useStyles(); @@ -148,6 +148,24 @@ function LoginForm() { } }, [location,loginCaptcha]); + const afterLogin = data =>{ + Auth.authenticate(data); + + // 设置用户主题色 + if (data["preferred_theme"] !== "") { + ApplyThemes(data["preferred_theme"]); + } + enableUploaderLoad(); + + // 设置登录状态 + SetSessionStatus(true); + + history.push("/home"); + ToggleSnackbar("top", "right", "登录成功", "success"); + + localStorage.removeItem("siteConfigCache"); + } + const authnLogin = e => { e.preventDefault(); if (!navigator.credentials) { @@ -160,7 +178,7 @@ function LoginForm() { API.get("/user/authn/" + email) .then(response => { - let credentialRequestOptions = response.data; + const credentialRequestOptions = response.data; console.log(credentialRequestOptions); credentialRequestOptions.publicKey.challenge = bufferDecode( credentialRequestOptions.publicKey.challenge @@ -176,11 +194,11 @@ function LoginForm() { }); }) .then(assertion => { - let authData = assertion.response.authenticatorData; - let clientDataJSON = assertion.response.clientDataJSON; - let rawId = assertion.rawId; - let sig = assertion.response.signature; - let userHandle = assertion.response.userHandle; + const authData = assertion.response.authenticatorData; + const clientDataJSON = assertion.response.clientDataJSON; + const rawId = assertion.rawId; + const sig = assertion.response.signature; + const userHandle = assertion.response.userHandle; return API.post( "/user/authn/finish/" + email, @@ -209,24 +227,6 @@ function LoginForm() { }); }; - const afterLogin = data =>{ - Auth.authenticate(data); - - // 设置用户主题色 - if (data["preferred_theme"] !== "") { - ApplyThemes(data["preferred_theme"]); - } - enableUploaderLoad(); - - // 设置登录状态 - SetSessionStatus(true); - - history.push("/home"); - ToggleSnackbar("top", "right", "登录成功", "success"); - - localStorage.removeItem("siteConfigCache"); - } - const login = e => { e.preventDefault(); setLoading(true); diff --git a/src/component/Login/ReCaptchaWrapper.js b/src/component/Login/ReCaptchaWrapper.js index 4cdb49d..7a8d21b 100644 --- a/src/component/Login/ReCaptchaWrapper.js +++ b/src/component/Login/ReCaptchaWrapper.js @@ -118,6 +118,7 @@ export default class ReCAPTCHA extends React.Component { render() { // consume properties owned by the reCATPCHA, pass the rest to the div so the user can style it. /* eslint-disable no-unused-vars */ + /* eslint-disable @typescript-eslint/no-unused-vars */ const { sitekey, onChange, @@ -154,6 +155,7 @@ ReCAPTCHA.propTypes = { badge: PropTypes.oneOf(["bottomright", "bottomleft", "inline"]), }; ReCAPTCHA.defaultProps = { + // eslint-disable-next-line @typescript-eslint/no-empty-function onChange: () => {}, theme: "light", type: "image", diff --git a/src/component/Login/ResetForm.js b/src/component/Login/ResetForm.js index 0ea1f99..9f3bb3f 100644 --- a/src/component/Login/ResetForm.js +++ b/src/component/Login/ResetForm.js @@ -59,7 +59,7 @@ function useQuery() { } function ResetForm() { - let query = useQuery(); + const query = useQuery(); const [input, setInput] = useState({ password: "", password_repeat: "" diff --git a/src/component/Modals/AddTag.js b/src/component/Modals/AddTag.js index b7e849c..171c67b 100644 --- a/src/component/Modals/AddTag.js +++ b/src/component/Modals/AddTag.js @@ -110,7 +110,7 @@ export default function AddTag(props) { // eslint-disable-next-line const [selectedPathName, setSelectedPathName] = useState(""); const setMoveTarget = folder => { - let path = + const path = folder.path === "/" ? folder.path + folder.name : folder.path + "/" + folder.name; @@ -148,14 +148,6 @@ export default function AddTag(props) { [dispatch] ); - const submit = () => { - if (value === 0) { - submitNewTag(); - }else{ - submitNewLink(); - } - }; - const submitNewLink = ()=>{ setLoading(true); @@ -210,7 +202,13 @@ export default function AddTag(props) { setLoading(false); }); }; - + const submit = () => { + if (value === 0) { + submitNewTag(); + }else{ + submitNewLink(); + } + }; const selectPath = ()=>{ setInput({ ...input, diff --git a/src/component/Modals/Compress.js b/src/component/Modals/Compress.js index 797990e..2ee02af 100644 --- a/src/component/Modals/Compress.js +++ b/src/component/Modals/Compress.js @@ -59,7 +59,7 @@ export default function CompressDialog(props) { ); const setMoveTarget = folder => { - let path = + const path = folder.path === "/" ? folder.path + folder.name : folder.path + "/" + folder.name; @@ -73,7 +73,7 @@ export default function CompressDialog(props) { } SetModalsLoading(true); - let dirs = [], + const dirs = [], items = []; // eslint-disable-next-line props.selected.map(value => { diff --git a/src/component/Modals/Copy.js b/src/component/Modals/Copy.js index 2e91342..91bb987 100644 --- a/src/component/Modals/Copy.js +++ b/src/component/Modals/Copy.js @@ -57,7 +57,7 @@ export default function CopyDialog(props) { }, [dispatch]); const setMoveTarget = folder => { - let path = + const path = folder.path === "/" ? folder.path + folder.name : folder.path + "/" + folder.name; @@ -70,7 +70,7 @@ export default function CopyDialog(props) { e.preventDefault(); } SetModalsLoading(true); - let dirs = [], + const dirs = [], items = []; // eslint-disable-next-line diff --git a/src/component/Modals/CreateShare.js b/src/component/Modals/CreateShare.js index b02768b..454b7f9 100644 --- a/src/component/Modals/CreateShare.js +++ b/src/component/Modals/CreateShare.js @@ -189,7 +189,7 @@ export default function CreatShare(props) { const submitShare = e => { e.preventDefault(); props.setModalsLoading(true); - let submitFormBody = { + const submitFormBody = { id: props.selected[0].id, is_dir: props.selected[0].type === "dir", password: values.password, diff --git a/src/component/Modals/CreateWebDAVAccount.js b/src/component/Modals/CreateWebDAVAccount.js index c46548d..d0239ce 100644 --- a/src/component/Modals/CreateWebDAVAccount.js +++ b/src/component/Modals/CreateWebDAVAccount.js @@ -43,7 +43,7 @@ export default function CreateWebDAVAccount(props) { const classes = useStyles(); const setMoveTarget = folder => { - let path = + const path = folder.path === "/" ? folder.path + folder.name : folder.path + "/" + folder.name; diff --git a/src/component/Modals/Decompress.js b/src/component/Modals/Decompress.js index e07002f..bf780be 100644 --- a/src/component/Modals/Decompress.js +++ b/src/component/Modals/Decompress.js @@ -54,7 +54,7 @@ export default function DecompressDialog(props) { ); const setMoveTarget = folder => { - let path = + const path = folder.path === "/" ? folder.path + folder.name : folder.path + "/" + folder.name; diff --git a/src/component/Modals/SelectFile.js b/src/component/Modals/SelectFile.js index 32d95f4..2216454 100644 --- a/src/component/Modals/SelectFile.js +++ b/src/component/Modals/SelectFile.js @@ -43,7 +43,7 @@ export default function SelectFileDialog(props) { const handleChange = index => event =>{ - let filesCopy = [...files]; + const filesCopy = [...files]; // eslint-disable-next-line filesCopy.map((v,k)=>{ if (v.index === index){ @@ -54,7 +54,7 @@ export default function SelectFileDialog(props) { }; const submit = () =>{ - let index = []; + const index = []; // eslint-disable-next-line files.map(v=>{ if(v.selected === "true"){ diff --git a/src/component/Navbar/DarkModeSwitcher.js b/src/component/Navbar/DarkModeSwitcher.js index e3edf0f..55f0379 100644 --- a/src/component/Navbar/DarkModeSwitcher.js +++ b/src/component/Navbar/DarkModeSwitcher.js @@ -21,13 +21,12 @@ const DarkModeSwitcher = ({ position }) => { const ToggleThemeMode = useCallback(() => dispatch(toggleDaylightMode()), [ dispatch ]); - const toggleMode = () => { - Auth.SetPreference("theme_mode",isDayLight?"dark":"light"); - ToggleThemeMode(); - }; const isDayLight = (ThemeType && ThemeType === "light") || !ThemeType; const isDark = ThemeType && ThemeType === "dark"; - + const toggleMode = () => { + Auth.SetPreference("theme_mode",isDayLight?"dark":"light"); + ToggleThemeMode(); + }; const classes = useStyles(); return ( import ("../Modals/AddTag" )); export default function FileTag() { const classes = useStyles(); - let location = useLocation(); - let history = useHistory(); + const location = useLocation(); + const history = useHistory(); const isHomePage = pathHelper.isHomePage(location.pathname); @@ -162,7 +162,7 @@ export default function FileTag() { const getIcon = (icon, color) => { if (icons[icon]) { - let IconComponent = icons[icon]; + const IconComponent = icons[icon]; return ( { - let newTags = [...tags,tag]; + const newTags = [...tags,tag]; setTags(newTags); - let user = Auth.GetUser(); + const user = Auth.GetUser(); user.tags = newTags; Auth.SetUser(user); }; @@ -190,9 +190,9 @@ export default function FileTag() { const submitDelete = id =>{ API.delete("/tag/"+id) .then(() => { - let newTags = tags.filter((v)=>{return v.id !== id}); + const newTags = tags.filter((v)=>{return v.id !== id}); setTags(newTags) - let user = Auth.GetUser(); + const user = Auth.GetUser(); user.tags = newTags; Auth.SetUser(user); }) diff --git a/src/component/Navbar/Navbar.js b/src/component/Navbar/Navbar.js index 8ba7d48..1dcb970 100644 --- a/src/component/Navbar/Navbar.js +++ b/src/component/Navbar/Navbar.js @@ -336,9 +336,9 @@ class NavbarCompoment extends Component { }; openPreview = () => { - let isShare = pathHelper.isSharePage(this.props.location.pathname); + const isShare = pathHelper.isSharePage(this.props.location.pathname); if (isShare) { - let user = Auth.GetUser(); + const user = Auth.GetUser(); if (!Auth.Check() && user && !user.group.shareDownload) { this.props.toggleSnackbar( "top", @@ -351,7 +351,7 @@ class NavbarCompoment extends Component { } } this.props.changeContextMenu("file", false); - let previewPath = + const previewPath = this.props.selected[0].path === "/" ? this.props.selected[0].path + this.props.selected[0].name : this.props.selected[0].path + diff --git a/src/component/Navbar/StorageBar.js b/src/component/Navbar/StorageBar.js index 4b59daf..86374ec 100644 --- a/src/component/Navbar/StorageBar.js +++ b/src/component/Navbar/StorageBar.js @@ -119,6 +119,7 @@ class StorageBarCompoment extends Component { total: sizeToString(response.data.total) }); }) + // eslint-disable-next-line @typescript-eslint/no-empty-function .catch(() => {}); }; diff --git a/src/component/Setting/Authn.js b/src/component/Setting/Authn.js index 7ddf8fb..7dbe960 100644 --- a/src/component/Setting/Authn.js +++ b/src/component/Setting/Authn.js @@ -95,7 +95,7 @@ export default function Authn(props) { } API.put("/user/authn", {}) .then(response => { - let credentialCreationOptions = response.data; + const credentialCreationOptions = response.data; credentialCreationOptions.publicKey.challenge = bufferDecode( credentialCreationOptions.publicKey.challenge ); @@ -104,7 +104,7 @@ export default function Authn(props) { ); if (credentialCreationOptions.publicKey.excludeCredentials) { for ( - var i = 0; + let i = 0; i < credentialCreationOptions.publicKey.excludeCredentials .length; @@ -124,9 +124,9 @@ export default function Authn(props) { }); }) .then(credential => { - let attestationObject = credential.response.attestationObject; - let clientDataJSON = credential.response.clientDataJSON; - let rawId = credential.rawId; + const attestationObject = credential.response.attestationObject; + const clientDataJSON = credential.response.clientDataJSON; + const rawId = credential.rawId; return API.put( "/user/authn/finish", JSON.stringify({ diff --git a/src/component/Setting/Tasks.js b/src/component/Setting/Tasks.js index 4d36114..7fe8fae 100644 --- a/src/component/Setting/Tasks.js +++ b/src/component/Setting/Tasks.js @@ -52,22 +52,6 @@ export default function Tasks() { const [total, setTotal] = useState(0); const [page, setPage] = useState(1); - useEffect(() => { - loadList(page); - // eslint-disable-next-line - }, [page]); - - const loadList = page => { - API.get("/user/setting/tasks?page=" + page) - .then(response => { - setTasks(response.data.tasks); - setTotal(response.data.total); - }) - .catch(error => { - ToggleSnackbar("top", "right", error.message, "error"); - }); - }; - const dispatch = useDispatch(); const ToggleSnackbar = useCallback( (vertical, horizontal, msg, color) => @@ -75,12 +59,28 @@ export default function Tasks() { [dispatch] ); + const loadList = page => { + API.get("/user/setting/tasks?page=" + page) + .then(response => { + setTasks(response.data.tasks); + setTotal(response.data.total); + }) + .catch(error => { + ToggleSnackbar("top", "right", error.message, "error"); + }); + }; + + useEffect(() => { + loadList(page); + // eslint-disable-next-line + }, [page]); + const getError = error => { if (error === ""){ return "-" } try { - let res = JSON.parse(error) + const res = JSON.parse(error) return res.msg }catch (e) { return "未知" diff --git a/src/component/Setting/UserSetting.js b/src/component/Setting/UserSetting.js index 8d302f4..0397ff6 100644 --- a/src/component/Setting/UserSetting.js +++ b/src/component/Setting/UserSetting.js @@ -233,7 +233,7 @@ class UserSettingCompoment extends Component { } toggleViewMethod = () => { - let newMethod = + const newMethod = this.props.viewMethod === "icon" ? "list" : this.props.viewMethod === "list" @@ -246,7 +246,7 @@ class UserSettingCompoment extends Component { loadSetting = () => { API.get("/user/setting") .then(response => { - let theme = JSON.parse(response.data.themes); + const theme = JSON.parse(response.data.themes); response.data.themes = theme; this.setState({ settings: response.data @@ -327,7 +327,7 @@ class UserSettingCompoment extends Component { this.setState({ loading: "avatar" }); - var formData = new FormData(); + const formData = new FormData(); formData.append("avatar", this.fileInput.current.files[0]); API.post("/user/setting/avatar", formData, { headers: { diff --git a/src/component/Setting/WebDAV.js b/src/component/Setting/WebDAV.js index 477eedb..d4b00eb 100644 --- a/src/component/Setting/WebDAV.js +++ b/src/component/Setting/WebDAV.js @@ -52,11 +52,13 @@ export default function WebDAV() { const [create, setCreate] = useState(false); const [accounts, setAccounts] = useState([]); - useEffect(() => { - loadList(); - // eslint-disable-next-line - }, []); - + const dispatch = useDispatch(); + const ToggleSnackbar = useCallback( + (vertical, horizontal, msg, color) => + dispatch(toggleSnackbar(vertical, horizontal, msg, color)), + [dispatch] + ); + const loadList = () =>{ API.get("/webdav/accounts") .then(response => { @@ -66,16 +68,13 @@ export default function WebDAV() { ToggleSnackbar("top", "right", error.message, "error"); }); } - - const dispatch = useDispatch(); - const ToggleSnackbar = useCallback( - (vertical, horizontal, msg, color) => - dispatch(toggleSnackbar(vertical, horizontal, msg, color)), - [dispatch] - ); + useEffect(() => { + loadList(); + // eslint-disable-next-line + }, []); const deleteAccount = id => { - let account = accounts[id]; + const account = accounts[id]; API.delete("/webdav/accounts/" + account.ID) .then(() => { let accountCopy = [...accounts]; diff --git a/src/component/Share/LockedFile.js b/src/component/Share/LockedFile.js index ed65542..2112685 100644 --- a/src/component/Share/LockedFile.js +++ b/src/component/Share/LockedFile.js @@ -55,7 +55,7 @@ const mapDispatchToProps = dispatch => { class LockedFileCompoment extends Component { constructor(props) { super(props); - let query = new URLSearchParams(this.props.location.search); + const query = new URLSearchParams(this.props.location.search); this.state = { pwd: query.get("password"), }; diff --git a/src/component/Share/MyShare.js b/src/component/Share/MyShare.js index 60bf634..5510a16 100644 --- a/src/component/Share/MyShare.js +++ b/src/component/Share/MyShare.js @@ -146,12 +146,12 @@ class MyShareCompoment extends Component { }; changePermission = id => { - let newPwd = Math.random() + const newPwd = Math.random() .toString(36) .substr(2) .slice(2, 8); - let oldList = this.state.shareList; - let shareIndex = oldList.findIndex(value => { + const oldList = this.state.shareList; + const shareIndex = oldList.findIndex(value => { return value.key === id; }); API @@ -171,8 +171,8 @@ class MyShareCompoment extends Component { }; changePreviewOption = id => { - let oldList = this.state.shareList; - let shareIndex = oldList.findIndex(value => { + const oldList = this.state.shareList; + const shareIndex = oldList.findIndex(value => { return value.key === id; }); API @@ -192,7 +192,7 @@ class MyShareCompoment extends Component { }; loadList = (page,orderBy) => { - let order = orderBy.split(" "); + const order = orderBy.split(" "); API.get("/share?page=" + page + "&order_by=" + order[0] + "&order=" + order[1]) .then(response => { if (response.data.items.length === 0) { diff --git a/src/component/Share/ReadMe.js b/src/component/Share/ReadMe.js index 0e976d7..7ed7ad4 100644 --- a/src/component/Share/ReadMe.js +++ b/src/component/Share/ReadMe.js @@ -73,11 +73,11 @@ export default function ReadMe(props) { [dispatch] ); - let $vm = React.createRef(); + const $vm = React.createRef(); useEffect(() => { setLoading(true); - let previewPath = + const previewPath = props.file.path === "/" ? props.file.path + props.file.name : props.file.path + "/" + props.file.name; diff --git a/src/component/Share/SearchResult.js b/src/component/Share/SearchResult.js index 783dd80..a357660 100644 --- a/src/component/Share/SearchResult.js +++ b/src/component/Share/SearchResult.js @@ -81,9 +81,9 @@ export default function SearchResult() { const classes = useStyles(); const dispatch = useDispatch(); - let query = useQuery(); - let location = useLocation(); - let history = useHistory(); + const query = useQuery(); + const location = useLocation(); + const history = useHistory(); const ToggleSnackbar = useCallback( (vertical, horizontal, msg, color) => @@ -97,7 +97,7 @@ export default function SearchResult() { const [orderBy, setOrderBy] = useState("created_at DESC"); const search = useCallback((keywords, page, orderBy) => { - let order = orderBy.split(" "); + const order = orderBy.split(" "); API.get( "/share/search?page=" + page + @@ -126,7 +126,7 @@ export default function SearchResult() { }, []); useEffect(() => { - let keywords = query.get("keywords"); + const keywords = query.get("keywords"); if (keywords) { search(keywords, page, orderBy); } else { @@ -136,13 +136,13 @@ export default function SearchResult() { const handlePageChange = (event, value) => { setPage(value); - let keywords = query.get("keywords"); + const keywords = query.get("keywords"); search(keywords, value, orderBy); }; const handleOrderChange = event => { setOrderBy(event.target.value); - let keywords = query.get("keywords"); + const keywords = query.get("keywords"); search(keywords, page, event.target.value); }; diff --git a/src/component/Share/SharePreload.js b/src/component/Share/SharePreload.js index e28a787..35da695 100644 --- a/src/component/Share/SharePreload.js +++ b/src/component/Share/SharePreload.js @@ -12,7 +12,7 @@ import SharedFolder from "./SharedFolder"; export default function SharePreload() { const dispatch = useDispatch(); - let { id } = useParams(); + const { id } = useParams(); const [share, setShare] = useState(undefined); const [loading, setLoading] = useState(false); diff --git a/src/component/Share/SharedFile.js b/src/component/Share/SharedFile.js index 8e99f6f..a826542 100644 --- a/src/component/Share/SharedFile.js +++ b/src/component/Share/SharedFile.js @@ -134,7 +134,7 @@ class SharedFileCompoment extends Component { preview = () => { if (pathHelper.isSharePage(this.props.location.pathname)) { - let user = Auth.GetUser(); + const user = Auth.GetUser(); if (!Auth.Check() && user && !user.group.shareDownload) { this.props.toggleSnackbar( "top", diff --git a/src/component/Upload/FileList.js b/src/component/Upload/FileList.js index 78d89d0..5a60dd4 100644 --- a/src/component/Upload/FileList.js +++ b/src/component/Upload/FileList.js @@ -89,8 +89,8 @@ class FileList extends Component { } deQueue(file) { - var filesNow = [...this.state.files]; - var fileID = filesNow.findIndex(f => { + const filesNow = [...this.state.files]; + const fileID = filesNow.findIndex(f => { return f.id === file.id; }); if (fileID !== -1) { @@ -103,8 +103,8 @@ class FileList extends Component { } updateStatus(file) { - var filesNow = [...this.state.files]; - var fileID = filesNow.findIndex(f => { + const filesNow = [...this.state.files]; + const fileID = filesNow.findIndex(f => { return f.id === file.id; }); if (!file.errMsg || file.ignoreMsg) { @@ -121,8 +121,8 @@ class FileList extends Component { setComplete(file) { console.log("setComplete"); - var filesNow = [...this.state.files]; - var fileID = filesNow.findIndex(f => { + const filesNow = [...this.state.files]; + const fileID = filesNow.findIndex(f => { return f.id === file.id; }); if (fileID !== -1) { @@ -136,8 +136,8 @@ class FileList extends Component { } setError(file, errMsg) { - var filesNow = [...this.state.files]; - var fileID = filesNow.findIndex(f => { + const filesNow = [...this.state.files]; + const fileID = filesNow.findIndex(f => { return f.id === file.id; }); if (fileID !== -1) { diff --git a/src/component/Upload/Uploader.js b/src/component/Upload/Uploader.js index be789c8..f01eb14 100644 --- a/src/component/Upload/Uploader.js +++ b/src/component/Upload/Uploader.js @@ -57,7 +57,7 @@ class UploaderComponent extends Component { } fileAdd = (up, files) => { - let path = window.currntPath ? window.currntPath : this.props.path; + const path = window.currntPath ? window.currntPath : this.props.path; if ( this.props.keywords === null && window.location.href @@ -76,7 +76,7 @@ class UploaderComponent extends Component { return !isDsStore }) .map(file => { - let source = file.getSource(); + const source = file.getSource(); if (source.relativePath && source.relativePath !== "") { file.path = basename( pathJoin([path, source.relativePath]) @@ -106,7 +106,7 @@ class UploaderComponent extends Component { return; } loaded = true; - var user = Auth.GetUser(); + const user = Auth.GetUser(); this.uploader = window.Qiniu.uploader({ runtimes: "html5", browse_button: ["pickfiles", "pickfolder"], @@ -133,6 +133,7 @@ class UploaderComponent extends Component { init: { FilesAdded: this.fileAdd, + // eslint-disable-next-line @typescript-eslint/no-empty-function BeforeUpload: function() {}, QueueChanged: up => { this.setState({ queued: up.total.queued }); @@ -149,7 +150,7 @@ class UploaderComponent extends Component { file[0].status, file[0] ); - for (var i = 0; i < file.length; i++) { + for (let i = 0; i < file.length; i++) { if (file[i].status === 5) { window.fileList["setComplete"](file[i]); } @@ -167,11 +168,13 @@ class UploaderComponent extends Component { this.props.refreshFileList(); this.props.refreshStorage(); }, + // eslint-disable-next-line @typescript-eslint/no-empty-function FileUploaded: function() {}, Error: (up, err, errTip) => { window.fileList["openFileList"](); window.fileList["setError"](err.file, errTip); }, + // eslint-disable-next-line @typescript-eslint/no-empty-function FilesRemoved: () => {} } }); @@ -180,6 +183,7 @@ class UploaderComponent extends Component { } } + // eslint-disable-next-line @typescript-eslint/no-empty-function onError() {} openFileList = () => { diff --git a/src/component/Viewer/Code.js b/src/component/Viewer/Code.js index 0cfa2cc..8ba26f8 100644 --- a/src/component/Viewer/Code.js +++ b/src/component/Viewer/Code.js @@ -58,9 +58,9 @@ export default function CodeViewer() { const [suffix, setSuffix] = useState("javascript"); const math = useRouteMatch(); - let location = useLocation(); - let query = useQuery(); - let { id } = useParams(); + const location = useLocation(); + const query = useQuery(); + const { id } = useParams(); const theme = useTheme(); const dispatch = useDispatch(); @@ -75,12 +75,12 @@ export default function CodeViewer() { useEffect(() => { if (!pathHelper.isSharePage(location.pathname)) { - let path = query.get("p").split("/"); - let extension = query.get("p").split("."); + const path = query.get("p").split("/"); + const extension = query.get("p").split("."); setSuffix(codePreviewSuffix[extension.pop()]); SetSubTitle(path[path.length - 1]); } else { - let extension = query.get("name").split("."); + const extension = query.get("name").split("."); setSuffix(codePreviewSuffix[extension.pop()]); SetSubTitle(query.get("name")); } @@ -100,8 +100,8 @@ export default function CodeViewer() { setLoading(true); API.get(requestURL, { responseType: "arraybuffer" }) .then(response => { - var buffer = new Buffer(response.rawData, "binary"); - var textdata = buffer.toString(); // for string + const buffer = new Buffer(response.rawData, "binary"); + const textdata = buffer.toString(); // for string setContent(textdata); }) .catch(error => { diff --git a/src/component/Viewer/Doc.js b/src/component/Viewer/Doc.js index 7e2b119..43258a4 100644 --- a/src/component/Viewer/Doc.js +++ b/src/component/Viewer/Doc.js @@ -27,11 +27,11 @@ function useQuery() { } export default function DocViewer() { - let [url,setURL] = useState(""); + const [url,setURL] = useState(""); const math = useRouteMatch(); - let location = useLocation(); - let query = useQuery(); - let { id } = useParams(); + const location = useLocation(); + const query = useQuery(); + const { id } = useParams(); const dispatch = useDispatch(); @@ -48,7 +48,7 @@ export default function DocViewer() { useEffect(() => { if (!pathHelper.isSharePage(location.pathname)) { - let path = query.get("p").split("/"); + const path = query.get("p").split("/"); SetSubTitle(path[path.length - 1]); } else { SetSubTitle(query.get("name")); diff --git a/src/component/Viewer/PDF.js b/src/component/Viewer/PDF.js index 116003c..077d3f0 100644 --- a/src/component/Viewer/PDF.js +++ b/src/component/Viewer/PDF.js @@ -41,9 +41,9 @@ function useQuery() { export default function PDFViewer() { const math = useRouteMatch(); - let location = useLocation(); - let query = useQuery(); - let { id } = useParams(); + const location = useLocation(); + const query = useQuery(); + const { id } = useParams(); const [pageNumber, setPageNumber] = useState(1); @@ -59,7 +59,7 @@ export default function PDFViewer() { useEffect(() => { if (!pathHelper.isSharePage(location.pathname)) { - let path = query.get("p").split("/"); + const path = query.get("p").split("/"); SetSubTitle(path[path.length - 1]); } else { SetSubTitle(query.get("name")); diff --git a/src/component/Viewer/Text.js b/src/component/Viewer/Text.js index b6aaa55..c3172fb 100644 --- a/src/component/Viewer/Text.js +++ b/src/component/Viewer/Text.js @@ -47,10 +47,10 @@ export default function TextViewer() { const [status, setStatus] = useState(""); const [loading, setLoading] = useState(true); const math = useRouteMatch(); - let $vm = React.createRef(); - let location = useLocation(); - let query = useQuery(); - let { id } = useParams(); + const $vm = React.createRef(); + const location = useLocation(); + const query = useQuery(); + const { id } = useParams(); const dispatch = useDispatch(); const SetSubTitle = useCallback(title => dispatch(changeSubTitle(title)), [ @@ -64,7 +64,7 @@ export default function TextViewer() { useEffect(() => { if (!pathHelper.isSharePage(location.pathname)) { - let path = query.get("p").split("/"); + const path = query.get("p").split("/"); SetSubTitle(path[path.length - 1]); } else { SetSubTitle(query.get("name")); @@ -84,8 +84,8 @@ export default function TextViewer() { setLoading(true); API.get(requestURL, { responseType: 'arraybuffer' }) .then(response => { - var buffer = new Buffer(response.rawData, 'binary'); - var textdata = buffer.toString(); // for string + const buffer = new Buffer(response.rawData, 'binary'); + const textdata = buffer.toString(); // for string setContent(textdata); }) .catch(error => { diff --git a/src/component/Viewer/Video.js b/src/component/Viewer/Video.js index 069c93e..1288824 100644 --- a/src/component/Viewer/Video.js +++ b/src/component/Viewer/Video.js @@ -33,16 +33,16 @@ function useQuery() { export default function VideoViewer() { const math = useRouteMatch(); - let location = useLocation(); - let query = useQuery(); - let { id } = useParams(); + const location = useLocation(); + const query = useQuery(); + const { id } = useParams(); const dispatch = useDispatch(); const SetSubTitle = useCallback(title => dispatch(changeSubTitle(title)), [ dispatch ]); useEffect(() => { if (!pathHelper.isSharePage(location.pathname)) { - let path = query.get("p").split("/"); + const path = query.get("p").split("/"); SetSubTitle(path[path.length - 1]); } else { SetSubTitle(query.get("name")); diff --git a/src/config.js b/src/config.js index 297d951..78e5f5c 100644 --- a/src/config.js +++ b/src/config.js @@ -57,7 +57,7 @@ export const policyTypeMap = { onedrive:"OneDrive", }; export const isPreviewable = name=>{ - let suffix = name.split(".").pop().toLowerCase(); + const suffix = name.split(".").pop().toLowerCase(); if(imgPreviewSuffix.indexOf(suffix)!==-1){ return "img"; }else if(msDocPreviewSuffix.indexOf(suffix)!==-1){ @@ -76,7 +76,7 @@ export const isPreviewable = name=>{ return false; } export const isTorrent = name=>{ - let suffix = name.split(".").pop().toLowerCase(); + const suffix = name.split(".").pop().toLowerCase(); if(mediaType.torrent.indexOf(suffix)!==-1){ return true; } @@ -84,7 +84,7 @@ export const isTorrent = name=>{ } export const isCompressFile = name=>{ - let suffix = name.split(".").pop().toLowerCase(); + const suffix = name.split(".").pop().toLowerCase(); return suffix === "zip" } diff --git a/src/loader/index.js b/src/loader/index.js index 4492dff..dfdd31b 100644 --- a/src/loader/index.js +++ b/src/loader/index.js @@ -7,44 +7,6 @@ const loadedScript = []; const pendingScripts = {}; let failedScript = []; -export function startLoadingScripts(scripts, onComplete = noop) { - // sequence load - const loadNewScript = script => { - const src = typeof script === "object" ? script.src : script; - if (loadedScript.indexOf(src) < 0) { - return taskComplete => { - const callbacks = pendingScripts[src] || []; - callbacks.push(taskComplete); - pendingScripts[src] = callbacks; - if (callbacks.length === 1) { - return newScript(script)(err => { - pendingScripts[src].forEach(cb => cb(err, src)); - delete pendingScripts[src]; - }); - } - }; - } - }; - const tasks = scripts.map(src => { - if (Array.isArray(src)) { - return src.map(loadNewScript); - } else return loadNewScript(src); - }); - - series(...tasks)((err, src) => { - if (err) { - failedScript.push(src); - } else { - if (Array.isArray(src)) { - src.forEach(addCache); - } else addCache(src); - } - })(err => { - removeFailedScript(); - onComplete(err); - }); -} - const addCache = entry => { if (loadedScript.indexOf(entry) < 0) { loadedScript.push(entry); @@ -64,6 +26,44 @@ const removeFailedScript = () => { } }; +export function startLoadingScripts(scripts, onComplete = noop) { + // sequence load + const loadNewScript = script => { + const src = typeof script === "object" ? script.src : script; + if (loadedScript.indexOf(src) < 0) { + return taskComplete => { + const callbacks = pendingScripts[src] || []; + callbacks.push(taskComplete); + pendingScripts[src] = callbacks; + if (callbacks.length === 1) { + return newScript(script)(err => { + pendingScripts[src].forEach(cb => cb(err, src)); + delete pendingScripts[src]; + }); + } + }; + } + }; + const tasks = scripts.map(src => { + if (Array.isArray(src)) { + return src.map(loadNewScript); + } else return loadNewScript(src); + }); + + series(...tasks)((err, src) => { + if (err) { + failedScript.push(src); + } else { + if (Array.isArray(src)) { + src.forEach(addCache); + } else addCache(src); + } + })(err => { + removeFailedScript(); + onComplete(err); + }); +} + const uploaderLoader = () => WrappedComponent => { class ScriptLoader extends Component { static propTypes = { @@ -87,7 +87,7 @@ const uploaderLoader = () => WrappedComponent => { componentDidMount() { this._isMounted = true; - let scripts = [ + const scripts = [ ["/static/js/uploader/moxie.js"], ["/static/js/uploader/plupload.dev.js"], ["/static/js/uploader/i18n/zh_CN.js"], diff --git a/src/loader/utils.js b/src/loader/utils.js index 8e92890..51a5960 100644 --- a/src/loader/utils.js +++ b/src/loader/utils.js @@ -1,12 +1,13 @@ export const isDefined = val => val != null export const isFunction = val => typeof val === 'function' +// eslint-disable-next-line @typescript-eslint/no-empty-function export const noop = () => { } export const newScript = (src) => (cb) => { const scriptElem = document.createElement('script') if (typeof src === 'object') { // copy every property to the element - for (var key in src) { + for (const key in src) { if (Object.prototype.hasOwnProperty.call(src, key)) { scriptElem[key] = src[key]; } @@ -72,6 +73,7 @@ export const series = (...tasks) => (each) => (cb) => { const nextThunk = () => { const key = nextKey.next() let thunk = tasks[key] + // eslint-disable-next-line prefer-spread if (Array.isArray(thunk)) thunk = parallel.apply(null, thunk).call(null, each) return [ +key, thunk ] // convert `key` to number } diff --git a/src/middleware/Api.js b/src/middleware/Api.js index 4d5041c..95becfd 100644 --- a/src/middleware/Api.js +++ b/src/middleware/Api.js @@ -1,7 +1,7 @@ import axios from "axios"; import Auth from "./Auth"; -export let baseURL = "/api/v3"; +export const baseURL = "/api/v3"; export const getBaseURL = () => { return baseURL; diff --git a/src/middleware/Auth.ts b/src/middleware/Auth.ts index 0659640..b7ca10f 100644 --- a/src/middleware/Auth.ts +++ b/src/middleware/Auth.ts @@ -5,7 +5,7 @@ const Auth = { Auth.isAuthenticated = true; }, GetUser(){ - return JSON.parse(localStorage.getItem("user")) + return JSON.parse(localStorage.getItem("user") || '') }, SetUser(newUser: any){ localStorage.setItem("user", JSON.stringify(newUser)); @@ -22,18 +22,18 @@ const Auth = { }, signout() { Auth.isAuthenticated = false; - let oldUser = Auth.GetUser(); + const oldUser = Auth.GetUser(); oldUser.id = 0; localStorage.setItem("user", JSON.stringify(oldUser)); }, SetPreference(key: string,value: any){ - let preference = JSON.parse(localStorage.getItem("user_preference")); + let preference = JSON.parse(localStorage.getItem("user_preference") || ''); preference = (preference == null) ? {} : preference; preference[key] = value; localStorage.setItem("user_preference", JSON.stringify(preference)); }, GetPreference(key: string): any | null{ - let preference = JSON.parse(localStorage.getItem("user_preference")); + const preference = JSON.parse(localStorage.getItem("user_preference") || ''); if (preference && preference[key]){ return preference[key]; } diff --git a/src/middleware/Init.js b/src/middleware/Init.js index bf4957b..9000d56 100644 --- a/src/middleware/Init.js +++ b/src/middleware/Init.js @@ -3,28 +3,11 @@ import { fixUrlHash } from "../utils/index" import API from "./Api" import Auth from "./Auth" import pathHelper from "../utils/page"; -export var InitSiteConfig = (rawStore) => { - // 从缓存获取默认配置 - let configCache = JSON.parse(localStorage.getItem('siteConfigCache')); - if (configCache != null) { - rawStore.siteConfig = configCache - } - // 检查是否有path参数 - var url = new URL(fixUrlHash(window.location.href)); - var c = url.searchParams.get("path"); - rawStore.navigator.path = c===null?"/":c; - // 初始化用户个性配置 - rawStore.siteConfig = initUserConfig(rawStore.siteConfig); - - // 更改站点标题 - document.title = rawStore.siteConfig.title; - return rawStore -} const initUserConfig = (siteConfig) => { if (siteConfig.user!==undefined && !siteConfig.user.anonymous){ - let themes = JSON.parse(siteConfig.themes); - let user = siteConfig.user; + const themes = JSON.parse(siteConfig.themes); + const user = siteConfig.user; delete siteConfig.user //更换用户自定配色 @@ -41,9 +24,27 @@ const initUserConfig = (siteConfig) => { return siteConfig } +export const InitSiteConfig = (rawStore) => { + // 从缓存获取默认配置 + const configCache = JSON.parse(localStorage.getItem('siteConfigCache')); + if (configCache != null) { + rawStore.siteConfig = configCache + } + // 检查是否有path参数 + const url = new URL(fixUrlHash(window.location.href)); + const c = url.searchParams.get("path"); + rawStore.navigator.path = c===null?"/":c; + // 初始化用户个性配置 + rawStore.siteConfig = initUserConfig(rawStore.siteConfig); + + // 更改站点标题 + document.title = rawStore.siteConfig.title; + return rawStore +} + export function enableUploaderLoad(){ // 开启上传组件加载 - let user = Auth.GetUser(); + const user = Auth.GetUser(); window.policyType = user!==null?user.policy.saveType : "local"; window.uploadConfig = user!==null?user.policy:{}; window.pathCache = []; @@ -51,18 +52,18 @@ export function enableUploaderLoad(){ export async function UpdateSiteConfig(store) { API.get("/site/config").then(function(response) { - let themes = JSON.parse(response.data.themes); + const themes = JSON.parse(response.data.themes); response.data.theme = themes[response.data.defaultTheme] response.data = initUserConfig(response.data) store.dispatch(setSiteConfig(response.data)); localStorage.setItem('siteConfigCache', JSON.stringify(response.data)); // 偏爱的列表样式 - let preferListMethod = Auth.GetPreference("view_method"); + const preferListMethod = Auth.GetPreference("view_method"); if(preferListMethod){ store.dispatch(changeViewMethod(preferListMethod)); }else{ - let path = window.location.hash.split("#"); + const path = window.location.hash.split("#"); if(path.length >=1 && pathHelper.isSharePage(path[1])){ store.dispatch(changeViewMethod(response.data.share_view_method)); }else{ diff --git a/src/pages/download.js b/src/pages/download.js index 2259d2d..cd5d01c 100644 --- a/src/pages/download.js +++ b/src/pages/download.js @@ -58,7 +58,7 @@ const defaultStatus = { } }; -let store = createStore(cloureveApp,defaultStatus) +const store = createStore(cloureveApp,defaultStatus) ReactDOM.render( diff --git a/src/pages/fileShare.js b/src/pages/fileShare.js index bfb0c39..83d1eb6 100644 --- a/src/pages/fileShare.js +++ b/src/pages/fileShare.js @@ -59,7 +59,7 @@ const defaultStatus = { } }; -let store = createStore(cloureveApp,defaultStatus) +const store = createStore(cloureveApp,defaultStatus) ReactDOM.render( diff --git a/src/pages/folderShare.js b/src/pages/folderShare.js index 14deaf9..207a1ae 100644 --- a/src/pages/folderShare.js +++ b/src/pages/folderShare.js @@ -59,7 +59,7 @@ const defaultStatus = { } }; -let store = createStore(cloureveApp,defaultStatus) +const store = createStore(cloureveApp,defaultStatus) ReactDOM.render( diff --git a/src/pages/lock.js b/src/pages/lock.js index 8ac4fe5..5bf9b76 100644 --- a/src/pages/lock.js +++ b/src/pages/lock.js @@ -58,7 +58,7 @@ const defaultStatus = { } }; -let store = createStore(cloureveApp,defaultStatus) +const store = createStore(cloureveApp,defaultStatus) ReactDOM.render( diff --git a/src/pages/login.js b/src/pages/login.js index 258de59..20bcc45 100644 --- a/src/pages/login.js +++ b/src/pages/login.js @@ -58,7 +58,7 @@ const defaultStatus = { } }; -let store = createStore(cloureveApp,defaultStatus) +const store = createStore(cloureveApp,defaultStatus) ReactDOM.render( diff --git a/src/pages/markdown.js b/src/pages/markdown.js index 8388397..133b894 100644 --- a/src/pages/markdown.js +++ b/src/pages/markdown.js @@ -58,7 +58,7 @@ const defaultStatus = { } }; -let store = createStore(cloureveApp,defaultStatus) +const store = createStore(cloureveApp,defaultStatus) ReactDOM.render( diff --git a/src/pages/myShare.js b/src/pages/myShare.js index 80ebefa..8acb30d 100644 --- a/src/pages/myShare.js +++ b/src/pages/myShare.js @@ -58,7 +58,7 @@ const defaultStatus = { } }; -let store = createStore(cloureveApp,defaultStatus) +const store = createStore(cloureveApp,defaultStatus) ReactDOM.render( diff --git a/src/pages/profile.js b/src/pages/profile.js index af795ba..22e8f5e 100644 --- a/src/pages/profile.js +++ b/src/pages/profile.js @@ -58,7 +58,7 @@ const defaultStatus = { } }; -let store = createStore(cloureveApp,defaultStatus) +const store = createStore(cloureveApp,defaultStatus) ReactDOM.render( diff --git a/src/pages/quota.js b/src/pages/quota.js index d3e5d71..be03d07 100644 --- a/src/pages/quota.js +++ b/src/pages/quota.js @@ -58,7 +58,7 @@ const defaultStatus = { } }; -let store = createStore(cloureveApp,defaultStatus) +const store = createStore(cloureveApp,defaultStatus) ReactDOM.render( diff --git a/src/pages/search.js b/src/pages/search.js index 72cb763..7eb0916 100644 --- a/src/pages/search.js +++ b/src/pages/search.js @@ -58,7 +58,7 @@ const defaultStatus = { } }; -let store = createStore(cloureveApp,defaultStatus) +const store = createStore(cloureveApp,defaultStatus) ReactDOM.render( diff --git a/src/pages/setting.js b/src/pages/setting.js index f9ffdac..e7a229b 100644 --- a/src/pages/setting.js +++ b/src/pages/setting.js @@ -58,7 +58,7 @@ const defaultStatus = { } }; -let store = createStore(cloureveApp,defaultStatus) +const store = createStore(cloureveApp,defaultStatus) ReactDOM.render( diff --git a/src/pages/video.js b/src/pages/video.js index ad15622..c91b6af 100644 --- a/src/pages/video.js +++ b/src/pages/video.js @@ -58,7 +58,7 @@ const defaultStatus = { } }; -let store = createStore(cloureveApp,defaultStatus) +const store = createStore(cloureveApp,defaultStatus) ReactDOM.render( diff --git a/src/reducers/explorer.js b/src/reducers/explorer.js deleted file mode 100644 index a9d0b31..0000000 --- a/src/reducers/explorer.js +++ /dev/null @@ -1,67 +0,0 @@ -const checkSelectedProps = (state)=>{ - let isMultiple,withFolder,withFile=false; - isMultiple = (state.selected.length>1); - state.selected.forEach((value) => { - if(value.type==="dir"){ - withFolder = true; - }else if(value.type==="file"){ - withFile = true; - } - }) - return [isMultiple,withFolder,withFile]; -} - -const explorer = (state = [], action) => { - switch (action.type) { - case 'UPDATE_FILE_LIST': - var dirList = action.list.filter(function (x) { - return x.type === "dir"; - }); - return Object.assign({}, state, { - fileList: action.list, - dirList: dirList, - }); - case 'ADD_SELECTED_TARGET': - var newState = Object.assign({}, state, { - selected: [...state.selected,action.targets] - }); - var selectedProps = checkSelectedProps(newState); - return Object.assign({}, newState, { - selectProps: { - isMultiple:selectedProps[0], - withFolder:selectedProps[1], - withFile:selectedProps[2], - } - }); - case 'SET_SELECTED_TARGET': - var newSelectedState = Object.assign({}, state, { - selected: action.targets - }); - var newSelectedProps = checkSelectedProps(newSelectedState); - return Object.assign({}, newSelectedState, { - selectProps: { - isMultiple:newSelectedProps[0], - withFolder:newSelectedProps[1], - withFile:newSelectedProps[2], - } - }); - case 'RMOVE_SELECTED_TARGET': - var oldSelected = state.selected.concat(); - oldSelected.splice(action.id,1); - var removedSelectedState = Object.assign({}, state, { - selected: oldSelected, - }); - var removedSelectedProps = checkSelectedProps(removedSelectedState); - return Object.assign({}, removedSelectedState, { - selectProps: { - isMultiple:removedSelectedProps[0], - withFolder:removedSelectedProps[1], - withFile:removedSelectedProps[2], - } - }); - default: - return state - } - } - - export default explorer \ No newline at end of file diff --git a/src/reducers/index.js b/src/reducers/index.js index 38687b2..c052ba5 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -2,20 +2,7 @@ import { InitSiteConfig } from "../middleware/Init"; import { combineReducers } from '../redux/combineReducers' import viewUpdate from '../redux/viewUpdate/reducer' - -const checkSelectedProps = (state)=>{ - let isMultiple,withFolder,withFile=false; - isMultiple = (state.selected.length>1); - // eslint-disable-next-line - state.selected.map((value)=>{ - if(value.type==="dir"){ - withFolder = true; - }else if(value.type==="file"){ - withFile = true; - } - }) - return [isMultiple,withFolder,withFile]; -} +import explorer from '../redux/explorer/reducer' const doNavigate = (path, state)=>{ window.currntPath = path; @@ -23,15 +10,6 @@ const doNavigate = (path, state)=>{ navigator:Object.assign({}, state.navigator, { path: path }), - explorer:Object.assign({}, state.explorer, { - selected:[], - selectProps: { - isMultiple:false, - withFolder:false, - withFile:false, - }, - keywords:null, - }), }); } @@ -89,29 +67,6 @@ export const initState = { path: "/", refresh: true }, - explorer: { - dndSignal:false, - dndTarget:null, - dndSource:null, - fileList: [], - dirList: [], - selected: [], - selectProps: { - isMultiple: false, - withFolder: false, - withFile: false - }, - lastSelect: { - file: null, - index: -1, - }, - shiftSelectedIds: [], - imgPreview: { - first: null, - other: [] - }, - keywords: null - } } const defaultStatus = InitSiteConfig(initState); @@ -119,142 +74,10 @@ const defaultStatus = InitSiteConfig(initState); // TODO: 将cloureveApp切分成小的reducer const cloudreveApp = (state = defaultStatus, action) => { switch (action.type) { - case 'CHANGE_SORT_METHOD': - let list = [...state.explorer.fileList,...state.explorer.dirList]; - // eslint-disable-next-line - list.sort((a,b)=>{ - switch (action.method) { - case "sizePos": - return a.size-b.size; - case "sizeRes": - return b.size-a.size; - case 'namePos': - return a.name.localeCompare(b.name); - case 'nameRev': - return b.name.localeCompare(a.name); - case 'timePos': - return Date.parse(a.date)-Date.parse(b.date); - case 'timeRev': - return Date.parse(b.date)-Date.parse(a.date); - default: - break; - } - }) - var dirList = list.filter(function (x) { - return x.type === "dir"; - }); - var fileList = list.filter(function (x) { - return x.type === "file"; - }); - - return Object.assign({}, state, { - explorer: Object.assign({}, state.explorer, { - fileList: fileList, - dirList: dirList, - }), - }); - case 'DRAG_AND_DROP': - return Object.assign({}, state, { - explorer: Object.assign({}, state.explorer, { - dndSignal: !state.explorer.dndSignal, - dndTarget:action.target, - dndSource:action.source, - }), - }); - case 'UPDATE_FILE_LIST': - // eslint-disable-next-line - action.list.sort((a,b)=>{ - switch (state.viewUpdate.sortMethod) { - case "sizePos": - return a.size-b.size; - case "sizeRes": - return b.size-a.size; - case 'namePos': - return a.name.localeCompare(b.name); - case 'nameRev': - return b.name.localeCompare(a.name); - case 'timePos': - return Date.parse(a.date)-Date.parse(b.date); - case 'timeRev': - return Date.parse(b.date)-Date.parse(a.date); - default: - break; - } - }) - // eslint-disable-next-line - var dirList = action.list.filter(function (x) { - return x.type === "dir"; - }); - // eslint-disable-next-line - var fileList = action.list.filter(function (x) { - return x.type === "file"; - }); - return Object.assign({}, state, { - explorer: Object.assign({}, state.explorer, { - fileList: fileList, - dirList: dirList, - }), - }); - case 'ADD_SELECTED_TARGETS': - var newState = Object.assign({}, state, { - explorer:Object.assign({}, state.explorer, { - selected: [...state.explorer.selected,...action.targets] - }), - }); - var selectedProps = checkSelectedProps(newState.explorer); - return Object.assign({}, newState, { - explorer:Object.assign({}, newState.explorer, { - selectProps: { - isMultiple:selectedProps[0], - withFolder:selectedProps[1], - withFile:selectedProps[2], - } - }), - }); - case 'SET_SELECTED_TARGET': - // eslint-disable-next-line - var newState = Object.assign({}, state, { - explorer:Object.assign({}, state.explorer, { - selected: action.targets - }), - }); - // eslint-disable-next-line - var selectedProps = checkSelectedProps(newState.explorer); - return Object.assign({}, newState, { - explorer:Object.assign({}, newState.explorer, { - selectProps: { - isMultiple:selectedProps[0], - withFolder:selectedProps[1], - withFile:selectedProps[2], - } - }), - }); - case 'RMOVE_SELECTED_TARGETS': - const { fileIds } = action - const newSelected = state.explorer.selected.filter((file) => { - return !fileIds.includes(file.id) - }) - // eslint-disable-next-line - var newState = Object.assign({}, state, { - explorer:Object.assign({}, state.explorer, { - selected: newSelected - }), - }); - // eslint-disable-next-line - var selectedProps = checkSelectedProps(newState.explorer); - return Object.assign({}, newState, { - explorer:Object.assign({}, newState.explorer, { - selectProps: { - isMultiple:selectedProps[0], - withFolder:selectedProps[1], - withFile:selectedProps[2], - } - }), - }); - case 'NAVIGATOR_TO': + case 'SET_NAVIGATOR': return doNavigate(action.path,state); case 'TOGGLE_DAYLIGHT_MODE':{ - let copy = Object.assign({}, state); + const copy = Object.assign({}, state); if (copy.siteConfig.theme.palette.type === undefined || copy.siteConfig.theme.palette.type === "light"){ return { ...state, @@ -286,7 +109,7 @@ const cloudreveApp = (state = defaultStatus, action) => { } case 'APPLY_THEME': if (state.siteConfig.themes !== null){ - let themes = JSON.parse(state.siteConfig.themes); + const themes = JSON.parse(state.siteConfig.themes); if (themes[action.theme] === undefined){ return state; } @@ -308,14 +131,6 @@ const cloudreveApp = (state = defaultStatus, action) => { navigator: Object.assign({}, state.navigator, { refresh:!state.navigator.refresh, }), - explorer:Object.assign({}, state.explorer, { - selected:[], - selectProps: { - isMultiple:false, - withFolder:false, - withFile:false, - } - }), }); case 'SEARCH_MY_FILE': return Object.assign({}, state, { @@ -323,61 +138,16 @@ const cloudreveApp = (state = defaultStatus, action) => { path: "/搜索结果", refresh:state.explorer.keywords === null? state.navigator.refresh:!state.navigator.refresh, }), - explorer:Object.assign({}, state.explorer, { - selected:[], - selectProps: { - isMultiple:false, - withFolder:false, - withFile:false, - }, - keywords:action.keywords, - }), }); - case 'SHOW_IMG_PREIVEW': - return Object.assign({}, state, { - explorer:Object.assign({}, state.explorer, { - imgPreview: { - first:action.first, - other:state.explorer.fileList, - }, - }), - }); - case 'SAVE_FILE': - return Object.assign({}, state, { - explorer:Object.assign({}, state.explorer, { - fileSave:!state.explorer.fileSave, - }), - }); - case 'SET_LAST_SELECT': - const { file, index } = action - return { - ...state, - explorer: { - ...state.explorer, - lastSelect: { - file, - index, - }, - } - } - case 'SET_SHIFT_SELECTED_IDS': - const { shiftSelectedIds } = action - return { - ...state, - explorer: { - ...state.explorer, - shiftSelectedIds, - } - } default: return state } } export default (state, action) => { - const { viewUpdate: viewUpdateState } = state || {} + const { viewUpdate: viewUpdateState, explorer: explorerState } = state || {} const appState = cloudreveApp(state, action) - const combinedState = combineReducers({ viewUpdate })({ viewUpdate: viewUpdateState }, action) + const combinedState = combineReducers({ viewUpdate, explorer })({ viewUpdate: viewUpdateState, explorer: explorerState }, action) return { ...appState, ...combinedState, diff --git a/src/reducers/index.test.js b/src/reducers/index.test.js index 4c739f7..7d925b4 100644 --- a/src/reducers/index.test.js +++ b/src/reducers/index.test.js @@ -2,12 +2,13 @@ import configureMockStore from 'redux-mock-store' import thunk from 'redux-thunk' import cloudreveApp, { initState as cloudreveState } from './index' import { initState as viewUpdateState } from '../redux/viewUpdate/reducer' +import { initState as explorerState } from '../redux/explorer/reducer' import { setModalsLoading, openLoadingDialog, openGetSourceDialog, openShareDialog, openMoveDialog, navigateUp, navigateTo, - drawerToggleAction, changeViewMethod, changeSortMethod, + drawerToggleAction, changeViewMethod, changeContextMenu, dragAndDrop, setNavigatorLoadingStatus, - setNavigatorError, updateFileList, addSelectedTargets, + setNavigatorError, addSelectedTargets, setNavigator, setSelectedTarget, removeSelectedTargets, toggleDaylightMode, applyThemes, openCreateFolderDialog, openRenameDialog, openRemoveDialog, openResaveDialog, setUserPopover, @@ -18,12 +19,13 @@ import { setModalsLoading, openLoadingDialog, openGetSourceDialog, enableLoadUploader, refreshFileList, searchMyFile, showImgPreivew, refreshStorage, saveFile, setLastSelect, setShiftSelectedIds } from '../actions/index' -import { changeSubTitle } from "../redux/viewUpdate/action" - +import { changeSubTitle, setSubtitle } from "../redux/viewUpdate/action" +import { updateFileList, setFileList, setDirList, setSortMethod, changeSortMethod } from "../redux/explorer/action" const initState = { ...cloudreveState, viewUpdate: viewUpdateState, + explorer: explorerState, } const middlewares = [thunk] const mockStore = configureMockStore(middlewares) @@ -68,6 +70,17 @@ describe('index reducer', () => { }) }) + it('should handle SET_SORT_METHOD', () => { + const action = setSortMethod('sizeRes') + expect(cloudreveApp(initState, action)).toEqual({ + ...initState, + viewUpdate: { + ...initState.viewUpdate, + sortMethod: 'sizeRes', + } + }) + }) + describe('CHANGE_SORT_METHOD', () => { const explorerState = { fileList: [{ @@ -103,178 +116,108 @@ describe('index reducer', () => { date: "2020/04/29" }], } - it('should handle sizePos', () => { + + const state = { + ...initState, + explorer: { + ...initState.explorer, + ...explorerState, + }, + } + it('should handle sizePos', async () => { const action = changeSortMethod('sizePos') const sortFunc = (a, b) => { return a.size-b.size } - const expectState = { - fileList: explorerState.fileList.sort(sortFunc), - dirList: explorerState.dirList.sort(sortFunc), - } - expect(cloudreveApp({ - ...initState, - explorer: { - ...initState.explorer, - ...explorerState, - }, - }, action)).toEqual({ - ...initState, - viewUpdate: { - ...initState.viewUpdate, - sortMethod: 'sizePos', - }, - explorer: { - ...initState.explorer, - fileList: expectState.fileList, - dirList: expectState.dirList, - } - }) + const fileList = explorerState.fileList + const dirList = explorerState.dirList + const store = mockStore(state) + await store.dispatch(action) + expect(store.getActions()).toEqual([ + setSortMethod('sizePos'), + setDirList(dirList.sort(sortFunc)), + setFileList(fileList.sort(sortFunc)), + ]) }) - it('should handle sizeRes', () => { - const action = changeSortMethod('sizeRes') + it('should handle sizeRes', async () => { + const action = changeSortMethod('sizePos') const sortFunc = (a, b) => { return b.size-a.size } - const expectState = { - fileList: explorerState.fileList.sort(sortFunc), - dirList: explorerState.dirList.sort(sortFunc), - } - expect(cloudreveApp({ - ...initState, - explorer: { - ...initState.explorer, - ...explorerState, - }, - }, action)).toEqual({ - ...initState, - viewUpdate: { - ...initState.viewUpdate, - sortMethod: 'sizeRes', - }, - explorer: { - ...initState.explorer, - fileList: expectState.fileList, - dirList: expectState.dirList, - } - }) + const fileList = explorerState.fileList + const dirList = explorerState.dirList + const store = mockStore(state) + await store.dispatch(action) + expect(store.getActions()).toEqual([ + setSortMethod('sizePos'), + setDirList(dirList.sort(sortFunc)), + setFileList(fileList.sort(sortFunc)), + ]) }) - it('should handle namePos', () => { + it('should handle namePos', async () => { const action = changeSortMethod('namePos') const sortFunc = (a, b) => { return a.name.localeCompare(b.name) } - const expectState = { - fileList: explorerState.fileList.sort(sortFunc), - dirList: explorerState.dirList.sort(sortFunc), - } - expect(cloudreveApp({ - ...initState, - explorer: { - ...initState.explorer, - ...explorerState, - }, - }, action)).toEqual({ - ...initState, - viewUpdate: { - ...initState.viewUpdate, - sortMethod: 'namePos', - }, - explorer: { - ...initState.explorer, - fileList: expectState.fileList, - dirList: expectState.dirList, - } - }) + const fileList = explorerState.fileList + const dirList = explorerState.dirList + const store = mockStore(state) + await store.dispatch(action) + expect(store.getActions()).toEqual([ + setSortMethod('namePos'), + setDirList(dirList.sort(sortFunc)), + setFileList(fileList.sort(sortFunc)), + ]) }) - it('should handle nameRev', () => { + it('should handle nameRev', async () => { const action = changeSortMethod('nameRev') const sortFunc = (a, b) => { return b.name.localeCompare(a.name) } - const expectState = { - fileList: explorerState.fileList.sort(sortFunc), - dirList: explorerState.dirList.sort(sortFunc), - } - expect(cloudreveApp({ - ...initState, - explorer: { - ...initState.explorer, - ...explorerState, - }, - }, action)).toEqual({ - ...initState, - viewUpdate: { - ...initState.viewUpdate, - sortMethod: 'nameRev', - }, - explorer: { - ...initState.explorer, - fileList: expectState.fileList, - dirList: expectState.dirList, - } - }) + const fileList = explorerState.fileList + const dirList = explorerState.dirList + const store = mockStore(state) + await store.dispatch(action) + expect(store.getActions()).toEqual([ + setSortMethod('nameRev'), + setDirList(dirList.sort(sortFunc)), + setFileList(fileList.sort(sortFunc)), + ]) }) - it('should handle timePos', () => { + it('should handle timePos', async () => { const action = changeSortMethod('timePos') const sortFunc = (a, b) => { return Date.parse(a.date)-Date.parse(b.date) } - const expectState = { - fileList: explorerState.fileList.sort(sortFunc), - dirList: explorerState.dirList.sort(sortFunc), - } - expect(cloudreveApp({ - ...initState, - explorer: { - ...initState.explorer, - ...explorerState, - }, - }, action)).toEqual({ - ...initState, - viewUpdate: { - ...initState.viewUpdate, - sortMethod: 'timePos', - }, - explorer: { - ...initState.explorer, - fileList: expectState.fileList, - dirList: expectState.dirList, - } - }) + const fileList = explorerState.fileList + const dirList = explorerState.dirList + const store = mockStore(state) + await store.dispatch(action) + expect(store.getActions()).toEqual([ + setSortMethod('timePos'), + setDirList(dirList.sort(sortFunc)), + setFileList(fileList.sort(sortFunc)), + ]) }) - it('should handle timeRev', () => { + it('should handle timeRev', async () => { const action = changeSortMethod('timeRev') const sortFunc = (a, b) => { return Date.parse(b.date)-Date.parse(a.date) } - const expectState = { - fileList: explorerState.fileList.sort(sortFunc), - dirList: explorerState.dirList.sort(sortFunc), - } - expect(cloudreveApp({ - ...initState, - explorer: { - ...initState.explorer, - ...explorerState, - }, - }, action)).toEqual({ - ...initState, - viewUpdate: { - ...initState.viewUpdate, - sortMethod: 'timeRev', - }, - explorer: { - ...initState.explorer, - fileList: expectState.fileList, - dirList: expectState.dirList, - } - }) + const fileList = explorerState.fileList + const dirList = explorerState.dirList + const store = mockStore(state) + await store.dispatch(action) + expect(store.getActions()).toEqual([ + setSortMethod('timeRev'), + setDirList(dirList.sort(sortFunc)), + setFileList(fileList.sort(sortFunc)), + ]) }) }) @@ -368,9 +311,8 @@ describe('index reducer', () => { size: 110, date: "2020/04/29" }] - const fileAction = updateFileList(fileList) - const dirAction = updateFileList(dirList) - it('should handle sizePos', () => { + const updateAction = updateFileList([...fileList, ...dirList]) + it('should handle sizePos', async () => { const sortFun = (a, b) => { return a.size-b.size } @@ -381,23 +323,15 @@ describe('index reducer', () => { sortMethod: 'sizePos' } } - expect(cloudreveApp(state, fileAction)).toEqual({ - ...state, - explorer: { - ...initState.explorer, - fileList: fileList.sort(sortFun), - } - }) - expect(cloudreveApp(state, dirAction)).toEqual({ - ...state, - explorer: { - ...initState.explorer, - dirList: dirList.sort(sortFun), - } - }) + const store = mockStore(state) + await store.dispatch(updateAction) + expect(store.getActions()).toEqual([ + setDirList(dirList.sort(sortFun)), + setFileList(fileList.sort(sortFun)), + ]) }) - it('should handle sizeRes', () => { + it('should handle sizeRes', async () => { const sortFun = (a, b) => { return b.size-a.size } @@ -408,23 +342,15 @@ describe('index reducer', () => { sortMethod: 'sizeRes' } } - expect(cloudreveApp(state, fileAction)).toEqual({ - ...state, - explorer: { - ...initState.explorer, - fileList: fileList.sort(sortFun), - } - }) - expect(cloudreveApp(state, dirAction)).toEqual({ - ...state, - explorer: { - ...initState.explorer, - dirList: dirList.sort(sortFun), - } - }) + const store = mockStore(state) + await store.dispatch(updateAction) + expect(store.getActions()).toEqual([ + setDirList(dirList.sort(sortFun)), + setFileList(fileList.sort(sortFun)), + ]) }) - it('should handle namePos', () => { + it('should handle namePos', async () => { const sortFun = (a, b) => { return a.name.localeCompare(b.name) } @@ -435,23 +361,15 @@ describe('index reducer', () => { sortMethod: 'namePos' } } - expect(cloudreveApp(state, fileAction)).toEqual({ - ...state, - explorer: { - ...initState.explorer, - fileList: fileList.sort(sortFun), - } - }) - expect(cloudreveApp(state, dirAction)).toEqual({ - ...state, - explorer: { - ...initState.explorer, - dirList: dirList.sort(sortFun), - } - }) + const store = mockStore(state) + await store.dispatch(updateAction) + expect(store.getActions()).toEqual([ + setDirList(dirList.sort(sortFun)), + setFileList(fileList.sort(sortFun)), + ]) }) - it('should handle nameRev', () => { + it('should handle nameRev', async () => { const sortFun = (a, b) => { return b.name.localeCompare(a.name) } @@ -462,23 +380,15 @@ describe('index reducer', () => { sortMethod: 'nameRev' } } - expect(cloudreveApp(state, fileAction)).toEqual({ - ...state, - explorer: { - ...initState.explorer, - fileList: fileList.sort(sortFun), - } - }) - expect(cloudreveApp(state, dirAction)).toEqual({ - ...state, - explorer: { - ...initState.explorer, - dirList: dirList.sort(sortFun), - } - }) + const store = mockStore(state) + await store.dispatch(updateAction) + expect(store.getActions()).toEqual([ + setDirList(dirList.sort(sortFun)), + setFileList(fileList.sort(sortFun)), + ]) }) - it('should handle timePos', () => { + it('should handle timePos', async () => { const sortFun = (a, b) => { return Date.parse(a.date)-Date.parse(b.date) } @@ -489,23 +399,15 @@ describe('index reducer', () => { sortMethod: 'timePos' } } - expect(cloudreveApp(state, fileAction)).toEqual({ - ...state, - explorer: { - ...initState.explorer, - fileList: fileList.sort(sortFun), - } - }) - expect(cloudreveApp(state, dirAction)).toEqual({ - ...state, - explorer: { - ...initState.explorer, - dirList: dirList.sort(sortFun), - } - }) + const store = mockStore(state) + await store.dispatch(updateAction) + expect(store.getActions()).toEqual([ + setDirList(dirList.sort(sortFun)), + setFileList(fileList.sort(sortFun)), + ]) }) - it('should handle timeRev', () => { + it('should handle timeRev', async () => { const sortFun = (a, b) => { return Date.parse(b.date)-Date.parse(a.date) } @@ -516,20 +418,70 @@ describe('index reducer', () => { sortMethod: 'timeRev' } } - expect(cloudreveApp(state, fileAction)).toEqual({ - ...state, - explorer: { - ...initState.explorer, - fileList: fileList.sort(sortFun), - } - }) - expect(cloudreveApp(state, dirAction)).toEqual({ - ...state, - explorer: { - ...initState.explorer, - dirList: dirList.sort(sortFun), - } - }) + const store = mockStore(state) + await store.dispatch(updateAction) + expect(store.getActions()).toEqual([ + setDirList(dirList.sort(sortFun)), + setFileList(fileList.sort(sortFun)), + ]) + }) + }) + + it('should handle SET_FILE_LIST', () => { + const action = setFileList([{ + type: 'file', + id: 'a' + }, { + type: 'file', + id: 'b' + }]) + expect(cloudreveApp({ + ...initState, + explorer: { + ...initState.explorer, + fileList: [{ type: 'file', id: 'test' }] + } + }, action)).toEqual({ + ...initState, + explorer: { + ...initState.explorer, + fileList: [{ + type: 'file', + id: 'a' + }, { + type: 'file', + id: 'b' + }] + } + }) + }) + + it('should handle SET_DIR_LIST', () => { + const action = setDirList([{ + type: 'dir', + id: 'a' + }, { + type: 'dir', + id: 'b' + }]) + expect(cloudreveApp({ + ...initState, + explorer: { + ...initState.explorer, + dirList: [{ type: 'dir', id: 'test' }] + } + }, action)).toEqual({ + ...initState, + explorer: { + ...initState.explorer, + dirList: [{ + type: 'dir', + id: 'a' + }, { + type: 'dir', + id: 'b' + }] + } }) }) @@ -614,31 +566,10 @@ describe('index reducer', () => { it('should handle NAVIGATOR_TO', async () => { const store = mockStore(initState) const action = navigateTo('/somewhere') - const navAction = await store.dispatch(action) - expect(cloudreveApp(initState, navAction)).toEqual({ - ...initState, - navigator: { - ...initState.navigator, - path: '/somewhere' - }, - viewUpdate: { - ...initState.viewUpdate, - contextOpen:false, - navigatorError:false, - navigatorLoading: true, - }, - explorer: { - ...initState.explorer, - selected: [], - selectProps: { - isMultiple:false, - withFolder:false, - withFile:false, - }, - keywords:null, - } - }) - expect(window.currntPath).toEqual('/somewhere') + await store.dispatch(action) + expect(store.getActions()).toEqual([ + setNavigator('/somewhere', true) + ]) }) it('should handle NAVIGATOR_UP', async () => { @@ -650,13 +581,27 @@ describe('index reducer', () => { } } const store = mockStore(navState) - const action = navigateUp('somewhere') - const navAction = await store.dispatch(action) - expect(cloudreveApp(navState, navAction)).toEqual({ + const action = navigateUp() + await store.dispatch(action) + expect(store.getActions()).toEqual([ + setNavigator('/to', true) + ]) + }) + + it('should handle SET_NAVIGATOR', () => { + const navState = { ...initState, navigator: { ...initState.navigator, - path: '/to' + path: '/to/somewhere' + } + } + const action = setNavigator('/newpath', true) + expect(cloudreveApp(navState, action)).toEqual({ + ...initState, + navigator: { + ...initState.navigator, + path: '/newpath' }, viewUpdate: { ...initState.viewUpdate, @@ -675,7 +620,7 @@ describe('index reducer', () => { keywords:null, } }) - expect(window.currntPath).toEqual('/to') + expect(window.currntPath).toEqual('/newpath') }) it('should handle TOGGLE_DAYLIGHT_MODE', () => { @@ -1018,15 +963,20 @@ describe('index reducer', () => { it('should handle CHANGE_SUB_TITLE', async () => { const store = mockStore(initState) const action = changeSubTitle('test sub title') - const changeSubtitleAction = await store.dispatch(action) - expect(cloudreveApp(initState, changeSubtitleAction)).toEqual({ + await store.dispatch(action) + expect(store.getActions()).toEqual([setSubtitle('test sub title')]) + expect(document.title).toEqual('test sub title - Cloudreve') + }) + + it('should handle SET_SUBTITLE', () => { + const action = setSubtitle('test sub title 2') + expect(cloudreveApp(initState, action)).toEqual({ ...initState, viewUpdate: { ...initState.viewUpdate, - subTitle: 'test sub title', + subTitle: 'test sub title 2', } }) - expect(document.title).toEqual('test sub title - Cloudreve') }) it('should handle TOGGLE_SNACKBAR', () => { diff --git a/src/redux/explorer/action.ts b/src/redux/explorer/action.ts new file mode 100644 index 0000000..01adb28 --- /dev/null +++ b/src/redux/explorer/action.ts @@ -0,0 +1,86 @@ +import { AnyAction } from 'redux' +import { ThunkAction } from 'redux-thunk' +import { CloudreveFile, SortMethod } from './../../types/index' + +export interface ActionSetFileList extends AnyAction { + type: 'SET_FILE_LIST'; + list: CloudreveFile[]; +} +export const setFileList = (list: CloudreveFile[]): ActionSetFileList => { + return { + type: 'SET_FILE_LIST', + list, + } +} + +export interface ActionSetDirList extends AnyAction { + type: 'SET_DIR_LIST'; + list: CloudreveFile[]; +} +export const setDirList = (list: CloudreveFile[]): ActionSetDirList => { + return { + type: 'SET_DIR_LIST', + list, + } +} + +export interface ActionSetSortMethod extends AnyAction { + type: 'SET_SORT_METHOD'; + method: SortMethod; +} +export const setSortMethod = (method: SortMethod): ActionSetSortMethod => { + return { + type: 'SET_SORT_METHOD', + method, + } +} +type SortFunc = (a: CloudreveFile, b: CloudreveFile) => number +const sortMethodFuncs: Record = { + sizePos: (a: CloudreveFile, b: CloudreveFile) => { + return a.size-b.size + }, + sizeRes: (a: CloudreveFile, b: CloudreveFile) => { + return b.size-a.size + }, + namePos: (a: CloudreveFile, b: CloudreveFile) => { + return a.name.localeCompare(b.name) + }, + nameRev: (a: CloudreveFile, b: CloudreveFile) => { + return b.name.localeCompare(a.name) + }, + timePos: (a: CloudreveFile, b: CloudreveFile) => { + return Date.parse(a.date)-Date.parse(b.date) + }, + timeRev: (a: CloudreveFile, b: CloudreveFile) => { + return Date.parse(b.date)-Date.parse(a.date) + }, +} + +export const updateFileList = (list: CloudreveFile[]): ThunkAction => { + return (dispatch, getState): void => { + const state = getState() + // TODO: define state type + const { sortMethod } = state.viewUpdate + const dirList = list.filter((x) => { + return x.type === "dir"; + }) + const fileList = list.filter((x) => { + return x.type === "file"; + }) + const sortFunc = sortMethodFuncs[sortMethod as SortMethod] + dispatch(setDirList(dirList.sort(sortFunc))) + dispatch(setFileList(fileList.sort(sortFunc))) + } +} + +export const changeSortMethod = (method: SortMethod): ThunkAction => { + return (dispatch, getState): void => { + const state = getState() + const { fileList, dirList } = state.explorer + const sortFunc = sortMethodFuncs[method] + dispatch(setSortMethod(method)) + dispatch(setDirList(dirList.sort(sortFunc))) + dispatch(setFileList(fileList.sort(sortFunc))) + } +}; + diff --git a/src/redux/explorer/index.ts b/src/redux/explorer/index.ts new file mode 100644 index 0000000..d23fc0b --- /dev/null +++ b/src/redux/explorer/index.ts @@ -0,0 +1,7 @@ +import * as actions from './action' +import * as reducers from './reducer' + +export default { + actions, + reducers, +} diff --git a/src/redux/explorer/reducer.ts b/src/redux/explorer/reducer.ts new file mode 100644 index 0000000..6109435 --- /dev/null +++ b/src/redux/explorer/reducer.ts @@ -0,0 +1,186 @@ +/* eslint-disable no-case-declarations */ +import { AnyAction } from "redux" +import { CloudreveFile } from "../../types"; + +interface SelectProps { + isMultiple: boolean; + withFolder: boolean; + withFile: boolean; +} + +export interface ExplorerState { + dndSignal: boolean; + dndTarget: any; + dndSource: any; + fileList: CloudreveFile[]; + dirList: CloudreveFile[]; + selected: CloudreveFile[]; + selectProps: SelectProps; + lastSelect: { + file: CloudreveFile; + index: number; + }; + shiftSelectedIds: string[]; + imgPreview: { + first: CloudreveFile; + other: []; + }; + keywords: string; + fileSave: boolean; +} + +export const initState: ExplorerState = { + dndSignal: false, + dndTarget: null, + dndSource: null, + fileList: [], + dirList: [], + selected: [], + selectProps: { + isMultiple: false, + withFolder: false, + withFile: false + }, + lastSelect: { + file: { + id: '', + name: '', + size: 0, + type: 'file', + date: '' + }, + index: -1, + }, + shiftSelectedIds: [], + imgPreview: { + first: { + id: '', + name: '', + size: 0, + type: 'file', + date: '' + }, + other: [] + }, + keywords: '', + fileSave: false +} + +const checkSelectedProps = (selected: CloudreveFile[]): SelectProps =>{ + const isMultiple = selected.length > 1; + let withFolder = false + let withFile = false + selected.forEach((value)=>{ + if(value.type === "dir"){ + withFolder = true; + }else if(value.type === "file"){ + withFile = true; + } + }) + return { + isMultiple, + withFolder, + withFile, + } +} + +const explorer = (state: ExplorerState = initState, action: AnyAction): ExplorerState => { + switch (action.type) { + case 'DRAG_AND_DROP': + return Object.assign({}, state, { + dndSignal: !state.dndSignal, + dndTarget: action.target, + dndSource: action.source, + }); + case 'SET_FILE_LIST': + return Object.assign({}, state, { + fileList: action.list, + }); + case 'SET_DIR_LIST': + return Object.assign({}, state, { + dirList: action.list, + }); + case 'ADD_SELECTED_TARGETS': + const addedSelected = [...state.selected,...action.targets] + return Object.assign({}, state, { + selected: addedSelected, + selectProps: checkSelectedProps(addedSelected) + }); + case 'SET_SELECTED_TARGET': + const newSelected = action.targets + return Object.assign({}, state, { + selected: newSelected, + selectProps: checkSelectedProps(newSelected) + }); + case 'RMOVE_SELECTED_TARGETS': + const { fileIds } = action + const filteredSelected = state.selected.filter((file) => { + return !fileIds.includes(file.id) + }) + return Object.assign({}, state, { + selected: filteredSelected, + selectProps: checkSelectedProps(filteredSelected) + }); + case 'REFRESH_FILE_LIST': + return Object.assign({}, state, { + selected:[], + selectProps: { + isMultiple: false, + withFolder: false, + withFile: false, + } + }); + case 'SEARCH_MY_FILE': + return Object.assign({}, state, { + selected:[], + selectProps: { + isMultiple: false, + withFolder: false, + withFile: false, + }, + keywords: action.keywords, + }); + case 'SHOW_IMG_PREIVEW': + return Object.assign({}, state, { + imgPreview: { + first: action.first, + other: state.fileList, + }, + }); + case 'SAVE_FILE': + return { + ...state, + fileSave: !state.fileSave, + } + case 'SET_LAST_SELECT': + const { file, index } = action + return { + ...state, + lastSelect: { + file, + index, + }, + } + case 'SET_SHIFT_SELECTED_IDS': + const { shiftSelectedIds } = action + return { + ...state, + shiftSelectedIds, + } + case 'SET_NAVIGATOR': + return { + ...state, + selected:[], + selectProps: { + isMultiple: false, + withFolder: false, + withFile: false, + }, + keywords: '', + } + default: + return state + } +} + +export default explorer \ No newline at end of file diff --git a/src/redux/viewUpdate/action.ts b/src/redux/viewUpdate/action.ts index 8041b8e..646dcbc 100644 --- a/src/redux/viewUpdate/action.ts +++ b/src/redux/viewUpdate/action.ts @@ -1,18 +1,22 @@ import { ThunkAction } from 'redux-thunk' +import { AnyAction } from 'redux' +export interface ActionSetSubtitle extends AnyAction { + type: "SET_SUBTITLE"; + title: string; +} -export interface ACTION_CHANGE_SUBTITLE { - type: "CHANGE_SUB_TITLE", - title: string, +export const setSubtitle = (title: string): ActionSetSubtitle => { + return { + type: 'SET_SUBTITLE', + title, + } } export const changeSubTitle = (title: string): -ThunkAction => { +ThunkAction => { return (dispatch, getState) => { const state = getState() document.title = (title === null || title === undefined) ? state.siteConfig.title : (title + " - " +state.siteConfig.title); - return dispatch({ - type: "CHANGE_SUB_TITLE", - title: title - }) + dispatch(setSubtitle(title)) } } diff --git a/src/redux/viewUpdate/reducer.ts b/src/redux/viewUpdate/reducer.ts index d2a0bcd..3d4b0ce 100644 --- a/src/redux/viewUpdate/reducer.ts +++ b/src/redux/viewUpdate/reducer.ts @@ -2,45 +2,45 @@ import { AnyAction } from "redux" import Auth from "../../middleware/Auth" export interface ViewUpdateState { - isLogin: boolean, - loadUploader:boolean, - open: boolean, - explorerViewMethod: string, - sortMethod: string, - subTitle: string | null, - contextType: string, - contextOpen: boolean, - menuOpen: boolean, - navigatorLoading: boolean, - navigatorError: boolean, - navigatorErrorMsg: string | null, - modalsLoading: boolean, - storageRefresh: boolean, - userPopoverAnchorEl: any, - shareUserPopoverAnchorEl: any, + isLogin: boolean; + loadUploader: boolean; + open: boolean; + explorerViewMethod: string; + sortMethod: 'sizePos' | 'sizeRes' | 'namePos' | 'nameRev' | 'timePos' | 'timeRev'; + subTitle: string | null; + contextType: string; + contextOpen: boolean; + menuOpen: boolean; + navigatorLoading: boolean; + navigatorError: boolean; + navigatorErrorMsg: string | null; + modalsLoading: boolean; + storageRefresh: boolean; + userPopoverAnchorEl: any; + shareUserPopoverAnchorEl: any; modals: { - createNewFolder: boolean, - createNewFile: boolean, - rename: boolean, - move: boolean, - remove: boolean, - share: boolean, - music: boolean, - remoteDownload: boolean, - torrentDownload: boolean, - getSource: boolean, - copy:boolean, - resave: boolean, - compress:boolean, - decompress:boolean, - }, + createNewFolder: boolean; + createNewFile: boolean; + rename: boolean; + move: boolean; + remove: boolean; + share: boolean; + music: boolean; + remoteDownload: boolean; + torrentDownload: boolean; + getSource: boolean; + copy: boolean; + resave: boolean; + compress: boolean; + decompress: boolean; + }; snackbar: { - toggle: boolean, - vertical: string, - horizontal: string, - msg: string, - color: string - } + toggle: boolean; + vertical: string; + horizontal: string; + msg: string; + color: string; + }; } export const initState: ViewUpdateState = { // 是否登录 @@ -279,28 +279,22 @@ const viewUpdate = (state: ViewUpdateState = initState, action: AnyAction) => { contextOpen: action.open, contextType: action.menuType, }); - case 'CHANGE_SUB_TITLE': + case 'SET_SUBTITLE': return Object.assign({}, state, { subTitle: action.title, }); - case 'CHANGE_SORT_METHOD': + case 'SET_SORT_METHOD': return { ...state, sortMethod: action.method } - case 'NAVIGATOR_TO': + case 'SET_NAVIGATOR': return { ...state, contextOpen:false, navigatorError:false, navigatorLoading: action.navigatorLoading } - // case 'NAVIGATOR_TO': - // return Object.assign({}, state, { - // contextOpen:false, - // navigatorError:false, - // navigatorLoading:true, - // }) default: return state } diff --git a/src/serviceWorker.js b/src/serviceWorker.js index f8c7e50..42aa0d1 100644 --- a/src/serviceWorker.js +++ b/src/serviceWorker.js @@ -9,51 +9,6 @@ // To learn more about the benefits of this model and instructions on how to // opt-in, read https://bit.ly/CRA-PWA - -const isLocalhost = Boolean( - window.location.hostname === 'localhost' || - // [::1] is the IPv6 localhost address. - window.location.hostname === '[::1]' || - // 127.0.0.1/8 is considered localhost for IPv4. - window.location.hostname.match( - /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ - ) -); - -export function register(config) { - if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { - // The URL constructor is available in all browsers that support SW. - const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); - if (publicUrl.origin !== window.location.origin) { - // Our service worker won't work if PUBLIC_URL is on a different origin - // from what our page is served on. This might happen if a CDN is used to - // serve assets; see https://github.com/facebook/create-react-app/issues/2374 - return; - } - - window.addEventListener('load', () => { - const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; - - if (isLocalhost) { - // This is running on localhost. Let's check if a service worker still exists or not. - checkValidServiceWorker(swUrl, config); - - // Add some additional logging to localhost, pointing developers to the - // service worker/PWA documentation. - navigator.serviceWorker.ready.then(() => { - console.log( - 'This web app is being served cache-first by a service ' + - 'worker. To learn more, visit https://bit.ly/CRA-PWA' - ); - }); - } else { - // Is not localhost. Just register service worker - registerValidSW(swUrl, config); - } - }); - } -} - function registerValidSW(swUrl, config) { navigator.serviceWorker .register(swUrl) @@ -126,6 +81,50 @@ function checkValidServiceWorker(swUrl, config) { }); } +const isLocalhost = Boolean( + window.location.hostname === 'localhost' || + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.1/8 is considered localhost for IPv4. + window.location.hostname.match( + /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ + ) +); + +export function register(config) { + if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + // The URL constructor is available in all browsers that support SW. + const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); + if (publicUrl.origin !== window.location.origin) { + // Our service worker won't work if PUBLIC_URL is on a different origin + // from what our page is served on. This might happen if a CDN is used to + // serve assets; see https://github.com/facebook/create-react-app/issues/2374 + return; + } + + window.addEventListener('load', () => { + const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; + + if (isLocalhost) { + // This is running on localhost. Let's check if a service worker still exists or not. + checkValidServiceWorker(swUrl, config); + + // Add some additional logging to localhost, pointing developers to the + // service worker/PWA documentation. + navigator.serviceWorker.ready.then(() => { + console.log( + 'This web app is being served cache-first by a service ' + + 'worker. To learn more, visit https://bit.ly/CRA-PWA' + ); + }); + } else { + // Is not localhost. Just register service worker + registerValidSW(swUrl, config); + } + }); + } +} + export function unregister() { if ('serviceWorker' in navigator) { navigator.serviceWorker.ready.then(registration => { diff --git a/src/setupProxy.js b/src/setupProxy.js index 3fdf3b0..c985b7b 100644 --- a/src/setupProxy.js +++ b/src/setupProxy.js @@ -1,9 +1,10 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ const proxy = require('http-proxy-middleware'); module.exports = function(app) { app.use( '/api', proxy({ - target: 'http://localhost:5000', + target: 'http://localhost:5212', changeOrigin: true, }) ); @@ -11,7 +12,7 @@ module.exports = function(app) { app.use( '/custom', proxy({ - target: 'http://localhost:5000', + target: 'http://localhost:5212', changeOrigin: true, }) ); diff --git a/src/types/index.ts b/src/types/index.ts new file mode 100644 index 0000000..a9810c5 --- /dev/null +++ b/src/types/index.ts @@ -0,0 +1,9 @@ +export interface CloudreveFile { + id: string, + name: string, + size: number, + date: string, + type: 'up' | 'file' | 'dir' +} + +export type SortMethod = 'sizePos' | 'sizeRes' | 'namePos' | 'nameRev' | 'timePos' | 'timeRev' \ No newline at end of file diff --git a/src/utils/index.js b/src/utils/index.js index 08f0e25..b7fa49c 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -1,31 +1,31 @@ export const sizeToString = bytes => { if (bytes === 0 || bytes==="0") return "0 B"; - var k = 1024; - var sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; - var i = Math.floor(Math.log(bytes) / Math.log(k)); + const k = 1024; + const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; + const i = Math.floor(Math.log(bytes) / Math.log(k)); return (bytes / Math.pow(k, i)).toFixed(1) + " " + sizes[i]; }; export const fixUrlHash = path => { - var relativePath = path.split("#"); - var url = new URL("http://example.com/" + relativePath[1]); + const relativePath = path.split("#"); + const url = new URL("http://example.com/" + relativePath[1]); return url.toString(); }; export const setCookie = (name, value, days) => { if (days) { - var date = new Date(); + const date = new Date(); date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000); } document.cookie = name + "=" + (value || "") + "; path=/"; }; export const setGetParameter = (paramName, paramValue) => { - var url = window.location.href; + let url = window.location.href; if (url.indexOf(paramName + "=") >= 0) { - var prefix = url.substring(0, url.indexOf(paramName)); - var suffix = url.substring(url.indexOf(paramName)); + const prefix = url.substring(0, url.indexOf(paramName)); + let suffix = url.substring(url.indexOf(paramName)); suffix = suffix.substring(suffix.indexOf("=") + 1); suffix = suffix.indexOf("&") >= 0 @@ -58,21 +58,21 @@ export const allowSharePreview = () => { }; export const checkGetParameters = field => { - var url = window.location.href; + const url = window.location.href; if (url.indexOf("?" + field + "=") !== -1) return true; else if (url.indexOf("&" + field + "=") !== -1) return true; return false; }; export const changeThemeColor = color => { - var metaThemeColor = window.document.querySelector( + const metaThemeColor = window.document.querySelector( "meta[name=theme-color]" ); metaThemeColor.setAttribute("content", color); }; export const decode = c => { - var e = c.height, + let e = c.height, a = c.width, b = document.createElement("canvas"); b.height = e; @@ -81,7 +81,7 @@ export const decode = c => { b.drawImage(c, 0, 0); c = b.getImageData(0, 0, a, e); b = []; - for (var d = 0; d < a * e * 4; d += 4) + for (let d = 0; d < a * e * 4; d += 4) 0 !== (d + 4) % (4 * a) && [].push.apply(b, [].slice.call(c.data, d, d + 3)); c = e = 0; @@ -119,7 +119,7 @@ export function bufferEncode(value) { } export function pathBack(path) { - let folders = + const folders = path !== null ? path.substr(1).split("/") : this.props.path.substr(1).split("/"); @@ -151,20 +151,20 @@ export function pathJoin(parts, sep){ } export function basename(path){ - let pathList = path.split("/"); + const pathList = path.split("/"); pathList.pop() return pathList.join("/") === "" ? "/" : pathList.join("/") } export function transformTime(timestamp = +new Date()) { if (timestamp) { - var time = new Date(timestamp); - var y = time.getFullYear(); //getFullYear方法以四位数字返回年份 - var M = time.getMonth() + 1; // getMonth方法从 Date 对象返回月份 (0 ~ 11),返回结果需要手动加一 - var d = time.getDate(); // getDate方法从 Date 对象返回一个月中的某一天 (1 ~ 31) - var h = time.getHours(); // getHours方法返回 Date 对象的小时 (0 ~ 23) - var m = time.getMinutes(); // getMinutes方法返回 Date 对象的分钟 (0 ~ 59) - var s = time.getSeconds(); // getSeconds方法返回 Date 对象的秒数 (0 ~ 59) + const time = new Date(timestamp); + const y = time.getFullYear(); //getFullYear方法以四位数字返回年份 + const M = time.getMonth() + 1; // getMonth方法从 Date 对象返回月份 (0 ~ 11),返回结果需要手动加一 + const d = time.getDate(); // getDate方法从 Date 对象返回一个月中的某一天 (1 ~ 31) + const h = time.getHours(); // getHours方法返回 Date 对象的小时 (0 ~ 23) + const m = time.getMinutes(); // getMinutes方法返回 Date 对象的分钟 (0 ~ 59) + const s = time.getSeconds(); // getSeconds方法返回 Date 对象的秒数 (0 ~ 59) return y + '-' + M + '-' + d + ' ' + h + ':' + m + ':' + s; } else { return ''; @@ -172,10 +172,10 @@ export function transformTime(timestamp = +new Date()) { } export function randomStr(length) { - var result = ''; - var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - var charactersLength = characters.length; - for ( var i = 0; i < length; i++ ) { + let result = ''; + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + const charactersLength = characters.length; + for ( let i = 0; i < length; i++ ) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); } return result; @@ -195,6 +195,6 @@ export const isMac = () => { } export function vhCheck() { - let vh = window.innerHeight; + const vh = window.innerHeight; document.documentElement.style.setProperty('--vh', `${vh}px`); } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 219cec0..0131634 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,34 @@ { "compilerOptions": { + "lib": [ + "es6", + "dom" + ], "outDir": "./dist/", "sourceMap": true, "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, "esModuleInterop": true, - "module": "commonjs", - "target": "es6", - "jsx": "react" - } + "module": "ESNext", + "target": "ES2017", + "jsx": "react", + "removeComments": true, + "strictFunctionTypes": true, + "strictPropertyInitialization": true, + "strictBindCallApply": true, + "noImplicitReturns": true, + "alwaysStrict": true, + "declaration": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "moduleResolution": "node", + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "**/*.spec.ts" + ] } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 55cd803..fb1f309 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1116,6 +1116,16 @@ "@types/istanbul-reports" "^1.1.1" "@types/yargs" "^13.0.0" +"@jest/types@^25.5.0": + version "25.5.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d" + integrity sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^15.0.0" + chalk "^3.0.0" + "@material-ui/core@^4.9.0": version "4.9.0" resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.9.0.tgz#96ca3281ee06216d44fd4d0e306dbe0429eb2ebe" @@ -1406,11 +1416,24 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" +"@types/jest@^25.2.2": + version "25.2.2" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-25.2.2.tgz#6a752e7a00f69c3e790ea00c345029d5cefa92bf" + integrity sha512-aRctFbG8Pb7DSLzUt/fEtL3q/GKb9mretFuYhRub2J0q6NhzBYbx9HTQzHrWgBNIxYOlxGNVe6Z54cpbUt+Few== + dependencies: + jest-diff "^25.2.1" + pretty-format "^25.2.1" + "@types/json-schema@^7.0.3": version "7.0.3" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636" integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A== +"@types/node@^14.0.1": + version "14.0.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.1.tgz#5d93e0a099cd0acd5ef3d5bde3c086e1f49ff68c" + integrity sha512-FAYBGwC+W6F9+huFIDtn43cpy7+SzG+atzRiTfdp3inUKL2hXnd4rG8hylJLIh4+hqrQy1P17kvJByE/z825hA== + "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" @@ -1426,10 +1449,10 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== -"@types/react-dom@^16.9.7": - version "16.9.7" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.7.tgz#60844d48ce252d7b2dccf0c7bb937130e27c0cd2" - integrity sha512-GHTYhM8/OwUCf254WO5xqR/aqD3gC9kSTLpopWGpQLpnw23jk44RvMHsyUSEplvRJZdHxhJGMMLF0kCPYHPhQA== +"@types/react-dom@^16.9.8": + version "16.9.8" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.8.tgz#fe4c1e11dfc67155733dfa6aa65108b4971cb423" + integrity sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA== dependencies: "@types/react" "*" @@ -1440,18 +1463,10 @@ dependencies: "@types/react" "*" -"@types/react@*": - version "16.9.13" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.13.tgz#b3ea5dd443f4a680599e2abba8cc66f5e1ce0059" - integrity sha512-LikzRslbiufJYHyzbHSW0GrAiff8QYLMBFeZmSxzCYGXKxi8m/1PHX+rsVOwhr7mJNq+VIu2Dhf7U6mjFERK6w== - dependencies: - "@types/prop-types" "*" - csstype "^2.2.0" - -"@types/react@^16.x": - version "16.9.34" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.34.tgz#f7d5e331c468f53affed17a8a4d488cd44ea9349" - integrity sha512-8AJlYMOfPe1KGLKyHpflCg5z46n0b5DbRfqDksxBLBTUpB75ypDBAO9eCUcjNwE6LCUslwTz00yyG/X9gaVtow== +"@types/react@*", "@types/react@^16.9.35", "@types/react@^16.x": + version "16.9.35" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.35.tgz#a0830d172e8aadd9bd41709ba2281a3124bbd368" + integrity sha512-q0n0SsWcGc8nDqH2GJfWQWUOmZSJhXV64CjVN5SvcNti3TdEaA3AH0D8DwNmMdzjMAC/78tB8nAZIlV8yTz+zQ== dependencies: "@types/prop-types" "*" csstype "^2.2.0" @@ -1478,45 +1493,55 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^2.2.0": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.3.2.tgz#7e112ca0bb29044d915baf10163a8199a20f7c69" - integrity sha512-tcnpksq1bXzcIRbYLeXkgp6l+ggEMXXUcl1wsSvL807fRtmvVQKygElwEUf4hBA76dNag3VAK1q2m3vd7qJaZA== +"@types/yargs@^15.0.0": + version "15.0.5" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.5.tgz#947e9a6561483bdee9adffc983e91a6902af8b79" + integrity sha512-Dk/IDOPtOgubt/IaevIUbTgV7doaKkoorvOyYM2CMwuDyP89bekI7H4xLIwunNYiK9jhCkmc6pUrJk3cj2AB9w== dependencies: - "@typescript-eslint/experimental-utils" "2.3.2" - eslint-utils "^1.4.2" + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@^2.33.0": + version "2.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.33.0.tgz#d6c8319d5011b4783bb3d2dadf105d8bdd499bd5" + integrity sha512-QV6P32Btu1sCI/kTqjTNI/8OpCYyvlGjW5vD8MpTIg+HGE5S88HtT1G+880M4bXlvXj/NjsJJG0aGcVh0DdbeQ== + dependencies: + "@typescript-eslint/experimental-utils" "2.33.0" functional-red-black-tree "^1.0.1" - regexpp "^2.0.1" + regexpp "^3.0.0" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@2.3.2": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.3.2.tgz#e50f31264507e6fec7b33840bb6af260c24f4ea8" - integrity sha512-t+JGdTT6dRbmvKDlhlVkEueoZa0fhJNfG6z2cpnRPLwm3VwYr2BjR//acJGC1Yza0I9ZNcDfRY7ubQEvvfG6Jg== +"@typescript-eslint/experimental-utils@2.33.0": + version "2.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.33.0.tgz#000f1e5f344fbea1323dc91cc174805d75f99a03" + integrity sha512-qzPM2AuxtMrRq78LwyZa8Qn6gcY8obkIrBs1ehqmQADwkYzTE1Pb4y2W+U3rE/iFkSWcWHG2LS6MJfj6SmHApg== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "2.3.2" + "@typescript-eslint/typescript-estree" "2.33.0" eslint-scope "^5.0.0" + eslint-utils "^2.0.0" -"@typescript-eslint/parser@^2.2.0": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.3.2.tgz#e9b742e191cd1209930da469cde379591ad0af5b" - integrity sha512-nq1UQeNGdKdqdgF6Ww+Ov2OidWgiL96+JYdXXZ2rkP/OWyc6KMNSbs6MpRCpI8q+PmDa7hBnHNQIo7w/drYccA== +"@typescript-eslint/parser@^2.33.0": + version "2.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.33.0.tgz#395c0ef229ebef883608f8632a34f0acf02b9bdd" + integrity sha512-AUtmwUUhJoH6yrtxZMHbRUEMsC2G6z5NSxg9KsROOGqNXasM71I8P2NihtumlWTUCRld70vqIZ6Pm4E5PAziEA== dependencies: "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "2.3.2" - "@typescript-eslint/typescript-estree" "2.3.2" + "@typescript-eslint/experimental-utils" "2.33.0" + "@typescript-eslint/typescript-estree" "2.33.0" eslint-visitor-keys "^1.1.0" -"@typescript-eslint/typescript-estree@2.3.2": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.3.2.tgz#107414aa04e689fe6f7251eb63fb500217f2b7f4" - integrity sha512-eZNEAai16nwyhIVIEaWQlaUgAU3S9CkQ58qvK0+3IuSdLJD3W1PNuehQFMIhW/mTP1oFR9GNoTcLg7gtXz6lzA== +"@typescript-eslint/typescript-estree@2.33.0": + version "2.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.33.0.tgz#33504c050ccafd38f397a645d4e9534d2eccbb5c" + integrity sha512-d8rY6/yUxb0+mEwTShCQF2zYQdLlqihukNfG9IUlLYz5y1CH6G/9XYbrxQLq3Z14RNvkCC6oe+OcFlyUpwUbkg== dependencies: - glob "^7.1.4" + debug "^4.1.1" + eslint-visitor-keys "^1.1.0" + glob "^7.1.6" is-glob "^4.0.1" - lodash.unescape "4.0.1" - semver "^6.3.0" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" "@webassemblyjs/ast@1.8.5": version "1.8.5" @@ -1820,7 +1845,7 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.1.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== @@ -3665,6 +3690,11 @@ diff-sequences@^24.9.0: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5" integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew== +diff-sequences@^25.2.6: + version "25.2.6" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" + integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== + diffie-hellman@^5.0.0: version "5.0.3" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" @@ -4061,9 +4091,9 @@ escodegen@^1.11.0, escodegen@^1.9.1: source-map "~0.6.1" eslint-config-react-app@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-5.0.2.tgz#df40d73a1402986030680c040bbee520db5a32a4" - integrity sha512-VhlESAQM83uULJ9jsvcKxx2Ab0yrmjUt8kDz5DyhTQufqWE0ssAnejlWri5LXv25xoXfdqOyeDPdfJS9dXKagQ== + version "5.2.1" + resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-5.2.1.tgz#698bf7aeee27f0cea0139eaef261c7bf7dd623df" + integrity sha512-pGIZ8t0mFLcV+6ZirRgYK6RVqUIKRIi9MmgzUEmrIknsn3AdO0I32asO86dJgloHq+9ZPl8UIg8mYrvgP5u2wQ== dependencies: confusing-browser-globals "^1.0.9" @@ -4172,13 +4202,6 @@ eslint-scope@^5.0.0: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-utils@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab" - integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q== - dependencies: - eslint-visitor-keys "^1.0.0" - eslint-utils@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" @@ -4186,6 +4209,13 @@ eslint-utils@^1.4.3: dependencies: eslint-visitor-keys "^1.1.0" +eslint-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.0.0.tgz#7be1cc70f27a72a76cd14aa698bcabed6890e1cd" + integrity sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA== + dependencies: + eslint-visitor-keys "^1.1.0" + eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" @@ -4895,6 +4925,18 @@ glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + global-modules@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" @@ -6024,6 +6066,16 @@ jest-diff@^24.9.0: jest-get-type "^24.9.0" pretty-format "^24.9.0" +jest-diff@^25.2.1: + version "25.5.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.5.0.tgz#1dd26ed64f96667c068cef026b677dfa01afcfa9" + integrity sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A== + dependencies: + chalk "^3.0.0" + diff-sequences "^25.2.6" + jest-get-type "^25.2.6" + pretty-format "^25.5.0" + jest-docblock@^24.3.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.9.0.tgz#7970201802ba560e1c4092cc25cbedf5af5a8ce2" @@ -6079,6 +6131,11 @@ jest-get-type@^24.9.0: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e" integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q== +jest-get-type@^25.2.6: + version "25.2.6" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" + integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== + jest-haste-map@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.9.0.tgz#b38a5d64274934e21fa417ae9a9fbeb77ceaac7d" @@ -6816,11 +6873,6 @@ lodash.throttle@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= -lodash.unescape@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" - integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= - lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" @@ -8854,6 +8906,16 @@ pretty-format@^24.9.0: ansi-styles "^3.2.0" react-is "^16.8.4" +pretty-format@^25.2.1, pretty-format@^25.5.0: + version "25.5.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a" + integrity sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ== + dependencies: + "@jest/types" "^25.5.0" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^16.12.0" + private@^0.1.6: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -9213,6 +9275,11 @@ react-hotkeys@^2.0.0: dependencies: prop-types "^15.6.1" +react-is@^16.12.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.9.0: version "16.12.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" @@ -9569,6 +9636,11 @@ regexpp@^2.0.1: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== +regexpp@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" + integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== + regexpu-core@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.6.0.tgz#2037c18b327cfce8a6fea2a4ec441f2432afb8b6" @@ -9982,6 +10054,11 @@ semver@6.3.0, semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.3.2: + version "7.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" + integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== + send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -10970,10 +11047,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^3.8.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" - integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== +typescript@^3.9.2: + version "3.9.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.2.tgz#64e9c8e9be6ea583c54607677dd4680a1cf35db9" + integrity sha512-q2ktq4n/uLuNNShyayit+DTobV2ApPEo/6so68JaD5ojvc/6GClBipedB9zNWYxRSAlZXAe405Rlijzl6qDiSw== ua-parser-js@^0.7.18: version "0.7.20"