feat(ui): Mission-Control-Kacheln behalten Position und Identitaetsfarbe ueber Handoffs

Ein Handoff schloss die alte Pane und haengte die neue hinten an -- die Kachel
sprang ans Ende und das ganze Grid ordnete sich neu. Die neue Pane wird jetzt am
Index der alten eingesetzt.

Dazu bekommt jede Kachel eine aus IdentityKey (Default: TaskId) abgeleitete Farbe:
3px-Streifen links am Tile, Punkt im Focus-Mode-Tab. Kein State, keine Persistenz --
derselbe Task faerbt nach App-Neustart gleich, und ein Handoff erbt die Farbe, weil
er dieselbe TaskId behaelt. Nur kuehle Hues, damit nichts als Status gelesen wird.
This commit is contained in:
mika kuns
2026-09-28 08:56:50 +02:00
parent c9dd885fe0
commit e0a1448f44
6 changed files with 72 additions and 4 deletions
@@ -408,6 +408,11 @@ public sealed partial class MissionControlViewModel : ViewModelBase, IDisposable
if (string.IsNullOrEmpty(taskId) || survivingTaskIds is not { Count: > 0 }) return;
OpenRequested?.Invoke();
// Keep the tile where it was: the incoming phase re-enters at the outgoing pane's slot
// instead of being appended, so a handoff doesn't reshuffle every other tile in the grid.
var slot = ConPtySessions.FirstOrDefault(s => s.TaskId == taskId) is { } first
? ConPtySessions.IndexOf(first)
: (int?)null;
foreach (var stale in ConPtySessions.Where(s => s.TaskId == taskId).ToList())
CloseConPtySession(stale);
@@ -428,7 +433,7 @@ public sealed partial class MissionControlViewModel : ViewModelBase, IDisposable
AddConPtyPane(new ConPtyPaneViewModel(taskId, title,
() => DescribeAsync(() => _worker.GetMergeHelperHandoffLaunchSpecAsync(taskId, survivingTaskIds, nextPhase)))
{ IsListHandler = true });
{ IsListHandler = true }, slot);
}
// The 5h usage window is about to run out under this handler session: type the worker's warning
@@ -446,14 +451,14 @@ public sealed partial class MissionControlViewModel : ViewModelBase, IDisposable
// Wires a freshly built pane and shows it immediately — the pane resolves its own launch spec,
// so the tile is on screen (spinner running) while the worker is still preparing the worktree.
private void AddConPtyPane(ConPtyPaneViewModel pane)
private void AddConPtyPane(ConPtyPaneViewModel pane, int? index = null)
{
pane.ErrorReported += OnConPtyPaneError;
pane.CloseRequested += OnPaneCloseRequested;
pane.SubmitForReviewRequested += OnPaneSubmitForReview;
pane.SessionDiedAfterStartup += OnPaneSessionDied;
pane.AbandonRunRequested += OnPaneAbandonRun;
ConPtySessions.Add(pane);
ConPtySessions.Insert(Math.Min(index ?? ConPtySessions.Count, ConPtySessions.Count), pane);
pane.Start();
}