fix: dashboard project tree rendering and session selection

- Use data-project attribute instead of index for project identification
- Fix toggleProject to use nextElementSibling for content panel
- Highlight selected session without re-rendering tree
- Add selected-session CSS class

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-06-26 15:10:57 +08:00
parent 63aedf52d7
commit e53113db55
2 changed files with 13 additions and 5 deletions
+8 -5
View File
@@ -79,28 +79,29 @@
return; return;
} }
tree.innerHTML = filtered.map(p => ` tree.innerHTML = filtered.map((p, idx) => `
<div class="mb-2"> <div class="mb-2">
<div class="collapse-header ${currentProject === p.project_name ? 'open' : ''}" <div class="collapse-header ${currentProject === p.project_name ? 'open' : ''}"
onclick="toggleProject(this, '${escapeHtml(p.project_name)}')"> onclick="toggleProject(this)" data-project="${escapeHtml(p.project_name)}">
<span class="collapse-arrow">▶</span> <span class="collapse-arrow">▶</span>
<span class="text-sm font-medium">${escapeHtml(p.project_name)}</span> <span class="text-sm font-medium">${escapeHtml(p.project_name)}</span>
<span class="text-xs text-muted ml-auto">${p.session_count}</span> <span class="text-xs text-muted ml-auto">${p.session_count}</span>
</div> </div>
<div class="collapse-content ${currentProject === p.project_name ? 'open' : ''}" <div class="collapse-content ${currentProject === p.project_name ? 'open' : ''}"
id="project-${escapeHtml(p.project_name).replace(/[^a-zA-Z0-9]/g, '_')}"> id="project-${idx}">
<div class="sessions-container text-sm text-muted">加载中...</div> <div class="sessions-container text-sm text-muted">加载中...</div>
</div> </div>
</div> </div>
`).join(''); `).join('');
} }
async function toggleProject(header, projectName) { async function toggleProject(header) {
header.classList.toggle('open'); header.classList.toggle('open');
const content = header.nextElementSibling; const content = header.nextElementSibling;
content.classList.toggle('open'); content.classList.toggle('open');
if (content.classList.contains('open')) { if (content.classList.contains('open')) {
const projectName = header.getAttribute('data-project');
currentProject = projectName; currentProject = projectName;
await loadSessions(projectName, content.querySelector('.sessions-container')); await loadSessions(projectName, content.querySelector('.sessions-container'));
} }
@@ -130,7 +131,9 @@
async function selectSession(sessionId, projectName) { async function selectSession(sessionId, projectName) {
currentSession = sessionId; currentSession = sessionId;
currentProject = projectName; currentProject = projectName;
renderProjectTree(); // Re-render to highlight // Update highlight without re-rendering the whole tree
document.querySelectorAll('.sessions-container .selected-session').forEach(el => el.classList.remove('selected-session'));
event.currentTarget.classList.add('selected-session');
try { try {
const data = await API.get(`/api/dashboard/prompts?session_id=${encodeURIComponent(sessionId)}&page_size=50`); const data = await API.get(`/api/dashboard/prompts?session_id=${encodeURIComponent(sessionId)}&page_size=50`);
+5
View File
@@ -406,3 +406,8 @@ body {
.w-full { width: 100%; } .w-full { width: 100%; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hidden { display: none !important; } .hidden { display: none !important; }
.selected-session {
background: var(--bg-tertiary) !important;
border-left: 3px solid var(--accent-color);
}