From a58c870561825f56233ca01083effb786ecd7f43 Mon Sep 17 00:00:00 2001 From: fs Date: Sun, 5 Apr 2026 19:16:42 +0200 Subject: [PATCH] =?UTF-8?q?fix(helpdesk):=20simplify=20team=20dashboard=20?= =?UTF-8?q?visuals=20=E2=80=94=20remove=20bars=20and=20colors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove progress bars (meaningless without a defined per-agent limit), remove deterministic hue coloring (too noisy), and fix spacing by using gap on a container grid instead of border-bottom on items. Avatars now use a single neutral style. Count badges remain as the key indicator (warning-colored when critical tickets exist). Cleaner, quieter layout. Co-Authored-By: Claude Opus 4.6 (1M context) --- modules/helpdesk/web/css/helpdesk.css | 60 +++++++---------------- modules/helpdesk/web/js/helpdesk-team.js | 61 +++++++----------------- 2 files changed, 32 insertions(+), 89 deletions(-) diff --git a/modules/helpdesk/web/css/helpdesk.css b/modules/helpdesk/web/css/helpdesk.css index e70c8c8..263498e 100644 --- a/modules/helpdesk/web/css/helpdesk.css +++ b/modules/helpdesk/web/css/helpdesk.css @@ -155,16 +155,18 @@ color: var(--app-muted-color); } - /* Team workload — agent card with avatar */ + /* Team workload — agent rows */ + .helpdesk-team-agents { + display: grid; + gap: calc(var(--app-spacing) * 0.5); + } + .helpdesk-team-agent { display: flex; gap: calc(var(--app-spacing) * 0.65); - padding: calc(var(--app-spacing) * 0.6) 0; - border-bottom: 1px solid color-mix(in srgb, var(--app-muted-border-color) 50%, transparent); - } - - .helpdesk-team-agent:last-child { - border-bottom: none; + padding: calc(var(--app-spacing) * 0.5) calc(var(--app-spacing) * 0.6); + border: 1px solid var(--app-muted-border-color); + border-radius: var(--app-radius, 0.375rem); } .helpdesk-team-avatar { @@ -178,8 +180,8 @@ font-weight: 700; letter-spacing: 0.02em; flex-shrink: 0; - background: hsl(var(--agent-hue, 210) 55% 92%); - color: hsl(var(--agent-hue, 210) 50% 35%); + background: color-mix(in srgb, var(--app-muted-border-color) 80%, transparent); + color: var(--app-muted-color); } .helpdesk-team-avatar-sm { @@ -188,11 +190,6 @@ font-size: 0.65rem; } - .helpdesk-team-avatar-muted { - background: var(--app-muted-border-color); - color: var(--app-muted-color); - } - .helpdesk-team-agent-content { flex: 1; min-width: 0; @@ -201,8 +198,7 @@ .helpdesk-team-agent-header { display: flex; align-items: center; - justify-content: space-between; - gap: calc(var(--app-spacing) * 0.5); + gap: calc(var(--app-spacing) * 0.4); margin-bottom: calc(var(--app-spacing) * 0.25); } @@ -214,11 +210,11 @@ .helpdesk-team-agent-count { font-variant-numeric: tabular-nums; font-weight: 600; - font-size: 0.75rem; + font-size: 0.7rem; padding: 0.1em 0.5em; border-radius: 999px; - background: color-mix(in srgb, var(--app-primary, #0d6efd) 12%, transparent); - color: var(--app-primary, #0d6efd); + background: color-mix(in srgb, var(--app-contrast, #000) 8%, transparent); + color: var(--app-muted-color); } .helpdesk-team-agent-count-warning { @@ -231,26 +227,6 @@ color: var(--app-success, #198754); } - /* Load bar */ - .helpdesk-team-agent-bar-track { - height: 3px; - border-radius: 999px; - background: color-mix(in srgb, var(--app-muted-border-color) 50%, transparent); - margin-bottom: calc(var(--app-spacing) * 0.35); - } - - .helpdesk-team-agent-bar-fill { - height: 100%; - border-radius: 999px; - background: hsl(var(--agent-hue, 210) 55% 55%); - transition: width 0.3s ease; - min-width: 2px; - } - - .helpdesk-team-agent-bar-success { - background: var(--app-success, #198754); - } - /* Ticket pills */ .helpdesk-team-pills { display: flex; @@ -301,11 +277,7 @@ /* Compact variant for performance tab */ .helpdesk-team-agent-compact { - padding: calc(var(--app-spacing) * 0.4) 0; - } - - .helpdesk-team-agent-compact .helpdesk-team-agent-bar-track { - margin-bottom: 0; + padding: calc(var(--app-spacing) * 0.4) calc(var(--app-spacing) * 0.6); } .helpdesk-team-performance-panel > .helpdesk-segment-control { diff --git a/modules/helpdesk/web/js/helpdesk-team.js b/modules/helpdesk/web/js/helpdesk-team.js index 0e9b0a1..13277c0 100644 --- a/modules/helpdesk/web/js/helpdesk-team.js +++ b/modules/helpdesk/web/js/helpdesk-team.js @@ -45,17 +45,6 @@ if (container) { return name.substring(0, 2).toUpperCase(); } - /** - * Deterministic hue from string — consistent color per agent. - */ - function nameHue(name) { - let hash = 0; - for (let i = 0; i < name.length; i++) { - hash = name.charCodeAt(i) + ((hash << 5) - hash); - } - return Math.abs(hash) % 360; - } - function formatAge(hours) { if (hours < 24) return hours + 'h'; return Math.floor(hours / 24) + 'd'; @@ -101,18 +90,13 @@ if (container) { } /** - * Build an agent card with avatar, load bar, and ticket pills. + * Build an agent card with avatar and ticket pills. */ - function buildAgentCard(m, maxOpen) { - const pct = maxOpen > 0 ? Math.round((m.open_tickets / maxOpen) * 100) : 0; - const hue = nameHue(m.display_name); - + function buildAgentCard(m) { const card = h('article', 'helpdesk-team-agent'); // Avatar - const avatar = h('div', 'helpdesk-team-avatar', initials(m.display_name)); - avatar.style.setProperty('--agent-hue', hue); - card.appendChild(avatar); + card.appendChild(h('div', 'helpdesk-team-avatar', initials(m.display_name))); // Content area const content = h('div', 'helpdesk-team-agent-content'); @@ -125,14 +109,6 @@ if (container) { nameRow.appendChild(countBadge); content.appendChild(nameRow); - // Load bar - const barTrack = h('div', 'helpdesk-team-agent-bar-track'); - const barFill = h('div', 'helpdesk-team-agent-bar-fill'); - barFill.style.width = pct + '%'; - barFill.style.setProperty('--agent-hue', hue); - barTrack.appendChild(barFill); - content.appendChild(barTrack); - // Ticket pills const tickets = m.open_ticket_details || []; if (tickets.length > 0) { @@ -146,31 +122,23 @@ if (container) { } /** - * Build a compact performance card with avatar and resolved bar. + * Build a compact performance card with avatar and resolved count. */ - function buildPerformanceCard(m, maxResolved) { - const pct = maxResolved > 0 ? Math.round((m.resolved_in_period / maxResolved) * 100) : 0; - const hue = nameHue(m.display_name || 'queue'); + function buildPerformanceCard(m) { + const isQueue = m.support_user === ''; const card = h('article', 'helpdesk-team-agent helpdesk-team-agent-compact'); - const avatar = h('div', 'helpdesk-team-avatar helpdesk-team-avatar-sm', m.support_user === '' ? '?' : initials(m.display_name)); - avatar.style.setProperty('--agent-hue', m.support_user === '' ? 0 : hue); - if (m.support_user === '') avatar.classList.add('helpdesk-team-avatar-muted'); + const avatar = h('div', 'helpdesk-team-avatar helpdesk-team-avatar-sm', isQueue ? '?' : initials(m.display_name)); + if (isQueue) avatar.classList.add('helpdesk-team-avatar-muted'); card.appendChild(avatar); const content = h('div', 'helpdesk-team-agent-content'); const nameRow = h('div', 'helpdesk-team-agent-header'); - nameRow.appendChild(h('span', 'helpdesk-team-agent-name', m.support_user === '' ? labelQueue : m.display_name)); + nameRow.appendChild(h('span', 'helpdesk-team-agent-name', isQueue ? labelQueue : m.display_name)); nameRow.appendChild(h('span', 'helpdesk-team-agent-count helpdesk-team-agent-count-success', String(m.resolved_in_period))); content.appendChild(nameRow); - const barTrack = h('div', 'helpdesk-team-agent-bar-track'); - const barFill = h('div', 'helpdesk-team-agent-bar-fill helpdesk-team-agent-bar-success'); - barFill.style.width = pct + '%'; - barTrack.appendChild(barFill); - content.appendChild(barTrack); - card.appendChild(content); return card; } @@ -181,10 +149,12 @@ if (container) { const queue = members.find(m => m.support_user === '' && m.open_tickets > 0); const agents = members.filter(m => m.support_user !== '' && (m.open_tickets > 0 || m.critical_tickets > 0)); - const maxOpen = Math.max(1, ...agents.map(m => m.open_tickets)); if (queue) elCurrentCards.appendChild(buildQueueSection(queue)); - for (const m of agents) elCurrentCards.appendChild(buildAgentCard(m, maxOpen)); + + const grid = h('div', 'helpdesk-team-agents'); + for (const m of agents) grid.appendChild(buildAgentCard(m)); + elCurrentCards.appendChild(grid); } function renderPerformanceTab(members) { @@ -199,8 +169,9 @@ if (container) { return b.resolved_in_period - a.resolved_in_period; }); - const maxResolved = Math.max(1, ...sorted.map(m => m.resolved_in_period)); - for (const m of sorted) elPerformanceCards.appendChild(buildPerformanceCard(m, maxResolved)); + const grid = h('div', 'helpdesk-team-agents'); + for (const m of sorted) grid.appendChild(buildPerformanceCard(m)); + elPerformanceCards.appendChild(grid); } async function fetchData(refresh = false) {