Root cause: Bootstrap offcanvas leaves backdrop/body classes in DOM
when navigating via window.location.href, causing viewport issues.
Changes:
- Remove hamburger menu button from DM navbar (caused overflow)
- Reduce menu button icon size on channels (remove font-size override)
- Add global navigateTo() function in app.js and contacts.js
- Function closes offcanvas, removes backdrops, clears body classes
- Replace all window.location.href calls with navigateTo()
- Updated navigation in: base.html, contacts*.html templates
- Add 100ms delay before navigation to ensure cleanup completes
This fixes the issue where:
1. Opening offcanvas menu on main page
2. Navigating to DM or Contact Management
3. Returning to main page
Results in corrupted viewport with hidden status bar
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Remove impractical path length filter from contact cleanup feature.
The out_path_len parameter is rarely useful as most contacts have
value -1 (no route), making this filter unpractical for real-world use.
Changes:
- Remove path_len parameter from backend API endpoints
- Remove path length input field from HTML template
- Remove path_len collection from JavaScript code
- Update documentation (CLAUDE.md, README.md)
- Simplify cleanup filter to: name, types, date field, and days
Backend changes:
- Update _filter_contacts_by_criteria() to remove path_len logic
- Remove path_len validation from both endpoints
- Update API documentation in docstrings
Frontend changes:
- Remove Path Length input section from contacts-manage.html
- Remove path_len from collectCleanupCriteria() function
Documentation changes:
- Update API endpoint descriptions in CLAUDE.md
- Update cleanup instructions in README.md
- Remove path_len from example use cases
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add Map button between Copy Key and Delete buttons on existing contacts cards.
Button appears only when contact has GPS coordinates (adv_lat/adv_lon != 0).
Opens contact location in Google Maps in new tab.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Move toast container from bottom-right to top-left corner
- Reduce notification display time from 3-5s to 1.5s
- Prevents notifications from blocking message input area
- Applied consistently across all pages (main, DM, contacts)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Testing revealed that meshcli's remove_contact command only works
with contact names, not with public keys (neither prefix nor full key).
Example test results:
- remove_contact bd030a71e091 → Unknown contact
- remove_contact bd030a71e091b14e...f7a → Unknown contact
- remove_contact "Progres-SLU-Lubsza-test" → SUCCESS
Changed frontend to send contact name as selector.
Problem:
- meshcli's remove_contact command requires full public key
- We were sending only 12-char prefix, causing 'Unknown contact' errors
- Contacts appeared in list but couldn't be deleted
Solution:
- API now includes full_public_key in /api/contacts/detailed response
- Frontend uses full_public_key when available, falls back to prefix
- Added detailed logging to track deletion attempts
This fixes the issue where contacts (especially with last_seen=4)
could not be removed from the device.
Add comprehensive "last seen" tracking for all contact types:
Backend (cli.py):
- New function get_contacts_with_last_seen() using 'apply_to t=1,t=2,t=3,t=4 contact_info'
- Fetches detailed contact metadata including last_advert timestamps
- Returns dictionary indexed by full public_key for efficient lookup
API (api.py):
- Enhanced /api/contacts/detailed endpoint to merge last_seen data
- Matches contacts by public_key_prefix (first 12 chars)
- Graceful fallback if detailed fetch fails (contacts still displayed without last_seen)
Frontend (contacts.js):
- formatRelativeTime() - converts Unix timestamps to human-readable format
("5 minutes ago", "2 hours ago", "3 days ago")
- getActivityStatus() - returns status indicator based on recency:
🟢 Active (< 5 min), 🟡 Recent (< 1 hour), 🔴 Inactive (> 1 hour)
- Contact cards now display "Last seen" with status icon and relative time
- Clean handling of missing last_seen data (shows "Unknown")
This feature helps users identify active vs. inactive contacts at a glance,
using the last_advert field from meshcli's contact_info command.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Compact Manual Approval and Pending Contacts sections to give more
space for Existing Contacts list, which is the primary focus.
Changes to Manual Approval section:
- Convert from full section to single-line compact control
- Replace description text with tooltip icon (hover for info)
- Reduce vertical space by ~70px
Changes to Pending Contacts section:
- Reduce header size from h5 to h6
- Compact empty state (1rem padding vs 3rem)
- Reduce icon size (1.5rem vs 3rem)
- Limit list height to 200px (was 600px)
- Remove "Refresh" text from button (icon only)
Changes to Existing Contacts section:
- Dynamic height: calc(100vh - 400px) with 300px minimum
- Adapts to viewport height automatically
- On mobile: calc(100vh - 450px) for better fit
- More contacts visible without scrolling
Other improvements:
- Initialize Bootstrap tooltips in contacts.js
- Smaller fonts and margins throughout
- Better vertical space distribution
Result: ~150px more space for main contacts list on desktop,
~200px more on mobile. Tooltip provides same info without clutter.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>