mirror of
https://github.com/MarekWo/mc-webui.git
synced 2026-08-07 17:22:57 +02:00
refactor(ui): rename contact type label CLI to COM (companion)
The MeshCore community uses "companion" not "client" for type 1 nodes. Rename the CLI label to COM across all UI, API, JS, and docs to align with official terminology. Includes cache migration for old CLI entries. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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({
|
||||
|
||||
@@ -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):
|
||||
|
||||
+1
-1
@@ -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:
|
||||
|
||||
+1
-1
@@ -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': '',
|
||||
})
|
||||
|
||||
+14
-14
@@ -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:
|
||||
|
||||
@@ -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<number>} Array of contact types (default: [1] for CLI only)
|
||||
* @returns {Array<number>} 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];
|
||||
}
|
||||
|
||||
|
||||
+14
-14
@@ -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<number>} types - Array of contact types to filter (1=CLI, 2=REP, 3=ROOM, 4=SENS)
|
||||
* @param {Array<number>} 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<number>} Array of contact types (default: [1] for CLI only)
|
||||
* @returns {Array<number>} 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<number>} types - Array of contact types (1=CLI, 2=REP, 3=ROOM, 4=SENS)
|
||||
* @param {Array<number>} 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;
|
||||
|
||||
+2
-2
@@ -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);
|
||||
|
||||
@@ -421,7 +421,7 @@
|
||||
<!-- Type filter (hidden for single contact view) -->
|
||||
<div id="mapTypeFilter" class="d-none px-3 py-2 border-bottom bg-light">
|
||||
<div class="d-flex flex-wrap gap-2 align-items-center">
|
||||
<span class="map-filter-badge active" data-type="1" id="mapFilterCLI">CLI</span>
|
||||
<span class="map-filter-badge active" data-type="1" id="mapFilterCOM">COM</span>
|
||||
<span class="map-filter-badge active" data-type="2" id="mapFilterREP">REP</span>
|
||||
<span class="map-filter-badge active" data-type="3" id="mapFilterROOM">ROOM</span>
|
||||
<span class="map-filter-badge active" data-type="4" id="mapFilterSENS">SENS</span>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<!-- Type Filter -->
|
||||
<select class="form-select" id="typeFilter">
|
||||
<option value="ALL">All Types</option>
|
||||
<option value="CLI">CLI</option>
|
||||
<option value="COM">COM</option>
|
||||
<option value="REP">REP</option>
|
||||
<option value="ROOM">ROOM</option>
|
||||
<option value="SENS">SENS</option>
|
||||
|
||||
@@ -85,8 +85,8 @@
|
||||
<label class="form-label">Contact Types:</label>
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input cleanup-type-filter" type="checkbox" value="1" id="cleanupTypeCLI" checked>
|
||||
<label class="form-check-label" for="cleanupTypeCLI">CLI</label>
|
||||
<input class="form-check-input cleanup-type-filter" type="checkbox" value="1" id="cleanupTypeCOM" checked>
|
||||
<label class="form-check-label" for="cleanupTypeCOM">COM</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input cleanup-type-filter" type="checkbox" value="2" id="cleanupTypeREP" checked>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
<!-- Type Filter Badges -->
|
||||
<div class="d-flex flex-wrap gap-2 mb-2">
|
||||
<span class="type-filter-badge active" data-type="CLI" id="typeFilterCLI">CLI</span>
|
||||
<span class="type-filter-badge active" data-type="COM" id="typeFilterCOM">COM</span>
|
||||
<span class="type-filter-badge" data-type="REP" id="typeFilterREP">REP</span>
|
||||
<span class="type-filter-badge" data-type="ROOM" id="typeFilterROOM">ROOM</span>
|
||||
<span class="type-filter-badge" data-type="SENS" id="typeFilterSENS">SENS</span>
|
||||
|
||||
@@ -286,7 +286,7 @@
|
||||
<input type="text" class="form-control" id="searchInput" placeholder="Search by name or public key...">
|
||||
<select class="form-select" id="typeFilter" style="max-width: 150px;">
|
||||
<option value="ALL">All Types</option>
|
||||
<option value="CLI">CLI</option>
|
||||
<option value="COM">COM</option>
|
||||
<option value="REP">REP</option>
|
||||
<option value="ROOM">ROOM</option>
|
||||
<option value="SENS">SENS</option>
|
||||
|
||||
@@ -165,12 +165,12 @@
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.type-filter-badge[data-type="CLI"] {
|
||||
.type-filter-badge[data-type="COM"] {
|
||||
color: #0d6efd;
|
||||
background-color: white;
|
||||
border: 2px solid #0d6efd;
|
||||
}
|
||||
.type-filter-badge[data-type="CLI"].active {
|
||||
.type-filter-badge[data-type="COM"].active {
|
||||
color: white;
|
||||
background-color: #0d6efd;
|
||||
}
|
||||
@@ -482,7 +482,7 @@
|
||||
<div id="mapTypeFilter" class="d-none px-3 py-2 border-bottom bg-light">
|
||||
<div class="d-flex flex-wrap gap-2 align-items-center">
|
||||
<span class="small text-muted me-1">Show:</span>
|
||||
<span class="map-filter-badge active" data-type="1" id="mapFilterCLI">CLI</span>
|
||||
<span class="map-filter-badge active" data-type="1" id="mapFilterCOM">COM</span>
|
||||
<span class="map-filter-badge active" data-type="2" id="mapFilterREP">REP</span>
|
||||
<span class="map-filter-badge active" data-type="3" id="mapFilterROOM">ROOM</span>
|
||||
<span class="map-filter-badge active" data-type="4" id="mapFilterSENS">SENS</span>
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ This guide explains how to manage a MeshCore repeater device directly from the m
|
||||
|
||||
<img src="../images/RPT-Mgmt-03-new-rpt-approve.png" alt="Approve repeater" width="200px">
|
||||
|
||||
- Reset your search filter (it is recommended to leave CLI selected only) and return to the main chat view
|
||||
- Reset your search filter (it is recommended to leave COM selected only) and return to the main chat view
|
||||
|
||||
<img src="../images/RPT-Mgmt-04-back-to-home.png" alt="Return to home" width="200px">
|
||||
|
||||
|
||||
@@ -330,7 +330,7 @@ After successful installation:
|
||||
|
||||
1. **Join channels** - Create or join encrypted channels with other users
|
||||
2. **Configure contacts** - Enable manual approval if desired
|
||||
3. **Test Direct Messages** - Send DM to other CLI contacts
|
||||
3. **Test Direct Messages** - Send DM to other COM contacts
|
||||
4. **Set up backups** - Schedule regular backups of `data/` directory
|
||||
5. **Read full documentation** - See [User Guide](user-guide.md) for all features
|
||||
|
||||
|
||||
+9
-9
@@ -149,7 +149,7 @@ Access the Direct Messages feature:
|
||||
1. **Select a recipient** from the dropdown at the top:
|
||||
- **Existing conversations** are shown first (with message history)
|
||||
- Separator: "--- Available contacts ---"
|
||||
- **All client contacts** from your device (only CLI type, no repeaters/rooms)
|
||||
- **All companion contacts** from your device (only COM type, no repeaters/rooms)
|
||||
- You can start a new conversation with anyone in your contacts list
|
||||
2. Type your message in the input field (max 140 bytes, same as channels)
|
||||
3. Use the emoji picker button to insert emojis
|
||||
@@ -162,7 +162,7 @@ Access the Direct Messages feature:
|
||||
- When you return to the DM page, it automatically opens the last conversation you were viewing
|
||||
- This works similarly to how the main page remembers your selected channel
|
||||
|
||||
**Note:** Only client contacts (CLI) are shown in the dropdown. Repeaters (REP), rooms (ROOM), and sensors (SENS) are automatically filtered out.
|
||||
**Note:** Only companion contacts (COM) are shown in the dropdown. Repeaters (REP), rooms (ROOM), and sensors (SENS) are automatically filtered out.
|
||||
|
||||
### Message Status Indicators
|
||||
|
||||
@@ -206,8 +206,8 @@ When manual approval is enabled, new contacts appear in the Pending Contacts lis
|
||||
|
||||
**View contact details:**
|
||||
- Contact name with emoji (if present)
|
||||
- Type badge (CLI, REP, ROOM, SENS) with color coding:
|
||||
- CLI (blue): Regular clients
|
||||
- Type badge (COM, REP, ROOM, SENS) with color coding:
|
||||
- COM (blue): Companions (clients)
|
||||
- REP (green): Repeaters
|
||||
- ROOM (cyan): Room servers
|
||||
- SENS (yellow): Sensors
|
||||
@@ -216,7 +216,7 @@ When manual approval is enabled, new contacts appear in the Pending Contacts lis
|
||||
- Map button (when GPS coordinates are available)
|
||||
|
||||
**Filter contacts:**
|
||||
- By type: Use checkboxes to show only specific contact types (default: CLI only)
|
||||
- By type: Use checkboxes to show only specific contact types (default: COM only)
|
||||
- By name or key: Search by partial contact name or public key prefix
|
||||
|
||||
**Approve contacts:**
|
||||
@@ -234,7 +234,7 @@ When manual approval is enabled, new contacts appear in the Pending Contacts lis
|
||||
|
||||
### Existing Contacts
|
||||
|
||||
The Existing Contacts section displays all contacts currently stored on your device (CLI, REP, ROOM, SENS types).
|
||||
The Existing Contacts section displays all contacts currently stored on your device (COM, REP, ROOM, SENS types).
|
||||
|
||||
**Features:**
|
||||
- **Counter badge** - Shows current contact count vs. 350 limit (MeshCore device max)
|
||||
@@ -242,7 +242,7 @@ The Existing Contacts section displays all contacts currently stored on your dev
|
||||
- Yellow: Warning (300-339 contacts)
|
||||
- Red (pulsing): Alarm (≥ 340 contacts)
|
||||
- **Search** - Filter contacts by name or public key prefix
|
||||
- **Type filter** - Show only specific contact types (All / CLI / REP / ROOM / SENS)
|
||||
- **Type filter** - Show only specific contact types (All / COM / REP / ROOM / SENS)
|
||||
- **Contact cards** - Display name, type badge, public key prefix, path info, and last seen timestamp
|
||||
- **Last Seen** - Shows when each contact was last active with activity indicators:
|
||||
- 🟢 **Active** (seen < 5 minutes ago)
|
||||
@@ -253,7 +253,7 @@ The Existing Contacts section displays all contacts currently stored on your dev
|
||||
|
||||
**Managing contacts:**
|
||||
1. **Search contacts:** Type in the search box to filter by name or public key prefix
|
||||
2. **Filter by type:** Use the type dropdown to show only CLI, REP, ROOM, or SENS
|
||||
2. **Filter by type:** Use the type dropdown to show only COM, REP, ROOM, or SENS
|
||||
3. **Copy public key:** Click "Copy Key" button to copy the public key prefix to clipboard
|
||||
4. **Delete a contact:** Click the "Delete" button (red trash icon) and confirm
|
||||
|
||||
@@ -286,7 +286,7 @@ The advanced cleanup tool allows you to filter and remove contacts based on mult
|
||||
3. Configure filters:
|
||||
- **Name Filter:** Enter partial contact name to search (optional)
|
||||
- **Advanced Filters** (collapsible):
|
||||
- **Contact Types:** Select which types to include (CLI, REP, ROOM, SENS)
|
||||
- **Contact Types:** Select which types to include (COM, REP, ROOM, SENS)
|
||||
- **Date Field:** Choose between "Last Advert" (recommended) or "Last Modified"
|
||||
- **Days of Inactivity:** Contacts inactive for more than X days (0 = ignore)
|
||||
4. Click **Preview Cleanup** to see matching contacts
|
||||
|
||||
@@ -30,7 +30,7 @@ EXPECTED_CONTACT_FIELDS = {
|
||||
}
|
||||
|
||||
# Valid contact types in text format
|
||||
VALID_CONTACT_TYPES = {"CLI", "REP", "ROOM", "SENS"}
|
||||
VALID_CONTACT_TYPES = {"COM", "REP", "ROOM", "SENS"}
|
||||
|
||||
# Expected fields in /health response
|
||||
EXPECTED_HEALTH_FIELDS = {
|
||||
@@ -148,7 +148,7 @@ class CompatChecker:
|
||||
return
|
||||
|
||||
# Parse using same logic as cli.py parse_contacts()
|
||||
type_counts = {"CLI": 0, "REP": 0, "ROOM": 0, "SENS": 0}
|
||||
type_counts = {"COM": 0, "REP": 0, "ROOM": 0, "SENS": 0}
|
||||
parsed = 0
|
||||
unparsed_lines = []
|
||||
|
||||
@@ -247,7 +247,7 @@ class CompatChecker:
|
||||
|
||||
stdout = data.get("stdout", "").strip()
|
||||
if not stdout:
|
||||
self.add(self.WARN, cat, "empty response (no CLI contacts)")
|
||||
self.add(self.WARN, cat, "empty response (no COM contacts)")
|
||||
return
|
||||
|
||||
# contact_info returns multiple JSON objects (one per contact)
|
||||
|
||||
Reference in New Issue
Block a user