add more ui logs and fix sonarqube lint

This commit is contained in:
Eduard Gert
2026-06-16 13:45:54 +02:00
parent b16bdf5e8f
commit 192c3109c0
10 changed files with 147 additions and 90 deletions

View File

@@ -50,7 +50,8 @@ export const CopyToClipboard = ({
setCopied(true);
if (copyTimer.current) clearTimeout(copyTimer.current);
copyTimer.current = setTimeout(() => setCopied(false), 500);
} catch {
} catch (e) {
console.warn("copy to clipboard failed", e);
}
};

View File

@@ -31,7 +31,7 @@ export function LanguagePicker() {
.then((list) => {
if (!cancelled) setLanguages(list);
})
.catch(() => {});
.catch((err: unknown) => console.error("load languages failed", err));
return () => {
cancelled = true;
};

View File

@@ -163,7 +163,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button
if (copyTimer.current) clearTimeout(copyTimer.current);
copyTimer.current = setTimeout(() => setCopied(false), 1500);
})
.catch(() => {});
.catch((e: unknown) => console.warn("copy to clipboard failed", e));
}
onClick?.(e);
}}

View File

@@ -279,7 +279,8 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
setCopied(true);
if (copyTimer.current) clearTimeout(copyTimer.current);
copyTimer.current = setTimeout(() => setCopied(false), 1500);
} catch {
} catch (e) {
console.warn("copy to clipboard failed", e);
}
};

View File

