Settings General pages

This commit is contained in:
Marc Brooks 2025-10-14 00:03:18 -05:00
parent f2e665126a
commit 340a04f23a
No known key found for this signature in database
GPG Key ID: 583A6AF2D6AE1DC6
4 changed files with 118 additions and 82 deletions

View File

@ -337,6 +337,7 @@
"rename_device_new_name_placeholder": "Plex Media Server", "rename_device_new_name_placeholder": "Plex Media Server",
"rename_device_no_name": "Please specify a name", "rename_device_no_name": "Please specify a name",
"rename": "Rename", "rename": "Rename",
"retry": "Retry",
"saving": "Saving…", "saving": "Saving…",
"search_placeholder": "Search…", "search_placeholder": "Search…",
"serial_console_baud_rate": "Baud Rate", "serial_console_baud_rate": "Baud Rate",
@ -599,5 +600,50 @@
"appearance_theme_light": "Light", "appearance_theme_light": "Light",
"appearance_theme_system": "System", "appearance_theme_system": "System",
"appearance_theme": "Theme", "appearance_theme": "Theme",
"appearance_title": "Appearance" "appearance_title": "Appearance",
"general_app_version": "App: {version}",
"general_auto_update_description": "Automatically update the device to the latest version",
"general_auto_update_error": "Failed to set auto-update: {error}",
"general_auto_update_title": "Auto Update",
"general_check_for_updates": "Check for Updates",
"general_page_description": "Configure device settings and update preferences",
"general_reboot_device": "Reboot Device",
"general_reboot_device_description": "Power cycle the JetKVM",
"general_system_version": "System: {version}",
"general_title": "General",
"general_update_app_update_title": "App Update",
"general_update_application_type": "App",
"general_update_available_description": "A new update is available to enhance system performance and improve compatibility. We recommend updating to ensure everything runs smoothly.",
"general_update_available_title": "Update available",
"general_update_background_button": "Update in Background",
"general_update_check_again_button": "Check Again",
"general_update_checking_description": "We're ensuring your device has the latest features and improvements.",
"general_update_checking_title": "Checking for updates...",
"general_update_completed_description": "Your device has been successfully updated to the latest version. Enjoy the new features and improvements!",
"general_update_completed_title": "Update Completed Successfully",
"general_update_error_description": "An error occurred while updating your device. Please try again later.",
"general_update_error_details": "Error details: {errorMessage}",
"general_update_error_title": "Update Error",
"general_update_later_button": "Do it later",
"general_update_now_button": "Update Now",
"general_update_rebooting": "Rebooting to complete the update...",
"general_update_system_type": "System",
"general_update_status_awaiting_reboot": "Awaiting reboot",
"general_update_status_downloading": "Downloading {update_type} update...",
"general_update_status_fetching": "Fetching update information...",
"general_update_status_installing": "Installing {update_type} update...",
"general_update_status_verifying": "Verifying {update_type} update...",
"general_update_system_update_title": "Linux System Update",
"general_update_up_to_date_description": "Your system is running the latest version. No updates are currently available.",
"general_update_up_to_date_title": "System is up to date",
"general_update_updating_description": "Please don't turn off your device. This process may take a few minutes.",
"general_update_updating_title": "Updating your device",
"general_reboot_description": "Do you want to proceed with rebooting the system?",
"general_reboot_no_button": "No",
"general_reboot_title": "Reboot JetKVM",
"general_reboot_yes_button": "Yes"
} }

View File

