From 9832be29ef76f9c2a1b7272d371019d285b30fb4 Mon Sep 17 00:00:00 2001
From: Siyuan
Date: Fri, 7 Nov 2025 17:13:04 +0000
Subject: [PATCH] refactor: remove downgrade attributes from ota state and
jsonrpc
---
internal/ota/ota.go | 15 ++++++++----
internal/ota/state.go | 19 ++++++---------
jsonrpc.go | 1 -
ota.go | 10 --------
ui/src/hooks/stores.ts | 1 -
ui/src/hooks/useVersion.tsx | 2 --
.../routes/devices.$id.settings.advanced.tsx | 24 +++++++++++++++----
.../devices.$id.settings.general.update.tsx | 5 ++--
ui/src/utils/jsonrpc.ts | 2 --
9 files changed, 40 insertions(+), 39 deletions(-)
diff --git a/internal/ota/ota.go b/internal/ota/ota.go
index e23010f5..272a5414 100644
--- a/internal/ota/ota.go
+++ b/internal/ota/ota.go
@@ -152,12 +152,12 @@ func (s *State) doUpdate(ctx context.Context, params UpdateParams) error {
return nil
}
- if shouldUpdateApp && (appUpdate.available || appUpdate.downgradeAvailable) {
+ if shouldUpdateApp && appUpdate.available {
appUpdate.pending = true
s.triggerComponentUpdateState("app", appUpdate)
}
- if shouldUpdateSystem && (systemUpdate.available || systemUpdate.downgradeAvailable) {
+ if shouldUpdateSystem && systemUpdate.available {
systemUpdate.pending = true
s.triggerComponentUpdateState("system", systemUpdate)
}
@@ -292,7 +292,6 @@ func (s *State) checkUpdateStatus(
return err
}
systemUpdateStatus.available = systemVersionRemote.GreaterThan(systemVersionLocal)
- systemUpdateStatus.downgradeAvailable = systemVersionRemote.LessThan(systemVersionLocal)
appVersionRemote, err := semver.NewVersion(remoteMetadata.AppVersion)
if err != nil {
@@ -300,7 +299,6 @@ func (s *State) checkUpdateStatus(
return err
}
appUpdateStatus.available = appVersionRemote.GreaterThan(appVersionLocal)
- appUpdateStatus.downgradeAvailable = appVersionRemote.LessThan(appVersionLocal)
// Handle pre-release updates
isRemoteSystemPreRelease := systemVersionRemote.Prerelease() != ""
@@ -313,6 +311,15 @@ func (s *State) checkUpdateStatus(
appUpdateStatus.available = false
}
+ // Handle custom target versions
+ if slices.Contains(params.Components, "app") && params.AppTargetVersion != "" {
+ appUpdateStatus.available = appVersionRemote.String() != appUpdateStatus.localVersion
+ }
+
+ if slices.Contains(params.Components, "system") && params.SystemTargetVersion != "" {
+ systemUpdateStatus.available = systemVersionRemote.String() != systemUpdateStatus.localVersion
+ }
+
return nil
}
diff --git a/internal/ota/state.go b/internal/ota/state.go
index f6a35e40..d8aa4399 100644
--- a/internal/ota/state.go
+++ b/internal/ota/state.go
@@ -28,12 +28,10 @@ type LocalMetadata struct {
// UpdateStatus represents the current update status
type UpdateStatus struct {
- Local *LocalMetadata `json:"local"`
- Remote *UpdateMetadata `json:"remote"`
- SystemUpdateAvailable bool `json:"systemUpdateAvailable"`
- SystemDowngradeAvailable bool `json:"systemDowngradeAvailable"`
- AppUpdateAvailable bool `json:"appUpdateAvailable"`
- AppDowngradeAvailable bool `json:"appDowngradeAvailable"`
+ Local *LocalMetadata `json:"local"`
+ Remote *UpdateMetadata `json:"remote"`
+ SystemUpdateAvailable bool `json:"systemUpdateAvailable"`
+ AppUpdateAvailable bool `json:"appUpdateAvailable"`
// for backwards compatibility
Error string `json:"error,omitempty"`
@@ -50,7 +48,6 @@ type PostRebootAction struct {
type componentUpdateStatus struct {
pending bool
available bool
- downgradeAvailable bool
version string
localVersion string
targetVersion string
@@ -170,11 +167,9 @@ func toUpdateStatus(appUpdate *componentUpdateStatus, systemUpdate *componentUpd
SystemURL: systemUpdate.url,
SystemHash: systemUpdate.hash,
},
- SystemUpdateAvailable: systemUpdate.available,
- SystemDowngradeAvailable: systemUpdate.downgradeAvailable,
- AppUpdateAvailable: appUpdate.available,
- AppDowngradeAvailable: appUpdate.downgradeAvailable,
- Error: error,
+ SystemUpdateAvailable: systemUpdate.available,
+ AppUpdateAvailable: appUpdate.available,
+ Error: error,
}
}
diff --git a/jsonrpc.go b/jsonrpc.go
index 2810e4f9..5b6d0457 100644
--- a/jsonrpc.go
+++ b/jsonrpc.go
@@ -1155,7 +1155,6 @@ var rpcHandlers = map[string]RPCHandler{
"getUpdateStatusChannel": {Func: rpcGetUpdateStatusChannel},
"tryUpdate": {Func: rpcTryUpdate},
"tryUpdateComponents": {Func: rpcTryUpdateComponents, Params: []string{"params", "includePreRelease", "resetConfig"}},
- "cancelDowngrade": {Func: rpcCancelDowngrade},
"getDevModeState": {Func: rpcGetDevModeState},
"setDevModeState": {Func: rpcSetDevModeState, Params: []string{"enabled"}},
"getSSHKeyState": {Func: rpcGetSSHKeyState},
diff --git a/ota.go b/ota.go
index 1ebd54e3..44fe0cd3 100644
--- a/ota.go
+++ b/ota.go
@@ -194,13 +194,3 @@ func rpcTryUpdateComponents(params updateParams, includePreRelease bool, resetCo
}()
return nil
}
-
-func rpcCancelDowngrade() error {
- if err := otaState.SetTargetVersion("app", ""); err != nil {
- return fmt.Errorf("failed to set app target version: %w", err)
- }
- if err := otaState.SetTargetVersion("system", ""); err != nil {
- return fmt.Errorf("failed to set system target version: %w", err)
- }
- return nil
-}
diff --git a/ui/src/hooks/stores.ts b/ui/src/hooks/stores.ts
index 9f7fd226..c56cb5f8 100644
--- a/ui/src/hooks/stores.ts
+++ b/ui/src/hooks/stores.ts
@@ -554,7 +554,6 @@ export type UpdateModalViews =
| "updating"
| "upToDate"
| "updateAvailable"
- | "updateDowngradeAvailable"
| "updateCompleted"
| "error";
diff --git a/ui/src/hooks/useVersion.tsx b/ui/src/hooks/useVersion.tsx
index 48af1f46..feb99617 100644
--- a/ui/src/hooks/useVersion.tsx
+++ b/ui/src/hooks/useVersion.tsx
@@ -15,9 +15,7 @@ export interface SystemVersionInfo {
local: VersionInfo;
remote?: VersionInfo;
systemUpdateAvailable: boolean;
- systemDowngradeAvailable: boolean;
appUpdateAvailable: boolean;
- appDowngradeAvailable: boolean;
error?: string;
}
diff --git a/ui/src/routes/devices.$id.settings.advanced.tsx b/ui/src/routes/devices.$id.settings.advanced.tsx
index 2d251598..260db3ca 100644
--- a/ui/src/routes/devices.$id.settings.advanced.tsx
+++ b/ui/src/routes/devices.$id.settings.advanced.tsx
@@ -185,10 +185,10 @@ export default function SettingsAdvancedRoute() {
setShowLoopbackWarning(false);
}, [applyLoopbackOnlyMode, setShowLoopbackWarning]);
- const handleVersionUpdateError = useCallback((error?: JsonRpcError) => {
+ const handleVersionUpdateError = useCallback((error?: JsonRpcError | string) => {
notifications.error(
m.advanced_error_version_update({
- error: error?.data ?? error?.message ?? m.unknown_error()
+ error: typeof error === "string" ? error : (error?.data ?? error?.message ?? m.unknown_error())
}),
{ duration: 1000 * 15 } // 15 seconds
);
@@ -214,15 +214,31 @@ export default function SettingsAdvancedRoute() {
return;
}
+ console.debug("versionInfo", versionInfo, components.includes("app") && versionInfo.remote?.appVersion && versionInfo?.appUpdateAvailable, components.includes("system") && versionInfo.remote?.systemVersion && versionInfo?.systemUpdateAvailable);
+ console.debug("components", components);
+ console.debug("versionInfo.remote?.appVersion", versionInfo.remote?.appVersion);
+ console.debug("versionInfo.appUpdateAvailable", versionInfo?.appUpdateAvailable);
+ console.debug("versionInfo.remote?.systemVersion", versionInfo.remote?.systemVersion);
+ console.debug("versionInfo.systemUpdateAvailable", versionInfo?.systemUpdateAvailable);
+
+ let hasUpdate = false;
+
const pageParams = new URLSearchParams();
- if (components.includes("app") && versionInfo.remote?.appVersion && versionInfo.appDowngradeAvailable) {
+ if (components.includes("app") && versionInfo.remote?.appVersion && versionInfo.appUpdateAvailable) {
+ hasUpdate = true;
pageParams.set("custom_app_version", versionInfo.remote?.appVersion);
}
- if (components.includes("system") && versionInfo.remote?.systemVersion && versionInfo.systemDowngradeAvailable) {
+ if (components.includes("system") && versionInfo.remote?.systemVersion && versionInfo.systemUpdateAvailable) {
+ hasUpdate = true;
pageParams.set("custom_system_version", versionInfo.remote?.systemVersion);
}
pageParams.set("reset_config", resetConfig.toString());
+ if (!hasUpdate) {
+ handleVersionUpdateError("No update available");
+ return;
+ }
+
// Navigate to update page
navigateTo(`/settings/general/update?${pageParams.toString()}`);
}, [
diff --git a/ui/src/routes/devices.$id.settings.general.update.tsx b/ui/src/routes/devices.$id.settings.general.update.tsx
index ea2dde49..31aac2a0 100644
--- a/ui/src/routes/devices.$id.settings.general.update.tsx
+++ b/ui/src/routes/devices.$id.settings.general.update.tsx
@@ -443,7 +443,6 @@ function SystemUpToDateState({
function UpdateAvailableState({
versionInfo,
- forceCustomUpdate,
onConfirm,
onClose,
}: {
@@ -462,13 +461,13 @@ function UpdateAvailableState({
{m.general_update_available_description()}
- {(forceCustomUpdate ? versionInfo?.systemDowngradeAvailable : versionInfo?.systemUpdateAvailable) ? (
+ {versionInfo?.systemUpdateAvailable ? (
<>
{m.general_update_system_type()}: {versionInfo?.local?.systemVersion} → {versionInfo?.remote?.systemVersion}
>
) : null}
- {(forceCustomUpdate ? versionInfo?.appDowngradeAvailable : versionInfo?.appUpdateAvailable) ? (
+ {versionInfo?.appUpdateAvailable ? (
<>
{m.general_update_application_type()}: {versionInfo?.local?.appVersion} → {versionInfo?.remote?.appVersion}
>
diff --git a/ui/src/utils/jsonrpc.ts b/ui/src/utils/jsonrpc.ts
index b219a30e..51d12127 100644
--- a/ui/src/utils/jsonrpc.ts
+++ b/ui/src/utils/jsonrpc.ts
@@ -220,9 +220,7 @@ export interface SystemVersionInfo {
local: VersionInfo;
remote?: VersionInfo;
systemUpdateAvailable: boolean;
- systemDowngradeAvailable: boolean;
appUpdateAvailable: boolean;
- appDowngradeAvailable: boolean;
error?: string;
}