mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-08-11 21:50:24 +02:00
refactor: cleanup
This commit is contained in:
@@ -54,6 +54,15 @@ export type BackendErrorCode =
|
||||
| "UNSUPPORTED_DNS_RULES_FORMAT"
|
||||
| "DNS_RULES_SAVE_FAILED"
|
||||
| "DNS_RULES_EXPORT_FAILED"
|
||||
| "WAYFERN_TERMS_REQUIRED"
|
||||
| "API_PORT_UNAVAILABLE"
|
||||
| "MCP_SERVER_ALREADY_RUNNING"
|
||||
| "MCP_SERVER_NOT_RUNNING"
|
||||
| "MCP_PORT_UNAVAILABLE"
|
||||
| "MCP_CONFIGURATION_UNAVAILABLE"
|
||||
| "MCP_AGENT_UNKNOWN"
|
||||
| "MCP_AGENT_INSTALL_FAILED"
|
||||
| "MCP_AGENT_REMOVE_FAILED"
|
||||
| "INTERNAL_ERROR";
|
||||
|
||||
export interface BackendError {
|
||||
@@ -211,6 +220,28 @@ export function translateBackendError(t: TFunction, err: unknown): string {
|
||||
return t("backendErrors.dnsRulesSaveFailed");
|
||||
case "DNS_RULES_EXPORT_FAILED":
|
||||
return t("backendErrors.dnsRulesExportFailed");
|
||||
case "WAYFERN_TERMS_REQUIRED":
|
||||
return t("backendErrors.wayfernTermsRequired");
|
||||
case "API_PORT_UNAVAILABLE":
|
||||
return t("backendErrors.apiPortUnavailable");
|
||||
case "MCP_SERVER_ALREADY_RUNNING":
|
||||
return t("backendErrors.mcpServerAlreadyRunning");
|
||||
case "MCP_SERVER_NOT_RUNNING":
|
||||
return t("backendErrors.mcpServerNotRunning");
|
||||
case "MCP_PORT_UNAVAILABLE":
|
||||
return t("backendErrors.mcpPortUnavailable");
|
||||
case "MCP_CONFIGURATION_UNAVAILABLE":
|
||||
return t("backendErrors.mcpConfigurationUnavailable");
|
||||
case "MCP_AGENT_UNKNOWN":
|
||||
return t("backendErrors.mcpAgentUnknown");
|
||||
case "MCP_AGENT_INSTALL_FAILED":
|
||||
return t("backendErrors.mcpAgentInstallFailed", {
|
||||
detail: parsed.params?.detail ?? "",
|
||||
});
|
||||
case "MCP_AGENT_REMOVE_FAILED":
|
||||
return t("backendErrors.mcpAgentRemoveFailed", {
|
||||
detail: parsed.params?.detail ?? "",
|
||||
});
|
||||
case "CLEAR_ON_CLOSE_UNAVAILABLE":
|
||||
return t("backendErrors.clearOnCloseUnavailable");
|
||||
case "INTERNAL_ERROR":
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
|
||||
import { FaChrome, FaExclamationTriangle, FaFire } from "react-icons/fa";
|
||||
import { LuLock } from "react-icons/lu";
|
||||
import { getCurrentOS } from "@/lib/platform";
|
||||
|
||||
export { getCurrentOS } from "@/lib/platform";
|
||||
|
||||
/**
|
||||
* Map internal browser names to display names
|
||||
@@ -45,16 +48,6 @@ export function getProfileIcon(profile: {
|
||||
return getBrowserIcon(profile.browser);
|
||||
}
|
||||
|
||||
export const getCurrentOS = () => {
|
||||
if (typeof window !== "undefined") {
|
||||
const userAgent = window.navigator.userAgent;
|
||||
if (userAgent.includes("Win")) return "windows";
|
||||
if (userAgent.includes("Mac")) return "macos";
|
||||
if (userAgent.includes("Linux")) return "linux";
|
||||
}
|
||||
return "unknown";
|
||||
};
|
||||
|
||||
export function isCrossOsProfile(profile: {
|
||||
host_os?: string;
|
||||
wayfern_config?: { os?: string };
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
/**
|
||||
* Extracts the root error message from nested error strings
|
||||
* Removes redundant "Failed to..." prefixes to show only the most specific error
|
||||
*/
|
||||
export function extractRootError(error: unknown): string {
|
||||
if (!error) return "Unknown error";
|
||||
|
||||
const errorStr = error instanceof Error ? error.message : String(error);
|
||||
|
||||
// Split by common error prefixes and take the last meaningful part
|
||||
const errorParts = errorStr.split(/Failed to [^:]+: /);
|
||||
const rootError = errorParts[errorParts.length - 1];
|
||||
|
||||
// Clean up any remaining nested structure
|
||||
const cleanError = rootError.replace(/^"([^"]+)"$/, "$1");
|
||||
|
||||
return cleanError || errorStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows error toast with cleaned error message
|
||||
*/
|
||||
export function showCleanErrorToast(error: unknown, prefix?: string) {
|
||||
const rootError = extractRootError(error);
|
||||
const message = prefix ? `${prefix}: ${rootError}` : rootError;
|
||||
|
||||
// Import dynamically to avoid circular dependencies
|
||||
void import("./toast-utils").then(({ showErrorToast }) => {
|
||||
showErrorToast(message);
|
||||
});
|
||||
}
|
||||
+1
-26
@@ -1,11 +1,4 @@
|
||||
import {
|
||||
attachConsole,
|
||||
debug,
|
||||
error,
|
||||
info,
|
||||
trace,
|
||||
warn,
|
||||
} from "@tauri-apps/plugin-log";
|
||||
import { attachConsole } from "@tauri-apps/plugin-log";
|
||||
|
||||
let consoleAttached = false;
|
||||
|
||||
@@ -22,21 +15,3 @@ export async function setupLogging() {
|
||||
console.error("Failed to attach console to logging plugin:", err);
|
||||
}
|
||||
}
|
||||
|
||||
export const logger = {
|
||||
error: (message: string, ...args: unknown[]) => {
|
||||
error(`${message} ${args.map((arg) => JSON.stringify(arg)).join(" ")}`);
|
||||
},
|
||||
warn: (message: string, ...args: unknown[]) => {
|
||||
warn(`${message} ${args.map((arg) => JSON.stringify(arg)).join(" ")}`);
|
||||
},
|
||||
info: (message: string, ...args: unknown[]) => {
|
||||
info(`${message} ${args.map((arg) => JSON.stringify(arg)).join(" ")}`);
|
||||
},
|
||||
debug: (message: string, ...args: unknown[]) => {
|
||||
debug(`${message} ${args.map((arg) => JSON.stringify(arg)).join(" ")}`);
|
||||
},
|
||||
log: (message: string, ...args: unknown[]) => {
|
||||
trace(`${message} ${args.map((arg) => JSON.stringify(arg)).join(" ")}`);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
/**
|
||||
* Trims a name to a maximum length and adds ellipsis if needed
|
||||
* @param name The name to trim
|
||||
* @param maxLength Maximum length before truncation (default: 30)
|
||||
* @returns Trimmed name with ellipsis if truncated
|
||||
*/
|
||||
export function trimName(name: string, maxLength: number = 30): string {
|
||||
return name.length > maxLength ? `${name.substring(0, maxLength)}...` : name;
|
||||
}
|
||||
@@ -16,3 +16,8 @@ export function isOnboardingActive(): boolean {
|
||||
// clicks "Finish" (not when they skip early). The page listens for it to show
|
||||
// the celebratory thank-you dialog.
|
||||
export const ONBOARDING_TOUR_FINISHED_EVENT = "donut:onboarding-tour-finished";
|
||||
|
||||
// Dispatched when the product tour is either finished or explicitly skipped.
|
||||
// This is separate from the finished event because both outcomes complete the
|
||||
// one-shot onboarding, while only a full finish earns the celebration.
|
||||
export const ONBOARDING_TOUR_CLOSED_EVENT = "donut:onboarding-tour-closed";
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
export type OperatingSystem = "macos" | "windows" | "linux" | "unknown";
|
||||
|
||||
type NavigatorWithUserAgentData = Navigator & {
|
||||
userAgentData?: {
|
||||
platform?: string;
|
||||
};
|
||||
};
|
||||
|
||||
export function getCurrentOS(): OperatingSystem {
|
||||
if (typeof navigator === "undefined") return "unknown";
|
||||
|
||||
const extendedNavigator = navigator as NavigatorWithUserAgentData;
|
||||
const platform =
|
||||
extendedNavigator.userAgentData?.platform ?? navigator.platform ?? "";
|
||||
const signature = `${platform} ${navigator.userAgent}`;
|
||||
|
||||
if (/Windows|Win32|Win64/i.test(signature)) return "windows";
|
||||
if (/Mac|iPhone|iPad|iPod/i.test(signature)) return "macos";
|
||||
if (/Linux|X11/i.test(signature)) return "linux";
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
export function isMacOS(): boolean {
|
||||
return getCurrentOS() === "macos";
|
||||
}
|
||||
+4
-11
@@ -5,6 +5,8 @@
|
||||
* the ⌘ glyph while everyone else sees `Ctrl`.
|
||||
*/
|
||||
|
||||
import { isMacOS } from "@/lib/platform";
|
||||
|
||||
export type ShortcutGroup =
|
||||
| "navigation"
|
||||
| "actions"
|
||||
@@ -137,17 +139,8 @@ export function formatGroupShortcut(digit: number): string[] {
|
||||
return [mac ? "⌘" : "Ctrl", String(digit)];
|
||||
}
|
||||
|
||||
export function isMac(): boolean {
|
||||
if (typeof navigator === "undefined") return false;
|
||||
// userAgentData is preferred but not in all browsers; fall back to platform.
|
||||
// `navigator.platform` is deprecated but still works in Tauri's webview.
|
||||
const ua = navigator.userAgent || "";
|
||||
const platform =
|
||||
(navigator as unknown as { userAgentData?: { platform?: string } })
|
||||
.userAgentData?.platform ??
|
||||
navigator.platform ??
|
||||
"";
|
||||
return /Mac|iPhone|iPad|iPod/.test(platform) || /Mac OS X/.test(ua);
|
||||
function isMac(): boolean {
|
||||
return isMacOS();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -283,27 +283,3 @@ export function showSyncProgressToast(
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function showUnifiedVersionUpdateToast(
|
||||
title: string,
|
||||
options?: {
|
||||
id?: string;
|
||||
description?: string;
|
||||
progress?: {
|
||||
current: number;
|
||||
total: number;
|
||||
found: number;
|
||||
current_browser?: string;
|
||||
};
|
||||
duration?: number;
|
||||
onCancel?: () => void;
|
||||
},
|
||||
) {
|
||||
return showToast({
|
||||
type: "version-update",
|
||||
title,
|
||||
id: "unified-version-update",
|
||||
duration: Number.POSITIVE_INFINITY, // Keep showing until completed
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,7 +4,3 @@ import { twMerge } from "tailwind-merge";
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
export function sleep(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user