diff --git a/modules/helpdesk/i18n/default_de.json b/modules/helpdesk/i18n/default_de.json index 83e51e4..d2772e3 100644 --- a/modules/helpdesk/i18n/default_de.json +++ b/modules/helpdesk/i18n/default_de.json @@ -301,5 +301,6 @@ "Current": "Aktuell", "Performance": "Leistung", "Historical": "Historisch", - "Queue": "Warteschlange" + "Queue": "Warteschlange", + "Wait time": "Wartezeit" } diff --git a/modules/helpdesk/i18n/default_en.json b/modules/helpdesk/i18n/default_en.json index 0046435..5778982 100644 --- a/modules/helpdesk/i18n/default_en.json +++ b/modules/helpdesk/i18n/default_en.json @@ -301,5 +301,6 @@ "Current": "Current", "Performance": "Performance", "Historical": "Historical", - "Queue": "Queue" + "Queue": "Queue", + "Wait time": "Wait time" } diff --git a/modules/helpdesk/pages/helpdesk/team/index(default).phtml b/modules/helpdesk/pages/helpdesk/team/index(default).phtml index 8f96574..0fc860a 100644 --- a/modules/helpdesk/pages/helpdesk/team/index(default).phtml +++ b/modules/helpdesk/pages/helpdesk/team/index(default).phtml @@ -32,6 +32,7 @@ $periodLabels = [ data-label-resolution-time="" data-label-top-customers="" data-label-top-categories="" + data-label-wait-time="" >
48h open)'; + const labelWaitTime = container.dataset.labelWaitTime || 'Wait time'; const ticketBaseUrl = container.dataset.ticketBaseUrl || ''; const debitorBaseUrl = container.dataset.debitorBaseUrl || ''; @@ -38,6 +39,13 @@ if (container) { return e; } + /** + * Detect queue entries — Support_User_Name contains 'warteschlange'. + */ + function isQueueMember(m) { + return m.support_user === '' || m.support_user.includes('warteschlange'); + } + function initials(name) { const parts = name.trim().split(/\s+/); if (parts.length >= 2) return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase(); @@ -298,14 +306,48 @@ if (container) { return section; } + /** + * Build a queue summary with wait time Ø/Min/Max from open ticket ages. + */ + function buildQueueWaitSummary(queueMembers) { + const allAges = queueMembers.flatMap(m => (m.open_ticket_details || []).map(t => t.age_hours)); + if (allAges.length === 0) return null; + + const stats = computeResolution(allAges); + const wrap = h('div', 'helpdesk-team-queue-wait'); + wrap.appendChild(h('span', 'helpdesk-team-perf-stat-label', labelWaitTime)); + + const list = h('ol', 'helpdesk-team-perf-ranked helpdesk-team-perf-ranked-plain'); + const items = [ + ['Ø', formatResolution(stats.avg)], + ['Min', formatResolution(stats.min)], + ['Max', formatResolution(stats.max)], + ]; + for (const [label, value] of items) { + const li = h('li'); + li.appendChild(h('span', 'helpdesk-team-perf-ranked-name', label)); + li.appendChild(h('span', 'helpdesk-team-perf-ranked-count', value)); + list.appendChild(li); + } + wrap.appendChild(list); + return wrap; + } + function renderCurrentTab(members) { if (!elCurrentCards) return; elCurrentCards.replaceChildren(); - 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 queueMembers = members.filter(m => isQueueMember(m) && m.open_tickets > 0); + const agents = members.filter(m => !isQueueMember(m) && (m.open_tickets > 0 || m.critical_tickets > 0)); - if (queue) elCurrentCards.appendChild(buildAgentWidget(queue, true)); + // Queue section(s) at top + for (const q of queueMembers) elCurrentCards.appendChild(buildAgentWidget(q, true)); + + // Wait time summary across all queues + const waitSummary = buildQueueWaitSummary(queueMembers); + if (waitSummary) elCurrentCards.appendChild(waitSummary); + + // Agent cards for (const m of agents) elCurrentCards.appendChild(buildAgentWidget(m, false)); // Legend @@ -324,15 +366,13 @@ if (container) { if (!elPerformanceCards) return; elPerformanceCards.replaceChildren(); - const sorted = [...members] - .filter(m => m.resolved_in_period > 0) - .sort((a, b) => { - if (a.support_user === '') return 1; - if (b.support_user === '') return -1; - return b.resolved_in_period - a.resolved_in_period; - }); + const queueResolved = members.filter(m => isQueueMember(m) && m.resolved_in_period > 0); + const agentsResolved = members + .filter(m => !isQueueMember(m) && m.resolved_in_period > 0) + .sort((a, b) => b.resolved_in_period - a.resolved_in_period); - for (const m of sorted) elPerformanceCards.appendChild(buildPerformanceWidget(m)); + for (const q of queueResolved) elPerformanceCards.appendChild(buildPerformanceWidget(q)); + for (const m of agentsResolved) elPerformanceCards.appendChild(buildPerformanceWidget(m)); } async function fetchData(refresh = false) {