feat: Factory Reset and Reboot wording rework. (#529)

This commit is contained in:
Adam Kelly 2025-07-15 17:32:43 +01:00
parent 488276f3a8
commit 8f76e1f2ab
6 changed files with 95 additions and 50 deletions

View File

@ -205,6 +205,20 @@ func SaveConfig() error {
return nil
}
func RemoveConfig() error {
configLock.Lock()
defer configLock.Unlock()
logger.Trace().Str("path", configPath).Msg("Removing config")
err := os.Remove(configPath)
if err != nil {
return fmt.Errorf("failed to remove config file: %w", err)
}
return nil
}
func ensureConfigLoaded() {
if config == nil {
LoadConfig()

View File

@ -192,6 +192,24 @@ func rpcReboot(force bool) error {
return nil
}
func rpcFactoryReset() error {
logger.Info().Msg("Got factory reset request from JSONRPC")
err := RemoveConfig()
if err != nil {
logger.Error().Err(err).Msg("failed to remove config")
return err
}
err = rpcReboot(true)
if err != nil {
logger.Error().Err(err).Msg("failed to reboot after config remove")
return err
}
return nil
}
var streamFactor = 1.0
func rpcGetStreamQualityFactor() (float64, error) {
@ -1038,6 +1056,7 @@ func rpcSetLocalLoopbackOnly(enabled bool) error {
var rpcHandlers = map[string]RPCHandler{
"ping": {Func: rpcPing},
"reboot": {Func: rpcReboot, Params: []string{"force"}},
"factoryReset": {Func: rpcFactoryReset},
"getDeviceID": {Func: rpcGetDeviceID},
"deregisterDevice": {Func: rpcDeregisterDevice},
"getCloudState": {Func: rpcGetCloudState},

View File

@ -43,6 +43,7 @@ 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 SettingsGeneralFactoryResetRoute from "./routes/devices.$id.settings.general.factory-reset";
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";
@ -145,6 +146,10 @@ if (isOnDevice) {
path: "reboot",
element: <SettingsGeneralRebootRoute />,
},
{
path: "factory-reset",
element: <SettingsGeneralFactoryResetRoute />,
},
{
path: "update",
element: <SettingsGeneralUpdateRoute />,

View File

@ -95,18 +95,33 @@ export default function SettingsGeneralRoute() {
<div className="mt-2 flex items-center justify-between gap-x-2">
<SettingsItem
title="Reboot Device"
description="Power cycle the JetKVM"
title="Reboot"
description="Reboot the JetKVM"
/>
<div>
<Button
size="SM"
theme="light"
text="Reboot Device"
text="Reboot"
onClick={() => navigateTo("./reboot")}
/>
</div>
</div>
<div className="mt-2 flex items-center justify-between gap-x-2">
<SettingsItem
title="Factory Reset"
description="Factory reset the JetKVM to the default configuration"
/>
<div>
<Button
size="SM"
theme="light"
text="Factory Reset"
onClick={() => navigateTo("./factory-reset")}
/>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,29 @@
import { useNavigate } from "react-router-dom";
import { useCallback } from "react";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { ConfirmDialog } from "@/components/ConfirmDialog";
export default function SettingsGeneralFactoryResetRoute() {
const navigate = useNavigate();
const [send] = useJsonRpc();
const onConfirmUpdate = useCallback(() => {
// This is where we send the RPC to the golang binary
send("factoryReset", {});
}, [send]);
{
/* TODO: Migrate to using URLs instead of the global state. To simplify the refactoring, we'll keep the global state for now. */
}
return (
<ConfirmDialog
open={true}
onClose={() => navigate("..")}
title="Factory Reset"
description="Do you want to proceed with factory resetting the JetKVM?"
variant="danger"
onConfirm={onConfirmUpdate}
/>
);
}

View File

@ -2,7 +2,7 @@ import { useNavigate } from "react-router-dom";
import { useCallback } from "react";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { Button } from "@components/Button";
import { ConfirmDialog } from "@/components/ConfirmDialog";
export default function SettingsGeneralRebootRoute() {
const navigate = useNavigate();
@ -16,51 +16,14 @@ export default function SettingsGeneralRebootRoute() {
{
/* TODO: Migrate to using URLs instead of the global state. To simplify the refactoring, we'll keep the global state for now. */
}
return <Dialog onClose={() => navigate("..")} onConfirmUpdate={onConfirmUpdate} />;
}
export function Dialog({
onClose,
onConfirmUpdate,
}: {
onClose: () => void;
onConfirmUpdate: () => void;
}) {
return (
<div className="pointer-events-auto relative mx-auto text-left">
<div>
<ConfirmationBox
onYes={onConfirmUpdate}
onNo={onClose}
<ConfirmDialog
open={true}
onClose={() => navigate("..")}
title="Reboot JetKVM"
description="Do you want to proceed with rebooting the JetKVM?"
variant="danger"
onConfirm={onConfirmUpdate}
/>
</div>
</div>
);
}
function ConfirmationBox({
onYes,
onNo,
}: {
onYes: () => void;
onNo: () => void;
}) {
return (
<div className="flex flex-col items-start justify-start space-y-4 text-left">
<div className="text-left">
<p className="text-base font-semibold text-black dark:text-white">
Reboot JetKVM
</p>
<p className="text-sm text-slate-600 dark:text-slate-300">
Do you want to proceed with rebooting the system?
</p>
<div className="mt-4 flex gap-x-2">
<Button size="SM" theme="light" text="Yes" onClick={onYes} />
<Button size="SM" theme="blank" text="No" onClick={onNo} />
</div>
</div>
</div>
);
}