mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-25 08:46:22 +02:00
73 lines
2.3 KiB
TypeScript
73 lines
2.3 KiB
TypeScript
|
|
import { toast } from "sonner";
|
||
|
|
import { AbortedError, AppError, AuthenticationError, SURFSENSE_ISSUES_URL } from "./error";
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Build a GitHub issue URL pre-filled with diagnostic context.
|
||
|
|
* Avoids including PII — only structural metadata.
|
||
|
|
*/
|
||
|
|
export function buildIssueUrl(error: unknown): string {
|
||
|
|
const params = new URLSearchParams();
|
||
|
|
|
||
|
|
const lines: string[] = ["## Bug Report", "", "**Describe what happened:**", "", ""];
|
||
|
|
|
||
|
|
if (error instanceof AppError) {
|
||
|
|
lines.push("## Diagnostics (auto-filled)", "");
|
||
|
|
if (error.code) lines.push(`- **Error code:** \`${error.code}\``);
|
||
|
|
if (error.requestId) lines.push(`- **Request ID:** \`${error.requestId}\``);
|
||
|
|
if (error.status) lines.push(`- **HTTP status:** ${error.status}`);
|
||
|
|
lines.push(`- **Message:** ${error.message}`);
|
||
|
|
} else if (error instanceof Error) {
|
||
|
|
lines.push("## Diagnostics (auto-filled)", "");
|
||
|
|
lines.push(`- **Error:** ${error.message}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
lines.push(`- **Timestamp:** ${new Date().toISOString()}`);
|
||
|
|
lines.push(
|
||
|
|
`- **Page:** \`${typeof window !== "undefined" ? window.location.pathname : "unknown"}\``
|
||
|
|
);
|
||
|
|
lines.push(
|
||
|
|
`- **User Agent:** \`${typeof navigator !== "undefined" ? navigator.userAgent : "unknown"}\``
|
||
|
|
);
|
||
|
|
|
||
|
|
params.set("body", lines.join("\n"));
|
||
|
|
params.set("labels", "bug");
|
||
|
|
|
||
|
|
return `${SURFSENSE_ISSUES_URL}/new?${params.toString()}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Show a standardized error toast with a "Report Issue" action.
|
||
|
|
*
|
||
|
|
* Suppressed for:
|
||
|
|
* - AbortedError (user-initiated cancellation)
|
||
|
|
* - AuthenticationError (handled by redirect)
|
||
|
|
*/
|
||
|
|
export function showErrorToast(error: unknown, fallbackMessage?: string) {
|
||
|
|
if (error instanceof AbortedError || error instanceof AuthenticationError) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const message =
|
||
|
|
error instanceof AppError
|
||
|
|
? error.message
|
||
|
|
: error instanceof Error
|
||
|
|
? error.message
|
||
|
|
: (fallbackMessage ?? "An unexpected error occurred.");
|
||
|
|
|
||
|
|
const code = error instanceof AppError ? error.code : undefined;
|
||
|
|
const requestId = error instanceof AppError ? error.requestId : undefined;
|
||
|
|
|
||
|
|
const descParts: string[] = [];
|
||
|
|
if (code) descParts.push(`Error: ${code}`);
|
||
|
|
if (requestId) descParts.push(`ID: ${requestId}`);
|
||
|
|
|
||
|
|
toast.error(message, {
|
||
|
|
description: descParts.length > 0 ? descParts.join(" | ") : undefined,
|
||
|
|
duration: 8000,
|
||
|
|
action: {
|
||
|
|
label: "Report Issue",
|
||
|
|
onClick: () => window.open(buildIssueUrl(error), "_blank"),
|
||
|
|
},
|
||
|
|
});
|
||
|
|
}
|