From 3d770e73c878c3362d5c52131d279b09f0a56bb2 Mon Sep 17 00:00:00 2001 From: Marc Brooks Date: Tue, 26 Aug 2025 21:40:20 -0500 Subject: [PATCH] chore/Deprecate browser mount No longer supported. --- ui/package-lock.json | 8 +- ui/package.json | 2 +- ui/src/components/popovers/MountPopover.tsx | 77 +-------- ui/src/hooks/stores.ts | 2 +- ui/src/routes/devices.$id.mount.tsx | 173 +------------------- 5 files changed, 13 insertions(+), 249 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 51c1642..1f53f37 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -49,7 +49,7 @@ "@tailwindcss/typography": "^0.5.16", "@tailwindcss/vite": "^4.1.12", "@types/react": "^19.1.11", - "@types/react-dom": "^19.1.7", + "@types/react-dom": "^19.1.8", "@types/semver": "^7.7.0", "@types/validator": "^13.15.2", "@typescript-eslint/eslint-plugin": "^8.41.0", @@ -1970,9 +1970,9 @@ } }, "node_modules/@types/react-dom": { - "version": "19.1.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.7.tgz", - "integrity": "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==", + "version": "19.1.8", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.8.tgz", + "integrity": "sha512-xG7xaBMJCpcK0RpN8jDbAACQo54ycO6h4dSSmgv8+fu6ZIAdANkx/WsawASUjVXYfy+J9AbUpRMNNEsXCDfDBQ==", "license": "MIT", "peerDependencies": { "@types/react": "^19.0.0" diff --git a/ui/package.json b/ui/package.json index 2ceaf30..51de695 100644 --- a/ui/package.json +++ b/ui/package.json @@ -60,7 +60,7 @@ "@tailwindcss/typography": "^0.5.16", "@tailwindcss/vite": "^4.1.12", "@types/react": "^19.1.11", - "@types/react-dom": "^19.1.7", + "@types/react-dom": "^19.1.8", "@types/semver": "^7.7.0", "@types/validator": "^13.15.2", "@typescript-eslint/eslint-plugin": "^8.41.0", diff --git a/ui/src/components/popovers/MountPopover.tsx b/ui/src/components/popovers/MountPopover.tsx index 1ed57d1..1381293 100644 --- a/ui/src/components/popovers/MountPopover.tsx +++ b/ui/src/components/popovers/MountPopover.tsx @@ -1,9 +1,6 @@ -import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; import { PlusCircleIcon } from "@heroicons/react/20/solid"; -import { useMemo, forwardRef, useEffect, useCallback } from "react"; +import { forwardRef, useEffect, useCallback } from "react"; import { - LuArrowUpFromLine, - LuCheckCheck, LuLink, LuPlus, LuRadioReceiver, @@ -14,38 +11,17 @@ import { useLocation } from "react-router-dom"; import { Button } from "@components/Button"; import Card, { GridCard } from "@components/Card"; import { formatters } from "@/utils"; -import { RemoteVirtualMediaState, useMountMediaStore, useRTCStore } from "@/hooks/stores"; +import { RemoteVirtualMediaState, useMountMediaStore } from "@/hooks/stores"; import { SettingsPageHeader } from "@components/SettingsPageheader"; import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc"; import { useDeviceUiNavigation } from "@/hooks/useAppNavigation"; import notifications from "@/notifications"; const MountPopopover = forwardRef((_props, ref) => { - const { diskDataChannelStats } = useRTCStore(); const { send } = useJsonRpc(); const { remoteVirtualMediaState, setModalView, setRemoteVirtualMediaState } = useMountMediaStore(); - const bytesSentPerSecond = useMemo(() => { - if (diskDataChannelStats.size < 2) return null; - - const secondLastItem = - Array.from(diskDataChannelStats)[diskDataChannelStats.size - 2]; - const lastItem = Array.from(diskDataChannelStats)[diskDataChannelStats.size - 1]; - - if (!secondLastItem || !lastItem) return 0; - - const lastTime = lastItem[0]; - const secondLastTime = secondLastItem[0]; - const timeDelta = lastTime - secondLastTime; - - const lastBytesSent = lastItem[1].bytesSent; - const secondLastBytesSent = secondLastItem[1].bytesSent; - const bytesDelta = lastBytesSent - secondLastBytesSent; - - return bytesDelta / timeDelta; - }, [diskDataChannelStats]); - const syncRemoteVirtualMediaState = useCallback(() => { send("getVirtualMediaState", {}, (response: JsonRpcResponse) => { if ("error" in response) { @@ -94,42 +70,6 @@ const MountPopopover = forwardRef((_props, ref) => { const { source, filename, size, url, path } = remoteVirtualMediaState; switch (source) { - case "WebRTC": - return ( - <> -
-
- -

- Streaming from Browser -

-
- -
- {formatters.truncateMiddle(filename, 50)} -
-
-
-
-
-
- {formatters.bytes(size ?? 0)} -
- - - {bytesSentPerSecond !== null - ? `${formatters.bytes(bytesSentPerSecond)}/s` - : "N/A"} - -
-
-
-
- - ); case "HTTP": return (
@@ -202,18 +142,7 @@ const MountPopopover = forwardRef((_props, ref) => { description="Mount an image to boot from or install an operating system." /> - {remoteVirtualMediaState?.source === "WebRTC" ? ( - -
- -
-
Closing this tab will unmount the image
-
-
-
- ) : null} - -
void; - modalView: "mode" | "browser" | "url" | "device" | "upload" | "error" | null; + modalView: "mode" | "url" | "device" | "upload" | "error" | null; setModalView: (view: MountMediaState["modalView"]) => void; isMountMediaDialogOpen: boolean; diff --git a/ui/src/routes/devices.$id.mount.tsx b/ui/src/routes/devices.$id.mount.tsx index 295429f..3361f38 100644 --- a/ui/src/routes/devices.$id.mount.tsx +++ b/ui/src/routes/devices.$id.mount.tsx @@ -1,9 +1,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { - LuGlobe, LuLink, LuRadioReceiver, - LuHardDrive, LuCheck, LuUpload, } from "react-icons/lu"; @@ -131,35 +129,7 @@ export function Dialog({ onClose }: { onClose: () => void }) { clearMountMediaState(); } - function handleBrowserMount(file: File, mode: RemoteVirtualMediaState["mode"]) { - console.log(`Mounting ${file.name} as ${mode}`); - - setMountInProgress(true); - send( - "mountWithWebRTC", - { filename: file.name, size: file.size, mode }, - async resp => { - if ("error" in resp) triggerError(resp.error.message); - - clearMountMediaState(); - syncRemoteVirtualMediaState() - .then(() => { - // We need to keep the local file in the store so that the browser can - // continue to stream the file to the device - setLocalFile(file); - navigate(".."); - }) - .catch(err => { - triggerError(err instanceof Error ? err.message : String(err)); - }) - .finally(() => { - setMountInProgress(false); - }); - }, - ); - } - - const [selectedMode, setSelectedMode] = useState<"browser" | "url" | "device">("url"); + const [selectedMode, setSelectedMode] = useState<"url" | "device">("url"); return (
void }) { "max-w-4xl": modalView === "mode", "max-w-2xl": modalView === "device", "max-w-xl": - modalView === "browser" || modalView === "url" || modalView === "upload" || modalView === "error", @@ -194,19 +163,6 @@ export function Dialog({ onClose }: { onClose: () => void }) { /> )} - {modalView === "browser" && ( - { - handleBrowserMount(file, mode); - }} - onBack={() => { - setMountInProgress(false); - setModalView("mode"); - }} - /> - )} - {modalView === "url" && ( void; - selectedMode: "browser" | "url" | "device"; - setSelectedMode: (mode: "browser" | "url" | "device") => void; + selectedMode: "url" | "device"; + setSelectedMode: (mode: "url" | "device") => void; }) { const { setModalView } = useMountMediaStore(); @@ -292,14 +248,6 @@ function ModeSelectionView({
{[ - { - label: "Browser Mount", - value: "browser", - description: "Stream files directly from your browser", - icon: LuGlobe, - tag: "Coming Soon", - disabled: true, - }, { label: "URL Mount", value: "url", @@ -338,7 +286,7 @@ function ModeSelectionView({
- disabled ? null : setSelectedMode(mode as "browser" | "url" | "device") + disabled ? null : setSelectedMode(mode as "url" | "device") } >
@@ -394,119 +342,6 @@ function ModeSelectionView({ ); } -function BrowserFileView({ - onMountFile, - onBack, - mountInProgress, -}: { - onBack: () => void; - onMountFile: (file: File, mode: RemoteVirtualMediaState["mode"]) => void; - mountInProgress: boolean; -}) { - const [selectedFile, setSelectedFile] = useState(null); - const [usbMode, setUsbMode] = useState("CDROM"); - - const handleFileChange = (event: React.ChangeEvent) => { - const file = event.target.files?.[0] || null; - setSelectedFile(file); - - if (file?.name.endsWith(".iso")) { - setUsbMode("CDROM"); - } else if (file?.name.endsWith(".img")) { - setUsbMode("Disk"); - } - }; - - const handleMount = () => { - if (selectedFile) { - console.log(`Mounting ${selectedFile.name} as ${setUsbMode}`); - onMountFile(selectedFile, usbMode); - } - }; - - return ( -
- -
-
document.getElementById("file-upload")?.click()} - className="block cursor-pointer select-none" - > -
- -
-
- {selectedFile ? ( - <> -
- -

- {formatters.truncateMiddle(selectedFile.name, 40)} -

-

- {formatters.bytes(selectedFile.size)} -

-
- - ) : ( -
- -

- Click to select a file -

-

- Supported formats: ISO, IMG -

-
- )} -
-
-
-
-
- -
- -
-
- -
-
-
-
-
- ); -} - function UrlView({ onBack, onMount,