Skip to content

Commit 4926038

Browse files
committed
Route operation failures to journal detail instead of modal dialog
1 parent bc864a3 commit 4926038

17 files changed

Lines changed: 92 additions & 249 deletions

BorgMate.Tests/ArchiveListViewModelTests.cs

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,11 @@ private static BorgOperationRunner CreateRunner(IJournalService? journal = null)
2626
private static ArchiveListViewModel CreateVm()
2727
{
2828
var borgFactory = new BorgServiceFactory(Substitute.For<ILoggerFactory>(), new AppSettings(), SshAgent, Wsl);
29-
var status = Substitute.For<IStatusService>();
3029
var filePicker = new FilePickerService();
3130
var cache = new BorgCacheService();
3231
var journal = Substitute.For<IJournalService>();
3332
var logger = Substitute.For<ILogger<ArchiveListViewModel>>();
34-
return new ArchiveListViewModel(borgFactory, status, filePicker, cache, journal, CreateRunner(journal), Prompt, null!, logger);
33+
return new ArchiveListViewModel(borgFactory, filePicker, cache, journal, CreateRunner(journal), Prompt, null!, logger);
3534
}
3635

3736
[Fact]
@@ -135,37 +134,6 @@ public void SortByDate_TogglesDirection()
135134
Assert.Contains("▼", vm.DateSortIndicator);
136135
}
137136

