feat(installer): show version info and offer worker restart in settings

- Surface Latest version and flag unparseable pre-release tags in
  VersionLabel so users know why auto-update was skipped.
- Prompt to stop/start the worker service after Save, since the
  worker only reads its config at process start.
This commit is contained in:
mika kuns
2026-04-23 13:07:31 +02:00
parent 2690332d13
commit 4a6d96b90e
4 changed files with 57 additions and 11 deletions

View File

@@ -10,6 +10,7 @@ public sealed class InstallContext
public string? InstallerVersion { get; set; } // from this installer's assembly
public string? InstalledVersion { get; set; } // from install.json (or set by DownloadAndExtractStep)
public string? LatestVersion { get; set; } // from Gitea API (may be null if offline)
public bool LatestTagUnparseable { get; set; } // true if latest tag isn't a System.Version
// PathsPage
public string DbPath { get; set; } = "~/.todo-app/todo.db";

View File

@@ -4,7 +4,12 @@ public sealed record DetectedState(
InstallerMode Mode,
InstallManifest? Existing,
GiteaRelease? LatestRelease,
string? LatestVersion);
string? LatestVersion)
{
/// <summary>True when a release was returned but its tag isn't a parseable
/// System.Version (e.g. "0.2.0-beta") — so we couldn't decide if it's newer.</summary>
public bool LatestTagUnparseable { get; init; }
}
public sealed class InstallModeDetector
{
@@ -26,23 +31,26 @@ public sealed class InstallModeDetector
return new DetectedState(InstallerMode.Config, manifest, null, null);
var latestVersion = release.TagName.TrimStart('v', 'V');
if (IsNewer(latestVersion, manifest.Version))
var newer = IsNewer(latestVersion, manifest.Version, out var unparseable);
if (newer)
return new DetectedState(InstallerMode.Update, manifest, release, latestVersion);
return new DetectedState(InstallerMode.Config, manifest, release, latestVersion);
return new DetectedState(InstallerMode.Config, manifest, release, latestVersion)
{
LatestTagUnparseable = unparseable,
};
}
/// <summary>
/// Returns true only when both versions parse as System.Version (major.minor[.build[.revision]])
/// AND latest &gt; current. Semver pre-release tags like "0.2.0-beta" fail to parse and are
/// treated as "not newer" — the user drops into Config mode with no update offered.
/// This is deliberate: offering an update we can't compare is worse than silently skipping it.
/// If the project starts shipping pre-release tags, revisit this.
/// treated as "not newer" — the user drops into Config mode with no update offered, but
/// <paramref name="unparseable"/> is set so the UI can surface a hint.
/// </summary>
private static bool IsNewer(string latest, string current)
private static bool IsNewer(string latest, string current, out bool unparseable)
{
if (!Version.TryParse(latest, out var lv)) return false;
if (!Version.TryParse(current, out var cv)) return false;
unparseable = !Version.TryParse(latest, out var lv) | !Version.TryParse(current, out var cv);
if (unparseable) return false;
return lv > cv;
}
}