@ -1,16 +1,14 @@
import { useState, useEffect } from "react";
import { useState , useEffect } from "react"; import { JsonRpcResponse, useJsonRpc } from "@hooks/useJsonRpc";
import { useDeviceUiNavigation } from "@hooks/useAppNavigation";
import { useDeviceStore } from "@hooks/stores";
import { Button } from "@components/Button";
import Checkbox from "@components/Checkbox";
import { SettingsItem } from "@components/SettingsItem"; import { SettingsItem } from "@components/SettingsItem";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc"; import { SettingsPageHeader } from "@components/SettingsPageheader";
import notifications from "@/notifications";
import { SettingsPageHeader } from "../components/SettingsPageheader"; import { m } from "@localizations/messages.js";
import { Button } from "../components/Button";
import notifications from "../notifications";
import Checkbox from "../components/Checkbox";
import { useDeviceUiNavigation } from "../hooks/useAppNavigation";
import { useDeviceStore } from "../hooks/stores";
export default function SettingsGeneralRoute() { export default function SettingsGeneralRoute() {
const { send } = useJsonRpc(); const { send } = useJsonRpc();
@ -34,7 +32,7 @@ export default function SettingsGeneralRoute() {
send("setAutoUpdateState", { enabled }, (resp: JsonRpcResponse) => { send("setAutoUpdateState", { enabled }, (resp: JsonRpcResponse) => {
if ("error" in resp) { if ("error" in resp) {
notifications.error( notifications.error(
`Failed to set auto-update: ${resp.error.data || "Unknown error"}`, m.general_auto_update_error({ error: resp.error.data || m.unknown_error() }),
); );
return; return;
} }
@ -45,44 +43,36 @@ export default function SettingsGeneralRoute() {
return ( return (
<div className="space-y-4"> <div className="space-y-4">
<SettingsPageHeader <SettingsPageHeader
title="General" title={m.general_title()}
description="Configure device settings and update preferences" description={m.general_page_description()}
/> />
<div className="space-y-4"> <div className="space-y-4">
<div className="space-y-4 pb-2"> <div className="space-y-4 pb-2">
<div className="mt-2 flex items-center justify-between gap-x-2"> <div className="mt-2 flex items-center justify-between gap-x-2">
<SettingsItem <SettingsItem
title="Check for Updates" title={m.general_check_for_updates()}
description={ description={
currentVersions ? ( <>
<> {m.general_app_version({ version: currentVersions ? currentVersions.appVersion : m.loading() })}
App: {currentVersions.appVersion} <br />
<br /> {m.general_system_version({ version: currentVersions ? currentVersions.systemVersion : m.loading() })}
System: {currentVersions.systemVersion} </>
</>
) : (
<>
App: Loading...
<br />
System: Loading...
</>
)
} }
/> />
<div> <div>
<Button <Button
size="SM" size="SM"
theme="light" theme="light"
text="Check for Updates" text={m.general_check_for_updates()}
onClick={() => navigateTo("./update")} onClick={() => navigateTo("./update")}
/> />
</div> </div>
</div> </div>
<div className="space-y-4"> <div className="space-y-4">
<SettingsItem <SettingsItem
title="Auto Update" title={m.general_auto_update_title()}
description="Automatically update the device to the latest version" description={m.general_auto_update_description()}
> >
<Checkbox <Checkbox
checked={autoUpdate} checked={autoUpdate}
@ -95,14 +85,14 @@ export default function SettingsGeneralRoute() {
<div className="mt-2 flex items-center justify-between gap-x-2"> <div className="mt-2 flex items-center justify-between gap-x-2">
<SettingsItem <SettingsItem
title="Reboot Device" title={m.general_reboot_device()}
description="Power cycle the JetKVM" description={m.general_reboot_device_description()}
/> />
<div> <div>
<Button <Button
size="SM" size="SM"
theme="light" theme="light"
text="Reboot Device" text={m.general_reboot_device()}
onClick={() => navigateTo("./reboot")} onClick={() => navigateTo("./reboot")}
/> />
</div> </div>

View File

@ -3,6 +3,7 @@ import { useNavigate } from "react-router";
import { useJsonRpc } from "@hooks/useJsonRpc"; import { useJsonRpc } from "@hooks/useJsonRpc";
import { Button } from "@components/Button"; import { Button } from "@components/Button";
import { m } from "@localizations/messages.js";
export default function SettingsGeneralRebootRoute() { export default function SettingsGeneralRebootRoute() {
const navigate = useNavigate(); const navigate = useNavigate();
@ -50,15 +51,15 @@ function ConfirmationBox({
<div className="flex flex-col items-start justify-start space-y-4 text-left"> <div className="flex flex-col items-start justify-start space-y-4 text-left">
<div className="text-left"> <div className="text-left">
<p className="text-base font-semibold text-black dark:text-white"> <p className="text-base font-semibold text-black dark:text-white">
Reboot JetKVM {m.general_reboot_title()}
</p> </p>
<p className="text-sm text-slate-600 dark:text-slate-300"> <p className="text-sm text-slate-600 dark:text-slate-300">
Do you want to proceed with rebooting the system? {m.general_reboot_description()}
</p> </p>
<div className="mt-4 flex gap-x-2"> <div className="mt-4 flex gap-x-2">
<Button size="SM" theme="light" text="Yes" onClick={onYes} /> <Button size="SM" theme="light" text={m.general_reboot_yes_button()} onClick={onYes} />
<Button size="SM" theme="blank" text="No" onClick={onNo} /> <Button size="SM" theme="blank" text={m.general_reboot_no_button()} onClick={onNo} />
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,14 +1,15 @@
import { useLocation, useNavigate } from "react-router";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { useLocation, useNavigate } from "react-router";
import { CheckCircleIcon } from "@heroicons/react/20/solid"; import { CheckCircleIcon } from "@heroicons/react/20/solid";
import Card from "@/components/Card"; import { useJsonRpc } from "@hooks/useJsonRpc";
import { useJsonRpc } from "@/hooks/useJsonRpc"; import { UpdateState, useUpdateStore } from "@hooks/stores";
import { useDeviceUiNavigation } from "@hooks/useAppNavigation";
import { SystemVersionInfo, useVersion } from "@hooks/useVersion";
import { Button } from "@components/Button"; import { Button } from "@components/Button";
import { UpdateState, useUpdateStore } from "@/hooks/stores"; import Card from "@components/Card";
import LoadingSpinner from "@/components/LoadingSpinner"; import LoadingSpinner from "@components/LoadingSpinner";
import { useDeviceUiNavigation } from "@/hooks/useAppNavigation"; import { m } from "@localizations/messages.js";
import { SystemVersionInfo, useVersion } from "@/hooks/useVersion";
export default function SettingsGeneralUpdateRoute() { export default function SettingsGeneralUpdateRoute() {
const navigate = useNavigate(); const navigate = useNavigate();
@ -160,10 +161,10 @@ function LoadingState({
<div className="space-y-4"> <div className="space-y-4">
<div className="space-y-0"> <div className="space-y-0">
<p className="text-base font-semibold text-black dark:text-white"> <p className="text-base font-semibold text-black dark:text-white">
Checking for updates... {m.general_update_checking_title()}
</p> </p>
<p className="text-sm text-slate-600 dark:text-slate-300"> <p className="text-sm text-slate-600 dark:text-slate-300">
We{"'"}re ensuring your device has the latest features and improvements. {m.general_update_checking_description()}
</p> </p>
</div> </div>
<div className="h-2.5 w-full overflow-hidden rounded-full bg-slate-300"> <div className="h-2.5 w-full overflow-hidden rounded-full bg-slate-300">
@ -174,7 +175,7 @@ function LoadingState({
></div> ></div>
</div> </div>
<div className="mt-4"> <div className="mt-4">
<Button size="SM" theme="light" text="Cancel" onClick={onCancelCheck} /> <Button size="SM" theme="light" text={m.cancel()} onClick={onCancelCheck} />
</div> </div>
</div> </div>
</div> </div>
@ -228,16 +229,18 @@ function UpdatingDeviceState({
const verfiedAt = otaState[`${type}VerifiedAt`]; const verfiedAt = otaState[`${type}VerifiedAt`];
const updatedAt = otaState[`${type}UpdatedAt`]; const updatedAt = otaState[`${type}UpdatedAt`];
const update_type = () => (type === "system" ? m.general_update_system_type() : m.general_update_app_type());
if (!otaState.metadataFetchedAt) { if (!otaState.metadataFetchedAt) {
return "Fetching update information..."; return m.general_update_status_fetching();
} else if (!downloadFinishedAt) { } else if (!downloadFinishedAt) {
return `Downloading ${type} update...`; return m.general_update_status_downloading({ update_type });
} else if (!verfiedAt) { } else if (!verfiedAt) {
return `Verifying ${type} update...`; return m.general_update_status_verifying({ update_type });
} else if (!updatedAt) { } else if (!updatedAt) {
return `Installing ${type} update...`; return m.general_update_status_installing({ update_type });
} else { } else {
return `Awaiting reboot`; return m.general_update_status_awaiting_reboot();
} }
}; };
@ -260,10 +263,10 @@ function UpdatingDeviceState({
<div className="w-full max-w-sm space-y-4"> <div className="w-full max-w-sm space-y-4">
<div className="space-y-0"> <div className="space-y-0">
<p className="text-base font-semibold text-black dark:text-white"> <p className="text-base font-semibold text-black dark:text-white">
Updating your device {m.general_update_updating_title()}
</p> </p>
<p className="text-sm text-slate-600 dark:text-slate-300"> <p className="text-sm text-slate-600 dark:text-slate-300">
Please don{"'"}t turn off your device. This process may take a few minutes. {m.general_update_updating_description()}
</p> </p>
</div> </div>
<Card className="space-y-4 p-4"> <Card className="space-y-4 p-4">
@ -272,7 +275,7 @@ function UpdatingDeviceState({
<LoadingSpinner className="h-6 w-6 text-blue-700 dark:text-blue-500" /> <LoadingSpinner className="h-6 w-6 text-blue-700 dark:text-blue-500" />
<div className="flex justify-between text-sm text-slate-600 dark:text-slate-300"> <div className="flex justify-between text-sm text-slate-600 dark:text-slate-300">
<span className="font-medium text-black dark:text-white"> <span className="font-medium text-black dark:text-white">
Rebooting to complete the update... {m.general_update_rebooting()}
</span> </span>
</div> </div>
</div> </div>
@ -288,7 +291,7 @@ function UpdatingDeviceState({
<div className="space-y-2"> <div className="space-y-2">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<p className="text-sm font-semibold text-black dark:text-white"> <p className="text-sm font-semibold text-black dark:text-white">
Linux System Update {m.general_update_system_update_title()}
</p> </p>
{calculateOverallProgress("system") < 100 ? ( {calculateOverallProgress("system") < 100 ? (
<LoadingSpinner className="h-4 w-4 text-blue-700 dark:text-blue-500" /> <LoadingSpinner className="h-4 w-4 text-blue-700 dark:text-blue-500" />
@ -320,7 +323,7 @@ function UpdatingDeviceState({
<div className="space-y-2"> <div className="space-y-2">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<p className="text-sm font-semibold text-black dark:text-white"> <p className="text-sm font-semibold text-black dark:text-white">
App Update {m.general_update_app_update_title()}
</p> </p>
{calculateOverallProgress("app") < 100 ? ( {calculateOverallProgress("app") < 100 ? (
<LoadingSpinner className="h-4 w-4 text-blue-700 dark:text-blue-500" /> <LoadingSpinner className="h-4 w-4 text-blue-700 dark:text-blue-500" />
@ -352,7 +355,7 @@ function UpdatingDeviceState({
<Button <Button
size="XS" size="XS"
theme="light" theme="light"
text="Update in Background" text={m.general_update_background_button()}
onClick={onMinimizeUpgradeDialog} onClick={onMinimizeUpgradeDialog}
/> />
</div> </div>
@ -372,15 +375,15 @@ function SystemUpToDateState({
<div className="flex flex-col items-start justify-start space-y-4 text-left"> <div className="flex flex-col items-start justify-start space-y-4 text-left">
<div className="text-left"> <div className="text-left">
<p className="text-base font-semibold text-black dark:text-white"> <p className="text-base font-semibold text-black dark:text-white">
System is up to date {m.general_update_up_to_date_title()}
</p> </p>
<p className="text-sm text-slate-600 dark:text-slate-300"> <p className="text-sm text-slate-600 dark:text-slate-300">
Your system is running the latest version. No updates are currently available. {m.general_update_up_to_date_description()}
</p> </p>
<div className="mt-4 flex gap-x-2"> <div className="mt-4 flex gap-x-2">
<Button size="SM" theme="light" text="Check Again" onClick={checkUpdate} /> <Button size="SM" theme="light" text={m.general_update_check_again_button()} onClick={checkUpdate} />
<Button size="SM" theme="blank" text="Back" onClick={onClose} /> <Button size="SM" theme="blank" text={m.general_update_back_button()} onClick={onClose} />
</div> </div>
</div> </div>
</div> </div>
@ -400,30 +403,27 @@ function UpdateAvailableState({
<div className="flex flex-col items-start justify-start space-y-4 text-left"> <div className="flex flex-col items-start justify-start space-y-4 text-left">
<div className="text-left"> <div className="text-left">
<p className="text-base font-semibold text-black dark:text-white"> <p className="text-base font-semibold text-black dark:text-white">
Update available {m.general_update_available_title()}
</p> </p>
<p className="mb-2 text-sm text-slate-600 dark:text-slate-300"> <p className="mb-2 text-sm text-slate-600 dark:text-slate-300">
A new update is available to enhance system performance and improve {m.general_update_available_description()}
compatibility. We recommend updating to ensure everything runs smoothly.
</p> </p>
<p className="mb-4 text-sm text-slate-600 dark:text-slate-300"> <p className="mb-4 text-sm text-slate-600 dark:text-slate-300">
{versionInfo?.systemUpdateAvailable ? ( {versionInfo?.systemUpdateAvailable ? (
<> <>
<span className="font-semibold">System:</span>{" "} <span className="font-semibold">{m.general_update_system_type()}</span>:&nbsp;{versionInfo?.remote?.systemVersion}
{versionInfo?.remote?.systemVersion}
<br /> <br />
</> </>
) : null} ) : null}
{versionInfo?.appUpdateAvailable ? ( {versionInfo?.appUpdateAvailable ? (
<> <>
<span className="font-semibold">App:</span>{" "} <span className="font-semibold">{m.general_update_application_type()}</span>:&nbsp;{versionInfo?.remote?.appVersion}
{versionInfo?.remote?.appVersion}
</> </>
) : null} ) : null}
</p> </p>
<div className="flex items-center justify-start gap-x-2"> <div className="flex items-center justify-start gap-x-2">
<Button size="SM" theme="primary" text="Update Now" onClick={onConfirmUpdate} /> <Button size="SM" theme="primary" text={m.general_update_now_button()} onClick={onConfirmUpdate} />
<Button size="SM" theme="light" text="Do it later" onClick={onClose} /> <Button size="SM" theme="light" text={m.general_update_later_button()} onClick={onClose} />
</div> </div>
</div> </div>
</div> </div>
@ -435,14 +435,13 @@ function UpdateCompletedState({ onClose }: { onClose: () => void }) {
<div className="flex flex-col items-start justify-start space-y-4 text-left"> <div className="flex flex-col items-start justify-start space-y-4 text-left">
<div className="text-left"> <div className="text-left">
<p className="text-base font-semibold dark:text-white"> <p className="text-base font-semibold dark:text-white">
Update Completed Successfully {m.general_update_completed_title()}
</p> </p>
<p className="mb-4 text-sm text-slate-600 dark:text-slate-400"> <p className="mb-4 text-sm text-slate-600 dark:text-slate-400">
Your device has been successfully updated to the latest version. Enjoy the new {m.general_update_completed_description()}
features and improvements!
</p> </p>
<div className="flex items-center justify-start"> <div className="flex items-center justify-start">
<Button size="SM" theme="primary" text="Back" onClick={onClose} /> <Button size="SM" theme="primary" text={m.back()} onClick={onClose} />
</div> </div>
</div> </div>
</div> </div>
@ -461,18 +460,18 @@ function UpdateErrorState({
return ( return (
<div className="flex flex-col items-start justify-start space-y-4 text-left"> <div className="flex flex-col items-start justify-start space-y-4 text-left">
<div className="text-left"> <div className="text-left">
<p className="text-base font-semibold dark:text-white">Update Error</p> <p className="text-base font-semibold dark:text-white">{m.general_update_error_title()}</p>
<p className="mb-4 text-sm text-slate-600 dark:text-slate-400"> <p className="mb-4 text-sm text-slate-600 dark:text-slate-400">
An error occurred while updating your device. Please try again later. {m.general_update_error_description()}
</p> </p>
{errorMessage && ( {errorMessage && (
<p className="mb-4 text-sm font-medium text-red-600 dark:text-red-400"> <p className="mb-4 text-sm font-medium text-red-600 dark:text-red-400">
Error details: {errorMessage} {m.general_update_error_details({ errorMessage })}
</p> </p>
)} )}
<div className="flex items-center justify-start gap-x-2"> <div className="flex items-center justify-start gap-x-2">
<Button size="SM" theme="light" text="Back" onClick={onClose} /> <Button size="SM" theme="light" text={m.back()} onClick={onClose} />
<Button size="SM" theme="blank" text="Retry" onClick={onRetryUpdate} /> <Button size="SM" theme="blank" text={m.retry()} onClick={onRetryUpdate} />
</div> </div>
</div> </div>
</div> </div>