From ddbaabb65777ff2bbff0b50c4e0776cdcbeaa9eb Mon Sep 17 00:00:00 2001 From: sorcier Date: Thu, 12 Nov 2026 10:25:40 +0100 Subject: [PATCH] v2.6.7: Replace Admin & UCP emojis with uniform Heroicons SVG icons --- public/assets/app.js | 123 ++++++++++++++++++++++++++----------------- public/index.php | 73 ++++++++++++------------- ucp/assets/ucp.js | 86 ++++++++++++++++++++---------- ucp/index.php | 30 +++++++---- version.json | 10 +++- 5 files changed, 198 insertions(+), 124 deletions(-) diff --git a/public/assets/app.js b/public/assets/app.js index 3b90078..c45f5ed 100644 --- a/public/assets/app.js +++ b/public/assets/app.js @@ -28,6 +28,31 @@ const chartHistory = { let metricsTimer = null; +function adminIcon(name, cls = 'w-3.5 h-3.5') { + const paths = { + shield: '', + lock: '', + unlock: '', + warning: '', + phone: '', + mobile: '', + building: '', + voicemail: '', + music: '', + refresh: '', + trash: '', + tag: '', + ban: '', + speaker: '', + rocket: '', + emergency: '', + clock: '', + globe: '', + dotGreen: '', + }; + return `${paths[name] || paths.tag}`; +} + // --- Notifications Toast Tailwind --- function showToast(message, type = 'success') { const container = document.getElementById('toast-container'); @@ -765,11 +790,11 @@ function renderDashboardPhonesTable() { const encMode = Number(ext.encryption ?? (isTls ? 1 : 0)); let srtpBadge = ''; if (encMode === 2) { - srtpBadge = `🛡️ SRTP Forcé`; + srtpBadge = `${adminIcon('shield', 'w-3 h-3')} SRTP Forcé`; } else if (encMode === 1) { - srtpBadge = `🛡️ SRTP Négociable`; + srtpBadge = `${adminIcon('shield', 'w-3 h-3')} SRTP Négociable`; } else { - srtpBadge = `🔈 RTP Clair`; + srtpBadge = `${adminIcon('speaker', 'w-3 h-3')} RTP Clair`; } // Détection dynamique du mode réel négocié en direct par le téléphone @@ -782,21 +807,21 @@ function renderDashboardPhonesTable() { if (actTr === 'tls') { trPill = ` - 🔒 TLS Actif (Chiffré) + ${adminIcon('lock', 'w-3 h-3')} TLS Actif (Chiffré) `; profileNote = `${isTls ? 'TLS Strict' : 'UDP Interne'}`; } else if (actTr === 'wss') { trPill = ` - 🔒 WSS WebRTC + ${adminIcon('lock', 'w-3 h-3')} WSS WebRTC `; profileNote = `WebRTC`; } else if (actTr === 'tcp') { trPill = ` - 🔓 TCP Actif (Clair) + ${adminIcon('unlock', 'w-3 h-3')} TCP Actif (Clair) `; profileNote = `${isTls ? 'TLS Strict' : 'UDP Interne'}`; @@ -804,10 +829,10 @@ function renderDashboardPhonesTable() { // UDP trPill = ` - 🔓 UDP Actif (Clair) + ${adminIcon('unlock', 'w-3 h-3')} UDP Actif (Clair) `; - profileNote = isTls ? '⚠️ Exige TLS' : 'UDP Interne'; + profileNote = isTls ? `${adminIcon('warning', 'w-3 h-3')} Exige TLS` : 'UDP Interne'; } modeBadge = ` @@ -853,7 +878,7 @@ function renderDashboardPhonesTable() { contactHtml = `
${escapeHtml(cleanIp)}
- ${ua ? `
📱 ${ua}
` : ''} + ${ua ? `
${adminIcon('mobile', 'w-3 h-3 text-indigo-400')} ${ua}
` : ''}
`; } else { @@ -909,10 +934,10 @@ function renderExtensionsTable() { encLabel = 'RTP Clair'; } const badge = isTls - ? `🔒 TLS (${encLabel})` + ? `${adminIcon('lock', 'w-3.5 h-3.5 text-emerald-400')} TLS (${encLabel})` : (encMode > 0 - ? `🛡️ UDP (${encLabel})` - : `🏢 UDP (RTP Clair)`); + ? `${adminIcon('shield', 'w-3.5 h-3.5 text-indigo-400')} UDP (${encLabel})` + : `${adminIcon('building', 'w-3.5 h-3.5 text-slate-400')} UDP (RTP Clair)`); const actTr = c ? (c.active_transport || 'udp').toUpperCase() : ''; const stLower = c ? String(c.status).toLowerCase() : ''; @@ -935,7 +960,7 @@ function renderExtensionsTable() { : `Aucun`; const vmBadge = Number(ext.voicemail_enabled) === 1 - ? `📟 Boîte` + ? `${adminIcon('voicemail', 'w-3 h-3')} Boîte` : ''; const gwBadge = Number(ext.groundwire_enabled) === 1 ? `GroundWire` @@ -1256,7 +1281,7 @@ function renderGroupsTable() { ? members.map(m => `${escapeHtml(m)}`).join(' ') : 'Aucun membre'; const failoverLabel = String(grp.failover_dest || '').startsWith('vm-') - ? `📬 Répondeur ${escapeHtml(String(grp.failover_dest).slice(3))}` + ? `${adminIcon('voicemail', 'w-3.5 h-3.5')} Répondeur ${escapeHtml(String(grp.failover_dest).slice(3))}` : `${escapeHtml(grp.failover_dest)}`; return ` @@ -1773,7 +1798,7 @@ function renderTrunksTable() { const mohSound = (appState.sounds || []).find(s => Number(s.id) === Number(t.moh_sound_id)); const mohBadge = mohSound - ? `🎵 ${escapeHtml(mohSound.name)}` + ? `${adminIcon('music', 'w-3 h-3')} ${escapeHtml(mohSound.name)}` : `MoH : Globale`; return ` @@ -1803,12 +1828,12 @@ function renderTrunksTable() { ${t.cid_name_prefix ? `CID: ${escapeHtml(t.cid_name_prefix)}` : ''} ${didCount > 0 ? `${didCount} règle(s) entrante(s)` : 'Tous numéros (Any)'} ${blockCount > 0 ? `${blockCount} blocage(s) CID` : ''} - ${tcCount > 0 ? `⏱️ ${tcCount} horaire(s)` : ''} + ${tcCount > 0 ? `${adminIcon('clock', 'w-3 h-3')} ${tcCount} horaire(s)` : ''}
${mohBadge}
- ${wantsReg ? `` : ''} + ${wantsReg ? `` : ''} @@ -2230,11 +2255,11 @@ function addTrunkInboundRouteRow(cid = 'Any', did = 'Any', description = '', des
- - +
@@ -2278,7 +2303,7 @@ function addTrunkInboundRouteRow(cid = 'Any', did = 'Any', description = '', des
@@ -2307,7 +2332,7 @@ function addTrunkInboundRouteRow(cid = 'Any', did = 'Any', description = '', des if (isEnabled) { toggleBtn.className = 'btn-toggle-time px-2 py-1.5 rounded-lg text-xs font-semibold bg-amber-500/20 text-amber-300 border border-amber-500/40 transition shadow-sm'; const daysLabel = tcWeekdaysSelect.value === 'mon-fri' ? 'Lun-Ven' : (tcWeekdaysSelect.value === 'mon-sat' ? 'Lun-Sam' : (tcWeekdaysSelect.value === '*' ? '7j/7' : 'Sam-Dim')); - badgeContainer.innerHTML = `⏱️ ${escapeHtml(tcStartInput.value)}-${escapeHtml(tcFinishInput.value)} (${escapeHtml(daysLabel)})`; + badgeContainer.innerHTML = `${adminIcon('clock', 'w-3 h-3')} ${escapeHtml(tcStartInput.value)}-${escapeHtml(tcFinishInput.value)} (${escapeHtml(daysLabel)})`; } else { toggleBtn.className = 'btn-toggle-time px-2 py-1.5 rounded-lg text-xs font-semibold bg-anthracite-950 hover:bg-anthracite-900 text-slate-400 hover:text-white border border-anthracite-700 transition'; badgeContainer.innerHTML = ''; @@ -2717,10 +2742,10 @@ function openTrunkModal(trunk = null) { if (mohSelect) { const mohSounds = (appState.sounds || []).filter(s => s.usage_type === 'moh'); const curMohId = trunk ? Number(trunk.moh_sound_id || 0) : 0; - let opts = ``; + let opts = ``; mohSounds.forEach(s => { const isSel = (Number(s.id) === curMohId) ? 'selected' : ''; - opts += ``; + opts += ``; }); mohSelect.innerHTML = opts; } @@ -2821,7 +2846,7 @@ function renderOutboundRoutesTable() { ${tIdx + 1}.${escapeHtml(t)} `).join(' → ') - : `⚠️ Aucun Trunk associé`; + : `${adminIcon('warning', 'w-3.5 h-3.5')} Aucun Trunk associé`; const isRestricted = r.permission_mode === 'restricted'; const allowedGrps = Array.isArray(r.allowed_groups) ? r.allowed_groups : []; @@ -2846,7 +2871,7 @@ function renderOutboundRoutesTable() { const patPreview = patterns.slice(0, 2).map(p => escapeHtml(p.match_pattern || '')).filter(Boolean).join(', '); const rTypeBadge = r.route_type === 'emergency' - ? `🚑 Urgence` + ? `${adminIcon('emergency', 'w-3 h-3')} Urgence` : (r.route_type === 'intracompany' ? `Intra` : `Standard`); @@ -2941,19 +2966,19 @@ function openOutboundRouteModal(route = null) { if (congSel) { const curCong = route ? route.congestion_dest : 'all-circuits-busy'; let congOpts = ` - - + + `; const annSounds = (appState.sounds || []).filter(s => s.usage_type !== 'moh'); if (annSounds.length > 0) { annSounds.forEach(s => { const val = `sound-${s.id}`; - congOpts += ``; + congOpts += ``; }); } congOpts += ` - + @@ -2967,7 +2992,7 @@ function openOutboundRouteModal(route = null) { if (mohSel) { const curMoh = route ? (route.moh_class || 'default') : 'default'; const mohSounds = (appState.sounds || []).filter(s => s.usage_type === 'moh'); - let mohOpts = ``; + let mohOpts = ``; mohSounds.forEach(s => { const sSlug = slugifyTrunkName(s.site_category || 'global'); const cName = (sSlug === 'global' || sSlug === 'default') ? 'default' : `moh-${sSlug}`; @@ -3092,7 +3117,7 @@ function addOutboundTrunkSeqRow(selectedTrunk = '') { - + `; row.querySelector('.btn-del-trunk-row').addEventListener('click', () => { @@ -3139,7 +3164,7 @@ function addOutboundPatternRow(prepend = '', prefix = '', match = '', cid = '') class="ob-pat-cid w-full px-2.5 py-1.5 rounded-lg bg-anthracite-950 border border-anthracite-700 text-xs text-indigo-300 font-mono">
- +
`; @@ -3322,8 +3347,8 @@ function renderIvrsTable() { -
⏱️ Attente : ${Number(ivr.timeout)}s (${Number(ivr.timeout_retries || 2)} rép)
-
⚠️ Erreur : max ${Number(ivr.invalid_retries || 3)} essais
+
${adminIcon('clock', 'w-3.5 h-3.5 text-amber-400')} Attente : ${Number(ivr.timeout)}s (${Number(ivr.timeout_retries || 2)} rép)
+
${adminIcon('warning', 'w-3.5 h-3.5 text-amber-400')} Erreur : max ${Number(ivr.invalid_retries || 3)} essais
@@ -3397,7 +3422,7 @@ function openIvrModal(ivr = null) { let audioHtml = ''; if (sounds.length > 0) { - audioHtml += ``; + audioHtml += ``; sounds.forEach(s => { const val = `custom/${s.slug}`; const isSel = curAudio === val || curAudio === s.slug || curAudio === String(s.id); @@ -3407,7 +3432,7 @@ function openIvrModal(ivr = null) { } audioHtml += ` - + @@ -5629,7 +5654,7 @@ function renderFirewall() { return ` - ⛔ ${escapeHtml(b.ip)} + ${adminIcon('ban', 'w-3.5 h-3.5')} ${escapeHtml(b.ip)} ${escapeHtml(b.jail_label || b.jail)} @@ -6260,7 +6285,7 @@ async function checkSystemUpdate(notify = false) { if (statusText) { statusText.className = 'text-amber-400 font-bold'; - statusText.innerHTML = `🚀 Nouvelle version disponible : v${escapeHtml(data.latest_version)} !`; + statusText.innerHTML = `${adminIcon('rocket', 'w-3.5 h-3.5 text-indigo-300')} Nouvelle version disponible : v${escapeHtml(data.latest_version)} !`; } if (btnRun) { btnRun.style.display = 'inline-flex'; @@ -6911,13 +6936,13 @@ async function refreshClusterStatus() { if (svcKeepalived) { if (!st.keepalived_installed) { svcKeepalived.className = 'font-mono text-amber-400 font-bold'; - svcKeepalived.textContent = '⚠️ Non installé'; + svcKeepalived.innerHTML = adminIcon('warning', 'w-3 h-3 text-amber-400') + ' Non installé'; } else if (st.keepalived_running) { svcKeepalived.className = 'font-mono text-emerald-400 font-bold'; - svcKeepalived.textContent = '🟢 Actif (En cours)'; + svcKeepalived.innerHTML = 'Actif (En cours)'; } else { svcKeepalived.className = 'font-mono text-slate-400'; - svcKeepalived.textContent = '⚪ Arrêté'; + svcKeepalived.innerHTML = 'Arrêté'; } } @@ -6925,13 +6950,13 @@ async function refreshClusterStatus() { if (svcAsterisk) { if (st.asterisk_healthy) { svcAsterisk.className = 'font-mono text-emerald-400 font-bold'; - svcAsterisk.textContent = '🟢 En ligne (Ping Pong OK)'; + svcAsterisk.innerHTML = 'En ligne (Ping Pong OK)'; } else if (st.asterisk_running) { svcAsterisk.className = 'font-mono text-amber-400 font-bold'; - svcAsterisk.textContent = '🟡 En cours (Ping en attente)'; + svcAsterisk.innerHTML = 'En cours (Ping en attente)'; } else { svcAsterisk.className = 'font-mono text-red-400 font-bold'; - svcAsterisk.textContent = '🔴 Arrêté'; + svcAsterisk.innerHTML = 'Arrêté'; } } @@ -6941,10 +6966,10 @@ async function refreshClusterStatus() { svcPeer.textContent = 'Non configuré'; svcPeer.className = 'font-mono text-slate-500'; } else if (st.peer_reachable) { - svcPeer.textContent = `🟢 Joignable (${st.peer_ping_ms !== null ? st.peer_ping_ms.toFixed(1) + 'ms' : 'OK'})`; + svcPeer.innerHTML = `Joignable (${st.peer_ping_ms !== null ? st.peer_ping_ms.toFixed(1) + 'ms' : 'OK'})`; svcPeer.className = 'font-mono text-emerald-400 font-bold'; } else { - svcPeer.textContent = '🔴 Injoignable (Timeout)'; + svcPeer.innerHTML = 'Injoignable (Timeout)'; svcPeer.className = 'font-mono text-red-400 font-bold'; } } @@ -7088,11 +7113,11 @@ function renderUcpTab() { const links = []; if (httpsPort > 0) { const url = `https://${host}:${httpsPort}/`; - links.push(`🔒 ${escapeHtml(url)}`); + links.push(`${adminIcon('lock', 'w-3.5 h-3.5')} ${escapeHtml(url)}`); } if (httpPort > 0) { const url = `http://${host}:${httpPort}/`; - links.push(`🌐 ${escapeHtml(url)} (Reverse Proxy)`); + links.push(`${adminIcon('globe', 'w-3.5 h-3.5')} ${escapeHtml(url)} (Reverse Proxy)`); } urlsBox.innerHTML = links.length ? links.join('') : 'Aucun port d’écoute configuré.'; } diff --git a/public/index.php b/public/index.php index 08fc338..b37e137 100644 --- a/public/index.php +++ b/public/index.php @@ -41,7 +41,7 @@ $isDevEnv = file_exists(__DIR__ . '/../.dev') - <?= $isDevEnv ? '🛠️ [DEV] ' : '' ?>NexusPBX — Supervision & Téléphonie IP • Powered by Asterisk + <?= $isDevEnv ? '[DEV] ' : '' ?>NexusPBX — Supervision & Téléphonie IP • Powered by Asterisk @@ -537,7 +537,7 @@ $isDevEnv = file_exists(__DIR__ . '/../.dev') @@ -1383,14 +1383,14 @@ $isDevEnv = file_exists(__DIR__ . '/../.dev')
-
📢
+
Annonce Générale de Groupe (Paging)

Composez le numéro du groupe configuré (ex: 100). Les téléphones cibles décrochent automatiquement sur haut-parleur après un bip d'avertissement sonore.

-
📞
+
Interphonie Directe 1-à-1 (*80 + poste)

Composez *80 suivi du numéro de l'extension (ex: *80101) pour ouvrir directement le haut-parleur et le micro du poste en conversation duplex.

@@ -2482,8 +2482,9 @@ $isDevEnv = file_exists(__DIR__ . '/../.dev')
Ligne (Line)Line 1
Extension (Pickup)**
-
- 💡 Quand le poste surveillé sonne, sa touche clignote : un simple appui dessus intercepte l'appel immédiatement via le préfixe ** ! +
+ + Quand le poste surveillé sonne, sa touche clignote : un simple appui dessus intercepte l'appel immédiatement via le préfixe ** !
@@ -2559,7 +2560,7 @@ $isDevEnv = file_exists(__DIR__ . '/../.dev')
Réseaux Locaux (Local Networks - CIDR) *
@@ -3068,9 +3069,9 @@ $isDevEnv = file_exists(__DIR__ . '/../.dev') + class="px-2.5 py-2 rounded-xl bg-anthracite-900 border border-anthracite-700 text-slate-300 hover:text-white transition"> + class="px-2.5 py-2 rounded-xl bg-anthracite-900 border border-anthracite-700 text-slate-300 hover:text-white transition"> @@ -3159,7 +3160,7 @@ $isDevEnv = file_exists(__DIR__ . '/../.dev')
- 💡 Conseil d'Architecture : Vos téléphones IP (Yealink, Groundwire) et vos Trunks SIP doivent pointer sur l'adresse IP Virtuelle (VIP). + Conseil d'Architecture : Vos téléphones IP (Yealink, Groundwire) et vos Trunks SIP doivent pointer sur l'adresse IP Virtuelle (VIP).
@@ -3181,11 +3182,11 @@ $isDevEnv = file_exists(__DIR__ . '/../.dev')
@@ -3377,7 +3378,7 @@ $isDevEnv = file_exists(__DIR__ . '/../.dev')
- 💡 +
Notification MWI automatique : Le voyant LED ou l'enveloppe clignoteront sur vos téléphones IP (Yealink, Fanvil, Grandstream, Snom...) dès qu'un message vocal est reçu. @@ -3711,11 +3712,11 @@ $isDevEnv = file_exists(__DIR__ . '/../.dev')
@@ -3757,11 +3758,11 @@ $isDevEnv = file_exists(__DIR__ . '/../.dev')
- +
- +
@@ -3772,7 +3773,7 @@ $isDevEnv = file_exists(__DIR__ . '/../.dev')
-
🪄 Masques de numérotation pré-définis (1 clic)
+
Masques de numérotation pré-définis (1 clic)

Ajoutez instantanément les masques standards ou créez vos propres règles (prepend) + préfixe | [match pattern / ID appelant].

@@ -3851,7 +3852,7 @@ $isDevEnv = file_exists(__DIR__ . '/../.dev')
-
👥 Groupes d'Extensions Autorisés (ex: Groupe Nice, Groupe Paris)
+
Groupes d'Extensions Autorisés (ex: Groupe Nice, Groupe Paris)

Tous les postes rattachés à un groupe d'extensions coché ci-dessous auront le droit d'appeler via cette route sortante.

` : ''; @@ -374,13 +397,13 @@ function renderExtensionsGrid() { @@ -546,21 +569,25 @@ function renderVoicemailsList() { ${escapeHtml(msg.callerid)} ${badge}
-
- 📅 ${escapeHtml(msg.date_human)} • ⏱️ ${formatDuration(msg.duration)} +
+ ${ucpIcon('calendar', 'w-3.5 h-3.5 text-slate-400')} ${escapeHtml(msg.date_human)} + • + ${ucpIcon('clock', 'w-3.5 h-3.5 text-slate-400')} ${formatDuration(msg.duration)}
- - ⬇️ Télécharger + + ${ucpIcon('download', 'w-3.5 h-3.5 text-slate-500')} + Télécharger
@@ -722,7 +749,7 @@ async function loadPersonalCdr() { ${dirBadge} ${stBadge} - ⏱ ${durText} + ${ucpIcon('clock', 'w-3.5 h-3.5 text-slate-400')} ${durText}
${formatInlineParty(srcName, srcNum)} @@ -864,17 +891,18 @@ function renderPhonebookGrid() {
${escapeHtml(c.group_name || 'Général')}
- ${c.internal_number ? `
📱 Interne : ${escapeHtml(c.internal_number)}
` : ''} - ${c.mobile_number ? `
📲 Mobile : ${escapeHtml(c.mobile_number)}
` : ''} - ${c.other_number ? `
☎️ Autre : ${escapeHtml(c.other_number)}
` : ''} - ${c.email ? `
✉️ ${escapeHtml(c.email)}
` : ''} + ${c.internal_number ? `
${ucpIcon('phone', 'w-3.5 h-3.5 text-indigo-500')} Interne : ${escapeHtml(c.internal_number)}
` : ''} + ${c.mobile_number ? `
${ucpIcon('mobile', 'w-3.5 h-3.5 text-emerald-500')} Mobile : ${escapeHtml(c.mobile_number)}
` : ''} + ${c.other_number ? `
${ucpIcon('phone', 'w-3.5 h-3.5 text-slate-400')} Autre : ${escapeHtml(c.other_number)}
` : ''} + ${c.email ? `
${ucpIcon('mail', 'w-3.5 h-3.5 text-slate-400')} ${escapeHtml(c.email)}
` : ''}
${c.is_mine ? ` ` : ''} @@ -996,7 +1024,7 @@ function renderFeatureGuide() { quickBox.innerHTML = `
- 📬 + ${ucpIcon('voicemail', 'w-4 h-4 text-indigo-600')} Utiliser la Messagerie Vocale
    @@ -1009,7 +1037,7 @@ function renderFeatureGuide() {
    - ↪️ + ${ucpIcon('forward', 'w-4 h-4 text-amber-600')} Gérer Renvois & Ne Pas Déranger
      @@ -1022,7 +1050,7 @@ function renderFeatureGuide() {
      - 🎧 + ${ucpIcon('pickup', 'w-4 h-4 text-emerald-600')} Interception & Prise d'Appel
        @@ -1049,12 +1077,12 @@ function renderFeatureGuide() { } const catMeta = { - voicemail: { label: 'Messagerie Vocale', icon: '📬', badge: 'bg-indigo-50 text-indigo-700 border-indigo-200', header: 'bg-indigo-50/60 border-indigo-100 text-indigo-950' }, - forward: { label: "Renvois d'Appel", icon: '↪️', badge: 'bg-amber-50 text-amber-800 border-amber-200', header: 'bg-amber-50/60 border-amber-100 text-amber-950' }, - dnd: { label: 'Ne Pas Déranger (DND)', icon: '🔕', badge: 'bg-rose-50 text-rose-700 border-rose-200', header: 'bg-rose-50/60 border-rose-100 text-rose-950' }, - pickup: { label: "Interception d'Appels", icon: '📲', badge: 'bg-emerald-50 text-emerald-700 border-emerald-200', header: 'bg-emerald-50/60 border-emerald-100 text-emerald-950' }, - security: { label: 'Liste Noire & Blocage Appels', icon: '🛡️', badge: 'bg-slate-100 text-slate-700 border-slate-300', header: 'bg-slate-100/80 border-slate-200 text-slate-900' }, - tools: { label: 'Outils, Tests Audio & Services', icon: '🛠️', badge: 'bg-sky-50 text-sky-700 border-sky-200', header: 'bg-sky-50/60 border-sky-100 text-sky-950' }, + voicemail: { label: 'Messagerie Vocale', icon: ucpIcon('voicemail', 'w-4 h-4 text-indigo-600'), badge: 'bg-indigo-50 text-indigo-700 border-indigo-200', header: 'bg-indigo-50/60 border-indigo-100 text-indigo-950' }, + forward: { label: "Renvois d'Appel", icon: ucpIcon('forward', 'w-4 h-4 text-amber-600'), badge: 'bg-amber-50 text-amber-800 border-amber-200', header: 'bg-amber-50/60 border-amber-100 text-amber-950' }, + dnd: { label: 'Ne Pas Déranger (DND)', icon: ucpIcon('dnd', 'w-4 h-4 text-rose-600'), badge: 'bg-rose-50 text-rose-700 border-rose-200', header: 'bg-rose-50/60 border-rose-100 text-rose-950' }, + pickup: { label: "Interception d'Appels", icon: ucpIcon('pickup', 'w-4 h-4 text-emerald-600'), badge: 'bg-emerald-50 text-emerald-700 border-emerald-200', header: 'bg-emerald-50/60 border-emerald-100 text-emerald-950' }, + security: { label: 'Liste Noire & Blocage Appels', icon: ucpIcon('shield', 'w-4 h-4 text-slate-600'), badge: 'bg-slate-100 text-slate-700 border-slate-300', header: 'bg-slate-100/80 border-slate-200 text-slate-900' }, + tools: { label: 'Outils, Tests Audio & Services', icon: ucpIcon('wrench', 'w-4 h-4 text-sky-600'), badge: 'bg-sky-50 text-sky-700 border-sky-200', header: 'bg-sky-50/60 border-sky-100 text-sky-950' }, }; const orderedCats = ['voicemail', 'forward', 'dnd', 'pickup', 'security', 'tools']; @@ -1071,7 +1099,7 @@ function renderFeatureGuide() { ]; catBox.innerHTML = catKeys.map(catKey => { - const meta = catMeta[catKey] || { label: catKey, icon: '📌', badge: 'bg-slate-100 text-slate-700 border-slate-300', header: 'bg-slate-50 border-slate-200 text-slate-900' }; + const meta = catMeta[catKey] || { label: catKey, icon: ucpIcon('tag', 'w-4 h-4 text-slate-500'), badge: 'bg-slate-100 text-slate-700 border-slate-300', header: 'bg-slate-50 border-slate-200 text-slate-900' }; const items = grouped.get(catKey) || []; const rows = items.map(item => ` diff --git a/ucp/index.php b/ucp/index.php index d2c791d..64b9a02 100644 --- a/ucp/index.php +++ b/ucp/index.php @@ -122,7 +122,9 @@ $csrfToken = UcpAuth::getCsrfToken();
        -
        🔒
        +
        + +

        Portail Utilisateur désactivé

        Ce service a été temporairement désactivé par votre administrateur système.

        @@ -216,29 +218,35 @@ $csrfToken = UcpAuth::getCsrfToken();
        @@ -451,7 +459,10 @@ $csrfToken = UcpAuth::getCsrfToken();
        -
        💡 Astuce : composez ces codes directement sur votre combiné IP, ou pilotez DND / renvois / messagerie depuis le portail UCP.
        +
        + + Astuce : composez ces codes directement sur votre combiné IP, ou pilotez DND / renvois / messagerie depuis le portail UCP. +
        — Document interne
      @@ -531,7 +542,8 @@ $csrfToken = UcpAuth::getCsrfToken();
      ?

      JPG, PNG ou WebP • 5 Mo max.

      diff --git a/version.json b/version.json index 297dc13..2e427c2 100644 --- a/version.json +++ b/version.json @@ -1,9 +1,17 @@ { - "version": "2.6.6", + "version": "2.6.7", "codename": "Pulsar UCP", "release_date": "2026-11-12", "min_php_version": "8.2", "changelog": [ + { + "version": "2.6.7", + "date": "2026-11-12", + "changes": [ + "UI Admin & UCP : Remplacement de l'ensemble des icônes emoji par des icônes vectorielles SVG uniformes (style Heroicons), sans modifier le menu latéral Admin", + "Correction d'un problème de syntaxe JS sur le badge d'avertissement TLS dans app.js" + ] + }, "UI v2.6.6 : menu déroulant personnalisé sombre avec icônes SVG Heroicons pour toutes les destinations d'appel (sans emojis natifs)", "UI v2.6.5 : refonte des intitulés de destinations audio (Musique d'attente & Annonce vocale en boucle continue), nouveau wallpaper clair UCP et placeholder générique", "Correctif v2.6.4 : prise en charge multi-groupes dans l'annuaire UCP & Admin (un poste appartenant à plusieurs groupes apparaît bien dans chacun des onglets correspondants)",