mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-04-17 07:50:33 +08:00
feat(notice): override context menu to copy error details
This commit is contained in:
parent
a981be80ef
commit
1889f18183
@ -40,5 +40,6 @@
|
|||||||
- 完善对 AnyTLS / Mieru / Sudoku 的 GUI 支持
|
- 完善对 AnyTLS / Mieru / Sudoku 的 GUI 支持
|
||||||
- macOS 和 Linux 对服务 IPC 权限进一步限制
|
- macOS 和 Linux 对服务 IPC 权限进一步限制
|
||||||
- 移除 Windows 自启动计划任务中冗余的 3 秒延时
|
- 移除 Windows 自启动计划任务中冗余的 3 秒延时
|
||||||
|
- 右键错误通知可复制错误详情
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|||||||
@ -6,13 +6,14 @@ import {
|
|||||||
Box,
|
Box,
|
||||||
type SnackbarOrigin,
|
type SnackbarOrigin,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import React, { useMemo, useSyncExternalStore } from "react";
|
import React, { useCallback, useMemo, useSyncExternalStore } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
subscribeNotices,
|
subscribeNotices,
|
||||||
hideNotice,
|
hideNotice,
|
||||||
getSnapshotNotices,
|
getSnapshotNotices,
|
||||||
|
showNotice,
|
||||||
} from "@/services/notice-service";
|
} from "@/services/notice-service";
|
||||||
import type { TranslationKey } from "@/types/generated/i18n-keys";
|
import type { TranslationKey } from "@/types/generated/i18n-keys";
|
||||||
|
|
||||||
@ -85,6 +86,45 @@ const resolveNoticeMessage = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const extractNoticeCopyText = (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 (React.isValidElement(input)) return undefined;
|
||||||
|
if (typeof input === "object") {
|
||||||
|
const maybeMessage = (input as { message?: unknown }).message;
|
||||||
|
if (typeof maybeMessage === "string") return maybeMessage;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return JSON.stringify(input);
|
||||||
|
} catch {
|
||||||
|
return String(input);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const resolveNoticeCopyText = (
|
||||||
|
notice: NoticeItem,
|
||||||
|
t: TranslationFn,
|
||||||
|
): string | undefined => {
|
||||||
|
if (
|
||||||
|
notice.i18n?.key === "shared.feedback.notices.prefixedRaw" ||
|
||||||
|
notice.i18n?.key === "shared.feedback.notices.raw"
|
||||||
|
) {
|
||||||
|
const rawText = extractNoticeCopyText(notice.i18n?.params?.message);
|
||||||
|
if (rawText) return rawText;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
extractNoticeCopyText(resolveNoticeMessage(notice, t)) ??
|
||||||
|
extractNoticeCopyText(notice.message)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
interface NoticeManagerProps {
|
interface NoticeManagerProps {
|
||||||
position?: NoticePosition | null;
|
position?: NoticePosition | null;
|
||||||
}
|
}
|
||||||
@ -105,6 +145,23 @@ export const NoticeManager: React.FC<NoticeManagerProps> = ({ position }) => {
|
|||||||
hideNotice(id);
|
hideNotice(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleNoticeCopy = useCallback(
|
||||||
|
async (notice: NoticeItem) => {
|
||||||
|
const text = resolveNoticeCopyText(notice, t);
|
||||||
|
if (!text) return;
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(text);
|
||||||
|
showNotice.success(
|
||||||
|
"shared.feedback.notifications.common.copySuccess",
|
||||||
|
1000,
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn("[NoticeManager] copy to clipboard failed:", error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[t],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -139,6 +196,11 @@ export const NoticeManager: React.FC<NoticeManagerProps> = ({ position }) => {
|
|||||||
severity={notice.type}
|
severity={notice.type}
|
||||||
variant="filled"
|
variant="filled"
|
||||||
sx={{ width: "100%" }}
|
sx={{ width: "100%" }}
|
||||||
|
onContextMenu={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
void handleNoticeCopy(notice);
|
||||||
|
}}
|
||||||
action={
|
action={
|
||||||
<IconButton
|
<IconButton
|
||||||
size="small"
|
size="small"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user