From 64c2db06c1f0dd7abe570334074d36465b3ce664 Mon Sep 17 00:00:00 2001 From: Pawel Date: Thu, 16 Apr 2026 16:26:16 +0300 Subject: [PATCH] feat: add message sort toggle in session drawer + default setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extract message rendering into renderDetailMessages() in detail.js - Add ↑/↓ sort toggle button in Conversation header - toggleMsgSort() flips order without re-fetching (uses cached _detailMessages) - Settings page: new "Message Sort Order" option (Oldest/Newest first) - Persisted in localStorage key codedash-msg-sort, default: asc --- src/frontend/app.js | 13 ++++++++ src/frontend/detail.js | 68 +++++++++++++++++++++++++++--------------- 2 files changed, 57 insertions(+), 24 deletions(-) diff --git a/src/frontend/app.js b/src/frontend/app.js index 38bd8bf..8d79b3d 100644 --- a/src/frontend/app.js +++ b/src/frontend/app.js @@ -1658,6 +1658,19 @@ function renderSettings(container) { html += '

Applies to grouped session views like All Sessions and Claude Code. Projects always stay repository-based.

'; html += ''; + // Message Sort Order + var savedMsgSort = localStorage.getItem('codedash-msg-sort') || 'asc'; + html += '
'; + html += ''; + html += '

Default order for messages in session drawer

'; + html += '
'; + [['asc', '↑ Oldest first'], ['desc', '↓ Newest first']].forEach(function(pair) { + var active = savedMsgSort === pair[0] ? ' active' : ''; + html += ''; + }); + html += '
'; + html += '
'; + // LLM Configuration html += '
'; html += ''; diff --git a/src/frontend/detail.js b/src/frontend/detail.js index 8555320..0f2ef85 100644 --- a/src/frontend/detail.js +++ b/src/frontend/detail.js @@ -101,30 +101,8 @@ async function openDetail(s) { var data = await resp.json(); var msgContainer = body.querySelector('.detail-messages'); if (data.messages && data.messages.length > 0) { - var msgsHtml = '

Conversation

'; - data.messages.forEach(function(m) { - var roleClass = m.role === 'user' ? 'msg-user' : 'msg-assistant'; - var roleLabel = m.role === 'user' ? 'You' : 'Assistant'; - var hasTools = m.tools && m.tools.length > 0; - msgsHtml += '
'; - msgsHtml += '
'; - msgsHtml += '
' + roleLabel + '
'; - msgsHtml += '
' + escHtml(m.content) + '
'; - msgsHtml += '
'; - if (hasTools) { - msgsHtml += '
'; - m.tools.forEach(function(t) { - if (t.type === 'mcp') { - msgsHtml += '' + escHtml(t.tool) + ''; - } else if (t.type === 'skill') { - msgsHtml += '' + escHtml(t.skill) + ''; - } - }); - msgsHtml += '
'; - } - msgsHtml += '
'; - }); - msgContainer.innerHTML = msgsHtml; + window._detailMessages = data.messages; + renderDetailMessages(msgContainer, data.messages); } else { msgContainer.innerHTML = '
No messages found in detail file.
'; } @@ -206,6 +184,48 @@ function closeDetail() { if (overlay) overlay.classList.remove('open'); } +function renderDetailMessages(container, messages) { + var sort = localStorage.getItem('codedash-msg-sort') || 'asc'; + var sorted = sort === 'desc' ? messages.slice().reverse() : messages; + var btnLabel = sort === 'asc' ? '↑ Oldest first' : '↓ Newest first'; + var msgsHtml = '
'; + msgsHtml += '

Conversation

'; + msgsHtml += ''; + msgsHtml += '
'; + sorted.forEach(function(m) { + var roleClass = m.role === 'user' ? 'msg-user' : 'msg-assistant'; + var roleLabel = m.role === 'user' ? 'You' : 'Assistant'; + var hasTools = m.tools && m.tools.length > 0; + msgsHtml += '
'; + msgsHtml += '
'; + msgsHtml += '
' + roleLabel + '
'; + msgsHtml += '
' + escHtml(m.content) + '
'; + msgsHtml += '
'; + if (hasTools) { + msgsHtml += '
'; + m.tools.forEach(function(t) { + if (t.type === 'mcp') { + msgsHtml += '' + escHtml(t.tool) + ''; + } else if (t.type === 'skill') { + msgsHtml += '' + escHtml(t.skill) + ''; + } + }); + msgsHtml += '
'; + } + msgsHtml += '
'; + }); + container.innerHTML = msgsHtml; +} + +function toggleMsgSort() { + var current = localStorage.getItem('codedash-msg-sort') || 'asc'; + localStorage.setItem('codedash-msg-sort', current === 'asc' ? 'desc' : 'asc'); + var container = document.querySelector('.detail-messages'); + if (container && window._detailMessages) { + renderDetailMessages(container, window._detailMessages); + } +} + // ── Detail panel resize ─────────────────────────────────────── (function initDetailResize() { var handle = document.getElementById('detailResizeHandle');