diff --git a/package.json b/package.json index aa8b89d..0ed36e2 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "axios": "^1.1.3", "dayjs": "1.11.5", "i18next": "^22.0.4", + "lodash-es": "^4.17.21", "monaco-editor": "^0.34.1", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -47,6 +48,7 @@ "@types/fs-extra": "^9.0.13", "@types/js-cookie": "^3.0.2", "@types/lodash": "^4.14.180", + "@types/lodash-es": "^4.17.7", "@types/react": "^17.0.0", "@types/react-dom": "^17.0.0", "@vitejs/plugin-react": "^2.0.1", diff --git a/src/locales/en.json b/src/locales/en.json index 93111e2..573e5f8 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -15,6 +15,7 @@ "global": "global", "direct": "direct", "script": "script", + "Profiles": "Profiles", "Profile URL": "Profile URL", "Import": "Import", @@ -34,6 +35,9 @@ "Refresh": "Refresh", "To Top": "To Top", "To End": "To End", + "Update All Profiles": "Update All Profiles", + "View Runtime Config": "View Runtime Config", + "Reactivate Profiles": "Reactivate Profiles", "Location": "Location", "Delay check": "Delay check", diff --git a/src/locales/zh.json b/src/locales/zh.json index 25a6212..b64ce7a 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -15,6 +15,7 @@ "global": "全局", "direct": "直连", "script": "脚本", + "Profiles": "配置", "Profile URL": "配置文件链接", "Import": "导入", @@ -34,6 +35,9 @@ "Refresh": "刷新", "To Top": "移到最前", "To End": "移到末尾", + "Update All Profiles": "更新所有配置", + "View Runtime Config": "查看运行时配置", + "Reactivate Profiles": "重新激活配置", "Location": "当前节点", "Delay check": "延迟测试", diff --git a/src/pages/profiles.tsx b/src/pages/profiles.tsx index ec423f1..1c10126 100644 --- a/src/pages/profiles.tsx +++ b/src/pages/profiles.tsx @@ -1,8 +1,13 @@ import useSWR, { mutate } from "swr"; -import { useLockFn } from "ahooks"; import { useMemo, useRef, useState } from "react"; +import { useLockFn } from "ahooks"; +import { useSetRecoilState } from "recoil"; import { Box, Button, Grid, IconButton, Stack, TextField } from "@mui/material"; -import { CachedRounded } from "@mui/icons-material"; +import { + LocalFireDepartmentRounded, + RefreshRounded, + TextSnippetOutlined, +} from "@mui/icons-material"; import { useTranslation } from "react-i18next"; import { getProfiles, @@ -10,9 +15,11 @@ import { enhanceProfiles, getRuntimeLogs, deleteProfile, + updateProfile, } from "@/services/cmds"; +import { atomLoadingCache } from "@/services/states"; import { closeAllConnections } from "@/services/api"; -import { BasePage, Notice } from "@/components/base"; +import { BasePage, DialogRef, Notice } from "@/components/base"; import { ProfileViewer, ProfileViewerRef, @@ -20,6 +27,8 @@ import { import { ProfileItem } from "@/components/profile/profile-item"; import { ProfileMore } from "@/components/profile/profile-more"; import { useProfiles } from "@/hooks/use-profiles"; +import { ConfigViewer } from "@/components/setting/mods/config-viewer"; +import { throttle } from "lodash-es"; const ProfilePage = () => { const { t } = useTranslation(); @@ -41,6 +50,7 @@ const ProfilePage = () => { const chain = profiles.chain || []; const viewerRef = useRef(null); + const configRef = useRef(null); // distinguish type const { regularItems, enhanceItems } = useMemo(() => { @@ -149,18 +159,65 @@ const ProfilePage = () => { mutateLogs(); }); + // 更新所有配置 + const setLoadingCache = useSetRecoilState(atomLoadingCache); + const onUpdateAll = useLockFn(async () => { + const throttleMutate = throttle(mutateProfiles, 2000, { + trailing: true, + }); + const updateOne = async (uid: string) => { + try { + await updateProfile(uid); + throttleMutate(); + } finally { + setLoadingCache((cache) => ({ ...cache, [uid]: false })); + } + }; + + return new Promise((resolve) => { + setLoadingCache((cache) => { + // 获取没有正在更新的配置 + const items = regularItems.filter( + (e) => e.type === "remote" && !cache[e.uid] + ); + const change = Object.fromEntries(items.map((e) => [e.uid, true])); + + Promise.allSettled(items.map((e) => updateOne(e.uid))).then(resolve); + return { ...cache, ...change }; + }); + }); + }); + return ( + + + + + configRef.current?.open()} + > + + + + - + } @@ -232,6 +289,7 @@ const ProfilePage = () => { )} mutateProfiles()} /> + ); }; diff --git a/yarn.lock b/yarn.lock index 75dddd4..ad799d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -869,6 +869,18 @@ resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-3.0.2.tgz#451eaeece64c6bdac8b2dde0caab23b085899e0d" integrity sha512-6+0ekgfusHftJNYpihfkMu8BWdeHs9EOJuGcSofErjstGPfPGEu9yTu4t460lTzzAMl2cM5zngQJqPMHbbnvYA== +"@types/lodash-es@^4.17.7": + version "4.17.7" + resolved "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.7.tgz#22edcae9f44aff08546e71db8925f05b33c7cc40" + integrity sha512-z0ptr6UI10VlU6l5MYhGwS4mC8DZyYer2mCoyysZtSF7p26zOX8UpbrV0YpNYLGS8K4PUFIyEr62IMFFjveSiQ== + dependencies: + "@types/lodash" "*" + +"@types/lodash@*": + version "4.14.191" + resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.191.tgz#09511e7f7cba275acd8b419ddac8da9a6a79e2fa" + integrity sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ== + "@types/lodash@^4.14.180": version "4.14.180" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.180.tgz#4ab7c9ddfc92ec4a887886483bc14c79fb380670" @@ -1722,6 +1734,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash-es@^4.17.21: + version "4.17.21" + resolved "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"