import SidebarHeader from "@components/SidebarHeader"; import { useLocalAuthModalStore, useSettingsStore, useUiStore, useUpdateStore, } from "@/hooks/stores"; import { Checkbox } from "@components/Checkbox"; import { Button, LinkButton } from "@components/Button"; import { TextAreaWithLabel } from "@components/TextArea"; import { SectionHeader } from "@components/SectionHeader"; import { GridCard } from "@components/Card"; import { CheckCircleIcon } from "@heroicons/react/20/solid"; import { cx } from "@/cva.config"; import React, { useCallback, useEffect, useRef, useState } from "react"; import { isOnDevice } from "@/main"; import PointingFinger from "@/assets/pointing-finger.svg"; import MouseIcon from "@/assets/mouse-icon.svg"; import { useJsonRpc } from "@/hooks/useJsonRpc"; import { SelectMenuBasic } from "../SelectMenuBasic"; import { SystemVersionInfo } from "@components/UpdateDialog"; import notifications from "@/notifications"; import api from "../../api"; import LocalAuthPasswordDialog from "@/components/LocalAuthPasswordDialog"; import { LocalDevice } from "@routes/devices.$id"; import { useRevalidator } from "react-router-dom"; import { ShieldCheckIcon } from "@heroicons/react/20/solid"; export function SettingsItem({ title, description, children, className, }: { title: string; description: string | React.ReactNode; children?: React.ReactNode; className?: string; name?: string; }) { return ( ); } const defaultEdid = "00ffffffffffff0052620188008888881c150103800000780a0dc9a05747982712484c00000001010101010101010101010101010101023a801871382d40582c4500c48e2100001e011d007251d01e206e285500c48e2100001e000000fc00543734392d6648443732300a20000000fd00147801ff1d000a202020202020017b"; const edids = [ { value: defaultEdid, label: "JetKVM Default", }, { value: "00FFFFFFFFFFFF00047265058A3F6101101E0104A53420783FC125A8554EA0260D5054BFEF80714F8140818081C081008B009500B300283C80A070B023403020360006442100001A000000FD00304C575716010A202020202020000000FC0042323436574C0A202020202020000000FF0054384E4545303033383532320A01F802031CF14F90020304050607011112131415161F2309070783010000011D8018711C1620582C250006442100009E011D007251D01E206E28550006442100001E8C0AD08A20E02D10103E9600064421000018C344806E70B028401720A80406442100001E00000000000000000000000000000000000000000000000000000096", label: "Acer B246WL, 1920x1200", }, { value: "00FFFFFFFFFFFF0006B3872401010101021F010380342078EA6DB5A7564EA0250D5054BF6F00714F8180814081C0A9409500B300D1C0283C80A070B023403020360006442100001A000000FD00314B1E5F19000A202020202020000000FC00504132343851560A2020202020000000FF004D314C4D51533035323135370A014D02032AF14B900504030201111213141F230907078301000065030C001000681A00000101314BE6E2006A023A801871382D40582C450006442100001ECD5F80B072B0374088D0360006442100001C011D007251D01E206E28550006442100001E8C0AD08A20E02D10103E960006442100001800000000000000000000000000DC", label: "ASUS PA248QV, 1920x1200", }, { value: "00FFFFFFFFFFFF0010AC132045393639201E0103803C22782ACD25A3574B9F270D5054A54B00714F8180A9C0D1C00101010101010101023A801871382D40582C450056502100001E000000FF00335335475132330A2020202020000000FC0044454C4C204432373231480A20000000FD00384C1E5311000A202020202020018102031AB14F90050403020716010611121513141F65030C001000023A801871382D40582C450056502100001E011D8018711C1620582C250056502100009E011D007251D01E206E28550056502100001E8C0AD08A20E02D10103E960056502100001800000000000000000000000000000000000000000000000000000000004F", label: "DELL D2721H, 1920x1080", }, ]; export default function SettingsSidebar() { const setSidebarView = useUiStore(state => state.setSidebarView); const settings = useSettingsStore(); const [send] = useJsonRpc(); const [streamQuality, setStreamQuality] = useState("1"); const [autoUpdate, setAutoUpdate] = useState(true); const [devChannel, setDevChannel] = useState(false); const [jiggler, setJiggler] = useState(false); const [edid, setEdid] = useState(null); const [customEdidValue, setCustomEdidValue] = useState(null); const [isAdopted, setAdopted] = useState(false); const [deviceId, setDeviceId] = useState(null); const [sshKey, setSSHKey] = useState(""); const [localDevice, setLocalDevice] = useState(null); const sidebarRef = useRef(null); const hideCursor = useSettingsStore(state => state.isCursorHidden); const setHideCursor = useSettingsStore(state => state.setCursorVisibility); const setDeveloperMode = useSettingsStore(state => state.setDeveloperMode); const [currentVersions, setCurrentVersions] = useState<{ appVersion: string; systemVersion: string; } | null>(null); const [usbEmulationEnabled, setUsbEmulationEnabled] = useState(false); const getUsbEmulationState = useCallback(() => { send("getUsbEmulationState", {}, resp => { if ("error" in resp) return; setUsbEmulationEnabled(resp.result as boolean); }); }, [send]); const handleUsbEmulationToggle = useCallback( (enabled: boolean) => { send("setUsbEmulationState", { enabled: enabled }, resp => { if ("error" in resp) { notifications.error( `Failed to ${enabled ? "enable" : "disable"} USB emulation: ${resp.error.data || "Unknown error"}`, ); return; } setUsbEmulationEnabled(enabled); getUsbEmulationState(); }); }, [getUsbEmulationState, send], ); const getCloudState = useCallback(() => { send("getCloudState", {}, resp => { if ("error" in resp) return console.error(resp.error); const cloudState = resp.result as { connected: boolean }; setAdopted(cloudState.connected); }); }, [send]); const deregisterDevice = async () => { send("deregisterDevice", {}, resp => { if ("error" in resp) { notifications.error( `Failed to de-register device: ${resp.error.data || "Unknown error"}`, ); return; } getCloudState(); return; }); }; const handleStreamQualityChange = (factor: string) => { send("setStreamQualityFactor", { factor: Number(factor) }, resp => { if ("error" in resp) { notifications.error( `Failed to set stream quality: ${resp.error.data || "Unknown error"}`, ); return; } setStreamQuality(factor); }); }; const handleAutoUpdateChange = (enabled: boolean) => { send("setAutoUpdateState", { enabled }, resp => { if ("error" in resp) { notifications.error( `Failed to set auto-update: ${resp.error.data || "Unknown error"}`, ); return; } setAutoUpdate(enabled); }); }; const handleDevChannelChange = (enabled: boolean) => { send("setDevChannelState", { enabled }, resp => { if ("error" in resp) { notifications.error( `Failed to set dev channel state: ${resp.error.data || "Unknown error"}`, ); return; } setDevChannel(enabled); }); }; const handleJigglerChange = (enabled: boolean) => { send("setJigglerState", { enabled }, resp => { if ("error" in resp) { notifications.error( `Failed to set jiggler state: ${resp.error.data || "Unknown error"}`, ); return; } setJiggler(enabled); }); }; const handleEDIDChange = (newEdid: string) => { send("setEDID", { edid: newEdid }, resp => { if ("error" in resp) { notifications.error(`Failed to set EDID: ${resp.error.data || "Unknown error"}`); return; } // Update the EDID value in the UI setEdid(newEdid); }); }; const handleSSHKeyChange = (newKey: string) => { setSSHKey(newKey); }; const handleDevModeChange = useCallback( (developerMode: boolean) => { send("setDevModeState", { enabled: developerMode }, resp => { if ("error" in resp) { notifications.error( `Failed to set dev mode: ${resp.error.data || "Unknown error"}`, ); return; } setDeveloperMode(developerMode); setTimeout(() => { sidebarRef.current?.scrollTo({ top: 5000, behavior: "smooth" }); }, 0); }); }, [send, setDeveloperMode], ); const handleUpdateSSHKey = useCallback(() => { send("setSSHKeyState", { sshKey }, resp => { if ("error" in resp) { notifications.error( `Failed to update SSH key: ${resp.error.data || "Unknown error"}`, ); return; } notifications.success("SSH key updated successfully"); }); }, [send, sshKey]); const { setIsUpdateDialogOpen, setModalView, otaState } = useUpdateStore(); const handleCheckForUpdates = () => { if (otaState.updating) { setModalView("updating"); setIsUpdateDialogOpen(true); } else { setModalView("loading"); setIsUpdateDialogOpen(true); } }; useEffect(() => { getCloudState(); send("getDeviceID", {}, async resp => { if ("error" in resp) return console.error(resp.error); setDeviceId(resp.result as string); }); send("getJigglerState", {}, resp => { if ("error" in resp) return; setJiggler(resp.result as boolean); }); send("getAutoUpdateState", {}, resp => { if ("error" in resp) return; setAutoUpdate(resp.result as boolean); }); send("getDevChannelState", {}, resp => { if ("error" in resp) return; setDevChannel(resp.result as boolean); }); send("getStreamQualityFactor", {}, resp => { if ("error" in resp) return; setStreamQuality(String(resp.result)); }); send("getEDID", {}, resp => { if ("error" in resp) { notifications.error(`Failed to get EDID: ${resp.error.data || "Unknown error"}`); return; } const receivedEdid = resp.result as string; const matchingEdid = edids.find( x => x.value.toLowerCase() === receivedEdid.toLowerCase(), ); if (matchingEdid) { // EDID is stored in uppercase in the UI setEdid(matchingEdid.value.toUpperCase()); // Reset custom EDID value setCustomEdidValue(null); } else { setEdid("custom"); setCustomEdidValue(receivedEdid); } }); send("getDevModeState", {}, resp => { if ("error" in resp) return; const result = resp.result as { enabled: boolean }; setDeveloperMode(result.enabled); }); send("getSSHKeyState", {}, resp => { if ("error" in resp) return; setSSHKey(resp.result as string); }); send("getUpdateStatus", {}, resp => { if ("error" in resp) return; const result = resp.result as SystemVersionInfo; setCurrentVersions({ appVersion: result.local.appVersion, systemVersion: result.local.systemVersion, }); }); send("getUsbEmulationState", {}, resp => { if ("error" in resp) return; setUsbEmulationEnabled(resp.result as boolean); }); }, [getCloudState, send, setDeveloperMode, setHideCursor, setJiggler]); const getDevice = useCallback(async () => { try { const status = await api .GET(`${import.meta.env.VITE_SIGNAL_API}/device`) .then(res => res.json() as Promise); setLocalDevice(status); } catch (error) { notifications.error("Failed to get authentication status"); } }, []); const { setModalView: setLocalAuthModalView } = useLocalAuthModalStore(); const [isLocalAuthDialogOpen, setIsLocalAuthDialogOpen] = useState(false); useEffect(() => { if (isOnDevice) getDevice(); }, [getDevice]); useEffect(() => { if (!isOnDevice) return; // Refresh device status when the local auth dialog is closed if (!isLocalAuthDialogOpen) { getDevice(); } }, [getDevice, isLocalAuthDialogOpen]); const revalidator = useRevalidator(); const [currentTheme, setCurrentTheme] = useState(() => { return localStorage.theme || "system"; }); const handleThemeChange = useCallback((value: string) => { const root = document.documentElement; if (value === "system") { localStorage.removeItem("theme"); // Check system preference const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; root.classList.remove("light", "dark"); root.classList.add(systemTheme); } else { localStorage.theme = value; root.classList.remove("light", "dark"); root.classList.add(value); } }, []); const handleResetConfig = useCallback(() => { send("resetConfig", {}, resp => { if ("error" in resp) { notifications.error( `Failed to reset configuration: ${resp.error.data || "Unknown error"}`, ); return; } notifications.success("Configuration reset to default successfully"); }); }, [send]); return (
e.stopPropagation()} onKeyUp={e => e.stopPropagation()} >
App: {currentVersions.appVersion}
System: {currentVersions.systemVersion} ) : ( "Loading current versions..." ) } />
{ setHideCursor(e.target.checked); }} /> { handleJigglerChange(e.target.checked); }} />
handleStreamQualityChange(e.target.value)} /> { if (e.target.value === "custom") { setEdid("custom"); setCustomEdidValue(""); } else { handleEDIDChange(e.target.value as string); } }} options={[...edids, { value: "custom", label: "Custom" }]} /> {customEdidValue !== null && ( <> setCustomEdidValue(e.target.value)} />
)}
{isOnDevice && ( <>

Cloud Security

  • • End-to-end encryption using WebRTC (DTLS and SRTP)
  • • Zero Trust security model
  • • OIDC (OpenID Connect) authentication
  • • All streams encrypted in transit
All cloud components are open-source and available on{" "} GitHub .

{!isAdopted ? (
) : (

Your device is adopted to JetKVM Cloud

)}
)}
{isOnDevice ? ( <>
{localDevice?.authMode === "password" ? (
) : null}
{ handleAutoUpdateChange(e.target.checked); }} /> { handleDevChannelChange(e.target.checked); }} />
{ setCurrentTheme(e.target.value); handleThemeChange(e.target.value); }} />
handleDevModeChange(e.target.checked)} /> {settings.developerMode && (
handleSSHKeyChange(e.target.value)} placeholder="Enter your SSH public key" />

The default SSH user is root.

)} { settings.setDebugMode(e.target.checked); }} /> {settings.debugMode && ( <>
{ // Revalidate the current route to refresh the local device status and dependent UI components revalidator.revalidate(); setIsLocalAuthDialogOpen(x); }} />
); }