@@ -8,9 +8,6 @@ import { startConnection } from "@/lib/connection.ts";
const NETBIRD_UPLOAD_URL = "https://upload.debug.netbird.io/upload-url";
const TRACE_LOG_FILE_COUNT = 5;
const PLAIN_LOG_FILE_COUNT = 1;
// Lowercase logrus level name sent to Debug.SetLogLevel (the Go binding
// upper-cases before the proto enum lookup). Raising to trace is what drives
// the daemon's verbose logging and the GUI's gui-client.log during a bundle.
const TRACE_LOG_LEVEL = "trace";
const DEFAULT_LOG_LEVEL = "info";
@@ -51,22 +48,53 @@ const throwIfAborted = (signal: AbortSignal) => {
const setLogLevelBestEffort = async (level: string) => {
try {
await DebugSvc.SetLogLevel({ level });
} catch {
// empty
} catch (e) {
console.warn("[DebugBundle] best-effort set log level failed", e);
}
};
const stopCaptureBestEffort = async () => {
try {
await DebugSvc.StopBundleCapture();
} catch {
// empty
} catch (e) {
console.warn("[DebugBundle] best-effort stop packet capture failed", e);
}
};
type LevelState = { original: string; raised: boolean };
type CaptureState = { started: boolean };
type BundleOptions = {
trace: boolean;
capture: boolean;
capturePackets: boolean;
hasWindow: boolean;
totalSec: number;
uploadUrl: string;
anonymize: boolean;
systemInfo: boolean;
};
const startCaptureBestEffort = async (totalSec: number, pcap: CaptureState) => {
try {
// Mirror the CLI's safety margin: window + 30s, server caps at 10m.
await DebugSvc.StartBundleCapture(totalSec + 30);
pcap.started = true;
} catch (e) {
console.warn("[DebugBundle] start packet capture failed", e);
}
};
const cleanupBestEffort = async (pcap: CaptureState, level: LevelState, restoreLevel: boolean) => {
if (pcap.started) {
await stopCaptureBestEffort();
pcap.started = false;
}
if (restoreLevel && level.raised) {
await setLogLevelBestEffort(level.original);
}
};
const raiseToTrace = async (
signal: AbortSignal,
level: LevelState,
@@ -76,8 +104,8 @@ const raiseToTrace = async (
try {
const cur = await DebugSvc.GetLogLevel();
if (cur?.level) level.original = cur.level;
} catch {
// empty
} catch (e) {
console.warn("[DebugBundle] read current log level failed", e);
}
throwIfAborted(signal);
await DebugSvc.SetLogLevel({ level: TRACE_LOG_LEVEL });
@@ -89,8 +117,8 @@ const cycleConnection = async (signal: AbortSignal, setStage: (s: DebugStage) =>
setStage({ kind: "reconnecting" });
try {
await ConnectionSvc.Down();
} catch {
// empty
} catch (e) {
console.warn("[DebugBundle] disconnect before capture failed", e);
}
throwIfAborted(signal);
await startConnection(undefined, signal);
@@ -101,8 +129,8 @@ const restoreLogLevel = async (level: LevelState, setStage: (s: DebugStage) => v
try {
await DebugSvc.SetLogLevel({ level: level.original });
level.raised = false;
} catch {
// empty
} catch (e) {
console.warn("[DebugBundle] restore log level failed", e);
}
};
@@ -117,6 +145,58 @@ const waitCaptureWindow = async (
}
};
const runBundleFlow = async (
signal: AbortSignal,
opts: BundleOptions,
level: LevelState,
pcap: CaptureState,
setStage: (s: DebugStage) => void,
setLastBundlePath: (p: string) => void,
) => {
if (opts.trace) {
await raiseToTrace(signal, level, setStage);
}
throwIfAborted(signal);
if (opts.capture) {
await cycleConnection(signal, setStage);
}
throwIfAborted(signal);
if (opts.hasWindow && opts.capturePackets) {
await startCaptureBestEffort(opts.totalSec, pcap);
}
throwIfAborted(signal);
if (opts.hasWindow) {
await waitCaptureWindow(signal, setStage, opts.totalSec);
}
if (pcap.started) {
await stopCaptureBestEffort();
pcap.started = false;
}
if (level.raised) {
await restoreLogLevel(level, setStage);
}
throwIfAborted(signal);
setStage({ kind: "bundling" });
const logFileCount = opts.trace ? TRACE_LOG_FILE_COUNT : PLAIN_LOG_FILE_COUNT;
if (opts.uploadUrl) setStage({ kind: "uploading" });
const result = await DebugSvc.Bundle({
anonymize: opts.anonymize,
systemInfo: opts.systemInfo,
uploadUrl: opts.uploadUrl,
logFileCount,
});
throwIfAborted(signal);
if (result.path) setLastBundlePath(result.path);
setStage({ kind: "done", result, uploadAttempted: Boolean(opts.uploadUrl) });
};
const useDebugBundle = () => {
const [anonymize, setAnonymize] = useState(false);
const [systemInfo, setSystemInfo] = useState(true);
@@ -150,74 +230,30 @@ const useDebugBundle = () => {
abortRef.current = ctrl;
const signal = ctrl.signal;
const uploadUrl = upload ? NETBIRD_UPLOAD_URL : "";
const totalSec = Math.max(1, Math.min(30, traceMinutes)) * 60;
const level: LevelState = { original: DEFAULT_LOG_LEVEL, raised: false };
const pcap: CaptureState = { started: false };
const totalSec = Math.max(1, Math.min(30, traceMinutes)) * 60;
const hasWindow = capture && totalSec > 0;
const opts: BundleOptions = {
trace,
capture,
capturePackets,
hasWindow: capture && totalSec > 0,
totalSec,
uploadUrl: upload ? NETBIRD_UPLOAD_URL : "",
anonymize,
systemInfo,
};
try {
if (trace) {
await raiseToTrace(signal, level, setStage);
}
throwIfAborted(signal);
if (capture) {
await cycleConnection(signal, setStage);
}
throwIfAborted(signal);
if (hasWindow && capturePackets) {
try {
// Mirror the CLI's safety margin: window + 30s, server caps at 10m.
await DebugSvc.StartBundleCapture(totalSec + 30);
pcap.started = true;
} catch {
// empty
}
}
throwIfAborted(signal);
if (hasWindow) {
await waitCaptureWindow(signal, setStage, totalSec);
}
if (pcap.started) {
await stopCaptureBestEffort();
pcap.started = false;
}
if (level.raised) {
await restoreLogLevel(level, setStage);
}
throwIfAborted(signal);
setStage({ kind: "bundling" });
const logFileCount = trace ? TRACE_LOG_FILE_COUNT : PLAIN_LOG_FILE_COUNT;
if (uploadUrl) setStage({ kind: "uploading" });
const result = await DebugSvc.Bundle({
anonymize,
systemInfo,
uploadUrl,
logFileCount,
});
throwIfAborted(signal);
if (result.path) setLastBundlePath(result.path);
setStage({
kind: "done",
result,
uploadAttempted: Boolean(uploadUrl),
});
await runBundleFlow(signal, opts, level, pcap, setStage, setLastBundlePath);
} catch (e) {
if (isAbort(e)) {
setStage({ kind: "cancelling" });
if (pcap.started) await stopCaptureBestEffort();
if (level.raised) await setLogLevelBestEffort(level.original);
await cleanupBestEffort(pcap, level, true);
setStage({ kind: "idle" });
return;
}
if (pcap.started) await stopCaptureBestEffort();
await cleanupBestEffort(pcap, level, false);
setStage({ kind: "idle" });
await errorDialog({
Title: i18next.t("settings.error.debugBundleTitle"),

View File

@@ -124,7 +124,7 @@ const useSettingsState = () => {
const save = useCallback(
async (profileName: string, next: Config, preSharedKey?: string) => {
const preSharedKeyWrite = preSharedKey !== undefined ? { preSharedKey } : {};
const preSharedKeyWrite = preSharedKey === undefined ? {} : { preSharedKey };
try {
await SettingsSvc.SetConfig({
...next,
@@ -194,9 +194,9 @@ const useSettingsState = () => {
const merged: Config = { ...loaded.data, ...partial };
const next: Config =
opts?.preSharedKey !== undefined
? { ...merged, preSharedKeySet: opts.preSharedKey !== "" }
: merged;
opts?.preSharedKey === undefined
? merged
: { ...merged, preSharedKeySet: opts.preSharedKey !== "" };
setLoaded({ profileName: loaded.profileName, data: next });
await save(loaded.profileName, next, opts?.preSharedKey);
},
@@ -235,8 +235,9 @@ export const AutostartSettingsProvider = ({ children }: { children: ReactNode })
const enabled = supported ? await Autostart.IsEnabled() : false;
if (cancelled) return;
setAutostart({ supported, enabled });
})().catch(() => {
})().catch((err: unknown) => {
if (cancelled) return;
console.warn("[SettingsContext] load autostart state failed", err);
setAutostart({ supported: false, enabled: false });
});
return () => {

View File

@@ -43,7 +43,7 @@ export const ViewModeProvider = ({ children }: { children: ReactNode }) => {
setMode(saved);
}
})
.catch(() => {});
.catch((err: unknown) => console.warn("[ViewModeContext] load preferences failed", err));
return () => {
cancelled = true;
};
@@ -54,10 +54,15 @@ export const ViewModeProvider = ({ children }: { children: ReactNode }) => {
if (modeRef.current === mode) return;
modeRef.current = mode;
(async () => {
const size = await Window.Size().catch(() => null);
const size = await Window.Size().catch((err: unknown) => {
console.warn("[ViewModeContext] read window size failed", err);
return null;
});
const width = VIEW_WIDTH[mode];
const height = size?.height ?? 640;
await Window.SetSize(width, height).catch(() => {});
await Window.SetSize(width, height).catch((err: unknown) =>
console.warn("[ViewModeContext] set window size failed", err),
);
setMode(mode);
const pref =
mode === "advanced" ? ViewModePref.ViewModeAdvanced : ViewModePref.ViewModeDefault;

View File

@@ -53,11 +53,14 @@ export async function initI18n(): Promise<void> {
firstRun = true;
language = detectBrowserLanguage(available) ?? "en";
}
} catch {
} catch (e) {
console.warn("read preferences for language failed, defaulting to en", e);
}
if (firstRun) {
Preferences.SetLanguage(language as LanguageCode).catch(() => {});
Preferences.SetLanguage(language as LanguageCode).catch((err: unknown) =>
console.warn("persist detected language failed", err),
);
}
await i18next.use(initReactI18next).init({

View File

@@ -197,7 +197,9 @@ export const MainConnectionStatusSwitch = () => {
console.error("emit browser-login cancel failed", err),
);
}
WindowManager.CloseBrowserLogin().catch(() => {});
WindowManager.CloseBrowserLogin().catch((err: unknown) =>
console.warn("close browser-login window failed", err),
);
setAction("disconnect");
try {
await Connection.Down();
@@ -356,7 +358,9 @@ const IpRow = ({ value }: { value: string }) => {
await navigator.clipboard.writeText(value);
setCopied(true);
setTimeout(() => setCopied(false), 500);
} catch {}
} catch (e) {
console.warn("copy IP to clipboard failed", e);
}
};
return (
<button

View File

@@ -38,18 +38,24 @@ export const MainHeader = () => {
const openSettings = useCallback(() => {
setMenuOpen(false);
WindowManager.OpenSettings("").catch(() => {});
WindowManager.OpenSettings("").catch((err: unknown) =>
console.error("open settings window failed", err),
);
}, []);
useKeyboardShortcut(SETTINGS_SHORTCUT, openSettings);
const openAbout = () => {
setMenuOpen(false);
WindowManager.OpenSettings("about").catch(() => {});
WindowManager.OpenSettings("about").catch((err: unknown) =>
console.error("open settings (about) window failed", err),
);
};
const openManageProfiles = () => {
WindowManager.OpenSettings("profiles").catch(() => {});
WindowManager.OpenSettings("profiles").catch((err: unknown) =>
console.error("open settings (profiles) window failed", err),
);
};
const selectMode = (mode: ViewMode) => {