fix(ui): gate Mission Control submit-for-review, add retry, fix event leak
Submit for Review is now disabled while a ConPTY pane is starting, has failed to launch, or has already exited, and MissionControlViewModel guards against a rapid double-click racing two SubmitTaskForReviewAsync calls. A failed launch no longer permanently occupies its TaskId dedupe slot -- a Retry button re-fetches the launch spec and restarts the pane in place. CloseConPtySession/Dispose now also unsubscribe SubmitForReviewRequested, matching the other pane event handlers. Also fixes the pre-existing nullable-dereference warning in IslandsShellViewModel.SyncInteractiveSessionChips.
This commit is contained in:
@@ -20,7 +20,11 @@ public sealed partial class ConPtyPaneViewModel : ViewModelBase, IMissionControl
|
||||
|
||||
[ObservableProperty] private string _displayTitle;
|
||||
|
||||
public InteractiveTerminalViewModel Terminal { get; } = new();
|
||||
[ObservableProperty] private InteractiveTerminalViewModel _terminal = new();
|
||||
|
||||
/// <summary>Set by the host (Mission Control) while a submit-for-review round trip is in
|
||||
/// flight, so a rapid double-click can't race two submissions for the same task.</summary>
|
||||
[ObservableProperty] private bool _isSubmitPending;
|
||||
|
||||
/// <summary>Raised when the terminal failed to start — the host surfaces this via the footer error strip.</summary>
|
||||
public event Action<string>? ErrorReported;
|
||||
@@ -76,12 +80,21 @@ public sealed partial class ConPtyPaneViewModel : ViewModelBase, IMissionControl
|
||||
{
|
||||
if (e.PropertyName == nameof(InteractiveTerminalViewModel.StartError) && Terminal.StartError is { Length: > 0 } error)
|
||||
ErrorReported?.Invoke(error);
|
||||
|
||||
if (e.PropertyName is nameof(InteractiveTerminalViewModel.IsStarting)
|
||||
or nameof(InteractiveTerminalViewModel.StartError)
|
||||
or nameof(InteractiveTerminalViewModel.HasExited))
|
||||
{
|
||||
SubmitForReviewCommand.NotifyCanExecuteChanged();
|
||||
RetryCommand.NotifyCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void Close() => CloseRequested?.Invoke(this);
|
||||
|
||||
private bool CanSubmitForReview() => IsTaskBased;
|
||||
private bool CanSubmitForReview() =>
|
||||
IsTaskBased && !IsSubmitPending && !Terminal.IsStarting && Terminal.StartError is null && !Terminal.HasExited;
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanSubmitForReview))]
|
||||
private void SubmitForReview()
|
||||
@@ -89,6 +102,22 @@ public sealed partial class ConPtyPaneViewModel : ViewModelBase, IMissionControl
|
||||
if (TaskId is { } id) SubmitForReviewRequested?.Invoke(id);
|
||||
}
|
||||
|
||||
partial void OnIsSubmitPendingChanged(bool value) => SubmitForReviewCommand.NotifyCanExecuteChanged();
|
||||
|
||||
// A launch failure permanently occupies the TaskId dedupe slot unless the user can retry —
|
||||
// re-opening the same task would otherwise just re-focus a dead tile.
|
||||
private bool CanRetry() => Terminal.HasExited && Terminal.StartError is not null;
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanRetry))]
|
||||
private void Retry()
|
||||
{
|
||||
Terminal.PropertyChanged -= OnTerminalPropertyChanged;
|
||||
Terminal.Dispose();
|
||||
Terminal = new InteractiveTerminalViewModel();
|
||||
Terminal.PropertyChanged += OnTerminalPropertyChanged;
|
||||
Start();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Terminal.PropertyChanged -= OnTerminalPropertyChanged;
|
||||
|
||||
Reference in New Issue
Block a user