Files
ClaudeDo/src/ClaudeDo.Ui/Views/MissionControl/MissionControlView.axaml.cs
T
mika kuns 3feb08d9d9 feat(interactive): New session button for ad-hoc ConPTY sessions
Adds a 'New session' header button in Mission Control that opens a folder picker
and starts a task-less embedded ConPTY session in the chosen directory. ConPtyPaneViewModel
TaskId is now nullable (ad-hoc panes have no task and are never deduped) with a
CreateAdHoc factory; the view does the picking, the VM stays picker-agnostic.
2026-07-23 16:47:15 +02:00

69 lines
2.4 KiB
C#

using System.Linq;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
using Avalonia.VisualTree;
using ClaudeDo.Ui.ViewModels;
using ClaudeDo.Ui.ViewModels.Islands;
namespace ClaudeDo.Ui.Views.MissionControl;
public partial class MissionControlView : UserControl
{
// Shared with MonitorPaneView (the drag source).
public static readonly DataFormat<string> PaneFormat =
DataFormat.CreateStringApplicationFormat("claudedo-monitor-pane");
public MissionControlView()
{
InitializeComponent();
AddHandler(DragDrop.DragOverEvent, OnPaneDragOver);
AddHandler(DragDrop.DropEvent, OnPaneDrop);
}
// Ad-hoc ConPTY session: the view owns the folder picker, the VM only takes the chosen path.
private async void OnNewSessionClicked(object? sender, RoutedEventArgs e)
{
if (DataContext is not MissionControlViewModel vm) return;
var topLevel = TopLevel.GetTopLevel(this);
if (topLevel is null) return;
var folders = await topLevel.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{
Title = "Choose a directory",
AllowMultiple = false,
});
if (folders.Count == 0) return;
await vm.OpenAdHocConPtySessionAsync(folders[0].Path.LocalPath);
}
private void OnPaneDragOver(object? sender, DragEventArgs e)
{
var dt = e.DataTransfer;
e.DragEffects = (dt?.Contains(PaneFormat) ?? false) ? DragDropEffects.Move : DragDropEffects.None;
}
private void OnPaneDrop(object? sender, DragEventArgs e)
{
if (DataContext is not MissionControlViewModel vm) return;
var dt = e.DataTransfer;
if (dt is null) return;
// A pane dragged within the grid → reorder. (Drag-to-queue from the main app now arrives
// via the custom ghost drag's screen hit-test, not an OLE drop.)
var draggedId = dt.TryGetValue(PaneFormat);
if (string.IsNullOrEmpty(draggedId)) return;
if (e.Source is not Avalonia.Visual src) return;
var targetPane = src.FindAncestorOfType<MonitorPaneView>();
if (targetPane?.DataContext is not TaskMonitorViewModel target) return;
var dragged = vm.Monitors.FirstOrDefault(m => m.SubscribedTaskId == draggedId);
if (dragged is null) return;
vm.MoveMonitor(dragged, target);
}
}