From fc28ecb19c16de625be0ddb09c1f117ac1755af6 Mon Sep 17 00:00:00 2001 From: Siyuan Miao Date: Fri, 23 May 2025 02:02:00 +0200 Subject: [PATCH] refactor: replace console.log with tslog --- ui/eslint.config.cjs | 1 + ui/package-lock.json | 12 ++ ui/package.json | 1 + ui/src/components/ActionBar.tsx | 4 +- ui/src/components/FeatureFlag.tsx | 5 +- ui/src/components/InfoBar.tsx | 5 +- ui/src/components/USBStateStatus.tsx | 3 +- ui/src/components/UsbDeviceSetting.tsx | 5 +- ui/src/components/UsbInfoSetting.tsx | 8 +- ui/src/components/WebRTCVideo.tsx | 5 +- .../components/extensions/ATXPowerControl.tsx | 5 +- .../components/extensions/SerialConsole.tsx | 2 +- ui/src/components/popovers/PasteModal.tsx | 4 +- .../components/popovers/WakeOnLan/Index.tsx | 9 +- ui/src/hooks/stores.ts | 21 ++-- ui/src/hooks/useAppNavigation.ts | 4 +- ui/src/hooks/useJsonRpc.ts | 4 +- ui/src/routes/devices.$id.deregister.tsx | 5 +- ui/src/routes/devices.$id.mount.tsx | 45 ++++---- ui/src/routes/devices.$id.rename.tsx | 5 +- .../devices.$id.settings.access._index.tsx | 7 +- ...devices.$id.settings.access.local-auth.tsx | 7 +- .../devices.$id.settings.general.update.tsx | 5 +- .../routes/devices.$id.settings.network.tsx | 6 +- ui/src/routes/devices.$id.settings.tsx | 4 +- ui/src/routes/devices.$id.tsx | 106 ++++++++++-------- ui/src/routes/devices.tsx | 4 +- ui/src/routes/login-local.tsx | 4 +- ui/src/routes/welcome-local.mode.tsx | 4 +- ui/src/routes/welcome-local.password.tsx | 4 +- 30 files changed, 173 insertions(+), 131 deletions(-) diff --git a/ui/eslint.config.cjs b/ui/eslint.config.cjs index a6c0c1f..662a9cb 100644 --- a/ui/eslint.config.cjs +++ b/ui/eslint.config.cjs @@ -62,6 +62,7 @@ module.exports = defineConfig([{ allowConstantExport: true, }], + "no-console": ["warn", {}], "import/order": ["error", { groups: ["builtin", "external", "internal", "parent", "sibling"], "newlines-between": "always", diff --git a/ui/package-lock.json b/ui/package-lock.json index 8ac57a1..5ffc4b2 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -36,6 +36,7 @@ "react-xtermjs": "^1.0.10", "recharts": "^2.15.3", "tailwind-merge": "^3.3.0", + "tslog": "^4.9.3", "usehooks-ts": "^3.1.1", "validator": "^13.15.0", "zustand": "^4.5.2" @@ -6533,6 +6534,17 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tslog": { + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/tslog/-/tslog-4.9.3.tgz", + "integrity": "sha512-oDWuGVONxhVEBtschLf2cs/Jy8i7h1T+CpdkTNWQgdAF7DhRo2G8vMCgILKe7ojdEkLhICWgI1LYSSKaJsRgcw==", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/fullstack-build/tslog?sponsor=1" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/ui/package.json b/ui/package.json index eb9a9a3..ac7aa19 100644 --- a/ui/package.json +++ b/ui/package.json @@ -47,6 +47,7 @@ "react-xtermjs": "^1.0.10", "recharts": "^2.15.3", "tailwind-merge": "^3.3.0", + "tslog": "^4.9.3", "usehooks-ts": "^3.1.1", "validator": "^13.15.0", "zustand": "^4.5.2" diff --git a/ui/src/components/ActionBar.tsx b/ui/src/components/ActionBar.tsx index 83ae509..e6c3e1a 100644 --- a/ui/src/components/ActionBar.tsx +++ b/ui/src/components/ActionBar.tsx @@ -19,7 +19,7 @@ import WakeOnLanModal from "@/components/popovers/WakeOnLan/Index"; import MountPopopover from "@/components/popovers/MountPopover"; import ExtensionPopover from "@/components/popovers/ExtensionPopover"; import { useDeviceUiNavigation } from "@/hooks/useAppNavigation"; - +import { logger } from "@/log"; export default function Actionbar({ requestFullscreen, }: { @@ -48,7 +48,7 @@ export default function Actionbar({ if (!open) { setTimeout(() => { setDisableFocusTrap(false); - console.log("Popover is closing. Returning focus trap to video"); + logger.info("Popover is closing. Returning focus trap to video"); }, 0); } } diff --git a/ui/src/components/FeatureFlag.tsx b/ui/src/components/FeatureFlag.tsx index cc0c7c5..a02d1c9 100644 --- a/ui/src/components/FeatureFlag.tsx +++ b/ui/src/components/FeatureFlag.tsx @@ -1,7 +1,8 @@ import { useEffect } from "react"; -import { useFeatureFlag } from "../hooks/useFeatureFlag"; +import { logger } from "@/log"; +import { useFeatureFlag } from "../hooks/useFeatureFlag"; export function FeatureFlag({ minAppVersion, name = "unnamed", @@ -17,7 +18,7 @@ export function FeatureFlag({ useEffect(() => { if (!appVersion) return; - console.log( + logger.info( `Feature '${name}' ${isEnabled ? "ENABLED" : "DISABLED"}: ` + `Current version: ${appVersion}, ` + `Required min version: ${minAppVersion || "N/A"}`, diff --git a/ui/src/components/InfoBar.tsx b/ui/src/components/InfoBar.tsx index b865985..b1ef75d 100644 --- a/ui/src/components/InfoBar.tsx +++ b/ui/src/components/InfoBar.tsx @@ -9,6 +9,7 @@ import { useVideoStore, } from "@/hooks/stores"; import { keys, modifiers } from "@/keyboardMappings"; +import { logger } from "@/log"; export default function InfoBar() { const activeKeys = useHidStore(state => state.activeKeys); @@ -31,9 +32,9 @@ export default function InfoBar() { useEffect(() => { if (!rpcDataChannel) return; - rpcDataChannel.onclose = () => console.log("rpcDataChannel has closed"); + rpcDataChannel.onclose = () => logger.info("rpcDataChannel has closed"); rpcDataChannel.onerror = e => - console.log(`Error on DataChannel '${rpcDataChannel.label}': ${e}`); + logger.error(`Error on DataChannel '${rpcDataChannel.label}': ${e}`); }, [rpcDataChannel]); const keyboardLedState = useHidStore(state => state.keyboardLedState); diff --git a/ui/src/components/USBStateStatus.tsx b/ui/src/components/USBStateStatus.tsx index f0b2cb2..af1c1c3 100644 --- a/ui/src/components/USBStateStatus.tsx +++ b/ui/src/components/USBStateStatus.tsx @@ -5,6 +5,7 @@ import KeyboardAndMouseConnectedIcon from "@/assets/keyboard-and-mouse-connected import LoadingSpinner from "@components/LoadingSpinner"; import StatusCard from "@components/StatusCards"; import { HidState } from "@/hooks/stores"; +import { logger } from "@/log"; type USBStates = HidState["usbState"]; @@ -67,7 +68,7 @@ export default function USBStateStatus({ }; const props = StatusCardProps[state]; if (!props) { - console.log("Unsupported USB state: ", state); + logger.error("Unsupported USB state: ", { state }); return; } diff --git a/ui/src/components/UsbDeviceSetting.tsx b/ui/src/components/UsbDeviceSetting.tsx index 432ec3d..41d491a 100644 --- a/ui/src/components/UsbDeviceSetting.tsx +++ b/ui/src/components/UsbDeviceSetting.tsx @@ -1,5 +1,7 @@ import { useCallback , useEffect, useState } from "react"; +import { logger } from "@/log"; + import { useJsonRpc } from "../hooks/useJsonRpc"; import notifications from "../notifications"; import { SettingsItem } from "../routes/devices.$id.settings"; @@ -9,6 +11,7 @@ import { Button } from "./Button"; import { SelectMenuBasic } from "./SelectMenuBasic"; import { SettingsSectionHeader } from "./SettingsSectionHeader"; import Fieldset from "./Fieldset"; + export interface USBConfig { vendor_id: string; product_id: string; @@ -69,7 +72,7 @@ export function UsbDeviceSetting() { const syncUsbDeviceConfig = useCallback(() => { send("getUsbDevices", {}, resp => { if ("error" in resp) { - console.error("Failed to load USB devices:", resp.error); + logger.error("Failed to load USB devices:", resp.error); notifications.error( `Failed to load USB devices: ${resp.error.data || "Unknown error"}`, ); diff --git a/ui/src/components/UsbInfoSetting.tsx b/ui/src/components/UsbInfoSetting.tsx index 198335c..ed86095 100644 --- a/ui/src/components/UsbInfoSetting.tsx +++ b/ui/src/components/UsbInfoSetting.tsx @@ -1,7 +1,7 @@ import { useMemo , useCallback , useEffect, useState } from "react"; import { Button } from "@components/Button"; - +import { jsonRpcLogger, logger } from "@/log"; import { UsbConfigState } from "../hooks/stores"; import { useJsonRpc } from "../hooks/useJsonRpc"; @@ -96,12 +96,12 @@ export function UsbInfoSetting() { const syncUsbConfigProduct = useCallback(() => { send("getUsbConfig", {}, resp => { if ("error" in resp) { - console.error("Failed to load USB Config:", resp.error); + jsonRpcLogger.error("Failed to load USB Config:", resp.error); notifications.error( `Failed to load USB Config: ${resp.error.data || "Unknown error"}`, ); } else { - console.log("syncUsbConfigProduct#getUsbConfig result:", resp.result); + jsonRpcLogger.info("syncUsbConfigProduct#getUsbConfig result:", resp.result); const usbConfigState = resp.result as UsbConfigState; const product = usbConfigs.map(u => u.value).includes(usbConfigState.product) ? usbConfigState.product @@ -210,7 +210,7 @@ function USBConfigDialog({ const syncUsbConfig = useCallback(() => { send("getUsbConfig", {}, resp => { if ("error" in resp) { - console.error("Failed to load USB Config:", resp.error); + logger.error("Failed to load USB Config:", resp.error); } else { setUsbConfigState(resp.result as UsbConfigState); } diff --git a/ui/src/components/WebRTCVideo.tsx b/ui/src/components/WebRTCVideo.tsx index ca4db08..8b5c97c 100644 --- a/ui/src/components/WebRTCVideo.tsx +++ b/ui/src/components/WebRTCVideo.tsx @@ -18,6 +18,7 @@ import InfoBar from "@components/InfoBar"; import useKeyboard from "@/hooks/useKeyboard"; import { useJsonRpc } from "@/hooks/useJsonRpc"; import notifications from "@/notifications"; +import { logger } from "@/log"; import { HDMIErrorOverlay, @@ -445,7 +446,7 @@ export default function WebRTCVideo() { // Fix only works in chrome based browsers. if (e.code === "Space") { if (videoElm.current?.paused == true) { - console.log("Force playing video"); + logger.info("Force playing video"); videoElm.current?.play(); } } @@ -487,7 +488,7 @@ export default function WebRTCVideo() { useEffect( function updateVideoStream() { if (!mediaStream) return; - console.log("Updating video stream from mediaStream"); + logger.info("Updating video stream from mediaStream"); // We set the as early as possible addStreamToVideoElm(mediaStream); }, diff --git a/ui/src/components/extensions/ATXPowerControl.tsx b/ui/src/components/extensions/ATXPowerControl.tsx index 0334a18..822722b 100644 --- a/ui/src/components/extensions/ATXPowerControl.tsx +++ b/ui/src/components/extensions/ATXPowerControl.tsx @@ -6,6 +6,7 @@ import Card from "@components/Card"; import { SettingsPageHeader } from "@components/SettingsPageheader"; import notifications from "@/notifications"; import LoadingSpinner from "@/components/LoadingSpinner"; +import { logger } from "@/log"; import { useJsonRpc } from "../../hooks/useJsonRpc"; @@ -53,7 +54,7 @@ export function ATXPowerControl() { // Start long press timer const timer = setTimeout(() => { // Send long press action - console.log("Sending long press ATX power action"); + logger.info("Sending long press ATX power action"); send("setATXPowerAction", { action: "power-long" }, resp => { if ("error" in resp) { notifications.error( @@ -74,7 +75,7 @@ export function ATXPowerControl() { setPowerPressTimer(null); // Send short press action - console.log("Sending short press ATX power action"); + logger.info("Sending short press ATX power action"); send("setATXPowerAction", { action: "power-short" }, resp => { if ("error" in resp) { notifications.error( diff --git a/ui/src/components/extensions/SerialConsole.tsx b/ui/src/components/extensions/SerialConsole.tsx index 544d3fd..56b14d7 100644 --- a/ui/src/components/extensions/SerialConsole.tsx +++ b/ui/src/components/extensions/SerialConsole.tsx @@ -69,7 +69,7 @@ export function SerialConsole() { text="Open Console" onClick={() => { setTerminalType("serial"); - console.log("Opening serial console with settings: ", settings); + logger.info("Opening serial console with settings: ", settings); }} /> diff --git a/ui/src/components/popovers/PasteModal.tsx b/ui/src/components/popovers/PasteModal.tsx index 26e4b82..ee42983 100644 --- a/ui/src/components/popovers/PasteModal.tsx +++ b/ui/src/components/popovers/PasteModal.tsx @@ -12,7 +12,7 @@ import { useHidStore, useRTCStore, useUiStore, useSettingsStore } from "@/hooks/ import { keys, modifiers } from "@/keyboardMappings"; import { layouts, chars } from "@/keyboardLayouts"; import notifications from "@/notifications"; - +import { logger } from "@/log"; const hidKeyboardPayload = (keys: number[], modifier: number) => { return { keys, modifier }; }; @@ -95,7 +95,7 @@ export default function PasteModal() { } } } catch (error) { - console.error(error); + logger.error("Failed to paste text", error); notifications.error("Failed to paste text"); } }, [rpcDataChannel?.readyState, send, setDisableVideoFocusTrap, setPasteMode, keyboardLayout]); diff --git a/ui/src/components/popovers/WakeOnLan/Index.tsx b/ui/src/components/popovers/WakeOnLan/Index.tsx index f4f4951..c9204ad 100644 --- a/ui/src/components/popovers/WakeOnLan/Index.tsx +++ b/ui/src/components/popovers/WakeOnLan/Index.tsx @@ -6,6 +6,7 @@ import { SettingsPageHeader } from "@components/SettingsPageheader"; import { useJsonRpc } from "@/hooks/useJsonRpc"; import { useRTCStore, useUiStore } from "@/hooks/stores"; import notifications from "@/notifications"; +import { logger } from "@/log"; import EmptyStateCard from "./EmptyStateCard"; import DeviceList, { StoredDevice } from "./DeviceList"; @@ -56,7 +57,7 @@ export default function WakeOnLanModal() { if ("result" in resp) { setStoredDevices(resp.result as StoredDevice[]); } else { - console.error("Failed to load Wake-on-LAN devices:", resp.error); + logger.error("Failed to load Wake-on-LAN devices:", resp.error); } }); }, [send, setStoredDevices]); @@ -72,7 +73,7 @@ export default function WakeOnLanModal() { send("setWakeOnLanDevices", { params: { devices: updatedDevices } }, resp => { if ("error" in resp) { - console.error("Failed to update Wake-on-LAN devices:", resp.error); + logger.error("Failed to update Wake-on-LAN devices:", resp.error); } else { syncStoredDevices(); } @@ -85,10 +86,10 @@ export default function WakeOnLanModal() { (name: string, macAddress: string) => { if (!name || !macAddress) return; const updatedDevices = [...storedDevices, { name, macAddress }]; - console.log("updatedDevices", updatedDevices); + logger.info("updatedDevices", updatedDevices); send("setWakeOnLanDevices", { params: { devices: updatedDevices } }, resp => { if ("error" in resp) { - console.error("Failed to add Wake-on-LAN device:", resp.error); + logger.error("Failed to add Wake-on-LAN device:", { error: resp.error }); setAddDeviceErrorMessage("Failed to add device"); } else { setShowAddForm(false); diff --git a/ui/src/hooks/stores.ts b/ui/src/hooks/stores.ts index 52ef89d..a947867 100644 --- a/ui/src/hooks/stores.ts +++ b/ui/src/hooks/stores.ts @@ -6,6 +6,7 @@ import { MAX_TOTAL_MACROS, MAX_KEYS_PER_STEP, } from "@/constants/macros"; +import { logger } from "@/log"; // Define the JsonRpc types for better type checking interface JsonRpcResponse { @@ -744,7 +745,7 @@ export const useNetworkStateStore = create((set, get) => ({ setDhcpLeaseExpiry: (expiry: Date) => { const lease = get().dhcp_lease; if (!lease) { - console.warn("No lease found"); + logger.warn("No lease found"); return; } @@ -807,7 +808,7 @@ export const useMacrosStore = create((set, get) => ({ const { sendFn } = get(); if (!sendFn) { - console.warn("JSON-RPC send function not available."); + logger.warn("JSON-RPC send function not available."); return; } @@ -817,7 +818,7 @@ export const useMacrosStore = create((set, get) => ({ await new Promise((resolve, reject) => { sendFn("getKeyboardMacros", {}, response => { if (response.error) { - console.error("Error loading macros:", response.error); + logger.error("Error loading macros:", response.error); reject(new Error(response.error.message)); return; } @@ -842,7 +843,7 @@ export const useMacrosStore = create((set, get) => ({ }); }); } catch (error) { - console.error("Failed to load macros:", error); + logger.error("Failed to load macros:", error); } finally { set({ loading: false }); } @@ -851,18 +852,18 @@ export const useMacrosStore = create((set, get) => ({ saveMacros: async (macros: KeySequence[]) => { const { sendFn } = get(); if (!sendFn) { - console.warn("JSON-RPC send function not available."); + logger.warn("JSON-RPC send function not available."); throw new Error("JSON-RPC send function not available"); } if (macros.length > MAX_TOTAL_MACROS) { - console.error(`Cannot save: exceeded maximum of ${MAX_TOTAL_MACROS} macros`); + logger.error(`Cannot save: exceeded maximum of ${MAX_TOTAL_MACROS} macros`); throw new Error(`Cannot save: exceeded maximum of ${MAX_TOTAL_MACROS} macros`); } for (const macro of macros) { if (macro.steps.length > MAX_STEPS_PER_MACRO) { - console.error( + logger.error( `Cannot save: macro "${macro.name}" exceeds maximum of ${MAX_STEPS_PER_MACRO} steps`, ); throw new Error( @@ -873,7 +874,7 @@ export const useMacrosStore = create((set, get) => ({ for (let i = 0; i < macro.steps.length; i++) { const step = macro.steps[i]; if (step.keys && step.keys.length > MAX_KEYS_PER_STEP) { - console.error( + logger.error( `Cannot save: macro "${macro.name}" step ${i + 1} exceeds maximum of ${MAX_KEYS_PER_STEP} keys`, ); throw new Error( @@ -902,7 +903,7 @@ export const useMacrosStore = create((set, get) => ({ }); if (response.error) { - console.error("Error saving macros:", response.error); + logger.error("Error saving macros:", response.error); const errorMessage = typeof response.error.data === "string" ? response.error.data @@ -913,7 +914,7 @@ export const useMacrosStore = create((set, get) => ({ // Only update the store if the request was successful set({ macros: macrosWithSortOrder }); } catch (error) { - console.error("Failed to save macros:", error); + logger.error("Failed to save macros:", error); throw error; } finally { set({ loading: false }); diff --git a/ui/src/hooks/useAppNavigation.ts b/ui/src/hooks/useAppNavigation.ts index 6c9270a..32ec5a3 100644 --- a/ui/src/hooks/useAppNavigation.ts +++ b/ui/src/hooks/useAppNavigation.ts @@ -1,6 +1,8 @@ import { useNavigate, useParams, NavigateOptions } from "react-router-dom"; import { useCallback, useMemo } from "react"; +import { logger } from "@/log"; + import { isOnDevice } from "../main"; /** @@ -21,7 +23,7 @@ export function getDeviceUiPath(path: string, deviceId?: string): string { return normalizedPath; } else { if (!deviceId) { - console.error("No device ID provided when generating path in cloud mode"); + logger.error("No device ID provided when generating path in cloud mode"); throw new Error("Device ID is required for cloud mode path generation"); } return `/devices/${deviceId}${normalizedPath}`; diff --git a/ui/src/hooks/useJsonRpc.ts b/ui/src/hooks/useJsonRpc.ts index 92b56ff..600f580 100644 --- a/ui/src/hooks/useJsonRpc.ts +++ b/ui/src/hooks/useJsonRpc.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect } from "react"; import { useRTCStore } from "@/hooks/stores"; - +import { jsonRpcLogger } from "@/log"; export interface JsonRpcRequest { jsonrpc: string; method: string; @@ -61,7 +61,7 @@ export function useJsonRpc(onRequest?: (payload: JsonRpcRequest) => void) { return; } - if ("error" in payload) console.error(payload.error); + if ("error" in payload) jsonRpcLogger.error(payload.error); if (!payload.id) return; const callback = callbackStore.get(payload.id); diff --git a/ui/src/routes/devices.$id.deregister.tsx b/ui/src/routes/devices.$id.deregister.tsx index 8c0a87f..d62090d 100644 --- a/ui/src/routes/devices.$id.deregister.tsx +++ b/ui/src/routes/devices.$id.deregister.tsx @@ -16,6 +16,7 @@ import { User } from "@/hooks/stores"; import { checkAuth } from "@/main"; import Fieldset from "@components/Fieldset"; import { CLOUD_API } from "@/ui.config"; +import { logger } from "@/log"; interface LoaderData { device: { id: string; name: string; user: { googleId: string } }; @@ -37,7 +38,7 @@ const action = async ({ request }: ActionFunctionArgs) => { return { message: "There was an error renaming your device. Please try again." }; } } catch (e) { - console.error(e); + logger.error("Error deregistering device", e); return { message: "There was an error renaming your device. Please try again." }; } @@ -61,7 +62,7 @@ const loader = async ({ params }: LoaderFunctionArgs) => { return { device, user }; } catch (e) { - console.error(e); + logger.error("Error deregistering device", e); return { devices: [] }; } }; diff --git a/ui/src/routes/devices.$id.mount.tsx b/ui/src/routes/devices.$id.mount.tsx index 7ac519c..ca69842 100644 --- a/ui/src/routes/devices.$id.mount.tsx +++ b/ui/src/routes/devices.$id.mount.tsx @@ -26,6 +26,7 @@ import ArchIcon from "@/assets/arch-icon.png"; import NetBootIcon from "@/assets/netboot-icon.svg"; import Fieldset from "@/components/Fieldset"; import { DEVICE_API } from "@/ui.config"; +import { logger } from "@/log"; import { useJsonRpc } from "../hooks/useJsonRpc"; import notifications from "../notifications"; @@ -86,7 +87,7 @@ export function Dialog({ onClose }: { onClose: () => void }) { } function handleUrlMount(url: string, mode: RemoteVirtualMediaState["mode"]) { - console.log(`Mounting ${url} as ${mode}`); + logger.info(`Mounting ${url} as ${mode}`); setMountInProgress(true); send("mountWithHTTP", { url, mode }, async resp => { @@ -105,7 +106,7 @@ export function Dialog({ onClose }: { onClose: () => void }) { } function handleStorageMount(fileName: string, mode: RemoteVirtualMediaState["mode"]) { - console.log(`Mounting ${fileName} as ${mode}`); + logger.info(`Mounting ${fileName} as ${mode}`); setMountInProgress(true); send("mountWithStorage", { filename: fileName, mode }, async resp => { @@ -132,7 +133,7 @@ export function Dialog({ onClose }: { onClose: () => void }) { } function handleBrowserMount(file: File, mode: RemoteVirtualMediaState["mode"]) { - console.log(`Mounting ${file.name} as ${mode}`); + logger.info(`Mounting ${file.name} as ${mode}`); setMountInProgress(true); send( @@ -419,7 +420,7 @@ function BrowserFileView({ const handleMount = () => { if (selectedFile) { - console.log(`Mounting ${selectedFile.name} as ${setUsbMode}`); + logger.info(`Mounting ${selectedFile.name} as ${setUsbMode}`); onMountFile(selectedFile, usbMode); } }; @@ -756,7 +757,7 @@ function DeviceFileView({ }, [syncStorage]); function handleDeleteFile(file: { name: string; size: string; createdAt: string }) { - console.log("Deleting file:", file); + logger.info("Deleting file:", file); send("deleteStorageFile", { filename: file.name }, res => { if ("error" in res) { notifications.error(`Error deleting file: ${res.error}`); @@ -986,6 +987,8 @@ function UploadFileView({ onCancelUpload: () => void; incompleteFileName?: string; }) { + const l = logger.getSubLogger({ name: "file-upload" }); + const [uploadState, setUploadState] = useState<"idle" | "uploading" | "success">( "idle", ); @@ -1002,7 +1005,7 @@ function UploadFileView({ useEffect(() => { const ref = rtcDataChannelRef.current; return () => { - console.log("unmounting"); + logger.info("unmounting"); if (ref) { ref.onopen = null; ref.onerror = null; @@ -1023,10 +1026,10 @@ function UploadFileView({ .peerConnection?.createDataChannel(dataChannel); if (!rtcDataChannel) { - console.error("Failed to create data channel for file upload"); + l.error("Failed to create data channel for file upload"); notifications.error("Failed to create data channel for file upload"); setUploadState("idle"); - console.log("Upload state set to 'idle'"); + l.info("Upload state set to 'idle'"); return; } @@ -1072,7 +1075,7 @@ function UploadFileView({ lastUploadedBytes = AlreadyUploadedBytes; lastUpdateTime = now; } catch (e) { - console.error("Error processing RTC Data channel message:", e); + l.error("Error processing RTC Data channel message:", e); } }; @@ -1099,24 +1102,24 @@ function UploadFileView({ } offset += buffer.byteLength; - console.log(`Chunk sent: ${offset} / ${file.size} bytes`); + l.info(`Chunk sent: ${offset} / ${file.size} bytes`); sendNextChunk(); }); }; sendNextChunk(); rtcDataChannel.onbufferedamountlow = () => { - console.log("RTC Data channel buffered amount low"); + l.info("RTC Data channel buffered amount low"); pauseSending = false; // Now the data channel is ready to send more data sendNextChunk(); }; }; rtcDataChannel.onerror = error => { - console.error("RTC Data channel error:", error); + l.error("RTC Data channel error:", error); notifications.error(`Upload failed: ${error}`); setUploadState("idle"); - console.log("Upload state set to 'idle'"); + l.info("Upload state set to 'idle'"); }; } @@ -1169,14 +1172,14 @@ function UploadFileView({ if (xhr.status === 200) { setUploadState("success"); } else { - console.error("Upload error:", xhr.statusText); + l.error("Upload error:", xhr.statusText); setUploadError(xhr.statusText); setUploadState("idle"); } }; xhr.onerror = () => { - console.error("XHR error:", xhr.statusText); + l.error("XHR error:", xhr.statusText); setUploadError(xhr.statusText); setUploadState("idle"); }; @@ -1205,19 +1208,19 @@ function UploadFileView({ } setFileError(null); - console.log(`File selected: ${file.name}, size: ${file.size} bytes`); + l.info(`File selected: ${file.name}, size: ${file.size} bytes`); setUploadedFileName(file.name); setUploadedFileSize(file.size); setUploadState("uploading"); - console.log("Upload state set to 'uploading'"); + l.info("Upload state set to 'uploading'"); send("startStorageFileUpload", { filename: file.name, size: file.size }, resp => { - console.log("startStorageFileUpload response:", resp); + l.info("startStorageFileUpload response:", resp); if ("error" in resp) { - console.error("Upload error:", resp.error.message); + l.error("Upload error:", resp.error.message); setUploadError(resp.error.data || resp.error.message); setUploadState("idle"); - console.log("Upload state set to 'idle'"); + l.info("Upload state set to 'idle'"); return; } @@ -1226,7 +1229,7 @@ function UploadFileView({ dataChannel: string; }; - console.log( + l.info( `Already uploaded bytes: ${alreadyUploadedBytes}, Data channel: ${dataChannel}`, ); diff --git a/ui/src/routes/devices.$id.rename.tsx b/ui/src/routes/devices.$id.rename.tsx index 2852561..76cd174 100644 --- a/ui/src/routes/devices.$id.rename.tsx +++ b/ui/src/routes/devices.$id.rename.tsx @@ -17,6 +17,7 @@ import { User } from "@/hooks/stores"; import { checkAuth } from "@/main"; import Fieldset from "@components/Fieldset"; import { CLOUD_API } from "@/ui.config"; +import { logger } from "@/log"; import api from "../api"; @@ -41,7 +42,7 @@ const action = async ({ params, request }: ActionFunctionArgs) => { return { message: "There was an error renaming your device. Please try again." }; } } catch (e) { - console.error(e); + logger.error("Error renaming device", e); return { message: "There was an error renaming your device. Please try again." }; } @@ -65,7 +66,7 @@ const loader = async ({ params }: LoaderFunctionArgs) => { return { device, user }; } catch (e) { - console.error(e); + logger.error("Error renaming device", e); return { devices: [] }; } }; diff --git a/ui/src/routes/devices.$id.settings.access._index.tsx b/ui/src/routes/devices.$id.settings.access._index.tsx index e0543b8..f035b26 100644 --- a/ui/src/routes/devices.$id.settings.access._index.tsx +++ b/ui/src/routes/devices.$id.settings.access._index.tsx @@ -15,6 +15,7 @@ import { DEVICE_API } from "@/ui.config"; import { useJsonRpc } from "@/hooks/useJsonRpc"; import { isOnDevice } from "@/main"; import { TextAreaWithLabel } from "@components/TextArea"; +import { logger } from "@/log"; import { LocalDevice } from "./devices.$id"; import { SettingsItem } from "./devices.$id.settings"; @@ -57,7 +58,7 @@ export default function SettingsAccessIndexRoute() { const getCloudState = useCallback(() => { send("getCloudState", {}, resp => { - if ("error" in resp) return console.error(resp.error); + if ("error" in resp) return logger.error("Error getting cloud state", resp.error); const cloudState = resp.result as CloudState; setAdopted(cloudState.connected); setCloudApiUrl(cloudState.url); @@ -78,7 +79,7 @@ export default function SettingsAccessIndexRoute() { const getTLSState = useCallback(() => { send("getTLSState", {}, resp => { - if ("error" in resp) return console.error(resp.error); + if ("error" in resp) return logger.error("Error getting TLS state", resp.error); const tlsState = resp.result as TLSState; setTlsMode(tlsState.mode); @@ -199,7 +200,7 @@ export default function SettingsAccessIndexRoute() { getTLSState(); send("getDeviceID", {}, async resp => { - if ("error" in resp) return console.error(resp.error); + if ("error" in resp) return logger.error("Error getting device ID", resp.error); setDeviceId(resp.result as string); }); }, [send, getCloudState, getTLSState]); diff --git a/ui/src/routes/devices.$id.settings.access.local-auth.tsx b/ui/src/routes/devices.$id.settings.access.local-auth.tsx index 50b2cc4..09a4f7f 100644 --- a/ui/src/routes/devices.$id.settings.access.local-auth.tsx +++ b/ui/src/routes/devices.$id.settings.access.local-auth.tsx @@ -6,6 +6,7 @@ import { InputFieldWithLabel } from "@/components/InputField"; import api from "@/api"; import { useLocalAuthModalStore } from "@/hooks/stores"; import { useDeviceUiNavigation } from "@/hooks/useAppNavigation"; +import { logger } from "@/log"; export default function SecurityAccessLocalAuthRoute() { const { setModalView } = useLocalAuthModalStore(); @@ -54,7 +55,7 @@ export function Dialog({ onClose }: { onClose: () => void }) { setError(data.error || "An error occurred while setting the password"); } } catch (error) { - console.error(error); + logger.error("An error occurred while setting the password", error); setError("An error occurred while setting the password"); } }; @@ -94,7 +95,7 @@ export function Dialog({ onClose }: { onClose: () => void }) { setError(data.error || "An error occurred while changing the password"); } } catch (error) { - console.error(error); + logger.error("An error occurred while changing the password", error); setError("An error occurred while changing the password"); } }; @@ -116,7 +117,7 @@ export function Dialog({ onClose }: { onClose: () => void }) { setError(data.error || "An error occurred while disabling the password"); } } catch (error) { - console.error(error); + logger.error("An error occurred while disabling the password", error); setError("An error occurred while disabling the password"); } }; diff --git a/ui/src/routes/devices.$id.settings.general.update.tsx b/ui/src/routes/devices.$id.settings.general.update.tsx index 7c41449..2bc0059 100644 --- a/ui/src/routes/devices.$id.settings.general.update.tsx +++ b/ui/src/routes/devices.$id.settings.general.update.tsx @@ -9,6 +9,7 @@ import { UpdateState, useDeviceStore, useUpdateStore } from "@/hooks/stores"; import notifications from "@/notifications"; import LoadingSpinner from "@/components/LoadingSpinner"; import { useDeviceUiNavigation } from "@/hooks/useAppNavigation"; +import { logger } from "@/log"; export default function SettingsGeneralUpdateRoute() { const navigate = useNavigate(); @@ -184,7 +185,7 @@ function LoadingState({ }) .catch(error => { if (!signal.aborted) { - console.error("LoadingState: Error fetching version info", error); + logger.error("LoadingState: Error fetching version info", error); } }); @@ -240,7 +241,7 @@ function UpdatingDeviceState({ return 0; } - console.log( + logger.info( `For ${type}:\n` + ` Download Progress: ${downloadProgress}% (${otaState[`${type}DownloadProgress`]})\n` + ` Update Progress: ${updateProgress}% (${otaState[`${type}UpdateProgress`]})\n` + diff --git a/ui/src/routes/devices.$id.settings.network.tsx b/ui/src/routes/devices.$id.settings.network.tsx index 0905db5..c63c2fe 100644 --- a/ui/src/routes/devices.$id.settings.network.tsx +++ b/ui/src/routes/devices.$id.settings.network.tsx @@ -22,6 +22,7 @@ import { SettingsPageHeader } from "@/components/SettingsPageheader"; import Fieldset from "@/components/Fieldset"; import { ConfirmDialog } from "@/components/ConfirmDialog"; import notifications from "@/notifications"; +import { logger } from "@/log"; import Ipv6NetworkCard from "../components/Ipv6NetworkCard"; import EmptyCard from "../components/EmptyCard"; @@ -29,7 +30,6 @@ import AutoHeight from "../components/AutoHeight"; import DhcpLeaseCard from "../components/DhcpLeaseCard"; import { SettingsItem } from "./devices.$id.settings"; - dayjs.extend(relativeTime); const defaultNetworkSettings: NetworkSettings = { @@ -105,7 +105,7 @@ export default function SettingsNetworkRoute() { setNetworkSettingsLoaded(false); send("getNetworkSettings", {}, resp => { if ("error" in resp) return; - console.log(resp.result); + logger.trace("getNetworkSettings result:", resp.result); setNetworkSettings(resp.result as NetworkSettings); if (!firstNetworkSettings.current) { @@ -118,7 +118,7 @@ export default function SettingsNetworkRoute() { const getNetworkState = useCallback(() => { send("getNetworkState", {}, resp => { if ("error" in resp) return; - console.log(resp.result); + logger.trace("getNetworkState result:", resp.result); setNetworkState(resp.result as NetworkState); }); }, [send, setNetworkState]); diff --git a/ui/src/routes/devices.$id.settings.tsx b/ui/src/routes/devices.$id.settings.tsx index 5b277a1..0e64311 100644 --- a/ui/src/routes/devices.$id.settings.tsx +++ b/ui/src/routes/devices.$id.settings.tsx @@ -20,11 +20,11 @@ import { LinkButton } from "@/components/Button"; import LoadingSpinner from "@/components/LoadingSpinner"; import { useUiStore } from "@/hooks/stores"; import useKeyboard from "@/hooks/useKeyboard"; +import { logger } from "@/log"; import { FeatureFlag } from "../components/FeatureFlag"; import { cx } from "../cva.config"; - /* TODO: Migrate to using URLs instead of the global state. To simplify the refactoring, we'll keep the global state for now. */ export default function SettingsRoute() { const location = useLocation(); @@ -73,7 +73,7 @@ export default function SettingsRoute() { // For some reason, the focus trap is not disabled immediately // so we need to blur the active element (document.activeElement as HTMLElement)?.blur(); - console.log("Just disabled focus trap"); + logger.info("Just disabled focus trap"); }, 300); return () => { diff --git a/ui/src/routes/devices.$id.tsx b/ui/src/routes/devices.$id.tsx index c9aac36..23b90ed 100644 --- a/ui/src/routes/devices.$id.tsx +++ b/ui/src/routes/devices.$id.tsx @@ -28,6 +28,7 @@ import { useNetworkStateStore, User, useRTCStore, + useSettingsStore, useUiStore, useUpdateStore, useVideoStore, @@ -40,6 +41,7 @@ import ConnectionStatsSidebar from "@/components/sidebar/connectionStats"; import { JsonRpcRequest, useJsonRpc } from "@/hooks/useJsonRpc"; import Terminal from "@components/Terminal"; import { CLOUD_API, DEVICE_API } from "@/ui.config"; +import { logger, enableDebugMode, disableDebugMode } from "@/log"; import UpdateInProgressStatusCard from "../components/UpdateInProgressStatusCard"; import api from "../api"; @@ -130,6 +132,16 @@ export default function KvmIdRoute() { const sidebarView = useUiStore(state => state.sidebarView); const [queryParams, setQueryParams] = useSearchParams(); + // Enable dev mode if the user is in debug mode + const isDebugMode = useSettingsStore(state => state.debugMode); + useEffect(() => { + if (isDebugMode) { + enableDebugMode(); + } else { + disableDebugMode(); + } + }, [isDebugMode]); + const setIsTurnServerInUse = useRTCStore(state => state.setTurnServerInUse); const peerConnection = useRTCStore(state => state.peerConnection); const setPeerConnectionState = useRTCStore(state => state.setPeerConnectionState); @@ -151,7 +163,7 @@ export default function KvmIdRoute() { const [loadingMessage, setLoadingMessage] = useState("Connecting to device..."); const cleanupAndStopReconnecting = useCallback( function cleanupAndStopReconnecting() { - console.log("Closing peer connection"); + logger.info("Closing peer connection"); setConnectionFailed(true); if (peerConnection) { @@ -187,15 +199,14 @@ export default function KvmIdRoute() { ) { setLoadingMessage("Setting remote description"); + const l = logger.getSubLogger({ name: "setRemoteSessionDescription" }); + try { await pc.setRemoteDescription(new RTCSessionDescription(remoteDescription)); - console.log("[setRemoteSessionDescription] Remote description set successfully"); + l.info("Remote description set successfully"); setLoadingMessage("Establishing secure connection..."); } catch (error) { - console.error( - "[setRemoteSessionDescription] Failed to set remote description:", - error, - ); + l.error("Failed to set remote description", { error }); cleanupAndStopReconnecting(); return; } @@ -207,12 +218,12 @@ export default function KvmIdRoute() { // When vivaldi has disabled "Broadcast IP for Best WebRTC Performance", this never connects if (pc.sctp?.state === "connected") { - console.log("[setRemoteSessionDescription] Remote description set"); + l.info("Remote description set"); clearInterval(checkInterval); setLoadingMessage("Connection established"); } else if (attempts >= 10) { - console.log( - "[setRemoteSessionDescription] Failed to establish connection after 10 attempts", + l.error( + "Failed to establish connection after 10 attempts", { connectionState: pc.connectionState, iceConnectionState: pc.iceConnectionState, @@ -221,7 +232,7 @@ export default function KvmIdRoute() { cleanupAndStopReconnecting(); clearInterval(checkInterval); } else { - console.log("[setRemoteSessionDescription] Waiting for connection, state:", { + l.info("[setRemoteSessionDescription] Waiting for connection, state:", { connectionState: pc.connectionState, iceConnectionState: pc.iceConnectionState, }); @@ -236,6 +247,7 @@ export default function KvmIdRoute() { const makingOffer = useRef(false); const wsProtocol = window.location.protocol === "https:" ? "wss:" : "ws:"; + const wsLogger = logger.getSubLogger({ name: "websocket" }); const { sendMessage, getWebSocket } = useWebSocket( isOnDevice @@ -247,27 +259,27 @@ export default function KvmIdRoute() { reconnectAttempts: 15, reconnectInterval: 1000, onReconnectStop: () => { - console.log("Reconnect stopped"); + wsLogger.info("Reconnect stopped"); cleanupAndStopReconnecting(); }, shouldReconnect(event) { - console.log("[Websocket] shouldReconnect", event); + wsLogger.info("shouldReconnect", event); // TODO: Why true? return true; }, onClose(event) { - console.log("[Websocket] onClose", event); + wsLogger.info("onClose", event); // We don't want to close everything down, we wait for the reconnect to stop instead }, onError(event) { - console.log("[Websocket] onError", event); + wsLogger.error("onError", event); // We don't want to close everything down, we wait for the reconnect to stop instead }, onOpen() { - console.log("[Websocket] onOpen"); + wsLogger.info("onOpen"); }, onMessage: message => { @@ -289,18 +301,18 @@ export default function KvmIdRoute() { const parsedMessage = JSON.parse(message.data); if (parsedMessage.type === "device-metadata") { const { deviceVersion } = parsedMessage.data; - console.log("[Websocket] Received device-metadata message"); - console.log("[Websocket] Device version", deviceVersion); + wsLogger.info("Received device-metadata message"); + wsLogger.info("Device version", deviceVersion); // If the device version is not set, we can assume the device is using the legacy signaling if (!deviceVersion) { - console.log("[Websocket] Device is using legacy signaling"); + wsLogger.info("Device is using legacy signaling"); // Now we don't need the websocket connection anymore, as we've established that we need to use the legacy signaling // which does everything over HTTP(at least from the perspective of the client) isLegacySignalingEnabled.current = true; getWebSocket()?.close(); } else { - console.log("[Websocket] Device is using new signaling"); + wsLogger.info("Device is using new signaling"); isLegacySignalingEnabled.current = false; } setupPeerConnection(); @@ -308,7 +320,7 @@ export default function KvmIdRoute() { if (!peerConnection) return; if (parsedMessage.type === "answer") { - console.log("[Websocket] Received answer"); + wsLogger.info("Received answer"); const readyForOffer = // If we're making an offer, we don't want to accept an answer !makingOffer && @@ -322,10 +334,7 @@ export default function KvmIdRoute() { // Set so we don't accept an answer while we're setting the remote description isSettingRemoteAnswerPending.current = parsedMessage.type === "answer"; - console.log( - "[Websocket] Setting remote answer pending", - isSettingRemoteAnswerPending.current, - ); + wsLogger.info("Setting remote answer pending", isSettingRemoteAnswerPending.current); const sd = atob(parsedMessage.data); const remoteSessionDescription = JSON.parse(sd); @@ -338,8 +347,8 @@ export default function KvmIdRoute() { // Reset the remote answer pending flag isSettingRemoteAnswerPending.current = false; } else if (parsedMessage.type === "new-ice-candidate") { - console.log("[Websocket] Received new-ice-candidate"); const candidate = parsedMessage.data; + wsLogger.info("Received new-ice-candidate", { candidate}); peerConnection.addIceCandidate(candidate); } }, @@ -366,7 +375,7 @@ export default function KvmIdRoute() { // In device mode, old devices wont server this JS, and on newer devices legacy mode wont be enabled const sessionUrl = `${CLOUD_API}/webrtc/session`; - console.log("Trying to get remote session description"); + logger.info("Trying to get remote session description"); setLoadingMessage( `Getting remote session description... ${signalingAttempts.current > 0 ? `(attempt ${signalingAttempts.current + 1})` : ""}`, ); @@ -379,12 +388,12 @@ export default function KvmIdRoute() { const json = await res.json(); if (res.status === 401) return navigate(isOnDevice ? "/login-local" : "/login"); if (!res.ok) { - console.error("Error getting SDP", { status: res.status, json }); + logger.error("Error getting SDP", { status: res.status, json }); cleanupAndStopReconnecting(); return; } - console.log("Successfully got Remote Session Description. Setting."); + logger.info("Successfully got Remote Session Description. Setting."); setLoadingMessage("Setting remote session description..."); const decodedSd = atob(json.sd); @@ -395,13 +404,15 @@ export default function KvmIdRoute() { ); const setupPeerConnection = useCallback(async () => { - console.log("[setupPeerConnection] Setting up peer connection"); + const l = logger.getSubLogger({ name: "setupPeerConnection" }); + + l.info("Setting up peer connection"); setConnectionFailed(false); setLoadingMessage("Connecting to device..."); let pc: RTCPeerConnection; try { - console.log("[setupPeerConnection] Creating peer connection"); + l.info("Creating peer connection"); setLoadingMessage("Creating peer connection..."); pc = new RTCPeerConnection({ // We only use STUN or TURN servers if we're in the cloud @@ -411,10 +422,10 @@ export default function KvmIdRoute() { }); setPeerConnectionState(pc.connectionState); - console.log("[setupPeerConnection] Peer connection created", pc); + l.info("Peer connection created", pc); setLoadingMessage("Setting up connection to device..."); } catch (e) { - console.error(`[setupPeerConnection] Error creating peer connection: ${e}`); + l.error(`Error creating peer connection: ${e}`); setTimeout(() => { cleanupAndStopReconnecting(); }, 1000); @@ -423,13 +434,13 @@ export default function KvmIdRoute() { // Set up event listeners and data channels pc.onconnectionstatechange = () => { - console.log("[setupPeerConnection] Connection state changed", pc.connectionState); + l.info("Connection state changed", pc.connectionState); setPeerConnectionState(pc.connectionState); }; pc.onnegotiationneeded = async () => { try { - console.log("[setupPeerConnection] Creating offer"); + l.info("Creating offer"); makingOffer.current = true; const offer = await pc.createOffer(); @@ -439,13 +450,10 @@ export default function KvmIdRoute() { if (isNewSignalingEnabled) { sendWebRTCSignal("offer", { sd: sd }); } else { - console.log("Legacy signanling. Waiting for ICE Gathering to complete..."); + l.info("Legacy signanling. Waiting for ICE Gathering to complete..."); } } catch (e) { - console.error( - `[setupPeerConnection] Error creating offer: ${e}`, - new Date().toISOString(), - ); + l.error(`Error creating offer`, { date: new Date().toISOString(), error: e }); cleanupAndStopReconnecting(); } finally { makingOffer.current = false; @@ -461,7 +469,7 @@ export default function KvmIdRoute() { pc.onicegatheringstatechange = event => { const pc = event.currentTarget as RTCPeerConnection; if (pc.iceGatheringState === "complete") { - console.log("ICE Gathering completed"); + l.info("ICE Gathering completed"); setLoadingMessage("ICE Gathering completed"); if (isLegacySignalingEnabled.current) { @@ -469,7 +477,7 @@ export default function KvmIdRoute() { legacyHTTPSignaling(pc); } } else if (pc.iceGatheringState === "gathering") { - console.log("ICE Gathering Started"); + l.info("ICE Gathering Started"); setLoadingMessage("Gathering ICE candidates..."); } }; @@ -506,7 +514,7 @@ export default function KvmIdRoute() { useEffect(() => { if (peerConnectionState === "failed") { - console.log("Connection failed, closing peer connection"); + logger.info("Connection failed, closing peer connection"); cleanupAndStopReconnecting(); } }, [peerConnectionState, cleanupAndStopReconnecting]); @@ -609,13 +617,13 @@ export default function KvmIdRoute() { } if (resp.method === "networkState") { - console.log("Setting network state", resp.params); + logger.info("Setting network state", resp.params); setNetworkState(resp.params as NetworkState); } if (resp.method === "keyboardLedState") { const ledState = resp.params as KeyboardLedState; - console.log("Setting keyboard led state", ledState); + logger.info("Setting keyboard led state", ledState); setKeyboardLedState(ledState); setKeyboardLedStateSyncAvailable(true); } @@ -660,20 +668,20 @@ export default function KvmIdRoute() { useEffect(() => { if (rpcDataChannel?.readyState !== "open") return; if (keyboardLedState !== undefined) return; - console.log("Requesting keyboard led state"); + logger.info("Requesting keyboard led state"); send("getKeyboardLedState", {}, resp => { if ("error" in resp) { // -32601 means the method is not supported if (resp.error.code === -32601) { setKeyboardLedStateSyncAvailable(false); - console.error("Failed to get keyboard led state, disabling sync", resp.error); + logger.error("Failed to get keyboard led state, disabling sync", resp.error); } else { - console.error("Failed to get keyboard led state", resp.error); + logger.error("Failed to get keyboard led state", resp.error); } return; } - console.log("Keyboard led state", resp.result); + logger.info("Keyboard led state", resp.result); setKeyboardLedState(resp.result as KeyboardLedState); setKeyboardLedStateSyncAvailable(true); }); @@ -691,7 +699,7 @@ export default function KvmIdRoute() { useEffect(() => { if (!diskChannel || !file) return; diskChannel.onmessage = async e => { - console.log("Received", e.data); + logger.info("Received", e.data); const data = JSON.parse(e.data); const blob = file.slice(data.start, data.end); const buf = await blob.arrayBuffer(); diff --git a/ui/src/routes/devices.tsx b/ui/src/routes/devices.tsx index b6af0f0..a5d083d 100644 --- a/ui/src/routes/devices.tsx +++ b/ui/src/routes/devices.tsx @@ -10,7 +10,7 @@ import { LinkButton } from "@components/Button"; import { User } from "@/hooks/stores"; import { checkAuth } from "@/main"; import { CLOUD_API } from "@/ui.config"; - +import { logger } from "@/log"; interface LoaderData { devices: { id: string; name: string; online: boolean; lastSeen: string }[]; user: User; @@ -29,7 +29,7 @@ const loader = async () => { const { devices } = await res.json(); return { devices, user }; } catch (e) { - console.error(e); + logger.error("Error loading devices", e); return { devices: [] }; } }; diff --git a/ui/src/routes/login-local.tsx b/ui/src/routes/login-local.tsx index 9258639..a3695d6 100644 --- a/ui/src/routes/login-local.tsx +++ b/ui/src/routes/login-local.tsx @@ -11,12 +11,12 @@ import { Button } from "@components/Button"; import LogoBlueIcon from "@/assets/logo-blue.png"; import LogoWhiteIcon from "@/assets/logo-white.svg"; import { DEVICE_API } from "@/ui.config"; +import { logger } from "@/log"; import api from "../api"; import ExtLink from "../components/ExtLink"; import { DeviceStatus } from "./welcome-local"; - const loader = async () => { const res = await api .GET(`${DEVICE_API}/device/status`) @@ -44,7 +44,7 @@ const action = async ({ request }: ActionFunctionArgs) => { return { error: "Invalid password" }; } } catch (error) { - console.error(error); + logger.error("An error occurred while logging in", error); return { error: "An error occurred while logging in" }; } }; diff --git a/ui/src/routes/welcome-local.mode.tsx b/ui/src/routes/welcome-local.mode.tsx index 06ca62a..d6dfe80 100644 --- a/ui/src/routes/welcome-local.mode.tsx +++ b/ui/src/routes/welcome-local.mode.tsx @@ -7,13 +7,13 @@ import { Button } from "@components/Button"; import LogoBlueIcon from "@/assets/logo-blue.png"; import LogoWhiteIcon from "@/assets/logo-white.svg"; import { DEVICE_API } from "@/ui.config"; + import { logger } from "@/log"; import { GridCard } from "../components/Card"; import { cx } from "../cva.config"; import api from "../api"; import { DeviceStatus } from "./welcome-local"; - const loader = async () => { const res = await api .GET(`${DEVICE_API}/device/status`) @@ -39,7 +39,7 @@ const action = async ({ request }: ActionFunctionArgs) => { }); return redirect("/"); } catch (error) { - console.error("Error setting authentication mode:", error); + logger.error("Error setting authentication mode:", error); return { error: "An error occurred while setting the authentication mode" }; } } diff --git a/ui/src/routes/welcome-local.password.tsx b/ui/src/routes/welcome-local.password.tsx index 4b2c05d..165df6b 100644 --- a/ui/src/routes/welcome-local.password.tsx +++ b/ui/src/routes/welcome-local.password.tsx @@ -10,11 +10,11 @@ import { Button } from "@components/Button"; import LogoBlueIcon from "@/assets/logo-blue.png"; import LogoWhiteIcon from "@/assets/logo-white.svg"; import { DEVICE_API } from "@/ui.config"; +import { logger } from "@/log"; import api from "../api"; import { DeviceStatus } from "./welcome-local"; - const loader = async () => { const res = await api .GET(`${DEVICE_API}/device/status`) @@ -45,7 +45,7 @@ const action = async ({ request }: ActionFunctionArgs) => { return { error: "Failed to set password" }; } } catch (error) { - console.error("Error setting password:", error); + logger.error("Error setting password:", error); return { error: "An error occurred while setting the password" }; } };