Dashboard: Session message counts, workspace path, Agent persona

This commit is contained in:
Meleki committed 2026-02-27 17:58:14 +01:00
1 parent 286a91204f
commit b1c1e462cc
9 files changed
+113 -15

No files matched your search

+1 -1
View File
@@ -26,7 +26,7 @@ public static class SessionEndpoint
private static async Task HandleList(HttpContext ctx, DatabaseService db)
{
var sessions = await db.GetSessions();
var sessions = await db.GetSessionsWithStats();
await ctx.Response.WriteAsJsonAsync(sessions);
}
+41
View File
@@ -214,6 +214,47 @@ public class DatabaseService
"SELECT * FROM sessions WHERE is_deleted = 0 ORDER BY updated_at DESC");
}
public async Task<IEnumerable<object>> GetSessionsWithStats()
{
using var conn = CreateConnection();
var sessions = await conn.QueryAsync<SessionRecord>(
"SELECT * FROM sessions WHERE is_deleted = 0 ORDER BY updated_at DESC");
var results = new List<object>();
foreach (var s in sessions)
{
var activeCount = await conn.ExecuteScalarAsync<int>(@"
SELECT COUNT(*) FROM messages m
JOIN chains c ON m.chain_id = c.chain_id
WHERE c.session_id = @sessionId AND c.archive_id IS NULL",
new { sessionId = s.SessionId });
var totalCount = await conn.ExecuteScalarAsync<int>(@"
SELECT COUNT(*) FROM messages m
JOIN chains c ON m.chain_id = c.chain_id
WHERE c.session_id = @sessionId",
new { sessionId = s.SessionId });
results.Add(new
{
s.SessionId,
s.Name,
s.Description,
s.Image,
s.AgentId,
s.Workspace,
s.Context,
s.CustomCommands,
s.IsDeleted,
s.CreatedAt,
s.UpdatedAt,
MessageCount = activeCount,
TotalMessageCount = totalCount
});
}
return results;
}
public async Task<SessionRecord> GetSession(string sessionId)
{
using var conn = CreateConnection();
+8 -2
View File
@@ -19,6 +19,10 @@ body, input, select, button, textarea {
color: var(--text);
}
input {
min-width: 0;
}
input, textarea, select {
padding: var(--s2);
}
@@ -55,6 +59,8 @@ button:disabled {
}
textarea {
height: 8em;
min-height: 8em;
height: 12em;
min-height: 12em;
max-height: 12em;
resize: none;
}
+34 -1
View File
@@ -4,6 +4,7 @@
.dashboard section {
margin-bottom: calc(var(--s4) * 2);
width: 100%;
}
.section-header {
@@ -80,7 +81,39 @@
flex-shrink: 0;
}
.card.placeholder {
#newAgentCard,
#newSessionCard {
margin-top: var(--s4);
}
#newAgentCard .card,
#newSessionCard .card {
align-items: center;
justify-content: center;
}
.card-meta {
display: flex;
flex-direction: column;
gap: var(--s1);
margin-top: var(--s1);
}
.card-meta:empty {
display: none;
}
.card-meta-item {
opacity: var(--semi-transparent);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.card-workspace {
font-family: monospace;
}
.card-persona {
font-style: italic;
}
-1
View File
@@ -140,7 +140,6 @@
.fe-textarea {
flex: 1;
resize: none;
border: none;
background: var(--f2-bg);
color: var(--text);
+13 -6
View File
@@ -5,6 +5,10 @@
gap: var(--s3);
}
.form label {
margin-top: var(--s4);
}
.avatar-section {
display: flex;
align-items: center;
@@ -60,23 +64,26 @@
.custom-command-item {
display: flex;
gap: var(--s2);
align-items: start;
}
.custom-command-fields {
flex: 1;
display: flex;
flex-direction: column;
gap: var(--s2);
}
.custom-command-fields .cmd-name {
flex: 2;
}
.custom-command-fields .cmd-command {
flex: 5;
}
.custom-command-item .remove-cmd-btn {
flex-shrink: 0;
margin-left: var(--s2);
color: #ff6b6b;
border-color: #ff6b6b;
padding: var(--s2) var(--s3);
align-self: center;
}
.custom-command-item .remove-cmd-btn:hover {
+2 -2
View File
@@ -1,4 +1,4 @@
.placeholder {
.settings-page .placeholder {
flex: 1;
display: flex;
flex-direction: column;
@@ -6,6 +6,6 @@
padding: calc(var(--s4) * 2);
}
.placeholder-icon {
.settings-page .placeholder-icon {
font-size: 4em;
}
+2
View File
@@ -38,12 +38,14 @@
<h2>Sessions</h2>
</div>
<div class="card-grid" id="sessionCards"></div>
<div class="card-grid" id="newSessionCard"></div>
</section>
<section>
<div class="section-header">
<h2>Agents</h2>
</div>
<div class="card-grid" id="agentCards"></div>
<div class="card-grid" id="newAgentCard"></div>
</section>
</div>
</div>
+12 -2
View File
@@ -15,6 +15,11 @@ registerPage('dashboard', {
const agent = s.agentId ? agentMap[s.agentId] : null;
const card = document.createElement('div');
card.className = 'card clickable';
const msgLabel = s.messageCount !== undefined
? `${s.messageCount}${s.totalMessageCount !== s.messageCount ? ` (${s.totalMessageCount})` : ''} Nachrichten`
: '';
const workspaceLabel = s.workspace ? s.workspace : '';
card.innerHTML = `
<div class="card-image">${s.image ? `<img src="${s.image}" alt="">` : ''}</div>
<div class="card-body">
@@ -23,6 +28,10 @@ registerPage('dashboard', {
${agent ? `<span class="badge">${esc(agent.name)}</span>` : ''}
</div>
${s.description ? `<div class="card-desc">${esc(s.description)}</div>` : ''}
<div class="card-meta">
${msgLabel ? `<span class="card-meta-item">💬 ${esc(msgLabel)}</span>` : ''}
${workspaceLabel ? `<span class="card-meta-item card-workspace" title="${esc(workspaceLabel)}">📁 ${esc(workspaceLabel)}</span>` : ''}
</div>
</div>
`;
card.addEventListener('click', () => navigateTo('session', { id: s.sessionId }));
@@ -34,7 +43,7 @@ registerPage('dashboard', {
newSession.className = 'card placeholder clickable';
newSession.innerHTML = '<div class="card-body"><div class="card-title">+ Neue Session</div></div>';
newSession.addEventListener('click', () => navigateTo('session'));
grid.appendChild(newSession);
document.getElementById('newSessionCard').appendChild(newSession);
// Agents
const agentGrid = document.getElementById('agentCards');
@@ -51,6 +60,7 @@ registerPage('dashboard', {
<span class="badge">${esc(a.model)}</span>
</div>
${a.description ? `<div class="card-desc">${esc(a.description)}</div>` : ''}
${a.persona ? `<div class="card-meta"><span class="card-meta-item card-persona">🎭 ${esc(a.persona)}</span></div>` : ''}
</div>
`;
card.addEventListener('click', () => navigateTo('agent', { id: a.agentId }));
@@ -61,7 +71,7 @@ registerPage('dashboard', {
placeholder.className = 'card placeholder clickable';
placeholder.innerHTML = '<div class="card-body"><div class="card-title">+ Neuer Agent</div></div>';
placeholder.addEventListener('click', () => navigateTo('agent'));
agentGrid.appendChild(placeholder);
document.getElementById('newAgentCard').appendChild(placeholder);
},
destroy() {}
});