138-
[Fact]
139-
public void Restore_NoRepo_ShowsError()
140-
{
141-
var status = Substitute.For<IStatusService>();
142-
var vm = new ArchiveListViewModel(
143-
new BorgServiceFactory(Substitute.For<ILoggerFactory>(), new AppSettings(), SshAgent, Wsl), status,
144-
new FilePickerService(), new BorgCacheService(),
145-
Substitute.For<IJournalService>(), CreateRunner(), Prompt,
146-
null!, Substitute.For<ILogger<ArchiveListViewModel>>());
147-
148-
vm.RestoreCommand.Execute(null);
149-
150-
status.Received().SetError(Arg.Any<string>());
151-
}
152-
153-
[Fact]
154-
public void Restore_NoArchive_ShowsError()
155-
{
156-
var status = Substitute.For<IStatusService>();
157-
var vm = new ArchiveListViewModel(
158-
new BorgServiceFactory(Substitute.For<ILoggerFactory>(), new AppSettings(), SshAgent, Wsl), status,
159-
new FilePickerService(), new BorgCacheService(),
160-
Substitute.For<IJournalService>(), CreateRunner(), Prompt,
161-
null!, Substitute.For<ILogger<ArchiveListViewModel>>());
162-
163-
vm.Repository = new BorgRepository { Name = "test", Path = "/test" };
164-
vm.RestoreCommand.Execute(null);
165-
166-
status.Received().SetError(Arg.Any<string>());
167-
}
168-
169137
[Fact]
170138
public void HasDetail_False_Initially()
171139
{

BorgMate.Tests/MainWindowViewModelTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ private RepositoryListViewModel CreateRepoListVm()
3838
var runner = new BorgOperationRunner(
3939
Substitute.For<ILogger<BorgOperationRunner>>(), _jobQueue, _journalService, passphrase);
4040
var sizeCalculator = new DirectorySizeCalculator(Substitute.For<ILogger<DirectorySizeCalculator>>());
41-
return new RepositoryListViewModel(borgFactory, _configService, Substitute.For<IStatusService>(),
41+
return new RepositoryListViewModel(borgFactory, _configService,
4242
new FilePickerService(), _journalService, runner, passphrase, Wsl, sizeCalculator, _jobQueue,
4343
Substitute.For<ILogger<RepositoryListViewModel>>());
4444
}
@@ -49,7 +49,7 @@ private ArchiveListViewModel CreateArchiveListVm()
4949
var passphrase = new PassphrasePrompt(null);
5050
var runner = new BorgOperationRunner(
5151
Substitute.For<ILogger<BorgOperationRunner>>(), _jobQueue, _journalService, passphrase);
52-
return new ArchiveListViewModel(borgFactory, Substitute.For<IStatusService>(),
52+
return new ArchiveListViewModel(borgFactory,
5353
new FilePickerService(), new BorgCacheService(), _journalService, runner, passphrase,
5454
null!, Substitute.For<ILogger<ArchiveListViewModel>>());
5555
}

BorgMate.Tests/RepositoryEditorViewModelTests.cs

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,22 @@ namespace BorgMate.Tests;
1111

1212
public class RepositoryEditorViewModelTests
1313
{
14+
private static BorgServiceFactory CreateFactory()
15+
{
16+
var wsl = new WslHelper(Substitute.For<ILogger<WslHelper>>());
17+
var sshAgent = new SshAgentHelper(Substitute.For<ILogger<SshAgentHelper>>(), null, wsl);
18+
return new BorgServiceFactory(Substitute.For<ILoggerFactory>(), new AppSettings(), sshAgent, wsl);
19+
}
20+
1421
private static RepositoryEditorViewModel CreateVm() =>
15-
new(new BorgServiceFactory(Substitute.For<ILoggerFactory>(), new AppSettings(), new SshAgentHelper(Substitute.For<ILogger<SshAgentHelper>>(), null, new WslHelper(Substitute.For<ILogger<WslHelper>>())), new WslHelper(Substitute.For<ILogger<WslHelper>>())),
16-
Substitute.For<IStatusService>(),
17-
new FilePickerService());
22+
new(CreateFactory(), new FilePickerService());
1823

1924
// --- Factory methods ---
2025

2126
[Fact]
2227
public void ForNew_SetsDefaults()
2328
{
24-
var vm = RepositoryEditorViewModel.ForNew(
25-
new BorgServiceFactory(Substitute.For<ILoggerFactory>(), new AppSettings(), new SshAgentHelper(Substitute.For<ILogger<SshAgentHelper>>(), null, new WslHelper(Substitute.For<ILogger<WslHelper>>())), new WslHelper(Substitute.For<ILogger<WslHelper>>())),
26-
Substitute.For<IStatusService>(),
27-
new FilePickerService());
29+
var vm = RepositoryEditorViewModel.ForNew(CreateFactory(), new FilePickerService());
2830

2931
Assert.True(vm.IsNew);
3032
Assert.False(vm.IsOpen);
@@ -35,10 +37,7 @@ public void ForNew_SetsDefaults()
3537
[Fact]
3638
public void ForOpen_SetsDefaults()
3739
{
38-
var vm = RepositoryEditorViewModel.ForOpen(
39-
new BorgServiceFactory(Substitute.For<ILoggerFactory>(), new AppSettings(), new SshAgentHelper(Substitute.For<ILogger<SshAgentHelper>>(), null, new WslHelper(Substitute.For<ILogger<WslHelper>>())), new WslHelper(Substitute.For<ILogger<WslHelper>>())),
40-
Substitute.For<IStatusService>(),
41-
new FilePickerService());
40+
var vm = RepositoryEditorViewModel.ForOpen(CreateFactory(), new FilePickerService());
4241

4342
Assert.True(vm.IsOpen);
4443
Assert.False(vm.IsNew);
@@ -60,10 +59,7 @@ public void ForEdit_LoadsRepoFields()
6059
repo.Schedule.Hour = 3;
6160
repo.SourceDirectories.Add("/home/user/docs");
6261

63-
var vm = RepositoryEditorViewModel.ForEdit(
64-
new BorgServiceFactory(Substitute.For<ILoggerFactory>(), new AppSettings(), new SshAgentHelper(Substitute.For<ILogger<SshAgentHelper>>(), null, new WslHelper(Substitute.For<ILogger<WslHelper>>())), new WslHelper(Substitute.For<ILogger<WslHelper>>())),
65-
Substitute.For<IStatusService>(),
66-
new FilePickerService(), repo);
62+
var vm = RepositoryEditorViewModel.ForEdit(CreateFactory(), new FilePickerService(), repo);
6763

6864
Assert.False(vm.IsNew);
6965
Assert.False(vm.IsOpen);
@@ -118,9 +114,7 @@ public void Save_SshWithoutKeyPath_SetsSshKeyError()
118114
[Fact]
119115
public void Save_ValidLocal_SetsSaved()
120116
{
121-
var vm = RepositoryEditorViewModel.ForNew(
122-
new BorgServiceFactory(Substitute.For<ILoggerFactory>(), new AppSettings(), new SshAgentHelper(Substitute.For<ILogger<SshAgentHelper>>(), null, new WslHelper(Substitute.For<ILogger<WslHelper>>())), new WslHelper(Substitute.For<ILogger<WslHelper>>())),
123-
Substitute.For<IStatusService>(), new FilePickerService());
117+
var vm = RepositoryEditorViewModel.ForNew(CreateFactory(), new FilePickerService());
124118
vm.Repository.IsLocal = true;
125119
vm.Repository.Name = "Test";
126120
vm.RepoPath = "/data/borg";
@@ -134,9 +128,7 @@ public void Save_ValidLocal_SetsSaved()
134128
[Fact]
135129
public void Save_AppliesSourceDirectories()
136130
{
137-
var vm = RepositoryEditorViewModel.ForNew(
138-
new BorgServiceFactory(Substitute.For<ILoggerFactory>(), new AppSettings(), new SshAgentHelper(Substitute.For<ILogger<SshAgentHelper>>(), null, new WslHelper(Substitute.For<ILogger<WslHelper>>())), new WslHelper(Substitute.For<ILogger<WslHelper>>())),
139-
Substitute.For<IStatusService>(), new FilePickerService());
131+
var vm = RepositoryEditorViewModel.ForNew(CreateFactory(), new FilePickerService());
140132
vm.Repository.IsLocal = true;
141133
vm.Repository.Name = "Test";
142134
vm.RepoPath = "/data/borg";
@@ -151,9 +143,7 @@ public void Save_AppliesSourceDirectories()
151143
[Fact]
152144
public void Save_AppliesSchedule()
153145
{
154-
var vm = RepositoryEditorViewModel.ForNew(
155-
new BorgServiceFactory(Substitute.For<ILoggerFactory>(), new AppSettings(), new SshAgentHelper(Substitute.For<ILogger<SshAgentHelper>>(), null, new WslHelper(Substitute.For<ILogger<WslHelper>>())), new WslHelper(Substitute.For<ILogger<WslHelper>>())),
156-
Substitute.For<IStatusService>(), new FilePickerService());
146+
var vm = RepositoryEditorViewModel.ForNew(CreateFactory(), new FilePickerService());
157147
vm.Repository.IsLocal = true;
158148
vm.Repository.Name = "Test";
159149
vm.RepoPath = "/data/borg";
@@ -172,10 +162,7 @@ public void Save_AppliesSchedule()
172162
[Fact]
173163
public void Save_WithNoName_SetsNameError()
174164
{
175-
var vm = RepositoryEditorViewModel.ForNew(
176-
new BorgServiceFactory(Substitute.For<ILoggerFactory>(), new AppSettings(), new SshAgentHelper(Substitute.For<ILogger<SshAgentHelper>>(), null, new WslHelper(Substitute.For<ILogger<WslHelper>>())), new WslHelper(Substitute.For<ILogger<WslHelper>>())),
177-
Substitute.For<IStatusService>(),
178-
new FilePickerService());
165+
var vm = RepositoryEditorViewModel.ForNew(CreateFactory(), new FilePickerService());
179166
vm.Repository.IsLocal = true;
180167
vm.RepoPath = "/data/my-backups";
181168

BorgMate.Tests/RepositoryListViewModelTests.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ public class RepositoryListViewModelTests : IDisposable
1717
private static readonly SshAgentHelper SshAgent = new(Substitute.For<ILogger<SshAgentHelper>>(), null, Wsl);
1818

1919
private readonly IConfigService _configService = Substitute.For<IConfigService>();
20-
private readonly IStatusService _statusService = Substitute.For<IStatusService>();
2120
private readonly IJournalService _journalService = Substitute.For<IJournalService>();
2221
private readonly JobQueueService _jobQueue = new();
2322

@@ -30,7 +29,7 @@ private RepositoryListViewModel CreateVm()
3029
Substitute.For<ILogger<BorgOperationRunner>>(), _jobQueue, _journalService, passphrase);
3130
var logger = Substitute.For<ILogger<RepositoryListViewModel>>();
3231
var sizeCalculator = new DirectorySizeCalculator(Substitute.For<ILogger<DirectorySizeCalculator>>());
33-
return new RepositoryListViewModel(borgFactory, _configService, _statusService, filePicker,
32+
return new RepositoryListViewModel(borgFactory, _configService, filePicker,
3433
_journalService, runner, passphrase, Wsl, sizeCalculator, _jobQueue, logger);
3534
}
3635

BorgMate/Localization/Resources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,9 @@
217217
<data name="SelectArchiveDetail" xml:space="preserve">
218218
<value>Select an archive</value>
219219
</data>
220+
<data name="SelectNotificationDetail" xml:space="preserve">
221+
<value>Select a notification</value>
222+
</data>
220223
<data name="General" xml:space="preserve">
221224
<value>General</value>
222225
</data>

BorgMate/Localization/Resources.ru.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,9 @@
217217
<data name="SelectArchiveDetail" xml:space="preserve">
218218
<value>Выберите архив</value>
219219
</data>
220+
<data name="SelectNotificationDetail" xml:space="preserve">
221+
<value>Выберите уведомление</value>
222+
</data>
220223
<data name="General" xml:space="preserve">
221224
<value>Основное</value>
222225
</data>

BorgMate/Services/Borg/BorgOperationRunner.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ private void OnPassphraseFailed(BorgRepository repo)
117117
jobQueue.CancelPendingByRepoPath(repo.Path);
118118
var entry = journalService.Add(
119119
JournalEventKind.PassphraseFailed, [repo.Name], repo.Name);
120-
journalService.Complete(entry, JournalResult.Failed);
120+
journalService.Complete(entry, JournalResult.Failed, Strings.Get("Error.WrongPassphrase"));
121121
});
122122
}
123123
}

BorgMate/Services/Config/IStatusService.cs

Lines changed: 0 additions & 10 deletions
This file was deleted.

BorgMate/Services/Config/StatusService.cs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace BorgMate.Services.Config;
77

8-
public partial class StatusService : ObservableObject, IStatusService
8+
public partial class StatusService : ObservableObject
99
{
1010
[ObservableProperty]
1111
private string? _updateMessage;
@@ -18,18 +18,6 @@ public partial class StatusService : ObservableObject, IStatusService
1818

1919
private Func<Task>? _updateAction;
2020

21-
public async void SetError(string message)
22-
{
23-
try { await DialogHelper.ErrorAsync(message); }
24-
catch (Exception ex) { Console.Error.WriteLine($"Failed to show error dialog: {ex.Message}"); }
25-
}
26-
27-
public async void SetError(string message, string repoName, string repoPath)
28-
{
29-
try { await DialogHelper.ErrorAsync(message, repoName, repoPath); }
30-
catch (Exception ex) { Console.Error.WriteLine($"Failed to show error dialog: {ex.Message}"); }
31-
}
32-
3321
public void SetUpdateAvailable(string message, Func<Task> action)
3422
{
3523
UpdateMessage = message;

BorgMate/Services/ServiceCollectionExtensions.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ public static ServiceProvider ConfigureBorgMateServices(this ServiceCollection s
6262
services.AddSingleton<ISchedulerService, SchedulerService>();
6363
}
6464
services.AddSingleton<StatusService>();
65-
services.AddSingleton<IStatusService>(sp => sp.GetRequiredService<StatusService>());
6665
if (OperatingSystem.IsMacOS())
6766
services.AddSingleton<IFilePickerService, MacOsFilePickerService>();
6867
else

0 commit comments

Comments
 (0)