Skip to content

Commit 29e02d7

Browse files
odedha-drclaude
andcommitted
feat: reverse turns order (newest first) and add search filter
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent a08fa35 commit 29e02d7

File tree

1 file changed

+45
-4
lines changed

1 file changed

+45
-4
lines changed

src/web/public/index.html

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,6 +1422,7 @@ <h3>Cost Breakdown</h3>
14221422
let expandedThinking = new Set();
14231423
let expandedToolInputs = new Set();
14241424
let expandedOutputs = new Set();
1425+
let turnsSearchQuery = '';
14251426

14261427
function fmtTime(iso) {
14271428
if (!iso) return '';
@@ -1451,15 +1452,43 @@ <h3>Cost Breakdown</h3>
14511452
const d = selectedDetail;
14521453
if (!d) return;
14531454

1454-
const turns = d.turns || [];
1455-
if (turns.length === 0) {
1455+
const allTurns = d.turns || [];
1456+
if (allTurns.length === 0) {
14561457
document.getElementById('tab-turns').innerHTML =
14571458
'<div style="padding:20px;text-align:center;color:var(--text-muted)">No turns in this session.</div>';
14581459
return;
14591460
}
14601461

1461-
let html = '<div class="turn-list">';
1462-
turns.forEach((t, idx) => {
1462+
// Filter by search query
1463+
const query = turnsSearchQuery.toLowerCase();
1464+
const turns = query
1465+
? allTurns.filter(t => {
1466+
// Search in text content, tool names, tool inputs, and results
1467+
for (const c of (t.content || [])) {
1468+
if (c.text && c.text.toLowerCase().includes(query)) return true;
1469+
if (c.toolName && c.toolName.toLowerCase().includes(query)) return true;
1470+
if (c.toolInput && JSON.stringify(c.toolInput).toLowerCase().includes(query)) return true;
1471+
if (c.toolResult) {
1472+
if (c.toolResult.stdout && c.toolResult.stdout.toLowerCase().includes(query)) return true;
1473+
if (c.toolResult.stderr && c.toolResult.stderr.toLowerCase().includes(query)) return true;
1474+
}
1475+
}
1476+
if (t.toolCalls && t.toolCalls.some(tc => tc.toLowerCase().includes(query))) return true;
1477+
return false;
1478+
})
1479+
: allTurns;
1480+
1481+
// Reverse: newest first
1482+
const reversed = [...turns].reverse();
1483+
1484+
let html = '';
1485+
html += `<div class="turns-search" style="padding:8px 12px;border-bottom:1px solid var(--border-color);">`;
1486+
html += `<input type="text" id="turns-search-input" placeholder="Search turns..." value="${escHtml(turnsSearchQuery)}" style="width:100%;padding:6px 10px;border:1px solid var(--border-color);border-radius:6px;background:var(--bg-secondary);color:var(--text-primary);font-size:13px;">`;
1487+
if (query) html += `<div style="font-size:11px;color:var(--text-muted);margin-top:4px;">${turns.length} of ${allTurns.length} turns match</div>`;
1488+
html += `</div>`;
1489+
1490+
html += '<div class="turn-list">';
1491+
reversed.forEach((t, idx) => {
14631492
const isExpanded = expandedTurns.has(t.number);
14641493
const roleClass = t.role === 'user' ? 'role-user' : 'role-assistant';
14651494
const durClass = durationClass(t.durationMs);
@@ -1634,6 +1663,18 @@ <h3>Cost Breakdown</h3>
16341663
renderTurns();
16351664
});
16361665
});
1666+
1667+
// Search input
1668+
const searchInput = document.getElementById('turns-search-input');
1669+
if (searchInput) {
1670+
searchInput.addEventListener('input', (e) => {
1671+
turnsSearchQuery = e.target.value;
1672+
renderTurns();
1673+
// Re-focus and restore cursor position
1674+
const el = document.getElementById('turns-search-input');
1675+
if (el) { el.focus(); el.selectionStart = el.selectionEnd = el.value.length; }
1676+
});
1677+
}
16371678
}
16381679

16391680
// ---- Tools Tab ----

0 commit comments

Comments
 (0)