refactor: Agent-Auswahl in Session-Form als Card + Picker-Modal
- buildAgentCard() Helper in ui.js erstellt (wiederverwendbar für Dashboard + Picker) - Session-Form: select-Dropdown durch klickbare Agent-Card ersetzt - Agent-Picker-Modal zeigt alle Agents mit identischen Cards wie am Dashboard - Dashboard refactored: nutzt buildAgentCard() statt dupliziertem Inline-HTML - Kein duplizierter Code mehr für Agent-Card-Rendering (Badges, Skills, Avatar)
This commit is contained in:
1 parent
a82540e7db
commit
92c20402eb
5 files changed
+252
-42
No files matched your search
@@ -176,46 +176,19 @@ registerPage('dashboard', {
|
||||
}));
|
||||
|
||||
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 === 'mention') badges.push('<span class="badge badge-feature" title="Git-Commits nur auf Anweisung"><i class="fa fa-code-fork"></i> Anmerken</span>');
|
||||
if (a.autoCommit === 'enforce') badges.push('<span class="badge badge-forced-feature" title="Git-Commits nach jeder Änderung erzwungen"><i class="fa fa-code-fork"></i> Erzwungen</span>');
|
||||
if (a.autoCommit === 'forbid') badges.push('<span class="badge badge-forced-feature" title="Git-Commits strikt verboten"><i class="fa fa-code-fork"></i> Verboten</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 (Benutzer-Persona)"><i class="fa fa-user"></i> Du</span>');
|
||||
if (a.useMemory) badges.push('<span class="badge badge-feature" title="Zugriff auf Erinnerungen (Memory-Tools)"><i class="fa fa-database"></i> Erinnerungen</span>');
|
||||
if (a.webSearchVersion) {
|
||||
const wsYear = a.webSearchVersion.includes('2025') ? 'Version 2025' : 'v2026';
|
||||
badges.push(`<span class="badge badge-feature" title="Web-Suche - ${wsYear}"><i class="fa fa-search"></i> Web-Suche</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>`);
|
||||
}
|
||||
const card = buildAgentCard(a, skills);
|
||||
|
||||
const agentScaleStyle = a.avatarScale && a.avatarScale !== 1 ? ` style="transform: scale(${a.avatarScale})"` : '';
|
||||
card.innerHTML = `
|
||||
<div class="card-image">${a.avatar ? `<img src="${a.avatar}" alt=""${agentScaleStyle}>` : ''}</div>
|
||||
<div class="card-body">
|
||||
<div class="card-title-row">
|
||||
<span class="card-title">${esc(a.name)}</span>
|
||||
<span class="badge">${prettyModelName(a.model)}</span>
|
||||
<div class="card-menu">
|
||||
// Menü zum title-row hinzufügen
|
||||
const titleRow = card.querySelector('.card-title-row');
|
||||
const menuHtml = `<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>
|
||||
<button class="card-menu-item" data-action="edit"><i class="fa fa-pencil"></i> Bearbeiten</button>
|
||||
<button class="card-menu-item" data-action="files"><i class="fa fa-folder"></i> Dateien verwalten</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-badges">${badges.join('')}</div>
|
||||
</div>
|
||||
`;
|
||||
</div>`;
|
||||
titleRow.insertAdjacentHTML('beforeend', menuHtml);
|
||||
const menuTrigger = card.querySelector('.card-menu-trigger');
|
||||
const menuDropdown = card.querySelector('.card-menu-dropdown');
|
||||
menuTrigger.addEventListener('click', (e) => {
|
||||
|
||||
@@ -20,6 +20,7 @@ registerPage('session', {
|
||||
const contextEl = document.getElementById('sessionContext');
|
||||
const workspaceEl = document.getElementById('sessionWorkspace');
|
||||
const agentSelect = document.getElementById('agentSelect');
|
||||
const agentSelectCard = document.getElementById('agentSelectCard');
|
||||
const imagePreview = document.getElementById('sessionImagePreview');
|
||||
const saveBtn = document.getElementById('sessionSaveBtn');
|
||||
const cancelBtn = document.getElementById('sessionCancelBtn');
|
||||
@@ -72,16 +73,45 @@ registerPage('session', {
|
||||
initSessionTelegram(sessionId);
|
||||
}
|
||||
|
||||
// Agents laden
|
||||
// Agents laden + Skills parallel
|
||||
const agents = await apiGetAgents();
|
||||
agentSelect.innerHTML = '<option value="">-- Kein Agent --</option>';
|
||||
for (const a of agents) {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = a.agentId;
|
||||
opt.textContent = `${a.name} (${a.model})`;
|
||||
agentSelect.appendChild(opt);
|
||||
const agentMap = {};
|
||||
for (const a of agents) agentMap[a.agentId] = a;
|
||||
|
||||
const agentSkillsMap = {};
|
||||
await Promise.all(agents.map(async a => {
|
||||
agentSkillsMap[a.agentId] = await apiGetAgentSkills(a.agentId);
|
||||
}));
|
||||
|
||||
function renderAgentSelectCard(agent) {
|
||||
agentSelectCard.innerHTML = '';
|
||||
if (!agent) {
|
||||
agentSelectCard.innerHTML = '<div class="agent-select-empty"><i class="fa fa-user-circle-o"></i> Kein Agent ausgewählt</div>';
|
||||
return;
|
||||
}
|
||||
const skills = agentSkillsMap[agent.agentId] || [];
|
||||
const inner = buildAgentCard(agent, skills);
|
||||
// Die inneren Elemente (card-image + card-body) in die Select-Card übernehmen
|
||||
while (inner.firstChild) agentSelectCard.appendChild(inner.firstChild);
|
||||
// Pencil-Icon hinzufügen
|
||||
agentSelectCard.insertAdjacentHTML('beforeend', '<span class="agent-select-change"><i class="fa fa-pencil"></i></span>');
|
||||
}
|
||||
if (session && session.agentId) agentSelect.value = session.agentId;
|
||||
|
||||
// Initiale Anzeige
|
||||
if (session && session.agentId) {
|
||||
agentSelect.value = session.agentId;
|
||||
renderAgentSelectCard(agentMap[session.agentId] || null);
|
||||
} else {
|
||||
renderAgentSelectCard(null);
|
||||
}
|
||||
|
||||
// Klick auf Card → Modal öffnen
|
||||
agentSelectCard.addEventListener('click', () => {
|
||||
openAgentPickerModal(agents, agentSkillsMap, agentSelect.value, (selectedId) => {
|
||||
agentSelect.value = selectedId || '';
|
||||
renderAgentSelectCard(selectedId ? agentMap[selectedId] : null);
|
||||
});
|
||||
});
|
||||
|
||||
more.addEventListener('click', () => {
|
||||
const content = more.querySelector('[hidden]');
|
||||
@@ -177,6 +207,65 @@ registerPage('session', {
|
||||
}
|
||||
});
|
||||
|
||||
function openAgentPickerModal(agents, agentSkillsMap, currentId, onSelect) {
|
||||
// Overlay
|
||||
const overlay = document.createElement('div');
|
||||
overlay.className = 'agent-picker-overlay';
|
||||
|
||||
const modal = document.createElement('div');
|
||||
modal.className = 'agent-picker-modal';
|
||||
|
||||
// Header
|
||||
const header = document.createElement('div');
|
||||
header.className = 'agent-picker-header';
|
||||
header.innerHTML = '<span>Agent auswählen</span><button class="icon-btn agent-picker-close"><i class="fa fa-times"></i></button>';
|
||||
modal.appendChild(header);
|
||||
|
||||
// Body
|
||||
const body = document.createElement('div');
|
||||
body.className = 'agent-picker-body';
|
||||
|
||||
// "Kein Agent" Option
|
||||
const noneCard = document.createElement('div');
|
||||
noneCard.className = 'card agent-picker-item' + (!currentId ? ' selected' : '');
|
||||
noneCard.innerHTML = `
|
||||
<div class="card-image" style="display:flex;align-items:center;justify-content:center"><i class="fa fa-ban" style="font-size:2em;opacity:var(--semi-transparent)"></i></div>
|
||||
<div class="card-body">
|
||||
<div class="card-title-row">
|
||||
<span class="card-title">Kein Agent</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
noneCard.addEventListener('click', () => {
|
||||
onSelect(null);
|
||||
overlay.remove();
|
||||
});
|
||||
body.appendChild(noneCard);
|
||||
|
||||
// Agent Cards via Helper
|
||||
for (const a of agents) {
|
||||
const skills = agentSkillsMap[a.agentId] || [];
|
||||
const item = buildAgentCard(a, skills);
|
||||
item.classList.add('agent-picker-item');
|
||||
if (a.agentId === currentId) item.classList.add('selected');
|
||||
item.addEventListener('click', () => {
|
||||
onSelect(a.agentId);
|
||||
overlay.remove();
|
||||
});
|
||||
body.appendChild(item);
|
||||
}
|
||||
|
||||
modal.appendChild(body);
|
||||
overlay.appendChild(modal);
|
||||
document.body.appendChild(overlay);
|
||||
|
||||
// Schließen
|
||||
header.querySelector('.agent-picker-close').addEventListener('click', () => overlay.remove());
|
||||
overlay.addEventListener('click', (e) => {
|
||||
if (e.target === overlay) overlay.remove();
|
||||
});
|
||||
}
|
||||
|
||||
function initSessionTelegram(sessionId) {
|
||||
var tokenInput = document.getElementById('sessionTelegramToken');
|
||||
var secretInput = document.getElementById('sessionTelegramSecret');
|
||||
|
||||
@@ -1,3 +1,50 @@
|
||||
// ── Agent Card Helper ──
|
||||
// Erzeugt ein .card-Element für einen Agent (wiederverwendbar für Dashboard + Picker).
|
||||
// agent: Agent-Objekt, skills: Array von Skills (optional)
|
||||
// Gibt ein DOM-Element zurück (.card mit .card-image + .card-body inkl. Badges).
|
||||
|
||||
function buildAgentCard(agent, skills) {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'card';
|
||||
|
||||
const scaleStyle = agent.avatarScale && agent.avatarScale !== 1 ? ` style="transform: scale(${agent.avatarScale})"` : '';
|
||||
const imageHtml = agent.avatar ? `<img src="${agent.avatar}" alt=""${scaleStyle}>` : '';
|
||||
|
||||
// Badges
|
||||
const badges = [];
|
||||
if (agent.toolChoice === 'any') badges.push('<span class="badge badge-forced-feature" title="Tool-Nutzung erzwingen"><i class="fa fa-wrench"></i> Erzwungen</span>');
|
||||
if (agent.autoCommit === 'mention') badges.push('<span class="badge badge-feature" title="Git-Commits nur auf Anweisung"><i class="fa fa-code-fork"></i> Anmerken</span>');
|
||||
if (agent.autoCommit === 'enforce') badges.push('<span class="badge badge-forced-feature" title="Git-Commits nach jeder Änderung erzwungen"><i class="fa fa-code-fork"></i> Erzwungen</span>');
|
||||
if (agent.autoCommit === 'forbid') badges.push('<span class="badge badge-forced-feature" title="Git-Commits strikt verboten"><i class="fa fa-code-fork"></i> Verboten</span>');
|
||||
if (agent.useSoul) badges.push('<span class="badge badge-feature" title="Hat eine Seele (SOUL.md)"><i class="fa fa-heart"></i> Seele</span>');
|
||||
if (agent.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 (agent.useUserInfo) badges.push('<span class="badge badge-feature" title="Kennt sein Gegenüber (Benutzer-Persona)"><i class="fa fa-user"></i> Du</span>');
|
||||
if (agent.useMemory) badges.push('<span class="badge badge-feature" title="Zugriff auf Erinnerungen (Memory-Tools)"><i class="fa fa-database"></i> Erinnerungen</span>');
|
||||
if (agent.webSearchVersion) {
|
||||
const wsYear = agent.webSearchVersion.includes('2025') ? 'Version 2025' : 'v2026';
|
||||
badges.push(`<span class="badge badge-feature" title="Web-Suche - ${wsYear}"><i class="fa fa-search"></i> Web-Suche</span>`);
|
||||
}
|
||||
|
||||
if (skills) {
|
||||
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">${imageHtml}</div>
|
||||
<div class="card-body">
|
||||
<div class="card-title-row">
|
||||
<span class="card-title">${esc(agent.name)}</span>
|
||||
<span class="badge">${prettyModelName(agent.model)}</span>
|
||||
</div>
|
||||
${badges.length ? `<div class="card-badges">${badges.join('')}</div>` : ''}
|
||||
</div>
|
||||
`;
|
||||
|
||||
return card;
|
||||
}
|
||||
|
||||
// ── Toast Notifications ──
|
||||
|
||||
function showToast(message, type) {
|
||||
|
||||
Reference in new issue
Block a user