diff --git a/public/index.html b/public/index.html
index ec120e5..26f82a5 100644
--- a/public/index.html
+++ b/public/index.html
@@ -809,6 +809,37 @@
Execution History
+
+
+
+
+
+
+ 🔍 Search:
+
+
+
+
+
+ 📊 Status Filter:
+
+ All Statuses
+ Running
+ Completed
+ Failed
+ Waiting
+
+
+
+
+
+ [ Clear Filters ]
+
+
+
+
[ 🔄 Refresh ]
[ 🗑️ Clear Completed ]
@@ -920,6 +951,7 @@
let currentUser = null;
let ws = null;
let workers = [];
+ let allExecutions = []; // Store all loaded executions for filtering
async function loadUser() {
try {
@@ -1080,6 +1112,13 @@
const data = await response.json();
const executions = data.executions || data; // Handle old and new API format
+ // Store executions for filtering
+ if (append) {
+ allExecutions = allExecutions.concat(executions);
+ } else {
+ allExecutions = executions;
+ }
+
// Dashboard view (always first 5)
if (!append) {
const dashHtml = executions.length === 0 ?
@@ -1094,25 +1133,8 @@
document.getElementById('dashExecutions').innerHTML = dashHtml;
}
- // Full execution list
- const fullHtml = executions.length === 0 ?
- '
No executions yet
' :
- executions.map(e => `
-
-
${e.status}
-
${e.workflow_name || '[Quick Command]'}
-
- Started by ${e.started_by} at ${new Date(e.started_at).toLocaleString()}
- ${e.completed_at ? ` • Completed at ${new Date(e.completed_at).toLocaleString()}` : ''}
-
-
- `).join('');
-
- if (append) {
- document.getElementById('executionList').innerHTML += fullHtml;
- } else {
- document.getElementById('executionList').innerHTML = fullHtml;
- }
+ // Apply filters and render
+ renderFilteredExecutions();
// Add "Load More" button if there are more executions
if (data.hasMore) {
@@ -1125,6 +1147,78 @@
}
}
+ function renderFilteredExecutions() {
+ const searchTerm = (document.getElementById('executionSearch')?.value || '').toLowerCase();
+ const statusFilter = document.getElementById('statusFilter')?.value || '';
+
+ // Filter executions
+ let filtered = allExecutions.filter(e => {
+ // Status filter
+ if (statusFilter && e.status !== statusFilter) return false;
+
+ // Search filter (search in workflow name, execution ID, and logs)
+ if (searchTerm) {
+ const workflowName = (e.workflow_name || '[Quick Command]').toLowerCase();
+ const executionId = e.id.toLowerCase();
+
+ // Try to extract command from logs if it's a quick command
+ let commandText = '';
+ try {
+ const logs = typeof e.logs === 'string' ? JSON.parse(e.logs) : e.logs;
+ if (logs && logs.length > 0 && logs[0].command) {
+ commandText = logs[0].command.toLowerCase();
+ }
+ } catch (err) {
+ // Ignore parsing errors
+ }
+
+ const matchFound = workflowName.includes(searchTerm) ||
+ executionId.includes(searchTerm) ||
+ commandText.includes(searchTerm);
+
+ if (!matchFound) return false;
+ }
+
+ return true;
+ });
+
+ // Update filter stats
+ const statsEl = document.getElementById('filterStats');
+ if (statsEl) {
+ if (searchTerm || statusFilter) {
+ statsEl.textContent = `Showing ${filtered.length} of ${allExecutions.length} executions`;
+ } else {
+ statsEl.textContent = '';
+ }
+ }
+
+ // Render filtered results
+ const fullHtml = filtered.length === 0 ?
+ '
No executions match your filters
' :
+ filtered.map(e => `
+
+
${e.status}
+
${e.workflow_name || '[Quick Command]'}
+
+ Started by ${e.started_by} at ${new Date(e.started_at).toLocaleString()}
+ ${e.completed_at ? ` • Completed at ${new Date(e.completed_at).toLocaleString()}` : ''}
+
+
+ `).join('');
+
+ document.getElementById('executionList').innerHTML = fullHtml;
+ }
+
+ function filterExecutions() {
+ renderFilteredExecutions();
+ }
+
+ function clearFilters() {
+ document.getElementById('executionSearch').value = '';
+ document.getElementById('statusFilter').value = '';
+ renderFilteredExecutions();
+ }
+
async function loadMoreExecutions() {
executionOffset += executionLimit;
await loadExecutions(true);