+
Update in Progress
@@ -39,7 +35,7 @@ export default function UpdateInProgressStatusCard({
text="View Details"
onClick={() => {
setModalView("updating");
- setIsUpdateDialogOpen(true);
+ navigate("update");
}}
/>
diff --git a/ui/src/components/sidebar/settings.tsx b/ui/src/components/sidebar/settings.tsx
index 340fe80..b7bd949 100644
--- a/ui/src/components/sidebar/settings.tsx
+++ b/ui/src/components/sidebar/settings.tsx
@@ -24,7 +24,7 @@ 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 { useRevalidator, useNavigate } from "react-router-dom";
import { ShieldCheckIcon } from "@heroicons/react/20/solid";
import { CLOUD_APP, DEVICE_API } from "@/ui.config";
import { InputFieldWithLabel } from "../InputField";
@@ -267,14 +267,16 @@ export default function SettingsSidebar() {
});
}, [send, sshKey]);
- const { setIsUpdateDialogOpen, setModalView, otaState } = useUpdateStore();
+ const { setModalView, otaState } = useUpdateStore();
+ const navigate = useNavigate();
+
const handleCheckForUpdates = () => {
if (otaState.updating) {
setModalView("updating");
- setIsUpdateDialogOpen(true);
+ navigate("update");
} else {
setModalView("loading");
- setIsUpdateDialogOpen(true);
+ navigate("update");
}
};
diff --git a/ui/src/hooks/stores.ts b/ui/src/hooks/stores.ts
index 5b1366c..ad8cb2b 100644
--- a/ui/src/hooks/stores.ts
+++ b/ui/src/hooks/stores.ts
@@ -303,7 +303,8 @@ export const useSettingsStore = create(
dim_after: 10000,
off_after: 50000,
},
- setBacklightSettings: (settings: BacklightSettings) => set({ backlightSettings: settings }),
+ setBacklightSettings: (settings: BacklightSettings) =>
+ set({ backlightSettings: settings }),
}),
{
name: "settings",
@@ -484,8 +485,6 @@ export interface UpdateState {
| "updateCompleted"
| "error";
setModalView: (view: UpdateState["modalView"]) => void;
- isUpdateDialogOpen: boolean;
- setIsUpdateDialogOpen: (isOpen: boolean) => void;
setUpdateErrorMessage: (errorMessage: string) => void;
updateErrorMessage: string | null;
}
@@ -520,8 +519,6 @@ export const useUpdateStore = create
(set => ({
set({ updateDialogHasBeenMinimized: hasBeenMinimized }),
modalView: "loading",
setModalView: view => set({ modalView: view }),
- isUpdateDialogOpen: false,
- setIsUpdateDialogOpen: isOpen => set({ isUpdateDialogOpen: isOpen }),
updateErrorMessage: null,
setUpdateErrorMessage: errorMessage => set({ updateErrorMessage: errorMessage }),
}));
diff --git a/ui/src/main.tsx b/ui/src/main.tsx
index 9b3599a..dd47073 100644
--- a/ui/src/main.tsx
+++ b/ui/src/main.tsx
@@ -29,6 +29,7 @@ import WelcomeRoute from "./routes/welcome-local";
import WelcomeLocalPasswordRoute from "./routes/welcome-local.password";
import { CLOUD_API } from "./ui.config";
import OtherSessionRoute from "./routes/devices.$id.other-session";
+import UpdateRoute from "./routes/devices.$id.update";
export const isOnDevice = import.meta.env.MODE === "device";
export const isInCloud = !isOnDevice;
@@ -81,6 +82,10 @@ if (isOnDevice) {
path: "other-session",
element: ,
},
+ {
+ path: "update",
+ element: ,
+ },
],
},
@@ -129,6 +134,10 @@ if (isOnDevice) {
path: "other-session",
element: ,
},
+ {
+ path: "update",
+ element: ,
+ },
],
},
{
diff --git a/ui/src/routes/devices.$id.tsx b/ui/src/routes/devices.$id.tsx
index d530e8c..142f29c 100644
--- a/ui/src/routes/devices.$id.tsx
+++ b/ui/src/routes/devices.$id.tsx
@@ -125,13 +125,7 @@ export default function KvmIdRoute() {
const setTransceiver = useRTCStore(state => state.setTransceiver);
const navigate = useNavigate();
- const {
- otaState,
- setOtaState,
- isUpdateDialogOpen,
- setIsUpdateDialogOpen,
- setModalView,
- } = useUpdateStore();
+ const { otaState, setOtaState, setModalView } = useUpdateStore();
const sdp = useCallback(
async (event: RTCPeerConnectionIceEvent, pc: RTCPeerConnection) => {
@@ -356,7 +350,7 @@ export default function KvmIdRoute() {
if (otaState.error) {
setModalView("error");
- setIsUpdateDialogOpen(true);
+ navigate("update");
return;
}
@@ -387,10 +381,10 @@ export default function KvmIdRoute() {
useEffect(() => {
if (queryParams.get("updateSuccess")) {
setModalView("updateCompleted");
- setIsUpdateDialogOpen(true);
+ navigate("update");
setQueryParams({});
}
- }, [queryParams, setIsUpdateDialogOpen, setModalView, setQueryParams]);
+ }, [navigate, queryParams, setModalView, setQueryParams]);
const diskChannel = useRTCStore(state => state.diskChannel)!;
const file = useMountMediaStore(state => state.localFile)!;
@@ -444,16 +438,13 @@ export default function KvmIdRoute() {
}, [kvmTerminal]);
const outlet = useOutlet();
-
+ const isUpdateDialogOpen = location.pathname.includes("/update");
return (
<>
@@ -494,8 +485,6 @@ export default function KvmIdRoute() {
-
-
{kvmTerminal && (
)}
diff --git a/ui/src/routes/devices.$id.update.tsx b/ui/src/routes/devices.$id.update.tsx
new file mode 100644
index 0000000..c8a6641
--- /dev/null
+++ b/ui/src/routes/devices.$id.update.tsx
@@ -0,0 +1,31 @@
+import { useNavigate } from "react-router-dom";
+import { GridCard } from "@/components/Card";
+import { useUpdateStore } from "@/hooks/stores";
+import { Dialog } from "@/components/UpdateDialog";
+import { useJsonRpc } from "@/hooks/useJsonRpc";
+import { useCallback } from "react";
+
+export default function UpdateRoute() {
+ const navigate = useNavigate();
+ const { setModalView } = useUpdateStore();
+ const [send] = useJsonRpc();
+
+ const onConfirmUpdate = useCallback(() => {
+ send("tryUpdate", {});
+ setModalView("updating");
+ }, [send, setModalView]);
+
+ return (
+
+ {/* TODO: Migrate to using URLs instead of the global state. To simplify the refactoring, we'll keep the global state for now. */}
+
+ );
+}