Compare commits

...

3 Commits

Author SHA1 Message Date
Marc Brooks e2e69e6975
Remove feral async declarations on things that have no await 2025-08-25 16:53:45 -05:00
Marc Brooks f8135263ed
feature/Faster loading
This refactors all the hot-path components for an already-setup JetKVM so that we only
lazy-load the components off the main path. This greatly reduces the initial .JS size at
initial page load from a single file of

dist/assets/index-D4LZBdmN.js                          1,969.46 kB │ gzip: 570.08 kB

To these files, of which the hot-path only loads the 963.29 kB index for a savings of
just over a megabyte (180kb savings in gzip).

dist/assets/login-DA9KVVX1.js                                     0.64 kB │ gzip:   0.40 kB
dist/assets/signup-Bb_VCzY1.js                                    0.67 kB │ gzip:   0.40 kB
dist/assets/devices._id.settings.macros.add-DpBnq5E0.js           0.82 kB │ gzip:   0.55 kB
dist/assets/devices._id.settings.appearance-VHd5B2H2.js           0.91 kB │ gzip:   0.52 kB
dist/assets/devices._id.settings.general.reboot-DsRBP5Dd.js       1.01 kB │ gzip:   0.52 kB
dist/assets/UpdateInProgressStatusCard-DJCdJo-z.js                1.05 kB │ gzip:   0.54 kB
dist/assets/devices._id.other-session-BpXjEP6K.js                 1.09 kB │ gzip:   0.56 kB
dist/assets/devices.already-adopted-BC1xoKrN.js                   1.16 kB │ gzip:   0.57 kB
dist/assets/Checkbox-DGO277w5.js                                  1.24 kB │ gzip:   0.64 kB
dist/assets/devices._id.settings.keyboard-Cno0kaUr.js             1.59 kB │ gzip:   0.81 kB
dist/assets/devices._id.settings.general._index-CNW0Pj5B.js       1.71 kB │ gzip:   0.76 kB
dist/assets/devices._id.settings.macros.edit-BYQGw2CJ.js          1.92 kB │ gzip:   1.00 kB
dist/assets/ConfirmDialog-lzerZkf7.js                             2.77 kB │ gzip:   1.13 kB
dist/assets/AuthLayout-H4vGP3TU.js                                2.96 kB │ gzip:   1.41 kB
dist/assets/AutoHeight-B-TU1fRg.js                                4.07 kB │ gzip:   1.63 kB
dist/assets/devices._id.settings.video-O3qJWstQ.js                5.68 kB │ gzip:   2.17 kB
dist/assets/devices._id.settings.advanced-Drd_iPzw.js             5.98 kB │ gzip:   2.08 kB
dist/assets/devices._id.settings.macros-D3unB0uf.js               6.05 kB │ gzip:   2.13 kB
dist/assets/devices._id.settings.access.local-auth-BltQI66N.js    6.17 kB │ gzip:   1.54 kB
dist/assets/devices._id.settings.mouse-CAwDHqxl.js               10.02 kB │ gzip:   3.59 kB
dist/assets/devices._id.settings.general.update-jkzXML1U.js      10.22 kB │ gzip:   2.67 kB
dist/assets/devices._id.settings.hardware-B7v3lfwA.js            10.41 kB │ gzip:   3.03 kB
dist/assets/devices._id.settings.network-CJYfzFt2.js             25.23 kB │ gzip:   7.21 kB
dist/assets/devices._id.mount-4AT1reig.js                        43.92 kB │ gzip:  19.81 kB
dist/assets/MacroForm-BQpdQgFn.js                                49.75 kB │ gzip:  16.25 kB
dist/assets/connectionStats-NM-PZeH3.js                         400.14 kB │ gzip: 110.33 kB
dist/assets/Terminal-Dgo3sfr-.js                                425.05 kB │ gzip: 109.49 kB
dist/assets/index-w6H2Mz3f.js                                   963.29 kB │ gzip: 294.20 kB
2025-08-25 16:23:47 -05:00
Marc Brooks d952480c2a
fix: useJsonRpc "any" issue
PR #743 didn't have all the files included in the commit.
Mea culpa, many apologies.
2025-08-24 11:40:43 +02:00
29 changed files with 199 additions and 195 deletions

View File

