PR updates

This commit is contained in:
Marc Brooks 2025-10-11 00:51:03 +00:00
parent 66ab743dfe
commit 774615557c
8 changed files with 134 additions and 24 deletions

112
ui/package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "kvm-ui",
"version": "2025.10.09.0200",
"version": "2025.10.10.2300",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "kvm-ui",
"version": "2025.10.09.0200",
"version": "2025.10.10.2300",
"dependencies": {
"@headlessui/react": "^2.2.9",
"@headlessui/tailwindcss": "^0.2.2",
@ -22,7 +22,7 @@
"dayjs": "^1.11.18",
"eslint-import-resolver-alias": "^1.1.2",
"focus-trap-react": "^11.0.4",
"framer-motion": "^12.23.22",
"framer-motion": "^12.23.24",
"lodash.throttle": "^4.1.1",
"mini-svg-data-uri": "^1.4.4",
"react": "^19.2.0",
@ -31,7 +31,7 @@
"react-hot-toast": "^2.6.0",
"react-icons": "^5.5.0",
"react-router": "^7.9.4",
"react-simple-keyboard": "^3.8.127",
"react-simple-keyboard": "^3.8.129",
"react-use-websocket": "^4.13.0",
"react-xtermjs": "^1.0.10",
"recharts": "^3.2.1",
@ -62,8 +62,8 @@
"@vitejs/plugin-react-swc": "^4.1.0",
"autoprefixer": "^10.4.21",
"eslint": "^9.37.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.0.0",
"eslint-plugin-react-refresh": "^0.4.23",
@ -1274,6 +1274,19 @@
"node": ">= 8"
}
},
"node_modules/@pkgr/core": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
"integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/pkgr"
}
},
"node_modules/@react-aria/focus": {
"version": "3.21.2",
"resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.21.2.tgz",
@ -4013,6 +4026,8 @@
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"bin": {
"eslint-config-prettier": "bin/cli.js"
},
@ -4132,6 +4147,37 @@
"semver": "bin/semver.js"
}
},
"node_modules/eslint-plugin-prettier": {
"version": "5.5.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz",
"integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==",
"dev": true,
"license": "MIT",
"dependencies": {
"prettier-linter-helpers": "^1.0.0",
"synckit": "^0.11.7"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint-plugin-prettier"
},
"peerDependencies": {
"@types/eslint": ">=8.0.0",
"eslint": ">=8.0.0",
"eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0",
"prettier": ">=3.0.0"
},
"peerDependenciesMeta": {
"@types/eslint": {
"optional": true
},
"eslint-config-prettier": {
"optional": true
}
}
},
"node_modules/eslint-plugin-react": {
"version": "7.37.5",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz",
@ -4360,6 +4406,13 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"license": "MIT"
},
"node_modules/fast-diff": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
"integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/fast-glob": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
@ -4540,12 +4593,12 @@
}
},
"node_modules/framer-motion": {
"version": "12.23.22",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.22.tgz",
"integrity": "sha512-ZgGvdxXCw55ZYvhoZChTlG6pUuehecgvEAJz0BHoC5pQKW1EC5xf1Mul1ej5+ai+pVY0pylyFfdl45qnM1/GsA==",
"version": "12.23.24",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.24.tgz",
"integrity": "sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==",
"license": "MIT",
"dependencies": {
"motion-dom": "^12.23.21",
"motion-dom": "^12.23.23",
"motion-utils": "^12.23.6",
"tslib": "^2.4.0"
},
@ -5869,9 +5922,9 @@
}
},
"node_modules/motion-dom": {
"version": "12.23.21",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.21.tgz",
"integrity": "sha512-5xDXx/AbhrfgsQmSE7YESMn4Dpo6x5/DTZ4Iyy4xqDvVHWvFVoV+V2Ri2S/ksx+D40wrZ7gPYiMWshkdoqNgNQ==",
"version": "12.23.23",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz",
"integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==",
"license": "MIT",
"dependencies": {
"motion-utils": "^12.23.6"
@ -6249,6 +6302,19 @@
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prettier-linter-helpers": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
"integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-diff": "^1.1.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/prettier-plugin-tailwindcss": {
"version": "0.6.14",
"resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.14.tgz",
@ -6498,9 +6564,9 @@
}
},
"node_modules/react-simple-keyboard": {
"version": "3.8.127",
"resolved": "https://registry.npmjs.org/react-simple-keyboard/-/react-simple-keyboard-3.8.127.tgz",
"integrity": "sha512-CncdXLnJ3tBlB6iEHtkgj5W21ns/DdKKO1bCy9pLWey5xONf+KAComVVnDsnAaC0b4LLI7frWBDjOT01vj8dew==",
"version": "3.8.129",
"resolved": "https://registry.npmjs.org/react-simple-keyboard/-/react-simple-keyboard-3.8.129.tgz",
"integrity": "sha512-dvZ+LjOAVkFFay8wZsg//VIMKqfr7tCp28scyFgidAufGjJ60yqWUdckTI1xue827DNb/rbiRuQm5B+3GjcEFQ==",
"license": "MIT",
"peerDependencies": {
"react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
@ -7107,6 +7173,22 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/synckit": {
"version": "0.11.11",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz",
"integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@pkgr/core": "^0.2.9"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/synckit"
}
},
"node_modules/tabbable": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",

View File

@ -1,7 +1,7 @@
{
"name": "kvm-ui",
"private": true,
"version": "2025.10.09.0200",
"version": "2025.10.10.2300",
"type": "module",
"engines": {
"node": "^22.15.0"
@ -35,7 +35,7 @@
"dayjs": "^1.11.18",
"eslint-import-resolver-alias": "^1.1.2",
"focus-trap-react": "^11.0.4",
"framer-motion": "^12.23.22",
"framer-motion": "^12.23.24",
"lodash.throttle": "^4.1.1",
"mini-svg-data-uri": "^1.4.4",
"react": "^19.2.0",
@ -44,7 +44,7 @@
"react-hot-toast": "^2.6.0",
"react-icons": "^5.5.0",
"react-router": "^7.9.4",
"react-simple-keyboard": "^3.8.127",
"react-simple-keyboard": "^3.8.129",
"react-use-websocket": "^4.13.0",
"react-xtermjs": "^1.0.10",
"recharts": "^3.2.1",

View File

@ -255,7 +255,7 @@ function KeyboardWrapper() {
)}
</div>
<h2 className="self-center font-sans text-sm leading-none font-medium text-slate-700 select-none dark:text-slate-300">
m.virtual_keyboard_header()
{m.virtual_keyboard_header()}
</h2>
<div className="absolute right-2 flex items-center gap-x-2">
<div className="hidden md:flex gap-x-2 items-center">

View File

@ -70,7 +70,7 @@ export default function DeviceList({
animationDelay: "0.2s",
}}
>
<Button size="SM" theme="blank" text={m.close()} onClick={onCancelWakeOnLanModal} />
<Button size="SM" theme="blank" text={m.close()} onClick={onCancelWakeOnLanModal} />
<Button
size="SM"
theme="primary"

View File

@ -245,6 +245,8 @@ export class KeyboardMacroReportMessage extends RpcMessage {
...fromUint32toUint8(this.stepCount),
]), 0);
let offset = 6;
for (let i = 0; i < this.stepCount; i++) {
const step = this.steps[i];
if (!withinUint8Range(step.modifier)) {
@ -271,8 +273,8 @@ export class KeyboardMacroReportMessage extends RpcMessage {
...fromUint16toUint8(step.delay),
]);
const offset = 6 + i * 9;
data.set(macroBinary, offset);
offset += 9;
}
return data;

