diff --git a/app/archiver/manager.py b/app/archiver/manager.py index e6a6ab3..c3d94c9 100644 --- a/app/archiver/manager.py +++ b/app/archiver/manager.py @@ -296,7 +296,7 @@ def _cleanup_job(): return # Convert to list format (same as preview-cleanup endpoint) - type_labels = {1: 'CLI', 2: 'REP', 3: 'ROOM', 4: 'SENS'} + type_labels = {1: 'COM', 2: 'REP', 3: 'ROOM', 4: 'SENS'} contacts = [] for public_key, details in contacts_detailed.items(): contacts.append({ diff --git a/app/contacts_cache.py b/app/contacts_cache.py index cbd6e55..f2fd39a 100644 --- a/app/contacts_cache.py +++ b/app/contacts_cache.py @@ -6,7 +6,7 @@ so @mention autocomplete works even for removed contacts. File format: JSONL ({device_name}.contacts_cache.jsonl) Each line: {"public_key": "...", "name": "...", "first_seen": ts, "last_seen": ts, - "source": "advert"|"device", "lat": float, "lon": float, "type_label": "CLI"|"REP"|...} + "source": "advert"|"device", "lat": float, "lon": float, "type_label": "COM"|"REP"|...} """ import json @@ -63,6 +63,9 @@ def load_cache() -> dict: entry = json.loads(line) pk = entry.get('public_key', '').lower() if pk: + # Migrate old "CLI" label to "COM" + if entry.get('type_label') == 'CLI': + entry['type_label'] = 'COM' _cache[pk] = entry except json.JSONDecodeError: continue @@ -248,7 +251,7 @@ def scan_new_adverts() -> int: return updated -_TYPE_LABELS = {1: 'CLI', 2: 'REP', 3: 'ROOM', 4: 'SENS'} +_TYPE_LABELS = {1: 'COM', 2: 'REP', 3: 'ROOM', 4: 'SENS'} def initialize_from_device(contacts_detailed: dict): diff --git a/app/main.py b/app/main.py index 03e1f97..bd42ad4 100644 --- a/app/main.py +++ b/app/main.py @@ -365,7 +365,7 @@ def _execute_console_command(args: list) -> str: elif cmd == 'contacts': # Show device-only contacts with path info (like meshcore-cli) - type_names = {0: 'NONE', 1: 'CLI', 2: 'REP', 3: 'ROOM', 4: 'SENS'} + type_names = {0: 'NONE', 1: 'COM', 2: 'REP', 3: 'ROOM', 4: 'SENS'} if not device_manager.mc or not device_manager.mc.contacts: return "No contacts on device" try: diff --git a/app/meshcore/cli.py b/app/meshcore/cli.py index f67ecb8..56d1a5d 100644 --- a/app/meshcore/cli.py +++ b/app/meshcore/cli.py @@ -130,7 +130,7 @@ def get_all_contacts_detailed() -> Tuple[bool, List[Dict], int, str]: result.append({ 'name': c.get('name', ''), 'public_key_prefix': pk[:12] if len(pk) >= 12 else pk, - 'type_label': {0: 'CLI', 1: 'CLI', 2: 'REP', 3: 'ROOM', 4: 'SENS'}.get(c.get('type', 1), 'UNKNOWN'), + 'type_label': {0: 'COM', 1: 'COM', 2: 'REP', 3: 'ROOM', 4: 'SENS'}.get(c.get('type', 1), 'UNKNOWN'), 'path_or_mode': c.get('out_path', '') or 'Flood', 'raw_line': '', }) diff --git a/app/routes/api.py b/app/routes/api.py index ab03819..9115b0c 100644 --- a/app/routes/api.py +++ b/app/routes/api.py @@ -696,7 +696,7 @@ def get_cached_contacts(): 'source': c.get('source', ''), 'adv_lat': c.get('adv_lat'), 'adv_lon': c.get('adv_lon'), - 'type_label': {0: 'CLI', 1: 'CLI', 2: 'REP', 3: 'ROOM', 4: 'SENS'}.get(c.get('type', 1), 'UNKNOWN'), + 'type_label': {0: 'COM', 1: 'COM', 2: 'REP', 3: 'ROOM', 4: 'SENS'}.get(c.get('type', 1), 'UNKNOWN'), 'is_ignored': pk in ignored_keys, 'is_blocked': pk in blocked_keys, }) @@ -811,7 +811,7 @@ def preview_cleanup_contacts(): JSON body: { "name_filter": "", # Partial name match (empty = ignore) - "types": [1, 2, 3, 4], # Contact types (1=CLI, 2=REP, 3=ROOM, 4=SENS) + "types": [1, 2, 3, 4], # Contact types (1=COM, 2=REP, 3=ROOM, 4=SENS) "date_field": "last_advert", # "last_advert" or "lastmod" "days": 2 # Days of inactivity (0 = ignore) } @@ -865,7 +865,7 @@ def preview_cleanup_contacts(): }), 500 # Convert to list format (same as /api/contacts/detailed) - type_labels = {1: 'CLI', 2: 'REP', 3: 'ROOM', 4: 'SENS'} + type_labels = {1: 'COM', 2: 'REP', 3: 'ROOM', 4: 'SENS'} contacts = [] for public_key, details in contacts_detailed.items(): out_path_len = details.get('out_path_len', -1) @@ -907,7 +907,7 @@ def cleanup_contacts(): JSON body: { "name_filter": "", # Partial name match (empty = ignore) - "types": [1, 2, 3, 4], # Contact types (1=CLI, 2=REP, 3=ROOM, 4=SENS) + "types": [1, 2, 3, 4], # Contact types (1=COM, 2=REP, 3=ROOM, 4=SENS) "date_field": "last_advert", # "last_advert" or "lastmod" "days": 2 # Days of inactivity (0 = ignore) } @@ -965,7 +965,7 @@ def cleanup_contacts(): }), 500 # Convert to list format - type_labels = {1: 'CLI', 2: 'REP', 3: 'ROOM', 4: 'SENS'} + type_labels = {1: 'COM', 2: 'REP', 3: 'ROOM', 4: 'SENS'} contacts = [] for public_key, details in contacts_detailed.items(): out_path_len = details.get('out_path_len', -1) @@ -2254,7 +2254,7 @@ def get_dm_updates(): @api_bp.route('/contacts/detailed', methods=['GET']) def get_contacts_detailed_api(): """ - Get detailed list of ALL existing contacts on the device (CLI, REP, ROOM, SENS). + Get detailed list of ALL existing contacts on the device (COM, REP, ROOM, SENS). Returns full contact_info data from meshcli including GPS coordinates, paths, etc. @@ -2269,7 +2269,7 @@ def get_contacts_detailed_api(): "name": "TK Zalesie Test 🦜", // adv_name "public_key": "df2027d3f2ef...", // Full public key (64 chars) "public_key_prefix": "df2027d3f2ef", // First 12 chars - "type": 2, // 1=CLI, 2=REP, 3=ROOM, 4=SENS + "type": 2, // 1=COM, 2=REP, 3=ROOM, 4=SENS "type_label": "REP", // Human-readable type "flags": 0, "out_path_len": -1, // -1 = Flood mode @@ -2298,7 +2298,7 @@ def get_contacts_detailed_api(): }), 500 # Convert dict to list and add computed fields - type_labels = {1: 'CLI', 2: 'REP', 3: 'ROOM', 4: 'SENS'} + type_labels = {1: 'COM', 2: 'REP', 3: 'ROOM', 4: 'SENS'} contacts = [] # Get protected/ignored/blocked contacts for status fields @@ -2868,8 +2868,8 @@ def get_pending_contacts_api(): Query parameters: types (list[int]): Filter by contact types (optional) - Example: ?types=1&types=2 (CLI and REP only) - Valid values: 1 (CLI), 2 (REP), 3 (ROOM), 4 (SENS) + Example: ?types=1&types=2 (COM and REP only) + Valid values: 1 (COM), 2 (REP), 3 (ROOM), 4 (SENS) If not provided, returns all pending contacts Returns: @@ -2906,7 +2906,7 @@ def get_pending_contacts_api(): if invalid_types: return jsonify({ 'success': False, - 'error': f'Invalid types: {invalid_types}. Valid types: 1 (CLI), 2 (REP), 3 (ROOM), 4 (SENS)', + 'error': f'Invalid types: {invalid_types}. Valid types: 1 (COM), 2 (REP), 3 (ROOM), 4 (SENS)', 'pending': [] }), 400 @@ -2922,9 +2922,9 @@ def get_pending_contacts_api(): 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'} + type_labels = {1: 'COM', 2: 'REP', 3: 'ROOM', 4: 'SENS'} for c in pending: - c['type_label'] = type_labels.get(c.get('type', 0), 'CLI') + c['type_label'] = type_labels.get(c.get('type', 0), 'COM') pk = c.get('public_key', '') c['public_key_prefix'] = pk[:12] if len(pk) >= 12 else pk @@ -2964,7 +2964,7 @@ def approve_pending_contact_api(): } IMPORTANT: Always send the full public_key (not name or prefix). - Full public key works for all contact types (CLI, ROOM, REP, SENS). + Full public key works for all contact types (COM, ROOM, REP, SENS). Returns: JSON with approval result: diff --git a/app/static/js/app.js b/app/static/js/app.js index 4c85225..79d74b0 100644 --- a/app/static/js/app.js +++ b/app/static/js/app.js @@ -40,14 +40,14 @@ let isMentionMode = false; // Is mention dropdown active // Contact type colors for map markers const CONTACT_TYPE_COLORS = { - 1: '#2196F3', // CLI - blue + 1: '#2196F3', // COM - blue 2: '#4CAF50', // REP - green 3: '#9C27B0', // ROOM - purple 4: '#FF9800' // SENS - orange }; const CONTACT_TYPE_NAMES = { - 1: 'CLI', + 1: 'COM', 2: 'REP', 3: 'ROOM', 4: 'SENS' @@ -140,7 +140,7 @@ window.showContactOnMap = showContactOnMap; */ function getSelectedMapTypes() { const types = []; - if (document.getElementById('mapFilterCLI')?.classList.contains('active')) types.push(1); + if (document.getElementById('mapFilterCOM')?.classList.contains('active')) types.push(1); if (document.getElementById('mapFilterREP')?.classList.contains('active')) types.push(2); if (document.getElementById('mapFilterROOM')?.classList.contains('active')) types.push(3); if (document.getElementById('mapFilterSENS')?.classList.contains('active')) types.push(4); @@ -162,7 +162,7 @@ function updateMapMarkers() { const filteredContacts = allContactsWithGps.filter(c => selectedTypes.includes(c.type)); // Cache-only contacts (not on device) filtered by type - const TYPE_LABEL_TO_NUM = { 'CLI': 1, 'REP': 2, 'ROOM': 3, 'SENS': 4 }; + const TYPE_LABEL_TO_NUM = { 'COM': 1, 'REP': 2, 'ROOM': 3, 'SENS': 4 }; let cachedFiltered = []; if (showCached) { cachedFiltered = allCachedContactsWithGps @@ -295,7 +295,7 @@ async function showAllContactsOnMap() { }; // Setup filter badge listeners - ['mapFilterCLI', 'mapFilterREP', 'mapFilterROOM', 'mapFilterSENS'].forEach(id => { + ['mapFilterCOM', 'mapFilterREP', 'mapFilterROOM', 'mapFilterSENS'].forEach(id => { const badge = document.getElementById(id); if (badge) { badge.onclick = () => { @@ -3303,7 +3303,7 @@ async function updatePendingContactsBadge() { /** * Load pending contacts type filter from localStorage. * This is a duplicate of the function in contacts.js for use in app.js - * @returns {Array} Array of contact types (default: [1] for CLI only) + * @returns {Array} Array of contact types (default: [1] for COM only) */ function loadPendingTypeFilter() { try { @@ -3318,7 +3318,7 @@ function loadPendingTypeFilter() { } catch (e) { console.error('Failed to load pending type filter from localStorage:', e); } - // Default: CLI only (most common use case) + // Default: COM only (most common use case) return [1]; } diff --git a/app/static/js/contacts.js b/app/static/js/contacts.js index 75e3f51..382b5cb 100644 --- a/app/static/js/contacts.js +++ b/app/static/js/contacts.js @@ -769,7 +769,7 @@ function attachPendingEventListeners() { } // Type filter badges - toggle on click, save to localStorage and reload - ['typeFilterCLI', 'typeFilterREP', 'typeFilterROOM', 'typeFilterSENS'].forEach(id => { + ['typeFilterCOM', 'typeFilterREP', 'typeFilterROOM', 'typeFilterSENS'].forEach(id => { const badge = document.getElementById(id); if (badge) { badge.addEventListener('click', () => { @@ -1154,7 +1154,7 @@ function isContactProtected(publicKey) { * This allows the filter to persist across page reloads and be used * in different parts of the app (Pending page, Contact Management badge, etc.) * - * @param {Array} types - Array of contact types to filter (1=CLI, 2=REP, 3=ROOM, 4=SENS) + * @param {Array} types - Array of contact types to filter (1=COM, 2=REP, 3=ROOM, 4=SENS) */ function savePendingTypeFilter(types) { try { @@ -1168,7 +1168,7 @@ function savePendingTypeFilter(types) { /** * Load pending contacts type filter from localStorage. * - * @returns {Array} Array of contact types (default: [1] for CLI only) + * @returns {Array} Array of contact types (default: [1] for COM only) */ function loadPendingTypeFilter() { try { @@ -1184,17 +1184,17 @@ function loadPendingTypeFilter() { } catch (e) { console.error('Failed to load pending type filter from localStorage:', e); } - // Default: CLI only (most common use case) + // Default: COM only (most common use case) return [1]; } /** * Set type filter badges based on types array. - * @param {Array} types - Array of contact types (1=CLI, 2=REP, 3=ROOM, 4=SENS) + * @param {Array} types - Array of contact types (1=COM, 2=REP, 3=ROOM, 4=SENS) */ function setTypeFilterBadges(types) { const badges = { - 1: document.getElementById('typeFilterCLI'), + 1: document.getElementById('typeFilterCOM'), 2: document.getElementById('typeFilterREP'), 3: document.getElementById('typeFilterROOM'), 4: document.getElementById('typeFilterSENS') @@ -1218,7 +1218,7 @@ function setTypeFilterBadges(types) { */ function getSelectedTypes() { const types = []; - if (document.getElementById('typeFilterCLI')?.classList.contains('active')) types.push(1); + if (document.getElementById('typeFilterCOM')?.classList.contains('active')) types.push(1); if (document.getElementById('typeFilterREP')?.classList.contains('active')) types.push(2); if (document.getElementById('typeFilterROOM')?.classList.contains('active')) types.push(3); if (document.getElementById('typeFilterSENS')?.classList.contains('active')) types.push(4); @@ -1269,7 +1269,7 @@ async function loadPendingContacts() { if (filteredCountBadge) filteredCountBadge.textContent = '0'; filteredPendingContacts = []; } else { - // Initialize filtered list and apply filters (default: CLI only) + // Initialize filtered list and apply filters (default: COM only) filteredPendingContacts = [...pendingContacts]; applyPendingFilters(); @@ -1338,11 +1338,11 @@ function createContactCard(contact, index) { const typeBadge = document.createElement('span'); typeBadge.className = 'badge type-badge'; - typeBadge.textContent = contact.type_label || 'CLI'; + typeBadge.textContent = contact.type_label || 'COM'; // Color-code by type (same as existing contacts) switch (contact.type_label) { - case 'CLI': + case 'COM': typeBadge.classList.add('bg-primary'); break; case 'REP': @@ -1441,7 +1441,7 @@ async function approveContact(contact, index) { 'Content-Type': 'application/json' }, body: JSON.stringify({ - public_key: contact.public_key // ALWAYS use full public_key (works for CLI, ROOM, etc.) + public_key: contact.public_key // ALWAYS use full public_key (works for COM, ROOM, etc.) }) }); @@ -1556,7 +1556,7 @@ function showBatchApprovalModal() { typeBadge.textContent = contact.type_label; switch (contact.type_label) { - case 'CLI': + case 'COM': typeBadge.classList.add('bg-primary'); break; case 'REP': @@ -1675,7 +1675,7 @@ function showBatchIgnoreModal() { typeBadge.textContent = contact.type_label; switch (contact.type_label) { - case 'CLI': typeBadge.classList.add('bg-primary'); break; + case 'COM': typeBadge.classList.add('bg-primary'); break; case 'REP': typeBadge.classList.add('bg-success'); break; case 'ROOM': typeBadge.classList.add('bg-info'); break; case 'SENS': typeBadge.classList.add('bg-warning', 'text-dark'); break; @@ -2180,7 +2180,7 @@ function createExistingContactCard(contact, index) { if (contact.type_label) { typeBadge.textContent = contact.type_label; switch (contact.type_label) { - case 'CLI': typeBadge.classList.add('bg-primary'); break; + case 'COM': typeBadge.classList.add('bg-primary'); break; case 'REP': typeBadge.classList.add('bg-success'); break; case 'ROOM': typeBadge.classList.add('bg-info'); break; case 'SENS': typeBadge.classList.add('bg-warning'); break; diff --git a/app/static/js/dm.js b/app/static/js/dm.js index 77d84d0..ea6ed9a 100644 --- a/app/static/js/dm.js +++ b/app/static/js/dm.js @@ -508,7 +508,7 @@ function createDropdownItem(name, conversationId, isUnread, contact) { if (contact && contact.type_label) { const badge = document.createElement('span'); badge.className = 'badge'; - const colors = { CLI: 'bg-primary', REP: 'bg-success', ROOM: 'bg-info', SENS: 'bg-warning' }; + const colors = { COM: 'bg-primary', REP: 'bg-success', ROOM: 'bg-info', SENS: 'bg-warning' }; badge.classList.add(colors[contact.type_label] || 'bg-secondary'); badge.textContent = contact.type_label; el.appendChild(badge); @@ -695,7 +695,7 @@ function populateContactInfoModal() { if (contact.type_label) { const badge = document.createElement('span'); badge.className = 'badge'; - const colors = { CLI: 'bg-primary', REP: 'bg-success', ROOM: 'bg-info', SENS: 'bg-warning' }; + const colors = { COM: 'bg-primary', REP: 'bg-success', ROOM: 'bg-info', SENS: 'bg-warning' }; badge.classList.add(colors[contact.type_label] || 'bg-secondary'); badge.textContent = contact.type_label; nameRow.appendChild(badge); diff --git a/app/templates/base.html b/app/templates/base.html index 4b415fe..0691f69 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -421,7 +421,7 @@
- CLI + COM REP ROOM SENS diff --git a/app/templates/contacts-existing.html b/app/templates/contacts-existing.html index 7e88340..0295ccb 100644 --- a/app/templates/contacts-existing.html +++ b/app/templates/contacts-existing.html @@ -41,7 +41,7 @@ - + +
diff --git a/app/templates/contacts-pending.html b/app/templates/contacts-pending.html index 2049d89..f50ac31 100644 --- a/app/templates/contacts-pending.html +++ b/app/templates/contacts-pending.html @@ -35,7 +35,7 @@
- CLI + COM REP ROOM SENS diff --git a/app/templates/contacts.html b/app/templates/contacts.html index d2f133f..a90b390 100644 --- a/app/templates/contacts.html +++ b/app/templates/contacts.html @@ -286,7 +286,7 @@