diff --git a/Endpoints/SessionEndpoint.cs b/Endpoints/SessionEndpoint.cs index c861399..cef75a0 100644 --- a/Endpoints/SessionEndpoint.cs +++ b/Endpoints/SessionEndpoint.cs @@ -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); } diff --git a/Services/DatabaseService.cs b/Services/DatabaseService.cs index afae6db..b84812f 100644 --- a/Services/DatabaseService.cs +++ b/Services/DatabaseService.cs @@ -214,6 +214,47 @@ public class DatabaseService "SELECT * FROM sessions WHERE is_deleted = 0 ORDER BY updated_at DESC"); } + public async Task> GetSessionsWithStats() + { + using var conn = CreateConnection(); + var sessions = await conn.QueryAsync( + "SELECT * FROM sessions WHERE is_deleted = 0 ORDER BY updated_at DESC"); + + var results = new List(); + foreach (var s in sessions) + { + var activeCount = await conn.ExecuteScalarAsync(@" + 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(@" + 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 GetSession(string sessionId) { using var conn = CreateConnection(); diff --git a/wwwroot/css/base.css b/wwwroot/css/base.css index 2f8eb0f..e1b6d6f 100644 --- a/wwwroot/css/base.css +++ b/wwwroot/css/base.css @@ -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; } diff --git a/wwwroot/css/dashboard.css b/wwwroot/css/dashboard.css index b32e079..ab18750 100644 --- a/wwwroot/css/dashboard.css +++ b/wwwroot/css/dashboard.css @@ -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; +} diff --git a/wwwroot/css/file-explorer.css b/wwwroot/css/file-explorer.css index 25aae5f..414c5ed 100644 --- a/wwwroot/css/file-explorer.css +++ b/wwwroot/css/file-explorer.css @@ -140,7 +140,6 @@ .fe-textarea { flex: 1; - resize: none; border: none; background: var(--f2-bg); color: var(--text); diff --git a/wwwroot/css/form.css b/wwwroot/css/form.css index c559c1a..fbf5add 100644 --- a/wwwroot/css/form.css +++ b/wwwroot/css/form.css @@ -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 { diff --git a/wwwroot/css/placeholder.css b/wwwroot/css/placeholder.css index a07386d..f646bf2 100644 --- a/wwwroot/css/placeholder.css +++ b/wwwroot/css/placeholder.css @@ -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; } diff --git a/wwwroot/index.html b/wwwroot/index.html index fda3e52..a6d3059 100644 --- a/wwwroot/index.html +++ b/wwwroot/index.html @@ -38,12 +38,14 @@

Sessions

+

Agents

+
diff --git a/wwwroot/js/pages/dashboard.js b/wwwroot/js/pages/dashboard.js index 2576d32..3456df6 100644 --- a/wwwroot/js/pages/dashboard.js +++ b/wwwroot/js/pages/dashboard.js @@ -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 = `
${s.image ? `` : ''}
@@ -23,6 +28,10 @@ registerPage('dashboard', { ${agent ? `${esc(agent.name)}` : ''}
${s.description ? `
${esc(s.description)}
` : ''} +
+ ${msgLabel ? `💬 ${esc(msgLabel)}` : ''} + ${workspaceLabel ? `📁 ${esc(workspaceLabel)}` : ''} +
`; card.addEventListener('click', () => navigateTo('session', { id: s.sessionId })); @@ -34,7 +43,7 @@ registerPage('dashboard', { newSession.className = 'card placeholder clickable'; newSession.innerHTML = '
+ Neue Session
'; 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', { ${esc(a.model)} ${a.description ? `
${esc(a.description)}
` : ''} + ${a.persona ? `
🎭 ${esc(a.persona)}
` : ''} `; card.addEventListener('click', () => navigateTo('agent', { id: a.agentId })); @@ -61,7 +71,7 @@ registerPage('dashboard', { placeholder.className = 'card placeholder clickable'; placeholder.innerHTML = '
+ Neuer Agent
'; placeholder.addEventListener('click', () => navigateTo('agent')); - agentGrid.appendChild(placeholder); + document.getElementById('newAgentCard').appendChild(placeholder); }, destroy() {} });