Skip to content

Commit 02cf605

Browse files
committed
fix: update components
1 parent 9e8ada3 commit 02cf605

File tree

7 files changed

+85
-36
lines changed

7 files changed

+85
-36
lines changed

internal/ota/logger.go

Lines changed: 0 additions & 5 deletions
This file was deleted.

internal/ota/ota.go

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"net/http"
88
"net/url"
9+
"slices"
910
"time"
1011

1112
"github.com/Masterminds/semver/v3"
@@ -59,6 +60,10 @@ func (s *State) fetchUpdateMetadata(ctx context.Context, params UpdateParams) (*
5960
return nil, fmt.Errorf("error getting update URL: %w", err)
6061
}
6162

63+
s.l.Trace().
64+
Str("url", url).
65+
Msg("fetching update metadata")
66+
6267
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
6368
if err != nil {
6469
return nil, fmt.Errorf("error creating request: %w", err)
@@ -107,6 +112,16 @@ func (s *State) doUpdate(ctx context.Context, params UpdateParams) error {
107112
return fmt.Errorf("update already in progress")
108113
}
109114

115+
if len(params.Components) == 0 {
116+
params.Components = []string{"app", "system"}
117+
}
118+
shouldUpdateApp := slices.Contains(params.Components, "app")
119+
shouldUpdateSystem := slices.Contains(params.Components, "system")
120+
121+
if !shouldUpdateApp && !shouldUpdateSystem {
122+
return fmt.Errorf("no components to update")
123+
}
124+
110125
if !params.CheckOnly {
111126
s.updating = true
112127
s.triggerStateUpdate()
@@ -128,12 +143,12 @@ func (s *State) doUpdate(ctx context.Context, params UpdateParams) error {
128143
return nil
129144
}
130145

131-
if appUpdate.available || appUpdate.downgradeAvailable {
146+
if shouldUpdateApp && (appUpdate.available || appUpdate.downgradeAvailable) {
132147
appUpdate.pending = true
133148
s.triggerComponentUpdateState("app", appUpdate)
134149
}
135150

136-
if systemUpdate.available || systemUpdate.downgradeAvailable {
151+
if shouldUpdateSystem && (systemUpdate.available || systemUpdate.downgradeAvailable) {
137152
systemUpdate.pending = true
138153
s.triggerComponentUpdateState("system", systemUpdate)
139154
}
@@ -177,11 +192,12 @@ func (s *State) doUpdate(ctx context.Context, params UpdateParams) error {
177192

178193
// UpdateParams represents the parameters for the update
179194
type UpdateParams struct {
180-
DeviceID string `json:"deviceID"`
181-
AppTargetVersion string `json:"appTargetVersion"`
182-
SystemTargetVersion string `json:"systemTargetVersion"`
183-
IncludePreRelease bool `json:"includePreRelease"`
184-
CheckOnly bool `json:"checkOnly"`
195+
DeviceID string `json:"deviceID"`
196+
AppTargetVersion string `json:"appTargetVersion"`
197+
SystemTargetVersion string `json:"systemTargetVersion"`
198+
Components []string `json:"components,omitempty"`
199+
IncludePreRelease bool `json:"includePreRelease"`
200+
CheckOnly bool `json:"checkOnly"`
185201
}
186202

187203
func (s *State) getUpdateStatus(

internal/ota/state.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ type componentUpdateStatus struct {
6262
verifiedAt time.Time
6363
updateProgress float32
6464
updatedAt time.Time
65-
dependsOn []string
65+
dependsOn []string //nolint:unused
6666
}
6767

6868
// RPCState represents the current OTA state for the RPC API

ota.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ func rpcGetLocalVersion() (*ota.LocalMetadata, error) {
137137
type tryUpdateComponents struct {
138138
AppTargetVersion string `json:"app"`
139139
SystemTargetVersion string `json:"system"`
140+
Components string `json:"components,omitempty"` // components is a comma-separated list of components to update
140141
}
141142

142143
func rpcTryUpdate() error {
@@ -155,17 +156,18 @@ func rpcTryUpdateComponents(components tryUpdateComponents, includePreRelease bo
155156

156157
logger.Info().Interface("components", components).Msg("components")
157158

158-
if components.AppTargetVersion != "" {
159-
updateParams.AppTargetVersion = components.AppTargetVersion
160-
if err := otaState.SetTargetVersion("app", components.AppTargetVersion); err != nil {
161-
return fmt.Errorf("failed to set app target version: %w", err)
162-
}
159+
updateParams.AppTargetVersion = components.AppTargetVersion
160+
if err := otaState.SetTargetVersion("app", components.AppTargetVersion); err != nil {
161+
return fmt.Errorf("failed to set app target version: %w", err)
163162
}
164-
if components.SystemTargetVersion != "" {
165-
updateParams.SystemTargetVersion = components.SystemTargetVersion
166-
if err := otaState.SetTargetVersion("system", components.SystemTargetVersion); err != nil {
167-
return fmt.Errorf("failed to set system target version: %w", err)
168-
}
163+
164+
updateParams.SystemTargetVersion = components.SystemTargetVersion
165+
if err := otaState.SetTargetVersion("system", components.SystemTargetVersion); err != nil {
166+
return fmt.Errorf("failed to set system target version: %w", err)
167+
}
168+
169+
if components.Components != "" {
170+
updateParams.Components = strings.Split(components.Components, ",")
169171
}
170172

171173
go func() {

ui/src/hooks/useVersion.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { useCallback, useMemo } from "react";
2+
import semver from "semver";
23

34
import { useDeviceStore } from "@/hooks/stores";
45
import { type JsonRpcResponse, RpcMethodNotFound, useJsonRpc } from "@/hooks/useJsonRpc";
56
import notifications from "@/notifications";
67
import { m } from "@localizations/messages.js";
7-
import semver from "semver";
88

99
export interface VersionInfo {
1010
appVersion: string;

ui/src/routes/devices.$id.settings.advanced.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,14 @@ export default function SettingsAdvancedRoute() {
196196
);
197197
return;
198198
}
199+
const pageParams = new URLSearchParams();
200+
pageParams.set("downgrade", "true");
201+
pageParams.set("components", updateTarget == "both" ? "app,system" : updateTarget);
202+
199203
// Navigate to update page
200-
navigateTo("/settings/general/update");
204+
navigateTo(`/settings/general/update?${pageParams.toString()}`);
201205
});
202-
}, [appVersion, systemVersion, devChannel, send, navigateTo]);
206+
}, [updateTarget,appVersion, systemVersion, devChannel, send, navigateTo]);
203207

204208
return (
205209
<div className="space-y-4">

ui/src/routes/devices.$id.settings.general.update.tsx

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2-
import { useLocation, useNavigate } from "react-router";
2+
import { useLocation, useNavigate, useSearchParams } from "react-router";
33

44
import { useJsonRpc } from "@hooks/useJsonRpc";
55
import { UpdateState, useUpdateStore } from "@hooks/stores";
@@ -14,16 +14,33 @@ import { m } from "@localizations/messages.js";
1414
export default function SettingsGeneralUpdateRoute() {
1515
const navigate = useNavigate();
1616
const location = useLocation();
17+
//@ts-ignore
18+
const [searchParams, setSearchParams] = useSearchParams();
1719
const { updateSuccess } = location.state || {};
1820

1921
const { setModalView, otaState } = useUpdateStore();
2022
const { send } = useJsonRpc();
2123

24+
const downgrade = useMemo(() => searchParams.get("downgrade") === "true", [searchParams]);
25+
const updateComponents = useMemo(() => searchParams.get("components") || "", [searchParams]);
26+
2227
const onConfirmUpdate = useCallback(() => {
2328
send("tryUpdate", {});
2429
setModalView("updating");
2530
}, [send, setModalView]);
2631

32+
const onConfirmDowngrade = useCallback((system?: string, app?: string) => {
33+
send("tryUpdateComponents", {
34+
components: {
35+
system, app,
36+
components: updateComponents
37+
},
38+
includePreRelease: true,
39+
checkOnly: false,
40+
});
41+
setModalView("updating");
42+
}, [send, setModalView, updateComponents]);
43+
2744
useEffect(() => {
2845
if (otaState.updating) {
2946
setModalView("updating");
@@ -36,15 +53,24 @@ export default function SettingsGeneralUpdateRoute() {
3653
}
3754
}, [otaState.updating, otaState.error, setModalView, updateSuccess]);
3855

39-
return <Dialog onClose={() => navigate("..")} onConfirmUpdate={onConfirmUpdate} />;
56+
return <Dialog
57+
onClose={() => navigate("..")}
58+
onConfirmUpdate={onConfirmUpdate}
59+
onConfirmDowngrade={onConfirmDowngrade}
60+
downgrade={downgrade}
61+
/>;
4062
}
4163

4264
export function Dialog({
4365
onClose,
4466
onConfirmUpdate,
67+
onConfirmDowngrade,
68+
downgrade,
4569
}: Readonly<{
70+
downgrade: boolean;
4671
onClose: () => void;
4772
onConfirmUpdate: () => void;
73+
onConfirmDowngrade: () => void;
4874
}>) {
4975
const { navigateTo } = useDeviceUiNavigation();
5076

@@ -61,15 +87,15 @@ export function Dialog({
6187

6288
setVersionInfo(versionInfo);
6389

64-
if (hasUpdate) {
65-
setModalView("updateAvailable");
66-
} else if (hasDowngrade) {
90+
if (hasDowngrade && downgrade) {
6791
setModalView("updateDowngradeAvailable");
92+
} else if (hasUpdate) {
93+
setModalView("updateAvailable");
6894
} else {
6995
setModalView("upToDate");
7096
}
7197
},
72-
[setModalView],
98+
[setModalView, downgrade],
7399
);
74100

75101
const onCancelDowngrade = useCallback(() => {
@@ -101,7 +127,7 @@ export function Dialog({
101127
)}
102128
{modalView === "updateDowngradeAvailable" && (
103129
<UpdateDowngradeAvailableState
104-
onConfirmUpdate={onConfirmUpdate}
130+
onConfirmDowngrade={onConfirmDowngrade}
105131
onCancelDowngrade={onCancelDowngrade}
106132
versionInfo={versionInfo!}
107133
/>
@@ -419,13 +445,19 @@ function UpdateAvailableState({
419445

420446
function UpdateDowngradeAvailableState({
421447
versionInfo,
422-
onConfirmUpdate,
448+
onConfirmDowngrade,
423449
onCancelDowngrade,
424450
}: {
425451
versionInfo: SystemVersionInfo;
426-
onConfirmUpdate: () => void;
452+
onConfirmDowngrade: (system?: string, app?: string) => void;
427453
onCancelDowngrade: () => void;
428454
}) {
455+
const confirmDowngrade = useCallback(() => {
456+
onConfirmDowngrade(
457+
versionInfo?.remote?.systemVersion || undefined,
458+
versionInfo?.remote?.appVersion || undefined,
459+
);
460+
}, [versionInfo, onConfirmDowngrade]);
429461
return (
430462
<div className="flex flex-col items-start justify-start space-y-4 text-left">
431463
<div className="text-left">
@@ -449,7 +481,7 @@ function UpdateDowngradeAvailableState({
449481
) : null}
450482
</p>
451483
<div className="flex items-center justify-start gap-x-2">
452-
<Button size="SM" theme="primary" text={m.general_update_downgrade_button()} onClick={onConfirmUpdate} />
484+
<Button size="SM" theme="primary" text={m.general_update_downgrade_button()} onClick={confirmDowngrade} />
453485
<Button size="SM" theme="light" text={m.general_update_keep_current_button()} onClick={onCancelDowngrade} />
454486
</div>
455487
</div>

0 commit comments

Comments
 (0)