Summary
Add a top-right toolbar button in the main window that opens a dedicated "Version & Updates" dialog. The dialog must show:
- The current running version.
- The available/latest version.
- An Update now button.
- A checkbox/toggle to enable auto-updating.
This is primarily a wiring/surfacing task: the update ViewModel and View already exist and are reused today only from the ⚙ Settings dialog. We need a dedicated quick-access dialog in addition to Settings.
Root Cause / Current State
The update UI is fully implemented but is only reachable via the ⚙ Settings dialog. There is no top-level entry point for users to quickly check the version or trigger an update.
Phantom.Workspaces/ViewModels/Configuration/UpdateSettingsViewModel.cs already exposes everything the new dialog needs:
RunningVersion (L65), LatestVersion (L98), IsUpdateAvailable (L105), IsBusy (L118), StatusText (L132).
Modes / SelectedMode (L62/L68) built from AutomaticUpdateMode (Off/NotifyOnly/DownloadAndInstall); record UpdateModeOption at L228.
RunAtStartup (L83).
CheckForUpdatesNowCommand (L139).
InstallUpdateNowCommand (L142) — gated on IsUpdateAvailable && !IsBusy. This is the "Update now" button.
Phantom.Workspaces/Views/Configuration/UpdateSettingsView.axaml already renders current version (L13-14), the auto-update mode ComboBox (L19-27), a run-at-startup checkbox (L30-31), Check-for-updates + Install-update buttons (L34-38), and a status line (L41). Code-behind is empty boilerplate.
- Data source:
IUpdateController (Phantom.Workspaces/Services/Updates/IUpdateController.cs) — RunningVersion (L24), Mode get/set (L27), LatestAvailableVersion (L30), IsRunAtStartupEnabled (L33), UpdateAvailabilityChanged event (L36), CheckForUpdatesAsync (L39), DownloadInstallAndRelaunchAsync (L45), SetRunAtStartup (L48). Runtime instance is available via (Application.Current as App)?.UpdateController.
AutomaticUpdateMode { Off=0, NotifyOnly=1, DownloadAndInstall=2 } in WorkspacesConfiguration.cs (L119-129).
- Today the Updates section is only reachable via
SettingsDialogWindow.axaml, which templates UpdateSettingsViewModel → UpdateSettingsView (L28-30) and is opened via the gear button (MainWindow.axaml.cs::OnOpenSettingsClicked, L165-193).
Because the VM/View already exist and cover every requirement, the change is: (a) add a new top-right button, (b) add a new lightweight UpdateDialogWindow that hosts the existing UpdateSettingsView, and (c) optionally add a simpler "auto-update" checkbox that maps to AutomaticUpdateMode.
Affected Files
| File |
Change |
Phantom.Workspaces/MainWindow.axaml |
Add a new button inside StackPanel x:Name="TopRightBar" (L63+, inside header Border L31, Grid.Column=2), adjacent to the ⚙ Settings button (~L164), using Classes="settings-gear top-right", distinct glyph and tooltip "Version & updates". |
Phantom.Workspaces/MainWindow.axaml.cs |
Add OnOpenUpdateDialogClicked handler mirroring OnOpenSettingsClicked (L165-193) / OnOpenConnectionStatusClicked (L195-206). Load config via ConfigurationPersistenceService, construct new UpdateSettingsViewModel(app.UpdateController, config.Updates, dispatch), then await new UpdateDialogWindow(vm).ShowDialog(this);. |
Phantom.Workspaces/UpdateDialogWindow.axaml (new) |
New Avalonia Window with WindowStartupLocation="CenterOwner", SizeToContent="WidthAndHeight", title "Version & Updates". Uses a <Window.DataTemplates> mapping UpdateSettingsViewModel → UpdateSettingsView (mirroring SettingsDialogWindow.axaml L28-30), or a ContentControl bound to the VM. |
Phantom.Workspaces/UpdateDialogWindow.axaml.cs (new) |
Ctor takes UpdateSettingsViewModel and assigns it as DataContext. Mirror ConnectionStatusWindow/CredentialManagerDialogWindow. |
Phantom.Workspaces/Views/Configuration/UpdateSettingsView.axaml (optional) |
Optionally add a simple "Enable auto-updates" checkbox mapped to AutomaticUpdateMode (checked ⇒ DownloadAndInstall, unchecked ⇒ NotifyOnly). Keep the existing full mode ComboBox for Settings. |
Phantom.Workspaces/ViewModels/Configuration/UpdateSettingsViewModel.cs (optional) |
If the checkbox is added, expose an AutoUpdateEnabled bool that maps to/from SelectedMode. |
Phantom.Workspaces.Tests/Services/Updates/UpdateSettingsViewModelTests.cs |
Extend with tests below (reuse existing FakeUpdateController). |
Design / Fix
-
New window UpdateDialogWindow (Phantom.Workspaces/UpdateDialogWindow.axaml + .axaml.cs):
- Avalonia
Window, WindowStartupLocation="CenterOwner", SizeToContent="WidthAndHeight", Title="Version & Updates".
- Declare a
<Window.DataTemplates> mapping UpdateSettingsViewModel → UpdateSettingsView (as in SettingsDialogWindow.axaml L28-30), and host a ContentControl Content="{Binding}".
- Constructor takes
UpdateSettingsViewModel and sets DataContext. Mirror ConnectionStatusWindow / SettingsDialogWindow.
-
New top-right button in MainWindow.axaml:
- Inside
StackPanel x:Name="TopRightBar" (L63+), placed adjacent to the ⚙ Settings button (~L164).
- Use
Classes="settings-gear top-right" for visual consistency with the other top-right buttons (Network/Scheduled tasks/Credentials/Agents/Usage/Notifications/Save/Settings).
- Distinct glyph (e.g. a version/up-arrow / cloud-download icon), tooltip "Version & updates",
Click="OnOpenUpdateDialogClicked".
-
New handler OnOpenUpdateDialogClicked in MainWindow.axaml.cs:
- Mirror
OnOpenSettingsClicked (L165-193) — same config-load / VM-construct pattern — but for the update slice only.
- Get
UpdateController via (Application.Current as App)?.UpdateController.
- Load current config through
ConfigurationPersistenceService, take its Updates section.
- Construct
new UpdateSettingsViewModel(app.UpdateController, config.Updates, dispatch).
await new UpdateDialogWindow(vm).ShowDialog(this);.
- Persistence of any changes must follow whatever pattern
OnOpenSettingsClicked uses today (e.g. persist on close), so the quick dialog behaves consistently with the Settings entry point.
-
Auto-update checkbox (owner explicitly requested a checkbox, not a mode dropdown, for the quick dialog):
- Recommend mapping the checkbox to
AutomaticUpdateMode:
- Checked ⇒
AutomaticUpdateMode.DownloadAndInstall.
- Unchecked ⇒
AutomaticUpdateMode.NotifyOnly (i.e. still notify, do not auto-install).
- Expose an
AutoUpdateEnabled bool on UpdateSettingsViewModel that reads/writes SelectedMode accordingly, so the existing full Modes/SelectedMode ComboBox in Settings continues to work unchanged.
- Only show the checkbox in the new dialog; the ⚙ Settings pane keeps the fuller mode selector.
-
"Update now" button and version display are already present in UpdateSettingsView.axaml:
- Current version binding at L13-14,
InstallUpdateNowCommand button at L34-38, StatusText line at L41. LatestVersion / IsUpdateAvailable from the VM (L98/L105) provide the "available version" surface. No behavioural change needed here.
-
Do not remove the Updates section from SettingsDialogWindow. Both entry points share the same VM and View. The new dialog is an additional, quick-access surface.
Expected Tests
Extend Phantom.Workspaces.Tests/Services/Updates/UpdateSettingsViewModelTests.cs (namespace Phantom.Workspaces.Tests.Updates, xUnit [Fact], existing Scenario_ExpectedBehavior style, reuse the inline FakeUpdateController implementing IUpdateController). Confirm exact class names by reading the existing test file first.
| Test Name |
Class |
What It Verifies |
UpdateSettingsViewModel_ExposesRunningAndLatestVersion |
UpdateSettingsViewModelTests |
The VM surfaces both RunningVersion and LatestVersion so the dialog can display current + available versions. |
UpdateSettingsViewModel_InstallUpdateNowCommand_WhenUpdateAvailable_IsEnabled |
UpdateSettingsViewModelTests |
The "Update now" command (InstallUpdateNowCommand) is enabled only when IsUpdateAvailable && !IsBusy, and disabled otherwise. |
UpdateSettingsViewModel_AutoUpdateCheckbox_MapsToDownloadAndInstallMode |
UpdateSettingsViewModelTests |
Toggling the auto-update checkbox (AutoUpdateEnabled) sets AutomaticUpdateMode to DownloadAndInstall when checked and NotifyOnly when unchecked, and flows the change to both the controller and the settings record. |
UpdateSettingsViewModel_AutoUpdateCheckbox_ReflectsExistingMode |
UpdateSettingsViewModelTests |
When the VM is seeded with DownloadAndInstall, AutoUpdateEnabled is true; when seeded with NotifyOnly or Off, AutoUpdateEnabled is false. |
MainWindow_OpenUpdateDialog_ShowsUpdateDialogWindowWithBoundViewModel |
MainWindowViewModelTests (or a new MainWindowTests) |
Invoking the top-right update-dialog button opens UpdateDialogWindow with a bound UpdateSettingsViewModel constructed from the current IUpdateController and UpdateSettings. |
Summary
Add a top-right toolbar button in the main window that opens a dedicated "Version & Updates" dialog. The dialog must show:
This is primarily a wiring/surfacing task: the update ViewModel and View already exist and are reused today only from the ⚙ Settings dialog. We need a dedicated quick-access dialog in addition to Settings.
Root Cause / Current State
The update UI is fully implemented but is only reachable via the ⚙ Settings dialog. There is no top-level entry point for users to quickly check the version or trigger an update.
Phantom.Workspaces/ViewModels/Configuration/UpdateSettingsViewModel.csalready exposes everything the new dialog needs:RunningVersion(L65),LatestVersion(L98),IsUpdateAvailable(L105),IsBusy(L118),StatusText(L132).Modes/SelectedMode(L62/L68) built fromAutomaticUpdateMode(Off/NotifyOnly/DownloadAndInstall); recordUpdateModeOptionat L228.RunAtStartup(L83).CheckForUpdatesNowCommand(L139).InstallUpdateNowCommand(L142) — gated onIsUpdateAvailable && !IsBusy. This is the "Update now" button.Phantom.Workspaces/Views/Configuration/UpdateSettingsView.axamlalready renders current version (L13-14), the auto-update mode ComboBox (L19-27), a run-at-startup checkbox (L30-31), Check-for-updates + Install-update buttons (L34-38), and a status line (L41). Code-behind is empty boilerplate.IUpdateController(Phantom.Workspaces/Services/Updates/IUpdateController.cs) —RunningVersion(L24),Modeget/set (L27),LatestAvailableVersion(L30),IsRunAtStartupEnabled(L33),UpdateAvailabilityChangedevent (L36),CheckForUpdatesAsync(L39),DownloadInstallAndRelaunchAsync(L45),SetRunAtStartup(L48). Runtime instance is available via(Application.Current as App)?.UpdateController.AutomaticUpdateMode { Off=0, NotifyOnly=1, DownloadAndInstall=2 }inWorkspacesConfiguration.cs(L119-129).SettingsDialogWindow.axaml, which templatesUpdateSettingsViewModel→UpdateSettingsView(L28-30) and is opened via the gear button (MainWindow.axaml.cs::OnOpenSettingsClicked, L165-193).Because the VM/View already exist and cover every requirement, the change is: (a) add a new top-right button, (b) add a new lightweight
UpdateDialogWindowthat hosts the existingUpdateSettingsView, and (c) optionally add a simpler "auto-update" checkbox that maps toAutomaticUpdateMode.Affected Files
Phantom.Workspaces/MainWindow.axamlStackPanel x:Name="TopRightBar"(L63+, inside header Border L31,Grid.Column=2), adjacent to the ⚙ Settings button (~L164), usingClasses="settings-gear top-right", distinct glyph and tooltip "Version & updates".Phantom.Workspaces/MainWindow.axaml.csOnOpenUpdateDialogClickedhandler mirroringOnOpenSettingsClicked(L165-193) /OnOpenConnectionStatusClicked(L195-206). Load config viaConfigurationPersistenceService, constructnew UpdateSettingsViewModel(app.UpdateController, config.Updates, dispatch), thenawait new UpdateDialogWindow(vm).ShowDialog(this);.Phantom.Workspaces/UpdateDialogWindow.axaml(new)WindowwithWindowStartupLocation="CenterOwner",SizeToContent="WidthAndHeight", title "Version & Updates". Uses a<Window.DataTemplates>mappingUpdateSettingsViewModel→UpdateSettingsView(mirroringSettingsDialogWindow.axamlL28-30), or aContentControlbound to the VM.Phantom.Workspaces/UpdateDialogWindow.axaml.cs(new)UpdateSettingsViewModeland assigns it asDataContext. MirrorConnectionStatusWindow/CredentialManagerDialogWindow.Phantom.Workspaces/Views/Configuration/UpdateSettingsView.axaml(optional)AutomaticUpdateMode(checked ⇒DownloadAndInstall, unchecked ⇒NotifyOnly). Keep the existing full mode ComboBox for Settings.Phantom.Workspaces/ViewModels/Configuration/UpdateSettingsViewModel.cs(optional)AutoUpdateEnabledbool that maps to/fromSelectedMode.Phantom.Workspaces.Tests/Services/Updates/UpdateSettingsViewModelTests.csFakeUpdateController).Design / Fix
New window
UpdateDialogWindow(Phantom.Workspaces/UpdateDialogWindow.axaml+.axaml.cs):Window,WindowStartupLocation="CenterOwner",SizeToContent="WidthAndHeight",Title="Version & Updates".<Window.DataTemplates>mappingUpdateSettingsViewModel→UpdateSettingsView(as inSettingsDialogWindow.axamlL28-30), and host aContentControl Content="{Binding}".UpdateSettingsViewModeland setsDataContext. MirrorConnectionStatusWindow/SettingsDialogWindow.New top-right button in
MainWindow.axaml:StackPanel x:Name="TopRightBar"(L63+), placed adjacent to the ⚙ Settings button (~L164).Classes="settings-gear top-right"for visual consistency with the other top-right buttons (Network/Scheduled tasks/Credentials/Agents/Usage/Notifications/Save/Settings).Click="OnOpenUpdateDialogClicked".New handler
OnOpenUpdateDialogClickedinMainWindow.axaml.cs:OnOpenSettingsClicked(L165-193) — same config-load / VM-construct pattern — but for the update slice only.UpdateControllervia(Application.Current as App)?.UpdateController.ConfigurationPersistenceService, take itsUpdatessection.new UpdateSettingsViewModel(app.UpdateController, config.Updates, dispatch).await new UpdateDialogWindow(vm).ShowDialog(this);.OnOpenSettingsClickeduses today (e.g. persist on close), so the quick dialog behaves consistently with the Settings entry point.Auto-update checkbox (owner explicitly requested a checkbox, not a mode dropdown, for the quick dialog):
AutomaticUpdateMode:AutomaticUpdateMode.DownloadAndInstall.AutomaticUpdateMode.NotifyOnly(i.e. still notify, do not auto-install).AutoUpdateEnabledbool onUpdateSettingsViewModelthat reads/writesSelectedModeaccordingly, so the existing fullModes/SelectedModeComboBox in Settings continues to work unchanged."Update now" button and version display are already present in
UpdateSettingsView.axaml:InstallUpdateNowCommandbutton at L34-38,StatusTextline at L41.LatestVersion/IsUpdateAvailablefrom the VM (L98/L105) provide the "available version" surface. No behavioural change needed here.Do not remove the Updates section from
SettingsDialogWindow. Both entry points share the same VM and View. The new dialog is an additional, quick-access surface.Expected Tests
Extend
Phantom.Workspaces.Tests/Services/Updates/UpdateSettingsViewModelTests.cs(namespacePhantom.Workspaces.Tests.Updates, xUnit[Fact], existingScenario_ExpectedBehaviorstyle, reuse the inlineFakeUpdateControllerimplementingIUpdateController). Confirm exact class names by reading the existing test file first.UpdateSettingsViewModel_ExposesRunningAndLatestVersionUpdateSettingsViewModelTestsRunningVersionandLatestVersionso the dialog can display current + available versions.UpdateSettingsViewModel_InstallUpdateNowCommand_WhenUpdateAvailable_IsEnabledUpdateSettingsViewModelTestsInstallUpdateNowCommand) is enabled only whenIsUpdateAvailable && !IsBusy, and disabled otherwise.UpdateSettingsViewModel_AutoUpdateCheckbox_MapsToDownloadAndInstallModeUpdateSettingsViewModelTestsAutoUpdateEnabled) setsAutomaticUpdateModetoDownloadAndInstallwhen checked andNotifyOnlywhen unchecked, and flows the change to both the controller and the settings record.UpdateSettingsViewModel_AutoUpdateCheckbox_ReflectsExistingModeUpdateSettingsViewModelTestsDownloadAndInstall,AutoUpdateEnabledistrue; when seeded withNotifyOnlyorOff,AutoUpdateEnabledisfalse.MainWindow_OpenUpdateDialog_ShowsUpdateDialogWindowWithBoundViewModelMainWindowViewModelTests(or a newMainWindowTests)UpdateDialogWindowwith a boundUpdateSettingsViewModelconstructed from the currentIUpdateControllerandUpdateSettings.