refactor(notice): unify showNotice API
This commit is contained in:
@@ -63,10 +63,58 @@ export const NoticeManager: React.FC = () => {
|
||||
}
|
||||
>
|
||||
{notice.i18n
|
||||
? t(notice.i18n.i18nKey, {
|
||||
defaultValue: notice.i18n.fallback,
|
||||
...(notice.i18n.params ?? {}),
|
||||
})
|
||||
? (() => {
|
||||
const params = (notice.i18n.params ?? {}) as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
const {
|
||||
prefixKey,
|
||||
prefixParams,
|
||||
prefix,
|
||||
message,
|
||||
...restParams
|
||||
} = params;
|
||||
|
||||
const prefixKeyParams =
|
||||
prefixParams &&
|
||||
typeof prefixParams === "object" &&
|
||||
prefixParams !== null
|
||||
? (prefixParams as Record<string, unknown>)
|
||||
: undefined;
|
||||
|
||||
const resolvedPrefix =
|
||||
typeof prefixKey === "string"
|
||||
? t(prefixKey, {
|
||||
defaultValue: prefixKey,
|
||||
...(prefixKeyParams ?? {}),
|
||||
})
|
||||
: typeof prefix === "string"
|
||||
? prefix
|
||||
: undefined;
|
||||
|
||||
const finalParams: Record<string, unknown> = {
|
||||
...restParams,
|
||||
};
|
||||
if (resolvedPrefix !== undefined) {
|
||||
finalParams.prefix = resolvedPrefix;
|
||||
}
|
||||
if (typeof message === "string") {
|
||||
finalParams.message = message;
|
||||
}
|
||||
|
||||
const defaultValue =
|
||||
resolvedPrefix && typeof message === "string"
|
||||
? `${resolvedPrefix} ${message}`
|
||||
: typeof message === "string"
|
||||
? message
|
||||
: undefined;
|
||||
|
||||
return t(notice.i18n.key, {
|
||||
defaultValue,
|
||||
...finalParams,
|
||||
});
|
||||
})()
|
||||
: notice.message}
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
|
||||
@@ -26,7 +26,7 @@ import { useNavigate } from "react-router";
|
||||
|
||||
import { useAppData } from "@/providers/app-data-context";
|
||||
import { openWebUrl, updateProfile } from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import parseTraffic from "@/utils/parse-traffic";
|
||||
|
||||
import { EnhancedCard } from "./enhanced-card";
|
||||
@@ -297,7 +297,7 @@ export const HomeProfileCard = ({
|
||||
// 刷新首页数据
|
||||
refreshAll();
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()), 3000);
|
||||
showNotice.error(err.message || err.toString(), 3000);
|
||||
} finally {
|
||||
setUpdating(false);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import ProxyControlSwitches from "@/components/shared/ProxyControlSwitches";
|
||||
import { useSystemProxyState } from "@/hooks/use-system-proxy-state";
|
||||
import { useSystemState } from "@/hooks/use-system-state";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
const LOCAL_STORAGE_TAB_KEY = "clash-verge-proxy-active-tab";
|
||||
|
||||
@@ -148,7 +148,7 @@ export const ProxyTunCard: FC = () => {
|
||||
const { enable_tun_mode } = verge ?? {};
|
||||
|
||||
const handleError = (err: Error) => {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
showNotice.error(err.message || err.toString());
|
||||
};
|
||||
|
||||
const handleTabChange = (tab: string) => {
|
||||
|
||||
@@ -24,7 +24,7 @@ import { useSystemState } from "@/hooks/use-system-state";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { useServiceInstaller } from "@/hooks/useServiceInstaller";
|
||||
import { getSystemInfo } from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import { checkUpdateSafe as checkUpdate } from "@/services/update";
|
||||
import { version as appVersion } from "@root/package.json";
|
||||
|
||||
@@ -174,15 +174,13 @@ export const SystemInfoCard = () => {
|
||||
try {
|
||||
const info = await checkUpdate();
|
||||
if (!info?.available) {
|
||||
showNotice.success({
|
||||
i18nKey: "Currently on the Latest Version",
|
||||
});
|
||||
showNotice.success("Currently on the Latest Version");
|
||||
} else {
|
||||
showNotice.info({ i18nKey: "Update Available" }, 2000);
|
||||
showNotice.info("Update Available", 2000);
|
||||
goToSettings();
|
||||
}
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
showNotice.error(err.message || err.toString());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import { useTranslation } from "react-i18next";
|
||||
import MonacoEditor from "react-monaco-editor";
|
||||
import pac from "types-pac/pac.d.ts?raw";
|
||||
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import { useThemeMode } from "@/services/states";
|
||||
import debounce from "@/utils/debounce";
|
||||
import getSystem from "@/utils/get-system";
|
||||
@@ -132,8 +132,8 @@ export const EditorViewer = <T extends Language>(props: Props<T>) => {
|
||||
try {
|
||||
currData.current = value;
|
||||
onChange?.(prevData.current, currData.current);
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -143,16 +143,16 @@ export const EditorViewer = <T extends Language>(props: Props<T>) => {
|
||||
onSave?.(prevData.current, currData.current);
|
||||
}
|
||||
onClose();
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
const handleClose = useLockFn(async () => {
|
||||
try {
|
||||
onClose();
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ import {
|
||||
readProfileFile,
|
||||
saveProfileFile,
|
||||
} from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import { useThemeMode } from "@/services/states";
|
||||
import getSystem from "@/utils/get-system";
|
||||
|
||||
@@ -384,14 +384,12 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
}
|
||||
|
||||
await saveProfileFile(property, nextData);
|
||||
showNotice.success({
|
||||
i18nKey: "components.profile.notifications.saved",
|
||||
});
|
||||
showNotice.success("components.profile.notifications.saved");
|
||||
setPrevData(nextData);
|
||||
onSave?.(prevData, nextData);
|
||||
onClose();
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.toString()));
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -921,10 +919,8 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
}
|
||||
}
|
||||
setPrependSeq([formIns.getValues(), ...prependSeq]);
|
||||
} catch (err: any) {
|
||||
showNotice.error(
|
||||
createRawNotice(err.message || err.toString()),
|
||||
);
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
}}
|
||||
>
|
||||
@@ -949,10 +945,8 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
}
|
||||
}
|
||||
setAppendSeq([...appendSeq, formIns.getValues()]);
|
||||
} catch (err: any) {
|
||||
showNotice.error(
|
||||
createRawNotice(err.message || err.toString()),
|
||||
);
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
saveProfileFile,
|
||||
getNextUpdateTime,
|
||||
} from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import { useLoadingCache, useSetLoadingCache } from "@/services/states";
|
||||
import parseTraffic from "@/utils/parse-traffic";
|
||||
|
||||
@@ -320,8 +320,8 @@ export const ProfileItem = (props: Props) => {
|
||||
setAnchorEl(null);
|
||||
try {
|
||||
await viewProfile(itemData.uid);
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err?.message || err.toString()));
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import { useTranslation } from "react-i18next";
|
||||
|
||||
import { EditorViewer } from "@/components/profile/editor-viewer";
|
||||
import { viewProfile, readProfileFile, saveProfileFile } from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
import { LogViewer } from "./log-viewer";
|
||||
import { ProfileBox } from "./profile-box";
|
||||
@@ -47,8 +47,8 @@ export const ProfileMore = (props: Props) => {
|
||||
setAnchorEl(null);
|
||||
try {
|
||||
await viewProfile(id);
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err?.message || err.toString()));
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { BaseDialog, Switch } from "@/components/base";
|
||||
import { useProfiles } from "@/hooks/use-profiles";
|
||||
import { createProfile, patchProfile } from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import { version } from "@root/package.json";
|
||||
|
||||
import { FileInput } from "./file-input";
|
||||
@@ -184,8 +184,8 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) {
|
||||
setTimeout(() => {
|
||||
onChange(isActivating);
|
||||
}, 0);
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ import { Virtuoso } from "react-virtuoso";
|
||||
|
||||
import { ProxyItem } from "@/components/profile/proxy-item";
|
||||
import { readProfileFile, saveProfileFile } from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import { useThemeMode } from "@/services/states";
|
||||
import getSystem from "@/utils/get-system";
|
||||
import parseUri from "@/utils/uri-parser";
|
||||
@@ -263,13 +263,11 @@ export const ProxiesEditorViewer = (props: Props) => {
|
||||
const handleSave = useLockFn(async () => {
|
||||
try {
|
||||
await saveProfileFile(property, currData);
|
||||
showNotice.success({
|
||||
i18nKey: "components.profile.notifications.saved",
|
||||
});
|
||||
showNotice.success("components.profile.notifications.saved");
|
||||
onSave?.(prevData, currData);
|
||||
onClose();
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.toString()));
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ import { Virtuoso } from "react-virtuoso";
|
||||
import { Switch } from "@/components/base";
|
||||
import { RuleItem } from "@/components/profile/rule-item";
|
||||
import { readProfileFile, saveProfileFile } from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import { useThemeMode } from "@/services/states";
|
||||
import getSystem from "@/utils/get-system";
|
||||
|
||||
@@ -350,10 +350,8 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
{ forceQuotes: true },
|
||||
),
|
||||
);
|
||||
} catch (e: any) {
|
||||
showNotice.error(
|
||||
createRawNotice(e?.message || e?.toString() || "YAML dump error"),
|
||||
);
|
||||
} catch (error) {
|
||||
showNotice.error(error ?? "YAML dump error");
|
||||
}
|
||||
};
|
||||
let idleId: number | undefined;
|
||||
@@ -481,13 +479,11 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
const handleSave = useLockFn(async () => {
|
||||
try {
|
||||
await saveProfileFile(property, currData);
|
||||
showNotice.success({
|
||||
i18nKey: "components.profile.notifications.saved",
|
||||
});
|
||||
showNotice.success("components.profile.notifications.saved");
|
||||
onSave?.(prevData, currData);
|
||||
onClose();
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.toString()));
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -630,9 +626,7 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
if (prependSeq.includes(raw)) return;
|
||||
setPrependSeq([raw, ...prependSeq]);
|
||||
} catch (err: any) {
|
||||
showNotice.error(
|
||||
createRawNotice(err.message || err.toString()),
|
||||
);
|
||||
showNotice.error(err);
|
||||
}
|
||||
}}
|
||||
>
|
||||
@@ -650,9 +644,7 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
if (appendSeq.includes(raw)) return;
|
||||
setAppendSeq([...appendSeq, raw]);
|
||||
} catch (err: any) {
|
||||
showNotice.error(
|
||||
createRawNotice(err.message || err.toString()),
|
||||
);
|
||||
showNotice.error(err);
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -21,7 +21,7 @@ import { closeAllConnections, upgradeCore } from "tauri-plugin-mihomo-api";
|
||||
import { BaseDialog, DialogRef } from "@/components/base";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { changeClashCore, restartCore } from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
const VALID_CORE = [
|
||||
{ name: "Mihomo", core: "verge-mihomo", chip: "Release Version" },
|
||||
@@ -54,7 +54,7 @@ export function ClashCoreViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
const errorMsg = await changeClashCore(core);
|
||||
|
||||
if (errorMsg) {
|
||||
showNotice.error(createRawNotice(errorMsg));
|
||||
showNotice.error(errorMsg);
|
||||
setChangingCore(null);
|
||||
return;
|
||||
}
|
||||
@@ -65,9 +65,9 @@ export function ClashCoreViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
mutate("getVersion");
|
||||
setChangingCore(null);
|
||||
}, 500);
|
||||
} catch (err: any) {
|
||||
} catch (err) {
|
||||
setChangingCore(null);
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -77,9 +77,9 @@ export function ClashCoreViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
await restartCore();
|
||||
showNotice.success({ i18nKey: "Clash Core Restarted" });
|
||||
setRestarting(false);
|
||||
} catch (err: any) {
|
||||
} catch (err) {
|
||||
setRestarting(false);
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -95,7 +95,7 @@ export function ClashCoreViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
const showMsg = errMsg.includes("already using latest version")
|
||||
? "Already Using Latest Core Version"
|
||||
: errMsg;
|
||||
showNotice.error({ i18nKey: showMsg, fallback: showMsg });
|
||||
showNotice.error(showMsg);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { BaseDialog, DialogRef, Switch } from "@/components/base";
|
||||
import { useClashInfo } from "@/hooks/use-clash";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { createPrefixedNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
export function ControllerViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -81,12 +81,11 @@ export function ControllerViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
setOpen(false);
|
||||
} catch (err: any) {
|
||||
const message = err?.message || err?.toString?.();
|
||||
showNotice.error(
|
||||
message
|
||||
? createPrefixedNotice(t("Failed to save configuration"), message)
|
||||
: { i18nKey: "Failed to save configuration" },
|
||||
4000,
|
||||
);
|
||||
if (message) {
|
||||
showNotice.error(t("Failed to save configuration"), message, 4000);
|
||||
} else {
|
||||
showNotice.error("Failed to save configuration", 4000);
|
||||
}
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
|
||||
@@ -29,11 +29,7 @@ import MonacoEditor from "react-monaco-editor";
|
||||
|
||||
import { BaseDialog, DialogRef, Switch } from "@/components/base";
|
||||
import { useClash } from "@/hooks/use-clash";
|
||||
import {
|
||||
createPrefixedNotice,
|
||||
createRawNotice,
|
||||
showNotice,
|
||||
} from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import { useThemeMode } from "@/services/states";
|
||||
import getSystem from "@/utils/get-system";
|
||||
|
||||
@@ -551,12 +547,7 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
}
|
||||
}
|
||||
|
||||
showNotice.error(
|
||||
createPrefixedNotice(
|
||||
`${t("DNS configuration error")}:`,
|
||||
cleanErrorMsg,
|
||||
),
|
||||
);
|
||||
showNotice.error(`${t("DNS configuration error")}:`, cleanErrorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -568,8 +559,8 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
setOpen(false);
|
||||
showNotice.success({ i18nKey: "DNS settings saved" });
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useTranslation } from "react-i18next";
|
||||
|
||||
import { BaseDialog, DialogRef, Switch } from "@/components/base";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
import { HotkeyInput } from "./hotkey-input";
|
||||
|
||||
@@ -81,8 +81,8 @@ export const HotkeyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
enable_global_hotkey: enableGlobalHotkey,
|
||||
});
|
||||
setOpen(false);
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import { DEFAULT_HOVER_DELAY } from "@/components/proxy/proxy-group-navigator";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { useWindowDecorations } from "@/hooks/use-window";
|
||||
import { copyIconFile, getAppDir } from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import getSystem from "@/utils/get-system";
|
||||
|
||||
import { GuardState } from "./guard-state";
|
||||
@@ -104,7 +104,7 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
|
||||
const onSwitchFormat = (_e: any, value: boolean) => value;
|
||||
const onError = (err: any) => {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
showNotice.error(err);
|
||||
};
|
||||
const onChangeData = (patch: Partial<IVergeConfig>) => {
|
||||
mutateVerge({ ...verge, ...patch }, false);
|
||||
|
||||
@@ -15,7 +15,7 @@ import { BaseDialog, DialogRef, Switch } from "@/components/base";
|
||||
import { TooltipIcon } from "@/components/base/base-tooltip-icon";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { entry_lightweight_mode } from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
export function LiteModeViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -45,8 +45,8 @@ export function LiteModeViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
auto_light_weight_minutes: values.autoEnterLiteModeDelay,
|
||||
});
|
||||
setOpen(false);
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { BaseDialog, DialogRef, Switch } from "@/components/base";
|
||||
import { TooltipIcon } from "@/components/base/base-tooltip-icon";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -69,8 +69,8 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
auto_log_clean: values.autoLogClean as any,
|
||||
});
|
||||
setOpen(false);
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.toString()));
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
getSystemProxy,
|
||||
patchVergeConfig,
|
||||
} from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import getSystem from "@/utils/get-system";
|
||||
|
||||
const sleep = (ms: number) =>
|
||||
@@ -160,8 +160,8 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
mutate("getAutotemProxy"),
|
||||
]);
|
||||
}
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.toString()));
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -404,10 +404,10 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
console.warn("代理状态更新失败:", err);
|
||||
}
|
||||
}, 50);
|
||||
} catch (err: any) {
|
||||
} catch (err) {
|
||||
console.error("配置保存失败:", err);
|
||||
mutateVerge();
|
||||
showNotice.error(createRawNotice(err.toString()));
|
||||
showNotice.error(err);
|
||||
// setOpen(true);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@ import { BaseDialog, DialogRef } from "@/components/base";
|
||||
import { EditorViewer } from "@/components/profile/editor-viewer";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { defaultDarkTheme, defaultTheme } from "@/pages/_theme";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
export function ThemeViewer(props: { ref?: React.Ref<DialogRef> }) {
|
||||
const { ref } = props;
|
||||
@@ -50,8 +50,8 @@ export function ThemeViewer(props: { ref?: React.Ref<DialogRef> }) {
|
||||
try {
|
||||
await patchVerge({ theme_setting: theme });
|
||||
setOpen(false);
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.toString()));
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { BaseDialog, DialogRef, Switch } from "@/components/base";
|
||||
import { useClash } from "@/hooks/use-clash";
|
||||
import { enhanceProfiles } from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import getSystem from "@/utils/get-system";
|
||||
|
||||
import { StackModeSwitch } from "./stack-mode-switch";
|
||||
@@ -80,15 +80,13 @@ export function TunViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
);
|
||||
try {
|
||||
await enhanceProfiles();
|
||||
showNotice.success({
|
||||
i18nKey: "components.settings.tun.messages.applied",
|
||||
});
|
||||
showNotice.success("components.settings.tun.messages.applied");
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
showNotice.error(err);
|
||||
}
|
||||
setOpen(false);
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import useSWR from "swr";
|
||||
import { BaseDialog, DialogRef } from "@/components/base";
|
||||
import { useListen } from "@/hooks/use-listen";
|
||||
import { portableFlag } from "@/pages/_layout";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import { useSetUpdateState, useUpdateState } from "@/services/states";
|
||||
import { checkUpdateSafe as checkUpdate } from "@/services/update";
|
||||
|
||||
@@ -91,7 +91,7 @@ export function UpdateViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
await updateInfo.downloadAndInstall();
|
||||
await relaunch();
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err?.message || err.toString()));
|
||||
showNotice.error(err);
|
||||
} finally {
|
||||
setUpdateState(false);
|
||||
if (progressListener) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { BaseDialog, BaseEmpty, DialogRef } from "@/components/base";
|
||||
import { useClashInfo } from "@/hooks/use-clash";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { openWebUrl } from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
import { WebUIItem } from "./web-ui-item";
|
||||
|
||||
@@ -92,7 +92,7 @@ export function WebUIViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
await openWebUrl(url);
|
||||
} catch (e: any) {
|
||||
showNotice.error(createRawNotice(e.message || e.toString()));
|
||||
showNotice.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import { TooltipIcon } from "@/components/base/base-tooltip-icon";
|
||||
import { useClash } from "@/hooks/use-clash";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { invoke_uwp_tool } from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import { useClashLog } from "@/services/states";
|
||||
import getSystem from "@/utils/get-system";
|
||||
|
||||
@@ -71,7 +71,7 @@ const SettingClash = ({ onError }: Props) => {
|
||||
t("components.settings.clash.messages.geoDataUpdated"),
|
||||
);
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
showNotice.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -88,7 +88,7 @@ const SettingClash = ({ onError }: Props) => {
|
||||
} catch (err: any) {
|
||||
setDnsSettingsEnabled(!enable);
|
||||
localStorage.setItem("dns_settings_enabled", String(!enable));
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
showNotice.error(err);
|
||||
await patchVerge({ enable_dns_settings: !enable }).catch(() => {});
|
||||
throw err;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
openDevTools,
|
||||
openLogsDir,
|
||||
} from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import { checkUpdateSafe as checkUpdate } from "@/services/update";
|
||||
import { version } from "@root/package.json";
|
||||
|
||||
@@ -54,7 +54,7 @@ const SettingVergeAdvanced = ({ onError: _ }: Props) => {
|
||||
updateRef.current?.open();
|
||||
}
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
showNotice.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import { useSystemState } from "@/hooks/use-system-state";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { useServiceInstaller } from "@/hooks/useServiceInstaller";
|
||||
import { useServiceUninstaller } from "@/hooks/useServiceUninstaller";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
interface ProxySwitchProps {
|
||||
label?: string;
|
||||
@@ -126,7 +126,7 @@ const ProxyControlSwitches = ({
|
||||
const { enable_tun_mode, enable_system_proxy } = verge ?? {};
|
||||
|
||||
const showErrorNotice = useCallback(
|
||||
(msg: string) => showNotice.error({ i18nKey: msg }),
|
||||
(msg: string) => showNotice.error(msg),
|
||||
[],
|
||||
);
|
||||
|
||||
@@ -145,7 +145,7 @@ const ProxyControlSwitches = ({
|
||||
await installServiceAndRestartCore();
|
||||
await mutateSystemState();
|
||||
} catch (err) {
|
||||
showNotice.error(createRawNotice((err as Error).message || String(err)));
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -157,7 +157,7 @@ const ProxyControlSwitches = ({
|
||||
await uninstallServiceAndRestartCore();
|
||||
await mutateSystemState();
|
||||
} catch (err) {
|
||||
showNotice.error(createRawNotice((err as Error).message || String(err)));
|
||||
showNotice.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import { BaseLoading } from "@/components/base";
|
||||
import { useListen } from "@/hooks/use-listen";
|
||||
import { cmdTestDelay, downloadIconCache } from "@/services/cmds";
|
||||
import delayManager from "@/services/delay";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
import { TestBox } from "./test-box";
|
||||
|
||||
@@ -82,7 +82,7 @@ export const TestItem = ({
|
||||
try {
|
||||
removeTest(uid);
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
showNotice.error(err.message || err.toString());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useTranslation } from "react-i18next";
|
||||
|
||||
import { BaseDialog } from "@/components/base";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
interface Props {
|
||||
onChange: (uid: string, patch?: Partial<IVergeTestItem>) => void;
|
||||
@@ -101,7 +101,7 @@ export const TestViewer = forwardRef<TestViewerRef, Props>((props, ref) => {
|
||||
setLoading(false);
|
||||
setTimeout(() => formIns.reset(), 500);
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()));
|
||||
showNotice.error(err.message || err.toString());
|
||||
setLoading(false);
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback } from "react";
|
||||
|
||||
import { installService, restartCore } from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
import { useSystemState } from "./use-system-state";
|
||||
|
||||
@@ -11,14 +11,14 @@ const executeWithErrorHandling = async (
|
||||
successMessage?: string,
|
||||
) => {
|
||||
try {
|
||||
showNotice.info({ i18nKey: loadingMessage });
|
||||
showNotice.info(loadingMessage);
|
||||
await operation();
|
||||
if (successMessage) {
|
||||
showNotice.success({ i18nKey: successMessage });
|
||||
showNotice.success(successMessage);
|
||||
}
|
||||
} catch (err) {
|
||||
const msg = (err as Error)?.message || String(err);
|
||||
showNotice.error(createRawNotice(msg));
|
||||
showNotice.error(msg);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback } from "react";
|
||||
|
||||
import { restartCore, stopCore, uninstallService } from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
import { useSystemState } from "./use-system-state";
|
||||
|
||||
@@ -11,14 +11,14 @@ const executeWithErrorHandling = async (
|
||||
successMessage?: string,
|
||||
) => {
|
||||
try {
|
||||
showNotice.info({ i18nKey: loadingMessage });
|
||||
showNotice.info(loadingMessage);
|
||||
await operation();
|
||||
if (successMessage) {
|
||||
showNotice.success({ i18nKey: successMessage });
|
||||
showNotice.success(successMessage);
|
||||
}
|
||||
} catch (err) {
|
||||
const msg = (err as Error)?.message || String(err);
|
||||
showNotice.error(createRawNotice(msg));
|
||||
showNotice.error(msg);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
createPrefixedNotice,
|
||||
createRawNotice,
|
||||
showNotice,
|
||||
} from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
type NavigateFunction = (path: string, options?: any) => void;
|
||||
type TranslateFunction = (key: string) => string;
|
||||
@@ -16,85 +12,59 @@ export const handleNoticeMessage = (
|
||||
const handlers: Record<string, () => void> = {
|
||||
"import_sub_url::ok": () => {
|
||||
navigate("/profile", { state: { current: msg } });
|
||||
showNotice.success({ i18nKey: "Import Subscription Successful" });
|
||||
showNotice.success("Import Subscription Successful");
|
||||
},
|
||||
"import_sub_url::error": () => {
|
||||
navigate("/profile");
|
||||
showNotice.error(createRawNotice(msg));
|
||||
showNotice.error(msg);
|
||||
},
|
||||
"set_config::error": () => showNotice.error(createRawNotice(msg)),
|
||||
"set_config::error": () => showNotice.error(msg),
|
||||
update_with_clash_proxy: () =>
|
||||
showNotice.success(
|
||||
createPrefixedNotice(t("Update with Clash proxy successfully"), msg),
|
||||
),
|
||||
showNotice.success(t("Update with Clash proxy successfully"), msg),
|
||||
update_retry_with_clash: () =>
|
||||
showNotice.info({
|
||||
i18nKey: "Update failed, retrying with Clash proxy...",
|
||||
}),
|
||||
showNotice.info("Update failed, retrying with Clash proxy..."),
|
||||
update_failed_even_with_clash: () =>
|
||||
showNotice.error(
|
||||
createPrefixedNotice(
|
||||
`${t("Update failed even with Clash proxy")}:`,
|
||||
msg,
|
||||
),
|
||||
),
|
||||
update_failed: () => showNotice.error(createRawNotice(msg)),
|
||||
showNotice.error(`${t("Update failed even with Clash proxy")}:`, msg),
|
||||
update_failed: () => showNotice.error(msg),
|
||||
"config_validate::boot_error": () =>
|
||||
showNotice.error(
|
||||
createPrefixedNotice(t("Boot Config Validation Failed"), msg),
|
||||
),
|
||||
showNotice.error(t("Boot Config Validation Failed"), msg),
|
||||
"config_validate::core_change": () =>
|
||||
showNotice.error(
|
||||
createPrefixedNotice(t("Core Change Config Validation Failed"), msg),
|
||||
),
|
||||
showNotice.error(t("Core Change Config Validation Failed"), msg),
|
||||
"config_validate::error": () =>
|
||||
showNotice.error(
|
||||
createPrefixedNotice(t("Config Validation Failed"), msg),
|
||||
),
|
||||
showNotice.error(t("Config Validation Failed"), msg),
|
||||
"config_validate::process_terminated": () =>
|
||||
showNotice.error({
|
||||
i18nKey: "Config Validation Process Terminated",
|
||||
}),
|
||||
showNotice.error("Config Validation Process Terminated"),
|
||||
"config_validate::stdout_error": () =>
|
||||
showNotice.error(
|
||||
createPrefixedNotice(t("Config Validation Failed"), msg),
|
||||
),
|
||||
showNotice.error(t("Config Validation Failed"), msg),
|
||||
"config_validate::script_error": () =>
|
||||
showNotice.error(createPrefixedNotice(t("Script File Error"), msg)),
|
||||
showNotice.error(t("Script File Error"), msg),
|
||||
"config_validate::script_syntax_error": () =>
|
||||
showNotice.error(createPrefixedNotice(t("Script Syntax Error"), msg)),
|
||||
showNotice.error(t("Script Syntax Error"), msg),
|
||||
"config_validate::script_missing_main": () =>
|
||||
showNotice.error(createPrefixedNotice(t("Script Missing Main"), msg)),
|
||||
showNotice.error(t("Script Missing Main"), msg),
|
||||
"config_validate::file_not_found": () =>
|
||||
showNotice.error(createPrefixedNotice(t("File Not Found"), msg)),
|
||||
showNotice.error(t("File Not Found"), msg),
|
||||
"config_validate::yaml_syntax_error": () =>
|
||||
showNotice.error(createPrefixedNotice(t("YAML Syntax Error"), msg)),
|
||||
showNotice.error(t("YAML Syntax Error"), msg),
|
||||
"config_validate::yaml_read_error": () =>
|
||||
showNotice.error(createPrefixedNotice(t("YAML Read Error"), msg)),
|
||||
showNotice.error(t("YAML Read Error"), msg),
|
||||
"config_validate::yaml_mapping_error": () =>
|
||||
showNotice.error(createPrefixedNotice(t("YAML Mapping Error"), msg)),
|
||||
showNotice.error(t("YAML Mapping Error"), msg),
|
||||
"config_validate::yaml_key_error": () =>
|
||||
showNotice.error(createPrefixedNotice(t("YAML Key Error"), msg)),
|
||||
"config_validate::yaml_error": () =>
|
||||
showNotice.error(createPrefixedNotice(t("YAML Error"), msg)),
|
||||
showNotice.error(t("YAML Key Error"), msg),
|
||||
"config_validate::yaml_error": () => showNotice.error(t("YAML Error"), msg),
|
||||
"config_validate::merge_syntax_error": () =>
|
||||
showNotice.error(createPrefixedNotice(t("Merge File Syntax Error"), msg)),
|
||||
showNotice.error(t("Merge File Syntax Error"), msg),
|
||||
"config_validate::merge_mapping_error": () =>
|
||||
showNotice.error(
|
||||
createPrefixedNotice(t("Merge File Mapping Error"), msg),
|
||||
),
|
||||
showNotice.error(t("Merge File Mapping Error"), msg),
|
||||
"config_validate::merge_key_error": () =>
|
||||
showNotice.error(createPrefixedNotice(t("Merge File Key Error"), msg)),
|
||||
showNotice.error(t("Merge File Key Error"), msg),
|
||||
"config_validate::merge_error": () =>
|
||||
showNotice.error(createPrefixedNotice(t("Merge File Error"), msg)),
|
||||
showNotice.error(t("Merge File Error"), msg),
|
||||
"config_core::change_success": () =>
|
||||
showNotice.success(
|
||||
createPrefixedNotice(`${t("Core Changed Successfully")}:`, msg),
|
||||
),
|
||||
showNotice.success(`${t("Core Changed Successfully")}:`, msg),
|
||||
"config_core::change_error": () =>
|
||||
showNotice.error(
|
||||
createPrefixedNotice(`${t("Failed to Change Core")}:`, msg),
|
||||
),
|
||||
showNotice.error(`${t("Failed to Change Core")}:`, msg),
|
||||
};
|
||||
|
||||
const handler = handlers[status];
|
||||
|
||||
@@ -58,11 +58,7 @@ import {
|
||||
reorderProfile,
|
||||
updateProfile,
|
||||
} from "@/services/cmds";
|
||||
import {
|
||||
createPrefixedNotice,
|
||||
createRawNotice,
|
||||
showNotice,
|
||||
} from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import { useSetLoadingCache, useThemeMode } from "@/services/states";
|
||||
|
||||
// 记录profile切换状态
|
||||
@@ -150,10 +146,8 @@ const ProfilePage = () => {
|
||||
|
||||
setActivatings((prev) => prev.filter((id) => id !== previousSwitching));
|
||||
showNotice.info(
|
||||
createPrefixedNotice(
|
||||
t("pages.profiles.notifications.switchInterrupted"),
|
||||
`${previousSwitching} → ${newProfile}`,
|
||||
),
|
||||
t("pages.profiles.notifications.switchInterrupted"),
|
||||
`${previousSwitching} → ${newProfile}`,
|
||||
3000,
|
||||
);
|
||||
},
|
||||
@@ -197,9 +191,7 @@ const ProfilePage = () => {
|
||||
|
||||
for (const file of paths) {
|
||||
if (!file.endsWith(".yaml") && !file.endsWith(".yml")) {
|
||||
showNotice.error({
|
||||
i18nKey: "pages.profiles.errors.onlyYaml",
|
||||
});
|
||||
showNotice.error("pages.profiles.errors.onlyYaml");
|
||||
continue;
|
||||
}
|
||||
const item = {
|
||||
@@ -247,18 +239,13 @@ const ProfilePage = () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
await onEnhance(false);
|
||||
|
||||
showNotice.success(
|
||||
{ i18nKey: "pages.profiles.notices.forceRefreshCompleted" },
|
||||
2000,
|
||||
);
|
||||
showNotice.success("pages.profiles.notices.forceRefreshCompleted", 2000);
|
||||
} catch (error: any) {
|
||||
console.error("[紧急刷新] 失败:", error);
|
||||
const message = error?.message || String(error);
|
||||
showNotice.error(
|
||||
{
|
||||
i18nKey: "pages.profiles.notices.emergencyRefreshFailed",
|
||||
params: { message },
|
||||
},
|
||||
"pages.profiles.notices.emergencyRefreshFailed",
|
||||
{ message },
|
||||
4000,
|
||||
);
|
||||
}
|
||||
@@ -289,15 +276,13 @@ const ProfilePage = () => {
|
||||
if (!url) return;
|
||||
// 校验url是否为http/https
|
||||
if (!/^https?:\/\//i.test(url)) {
|
||||
showNotice.error({
|
||||
i18nKey: "pages.profiles.errors.invalidUrl",
|
||||
});
|
||||
showNotice.error("pages.profiles.errors.invalidUrl");
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
|
||||
const handleImportSuccess = async (noticeKey: string) => {
|
||||
showNotice.success({ i18nKey: noticeKey });
|
||||
showNotice.success(noticeKey);
|
||||
setUrl("");
|
||||
await performRobustRefresh();
|
||||
};
|
||||
@@ -309,9 +294,7 @@ const ProfilePage = () => {
|
||||
} catch (initialErr) {
|
||||
console.warn("[订阅导入] 首次导入失败:", initialErr);
|
||||
|
||||
showNotice.info({
|
||||
i18nKey: "pages.profiles.notifications.importRetry",
|
||||
});
|
||||
showNotice.info("pages.profiles.notifications.importRetry");
|
||||
try {
|
||||
// 使用自身代理尝试导入
|
||||
await importProfile(url, {
|
||||
@@ -527,7 +510,7 @@ const ProfilePage = () => {
|
||||
}
|
||||
|
||||
console.error(`[Profile] 切换失败:`, err);
|
||||
showNotice.error(createRawNotice(err?.message || err.toString()), 4000);
|
||||
showNotice.error(err, 4000);
|
||||
} finally {
|
||||
// 只有当前profile仍然是正在切换的profile且序列号匹配时才清理状态
|
||||
if (
|
||||
@@ -599,7 +582,7 @@ const ProfilePage = () => {
|
||||
);
|
||||
}
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.message || err.toString()), 3000);
|
||||
showNotice.error(err, 3000);
|
||||
} finally {
|
||||
// 保留正在切换的profile,清除其他状态
|
||||
setActivatings((prev) =>
|
||||
@@ -619,7 +602,7 @@ const ProfilePage = () => {
|
||||
await onEnhance(false);
|
||||
}
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err?.message || err.toString()));
|
||||
showNotice.error(err);
|
||||
} finally {
|
||||
setActivatings([]);
|
||||
}
|
||||
@@ -739,7 +722,7 @@ const ProfilePage = () => {
|
||||
i18nKey: "pages.profiles.notifications.batchDeleted",
|
||||
});
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err?.message || err.toString()));
|
||||
showNotice.error(err);
|
||||
} finally {
|
||||
setActivatings([]);
|
||||
}
|
||||
|
||||
@@ -9,14 +9,14 @@ import SettingSystem from "@/components/setting/setting-system";
|
||||
import SettingVergeAdvanced from "@/components/setting/setting-verge-advanced";
|
||||
import SettingVergeBasic from "@/components/setting/setting-verge-basic";
|
||||
import { openWebUrl } from "@/services/cmds";
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import { useThemeMode } from "@/services/states";
|
||||
|
||||
const SettingPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onError = (err: any) => {
|
||||
showNotice.error(createRawNotice(err?.message || err.toString()));
|
||||
showNotice.error(err?.message || err.toString());
|
||||
};
|
||||
|
||||
const toGithubRepo = useLockFn(() => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { invoke } from "@tauri-apps/api/core";
|
||||
import dayjs from "dayjs";
|
||||
import { getProxies, getProxyProviders } from "tauri-plugin-mihomo-api";
|
||||
|
||||
import { createRawNotice, showNotice } from "@/services/noticeService";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
export async function copyClashEnv() {
|
||||
return invoke<void>("copy_clash_env");
|
||||
@@ -314,28 +314,22 @@ export async function getAppDir() {
|
||||
}
|
||||
|
||||
export async function openAppDir() {
|
||||
return invoke<void>("open_app_dir").catch((err) =>
|
||||
showNotice.error(createRawNotice(err?.message || err.toString())),
|
||||
);
|
||||
return invoke<void>("open_app_dir").catch((err) => showNotice.error(err));
|
||||
}
|
||||
|
||||
export async function openCoreDir() {
|
||||
return invoke<void>("open_core_dir").catch((err) =>
|
||||
showNotice.error(createRawNotice(err?.message || err.toString())),
|
||||
);
|
||||
return invoke<void>("open_core_dir").catch((err) => showNotice.error(err));
|
||||
}
|
||||
|
||||
export async function openLogsDir() {
|
||||
return invoke<void>("open_logs_dir").catch((err) =>
|
||||
showNotice.error(createRawNotice(err?.message || err.toString())),
|
||||
);
|
||||
return invoke<void>("open_logs_dir").catch((err) => showNotice.error(err));
|
||||
}
|
||||
|
||||
export const openWebUrl = async (url: string) => {
|
||||
try {
|
||||
await invoke("open_web_url", { url });
|
||||
} catch (err: any) {
|
||||
showNotice.error(createRawNotice(err.toString()));
|
||||
showNotice.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -377,7 +371,7 @@ export async function cmdTestDelay(url: string) {
|
||||
|
||||
export async function invoke_uwp_tool() {
|
||||
return invoke<void>("invoke_uwp_tool").catch((err) =>
|
||||
showNotice.error(createRawNotice(err?.message || err.toString()), 1500),
|
||||
showNotice.error(err, 1500),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ReactNode } from "react";
|
||||
import i18n from "i18next";
|
||||
import { ReactNode, isValidElement } from "react";
|
||||
|
||||
type NoticeType = "success" | "error" | "info";
|
||||
|
||||
@@ -6,16 +7,13 @@ type NoticeType = "success" | "error" | "info";
|
||||
* Descriptor used when the notice content should be resolved through i18n.
|
||||
*/
|
||||
export interface NoticeTranslationDescriptor {
|
||||
i18nKey: string;
|
||||
key: string;
|
||||
params?: Record<string, unknown>;
|
||||
fallback?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification payload that either renders raw React content or defers to i18n.
|
||||
* Runtime representation of a notice entry queued for rendering.
|
||||
*/
|
||||
type NoticeMessage = ReactNode | NoticeTranslationDescriptor;
|
||||
|
||||
interface NoticeItem {
|
||||
readonly id: number;
|
||||
readonly type: NoticeType;
|
||||
@@ -25,12 +23,19 @@ interface NoticeItem {
|
||||
timerId?: ReturnType<typeof setTimeout>;
|
||||
}
|
||||
|
||||
type NoticeShortcut = (message: NoticeMessage, duration?: number) => number;
|
||||
type NoticeContent = unknown;
|
||||
|
||||
type NoticeExtra = unknown;
|
||||
|
||||
type NoticeShortcut = (
|
||||
message: NoticeContent,
|
||||
...extras: NoticeExtra[]
|
||||
) => number;
|
||||
|
||||
type ShowNotice = ((
|
||||
type: NoticeType,
|
||||
message: NoticeMessage,
|
||||
duration?: number,
|
||||
message: NoticeContent,
|
||||
...extras: NoticeExtra[]
|
||||
) => number) & {
|
||||
success: NoticeShortcut;
|
||||
error: NoticeShortcut;
|
||||
@@ -53,6 +58,54 @@ function notifySubscribers() {
|
||||
subscribers.forEach((subscriber) => subscriber());
|
||||
}
|
||||
|
||||
interface ParsedNoticeExtras {
|
||||
params?: Record<string, unknown>;
|
||||
raw?: unknown;
|
||||
duration?: number;
|
||||
}
|
||||
|
||||
function parseNoticeExtras(extras: NoticeExtra[]): ParsedNoticeExtras {
|
||||
let params: Record<string, unknown> | undefined;
|
||||
let raw: unknown;
|
||||
let duration: number | undefined;
|
||||
|
||||
for (const extra of extras) {
|
||||
if (extra === undefined) continue;
|
||||
|
||||
if (typeof extra === "number" && duration === undefined) {
|
||||
duration = extra;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isPlainRecord(extra)) {
|
||||
if (!params) {
|
||||
params = extra;
|
||||
continue;
|
||||
}
|
||||
if (!raw) {
|
||||
raw = extra;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!raw) {
|
||||
raw = extra;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!params && isPlainRecord(extra)) {
|
||||
params = extra;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (duration === undefined && typeof extra === "number") {
|
||||
duration = extra;
|
||||
}
|
||||
}
|
||||
|
||||
return { params, raw, duration };
|
||||
}
|
||||
|
||||
function resolveDuration(type: NoticeType, override?: number) {
|
||||
return override ?? DEFAULT_DURATIONS[type];
|
||||
}
|
||||
@@ -60,44 +113,201 @@ function resolveDuration(type: NoticeType, override?: number) {
|
||||
function buildNotice(
|
||||
id: number,
|
||||
type: NoticeType,
|
||||
message: NoticeMessage,
|
||||
duration: number,
|
||||
payload: { message?: ReactNode; i18n?: NoticeTranslationDescriptor },
|
||||
timerId?: ReturnType<typeof setTimeout>,
|
||||
): NoticeItem {
|
||||
if (isTranslationDescriptor(message)) {
|
||||
return {
|
||||
id,
|
||||
type,
|
||||
duration,
|
||||
timerId,
|
||||
i18n: message,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
id,
|
||||
type,
|
||||
duration,
|
||||
timerId,
|
||||
message,
|
||||
...payload,
|
||||
};
|
||||
}
|
||||
|
||||
function isMaybeTranslationDescriptor(
|
||||
message: unknown,
|
||||
): message is NoticeTranslationDescriptor {
|
||||
if (
|
||||
typeof message === "object" &&
|
||||
message !== null &&
|
||||
!Array.isArray(message) &&
|
||||
!isValidElement(message)
|
||||
) {
|
||||
return typeof (message as Record<string, unknown>).key === "string";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isPlainRecord(value: unknown): value is Record<string, unknown> {
|
||||
if (
|
||||
typeof value !== "object" ||
|
||||
value === null ||
|
||||
Array.isArray(value) ||
|
||||
value instanceof Error ||
|
||||
isValidElement(value)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const proto = Object.getPrototypeOf(value);
|
||||
return proto === Object.prototype || proto === null;
|
||||
}
|
||||
|
||||
function createRawDescriptor(message: string): NoticeTranslationDescriptor {
|
||||
return {
|
||||
key: "common.notices.raw",
|
||||
params: { message },
|
||||
};
|
||||
}
|
||||
|
||||
function shouldUseTranslationKey(
|
||||
key: string,
|
||||
params?: Record<string, unknown>,
|
||||
) {
|
||||
if (params && Object.keys(params).length > 0) return true;
|
||||
if (i18n.isInitialized) {
|
||||
return i18n.exists(key);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function extractDisplayText(input: unknown): string | undefined {
|
||||
if (input === null || input === undefined) return undefined;
|
||||
if (typeof input === "string") return input;
|
||||
if (typeof input === "number" || typeof input === "boolean") {
|
||||
return String(input);
|
||||
}
|
||||
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;
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(input);
|
||||
} catch {
|
||||
return String(input);
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeNoticeMessage(
|
||||
message: NoticeContent,
|
||||
params?: Record<string, unknown>,
|
||||
raw?: unknown,
|
||||
): { message?: ReactNode; i18n?: NoticeTranslationDescriptor } {
|
||||
const rawText = raw !== undefined ? extractDisplayText(raw) : undefined;
|
||||
|
||||
if (isValidElement(message)) {
|
||||
return { message };
|
||||
}
|
||||
|
||||
if (isMaybeTranslationDescriptor(message)) {
|
||||
const originalParams = message.params ?? {};
|
||||
const mergedParams = Object.keys(params ?? {}).length
|
||||
? { ...originalParams, ...params }
|
||||
: { ...originalParams };
|
||||
|
||||
if (rawText !== undefined) {
|
||||
return {
|
||||
i18n: {
|
||||
key: "common.notices.prefixedRaw",
|
||||
params: {
|
||||
...mergedParams,
|
||||
prefixKey: message.key,
|
||||
prefixParams: originalParams,
|
||||
message: rawText,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
i18n: {
|
||||
key: message.key,
|
||||
params: Object.keys(mergedParams).length ? mergedParams : undefined,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof message === "string") {
|
||||
if (rawText !== undefined) {
|
||||
if (shouldUseTranslationKey(message, params)) {
|
||||
return {
|
||||
i18n: {
|
||||
key: "common.notices.prefixedRaw",
|
||||
params: {
|
||||
...(params ?? {}),
|
||||
prefixKey: message,
|
||||
message: rawText,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
i18n: {
|
||||
key: "common.notices.prefixedRaw",
|
||||
params: {
|
||||
...(params ?? {}),
|
||||
prefix: message,
|
||||
message: rawText,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (shouldUseTranslationKey(message, params)) {
|
||||
return {
|
||||
i18n: {
|
||||
key: message,
|
||||
params: params && Object.keys(params).length ? params : undefined,
|
||||
},
|
||||
};
|
||||
}
|
||||
return { i18n: createRawDescriptor(message) };
|
||||
}
|
||||
|
||||
if (rawText !== undefined) {
|
||||
return { i18n: createRawDescriptor(rawText) };
|
||||
}
|
||||
|
||||
const extracted = extractDisplayText(message);
|
||||
if (extracted !== undefined) {
|
||||
return { i18n: createRawDescriptor(extracted) };
|
||||
}
|
||||
|
||||
return { i18n: createRawDescriptor("") };
|
||||
}
|
||||
|
||||
/**
|
||||
* Imperative entry point for users to display new notices.
|
||||
*/
|
||||
const baseShowNotice = (
|
||||
type: NoticeType,
|
||||
message: NoticeMessage,
|
||||
duration?: number,
|
||||
message: NoticeContent,
|
||||
...extras: NoticeExtra[]
|
||||
): number => {
|
||||
const id = nextId++;
|
||||
const { params, raw, duration } = parseNoticeExtras(extras);
|
||||
const effectiveDuration = resolveDuration(type, duration);
|
||||
const timerId =
|
||||
effectiveDuration > 0
|
||||
? setTimeout(() => hideNotice(id), effectiveDuration)
|
||||
: undefined;
|
||||
const notice = buildNotice(id, type, message, effectiveDuration, timerId);
|
||||
const normalizedMessage = normalizeNoticeMessage(message, params, raw);
|
||||
const notice = buildNotice(
|
||||
id,
|
||||
type,
|
||||
effectiveDuration,
|
||||
normalizedMessage,
|
||||
timerId,
|
||||
);
|
||||
|
||||
notices = [...notices, notice];
|
||||
notifySubscribers();
|
||||
@@ -105,31 +315,12 @@ const baseShowNotice = (
|
||||
};
|
||||
|
||||
export const showNotice: ShowNotice = Object.assign(baseShowNotice, {
|
||||
success: (message: NoticeMessage, duration?: number) =>
|
||||
baseShowNotice("success", message, duration),
|
||||
error: (message: NoticeMessage, duration?: number) =>
|
||||
baseShowNotice("error", message, duration),
|
||||
info: (message: NoticeMessage, duration?: number) =>
|
||||
baseShowNotice("info", message, duration),
|
||||
});
|
||||
|
||||
export const createRawNotice = (
|
||||
message: string,
|
||||
fallback?: string,
|
||||
): NoticeTranslationDescriptor => ({
|
||||
i18nKey: "common.notices.raw",
|
||||
params: { message },
|
||||
fallback: fallback ?? message,
|
||||
});
|
||||
|
||||
export const createPrefixedNotice = (
|
||||
prefix: string,
|
||||
message: string,
|
||||
fallback?: string,
|
||||
): NoticeTranslationDescriptor => ({
|
||||
i18nKey: "common.notices.prefixedRaw",
|
||||
params: { prefix, message },
|
||||
fallback: fallback ?? `${prefix} ${message}`,
|
||||
success: (message: NoticeContent, ...extras: NoticeExtra[]) =>
|
||||
baseShowNotice("success", message, ...extras),
|
||||
error: (message: NoticeContent, ...extras: NoticeExtra[]) =>
|
||||
baseShowNotice("error", message, ...extras),
|
||||
info: (message: NoticeContent, ...extras: NoticeExtra[]) =>
|
||||
baseShowNotice("info", message, ...extras),
|
||||
});
|
||||
|
||||
export function hideNotice(id: number) {
|
||||
@@ -159,17 +350,3 @@ export function clearAllNotices() {
|
||||
notices = [];
|
||||
notifySubscribers();
|
||||
}
|
||||
|
||||
function isTranslationDescriptor(
|
||||
message: NoticeMessage,
|
||||
): message is NoticeTranslationDescriptor {
|
||||
if (
|
||||
typeof message === "object" &&
|
||||
message !== null &&
|
||||
Object.prototype.hasOwnProperty.call(message, "i18nKey")
|
||||
) {
|
||||
const descriptor = message as NoticeTranslationDescriptor;
|
||||
return typeof descriptor.i18nKey === "string";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user