chore(claude-do): merge fix(ui): Listen-Settings-Modal verschluckt Ladefehler nach d
ClaudeDo-Task: 9256fcfe-6cad-4350-a979-0c49cd5b9799
This commit is contained in:
@@ -58,6 +58,7 @@ public sealed partial class ListsIslandViewModel : ViewModelBase, IDisposable
|
||||
if (row is null || Dialogs is null || _services is null) return;
|
||||
var rawId = row.Id.StartsWith("user:", StringComparison.Ordinal) ? row.Id["user:".Length..] : row.Id;
|
||||
var vm = _services.GetRequiredService<ListSettingsModalViewModel>();
|
||||
vm.ErrorReported += msg => ErrorReported?.Invoke(msg);
|
||||
vm.BeginLoad(rawId, row.Name, row.WorkingDir, row.DefaultCommitType, row.IsManual, row.FindingsTracked, row.IconKey);
|
||||
await Dialogs.ShowListSettingsAsync(vm);
|
||||
if (vm.Deleted) await LoadAsync();
|
||||
@@ -408,6 +409,7 @@ public sealed partial class ListsIslandViewModel : ViewModelBase, IDisposable
|
||||
if (Dialogs is not null && _services is not null)
|
||||
{
|
||||
var vm = _services.GetRequiredService<ListSettingsModalViewModel>();
|
||||
vm.ErrorReported += msg => ErrorReported?.Invoke(msg);
|
||||
vm.BeginLoad(entity.Id, entity.Name, entity.WorkingDir, entity.DefaultCommitType, entity.IsManual, entity.FindingsTracked, entity.Icon);
|
||||
await Dialogs.ShowListSettingsAsync(vm);
|
||||
if (!vm.Saved && !vm.Deleted)
|
||||
|
||||
@@ -34,6 +34,9 @@ public sealed partial class ListSettingsModalViewModel : ViewModelBase
|
||||
public Func<string, Task<bool>>? ConfirmAsync { get; set; }
|
||||
public Func<string, Task>? ShowErrorAsync { get; set; }
|
||||
|
||||
// Mirrors UsageMonitorModalViewModel.ErrorReported — the caller wires this into FlashFooterError.
|
||||
public event Action<string>? ErrorReported;
|
||||
|
||||
[ObservableProperty] private string _name = "";
|
||||
[ObservableProperty] private string _workingDir = "";
|
||||
[ObservableProperty] private string _defaultCommitType = CommitTypeRegistry.DefaultType;
|
||||
@@ -65,6 +68,11 @@ public sealed partial class ListSettingsModalViewModel : ViewModelBase
|
||||
[NotifyCanExecuteChangedFor(nameof(DeleteCommand))]
|
||||
private bool _isLoading;
|
||||
|
||||
// Set when the core load (name/agent/verify command) threw — keeps Save gated even after
|
||||
// IsLoading resets to false in LoadAsync's finally, so a failed load can't clobber the
|
||||
// stored config with blank fields.
|
||||
private bool _loadFailed;
|
||||
|
||||
// True once GetTicketProjectsAsync has completed successfully for the current load — Save
|
||||
// only writes an explicit TicketProjectId when this is true, so a slow/unreachable ticket
|
||||
// system leaves the stored link untouched instead of wiping it to "none".
|
||||
@@ -128,8 +136,9 @@ public sealed partial class ListSettingsModalViewModel : ViewModelBase
|
||||
string? icon = null,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
ListConfigDto? cfg;
|
||||
ListConfigDto? cfg = null;
|
||||
IsLoading = true;
|
||||
_loadFailed = false;
|
||||
try
|
||||
{
|
||||
ListId = listId;
|
||||
@@ -147,8 +156,18 @@ public sealed partial class ListSettingsModalViewModel : ViewModelBase
|
||||
VerifyCommand = cfg?.VerifyCommand ?? "";
|
||||
PowerUseAllowed = cfg?.PowerUseAllowed ?? false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// BeginLoad fires this without awaiting it — catching here (instead of letting it
|
||||
// propagate) turns what would be an unobserved task exception, with the modal stuck
|
||||
// open and every field blank, into a reported error and a locked Save button.
|
||||
_loadFailed = true;
|
||||
ErrorReported?.Invoke(Loc.T("vm.listSettings.loadFailed", ex.Message));
|
||||
}
|
||||
finally { IsLoading = false; }
|
||||
|
||||
if (_loadFailed) return;
|
||||
|
||||
// Deliberately NOT awaited: an unreachable ticket system (10s HTTP timeout) must not hold
|
||||
// up the rest of the modal. The dropdown just stays empty until this finishes.
|
||||
_ = LoadTicketProjectsAsync(cfg?.TicketProjectId);
|
||||
@@ -179,15 +198,16 @@ public sealed partial class ListSettingsModalViewModel : ViewModelBase
|
||||
: TicketProjects[0];
|
||||
_ticketProjectsLoaded = true;
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Ticket system unreachable/slow — leave the dropdown as-is. Save's tri-state (below)
|
||||
// skips writing TicketProjectId when _ticketProjectsLoaded is false, so the stored
|
||||
// link survives instead of being wiped to "none".
|
||||
ErrorReported?.Invoke(Loc.T("vm.listSettings.ticketProjectsLoadFailed", ex.Message));
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanSave() => !IsLoading;
|
||||
private bool CanSave() => !IsLoading && !_loadFailed;
|
||||
private bool CanDelete() => !IsLoading;
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanSave))]
|
||||
|
||||
Reference in New Issue
Block a user