Files
clash-verge-rev-lite/src/components/setting/mods/clash-core-viewer.tsx
renovate[bot] 600b0b52f4 chore(deps): update npm dependencies (#4939)
* chore(deps): update npm dependencies

* Refactor components to use function syntax instead of forwardRef for better type handling and clarity. Updated imports and adjusted prop types accordingly across multiple viewer components including TrafficGraph, ProfileViewer, BackupViewer, ClashCoreViewer, ControllerViewer, DnsViewer, LiteModeViewer, NetworkInterfaceViewer, ThemeViewer, TunViewer, UpdateViewer, and WebUIViewer.

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Tunglies <77394545+Tunglies@users.noreply.github.com>
2025-10-04 20:26:10 +08:00

175 lines
4.8 KiB
TypeScript

import {
RestartAltRounded,
SwitchAccessShortcutRounded,
} from "@mui/icons-material";
import { LoadingButton } from "@mui/lab";
import {
Box,
Chip,
CircularProgress,
List,
ListItemButton,
ListItemText,
} from "@mui/material";
import { useLockFn } from "ahooks";
import type { Ref } from "react";
import { useImperativeHandle, useState } from "react";
import { useTranslation } from "react-i18next";
import { mutate } from "swr";
import { BaseDialog, DialogRef } from "@/components/base";
import { useVerge } from "@/hooks/use-verge";
import {
changeClashCore,
closeAllConnections,
forceRefreshClashConfig,
restartCore,
upgradeCore,
} from "@/services/cmds";
import { showNotice } from "@/services/noticeService";
const VALID_CORE = [
{ name: "Mihomo", core: "verge-mihomo", chip: "Release Version" },
{ name: "Mihomo Alpha", core: "verge-mihomo-alpha", chip: "Alpha Version" },
];
export function ClashCoreViewer({ ref }: { ref?: Ref<DialogRef> }) {
const { t } = useTranslation();
const { verge, mutateVerge } = useVerge();
const [open, setOpen] = useState(false);
const [upgrading, setUpgrading] = useState(false);
const [restarting, setRestarting] = useState(false);
const [changingCore, setChangingCore] = useState<string | null>(null);
useImperativeHandle(ref, () => ({
open: () => setOpen(true),
close: () => setOpen(false),
}));
const { clash_core = "verge-mihomo" } = verge ?? {};
const onCoreChange = useLockFn(async (core: string) => {
if (core === clash_core) return;
try {
setChangingCore(core);
closeAllConnections();
const errorMsg = await changeClashCore(core);
if (errorMsg) {
showNotice("error", errorMsg);
setChangingCore(null);
return;
}
mutateVerge();
setTimeout(async () => {
// 核心切换后强制刷新配置缓存
await forceRefreshClashConfig();
mutate("getClashConfig");
mutate("getVersion");
setChangingCore(null);
}, 500);
} catch (err: any) {
setChangingCore(null);
showNotice("error", err.message || err.toString());
}
});
const onRestart = useLockFn(async () => {
try {
setRestarting(true);
await restartCore();
showNotice("success", t(`Clash Core Restarted`));
setRestarting(false);
} catch (err: any) {
setRestarting(false);
showNotice("error", err.message || err.toString());
}
});
const onUpgrade = useLockFn(async () => {
try {
setUpgrading(true);
await upgradeCore();
setUpgrading(false);
showNotice("success", t(`Core Version Updated`));
} catch (err: any) {
setUpgrading(false);
const errMsg = err.response?.data?.message || err.toString();
const showMsg = errMsg.includes("already using latest version")
? "Already Using Latest Core Version"
: errMsg;
showNotice("error", t(showMsg));
}
});
return (
<BaseDialog
open={open}
title={
<Box display="flex" justifyContent="space-between">
{t("Clash Core")}
<Box>
<LoadingButton
variant="contained"
size="small"
startIcon={<SwitchAccessShortcutRounded />}
loadingPosition="start"
loading={upgrading}
disabled={restarting || changingCore !== null}
sx={{ marginRight: "8px" }}
onClick={onUpgrade}
>
{t("Upgrade")}
</LoadingButton>
<LoadingButton
variant="contained"
size="small"
startIcon={<RestartAltRounded />}
loadingPosition="start"
loading={restarting}
disabled={upgrading}
onClick={onRestart}
>
{t("Restart")}
</LoadingButton>
</Box>
</Box>
}
contentSx={{
pb: 0,
width: 400,
height: 180,
overflowY: "auto",
userSelect: "text",
marginTop: "-8px",
}}
disableOk
cancelBtn={t("Close")}
onClose={() => setOpen(false)}
onCancel={() => setOpen(false)}
>
<List component="nav">
{VALID_CORE.map((each) => (
<ListItemButton
key={each.core}
selected={each.core === clash_core}
onClick={() => onCoreChange(each.core)}
disabled={changingCore !== null || restarting || upgrading}
>
<ListItemText primary={each.name} secondary={`/${each.core}`} />
{changingCore === each.core ? (
<CircularProgress size={20} sx={{ mr: 1 }} />
) : (
<Chip label={t(`${each.chip}`)} size="small" />
)}
</ListItemButton>
))}
</List>
</BaseDialog>
);
}