Dashboard: Badges für Sessions (Kontext) und Agents (Features, Skills, Model-Name)

- prettyModelName() von chat.js nach ui.js als globale Funktion verschoben
- Session-Cards: Kontext-Badge mit Tooltip wenn context vorhanden
- Agent-Cards: Badges für ToolChoice:any, AutoCommit, Soul, Identity, UserInfo, Memory
- Agent-Cards: Skill-Badges pro aktiviertem Skill (parallel geladen)
- Agent-Cards: Model-Name via prettyModelName() statt roher Model-ID
- Neue CSS-Klassen: badge-feature, badge-forced-feature, badge-skill
- Theme: primary/dangerous Farben angepasst
- Chat: Input overflow hidden→auto
This commit is contained in:
Meleki committed 2026-03-02 08:22:18 +01:00
1 parent 754b2aa3e3
commit 56d4d1be0a
6 files changed
+73 -29

No files matched your search

+1 -18
View File
@@ -1,25 +1,8 @@
// ── Helpers ──
function _prettyModelName(model) {
if (!model) return '?';
// claude-sonnet-4-20250514 → Sonnet 4
// claude-opus-4-6 → Opus 4.6
// claude-haiku-3-5 → Haiku 3.5
const m = model.match(/claude-(\w+)-(\d+)(?:-(\d+))?/);
if (m) {
const family = m[1].charAt(0).toUpperCase() + m[1].slice(1);
const major = m[2];
const minor = m[3];
// minor > 20000000 ist ein Datums-Suffix, kein Minor-Version
if (minor && minor.length <= 2) return family + ' ' + major + '.' + minor;
return family + ' ' + major;
}
return 'Unbekannt';
}
function buildMetaBadges(d) {
const badges = [];
badges.push(_prettyModelName(d.model));
badges.push(prettyModelName(d.model));
badges.push('Tokens: ' + (d.inputTokens || 0) + ' / ' + (d.outputTokens || 0));
if (d.cacheCreationTokens > 0 || d.cacheReadTokens > 0) {
badges.push('Cache: ' + (d.cacheReadTokens || 0) + ' / ' + (d.cacheCreationTokens || 0));
+28 -6
View File
@@ -29,12 +29,16 @@ registerPage('dashboard', {
: '';
const workspaceLabel = s.workspace ? s.workspace : '';
const sessionBadges = [];
if (agent) sessionBadges.push(`<span class="badge">${esc(agent.name)}</span>`);
if (s.context) sessionBadges.push(`<span class="badge badge-feature" title="${esc(s.context)}"><i class="fa fa-file-text-o"></i></span>`);
card.innerHTML = `
<div class="card-image">${s.image ? `<img src="${s.image}" alt="">` : ''}</div>
<div class="card-body">
<div class="card-title-row">
<span class="card-title">${esc(s.name || 'Unbenannt')}</span>
${agent ? `<span class="badge">${esc(agent.name)}</span>` : ''}
${sessionBadges.join('')}
<div class="card-menu">
<button class="card-menu-trigger icon-btn"><i class="fa fa-ellipsis-v"></i></button>
<div class="card-menu-dropdown" hidden>
@@ -43,7 +47,6 @@ registerPage('dashboard', {
</div>
</div>
</div>
${s.description ? `<div class="card-desc">${esc(s.description)}</div>` : ''}
<div class="card-meta">
${msgLabel ? `<span class="card-meta-item"><i class="fa fa-comment"></i> ${esc(msgLabel)}</span>` : ''}
${workspaceLabel ? `<span class="card-meta-item card-workspace" title="${esc(workspaceLabel)}"><i class="fa fa-folder"></i> ${esc(workspaceLabel)}</span>` : ''}
@@ -102,7 +105,7 @@ registerPage('dashboard', {
const gitEl = document.createElement('span');
gitEl.className = 'card-meta-item card-git-status';
gitEl.innerHTML = `<i class="fa fa-code-fork"></i> ${parts.join(' ')}`;
gitEl.innerHTML = parts.join(' ');
metaEl.appendChild(gitEl);
});
}
@@ -119,15 +122,35 @@ registerPage('dashboard', {
const agentGrid = document.getElementById('agentCards');
agentGrid.innerHTML = '';
// Skills pro Agent parallel laden
const agentSkillsMap = {};
await Promise.all(agents.map(async a => {
agentSkillsMap[a.agentId] = await apiGetAgentSkills(a.agentId);
}));
for (const a of agents) {
const card = document.createElement('div');
card.className = 'card';
const badges = [];
if (a.toolChoice === 'any') badges.push('<span class="badge badge-forced-feature" title="Tool-Nutzung erzwingen"><i class="fa fa-wrench"></i> Erzwungen</span>');
if (a.autoCommit) badges.push('<span class="badge badge-feature" title="Auto-Commit erlauben"><i class="fa fa-check-circle"></i> Auto-Commit</span>');
if (a.useSoul) badges.push('<span class="badge badge-feature" title="Hat eine Seele (SOUL.md)"><i class="fa fa-heart"></i> Seele</span>');
if (a.useIdentity) badges.push('<span class="badge badge-feature" title="Hat eine Identität (IDENTITY.md)"><i class="fa fa-id-badge"></i> Ich</span>');
if (a.useUserInfo) badges.push('<span class="badge badge-feature" title="Kennt sein Gegenüber (USER.md)"><i class="fa fa-user"></i> Du</span>');
if (a.useMemory) badges.push('<span class="badge badge-feature" title="Auf Erinnerungen zugreifen (Memory-Tools)"><i class="fa fa-database"></i> Erinnerungen</span>');
const skills = agentSkillsMap[a.agentId] || [];
for (const skill of skills) {
badges.push(`<span class="badge badge-skill" title="${esc(skill.description || skill.slug)}"><i class="fa fa-puzzle-piece"></i> ${esc(skill.name)}</span>`);
}
card.innerHTML = `
<div class="card-image">${a.avatar ? `<img src="${a.avatar}" alt="">` : ''}</div>
<div class="card-body">
<div class="card-title-row">
<span class="card-title">${esc(a.name)}</span>
<span class="badge">${esc(a.model)}</span>
<span class="badge">${prettyModelName(a.model)}</span>
<div class="card-menu">
<button class="card-menu-trigger icon-btn"><i class="fa fa-ellipsis-v"></i></button>
<div class="card-menu-dropdown" hidden>
@@ -135,8 +158,7 @@ registerPage('dashboard', {
</div>
</div>
</div>
${a.description ? `<div class="card-desc">${esc(a.description)}</div>` : ''}
${a.persona ? `<div class="card-meta"><span class="card-meta-item card-persona"><i class="fa fa-user-secret"></i> ${esc(a.persona)}</span></div>` : ''}
<div class="card-badges">${badges.join('')}</div>
</div>
`;
const menuTrigger = card.querySelector('.card-menu-trigger');
+15
View File
@@ -4,6 +4,21 @@ const $ = (sel) => document.querySelector(sel);
const chatEl = () => $('#chat');
const metaEl = () => $('#meta');
function prettyModelName(model) {
if (!model) return '?';
var m = model.match(/claude-(\w+)-(\d+)(?:-(\d+))?/);
if (m) {
var family = m[1].charAt(0).toUpperCase() + m[1].slice(1);
var major = m[2];
var minor = m[3];
if (minor && minor.length <= 2) return family + ' ' + major + '.' + minor;
return family + ' ' + major;
}
if (model == 'sonnet') return 'Sonnet'
if (model == 'opus') return 'Opus'
return 'Unbekannt (' + model + ')';
}
// ── Markdown ──
marked.setOptions({ breaks: true, gfm: true });