import { useState, useEffect } from 'react'; import { workbenchStore } from '~/lib/stores/workbench'; import { classNames } from '~/utils/classNames'; import { Checkbox } from '~/components/ui/Checkbox'; import { toast } from '~/components/ui/use-toast'; interface LockedItem { path: string; type: 'file' | 'folder'; } export function LockManager() { const [lockedItems, setLockedItems] = useState([]); const [selectedItems, setSelectedItems] = useState>(new Set()); const [filter, setFilter] = useState<'all' | 'files' | 'folders'>('all'); const [searchTerm, setSearchTerm] = useState(''); // Load locked items useEffect(() => { const loadLockedItems = () => { // We don't need to filter by chat ID here as we want to show all locked files const items: LockedItem[] = []; // Get all files and folders from the workbench store const allFiles = workbenchStore.files.get(); // Check each file/folder for locks Object.entries(allFiles).forEach(([path, item]) => { if (!item) { return; } if (item.type === 'file' && item.isLocked) { items.push({ path, type: 'file', }); } else if (item.type === 'folder' && item.isLocked) { items.push({ path, type: 'folder', }); } }); setLockedItems(items); }; loadLockedItems(); // Set up an interval to refresh the list periodically const intervalId = setInterval(loadLockedItems, 5000); return () => clearInterval(intervalId); }, []); // Filter and sort the locked items const filteredAndSortedItems = lockedItems .filter((item) => { // Apply type filter if (filter === 'files' && item.type !== 'file') { return false; } if (filter === 'folders' && item.type !== 'folder') { return false; } // Apply search filter if (searchTerm && !item.path.toLowerCase().includes(searchTerm.toLowerCase())) { return false; } return true; }) .sort((a, b) => { return a.path.localeCompare(b.path); }); // Handle selecting/deselecting a single item const handleSelectItem = (path: string) => { const newSelectedItems = new Set(selectedItems); if (newSelectedItems.has(path)) { newSelectedItems.delete(path); } else { newSelectedItems.add(path); } setSelectedItems(newSelectedItems); }; // Handle selecting/deselecting all visible items const handleSelectAll = (checked: boolean | 'indeterminate') => { if (checked === true) { // Select all filtered items const allVisiblePaths = new Set(filteredAndSortedItems.map((item) => item.path)); setSelectedItems(allVisiblePaths); } else { // Deselect all (clear selection) setSelectedItems(new Set()); } }; // Handle unlocking selected items const handleUnlockSelected = () => { if (selectedItems.size === 0) { toast.error('No items selected to unlock.'); return; } let unlockedCount = 0; selectedItems.forEach((path) => { const item = lockedItems.find((i) => i.path === path); if (item) { if (item.type === 'file') { workbenchStore.unlockFile(path); } else { workbenchStore.unlockFolder(path); } unlockedCount++; } }); if (unlockedCount > 0) { toast.success(`Unlocked ${unlockedCount} selected item(s).`); setSelectedItems(new Set()); // Clear selection after unlocking } }; // Determine the state of the "Select All" checkbox const isAllSelected = filteredAndSortedItems.length > 0 && selectedItems.size === filteredAndSortedItems.length; const isSomeSelected = selectedItems.size > 0 && selectedItems.size < filteredAndSortedItems.length; const selectAllCheckedState: boolean | 'indeterminate' = isAllSelected ? true : isSomeSelected ? 'indeterminate' : false; return (
{/* Controls */}
{/* Search Input */}
setSearchTerm(e.target.value)} style={{ minWidth: 0 }} />
{/* Filter Select */}
{/* Header Row with Select All */}
All
{selectedItems.size > 0 && ( )}
{/* List of locked items */}
{filteredAndSortedItems.length === 0 ? (
No locked items found
) : (
    {filteredAndSortedItems.map((item) => (
  • handleSelectItem(item.path)} className="w-3 h-3 rounded border-bolt-elements-borderColor" aria-labelledby={`item-label-${item.path}`} // For accessibility /> {item.path.replace('/home/project/', '')} {/* ... rest of the item details and buttons ... */}
  • ))}
)}
{/* Footer */}
{filteredAndSortedItems.length} item(s) • {selectedItems.size} selected
); }