Add foundational components and logic for migration, UI design, and input handling
- Introduced foundational UI components (`Badge`, `LockCard`, `SectionHeader`, `AvatarIcon`, etc.) for flexible layouts and consistent design. - Added migration support with the `MigrationModal` component and backend integration for exporting/importing data between Electron and Tauri. - Extended form components with `TextAreaInput`, `OrderInput`, `ToggleField`, and `ToolbarSelect` for improved input handling. - Updated `ScribeShell` with migration popup logic to prompt users for data migration. - Integrated `AlertStack` for better alert handling and notification management. - Enhanced Rust/Tauri services with migration command implementations. - Added translations and styles for new components.
This commit is contained in:
101
lib/crashReporter.ts
Normal file
101
lib/crashReporter.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import axios from 'axios';
|
||||
import {configs, isDesktop} from '@/lib/configs';
|
||||
|
||||
interface CrashReportPayload {
|
||||
appName: string;
|
||||
appVersion: string;
|
||||
platform: string;
|
||||
osVersion?: string;
|
||||
errorType: string;
|
||||
errorMessage: string;
|
||||
stackTrace?: string;
|
||||
screenName?: string;
|
||||
userId?: string;
|
||||
breadcrumbs?: Breadcrumb[];
|
||||
extraData?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
interface Breadcrumb {
|
||||
timestamp: number;
|
||||
action: string;
|
||||
detail?: string;
|
||||
}
|
||||
|
||||
const MAX_BREADCRUMBS = 30;
|
||||
const breadcrumbs: Breadcrumb[] = [];
|
||||
|
||||
export function addBreadcrumb(action: string, detail?: string): void {
|
||||
breadcrumbs.push({timestamp: Date.now(), action, detail});
|
||||
if (breadcrumbs.length > MAX_BREADCRUMBS) breadcrumbs.shift();
|
||||
}
|
||||
|
||||
function getPlatform(): string {
|
||||
if (!isDesktop) return 'web';
|
||||
const ua: string = navigator.userAgent.toLowerCase();
|
||||
if (ua.includes('mac')) return 'desktop-macos';
|
||||
if (ua.includes('win')) return 'desktop-windows';
|
||||
if (ua.includes('linux')) return 'desktop-linux';
|
||||
return 'desktop';
|
||||
}
|
||||
|
||||
function getUserId(): string | undefined {
|
||||
try {
|
||||
const raw: string | null = localStorage.getItem('userId');
|
||||
return raw ?? undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async function sendCrashReport(payload: CrashReportPayload): Promise<void> {
|
||||
try {
|
||||
await axios.post(configs.apiUrl + 'crash-report', payload, {
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
timeout: 5000,
|
||||
});
|
||||
} catch {
|
||||
// Silently fail — we can't crash while reporting a crash
|
||||
}
|
||||
}
|
||||
|
||||
function buildReport(errorType: string, errorMessage: string, stackTrace?: string): CrashReportPayload {
|
||||
return {
|
||||
appName: configs.appName,
|
||||
appVersion: configs.appVersion,
|
||||
platform: getPlatform(),
|
||||
osVersion: navigator.userAgent,
|
||||
errorType,
|
||||
errorMessage,
|
||||
stackTrace,
|
||||
screenName: window.location.pathname,
|
||||
userId: getUserId(),
|
||||
breadcrumbs: [...breadcrumbs],
|
||||
};
|
||||
}
|
||||
|
||||
export function reportError(error: Error, extraData?: Record<string, unknown>): void {
|
||||
const report: CrashReportPayload = buildReport(
|
||||
error.name || 'Error',
|
||||
error.message,
|
||||
error.stack,
|
||||
);
|
||||
if (extraData) report.extraData = extraData;
|
||||
sendCrashReport(report);
|
||||
}
|
||||
|
||||
export function initCrashReporter(): void {
|
||||
window.onerror = (_message, _source, _lineno, _colno, error: Error | undefined): void => {
|
||||
if (error) {
|
||||
sendCrashReport(buildReport('UncaughtError', error.message, error.stack));
|
||||
}
|
||||
};
|
||||
|
||||
window.onunhandledrejection = (event: PromiseRejectionEvent): void => {
|
||||
const reason: unknown = event.reason;
|
||||
if (reason instanceof Error) {
|
||||
sendCrashReport(buildReport('UnhandledRejection', reason.message, reason.stack));
|
||||
} else {
|
||||
sendCrashReport(buildReport('UnhandledRejection', String(reason)));
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user