refactor(notice): unify showNotice usage
This commit is contained in:
@@ -193,7 +193,8 @@ const TrafficErrorFallback: React.FC<TrafficErrorFallbackProps> = ({
|
||||
|
||||
<Alert severity="error" sx={{ mb: 2, maxWidth: 400 }}>
|
||||
<Typography variant="body2">
|
||||
<strong>Error:</strong> {error?.message || "Unknown error"}
|
||||
<strong>Error:</strong>{" "}
|
||||
{error instanceof Error ? error.message : "Unknown error"}
|
||||
</Typography>
|
||||
{retryCount > 0 && (
|
||||
<Typography variant="caption" display="block" sx={{ mt: 1 }}>
|
||||
|
||||
@@ -296,8 +296,8 @@ export const HomeProfileCard = ({
|
||||
|
||||
// 刷新首页数据
|
||||
refreshAll();
|
||||
} catch (err: any) {
|
||||
showNotice.error(err.message || err.toString(), 3000);
|
||||
} catch (err) {
|
||||
showNotice.error(err, 3000);
|
||||
} finally {
|
||||
setUpdating(false);
|
||||
}
|
||||
|
||||
@@ -68,8 +68,8 @@ export const IpInfoCard = () => {
|
||||
const data = await getIpInfo();
|
||||
setIpInfo(data);
|
||||
setCountdown(IP_REFRESH_SECONDS);
|
||||
} catch (err: any) {
|
||||
setError(err.message || t("Failed to get IP info"));
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : t("Failed to get IP info"));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -147,8 +147,8 @@ export const ProxyTunCard: FC = () => {
|
||||
|
||||
const { enable_tun_mode } = verge ?? {};
|
||||
|
||||
const handleError = (err: Error) => {
|
||||
showNotice.error(err.message || err.toString());
|
||||
const handleError = (err: unknown) => {
|
||||
showNotice.error(err);
|
||||
};
|
||||
|
||||
const handleTabChange = (tab: string) => {
|
||||
|
||||
@@ -179,8 +179,8 @@ export const SystemInfoCard = () => {
|
||||
showNotice.info("Update Available", 2000);
|
||||
goToSettings();
|
||||
}
|
||||
} catch (err: any) {
|
||||
showNotice.error(err.message || err.toString());
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) {
|
||||
} catch {
|
||||
// 首次创建/更新失败,尝试使用自身代理
|
||||
showNotice.info(
|
||||
t("components.profile.viewer.notifications.creationRetry"),
|
||||
"components.profile.viewer.notifications.creationRetry",
|
||||
);
|
||||
|
||||
// 使用自身代理的配置
|
||||
@@ -170,7 +170,7 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) {
|
||||
}
|
||||
|
||||
showNotice.success(
|
||||
t("components.profile.viewer.notifications.creationSuccess"),
|
||||
"components.profile.viewer.notifications.creationSuccess",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,11 +163,11 @@ export const ProxiesEditorViewer = (props: Props) => {
|
||||
proxies.push(proxy);
|
||||
names.push(proxy.name);
|
||||
}
|
||||
} catch (err: any) {
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
"[ProxiesEditorViewer] parseUri failed for line:",
|
||||
uri,
|
||||
err?.message || err,
|
||||
err,
|
||||
);
|
||||
// 不阻塞主流程
|
||||
}
|
||||
|
||||
@@ -66,15 +66,13 @@ export const ProviderButton = () => {
|
||||
await refreshProxy();
|
||||
await refreshProxyProviders();
|
||||
|
||||
showNotice.success({
|
||||
i18nKey: "components.providers.notices.updateSuccess",
|
||||
params: { name },
|
||||
showNotice.success("components.providers.notices.updateSuccess", {
|
||||
name,
|
||||
});
|
||||
} catch (err: any) {
|
||||
const message = err?.message || err?.toString?.() || String(err);
|
||||
showNotice.error({
|
||||
i18nKey: "components.providers.notices.updateFailed",
|
||||
params: { name, message },
|
||||
} catch (err) {
|
||||
showNotice.error("components.providers.notices.updateFailed", {
|
||||
name,
|
||||
message: String(err),
|
||||
});
|
||||
} finally {
|
||||
// 清除更新状态
|
||||
@@ -88,9 +86,7 @@ export const ProviderButton = () => {
|
||||
// 获取所有provider的名称
|
||||
const allProviders = Object.keys(proxyProviders || {});
|
||||
if (allProviders.length === 0) {
|
||||
showNotice.info({
|
||||
i18nKey: "components.providers.notices.none",
|
||||
});
|
||||
showNotice.info("components.providers.notices.none");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -120,14 +116,10 @@ export const ProviderButton = () => {
|
||||
await refreshProxy();
|
||||
await refreshProxyProviders();
|
||||
|
||||
showNotice.success({
|
||||
i18nKey: "components.providers.notices.allUpdated",
|
||||
});
|
||||
} catch (err: any) {
|
||||
const message = err?.message || err?.toString?.() || String(err);
|
||||
showNotice.error({
|
||||
i18nKey: "components.providers.notices.genericError",
|
||||
params: { message },
|
||||
showNotice.success("components.providers.notices.allUpdated");
|
||||
} catch (err) {
|
||||
showNotice.error("components.providers.notices.genericError", {
|
||||
message: String(err),
|
||||
});
|
||||
} finally {
|
||||
// 清除所有更新状态
|
||||
|
||||
@@ -58,15 +58,13 @@ export const ProviderButton = () => {
|
||||
await refreshRules();
|
||||
await refreshRuleProviders();
|
||||
|
||||
showNotice.success({
|
||||
i18nKey: "components.notices.providers.updateSuccess",
|
||||
params: { name },
|
||||
showNotice.success("components.notices.providers.updateSuccess", {
|
||||
name,
|
||||
});
|
||||
} catch (err: any) {
|
||||
const message = err?.message || err?.toString?.() || String(err);
|
||||
showNotice.error({
|
||||
i18nKey: "components.notices.providers.updateFailed",
|
||||
params: { name, message },
|
||||
} catch (err) {
|
||||
showNotice.error("components.notices.providers.updateFailed", {
|
||||
name,
|
||||
message: String(err),
|
||||
});
|
||||
} finally {
|
||||
// 清除更新状态
|
||||
@@ -80,9 +78,7 @@ export const ProviderButton = () => {
|
||||
// 获取所有provider的名称
|
||||
const allProviders = Object.keys(ruleProviders || {});
|
||||
if (allProviders.length === 0) {
|
||||
showNotice.info({
|
||||
i18nKey: "components.notices.providers.none",
|
||||
});
|
||||
showNotice.info("components.notices.providers.none");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -112,14 +108,10 @@ export const ProviderButton = () => {
|
||||
await refreshRules();
|
||||
await refreshRuleProviders();
|
||||
|
||||
showNotice.success({
|
||||
i18nKey: "components.notices.providers.allUpdated",
|
||||
});
|
||||
} catch (err: any) {
|
||||
const message = err?.message || err?.toString?.() || String(err);
|
||||
showNotice.error({
|
||||
i18nKey: "components.notices.providers.genericError",
|
||||
params: { message },
|
||||
showNotice.success("components.notices.providers.allUpdated");
|
||||
} catch (err) {
|
||||
showNotice.error("components.notices.providers.genericError", {
|
||||
message: String(err),
|
||||
});
|
||||
} finally {
|
||||
// 清除所有更新状态
|
||||
|
||||
@@ -84,18 +84,16 @@ export const BackupConfigViewer = memo(
|
||||
|
||||
if (!url) {
|
||||
urlRef.current?.focus();
|
||||
showNotice(
|
||||
"error",
|
||||
t("components.settings.backup.messages.webdavUrlRequired"),
|
||||
showNotice.error(
|
||||
"components.settings.backup.messages.webdavUrlRequired",
|
||||
);
|
||||
throw new Error(
|
||||
t("components.settings.backup.messages.webdavUrlRequired"),
|
||||
);
|
||||
} else if (!isValidUrl(url)) {
|
||||
urlRef.current?.focus();
|
||||
showNotice(
|
||||
"error",
|
||||
t("components.settings.backup.messages.invalidWebdavUrl"),
|
||||
showNotice.error(
|
||||
"components.settings.backup.messages.invalidWebdavUrl",
|
||||
);
|
||||
throw new Error(
|
||||
t("components.settings.backup.messages.invalidWebdavUrl"),
|
||||
@@ -103,9 +101,8 @@ export const BackupConfigViewer = memo(
|
||||
}
|
||||
if (!username) {
|
||||
usernameRef.current?.focus();
|
||||
showNotice(
|
||||
"error",
|
||||
t("components.settings.backup.messages.usernameRequired"),
|
||||
showNotice.error(
|
||||
"components.settings.backup.messages.usernameRequired",
|
||||
);
|
||||
throw new Error(
|
||||
t("components.settings.backup.messages.usernameRequired"),
|
||||
@@ -113,9 +110,8 @@ export const BackupConfigViewer = memo(
|
||||
}
|
||||
if (!password) {
|
||||
passwordRef.current?.focus();
|
||||
showNotice(
|
||||
"error",
|
||||
t("components.settings.backup.messages.passwordRequired"),
|
||||
showNotice.error(
|
||||
"components.settings.backup.messages.passwordRequired",
|
||||
);
|
||||
throw new Error(
|
||||
t("components.settings.backup.messages.passwordRequired"),
|
||||
@@ -132,18 +128,15 @@ export const BackupConfigViewer = memo(
|
||||
data.username.trim(),
|
||||
data.password,
|
||||
).then(() => {
|
||||
showNotice(
|
||||
"success",
|
||||
t("components.settings.backup.messages.webdavConfigSaved"),
|
||||
showNotice.success(
|
||||
"components.settings.backup.messages.webdavConfigSaved",
|
||||
);
|
||||
onSaveSuccess();
|
||||
});
|
||||
} catch (error) {
|
||||
showNotice(
|
||||
"error",
|
||||
t("components.settings.backup.messages.webdavConfigSaveFailed", {
|
||||
error,
|
||||
}),
|
||||
showNotice.error(
|
||||
"components.settings.backup.messages.webdavConfigSaveFailed",
|
||||
{ error },
|
||||
3000,
|
||||
);
|
||||
} finally {
|
||||
@@ -156,17 +149,15 @@ export const BackupConfigViewer = memo(
|
||||
try {
|
||||
setLoading(true);
|
||||
await createWebdavBackup().then(async () => {
|
||||
showNotice(
|
||||
"success",
|
||||
t("components.settings.backup.messages.backupCreated"),
|
||||
showNotice.success(
|
||||
"components.settings.backup.messages.backupCreated",
|
||||
);
|
||||
await onBackupSuccess();
|
||||
});
|
||||
} catch (error) {
|
||||
showNotice(
|
||||
"error",
|
||||
t("components.settings.backup.messages.backupFailed", { error }),
|
||||
);
|
||||
showNotice.error("components.settings.backup.messages.backupFailed", {
|
||||
error,
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -75,9 +75,8 @@ export const BackupTableViewer = memo(
|
||||
|
||||
const handleRestore = useLockFn(async (filename: string) => {
|
||||
await onRestore(filename).then(() => {
|
||||
showNotice(
|
||||
"success",
|
||||
t("components.settings.backup.messages.restoreSuccess"),
|
||||
showNotice.success(
|
||||
"components.settings.backup.messages.restoreSuccess",
|
||||
);
|
||||
});
|
||||
await restartApp();
|
||||
@@ -95,15 +94,13 @@ export const BackupTableViewer = memo(
|
||||
return;
|
||||
}
|
||||
await onExport(filename, savePath);
|
||||
showNotice(
|
||||
"success",
|
||||
t("components.settings.backup.messages.localBackupExported"),
|
||||
showNotice.success(
|
||||
"components.settings.backup.messages.localBackupExported",
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
showNotice(
|
||||
"error",
|
||||
t("components.settings.backup.messages.localBackupExportFailed"),
|
||||
showNotice.error(
|
||||
"components.settings.backup.messages.localBackupExportFailed",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -75,7 +75,7 @@ export function ClashCoreViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
try {
|
||||
setRestarting(true);
|
||||
await restartCore();
|
||||
showNotice.success({ i18nKey: "Clash Core Restarted" });
|
||||
showNotice.success("Clash Core Restarted");
|
||||
setRestarting(false);
|
||||
} catch (err) {
|
||||
setRestarting(false);
|
||||
@@ -88,10 +88,10 @@ export function ClashCoreViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
setUpgrading(true);
|
||||
await upgradeCore();
|
||||
setUpgrading(false);
|
||||
showNotice.success({ i18nKey: "Core Version Updated" });
|
||||
showNotice.success("Core Version Updated");
|
||||
} catch (err: any) {
|
||||
setUpgrading(false);
|
||||
const errMsg = err.response?.data?.message || err.toString();
|
||||
const errMsg = err?.response?.data?.message ?? String(err);
|
||||
const showMsg = errMsg.includes("already using latest version")
|
||||
? "Already Using Latest Core Version"
|
||||
: errMsg;
|
||||
|
||||
@@ -69,16 +69,10 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
|
||||
manual: true,
|
||||
onSuccess: () => {
|
||||
setOpen(false);
|
||||
showNotice(
|
||||
"success",
|
||||
t("components.settings.clash.port.messages.saved"),
|
||||
);
|
||||
showNotice.success("components.settings.clash.port.messages.saved");
|
||||
},
|
||||
onError: () => {
|
||||
showNotice(
|
||||
"error",
|
||||
t("components.settings.clash.port.messages.saveFailed"),
|
||||
);
|
||||
showNotice.error("components.settings.clash.port.messages.saveFailed");
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -56,18 +56,16 @@ export function ControllerViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
// 如果启用了外部控制器,则保存控制器地址和密钥
|
||||
if (enableController) {
|
||||
if (!controller.trim()) {
|
||||
showNotice.error({
|
||||
i18nKey:
|
||||
"components.settings.externalController.messages.addressRequired",
|
||||
});
|
||||
showNotice.error(
|
||||
"components.settings.externalController.messages.addressRequired",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!secret.trim()) {
|
||||
showNotice.error({
|
||||
i18nKey:
|
||||
"components.settings.externalController.messages.secretRequired",
|
||||
});
|
||||
showNotice.error(
|
||||
"components.settings.externalController.messages.secretRequired",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -77,15 +75,10 @@ export function ControllerViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
await patchInfo({ "external-controller": "" });
|
||||
}
|
||||
|
||||
showNotice.success({ i18nKey: "Configuration saved successfully" });
|
||||
showNotice.success("Configuration saved successfully");
|
||||
setOpen(false);
|
||||
} catch (err: any) {
|
||||
const message = err?.message || err?.toString?.();
|
||||
if (message) {
|
||||
showNotice.error(t("Failed to save configuration"), message, 4000);
|
||||
} else {
|
||||
showNotice.error("Failed to save configuration", 4000);
|
||||
}
|
||||
} catch (err) {
|
||||
showNotice.error("Failed to save configuration", err, 4000);
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
@@ -100,9 +93,9 @@ export function ControllerViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
setTimeout(() => setCopySuccess(null));
|
||||
} catch (err) {
|
||||
console.warn("[ControllerViewer] copy to clipboard failed:", err);
|
||||
showNotice.error({
|
||||
i18nKey: "components.settings.externalController.messages.copyFailed",
|
||||
});
|
||||
showNotice.error(
|
||||
"components.settings.externalController.messages.copyFailed",
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -424,7 +424,7 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
skipYamlSyncRef.current = true;
|
||||
updateValuesFromConfig(parsedYaml);
|
||||
} catch {
|
||||
showNotice.error({ i18nKey: "Invalid YAML format" });
|
||||
showNotice.error("Invalid YAML format");
|
||||
}
|
||||
}, [yamlContent, updateValuesFromConfig]);
|
||||
|
||||
@@ -547,7 +547,7 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
}
|
||||
}
|
||||
|
||||
showNotice.error(`${t("DNS configuration error")}:`, cleanErrorMsg);
|
||||
showNotice.error("DNS configuration error:", cleanErrorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -558,7 +558,7 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
}
|
||||
|
||||
setOpen(false);
|
||||
showNotice.success({ i18nKey: "DNS settings saved" });
|
||||
showNotice.success("DNS settings saved");
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
|
||||
@@ -140,12 +140,10 @@ export const HeaderConfiguration = forwardRef<ClashHeaderConfigingRef>(
|
||||
manual: true,
|
||||
onSuccess: () => {
|
||||
setOpen(false);
|
||||
showNotice.success({
|
||||
i18nKey: "Configuration saved successfully",
|
||||
});
|
||||
showNotice.success("Configuration saved successfully");
|
||||
},
|
||||
onError: () => {
|
||||
showNotice.error({ i18nKey: "Failed to save configuration" });
|
||||
showNotice.error("Failed to save configuration");
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -20,16 +20,14 @@ export const LocalBackupActions = memo(
|
||||
try {
|
||||
setLoading(true);
|
||||
await createLocalBackup();
|
||||
showNotice(
|
||||
"success",
|
||||
t("components.settings.backup.messages.localBackupCreated"),
|
||||
showNotice.success(
|
||||
"components.settings.backup.messages.localBackupCreated",
|
||||
);
|
||||
await onBackupSuccess();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
showNotice(
|
||||
"error",
|
||||
t("components.settings.backup.messages.localBackupFailed"),
|
||||
showNotice.error(
|
||||
"components.settings.backup.messages.localBackupFailed",
|
||||
);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
|
||||
@@ -133,7 +133,7 @@ const AddressDisplay = ({
|
||||
size="small"
|
||||
onClick={async () => {
|
||||
await writeText(content);
|
||||
showNotice.success({ i18nKey: "Copy Success" });
|
||||
showNotice.success("Copy Success");
|
||||
}}
|
||||
>
|
||||
<ContentCopyRounded sx={{ fontSize: "18px" }} />
|
||||
|
||||
@@ -278,14 +278,12 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
const onSave = useLockFn(async () => {
|
||||
if (value.duration < 1) {
|
||||
showNotice.error(
|
||||
t("components.settings.sysproxy.messages.durationTooShort"),
|
||||
"components.settings.sysproxy.messages.durationTooShort",
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (value.bypass && !validReg.test(value.bypass)) {
|
||||
showNotice.error(
|
||||
t("components.settings.sysproxy.messages.invalidBypass"),
|
||||
);
|
||||
showNotice.error("components.settings.sysproxy.messages.invalidBypass");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -303,7 +301,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
!hostnameRegex.test(value.proxy_host)
|
||||
) {
|
||||
showNotice.error(
|
||||
t("components.settings.sysproxy.messages.invalidProxyHost"),
|
||||
"components.settings.sysproxy.messages.invalidProxyHost",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -58,14 +58,12 @@ export function UpdateViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
const onUpdate = useLockFn(async () => {
|
||||
if (portableFlag) {
|
||||
showNotice.error(t("components.settings.update.messages.portableError"));
|
||||
showNotice.error("components.settings.update.messages.portableError");
|
||||
return;
|
||||
}
|
||||
if (!updateInfo?.body) return;
|
||||
if (breakChangeFlag) {
|
||||
showNotice.error(
|
||||
t("components.settings.update.messages.breakChangeError"),
|
||||
);
|
||||
showNotice.error("components.settings.update.messages.breakChangeError");
|
||||
return;
|
||||
}
|
||||
if (updateState) return;
|
||||
|
||||
@@ -67,9 +67,7 @@ const SettingClash = ({ onError }: Props) => {
|
||||
const onUpdateGeo = async () => {
|
||||
try {
|
||||
await updateGeo();
|
||||
showNotice.success(
|
||||
t("components.settings.clash.messages.geoDataUpdated"),
|
||||
);
|
||||
showNotice.success("components.settings.clash.messages.geoDataUpdated");
|
||||
} catch (err: any) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
|
||||
@@ -78,9 +78,8 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
}}
|
||||
onGuard={async (e) => {
|
||||
if (isAdminMode) {
|
||||
showNotice(
|
||||
"info",
|
||||
t("components.settings.system.tooltips.autoLaunchAdmin"),
|
||||
showNotice.info(
|
||||
"components.settings.system.tooltips.autoLaunchAdmin",
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ const SettingVergeAdvanced = ({ onError: _ }: Props) => {
|
||||
const info = await checkUpdate();
|
||||
if (!info?.available) {
|
||||
showNotice.success(
|
||||
t("components.settings.verge.advanced.notifications.latestVersion"),
|
||||
"components.settings.verge.advanced.notifications.latestVersion",
|
||||
);
|
||||
} else {
|
||||
updateRef.current?.open();
|
||||
@@ -61,19 +61,19 @@ const SettingVergeAdvanced = ({ onError: _ }: Props) => {
|
||||
const onExportDiagnosticInfo = useCallback(async () => {
|
||||
await exportDiagnosticInfo();
|
||||
showNotice.success(
|
||||
t("components.settings.common.notifications.copySuccess"),
|
||||
"components.settings.common.notifications.copySuccess",
|
||||
1000,
|
||||
);
|
||||
}, [t]);
|
||||
}, []);
|
||||
|
||||
const copyVersion = useCallback(() => {
|
||||
navigator.clipboard.writeText(`v${version}`).then(() => {
|
||||
showNotice.success(
|
||||
t("components.settings.verge.advanced.notifications.versionCopied"),
|
||||
"components.settings.verge.advanced.notifications.versionCopied",
|
||||
1000,
|
||||
);
|
||||
});
|
||||
}, [t]);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<SettingList title={t("components.settings.verge.advanced.title")}>
|
||||
|
||||
@@ -76,12 +76,11 @@ const SettingVergeBasic = ({ onError }: Props) => {
|
||||
|
||||
const onCopyClashEnv = useCallback(async () => {
|
||||
await copyClashEnv();
|
||||
showNotice(
|
||||
"success",
|
||||
t("components.settings.common.notifications.copySuccess"),
|
||||
showNotice.success(
|
||||
"components.settings.common.notifications.copySuccess",
|
||||
1000,
|
||||
);
|
||||
}, [t]);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<SettingList title={t("components.settings.verge.basic.title")}>
|
||||
|
||||
@@ -82,7 +82,7 @@ export const TestItem = ({
|
||||
try {
|
||||
removeTest(uid);
|
||||
} catch (err: any) {
|
||||
showNotice.error(err.message || err.toString());
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ export const TestViewer = forwardRef<TestViewerRef, Props>((props, ref) => {
|
||||
setLoading(false);
|
||||
setTimeout(() => formIns.reset(), 500);
|
||||
} catch (err: any) {
|
||||
showNotice.error(err.message || err.toString());
|
||||
showNotice.error(err);
|
||||
setLoading(false);
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import useSWR from "swr";
|
||||
|
||||
import { getRunningMode, isAdmin, isServiceAvailable } from "@/services/cmds";
|
||||
@@ -26,7 +25,6 @@ let disablingTunMode = false;
|
||||
* 包括运行模式、管理员状态、系统服务是否可用
|
||||
*/
|
||||
export function useSystemState() {
|
||||
const { t } = useTranslation();
|
||||
const { verge, patchVerge } = useVerge();
|
||||
|
||||
const {
|
||||
@@ -67,16 +65,13 @@ export function useSystemState() {
|
||||
disablingTunMode = true;
|
||||
patchVerge({ enable_tun_mode: false })
|
||||
.then(() => {
|
||||
showNotice.info({
|
||||
i18nKey:
|
||||
"TUN Mode automatically disabled due to service unavailable",
|
||||
});
|
||||
showNotice.info(
|
||||
"TUN Mode automatically disabled due to service unavailable",
|
||||
);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("[useVerge] 自动关闭TUN模式失败:", err);
|
||||
showNotice.error({
|
||||
i18nKey: "Failed to disable TUN Mode automatically",
|
||||
});
|
||||
showNotice.error("Failed to disable TUN Mode automatically");
|
||||
})
|
||||
.finally(() => {
|
||||
const tid = setTimeout(() => {
|
||||
@@ -86,7 +81,7 @@ export function useSystemState() {
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
}, [enable_tun_mode, isTunModeAvailable, patchVerge, isLoading, t]);
|
||||
}, [enable_tun_mode, isTunModeAvailable, patchVerge, isLoading]);
|
||||
|
||||
return {
|
||||
runningMode: systemState.runningMode,
|
||||
|
||||
@@ -17,8 +17,7 @@ const executeWithErrorHandling = async (
|
||||
showNotice.success(successMessage);
|
||||
}
|
||||
} catch (err) {
|
||||
const msg = (err as Error)?.message || String(err);
|
||||
showNotice.error(msg);
|
||||
showNotice.error(err);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -17,8 +17,7 @@ const executeWithErrorHandling = async (
|
||||
showNotice.success(successMessage);
|
||||
}
|
||||
} catch (err) {
|
||||
const msg = (err as Error)?.message || String(err);
|
||||
showNotice.error(msg);
|
||||
showNotice.error(err);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -373,6 +373,7 @@
|
||||
"Service Administrator Prompt": "Clash Verge requires administrator privileges to reinstall the system service",
|
||||
"DNS Settings": "DNS Settings",
|
||||
"DNS settings saved": "DNS settings saved",
|
||||
"DNS configuration error:": "DNS configuration error:",
|
||||
"DNS Overwrite": "DNS Overwrite",
|
||||
"DNS Settings Warning": "If you are not familiar with these settings, please do not modify them and keep DNS Overwrite enabled",
|
||||
"Enable DNS": "Enable DNS",
|
||||
|
||||
@@ -373,6 +373,7 @@
|
||||
"Service Administrator Prompt": "Clash Verge 需要管理员权限安装系统服务",
|
||||
"DNS Settings": "DNS 设置",
|
||||
"DNS settings saved": "DNS 设置已保存",
|
||||
"DNS configuration error:": "DNS 配置错误:",
|
||||
"DNS Overwrite": "DNS 覆写",
|
||||
"DNS Settings Warning": "如果你不清楚这里的设置请不要修改,并保持 DNS 覆写开启",
|
||||
"Enable DNS": "启用 DNS",
|
||||
|
||||
@@ -373,6 +373,7 @@
|
||||
"Service Administrator Prompt": "Clash Verge 需要管理員權限安裝系統服務",
|
||||
"DNS Settings": "DNS 設定",
|
||||
"DNS settings saved": "DNS 設定已儲存",
|
||||
"DNS configuration error:": "DNS 設定錯誤:",
|
||||
"DNS Overwrite": "DNS 覆寫",
|
||||
"DNS Settings Warning": "如果你不清楚這裡的設定請不要修改,並保持 DNS 覆寫開啟",
|
||||
"Enable DNS": "啟用 DNS",
|
||||
|
||||
@@ -20,51 +20,51 @@ export const handleNoticeMessage = (
|
||||
},
|
||||
"set_config::error": () => showNotice.error(msg),
|
||||
update_with_clash_proxy: () =>
|
||||
showNotice.success(t("Update with Clash proxy successfully"), msg),
|
||||
showNotice.success("Update with Clash proxy successfully", msg),
|
||||
update_retry_with_clash: () =>
|
||||
showNotice.info("Update failed, retrying with Clash proxy..."),
|
||||
update_failed_even_with_clash: () =>
|
||||
showNotice.error(`${t("Update failed even with Clash proxy")}:`, msg),
|
||||
showNotice.error("Update failed even with Clash proxy", msg),
|
||||
update_failed: () => showNotice.error(msg),
|
||||
"config_validate::boot_error": () =>
|
||||
showNotice.error(t("Boot Config Validation Failed"), msg),
|
||||
showNotice.error("Boot Config Validation Failed", msg),
|
||||
"config_validate::core_change": () =>
|
||||
showNotice.error(t("Core Change Config Validation Failed"), msg),
|
||||
showNotice.error("Core Change Config Validation Failed", msg),
|
||||
"config_validate::error": () =>
|
||||
showNotice.error(t("Config Validation Failed"), msg),
|
||||
showNotice.error("Config Validation Failed", msg),
|
||||
"config_validate::process_terminated": () =>
|
||||
showNotice.error("Config Validation Process Terminated"),
|
||||
"config_validate::stdout_error": () =>
|
||||
showNotice.error(t("Config Validation Failed"), msg),
|
||||
showNotice.error("Config Validation Failed", msg),
|
||||
"config_validate::script_error": () =>
|
||||
showNotice.error(t("Script File Error"), msg),
|
||||
showNotice.error("Script File Error", msg),
|
||||
"config_validate::script_syntax_error": () =>
|
||||
showNotice.error(t("Script Syntax Error"), msg),
|
||||
showNotice.error("Script Syntax Error", msg),
|
||||
"config_validate::script_missing_main": () =>
|
||||
showNotice.error(t("Script Missing Main"), msg),
|
||||
showNotice.error("Script Missing Main", msg),
|
||||
"config_validate::file_not_found": () =>
|
||||
showNotice.error(t("File Not Found"), msg),
|
||||
showNotice.error("File Not Found", msg),
|
||||
"config_validate::yaml_syntax_error": () =>
|
||||
showNotice.error(t("YAML Syntax Error"), msg),
|
||||
showNotice.error("YAML Syntax Error", msg),
|
||||
"config_validate::yaml_read_error": () =>
|
||||
showNotice.error(t("YAML Read Error"), msg),
|
||||
showNotice.error("YAML Read Error", msg),
|
||||
"config_validate::yaml_mapping_error": () =>
|
||||
showNotice.error(t("YAML Mapping Error"), msg),
|
||||
showNotice.error("YAML Mapping Error", msg),
|
||||
"config_validate::yaml_key_error": () =>
|
||||
showNotice.error(t("YAML Key Error"), msg),
|
||||
"config_validate::yaml_error": () => showNotice.error(t("YAML Error"), msg),
|
||||
showNotice.error("YAML Key Error", msg),
|
||||
"config_validate::yaml_error": () => showNotice.error("YAML Error", msg),
|
||||
"config_validate::merge_syntax_error": () =>
|
||||
showNotice.error(t("Merge File Syntax Error"), msg),
|
||||
showNotice.error("Merge File Syntax Error", msg),
|
||||
"config_validate::merge_mapping_error": () =>
|
||||
showNotice.error(t("Merge File Mapping Error"), msg),
|
||||
showNotice.error("Merge File Mapping Error", msg),
|
||||
"config_validate::merge_key_error": () =>
|
||||
showNotice.error(t("Merge File Key Error"), msg),
|
||||
showNotice.error("Merge File Key Error", msg),
|
||||
"config_validate::merge_error": () =>
|
||||
showNotice.error(t("Merge File Error"), msg),
|
||||
showNotice.error("Merge File Error", msg),
|
||||
"config_core::change_success": () =>
|
||||
showNotice.success(`${t("Core Changed Successfully")}:`, msg),
|
||||
showNotice.success("Core Changed Successfully", msg),
|
||||
"config_core::change_error": () =>
|
||||
showNotice.error(`${t("Failed to Change Core")}:`, msg),
|
||||
showNotice.error("Failed to Change Core", msg),
|
||||
};
|
||||
|
||||
const handler = handlers[status];
|
||||
|
||||
@@ -146,12 +146,12 @@ const ProfilePage = () => {
|
||||
|
||||
setActivatings((prev) => prev.filter((id) => id !== previousSwitching));
|
||||
showNotice.info(
|
||||
t("pages.profiles.notifications.switchInterrupted"),
|
||||
"pages.profiles.notifications.switchInterrupted",
|
||||
`${previousSwitching} → ${newProfile}`,
|
||||
3000,
|
||||
);
|
||||
},
|
||||
[t],
|
||||
[],
|
||||
);
|
||||
|
||||
// 清理切换状态
|
||||
@@ -240,12 +240,11 @@ const ProfilePage = () => {
|
||||
await onEnhance(false);
|
||||
|
||||
showNotice.success("pages.profiles.notices.forceRefreshCompleted", 2000);
|
||||
} catch (error: any) {
|
||||
} catch (error) {
|
||||
console.error("[紧急刷新] 失败:", error);
|
||||
const message = error?.message || String(error);
|
||||
showNotice.error(
|
||||
"pages.profiles.notices.emergencyRefreshFailed",
|
||||
{ message },
|
||||
{ message: String(error) },
|
||||
4000,
|
||||
);
|
||||
}
|
||||
@@ -302,11 +301,11 @@ const ProfilePage = () => {
|
||||
self_proxy: true,
|
||||
});
|
||||
await handleImportSuccess("Profile Imported with Clash proxy");
|
||||
} catch (retryErr: any) {
|
||||
} catch (retryErr) {
|
||||
// 回退导入也失败
|
||||
const retryErrmsg = retryErr?.message || retryErr.toString();
|
||||
showNotice.error(
|
||||
`${t("pages.profiles.notifications.importFail")}: ${retryErrmsg}`,
|
||||
"pages.profiles.notifications.importFail",
|
||||
String(retryErr),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
@@ -353,13 +352,10 @@ const ProfilePage = () => {
|
||||
// 清除SWR缓存并重新获取
|
||||
await mutate("getProfiles", getProfiles(), { revalidate: true });
|
||||
await onEnhance(false);
|
||||
showNotice.error(
|
||||
t("pages.profiles.notifications.importNeedsRefresh"),
|
||||
3000,
|
||||
);
|
||||
showNotice.error("pages.profiles.notifications.importNeedsRefresh", 3000);
|
||||
} catch (finalError) {
|
||||
console.error(`[导入刷新] 最终刷新尝试失败:`, finalError);
|
||||
showNotice.error(t("pages.profiles.notifications.importSuccess"), 5000);
|
||||
showNotice.error("pages.profiles.notifications.importSuccess", 5000);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -477,7 +473,7 @@ const ProfilePage = () => {
|
||||
|
||||
if (notifySuccess && success) {
|
||||
showNotice.success(
|
||||
t("pages.profiles.notifications.profileSwitched"),
|
||||
"pages.profiles.notifications.profileSwitched",
|
||||
1000,
|
||||
);
|
||||
}
|
||||
@@ -531,7 +527,6 @@ const ProfilePage = () => {
|
||||
profiles,
|
||||
patchProfiles,
|
||||
mutateLogs,
|
||||
t,
|
||||
executeBackgroundTasks,
|
||||
handleProfileInterrupt,
|
||||
cleanupSwitchState,
|
||||
@@ -577,7 +572,7 @@ const ProfilePage = () => {
|
||||
mutateLogs();
|
||||
if (notifySuccess) {
|
||||
showNotice.success(
|
||||
t("pages.profiles.notifications.profileReactivated"),
|
||||
"pages.profiles.notifications.profileReactivated",
|
||||
1000,
|
||||
);
|
||||
}
|
||||
@@ -718,9 +713,7 @@ const ProfilePage = () => {
|
||||
setSelectedProfiles(new Set());
|
||||
setBatchMode(false);
|
||||
|
||||
showNotice.success({
|
||||
i18nKey: "pages.profiles.notifications.batchDeleted",
|
||||
});
|
||||
showNotice.success("pages.profiles.notifications.batchDeleted");
|
||||
} catch (err: any) {
|
||||
showNotice.error(err);
|
||||
} finally {
|
||||
@@ -729,8 +722,8 @@ const ProfilePage = () => {
|
||||
});
|
||||
|
||||
const mode = useThemeMode();
|
||||
const islight = mode === "light" ? true : false;
|
||||
const dividercolor = islight
|
||||
const isLight = mode === "light";
|
||||
const dividercolor = isLight
|
||||
? "rgba(0, 0, 0, 0.06)"
|
||||
: "rgba(255, 255, 255, 0.06)";
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ const SettingPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onError = (err: any) => {
|
||||
showNotice.error(err?.message || err.toString());
|
||||
showNotice.error(err);
|
||||
};
|
||||
|
||||
const toGithubRepo = useLockFn(() => {
|
||||
|
||||
@@ -173,10 +173,7 @@ const UnlockPage = () => {
|
||||
setIsCheckingAll(false);
|
||||
} catch (err: any) {
|
||||
setIsCheckingAll(false);
|
||||
showNotice(
|
||||
"error",
|
||||
err?.message || err?.toString() || t("Detection timeout or failed"),
|
||||
);
|
||||
showNotice.error("Detection timeout or failed", err);
|
||||
console.error("Failed to check media unlock:", err);
|
||||
}
|
||||
});
|
||||
@@ -206,12 +203,7 @@ const UnlockPage = () => {
|
||||
setLoadingItems((prev) => prev.filter((item) => item !== name));
|
||||
} catch (err: any) {
|
||||
setLoadingItems((prev) => prev.filter((item) => item !== name));
|
||||
showNotice(
|
||||
"error",
|
||||
err?.message ||
|
||||
err?.toString() ||
|
||||
t("Detection failed for {name}").replace("{name}", name),
|
||||
);
|
||||
showNotice.error("Detection failed for {name}", { name }, err);
|
||||
console.error(`Failed to check ${name}:`, err);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3,17 +3,11 @@ import { ReactNode, isValidElement } from "react";
|
||||
|
||||
type NoticeType = "success" | "error" | "info";
|
||||
|
||||
/**
|
||||
* Descriptor used when the notice content should be resolved through i18n.
|
||||
*/
|
||||
export interface NoticeTranslationDescriptor {
|
||||
key: string;
|
||||
params?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runtime representation of a notice entry queued for rendering.
|
||||
*/
|
||||
interface NoticeItem {
|
||||
readonly id: number;
|
||||
readonly type: NoticeType;
|
||||
@@ -69,6 +63,7 @@ function parseNoticeExtras(extras: NoticeExtra[]): ParsedNoticeExtras {
|
||||
let raw: unknown;
|
||||
let duration: number | undefined;
|
||||
|
||||
// Prioritize objects as translation params, then as raw payloads, while the first number wins as duration.
|
||||
for (const extra of extras) {
|
||||
if (extra === undefined) continue;
|
||||
|
||||
@@ -182,13 +177,9 @@ function extractDisplayText(input: unknown): string | undefined {
|
||||
if (input instanceof Error) {
|
||||
return input.message || input.name;
|
||||
}
|
||||
if (
|
||||
typeof input === "object" &&
|
||||
input !== null &&
|
||||
"message" in input &&
|
||||
typeof (input as { message?: unknown }).message === "string"
|
||||
) {
|
||||
return (input as { message?: string }).message;
|
||||
if (typeof input === "object" && input !== null) {
|
||||
const maybeMessage = (input as { message?: unknown }).message;
|
||||
if (typeof maybeMessage === "string") return maybeMessage;
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(input);
|
||||
@@ -250,6 +241,7 @@ function normalizeNoticeMessage(
|
||||
},
|
||||
};
|
||||
}
|
||||
// Prefer showing the original string while still surfacing the raw details below.
|
||||
return {
|
||||
i18n: {
|
||||
key: "common.notices.prefixedRaw",
|
||||
@@ -285,9 +277,6 @@ function normalizeNoticeMessage(
|
||||
return { i18n: createRawDescriptor("") };
|
||||
}
|
||||
|
||||
/**
|
||||
* Imperative entry point for users to display new notices.
|
||||
*/
|
||||
const baseShowNotice = (
|
||||
type: NoticeType,
|
||||
message: NoticeContent,
|
||||
@@ -300,6 +289,7 @@ const baseShowNotice = (
|
||||
effectiveDuration > 0
|
||||
? setTimeout(() => hideNotice(id), effectiveDuration)
|
||||
: undefined;
|
||||
|
||||
const normalizedMessage = normalizeNoticeMessage(message, params, raw);
|
||||
const notice = buildNotice(
|
||||
id,
|
||||
@@ -342,11 +332,3 @@ export function subscribeNotices(subscriber: NoticeSubscriber) {
|
||||
export function getSnapshotNotices() {
|
||||
return notices;
|
||||
}
|
||||
|
||||
export function clearAllNotices() {
|
||||
notices.forEach((notice) => {
|
||||
if (notice.timerId) clearTimeout(notice.timerId);
|
||||
});
|
||||
notices = [];
|
||||
notifySubscribers();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user