View File

@ -395,7 +395,33 @@ function ErrorBoundary() {
if (error.status === 404) return <NotFoundPage />;
}
const errorMessage: string | null = error?.data?.error?.message ?? error?.message ?? null;
const getErrorMessage = (err: unknown): string | null => {
// If it's a route error response, try to read a string at err.data.error.message or err.data.error safely
if (isRouteErrorResponse(err)) {
const data = (err as { data?: unknown }).data;
if (data && typeof data === "object") {
const maybeError = (data as Record<string, unknown>)["error"];
if (maybeError) {
if (typeof maybeError === "object") {
const msg = (maybeError as Record<string, unknown>)["message"];
if (typeof msg === "string") return msg;
} else if (typeof maybeError === "string") {
return maybeError;
}
}
}
}
// Fallback: check plain object message property
if (err && typeof err === "object") {
const maybeMsg = (err as Record<string, unknown>)["message"];
if (typeof maybeMsg === "string") return maybeMsg;
}
return null;
};
const errorMessage = getErrorMessage(error);
return (
<div className="h-full w-full">

View File

@ -8,6 +8,7 @@ import {
} from "react-icons/lu";
import { PlusCircleIcon, ExclamationTriangleIcon } from "@heroicons/react/20/solid";
import { TrashIcon } from "@heroicons/react/16/solid";
import DebianIcon from "@assets/debian-icon.png";
import UbuntuIcon from "@assets/ubuntu-icon.png";
import FedoraIcon from "@assets/fedora-icon.png";
@ -17,7 +18,6 @@ import NetBootIcon from "@assets/netboot-icon.svg";
import LogoBlueIcon from "@assets/logo-blue.svg";
import LogoWhiteIcon from "@assets/logo-white.svg";
import { cx } from "@/cva.config";
import { JsonRpcResponse, useJsonRpc } from "@hooks/useJsonRpc";
import AutoHeight from "@components/AutoHeight";
import { Button } from "@components/Button";