mirror of https://github.com/jetkvm/kvm.git
Compare commits
6 Commits
1bca0c5e26
...
9832be29ef
| Author | SHA1 | Date |
|---|---|---|
|
|
9832be29ef | |
|
|
8bd3d4cfcf | |
|
|
a246ef1213 | |
|
|
9372afed6b | |
|
|
ba76d5bbc9 | |
|
|
882eb703c5 |
|
|
@ -152,12 +152,12 @@ func (s *State) doUpdate(ctx context.Context, params UpdateParams) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if shouldUpdateApp && (appUpdate.available || appUpdate.downgradeAvailable) {
|
if shouldUpdateApp && appUpdate.available {
|
||||||
appUpdate.pending = true
|
appUpdate.pending = true
|
||||||
s.triggerComponentUpdateState("app", appUpdate)
|
s.triggerComponentUpdateState("app", appUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
if shouldUpdateSystem && (systemUpdate.available || systemUpdate.downgradeAvailable) {
|
if shouldUpdateSystem && systemUpdate.available {
|
||||||
systemUpdate.pending = true
|
systemUpdate.pending = true
|
||||||
s.triggerComponentUpdateState("system", systemUpdate)
|
s.triggerComponentUpdateState("system", systemUpdate)
|
||||||
}
|
}
|
||||||
|
|
@ -220,6 +220,8 @@ type UpdateParams struct {
|
||||||
ResetConfig bool `json:"resetConfig"`
|
ResetConfig bool `json:"resetConfig"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getUpdateStatus gets the update status for the given components
|
||||||
|
// and updates the componentUpdateStatuses map
|
||||||
func (s *State) getUpdateStatus(
|
func (s *State) getUpdateStatus(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
params UpdateParams,
|
params UpdateParams,
|
||||||
|
|
@ -239,7 +241,7 @@ func (s *State) getUpdateStatus(
|
||||||
systemUpdate = ¤tSystemUpdate
|
systemUpdate = ¤tSystemUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.doGetUpdateStatus(ctx, params, appUpdate, systemUpdate)
|
err = s.checkUpdateStatus(ctx, params, appUpdate, systemUpdate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -250,21 +252,20 @@ func (s *State) getUpdateStatus(
|
||||||
return appUpdate, systemUpdate, nil
|
return appUpdate, systemUpdate, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// doGetUpdateStatus is the internal function that gets the update status
|
// checkUpdateStatus checks the update status for the given components
|
||||||
// it WON'T change the state of the OTA state
|
func (s *State) checkUpdateStatus(
|
||||||
func (s *State) doGetUpdateStatus(
|
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
params UpdateParams,
|
params UpdateParams,
|
||||||
appUpdate *componentUpdateStatus,
|
appUpdateStatus *componentUpdateStatus,
|
||||||
systemUpdate *componentUpdateStatus,
|
systemUpdateStatus *componentUpdateStatus,
|
||||||
) error {
|
) error {
|
||||||
// Get local versions
|
// Get local versions
|
||||||
systemVersionLocal, appVersionLocal, err := s.getLocalVersion()
|
systemVersionLocal, appVersionLocal, err := s.getLocalVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error getting local version: %w", err)
|
return fmt.Errorf("error getting local version: %w", err)
|
||||||
}
|
}
|
||||||
appUpdate.localVersion = appVersionLocal.String()
|
appUpdateStatus.localVersion = appVersionLocal.String()
|
||||||
systemUpdate.localVersion = systemVersionLocal.String()
|
systemUpdateStatus.localVersion = systemVersionLocal.String()
|
||||||
|
|
||||||
// Get remote metadata
|
// Get remote metadata
|
||||||
remoteMetadata, err := s.fetchUpdateMetadata(ctx, params)
|
remoteMetadata, err := s.fetchUpdateMetadata(ctx, params)
|
||||||
|
|
@ -276,13 +277,13 @@ func (s *State) doGetUpdateStatus(
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
appUpdate.url = remoteMetadata.AppURL
|
appUpdateStatus.url = remoteMetadata.AppURL
|
||||||
appUpdate.hash = remoteMetadata.AppHash
|
appUpdateStatus.hash = remoteMetadata.AppHash
|
||||||
appUpdate.version = remoteMetadata.AppVersion
|
appUpdateStatus.version = remoteMetadata.AppVersion
|
||||||
|
|
||||||
systemUpdate.url = remoteMetadata.SystemURL
|
systemUpdateStatus.url = remoteMetadata.SystemURL
|
||||||
systemUpdate.hash = remoteMetadata.SystemHash
|
systemUpdateStatus.hash = remoteMetadata.SystemHash
|
||||||
systemUpdate.version = remoteMetadata.SystemVersion
|
systemUpdateStatus.version = remoteMetadata.SystemVersion
|
||||||
|
|
||||||
// Get remote versions
|
// Get remote versions
|
||||||
systemVersionRemote, err := semver.NewVersion(remoteMetadata.SystemVersion)
|
systemVersionRemote, err := semver.NewVersion(remoteMetadata.SystemVersion)
|
||||||
|
|
@ -290,26 +291,33 @@ func (s *State) doGetUpdateStatus(
|
||||||
err = fmt.Errorf("error parsing remote system version: %w", err)
|
err = fmt.Errorf("error parsing remote system version: %w", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
systemUpdate.available = systemVersionRemote.GreaterThan(systemVersionLocal)
|
systemUpdateStatus.available = systemVersionRemote.GreaterThan(systemVersionLocal)
|
||||||
systemUpdate.downgradeAvailable = systemVersionRemote.LessThan(systemVersionLocal)
|
|
||||||
|
|
||||||
appVersionRemote, err := semver.NewVersion(remoteMetadata.AppVersion)
|
appVersionRemote, err := semver.NewVersion(remoteMetadata.AppVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("error parsing remote app version: %w, %s", err, remoteMetadata.AppVersion)
|
err = fmt.Errorf("error parsing remote app version: %w, %s", err, remoteMetadata.AppVersion)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
appUpdate.available = appVersionRemote.GreaterThan(appVersionLocal)
|
appUpdateStatus.available = appVersionRemote.GreaterThan(appVersionLocal)
|
||||||
appUpdate.downgradeAvailable = appVersionRemote.LessThan(appVersionLocal)
|
|
||||||
|
|
||||||
// Handle pre-release updates
|
// Handle pre-release updates
|
||||||
isRemoteSystemPreRelease := systemVersionRemote.Prerelease() != ""
|
isRemoteSystemPreRelease := systemVersionRemote.Prerelease() != ""
|
||||||
isRemoteAppPreRelease := appVersionRemote.Prerelease() != ""
|
isRemoteAppPreRelease := appVersionRemote.Prerelease() != ""
|
||||||
|
|
||||||
if isRemoteSystemPreRelease && !params.IncludePreRelease {
|
if isRemoteSystemPreRelease && !params.IncludePreRelease {
|
||||||
systemUpdate.available = false
|
systemUpdateStatus.available = false
|
||||||
}
|
}
|
||||||
if isRemoteAppPreRelease && !params.IncludePreRelease {
|
if isRemoteAppPreRelease && !params.IncludePreRelease {
|
||||||
appUpdate.available = false
|
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
|
return nil
|
||||||
|
|
@ -317,12 +325,12 @@ func (s *State) doGetUpdateStatus(
|
||||||
|
|
||||||
// GetUpdateStatus returns the current update status (for backwards compatibility)
|
// GetUpdateStatus returns the current update status (for backwards compatibility)
|
||||||
func (s *State) GetUpdateStatus(ctx context.Context, params UpdateParams) (*UpdateStatus, error) {
|
func (s *State) GetUpdateStatus(ctx context.Context, params UpdateParams) (*UpdateStatus, error) {
|
||||||
appUpdate := &componentUpdateStatus{}
|
appUpdateStatus := componentUpdateStatus{}
|
||||||
systemUpdate := &componentUpdateStatus{}
|
systemUpdateStatus := componentUpdateStatus{}
|
||||||
err := s.doGetUpdateStatus(ctx, params, appUpdate, systemUpdate)
|
err := s.checkUpdateStatus(ctx, params, &appUpdateStatus, &systemUpdateStatus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error getting update status: %w", err)
|
return nil, fmt.Errorf("error getting update status: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return toUpdateStatus(appUpdate, systemUpdate, ""), nil
|
return toUpdateStatus(&appUpdateStatus, &systemUpdateStatus, ""), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,10 @@ type LocalMetadata struct {
|
||||||
|
|
||||||
// UpdateStatus represents the current update status
|
// UpdateStatus represents the current update status
|
||||||
type UpdateStatus struct {
|
type UpdateStatus struct {
|
||||||
Local *LocalMetadata `json:"local"`
|
Local *LocalMetadata `json:"local"`
|
||||||
Remote *UpdateMetadata `json:"remote"`
|
Remote *UpdateMetadata `json:"remote"`
|
||||||
SystemUpdateAvailable bool `json:"systemUpdateAvailable"`
|
SystemUpdateAvailable bool `json:"systemUpdateAvailable"`
|
||||||
SystemDowngradeAvailable bool `json:"systemDowngradeAvailable"`
|
AppUpdateAvailable bool `json:"appUpdateAvailable"`
|
||||||
AppUpdateAvailable bool `json:"appUpdateAvailable"`
|
|
||||||
AppDowngradeAvailable bool `json:"appDowngradeAvailable"`
|
|
||||||
|
|
||||||
// for backwards compatibility
|
// for backwards compatibility
|
||||||
Error string `json:"error,omitempty"`
|
Error string `json:"error,omitempty"`
|
||||||
|
|
@ -50,7 +48,6 @@ type PostRebootAction struct {
|
||||||
type componentUpdateStatus struct {
|
type componentUpdateStatus struct {
|
||||||
pending bool
|
pending bool
|
||||||
available bool
|
available bool
|
||||||
downgradeAvailable bool
|
|
||||||
version string
|
version string
|
||||||
localVersion string
|
localVersion string
|
||||||
targetVersion string
|
targetVersion string
|
||||||
|
|
@ -170,11 +167,9 @@ func toUpdateStatus(appUpdate *componentUpdateStatus, systemUpdate *componentUpd
|
||||||
SystemURL: systemUpdate.url,
|
SystemURL: systemUpdate.url,
|
||||||
SystemHash: systemUpdate.hash,
|
SystemHash: systemUpdate.hash,
|
||||||
},
|
},
|
||||||
SystemUpdateAvailable: systemUpdate.available,
|
SystemUpdateAvailable: systemUpdate.available,
|
||||||
SystemDowngradeAvailable: systemUpdate.downgradeAvailable,
|
AppUpdateAvailable: appUpdate.available,
|
||||||
AppUpdateAvailable: appUpdate.available,
|
Error: error,
|
||||||
AppDowngradeAvailable: appUpdate.downgradeAvailable,
|
|
||||||
Error: error,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1155,7 +1155,6 @@ var rpcHandlers = map[string]RPCHandler{
|
||||||
"getUpdateStatusChannel": {Func: rpcGetUpdateStatusChannel},
|
"getUpdateStatusChannel": {Func: rpcGetUpdateStatusChannel},
|
||||||
"tryUpdate": {Func: rpcTryUpdate},
|
"tryUpdate": {Func: rpcTryUpdate},
|
||||||
"tryUpdateComponents": {Func: rpcTryUpdateComponents, Params: []string{"params", "includePreRelease", "resetConfig"}},
|
"tryUpdateComponents": {Func: rpcTryUpdateComponents, Params: []string{"params", "includePreRelease", "resetConfig"}},
|
||||||
"cancelDowngrade": {Func: rpcCancelDowngrade},
|
|
||||||
"getDevModeState": {Func: rpcGetDevModeState},
|
"getDevModeState": {Func: rpcGetDevModeState},
|
||||||
"setDevModeState": {Func: rpcSetDevModeState, Params: []string{"enabled"}},
|
"setDevModeState": {Func: rpcSetDevModeState, Params: []string{"enabled"}},
|
||||||
"getSSHKeyState": {Func: rpcGetSSHKeyState},
|
"getSSHKeyState": {Func: rpcGetSSHKeyState},
|
||||||
|
|
|
||||||
14
ota.go
14
ota.go
|
|
@ -135,8 +135,8 @@ func rpcGetLocalVersion() (*ota.LocalMetadata, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type updateParams struct {
|
type updateParams struct {
|
||||||
AppTargetVersion string `json:"app"`
|
AppTargetVersion string `json:"appTargetVersion"`
|
||||||
SystemTargetVersion string `json:"system"`
|
SystemTargetVersion string `json:"systemTargetVersion"`
|
||||||
Components string `json:"components,omitempty"` // components is a comma-separated list of components to update
|
Components string `json:"components,omitempty"` // components is a comma-separated list of components to update
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -194,13 +194,3 @@ func rpcTryUpdateComponents(params updateParams, includePreRelease bool, resetCo
|
||||||
}()
|
}()
|
||||||
return nil
|
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
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -554,7 +554,6 @@ export type UpdateModalViews =
|
||||||
| "updating"
|
| "updating"
|
||||||
| "upToDate"
|
| "upToDate"
|
||||||
| "updateAvailable"
|
| "updateAvailable"
|
||||||
| "updateDowngradeAvailable"
|
|
||||||
| "updateCompleted"
|
| "updateCompleted"
|
||||||
| "error";
|
| "error";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,7 @@ export interface SystemVersionInfo {
|
||||||
local: VersionInfo;
|
local: VersionInfo;
|
||||||
remote?: VersionInfo;
|
remote?: VersionInfo;
|
||||||
systemUpdateAvailable: boolean;
|
systemUpdateAvailable: boolean;
|
||||||
systemDowngradeAvailable: boolean;
|
|
||||||
appUpdateAvailable: boolean;
|
appUpdateAvailable: boolean;
|
||||||
appDowngradeAvailable: boolean;
|
|
||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -185,10 +185,10 @@ export default function SettingsAdvancedRoute() {
|
||||||
setShowLoopbackWarning(false);
|
setShowLoopbackWarning(false);
|
||||||
}, [applyLoopbackOnlyMode, setShowLoopbackWarning]);
|
}, [applyLoopbackOnlyMode, setShowLoopbackWarning]);
|
||||||
|
|
||||||
const handleVersionUpdateError = useCallback((error?: JsonRpcError) => {
|
const handleVersionUpdateError = useCallback((error?: JsonRpcError | string) => {
|
||||||
notifications.error(
|
notifications.error(
|
||||||
m.advanced_error_version_update({
|
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
|
{ duration: 1000 * 15 } // 15 seconds
|
||||||
);
|
);
|
||||||
|
|
@ -204,30 +204,40 @@ export default function SettingsAdvancedRoute() {
|
||||||
setVersionUpdateLoading(true);
|
setVersionUpdateLoading(true);
|
||||||
versionInfo = await checkUpdateComponents({
|
versionInfo = await checkUpdateComponents({
|
||||||
components: components.join(","),
|
components: components.join(","),
|
||||||
app: appVersion,
|
appTargetVersion: appVersion,
|
||||||
system: systemVersion,
|
systemTargetVersion: systemVersion,
|
||||||
}, devChannel);
|
}, devChannel);
|
||||||
console.log("versionInfo", versionInfo);
|
console.log("versionInfo", versionInfo);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const jsonRpcError = error as JsonRpcError;
|
const jsonRpcError = error as JsonRpcError;
|
||||||
handleVersionUpdateError(jsonRpcError);
|
handleVersionUpdateError(jsonRpcError);
|
||||||
return ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!versionInfo) {
|
|
||||||
handleVersionUpdateError();
|
|
||||||
return;
|
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();
|
const pageParams = new URLSearchParams();
|
||||||
pageParams.set("downgrade", "true");
|
if (components.includes("app") && versionInfo.remote?.appVersion && versionInfo.appUpdateAvailable) {
|
||||||
if (components.includes("app") && versionInfo.remote?.appVersion && versionInfo.appDowngradeAvailable) {
|
hasUpdate = true;
|
||||||
pageParams.set("app", versionInfo.remote?.appVersion);
|
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) {
|
||||||
pageParams.set("system", versionInfo.remote?.systemVersion);
|
hasUpdate = true;
|
||||||
|
pageParams.set("custom_system_version", versionInfo.remote?.systemVersion);
|
||||||
|
}
|
||||||
|
pageParams.set("reset_config", resetConfig.toString());
|
||||||
|
|
||||||
|
if (!hasUpdate) {
|
||||||
|
handleVersionUpdateError("No update available");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
pageParams.set("resetConfig", resetConfig.toString());
|
|
||||||
|
|
||||||
// Navigate to update page
|
// Navigate to update page
|
||||||
navigateTo(`/settings/general/update?${pageParams.toString()}`);
|
navigateTo(`/settings/general/update?${pageParams.toString()}`);
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import LoadingSpinner from "@components/LoadingSpinner";
|
||||||
import UpdatingStatusCard, { type UpdatePart } from "@components/UpdatingStatusCard";
|
import UpdatingStatusCard, { type UpdatePart } from "@components/UpdatingStatusCard";
|
||||||
import { m } from "@localizations/messages.js";
|
import { m } from "@localizations/messages.js";
|
||||||
import { sleep } from "@/utils";
|
import { sleep } from "@/utils";
|
||||||
import { SystemVersionInfo } from "@/utils/jsonrpc";
|
import { checkUpdateComponents, SystemVersionInfo, updateParams } from "@/utils/jsonrpc";
|
||||||
|
|
||||||
export default function SettingsGeneralUpdateRoute() {
|
export default function SettingsGeneralUpdateRoute() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
@ -22,10 +22,9 @@ export default function SettingsGeneralUpdateRoute() {
|
||||||
const { setModalView, otaState } = useUpdateStore();
|
const { setModalView, otaState } = useUpdateStore();
|
||||||
const { send } = useJsonRpc();
|
const { send } = useJsonRpc();
|
||||||
|
|
||||||
const downgrade = useMemo(() => searchParams.get("downgrade") === "true", [searchParams]);
|
const customAppVersion = useMemo(() => searchParams.get("custom_app_version") || undefined, [searchParams]);
|
||||||
const customAppVersion = useMemo(() => searchParams.get("app") || "", [searchParams]);
|
const customSystemVersion = useMemo(() => searchParams.get("custom_system_version") || undefined, [searchParams]);
|
||||||
const customSystemVersion = useMemo(() => searchParams.get("system") || "", [searchParams]);
|
const resetConfig = useMemo(() => searchParams.get("reset_config") === "true", [searchParams]);
|
||||||
const resetConfig = useMemo(() => searchParams.get("resetConfig") === "true", [searchParams]);
|
|
||||||
|
|
||||||
const onClose = useCallback(async () => {
|
const onClose = useCallback(async () => {
|
||||||
navigate(".."); // back to the devices.$id.settings page
|
navigate(".."); // back to the devices.$id.settings page
|
||||||
|
|
@ -39,20 +38,16 @@ export default function SettingsGeneralUpdateRoute() {
|
||||||
setModalView("updating");
|
setModalView("updating");
|
||||||
}, [send, setModalView]);
|
}, [send, setModalView]);
|
||||||
|
|
||||||
const onConfirmDowngrade = useCallback(() => {
|
const onConfirmCustomUpdate = useCallback((appTargetVersion?: string, systemTargetVersion?: string) => {
|
||||||
const components = [];
|
const components = [];
|
||||||
if (customSystemVersion) {
|
if (appTargetVersion) components.push("app");
|
||||||
components.push("system");
|
if (systemTargetVersion) components.push("system");
|
||||||
}
|
|
||||||
if (customAppVersion) {
|
|
||||||
components.push("app");
|
|
||||||
}
|
|
||||||
|
|
||||||
send("tryUpdateComponents", {
|
send("tryUpdateComponents", {
|
||||||
params: {
|
params: {
|
||||||
components: components.join(","),
|
components: components.join(","),
|
||||||
app: customAppVersion,
|
appTargetVersion,
|
||||||
system: customSystemVersion,
|
systemTargetVersion,
|
||||||
},
|
},
|
||||||
includePreRelease: false,
|
includePreRelease: false,
|
||||||
resetConfig,
|
resetConfig,
|
||||||
|
|
@ -60,7 +55,7 @@ export default function SettingsGeneralUpdateRoute() {
|
||||||
if ("error" in resp) return;
|
if ("error" in resp) return;
|
||||||
setModalView("updating");
|
setModalView("updating");
|
||||||
});
|
});
|
||||||
}, [send, setModalView, customAppVersion, customSystemVersion, resetConfig]);
|
}, [send, setModalView, resetConfig]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (otaState.updating) {
|
if (otaState.updating) {
|
||||||
|
|
@ -77,8 +72,7 @@ export default function SettingsGeneralUpdateRoute() {
|
||||||
return <Dialog
|
return <Dialog
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
onConfirmUpdate={onConfirmUpdate}
|
onConfirmUpdate={onConfirmUpdate}
|
||||||
onConfirmDowngrade={onConfirmDowngrade}
|
onConfirmCustomUpdate={onConfirmCustomUpdate}
|
||||||
downgrade={downgrade}
|
|
||||||
customAppVersion={customAppVersion}
|
customAppVersion={customAppVersion}
|
||||||
customSystemVersion={customSystemVersion}
|
customSystemVersion={customSystemVersion}
|
||||||
/>;
|
/>;
|
||||||
|
|
@ -87,15 +81,13 @@ export default function SettingsGeneralUpdateRoute() {
|
||||||
export function Dialog({
|
export function Dialog({
|
||||||
onClose,
|
onClose,
|
||||||
onConfirmUpdate,
|
onConfirmUpdate,
|
||||||
onConfirmDowngrade,
|
onConfirmCustomUpdate: onConfirmCustomUpdateCallback,
|
||||||
downgrade,
|
|
||||||
customAppVersion,
|
customAppVersion,
|
||||||
customSystemVersion,
|
customSystemVersion,
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
downgrade: boolean;
|
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onConfirmUpdate: () => void;
|
onConfirmUpdate: () => void;
|
||||||
onConfirmDowngrade: () => void;
|
onConfirmCustomUpdate: (appVersion?: string, systemVersion?: string) => void;
|
||||||
customAppVersion?: string;
|
customAppVersion?: string;
|
||||||
customSystemVersion?: string;
|
customSystemVersion?: string;
|
||||||
}>) {
|
}>) {
|
||||||
|
|
@ -103,32 +95,31 @@ export function Dialog({
|
||||||
|
|
||||||
const [versionInfo, setVersionInfo] = useState<null | SystemVersionInfo>(null);
|
const [versionInfo, setVersionInfo] = useState<null | SystemVersionInfo>(null);
|
||||||
const { modalView, setModalView, otaState } = useUpdateStore();
|
const { modalView, setModalView, otaState } = useUpdateStore();
|
||||||
const { send } = useJsonRpc();
|
const forceCustomUpdate = customSystemVersion !== undefined || customAppVersion !== undefined;
|
||||||
|
const onConfirmCustomUpdate = useCallback(() => {
|
||||||
|
console.debug("onConfirmCustomUpdate", customAppVersion, customSystemVersion, versionInfo);
|
||||||
|
onConfirmCustomUpdateCallback(
|
||||||
|
customAppVersion !== undefined ? customAppVersion : versionInfo?.remote?.appVersion,
|
||||||
|
customSystemVersion !== undefined ? customSystemVersion : versionInfo?.remote?.systemVersion,
|
||||||
|
);
|
||||||
|
}, [onConfirmCustomUpdateCallback, customAppVersion, customSystemVersion, versionInfo]);
|
||||||
|
|
||||||
const onFinishedLoading = useCallback(
|
const onFinishedLoading = useCallback(
|
||||||
(versionInfo: SystemVersionInfo) => {
|
(versionInfo: SystemVersionInfo) => {
|
||||||
const hasUpdate =
|
const hasUpdate =
|
||||||
versionInfo?.systemUpdateAvailable || versionInfo?.appUpdateAvailable;
|
versionInfo?.systemUpdateAvailable || versionInfo?.appUpdateAvailable;
|
||||||
const hasDowngrade = customSystemVersion !== undefined || customAppVersion !== undefined;
|
|
||||||
|
|
||||||
setVersionInfo(versionInfo);
|
setVersionInfo(versionInfo);
|
||||||
|
|
||||||
if (hasDowngrade && downgrade) {
|
if (hasUpdate || forceCustomUpdate) {
|
||||||
setModalView("updateDowngradeAvailable");
|
|
||||||
} else if (hasUpdate) {
|
|
||||||
setModalView("updateAvailable");
|
setModalView("updateAvailable");
|
||||||
} else {
|
} else {
|
||||||
setModalView("upToDate");
|
setModalView("upToDate");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[setModalView, downgrade, customAppVersion, customSystemVersion],
|
[setModalView, forceCustomUpdate],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onCancelDowngrade = useCallback(() => {
|
|
||||||
send("cancelDowngrade", {});
|
|
||||||
onClose();
|
|
||||||
}, [onClose, send]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="pointer-events-auto relative mx-auto text-left">
|
<div className="pointer-events-auto relative mx-auto text-left">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -141,24 +132,22 @@ export function Dialog({
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{modalView === "loading" && (
|
{modalView === "loading" && (
|
||||||
<LoadingState onFinished={onFinishedLoading} onCancelCheck={onClose} />
|
<LoadingState
|
||||||
|
onFinished={onFinishedLoading}
|
||||||
|
onCancelCheck={onClose}
|
||||||
|
customAppVersion={customAppVersion}
|
||||||
|
customSystemVersion={customSystemVersion}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{modalView === "updateAvailable" && (
|
{modalView === "updateAvailable" && (
|
||||||
<UpdateAvailableState
|
<UpdateAvailableState
|
||||||
onConfirmUpdate={onConfirmUpdate}
|
forceCustomUpdate={forceCustomUpdate}
|
||||||
|
onConfirm={forceCustomUpdate ? onConfirmCustomUpdate : onConfirmUpdate}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
versionInfo={versionInfo!}
|
versionInfo={versionInfo!}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{modalView === "updateDowngradeAvailable" && (
|
|
||||||
<UpdateDowngradeAvailableState
|
|
||||||
appVersion={customAppVersion}
|
|
||||||
systemVersion={customSystemVersion}
|
|
||||||
onConfirmDowngrade={onConfirmDowngrade}
|
|
||||||
onCancelDowngrade={onCancelDowngrade}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{modalView === "updating" && (
|
{modalView === "updating" && (
|
||||||
<UpdatingDeviceState
|
<UpdatingDeviceState
|
||||||
|
|
@ -183,9 +172,13 @@ export function Dialog({
|
||||||
function LoadingState({
|
function LoadingState({
|
||||||
onFinished,
|
onFinished,
|
||||||
onCancelCheck,
|
onCancelCheck,
|
||||||
|
customAppVersion,
|
||||||
|
customSystemVersion,
|
||||||
}: {
|
}: {
|
||||||
onFinished: (versionInfo: SystemVersionInfo) => void;
|
onFinished: (versionInfo: SystemVersionInfo) => void;
|
||||||
onCancelCheck: () => void;
|
onCancelCheck: () => void;
|
||||||
|
customAppVersion?: string;
|
||||||
|
customSystemVersion?: string;
|
||||||
}) {
|
}) {
|
||||||
const [progressWidth, setProgressWidth] = useState("0%");
|
const [progressWidth, setProgressWidth] = useState("0%");
|
||||||
const abortControllerRef = useRef<AbortController | null>(null);
|
const abortControllerRef = useRef<AbortController | null>(null);
|
||||||
|
|
@ -194,6 +187,23 @@ function LoadingState({
|
||||||
const { setModalView } = useUpdateStore();
|
const { setModalView } = useUpdateStore();
|
||||||
|
|
||||||
const progressBarRef = useRef<HTMLDivElement>(null);
|
const progressBarRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const checkUpdate = useCallback(async () => {
|
||||||
|
if (!customAppVersion && !customSystemVersion) {
|
||||||
|
return await getVersionInfo();
|
||||||
|
}
|
||||||
|
const params : updateParams = {
|
||||||
|
components: "",
|
||||||
|
appTargetVersion: customAppVersion,
|
||||||
|
systemTargetVersion: customSystemVersion,
|
||||||
|
};
|
||||||
|
if (customAppVersion) params.components += ",app";
|
||||||
|
if (customSystemVersion) params.components += ",system";
|
||||||
|
params.components = params.components?.replace(/^,+/, "");
|
||||||
|
|
||||||
|
return await checkUpdateComponents(params, false);
|
||||||
|
}, [customAppVersion, customSystemVersion, getVersionInfo]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
abortControllerRef.current = new AbortController();
|
abortControllerRef.current = new AbortController();
|
||||||
const signal = abortControllerRef.current.signal;
|
const signal = abortControllerRef.current.signal;
|
||||||
|
|
@ -203,7 +213,7 @@ function LoadingState({
|
||||||
setProgressWidth("100%");
|
setProgressWidth("100%");
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
getVersionInfo()
|
checkUpdate()
|
||||||
.then(async versionInfo => {
|
.then(async versionInfo => {
|
||||||
// Add a small delay to ensure it's not just flickering
|
// Add a small delay to ensure it's not just flickering
|
||||||
await sleep(600);
|
await sleep(600);
|
||||||
|
|
@ -225,7 +235,7 @@ function LoadingState({
|
||||||
clearTimeout(animationTimer);
|
clearTimeout(animationTimer);
|
||||||
abortControllerRef.current?.abort();
|
abortControllerRef.current?.abort();
|
||||||
};
|
};
|
||||||
}, [getVersionInfo, onFinished, setModalView]);
|
}, [checkUpdate, onFinished, setModalView]);
|
||||||
|
|
||||||
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">
|
||||||
|
|
@ -433,11 +443,12 @@ function SystemUpToDateState({
|
||||||
|
|
||||||
function UpdateAvailableState({
|
function UpdateAvailableState({
|
||||||
versionInfo,
|
versionInfo,
|
||||||
onConfirmUpdate,
|
onConfirm,
|
||||||
onClose,
|
onClose,
|
||||||
}: {
|
}: {
|
||||||
versionInfo: SystemVersionInfo;
|
versionInfo: SystemVersionInfo;
|
||||||
onConfirmUpdate: () => void;
|
forceCustomUpdate: boolean;
|
||||||
|
onConfirm: () => void;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
|
|
@ -452,18 +463,18 @@ function UpdateAvailableState({
|
||||||
<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">{m.general_update_system_type()}</span>: {versionInfo?.remote?.systemVersion}
|
<span className="font-semibold">{m.general_update_system_type()}</span>: {versionInfo?.local?.systemVersion} <span className="text-slate-600 dark:text-slate-300">→</span> {versionInfo?.remote?.systemVersion}
|
||||||
<br />
|
<br />
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
{versionInfo?.appUpdateAvailable ? (
|
{versionInfo?.appUpdateAvailable ? (
|
||||||
<>
|
<>
|
||||||
<span className="font-semibold">{m.general_update_application_type()}</span>: {versionInfo?.remote?.appVersion}
|
<span className="font-semibold">{m.general_update_application_type()}</span>: {versionInfo?.local?.appVersion} <span className="text-slate-600 dark:text-slate-300">→</span> {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={m.general_update_now_button()} onClick={onConfirmUpdate} />
|
<Button size="SM" theme="primary" text={m.general_update_now_button()} onClick={onConfirm} />
|
||||||
<Button size="SM" theme="light" text={m.general_update_later_button()} onClick={onClose} />
|
<Button size="SM" theme="light" text={m.general_update_later_button()} onClick={onClose} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -471,51 +482,6 @@ function UpdateAvailableState({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function UpdateDowngradeAvailableState({
|
|
||||||
appVersion,
|
|
||||||
systemVersion,
|
|
||||||
onConfirmDowngrade,
|
|
||||||
onCancelDowngrade,
|
|
||||||
}: {
|
|
||||||
appVersion?: string;
|
|
||||||
systemVersion?: string;
|
|
||||||
onConfirmDowngrade: () => void;
|
|
||||||
onCancelDowngrade: () => void;
|
|
||||||
}) {
|
|
||||||
const confirmDowngrade = useCallback(() => {
|
|
||||||
onConfirmDowngrade();
|
|
||||||
}, [onConfirmDowngrade]);
|
|
||||||
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">
|
|
||||||
{m.general_update_downgrade_available_title()}
|
|
||||||
</p>
|
|
||||||
<p className="mb-2 text-sm text-slate-600 dark:text-slate-300">
|
|
||||||
{m.general_update_downgrade_available_description()}
|
|
||||||
</p>
|
|
||||||
<p className="mb-4 text-sm text-slate-600 dark:text-slate-300">
|
|
||||||
{systemVersion ? (
|
|
||||||
<>
|
|
||||||
<span className="font-semibold">{m.general_update_system_type()}</span>: {systemVersion}
|
|
||||||
<br />
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
{appVersion ? (
|
|
||||||
<>
|
|
||||||
<span className="font-semibold">{m.general_update_application_type()}</span>: {appVersion}
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
</p>
|
|
||||||
<div className="flex items-center justify-start gap-x-2">
|
|
||||||
<Button size="SM" theme="primary" text={m.general_update_downgrade_button()} onClick={confirmDowngrade} />
|
|
||||||
<Button size="SM" theme="light" text={m.general_update_keep_current_button()} onClick={onCancelDowngrade} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function UpdateCompletedState({ onClose }: { onClose: () => void }) {
|
function UpdateCompletedState({ onClose }: { onClose: () => void }) {
|
||||||
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">
|
||||||
|
|
|
||||||
|
|
@ -220,9 +220,7 @@ export interface SystemVersionInfo {
|
||||||
local: VersionInfo;
|
local: VersionInfo;
|
||||||
remote?: VersionInfo;
|
remote?: VersionInfo;
|
||||||
systemUpdateAvailable: boolean;
|
systemUpdateAvailable: boolean;
|
||||||
systemDowngradeAvailable: boolean;
|
|
||||||
appUpdateAvailable: boolean;
|
appUpdateAvailable: boolean;
|
||||||
appDowngradeAvailable: boolean;
|
|
||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,8 +244,8 @@ export async function getLocalVersion() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface updateParams {
|
export interface updateParams {
|
||||||
app?: string;
|
appTargetVersion?: string;
|
||||||
system?: string;
|
systemTargetVersion?: string;
|
||||||
components?: string;
|
components?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue