// CLI History View // Standalone view for CLI execution history with batch delete support // ========== Multi-Select State ========== var selectedExecutions = new Set(); var isMultiSelectMode = false; // ========== Rendering ========== async function renderCliHistoryView() { var container = document.getElementById('mainContent'); if (!container) return; // Hide stats grid and search for History view var statsGrid = document.getElementById('statsGrid'); var searchInput = document.getElementById('searchInput'); if (statsGrid) statsGrid.style.display = 'none'; if (searchInput) searchInput.parentElement.style.display = 'none'; // Load history data await loadCliHistory(); // Filter by search query var filteredHistory = cliHistorySearch ? cliExecutionHistory.filter(function(exec) { return exec.prompt_preview.toLowerCase().includes(cliHistorySearch.toLowerCase()) || exec.tool.toLowerCase().includes(cliHistorySearch.toLowerCase()); }) : cliExecutionHistory; var historyHtml = ''; if (cliExecutionHistory.length === 0) { historyHtml = '
' + '' + '

No executions yet

' + '

CLI execution history will appear here

' + '
'; } else if (filteredHistory.length === 0) { historyHtml = '
' + '' + '

No matching results

' + '

Try adjusting your search or filter

' + '
'; } else { historyHtml = '
'; for (var i = 0; i < filteredHistory.length; i++) { var exec = filteredHistory[i]; var statusIcon = exec.status === 'success' ? 'check-circle' : exec.status === 'timeout' ? 'clock' : 'x-circle'; var statusClass = exec.status === 'success' ? 'success' : exec.status === 'timeout' ? 'warning' : 'error'; var duration = formatDuration(exec.duration_ms); var timeAgo = getTimeAgo(new Date(exec.timestamp)); var isSelected = selectedExecutions.has(exec.id); // Turn count badge for multi-turn conversations var turnBadge = exec.turn_count && exec.turn_count > 1 ? ' ' + exec.turn_count + '' : ''; var sourceDirHtml = exec.sourceDir && exec.sourceDir !== '.' ? ' ' + escapeHtml(exec.sourceDir) + '' : ''; // Multi-select checkbox var checkboxHtml = isMultiSelectMode ? '
' + '' + '
' : ''; historyHtml += '
' + checkboxHtml + '
' + '
' + '' + exec.tool + '' + '' + (exec.mode || 'analysis') + '' + turnBadge + sourceDirHtml + '' + '' + exec.status + '' + '
' + '
' + escapeHtml(exec.prompt_preview) + '
' + '
' + ' ' + timeAgo + '' + ' ' + duration + '' + ' ' + exec.id.split('-')[0] + '' + '
' + '
' + '
' + '' + '' + '
' + '
'; } historyHtml += '
'; } // Build batch actions bar var batchActionsHtml = ''; if (isMultiSelectMode) { batchActionsHtml = '
' + '' + selectedExecutions.size + ' selected' + '' + '' + '' + '' + '
'; } container.innerHTML = '
' + '
' + '
' + '' + cliExecutionHistory.length + ' execution' + (cliExecutionHistory.length !== 1 ? 's' : '') + '' + '
' + '
' + '
' + '' + '' + '
' + '' + // Batch delete dropdown '
' + '' + '
' + '' + '' + '' + '' + '' + '' + '
' + '
' + '' + '
' + '
' + batchActionsHtml + historyHtml + '
'; // Initialize Lucide icons if (window.lucide) lucide.createIcons(); } // ========== Actions ========== async function filterCliHistoryView(tool) { cliHistoryFilter = tool || null; await loadCliHistory(); renderCliHistoryView(); } function searchCliHistoryView(query) { cliHistorySearch = query; renderCliHistoryView(); // Preserve focus and cursor position var searchInput = document.querySelector('.history-search-input'); if (searchInput) { searchInput.focus(); searchInput.setSelectionRange(query.length, query.length); } } async function refreshCliHistoryView() { await loadCliHistory(); renderCliHistoryView(); showRefreshToast('History refreshed', 'success'); } // ========== Multi-Select Functions ========== function toggleDeleteDropdown(event) { event.stopPropagation(); var menu = document.getElementById('deleteDropdownMenu'); if (menu) { menu.classList.toggle('show'); // Close on outside click if (menu.classList.contains('show')) { setTimeout(function() { document.addEventListener('click', closeDeleteDropdown); }, 0); } } } function closeDeleteDropdown() { var menu = document.getElementById('deleteDropdownMenu'); if (menu) menu.classList.remove('show'); document.removeEventListener('click', closeDeleteDropdown); } function enterMultiSelectMode() { closeDeleteDropdown(); isMultiSelectMode = true; selectedExecutions.clear(); renderCliHistoryView(); } function exitMultiSelectMode() { isMultiSelectMode = false; selectedExecutions.clear(); renderCliHistoryView(); } function toggleExecutionSelection(executionId) { if (selectedExecutions.has(executionId)) { selectedExecutions.delete(executionId); } else { selectedExecutions.add(executionId); } renderCliHistoryView(); } function selectAllExecutions() { var filteredHistory = cliHistorySearch ? cliExecutionHistory.filter(function(exec) { return exec.prompt_preview.toLowerCase().includes(cliHistorySearch.toLowerCase()) || exec.tool.toLowerCase().includes(cliHistorySearch.toLowerCase()); }) : cliExecutionHistory; filteredHistory.forEach(function(exec) { selectedExecutions.add(exec.id); }); renderCliHistoryView(); } function clearExecutionSelection() { selectedExecutions.clear(); renderCliHistoryView(); } // ========== Batch Delete Functions ========== function confirmBatchDelete() { var count = selectedExecutions.size; if (count === 0) return; if (confirm('Delete ' + count + ' selected execution' + (count > 1 ? 's' : '') + '? This action cannot be undone.')) { batchDeleteExecutions(Array.from(selectedExecutions)); } } function confirmDeleteByTool(tool) { closeDeleteDropdown(); var toolExecutions = cliExecutionHistory.filter(function(exec) { return exec.tool === tool; }); var count = toolExecutions.length; if (count === 0) { showRefreshToast('No ' + tool + ' executions to delete', 'info'); return; } if (confirm('Delete all ' + count + ' ' + tool + ' execution' + (count > 1 ? 's' : '') + '? This action cannot be undone.')) { var ids = toolExecutions.map(function(exec) { return exec.id; }); batchDeleteExecutions(ids); } } function confirmDeleteAll() { closeDeleteDropdown(); var count = cliExecutionHistory.length; if (count === 0) { showRefreshToast('No executions to delete', 'info'); return; } if (confirm('Delete ALL ' + count + ' execution' + (count > 1 ? 's' : '') + '? This action cannot be undone.')) { var ids = cliExecutionHistory.map(function(exec) { return exec.id; }); batchDeleteExecutions(ids); } } async function batchDeleteExecutions(ids) { showRefreshToast('Deleting ' + ids.length + ' executions...', 'info'); try { var response = await fetch('/api/cli/batch-delete', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ path: projectPath, ids: ids }) }); var result = await response.json(); if (result.success) { showRefreshToast('Deleted ' + result.deleted + ' execution' + (result.deleted > 1 ? 's' : ''), 'success'); // Exit multi-select mode and refresh isMultiSelectMode = false; selectedExecutions.clear(); await loadCliHistory(); renderCliHistoryView(); } else { showRefreshToast('Delete failed: ' + (result.error || 'Unknown error'), 'error'); } } catch (err) { console.error('Batch delete failed:', err); showRefreshToast('Delete failed: ' + err.message, 'error'); } }