@ -2,7 +2,7 @@ import { useEffect, useMemo, useState } from "react";
import { LuExternalLink } from "react-icons/lu";
import { Button, LinkButton } from "@components/Button";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import { InputFieldWithLabel } from "./InputField";
import { SelectMenuBasic } from "./SelectMenuBasic";
@ -34,7 +34,7 @@ export function JigglerSetting({
const [timezones, setTimezones] = useState<string[]>([]);
useEffect(() => {
send("getTimezones", {}, resp => {
send("getTimezones", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return;
setTimezones(resp.result as string[]);
});

View File

@ -10,7 +10,7 @@ import { useJsonRpc } from "@/hooks/useJsonRpc";
export default function MacroBar() {
const { macros, initialized, loadMacros, setSendFn } = useMacrosStore();
const { executeMacro } = useKeyboard();
const [send] = useJsonRpc();
const { send } = useJsonRpc();
useEffect(() => {
setSendFn(send);

View File

@ -1,6 +1,6 @@
import { useCallback , useEffect, useState } from "react";
import { useJsonRpc } from "../hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "../hooks/useJsonRpc";
import notifications from "../notifications";
import { SettingsItem } from "../routes/devices.$id.settings";
@ -59,7 +59,7 @@ const usbPresets = [
];
export function UsbDeviceSetting() {
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const [loading, setLoading] = useState(false);
const [usbDeviceConfig, setUsbDeviceConfig] =
@ -67,7 +67,7 @@ export function UsbDeviceSetting() {
const [selectedPreset, setSelectedPreset] = useState<string>("default");
const syncUsbDeviceConfig = useCallback(() => {
send("getUsbDevices", {}, resp => {
send("getUsbDevices", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
console.error("Failed to load USB devices:", resp.error);
notifications.error(
@ -97,7 +97,7 @@ export function UsbDeviceSetting() {
const handleUsbConfigChange = useCallback(
(devices: UsbDeviceConfig) => {
setLoading(true);
send("setUsbDevices", { devices }, async resp => {
send("setUsbDevices", { devices }, async (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to set usb devices: ${resp.error.data || "Unknown error"}`,
@ -127,7 +127,7 @@ export function UsbDeviceSetting() {
);
const handlePresetChange = useCallback(
async (e: React.ChangeEvent<HTMLSelectElement>) => {
(e: React.ChangeEvent<HTMLSelectElement>) => {
const newPreset = e.target.value;
setSelectedPreset(newPreset);

View File

@ -4,7 +4,7 @@ import { Button } from "@components/Button";
import { UsbConfigState } from "../hooks/stores";
import { useJsonRpc } from "../hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "../hooks/useJsonRpc";
import notifications from "../notifications";
import { SettingsItem } from "../routes/devices.$id.settings";
@ -54,7 +54,7 @@ const usbConfigs = [
type UsbConfigMap = Record<string, USBConfig>;
export function UsbInfoSetting() {
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const [loading, setLoading] = useState(false);
const [usbConfigProduct, setUsbConfigProduct] = useState("");
@ -94,7 +94,7 @@ export function UsbInfoSetting() {
);
const syncUsbConfigProduct = useCallback(() => {
send("getUsbConfig", {}, resp => {
send("getUsbConfig", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
console.error("Failed to load USB Config:", resp.error);
notifications.error(
@ -114,7 +114,7 @@ export function UsbInfoSetting() {
const handleUsbConfigChange = useCallback(
(usbConfig: USBConfig) => {
setLoading(true);
send("setUsbConfig", { usbConfig }, async resp => {
send("setUsbConfig", { usbConfig }, async (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to set usb config: ${resp.error.data || "Unknown error"}`,
@ -137,7 +137,7 @@ export function UsbInfoSetting() {
);
useEffect(() => {
send("getDeviceID", {}, async resp => {
send("getDeviceID", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
return notifications.error(
`Failed to get device ID: ${resp.error.data || "Unknown error"}`,
@ -205,10 +205,10 @@ function USBConfigDialog({
product: "",
});
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const syncUsbConfig = useCallback(() => {
send("getUsbConfig", {}, resp => {
send("getUsbConfig", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
console.error("Failed to load USB Config:", resp.error);
} else {

View File

@ -74,7 +74,7 @@ export default function WebRTCVideo() {
const [blockWheelEvent, setBlockWheelEvent] = useState(false);
// Misc states and hooks
const [send] = useJsonRpc();
const { send } = useJsonRpc();
// Video-related
useResizeObserver({
@ -411,7 +411,7 @@ export default function WebRTCVideo() {
);
const keyDownHandler = useCallback(
async (e: KeyboardEvent) => {
(e: KeyboardEvent) => {
e.preventDefault();
const prev = useHidStore.getState();
let code = e.code;

View File

@ -7,7 +7,7 @@ import { SettingsPageHeader } from "@components/SettingsPageheader";
import notifications from "@/notifications";
import LoadingSpinner from "@/components/LoadingSpinner";
import { useJsonRpc } from "../../hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "../../hooks/useJsonRpc";
const LONG_PRESS_DURATION = 3000; // 3 seconds for long press
@ -23,7 +23,7 @@ export function ATXPowerControl() {
> | null>(null);
const [atxState, setAtxState] = useState<ATXState | null>(null);
const [send] = useJsonRpc(function onRequest(resp) {
const { send } = useJsonRpc(function onRequest(resp) {
if (resp.method === "atxState") {
setAtxState(resp.params as ATXState);
}
@ -31,7 +31,7 @@ export function ATXPowerControl() {
// Request initial state
useEffect(() => {
send("getATXState", {}, resp => {
send("getATXState", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to get ATX state: ${resp.error.data || "Unknown error"}`,
@ -54,7 +54,7 @@ export function ATXPowerControl() {
const timer = setTimeout(() => {
// Send long press action
console.log("Sending long press ATX power action");
send("setATXPowerAction", { action: "power-long" }, resp => {
send("setATXPowerAction", { action: "power-long" }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to send ATX power action: ${resp.error.data || "Unknown error"}`,
@ -75,7 +75,7 @@ export function ATXPowerControl() {
// Send short press action
console.log("Sending short press ATX power action");
send("setATXPowerAction", { action: "power-short" }, resp => {
send("setATXPowerAction", { action: "power-short" }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to send ATX power action: ${resp.error.data || "Unknown error"}`,
@ -127,7 +127,7 @@ export function ATXPowerControl() {
LeadingIcon={LuRotateCcw}
text="Reset"
onClick={() => {
send("setATXPowerAction", { action: "reset" }, resp => {
send("setATXPowerAction", { action: "reset" }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to send ATX power action: ${resp.error.data || "Unknown error"}`,

View File

@ -4,7 +4,7 @@ import { useCallback, useEffect, useState } from "react";
import { Button } from "@components/Button";
import Card from "@components/Card";
import { SettingsPageHeader } from "@components/SettingsPageheader";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import notifications from "@/notifications";
import FieldLabel from "@components/FieldLabel";
import LoadingSpinner from "@components/LoadingSpinner";
@ -19,11 +19,11 @@ interface DCPowerState {
}
export function DCPowerControl() {
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const [powerState, setPowerState] = useState<DCPowerState | null>(null);
const getDCPowerState = useCallback(() => {
send("getDCPowerState", {}, resp => {
send("getDCPowerState", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to get DC power state: ${resp.error.data || "Unknown error"}`,
@ -35,7 +35,7 @@ export function DCPowerControl() {
}, [send]);
const handlePowerToggle = (enabled: boolean) => {
send("setDCPowerState", { enabled }, resp => {
send("setDCPowerState", { enabled }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to set DC power state: ${resp.error.data || "Unknown error"}`,
@ -47,7 +47,7 @@ export function DCPowerControl() {
};
const handleRestoreChange = (state: number) => {
// const state = powerState?.restoreState === 0 ? 1 : powerState?.restoreState === 1 ? 2 : 0;
send("setDCRestoreState", { state }, resp => {
send("setDCRestoreState", { state }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to set DC power state: ${resp.error.data || "Unknown error"}`,

View File

@ -4,7 +4,7 @@ import { useEffect, useState } from "react";
import { Button } from "@components/Button";
import Card from "@components/Card";
import { SettingsPageHeader } from "@components/SettingsPageheader";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import notifications from "@/notifications";
import { useUiStore } from "@/hooks/stores";
import { SelectMenuBasic } from "@components/SelectMenuBasic";
@ -17,7 +17,7 @@ interface SerialSettings {
}
export function SerialConsole() {
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const [settings, setSettings] = useState<SerialSettings>({
baudRate: "9600",
dataBits: "8",
@ -26,7 +26,7 @@ export function SerialConsole() {
});
useEffect(() => {
send("getSerialSettings", {}, resp => {
send("getSerialSettings", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to get serial settings: ${resp.error.data || "Unknown error"}`,
@ -39,7 +39,7 @@ export function SerialConsole() {
const handleSettingChange = (setting: keyof SerialSettings, value: string) => {
const newSettings = { ...settings, [setting]: value };
send("setSerialSettings", { settings: newSettings }, resp => {
send("setSerialSettings", { settings: newSettings }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to update serial settings: ${resp.error.data || "Unknown error"}`,

View File

@ -1,7 +1,7 @@
import { useEffect, useState } from "react";
import { LuPower, LuTerminal, LuPlugZap } from "react-icons/lu";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import Card, { GridCard } from "@components/Card";
import { SettingsPageHeader } from "@components/SettingsPageheader";
import { ATXPowerControl } from "@components/extensions/ATXPowerControl";
@ -39,12 +39,12 @@ const AVAILABLE_EXTENSIONS: Extension[] = [
];
export default function ExtensionPopover() {
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const [activeExtension, setActiveExtension] = useState<Extension | null>(null);
// Load active extension on component mount
useEffect(() => {
send("getActiveExtension", {}, resp => {
send("getActiveExtension", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return;
const extensionId = resp.result as string;
if (extensionId) {
@ -57,7 +57,7 @@ export default function ExtensionPopover() {
}, [send]);
const handleSetActiveExtension = (extension: Extension | null) => {
send("setActiveExtension", { extensionId: extension?.id || "" }, resp => {
send("setActiveExtension", { extensionId: extension?.id || "" }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to set active extension: ${resp.error.data || "Unknown error"}`,

View File

@ -16,13 +16,13 @@ import Card, { GridCard } from "@components/Card";
import { formatters } from "@/utils";
import { RemoteVirtualMediaState, useMountMediaStore, useRTCStore } from "@/hooks/stores";
import { SettingsPageHeader } from "@components/SettingsPageheader";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import { useDeviceUiNavigation } from "@/hooks/useAppNavigation";
import notifications from "@/notifications";
const MountPopopover = forwardRef<HTMLDivElement, object>((_props, ref) => {
const diskDataChannelStats = useRTCStore(state => state.diskDataChannelStats);
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const { remoteVirtualMediaState, setModalView, setRemoteVirtualMediaState } =
useMountMediaStore();
@ -47,7 +47,7 @@ const MountPopopover = forwardRef<HTMLDivElement, object>((_props, ref) => {
}, [diskDataChannelStats]);
const syncRemoteVirtualMediaState = useCallback(() => {
send("getVirtualMediaState", {}, response => {
send("getVirtualMediaState", {}, (response: JsonRpcResponse) => {
if ("error" in response) {
notifications.error(
`Failed to get virtual media state: ${response.error.message}`,
@ -59,7 +59,7 @@ const MountPopopover = forwardRef<HTMLDivElement, object>((_props, ref) => {
}, [send, setRemoteVirtualMediaState]);
const handleUnmount = () => {
send("unmountImage", {}, response => {
send("unmountImage", {}, (response: JsonRpcResponse) => {
if ("error" in response) {
notifications.error(`Failed to unmount image: ${response.error.message}`);
} else {

View File

@ -7,7 +7,7 @@ import { Button } from "@components/Button";
import { GridCard } from "@components/Card";
import { TextAreaWithLabel } from "@components/TextArea";
import { SettingsPageHeader } from "@components/SettingsPageheader";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import { useHidStore, useRTCStore, useUiStore, useSettingsStore } from "@/hooks/stores";
import { keys, modifiers } from "@/keyboardMappings";
import { KeyStroke, KeyboardLayout, selectedKeyboard } from "@/keyboardLayouts";
@ -28,7 +28,7 @@ export default function PasteModal() {
const setPasteMode = useHidStore(state => state.setPasteModeEnabled);
const setDisableVideoFocusTrap = useUiStore(state => state.setDisableVideoFocusTrap);
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const rpcDataChannel = useRTCStore(state => state.rpcDataChannel);
const [invalidChars, setInvalidChars] = useState<string[]>([]);
@ -47,7 +47,7 @@ export default function PasteModal() {
}, [keyboardLayout]);
useEffect(() => {
send("getKeyboardLayout", {}, resp => {
send("getKeyboardLayout", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return;
setKeyboardLayout(resp.result as string);
});

View File

@ -3,7 +3,7 @@ import { useClose } from "@headlessui/react";
import { GridCard } from "@components/Card";
import { SettingsPageHeader } from "@components/SettingsPageheader";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import { useRTCStore, useUiStore } from "@/hooks/stores";
import notifications from "@/notifications";
@ -18,7 +18,7 @@ export default function WakeOnLanModal() {
const rpcDataChannel = useRTCStore(state => state.rpcDataChannel);
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const close = useClose();
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const [addDeviceErrorMessage, setAddDeviceErrorMessage] = useState<string | null>(null);
@ -33,7 +33,7 @@ export default function WakeOnLanModal() {
setErrorMessage(null);
if (rpcDataChannel?.readyState !== "open") return;
send("sendWOLMagicPacket", { macAddress }, resp => {
send("sendWOLMagicPacket", { macAddress }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
const isInvalid = resp.error.data?.includes("invalid MAC address");
if (isInvalid) {
@ -52,7 +52,7 @@ export default function WakeOnLanModal() {
);
const syncStoredDevices = useCallback(() => {
send("getWakeOnLanDevices", {}, resp => {
send("getWakeOnLanDevices", {}, (resp: JsonRpcResponse) => {
if ("result" in resp) {
setStoredDevices(resp.result as StoredDevice[]);
} else {
@ -70,7 +70,7 @@ export default function WakeOnLanModal() {
(index: number) => {
const updatedDevices = storedDevices.filter((_, i) => i !== index);
send("setWakeOnLanDevices", { params: { devices: updatedDevices } }, resp => {
send("setWakeOnLanDevices", { params: { devices: updatedDevices } }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
console.error("Failed to update Wake-on-LAN devices:", resp.error);
} else {
@ -86,7 +86,7 @@ export default function WakeOnLanModal() {
if (!name || !macAddress) return;
const updatedDevices = [...storedDevices, { name, macAddress }];
console.log("updatedDevices", updatedDevices);
send("setWakeOnLanDevices", { params: { devices: updatedDevices } }, resp => {
send("setWakeOnLanDevices", { params: { devices: updatedDevices } }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
console.error("Failed to add Wake-on-LAN device:", resp.error);
setAddDeviceErrorMessage("Failed to add device");

View File

@ -833,7 +833,7 @@ export const useMacrosStore = create<MacrosState>((set, get) => ({
try {
await new Promise<void>((resolve, reject) => {
sendFn("getKeyboardMacros", {}, response => {
sendFn("getKeyboardMacros", {}, (response: JsonRpcResponse) => {
if (response.error) {
console.error("Error loading macros:", response.error);
reject(new Error(response.error.message));

View File

@ -78,5 +78,5 @@ export function useJsonRpc(onRequest?: (payload: JsonRpcRequest) => void) {
};
}, [rpcDataChannel, onRequest]);
return [send];
return { send };
}

View File

@ -5,7 +5,7 @@ import { useJsonRpc } from "@/hooks/useJsonRpc";
import { keys, modifiers } from "@/keyboardMappings";
export default function useKeyboard() {
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const rpcDataChannel = useRTCStore(state => state.rpcDataChannel);
const updateActiveKeysAndModifiers = useHidStore(

View File

@ -1,3 +1,4 @@
import { lazy } from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import {
@ -9,46 +10,45 @@ import {
} from "react-router-dom";
import { ExclamationTriangleIcon } from "@heroicons/react/16/solid";
import { CLOUD_API, DEVICE_API } from "@/ui.config";
import api from "@/api";
import Root from "@/root";
import Card from "@components/Card";
import EmptyCard from "@components/EmptyCard";
import NotFoundPage from "@components/NotFoundPage";
import DeviceRoute, { LocalDevice } from "@routes/devices.$id";
import WelcomeRoute, { DeviceStatus } from "@routes/welcome-local";
import LoginLocalRoute from "@routes/login-local";
import WelcomeLocalModeRoute from "@routes/welcome-local.mode";
import WelcomeLocalPasswordRoute from "@routes/welcome-local.password";
import AdoptRoute from "@routes/adopt";
import SetupRoute from "@routes/devices.$id.setup";
import DevicesIdDeregister from "@routes/devices.$id.deregister";
import DeviceIdRename from "@routes/devices.$id.rename";
import AdoptRoute from "@routes/adopt";
import SignupRoute from "@routes/signup";
import LoginRoute from "@routes/login";
import SetupRoute from "@routes/devices.$id.setup";
import DevicesRoute from "@routes/devices";
import DeviceRoute, { LocalDevice } from "@routes/devices.$id";
import Card from "@components/Card";
import DevicesAlreadyAdopted from "@routes/devices.already-adopted";
import Root from "./root";
import Notifications from "./notifications";
import LoginLocalRoute from "./routes/login-local";
import WelcomeLocalModeRoute from "./routes/welcome-local.mode";
import WelcomeRoute, { DeviceStatus } from "./routes/welcome-local";
import WelcomeLocalPasswordRoute from "./routes/welcome-local.password";
import { CLOUD_API, DEVICE_API } from "./ui.config";
import OtherSessionRoute from "./routes/devices.$id.other-session";
import MountRoute from "./routes/devices.$id.mount";
import * as SettingsRoute from "./routes/devices.$id.settings";
import SettingsMouseRoute from "./routes/devices.$id.settings.mouse";
import SettingsKeyboardRoute from "./routes/devices.$id.settings.keyboard";
import api from "./api";
import * as SettingsIndexRoute from "./routes/devices.$id.settings._index";
import SettingsAdvancedRoute from "./routes/devices.$id.settings.advanced";
import SettingsAccessIndexRoute from "./routes/devices.$id.settings.access._index";
import SettingsHardwareRoute from "./routes/devices.$id.settings.hardware";
import SettingsVideoRoute from "./routes/devices.$id.settings.video";
import SettingsAppearanceRoute from "./routes/devices.$id.settings.appearance";
import * as SettingsGeneralIndexRoute from "./routes/devices.$id.settings.general._index";
import SettingsGeneralRebootRoute from "./routes/devices.$id.settings.general.reboot";
import SettingsGeneralUpdateRoute from "./routes/devices.$id.settings.general.update";
import SettingsNetworkRoute from "./routes/devices.$id.settings.network";
import SecurityAccessLocalAuthRoute from "./routes/devices.$id.settings.access.local-auth";
import SettingsMacrosRoute from "./routes/devices.$id.settings.macros";
import SettingsMacrosAddRoute from "./routes/devices.$id.settings.macros.add";
import SettingsMacrosEditRoute from "./routes/devices.$id.settings.macros.edit";
import SettingsIndexRoute from "@routes/devices.$id.settings._index";
import SettingsAccessIndexRoute from "@routes/devices.$id.settings.access._index";
const Notifications = lazy(() => import("@/notifications"));
const SignupRoute = lazy(() => import("@routes/signup"));
const LoginRoute = lazy(() => import("@routes/login"));
const DevicesAlreadyAdopted = lazy(() => import("@routes/devices.already-adopted"));
const OtherSessionRoute = lazy(() => import("@routes/devices.$id.other-session"));
const MountRoute = lazy(() => import("./routes/devices.$id.mount"));
const SettingsRoute = lazy(() => import("@routes/devices.$id.settings"));
const SettingsMouseRoute = lazy(() => import("@routes/devices.$id.settings.mouse"));
const SettingsKeyboardRoute = lazy(() => import("@routes/devices.$id.settings.keyboard"));
const SettingsAdvancedRoute = lazy(() => import("@routes/devices.$id.settings.advanced"));
const SettingsHardwareRoute = lazy(() => import("@routes/devices.$id.settings.hardware"));
const SettingsVideoRoute = lazy(() => import("@routes/devices.$id.settings.video"));
const SettingsAppearanceRoute = lazy(() => import("@routes/devices.$id.settings.appearance"));
const SettingsGeneralIndexRoute = lazy(() => import("@routes/devices.$id.settings.general._index"));
const SettingsGeneralRebootRoute = lazy(() => import("@routes/devices.$id.settings.general.reboot"));
const SettingsGeneralUpdateRoute = lazy(() => import("@routes/devices.$id.settings.general.update"));
const SettingsNetworkRoute = lazy(() => import("@routes/devices.$id.settings.network"));
const SecurityAccessLocalAuthRoute = lazy(() => import("@routes/devices.$id.settings.access.local-auth"));
const SettingsMacrosRoute = lazy(() => import("@routes/devices.$id.settings.macros"));
const SettingsMacrosAddRoute = lazy(() => import("@routes/devices.$id.settings.macros.add"));
const SettingsMacrosEditRoute = lazy(() => import("@routes/devices.$id.settings.macros.edit"));
export const isOnDevice = import.meta.env.MODE === "device";
export const isInCloud = !isOnDevice;
@ -128,7 +128,7 @@ if (isOnDevice) {
},
{
path: "settings",
element: <SettingsRoute.default />,
element: <SettingsRoute />,
children: [
{
index: true,
@ -139,7 +139,7 @@ if (isOnDevice) {
children: [
{
index: true,
element: <SettingsGeneralIndexRoute.default />,
element: <SettingsGeneralIndexRoute />,
},
{
path: "reboot",
@ -265,7 +265,7 @@ if (isOnDevice) {
},
{
path: "settings",
element: <SettingsRoute.default />,
element: <SettingsRoute />,
children: [
{
index: true,
@ -276,7 +276,7 @@ if (isOnDevice) {
children: [
{
index: true,
element: <SettingsGeneralIndexRoute.default />,
element: <SettingsGeneralIndexRoute />,
},
{
path: "update",

View File

@ -27,7 +27,7 @@ import NetBootIcon from "@/assets/netboot-icon.svg";
import Fieldset from "@/components/Fieldset";
import { DEVICE_API } from "@/ui.config";
import { useJsonRpc } from "../hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "../hooks/useJsonRpc";
import notifications from "../notifications";
import { isOnDevice } from "../main";
import { cx } from "../cva.config";
@ -64,10 +64,10 @@ export function Dialog({ onClose }: { onClose: () => void }) {
setRemoteVirtualMediaState(null);
}
const [send] = useJsonRpc();
const { send } = useJsonRpc();
async function syncRemoteVirtualMediaState() {
return new Promise((resolve, reject) => {
send("getVirtualMediaState", {}, resp => {
send("getVirtualMediaState", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
reject(new Error(resp.error.message));
} else {
@ -89,7 +89,7 @@ export function Dialog({ onClose }: { onClose: () => void }) {
console.log(`Mounting ${url} as ${mode}`);
setMountInProgress(true);
send("mountWithHTTP", { url, mode }, async resp => {
send("mountWithHTTP", { url, mode }, (resp: JsonRpcResponse) => {
if ("error" in resp) triggerError(resp.error.message);
clearMountMediaState();
@ -108,7 +108,7 @@ export function Dialog({ onClose }: { onClose: () => void }) {
console.log(`Mounting ${fileName} as ${mode}`);
setMountInProgress(true);
send("mountWithStorage", { filename: fileName, mode }, async resp => {
send("mountWithStorage", { filename: fileName, mode }, (resp: JsonRpcResponse) => {
if ("error" in resp) triggerError(resp.error.message);
clearMountMediaState();
@ -689,7 +689,7 @@ function DeviceFileView({
const [currentPage, setCurrentPage] = useState(1);
const filesPerPage = 5;
const [send] = useJsonRpc();
const { send } = useJsonRpc();
interface StorageSpace {
bytesUsed: number;
@ -718,12 +718,12 @@ function DeviceFileView({
}, [storageSpace]);
const syncStorage = useCallback(() => {
send("listStorageFiles", {}, res => {
if ("error" in res) {
notifications.error(`Error listing storage files: ${res.error}`);
send("listStorageFiles", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(`Error listing storage files: ${resp.error}`);
return;
}
const { files } = res.result as StorageFiles;
const { files } = resp.result as StorageFiles;
const formattedFiles = files.map(file => ({
name: file.filename,
size: formatters.bytes(file.size),
@ -733,13 +733,13 @@ function DeviceFileView({
setOnStorageFiles(formattedFiles);
});
send("getStorageSpace", {}, res => {
if ("error" in res) {
notifications.error(`Error getting storage space: ${res.error}`);
send("getStorageSpace", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(`Error getting storage space: ${resp.error}`);
return;
}
const space = res.result as StorageSpace;
const space = resp.result as StorageSpace;
setStorageSpace(space);
});
}, [send, setOnStorageFiles, setStorageSpace]);
@ -762,9 +762,9 @@ function DeviceFileView({
function handleDeleteFile(file: { name: string; size: string; createdAt: string }) {
console.log("Deleting file:", file);
send("deleteStorageFile", { filename: file.name }, res => {
if ("error" in res) {
notifications.error(`Error deleting file: ${res.error}`);
send("deleteStorageFile", { filename: file.name }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(`Error deleting file: ${resp.error}`);
return;
}
@ -1001,7 +1001,7 @@ function UploadFileView({
const [fileError, setFileError] = useState<string | null>(null);
const [uploadError, setUploadError] = useState<string | null>(null);
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const rtcDataChannelRef = useRef<RTCDataChannel | null>(null);
useEffect(() => {
@ -1216,7 +1216,7 @@ function UploadFileView({
setUploadState("uploading");
console.log("Upload state set to 'uploading'");
send("startStorageFileUpload", { filename: file.name, size: file.size }, resp => {
send("startStorageFileUpload", { filename: file.name, size: file.size }, (resp: JsonRpcResponse) => {
console.log("startStorageFileUpload response:", resp);
if ("error" in resp) {
console.error("Upload error:", resp.error.message);

View File

@ -2,6 +2,12 @@ import { LoaderFunctionArgs, redirect } from "react-router-dom";
import { getDeviceUiPath } from "../hooks/useAppNavigation";
export function loader({ params }: LoaderFunctionArgs) {
const loader = ({ params }: LoaderFunctionArgs) => {
return redirect(getDeviceUiPath("/settings/general", params.id));
}
export default function SettingIndexRoute() {
return (<></>);
}
SettingIndexRoute.loader = loader;

View File

@ -12,7 +12,7 @@ import { SettingsSectionHeader } from "@/components/SettingsSectionHeader";
import { useDeviceUiNavigation } from "@/hooks/useAppNavigation";
import notifications from "@/notifications";
import { DEVICE_API } from "@/ui.config";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import { isOnDevice } from "@/main";
import { TextAreaWithLabel } from "@components/TextArea";
@ -42,7 +42,7 @@ export default function SettingsAccessIndexRoute() {
const { navigateTo } = useDeviceUiNavigation();
const navigate = useNavigate();
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const [isAdopted, setAdopted] = useState(false);
const [deviceId, setDeviceId] = useState<string | null>(null);
@ -56,7 +56,7 @@ export default function SettingsAccessIndexRoute() {
const [tlsKey, setTlsKey] = useState<string>("");
const getCloudState = useCallback(() => {
send("getCloudState", {}, resp => {
send("getCloudState", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return console.error(resp.error);
const cloudState = resp.result as CloudState;
setAdopted(cloudState.connected);
@ -77,7 +77,7 @@ export default function SettingsAccessIndexRoute() {
}, [send]);
const getTLSState = useCallback(() => {
send("getTLSState", {}, resp => {
send("getTLSState", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return console.error(resp.error);
const tlsState = resp.result as TLSState;
@ -87,8 +87,8 @@ export default function SettingsAccessIndexRoute() {
});
}, [send]);
const deregisterDevice = async () => {
send("deregisterDevice", {}, resp => {
const deregisterDevice = () => {
send("deregisterDevice", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to de-register device: ${resp.error.data || "Unknown error"}`,
@ -110,7 +110,7 @@ export default function SettingsAccessIndexRoute() {
return;
}
send("setCloudUrl", { apiUrl: cloudApiUrl, appUrl: cloudAppUrl }, resp => {
send("setCloudUrl", { apiUrl: cloudApiUrl, appUrl: cloudAppUrl }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to update cloud URL: ${resp.error.data || "Unknown error"}`,
@ -156,7 +156,7 @@ export default function SettingsAccessIndexRoute() {
state.privateKey = key;
}
send("setTLSState", { state }, resp => {
send("setTLSState", { state }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to update TLS settings: ${resp.error.data || "Unknown error"}`,
@ -198,7 +198,7 @@ export default function SettingsAccessIndexRoute() {
getCloudState();
getTLSState();
send("getDeviceID", {}, async resp => {
send("getDeviceID", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return console.error(resp.error);
setDeviceId(resp.result as string);
});

View File

@ -8,14 +8,14 @@ import { ConfirmDialog } from "../components/ConfirmDialog";
import { SettingsPageHeader } from "../components/SettingsPageheader";
import { TextAreaWithLabel } from "../components/TextArea";
import { useSettingsStore } from "../hooks/stores";
import { useJsonRpc } from "../hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "../hooks/useJsonRpc";
import { isOnDevice } from "../main";
import notifications from "../notifications";
import { SettingsItem } from "./devices.$id.settings";
export default function SettingsAdvancedRoute() {
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const [sshKey, setSSHKey] = useState<string>("");
const setDeveloperMode = useSettingsStore(state => state.setDeveloperMode);
@ -27,35 +27,35 @@ export default function SettingsAdvancedRoute() {
const settings = useSettingsStore();
useEffect(() => {
send("getDevModeState", {}, resp => {
send("getDevModeState", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return;
const result = resp.result as { enabled: boolean };
setDeveloperMode(result.enabled);
});
send("getSSHKeyState", {}, resp => {
send("getSSHKeyState", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return;
setSSHKey(resp.result as string);
});
send("getUsbEmulationState", {}, resp => {
send("getUsbEmulationState", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return;
setUsbEmulationEnabled(resp.result as boolean);
});
send("getDevChannelState", {}, resp => {
send("getDevChannelState", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return;
setDevChannel(resp.result as boolean);
});
send("getLocalLoopbackOnly", {}, resp => {
send("getLocalLoopbackOnly", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return;
setLocalLoopbackOnly(resp.result as boolean);
});
}, [send, setDeveloperMode]);
const getUsbEmulationState = useCallback(() => {
send("getUsbEmulationState", {}, resp => {
send("getUsbEmulationState", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return;
setUsbEmulationEnabled(resp.result as boolean);
});
@ -63,7 +63,7 @@ export default function SettingsAdvancedRoute() {
const handleUsbEmulationToggle = useCallback(
(enabled: boolean) => {
send("setUsbEmulationState", { enabled: enabled }, resp => {
send("setUsbEmulationState", { enabled: enabled }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to ${enabled ? "enable" : "disable"} USB emulation: ${resp.error.data || "Unknown error"}`,
@ -78,7 +78,7 @@ export default function SettingsAdvancedRoute() {
);
const handleResetConfig = useCallback(() => {
send("resetConfig", {}, resp => {
send("resetConfig", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to reset configuration: ${resp.error.data || "Unknown error"}`,
@ -90,7 +90,7 @@ export default function SettingsAdvancedRoute() {
}, [send]);
const handleUpdateSSHKey = useCallback(() => {
send("setSSHKeyState", { sshKey }, resp => {
send("setSSHKeyState", { sshKey }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to update SSH key: ${resp.error.data || "Unknown error"}`,
@ -103,7 +103,7 @@ export default function SettingsAdvancedRoute() {
const handleDevModeChange = useCallback(
(developerMode: boolean) => {
send("setDevModeState", { enabled: developerMode }, resp => {
send("setDevModeState", { enabled: developerMode }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to set dev mode: ${resp.error.data || "Unknown error"}`,
@ -118,7 +118,7 @@ export default function SettingsAdvancedRoute() {
const handleDevChannelChange = useCallback(
(enabled: boolean) => {
send("setDevChannelState", { enabled }, resp => {
send("setDevChannelState", { enabled }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to set dev channel state: ${resp.error.data || "Unknown error"}`,
@ -133,7 +133,7 @@ export default function SettingsAdvancedRoute() {
const applyLoopbackOnlyMode = useCallback(
(enabled: boolean) => {
send("setLocalLoopbackOnly", { enabled }, resp => {
send("setLocalLoopbackOnly", { enabled }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to ${enabled ? "enable" : "disable"} loopback-only mode: ${resp.error.data || "Unknown error"}`,

View File

@ -1,7 +1,7 @@
import { useState , useEffect } from "react";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import { SettingsPageHeader } from "../components/SettingsPageheader";
import { Button } from "../components/Button";
@ -13,7 +13,7 @@ import { useDeviceStore } from "../hooks/stores";
import { SettingsItem } from "./devices.$id.settings";
export default function SettingsGeneralRoute() {
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const { navigateTo } = useDeviceUiNavigation();
const [autoUpdate, setAutoUpdate] = useState(true);
@ -24,14 +24,14 @@ export default function SettingsGeneralRoute() {
});
useEffect(() => {
send("getAutoUpdateState", {}, resp => {
send("getAutoUpdateState", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return;
setAutoUpdate(resp.result as boolean);
});
}, [send]);
const handleAutoUpdateChange = (enabled: boolean) => {
send("setAutoUpdateState", { enabled }, resp => {
send("setAutoUpdateState", { enabled }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to set auto-update: ${resp.error.data || "Unknown error"}`,

View File

@ -6,7 +6,7 @@ import { Button } from "@components/Button";
export default function SettingsGeneralRebootRoute() {
const navigate = useNavigate();
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const onConfirmUpdate = useCallback(() => {
// This is where we send the RPC to the golang binary

View File

@ -3,7 +3,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
import { CheckCircleIcon } from "@heroicons/react/20/solid";
import Card from "@/components/Card";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import { Button } from "@components/Button";
import { UpdateState, useDeviceStore, useUpdateStore } from "@/hooks/stores";
import notifications from "@/notifications";
@ -16,7 +16,7 @@ export default function SettingsGeneralUpdateRoute() {
const { updateSuccess } = location.state || {};
const { setModalView, otaState } = useUpdateStore();
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const onConfirmUpdate = useCallback(() => {
send("tryUpdate", {});
@ -62,7 +62,7 @@ export function Dialog({
const { modalView, setModalView, otaState } = useUpdateStore();
const onFinishedLoading = useCallback(
async (versionInfo: SystemVersionInfo) => {
(versionInfo: SystemVersionInfo) => {
const hasUpdate =
versionInfo?.systemUpdateAvailable || versionInfo?.appUpdateAvailable;
@ -134,14 +134,14 @@ function LoadingState({
}) {
const [progressWidth, setProgressWidth] = useState("0%");
const abortControllerRef = useRef<AbortController | null>(null);
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const setAppVersion = useDeviceStore(state => state.setAppVersion);
const setSystemVersion = useDeviceStore(state => state.setSystemVersion);
const getVersionInfo = useCallback(() => {
return new Promise<SystemVersionInfo>((resolve, reject) => {
send("getUpdateStatus", {}, async resp => {
send("getUpdateStatus", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(`Failed to check for updates: ${resp.error}`);
reject(new Error("Failed to check for updates"));

View File

@ -3,7 +3,7 @@ import { useEffect } from "react";
import { SettingsPageHeader } from "@components/SettingsPageheader";
import { SettingsItem } from "@routes/devices.$id.settings";
import { BacklightSettings, useSettingsStore } from "@/hooks/stores";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import { SelectMenuBasic } from "@components/SelectMenuBasic";
import { UsbDeviceSetting } from "@components/UsbDeviceSetting";
@ -12,7 +12,7 @@ import { UsbInfoSetting } from "../components/UsbInfoSetting";
import { FeatureFlag } from "../components/FeatureFlag";
export default function SettingsHardwareRoute() {
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const settings = useSettingsStore();
const setDisplayRotation = useSettingsStore(state => state.setDisplayRotation);
@ -23,7 +23,7 @@ export default function SettingsHardwareRoute() {
};
const handleDisplayRotationSave = () => {
send("setDisplayRotation", { params: { rotation: settings.displayRotation } }, resp => {
send("setDisplayRotation", { params: { rotation: settings.displayRotation } }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to set display orientation: ${resp.error.data || "Unknown error"}`,
@ -48,7 +48,7 @@ export default function SettingsHardwareRoute() {
};
const handleBacklightSettingsSave = () => {
send("setBacklightSettings", { params: settings.backlightSettings }, resp => {
send("setBacklightSettings", { params: settings.backlightSettings }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to set backlight settings: ${resp.error.data || "Unknown error"}`,
@ -60,7 +60,7 @@ export default function SettingsHardwareRoute() {
};
useEffect(() => {
send("getBacklightSettings", {}, resp => {
send("getBacklightSettings", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
return notifications.error(
`Failed to get backlight settings: ${resp.error.data || "Unknown error"}`,

View File

@ -1,7 +1,7 @@
import { useCallback, useEffect, useMemo } from "react";
import { KeyboardLedSync, useSettingsStore } from "@/hooks/stores";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import notifications from "@/notifications";
import { SettingsPageHeader } from "@components/SettingsPageheader";
import { keyboardOptions } from "@/keyboardLayouts";
@ -39,10 +39,10 @@ export default function SettingsKeyboardRoute() {
{ value: "host", label: "Host Only" },
];
const [send] = useJsonRpc();
const { send } = useJsonRpc();
useEffect(() => {
send("getKeyboardLayout", {}, resp => {
send("getKeyboardLayout", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return;
setKeyboardLayout(resp.result as string);
});
@ -51,7 +51,7 @@ export default function SettingsKeyboardRoute() {
const onKeyboardLayoutChange = useCallback(
(e: React.ChangeEvent<HTMLSelectElement>) => {
const layout = e.target.value;
send("setKeyboardLayout", { layout }, resp => {
send("setKeyboardLayout", { layout }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to set keyboard layout: ${resp.error.data || "Unknown error"}`,

View File

@ -6,7 +6,7 @@ import PointingFinger from "@/assets/pointing-finger.svg";
import { GridCard } from "@/components/Card";
import { Checkbox } from "@/components/Checkbox";
import { useSettingsStore } from "@/hooks/stores";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import { SettingsPageHeader } from "@components/SettingsPageheader";
import { SelectMenuBasic } from "@components/SelectMenuBasic";
import { JigglerSetting } from "@components/JigglerSetting";
@ -87,17 +87,17 @@ export default function SettingsMouseRoute() {
{ value: "100", label: "Very High" },
];
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const syncJigglerSettings = useCallback(() => {
send("getJigglerState", {}, resp => {
send("getJigglerState", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return;
const isEnabled = resp.result as boolean;
// If the jiggler is disabled, set the selected option to "disabled" and nothing else
if (!isEnabled) return setSelectedJigglerOption("disabled");
send("getJigglerConfig", {}, resp => {
send("getJigglerConfig", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return;
const result = resp.result as JigglerConfig;
setCurrentJigglerConfig(result);
@ -121,7 +121,7 @@ export default function SettingsMouseRoute() {
const saveJigglerConfig = useCallback(
(jigglerConfig: JigglerConfig) => {
// We assume the jiggler should be set to enabled if the config is being updated
send("setJigglerState", { enabled: true }, async resp => {
send("setJigglerState", { enabled: true }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
return notifications.error(
`Failed to set jiggler state: ${resp.error.data || "Unknown error"}`,
@ -129,7 +129,7 @@ export default function SettingsMouseRoute() {
}
});
send("setJigglerConfig", { jigglerConfig }, async resp => {
send("setJigglerConfig", { jigglerConfig }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
const errorMsg = resp.error.data || "Unknown error";
@ -163,7 +163,7 @@ export default function SettingsMouseRoute() {
// We don't need to update the device jiggler state when the option is "disabled"
if (option === "disabled") {
send("setJigglerState", { enabled: false }, async resp => {
send("setJigglerState", { enabled: false }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
return notifications.error(
`Failed to set jiggler state: ${resp.error.data || "Unknown error"}`,

View File

@ -13,7 +13,7 @@ import {
TimeSyncMode,
useNetworkStateStore,
} from "@/hooks/stores";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import { Button } from "@components/Button";
import { GridCard } from "@components/Card";
import InputField, { InputFieldWithLabel } from "@components/InputField";
@ -72,7 +72,7 @@ export function LifeTimeLabel({ lifetime }: { lifetime: string }) {
}
export default function SettingsNetworkRoute() {
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const [networkState, setNetworkState] = useNetworkStateStore(state => [
state,
state.setNetworkState,
@ -104,7 +104,7 @@ export default function SettingsNetworkRoute() {
const getNetworkSettings = useCallback(() => {
setNetworkSettingsLoaded(false);
send("getNetworkSettings", {}, resp => {
send("getNetworkSettings", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return;
console.log(resp.result);
setNetworkSettings(resp.result as NetworkSettings);
@ -117,7 +117,7 @@ export default function SettingsNetworkRoute() {
}, [send]);
const getNetworkState = useCallback(() => {
send("getNetworkState", {}, resp => {
send("getNetworkState", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return;
console.log(resp.result);
setNetworkState(resp.result as NetworkState);
@ -127,7 +127,7 @@ export default function SettingsNetworkRoute() {
const setNetworkSettingsRemote = useCallback(
(settings: NetworkSettings) => {
setNetworkSettingsLoaded(false);
send("setNetworkSettings", { settings }, resp => {
send("setNetworkSettings", { settings }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
"Failed to save network settings: " +
@ -148,7 +148,7 @@ export default function SettingsNetworkRoute() {
);
const handleRenewLease = useCallback(() => {
send("renewDHCPLease", {}, resp => {
send("renewDHCPLease", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error("Failed to renew lease: " + resp.error.message);
} else {

View File

@ -2,7 +2,7 @@ import { useState, useEffect } from "react";
import { Button } from "@/components/Button";
import { TextAreaWithLabel } from "@/components/TextArea";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import { SettingsPageHeader } from "@components/SettingsPageheader";
import { useSettingsStore } from "@/hooks/stores";
@ -41,7 +41,7 @@ const streamQualityOptions = [
];
export default function SettingsVideoRoute() {
const [send] = useJsonRpc();
const { send } = useJsonRpc();
const [streamQuality, setStreamQuality] = useState("1");
const [customEdidValue, setCustomEdidValue] = useState<string | null>(null);
const [edid, setEdid] = useState<string | null>(null);
@ -55,12 +55,12 @@ export default function SettingsVideoRoute() {
const setVideoContrast = useSettingsStore(state => state.setVideoContrast);
useEffect(() => {
send("getStreamQualityFactor", {}, resp => {
send("getStreamQualityFactor", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return;
setStreamQuality(String(resp.result));
});
send("getEDID", {}, resp => {
send("getEDID", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(`Failed to get EDID: ${resp.error.data || "Unknown error"}`);
return;
@ -85,7 +85,7 @@ export default function SettingsVideoRoute() {
}, [send]);
const handleStreamQualityChange = (factor: string) => {
send("setStreamQualityFactor", { factor: Number(factor) }, resp => {
send("setStreamQualityFactor", { factor: Number(factor) }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(
`Failed to set stream quality: ${resp.error.data || "Unknown error"}`,
@ -99,7 +99,7 @@ export default function SettingsVideoRoute() {
};
const handleEDIDChange = (newEdid: string) => {
send("setEDID", { edid: newEdid }, resp => {
send("setEDID", { edid: newEdid }, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(`Failed to set EDID: ${resp.error.data || "Unknown error"}`);
return;

View File

@ -1,4 +1,4 @@
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { lazy, useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
LoaderFunctionArgs,
Outlet,
@ -16,7 +16,11 @@ import { FocusTrap } from "focus-trap-react";
import { motion, AnimatePresence } from "framer-motion";
import useWebSocket from "react-use-websocket";
import { CLOUD_API, DEVICE_API } from "@/ui.config";
import api from "@/api";
import { checkAuth, isInCloud, isOnDevice } from "@/main";
import { cx } from "@/cva.config";
import notifications from "@/notifications";
import {
HidState,
KeyboardLedState,
@ -34,27 +38,21 @@ import {
VideoState,
} from "@/hooks/stores";
import WebRTCVideo from "@components/WebRTCVideo";
import { checkAuth, isInCloud, isOnDevice } from "@/main";
import DashboardNavbar from "@components/Header";
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 UpdateInProgressStatusCard from "../components/UpdateInProgressStatusCard";
import api from "../api";
import Modal from "../components/Modal";
import { useDeviceUiNavigation } from "../hooks/useAppNavigation";
const ConnectionStatsSidebar = lazy(() => import('@/components/sidebar/connectionStats'));
const Terminal = lazy(() => import('@components/Terminal'));
const UpdateInProgressStatusCard = lazy(() => import("@/components/UpdateInProgressStatusCard"));
import Modal from "@/components/Modal";
import { JsonRpcRequest, JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import {
ConnectionFailedOverlay,
LoadingConnectionOverlay,
PeerConnectionDisconnectedOverlay,
} from "../components/VideoOverlay";
import { FeatureFlagProvider } from "../providers/FeatureFlagProvider";
import notifications from "../notifications";
import { DeviceStatus } from "./welcome-local";
import { SystemVersionInfo } from "./devices.$id.settings.general.update";
} from "@/components/VideoOverlay";
import { useDeviceUiNavigation } from "@/hooks/useAppNavigation";
import { FeatureFlagProvider } from "@/providers/FeatureFlagProvider";
import { DeviceStatus } from "@routes/welcome-local";
import { SystemVersionInfo } from "@routes/devices.$id.settings.general.update";
interface LocalLoaderResp {
authMode: "password" | "noPassword" | null;
@ -114,7 +112,7 @@ const cloudLoader = async (params: Params<string>): Promise<CloudLoaderResp> =>
return { user, iceConfig, deviceName: device.name || device.id };
};
const loader = async ({ params }: LoaderFunctionArgs) => {
const loader = ({ params }: LoaderFunctionArgs) => {
return import.meta.env.MODE === "device" ? deviceLoader() : cloudLoader(params);
};
@ -452,7 +450,7 @@ export default function KvmIdRoute() {
}
};
pc.onicecandidate = async ({ candidate }) => {
pc.onicecandidate = ({ candidate }) => {
if (!candidate) return;
if (candidate.candidate === "") return;
sendWebRTCSignal("new-ice-candidate", candidate);
@ -646,11 +644,11 @@ export default function KvmIdRoute() {
}
const rpcDataChannel = useRTCStore(state => state.rpcDataChannel);
const [send] = useJsonRpc(onJsonRpcRequest);
const { send } = useJsonRpc(onJsonRpcRequest);
useEffect(() => {
if (rpcDataChannel?.readyState !== "open") return;
send("getVideoState", {}, resp => {
send("getVideoState", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return;
setHdmiState(resp.result as Parameters<VideoState["setHdmiState"]>[0]);
});
@ -662,7 +660,7 @@ export default function KvmIdRoute() {
if (keyboardLedState !== undefined) return;
console.log("Requesting keyboard led state");
send("getKeyboardLedState", {}, resp => {
send("getKeyboardLedState", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
// -32601 means the method is not supported
if (resp.error.code === -32601) {
@ -735,7 +733,7 @@ export default function KvmIdRoute() {
useEffect(() => {
if (appVersion) return;
send("getUpdateStatus", {}, async resp => {
send("getUpdateStatus", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) {
notifications.error(`Failed to get device version: ${resp.error}`);
return