From 0d5c021e40c80ebe254e0a57647c53da50926988 Mon Sep 17 00:00:00 2001 From: MarekWo Date: Tue, 10 Mar 2026 07:16:04 +0100 Subject: [PATCH] fix(contacts): type label bug, responsive buttons, remove Copy Key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix pending contacts always showing "CLI" — compute type_label in API - Remove Copy Key button from pending cards, make key clickable instead - Responsive contact buttons: icon+text on desktop, icon-only on <=768px - Add flex-wrap for button rows on small screens Co-Authored-By: Claude Opus 4.6 --- app/routes/api.py | 7 +++++++ app/static/css/style.css | 12 +++++++++++ app/static/js/contacts.js | 43 ++++++++++++++++----------------------- 3 files changed, 37 insertions(+), 25 deletions(-) diff --git a/app/routes/api.py b/app/routes/api.py index ee5f222..5f8c9d3 100644 --- a/app/routes/api.py +++ b/app/routes/api.py @@ -2751,6 +2751,13 @@ def get_pending_contacts_api(): excluded = ignored_keys | blocked_keys pending = [c for c in pending if c.get('public_key', '').lower() not in excluded] + # Add type_label for frontend display + type_labels = {1: 'CLI', 2: 'REP', 3: 'ROOM', 4: 'SENS'} + for c in pending: + c['type_label'] = type_labels.get(c.get('type', 0), 'CLI') + pk = c.get('public_key', '') + c['public_key_prefix'] = pk[:12] if len(pk) >= 12 else pk + # Filter by types if specified if types_param: pending = [contact for contact in pending if contact.get('type') in types_param] diff --git a/app/static/css/style.css b/app/static/css/style.css index f7000eb..81a92d8 100644 --- a/app/static/css/style.css +++ b/app/static/css/style.css @@ -333,6 +333,18 @@ main { font-size: 0.875rem; } + /* Contact card buttons: icon-only on mobile */ + .pending-contact-card .btn-label, + .existing-contact-card .btn-label { + display: none; + } + + /* Allow button wrapping on small screens */ + .pending-contact-card .d-flex.gap-2, + .existing-contact-card .d-flex.gap-2 { + flex-wrap: wrap; + } + /* Modal: Better mobile layout */ .modal-dialog { margin: 0.5rem; diff --git a/app/static/js/contacts.js b/app/static/js/contacts.js index 5c65d94..0ab3dea 100644 --- a/app/static/js/contacts.js +++ b/app/static/js/contacts.js @@ -1037,11 +1037,11 @@ function updateProtectionUI(publicKey, isProtected, buttonEl) { // Update button appearance buttonEl.disabled = false; if (isProtected) { - buttonEl.innerHTML = ' Protected'; + buttonEl.innerHTML = ' Protected'; buttonEl.classList.remove('btn-outline-warning'); buttonEl.classList.add('btn-warning'); } else { - buttonEl.innerHTML = ' Protect'; + buttonEl.innerHTML = ' Protect'; buttonEl.classList.remove('btn-warning'); buttonEl.classList.add('btn-outline-warning'); } @@ -1337,11 +1337,12 @@ function createContactCard(contact, index) { infoRow.appendChild(nameDiv); infoRow.appendChild(typeBadge); - // Public key row (use prefix for display) + // Public key row (clickable to copy) const keyDiv = document.createElement('div'); - keyDiv.className = 'contact-key'; + keyDiv.className = 'contact-key clickable-key'; keyDiv.textContent = contact.public_key_prefix || contact.public_key.substring(0, 12); - keyDiv.title = 'Public Key Prefix'; + keyDiv.title = 'Click to copy'; + keyDiv.onclick = () => copyToClipboard(keyDiv.textContent, keyDiv); // Last advert (optional - show if available) let lastAdvertDiv = null; @@ -1359,7 +1360,7 @@ function createContactCard(contact, index) { // Approve button const approveBtn = document.createElement('button'); approveBtn.className = 'btn btn-sm btn-success'; - approveBtn.innerHTML = ' Approve'; + approveBtn.innerHTML = ' Approve'; approveBtn.onclick = () => approveContact(contact, index); actionsDiv.appendChild(approveBtn); @@ -1368,23 +1369,15 @@ function createContactCard(contact, index) { if (contact.adv_lat && contact.adv_lon && (contact.adv_lat !== 0 || contact.adv_lon !== 0)) { const mapBtn = document.createElement('button'); mapBtn.className = 'btn btn-sm btn-outline-primary'; - mapBtn.innerHTML = ' Map'; + mapBtn.innerHTML = ' Map'; mapBtn.onclick = () => window.showContactOnMap(contact.name, contact.adv_lat, contact.adv_lon); actionsDiv.appendChild(mapBtn); } - // Copy key button - const copyBtn = document.createElement('button'); - copyBtn.className = 'btn btn-sm btn-outline-secondary'; - copyBtn.innerHTML = ' Copy Key'; - copyBtn.onclick = () => copyPublicKey(contact.public_key, copyBtn); - - actionsDiv.appendChild(copyBtn); - // Ignore button const ignoreBtn = document.createElement('button'); ignoreBtn.className = 'btn btn-sm btn-outline-secondary'; - ignoreBtn.innerHTML = ' Ignore'; + ignoreBtn.innerHTML = ' Ignore'; ignoreBtn.onclick = () => { toggleContactIgnore(contact.public_key, true).then(() => loadPendingContacts()); }; @@ -1393,7 +1386,7 @@ function createContactCard(contact, index) { // Block button const blockBtn = document.createElement('button'); blockBtn.className = 'btn btn-sm btn-outline-danger'; - blockBtn.innerHTML = ' Block'; + blockBtn.innerHTML = ' Block'; blockBtn.onclick = () => { toggleContactBlock(contact.public_key, true).then(() => loadPendingContacts()); }; @@ -2091,7 +2084,7 @@ function createExistingContactCard(contact, index) { if (contact.adv_lat && contact.adv_lon && (contact.adv_lat !== 0 || contact.adv_lon !== 0)) { const mapBtn = document.createElement('button'); mapBtn.className = 'btn btn-sm btn-outline-primary'; - mapBtn.innerHTML = ' Map'; + mapBtn.innerHTML = ' Map'; mapBtn.onclick = () => window.showContactOnMap(contact.name, contact.adv_lat, contact.adv_lon); actionsDiv.appendChild(mapBtn); } @@ -2101,14 +2094,14 @@ function createExistingContactCard(contact, index) { const protectBtn = document.createElement('button'); protectBtn.className = isProtected ? 'btn btn-sm btn-warning' : 'btn btn-sm btn-outline-warning'; protectBtn.innerHTML = isProtected - ? ' Protected' - : ' Protect'; + ? ' Protected' + : ' Protect'; protectBtn.onclick = () => toggleContactProtection(contact.public_key, protectBtn); actionsDiv.appendChild(protectBtn); const deleteBtn = document.createElement('button'); deleteBtn.className = 'btn btn-sm btn-outline-danger'; - deleteBtn.innerHTML = ' Delete'; + deleteBtn.innerHTML = ' Delete'; deleteBtn.onclick = () => showDeleteModal(contact); deleteBtn.disabled = isProtected; if (isProtected) { @@ -2121,25 +2114,25 @@ function createExistingContactCard(contact, index) { if (contact.is_blocked) { const unblockBtn = document.createElement('button'); unblockBtn.className = 'btn btn-sm btn-outline-success'; - unblockBtn.innerHTML = ' Unblock'; + unblockBtn.innerHTML = ' Unblock'; unblockBtn.onclick = () => toggleContactBlock(contact.public_key, false); actionsDiv.appendChild(unblockBtn); } else if (contact.is_ignored) { const unignoreBtn = document.createElement('button'); unignoreBtn.className = 'btn btn-sm btn-outline-success'; - unignoreBtn.innerHTML = ' Unignore'; + unignoreBtn.innerHTML = ' Unignore'; unignoreBtn.onclick = () => toggleContactIgnore(contact.public_key, false); actionsDiv.appendChild(unignoreBtn); } else { const ignoreBtn = document.createElement('button'); ignoreBtn.className = 'btn btn-sm btn-outline-secondary'; - ignoreBtn.innerHTML = ' Ignore'; + ignoreBtn.innerHTML = ' Ignore'; ignoreBtn.onclick = () => toggleContactIgnore(contact.public_key, true); actionsDiv.appendChild(ignoreBtn); const blockBtn = document.createElement('button'); blockBtn.className = 'btn btn-sm btn-outline-danger'; - blockBtn.innerHTML = ' Block'; + blockBtn.innerHTML = ' Block'; blockBtn.onclick = () => toggleContactBlock(contact.public_key, true); actionsDiv.appendChild(blockBtn); }