refactor: cleanup

This commit is contained in:
zhom
2026-07-25 22:59:13 +04:00
parent 59a3e5f2a1
commit b9070693ed
49 changed files with 1204 additions and 2208 deletions
+31
View File
@@ -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":
+3 -10
View File
@@ -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 };
-31
View File
@@ -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
View File
@@ -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(" ")}`);
},
};
-9
View File
@@ -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;
}
+5
View File
@@ -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";
+25
View File
@@ -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
View File
@@ -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();
}
/**
-24
View File
@@ -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
View File
@@ -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));
}