fix(gui): show restarting modal during upgrade restart (fixes #1248) (#10566)

Signed-off-by: steadytao <mail@steadytao.com>
Signed-off-by: Jakob Borg <jakob@kastelo.net>
Co-authored-by: Jakob Borg <jakob@kastelo.net>
This commit is contained in:
Tao
2026-02-11 19:46:37 +10:00
committed by GitHub
parent 5cf9168dc2
commit f86c1d83db
4 changed files with 60 additions and 2 deletions

View File

@@ -748,8 +748,13 @@ func autoUpgrade(cfg config.Wrapper, app *syncthing.App, evLogger events.Logger)
continue
}
sub.Unsubscribe()
restartDelay := time.Minute
evLogger.Log(events.UpgradeRestartScheduled, map[string]any{
"delayS": int(restartDelay / time.Second),
"newVersion": rel.Tag,
})
slog.Error("Automatically upgraded, restarting in 1 minute", slog.String("newVersion", rel.Tag))
time.Sleep(time.Minute)
time.Sleep(restartDelay)
app.Stop(svcutil.ExitUpgrade)
return
}

View File

@@ -73,6 +73,7 @@ angular.module('syncthing.core')
CLUSTER_CONFIG_RECEIVED: 'ClusterConfigReceived', // Emitted when receiving a remote device's cluster config
DOWNLOAD_PROGRESS: 'DownloadProgress', // Emitted during file downloads for each folder for each file
FAILURE: 'Failure', // Specific errors sent to the usage reporting server for diagnosis
UPGRADE_RESTART_SCHEDULED: 'UpgradeRestartScheduled', // Auto-upgrade completed, restart scheduled
FOLDER_COMPLETION: 'FolderCompletion', //Emitted when the local or remote contents for a folder changes
FOLDER_REJECTED: 'FolderRejected', // DEPRECATED: Emitted when a device sends index information for a folder we do not have, or have but do not share with the device in question
PENDING_FOLDERS_CHANGED: 'PendingFoldersChanged', // Emitted when pending folders were added / updated (offered by some device, but not shared to them) or removed (folder ignored or added or no longer offered from the remote device)

View File

@@ -11,6 +11,8 @@ angular.module('syncthing.core')
var navigatingAway = false;
var online = false;
var restarting = false;
var restartExpectedFrom = 0;
var restartExpectedUntil = 0;
function initController() {
LocaleService.autoConfigLocale();
@@ -33,6 +35,34 @@ angular.module('syncthing.core')
Events.start();
}
function clearRestartExpectation() {
restartExpectedFrom = 0;
restartExpectedUntil = 0;
}
function setRestartExpectation(delayS) {
var delay = delayS > 0 ? delayS : 60;
var delayMs = delay * 1000;
var earlyMs = 5 * 1000;
var graceMs = 60 * 1000;
var now = Date.now();
restartExpectedFrom = now + Math.max(0, delayMs - earlyMs);
restartExpectedUntil = now + delayMs + graceMs;
}
function restartExpectedNow() {
if (!restartExpectedUntil) {
return false;
}
var now = Date.now();
if (now > restartExpectedUntil) {
clearRestartExpectation();
return false;
}
return now >= restartExpectedFrom;
}
// public/scope definitions
// window.metadata is set in /meta.js which requires authentication
@@ -204,6 +234,7 @@ angular.module('syncthing.core')
online = true;
restarting = false;
clearRestartExpectation();
hideModal('#networkError');
hideModal('#restarting');
hideModal('#shutdown');
@@ -218,10 +249,26 @@ angular.module('syncthing.core')
console.log('UIOffline');
online = false;
if (!restarting) {
showModal('#networkError');
if (restartExpectedNow()) {
restarting = true;
showModal('#restarting');
} else {
showModal('#networkError');
}
}
});
$scope.$on(Events.UPGRADE_RESTART_SCHEDULED, function (_event, arg) {
var delayS = 0;
if (arg && arg.data && arg.data.delayS !== undefined) {
delayS = parseInt(arg.data.delayS, 10);
if (isNaN(delayS) || delayS < 0) {
delayS = 0;
}
}
setRestartExpectation(delayS);
});
$scope.$on('HTTPError', function (event, arg) {
// Emitted when a HTTP call fails. We use the status code to try
// to figure out what's wrong.

View File

@@ -57,6 +57,7 @@ const (
ListenAddressesChanged
LoginAttempt
Failure
UpgradeRestartScheduled
AllEvents = (1 << iota) - 1
)
@@ -134,6 +135,8 @@ func (t EventType) String() string {
return "FolderWatchStateChanged"
case Failure:
return "Failure"
case UpgradeRestartScheduled:
return "UpgradeRestartScheduled"
default:
return "Unknown"
}
@@ -221,6 +224,8 @@ func UnmarshalEventType(s string) EventType {
return FolderWatchStateChanged
case "Failure":
return Failure
case "UpgradeRestartScheduled":
return UpgradeRestartScheduled
default:
return 0
}