MCPcopy
hub / github.com/stravu/crystal / handleSessionDrop

Function handleSessionDrop

frontend/src/components/DraggableProjectTreeView.tsx:1474–1661  ·  view source on GitHub ↗
(e: React.DragEvent, targetSession: Session, projectId: number)

Source from the content-addressed store, hash-verified

1472 };
1473
1474 const handleSessionDrop = async (e: React.DragEvent, targetSession: Session, projectId: number) => {
1475 e.preventDefault();
1476 e.stopPropagation();
1477
1478 const project = projectsWithSessions.find(p => p.id === projectId);
1479 if (!project) return;
1480
1481 // Handle both session-to-session and folder-to-session reordering
1482 if (dragState.type === 'session' &&
1483 dragState.sessionId &&
1484 dragState.projectId === projectId &&
1485 dragState.sessionId !== targetSession.id &&
1486 !targetSession.folderId && // Only reorder at root level
1487 !dragState.folderId) { // Only if dragged session is also at root level
1488
1489 // Get root-level items only (sessions and folders without parents)
1490 const rootSessions = project.sessions.filter(s => !s.folderId);
1491 const rootFolders = project.folders ? buildFolderTree(project.folders) : [];
1492
1493 // Find indices in the root-level combined list
1494 const sourceSessionIndex = rootSessions.findIndex(s => s.id === dragState.sessionId);
1495 const targetSessionIndex = rootSessions.findIndex(s => s.id === targetSession.id);
1496
1497 if (sourceSessionIndex !== -1 && targetSessionIndex !== -1) {
1498 // Update display orders for root sessions and folders together
1499 // Build a combined list with CURRENT displayOrder values, sorted by displayOrder
1500 type RootItem = { type: 'session' | 'folder'; id: string; displayOrder: number; createdAt: string; originalIndex: number };
1501 const rootItems: RootItem[] = [
1502 ...rootFolders.map((f, idx) => ({ type: 'folder' as const, id: f.id, displayOrder: f.displayOrder ?? 0, createdAt: f.createdAt, originalIndex: idx })),
1503 ...rootSessions.map((s, idx) => ({ type: 'session' as const, id: s.id, displayOrder: s.displayOrder ?? 0, createdAt: s.createdAt, originalIndex: idx }))
1504 ];
1505
1506 // Sort by current displayOrder to get the current visual order
1507 // Use createdAt as a tiebreaker to ensure stable sorting when displayOrder values are duplicated
1508 rootItems.sort((a, b) => {
1509 const orderDiff = a.displayOrder - b.displayOrder;
1510 if (orderDiff !== 0) return orderDiff;
1511 // If displayOrder is equal, sort by createdAt (older items first)
1512 return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
1513 });
1514
1515 // Find positions of source and target in the current order
1516 const sourceItemIndex = rootItems.findIndex(item => item.type === 'session' && item.id === dragState.sessionId);
1517 const targetItemIndex = rootItems.findIndex(item => item.type === 'session' && item.id === targetSession.id);
1518
1519 if (sourceItemIndex !== -1 && targetItemIndex !== -1) {
1520 // Remove the source item and insert it at the target position
1521 const [removedItem] = rootItems.splice(sourceItemIndex, 1);
1522 rootItems.splice(targetItemIndex, 0, removedItem);
1523
1524 // Reassign displayOrder values sequentially to reflect the new order
1525 rootItems.forEach((item, index) => {
1526 item.displayOrder = index;
1527 });
1528 }
1529
1530 // Prepare updates for API
1531 const sessionOrders = rootItems

Callers 2

renderFolderFunction · 0.85
DraggableProjectTreeViewFunction · 0.85

Calls 3

handleDragEndFunction · 0.85
reorderMethod · 0.80
errorMethod · 0.80

Tested by

no test coverage detected