feat(ui): prompt once on worker connection failure with grace timer
Adds ShowWorkerConnectionModal hook, DecideShowConnectionPrompt one-shot gate, OpenWorkerConnectionHelp relay command, and a 12 s _connectTimer to IslandsShellViewModel; covered by two new unit tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -51,6 +51,9 @@ public sealed partial class IslandsShellViewModel : ViewModelBase
|
|||||||
// Set by MainWindow to open the global worktrees overview dialog.
|
// Set by MainWindow to open the global worktrees overview dialog.
|
||||||
public Func<WorktreesOverviewModalViewModel, Task>? ShowWorktreesOverviewModal { get; set; }
|
public Func<WorktreesOverviewModalViewModel, Task>? ShowWorktreesOverviewModal { get; set; }
|
||||||
|
|
||||||
|
// Set by MainWindow to open the worker-connection help dialog.
|
||||||
|
public Func<WorkerConnectionModalViewModel, Task>? ShowWorkerConnectionModal { get; set; }
|
||||||
|
|
||||||
[ObservableProperty] private bool _isUpdateBannerVisible;
|
[ObservableProperty] private bool _isUpdateBannerVisible;
|
||||||
[ObservableProperty] private string? _updateBannerLatestVersion;
|
[ObservableProperty] private string? _updateBannerLatestVersion;
|
||||||
[ObservableProperty] private string? _inlineUpdateStatus;
|
[ObservableProperty] private string? _inlineUpdateStatus;
|
||||||
@@ -72,6 +75,7 @@ public sealed partial class IslandsShellViewModel : ViewModelBase
|
|||||||
public bool ShowLists => WindowWidth >= 780;
|
public bool ShowLists => WindowWidth >= 780;
|
||||||
|
|
||||||
private readonly System.Timers.Timer _clearTimer = new(30_000) { AutoReset = false };
|
private readonly System.Timers.Timer _clearTimer = new(30_000) { AutoReset = false };
|
||||||
|
private readonly System.Timers.Timer _connectTimer = new(12_000) { AutoReset = false };
|
||||||
|
|
||||||
[ObservableProperty] private string? _primeStatus;
|
[ObservableProperty] private string? _primeStatus;
|
||||||
private readonly System.Timers.Timer _primeStatusTimer = new(5_000) { AutoReset = false };
|
private readonly System.Timers.Timer _primeStatusTimer = new(5_000) { AutoReset = false };
|
||||||
@@ -220,6 +224,11 @@ public sealed partial class IslandsShellViewModel : ViewModelBase
|
|||||||
};
|
};
|
||||||
_primeStatusTimer.Elapsed += (_, _) =>
|
_primeStatusTimer.Elapsed += (_, _) =>
|
||||||
Avalonia.Threading.Dispatcher.UIThread.Post(() => PrimeStatus = null);
|
Avalonia.Threading.Dispatcher.UIThread.Post(() => PrimeStatus = null);
|
||||||
|
_connectTimer.Elapsed += (_, _) => Dispatcher.UIThread.Post(() =>
|
||||||
|
{
|
||||||
|
if (DecideShowConnectionPrompt(IsOffline)) _ = OpenWorkerConnectionHelpAsync();
|
||||||
|
});
|
||||||
|
_connectTimer.Start();
|
||||||
_ = Lists.LoadAsync();
|
_ = Lists.LoadAsync();
|
||||||
_updateCheck.PropertyChanged += (_, e) =>
|
_updateCheck.PropertyChanged += (_, e) =>
|
||||||
{
|
{
|
||||||
@@ -269,6 +278,25 @@ public sealed partial class IslandsShellViewModel : ViewModelBase
|
|||||||
if (ShowAboutModal is not null) await ShowAboutModal(vm);
|
if (ShowAboutModal is not null) await ShowAboutModal(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool _connectionPromptShown;
|
||||||
|
|
||||||
|
internal bool DecideShowConnectionPrompt(bool isOffline)
|
||||||
|
{
|
||||||
|
if (!isOffline) return false;
|
||||||
|
if (_connectionPromptShown) return false;
|
||||||
|
_connectionPromptShown = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OpenWorkerConnectionHelpAsync()
|
||||||
|
{
|
||||||
|
var vm = new WorkerConnectionModalViewModel(_workerLocator, _installerLocator);
|
||||||
|
if (ShowWorkerConnectionModal is not null) await ShowWorkerConnectionModal(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private Task OpenWorkerConnectionHelp() => OpenWorkerConnectionHelpAsync();
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private async Task OpenRepoImport()
|
private async Task OpenRepoImport()
|
||||||
{
|
{
|
||||||
|
|||||||
22
tests/ClaudeDo.Ui.Tests/ConnectionPromptGateTests.cs
Normal file
22
tests/ClaudeDo.Ui.Tests/ConnectionPromptGateTests.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using ClaudeDo.Ui.ViewModels;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace ClaudeDo.Ui.Tests;
|
||||||
|
|
||||||
|
public class ConnectionPromptGateTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Shows_once_when_offline()
|
||||||
|
{
|
||||||
|
var vm = new IslandsShellViewModel();
|
||||||
|
Assert.True(vm.DecideShowConnectionPrompt(isOffline: true));
|
||||||
|
Assert.False(vm.DecideShowConnectionPrompt(isOffline: true)); // not a second time
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Does_not_show_when_connected_before_grace()
|
||||||
|
{
|
||||||
|
var vm = new IslandsShellViewModel();
|
||||||
|
Assert.False(vm.DecideShowConnectionPrompt(isOffline: false));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user