43 Commits

Author SHA1 Message Date
MarekWo
7b2f721d1d fix(contacts): wrap long public keys in add contact previews
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 21:43:28 +01:00
MarekWo
878d489661 feat(contacts): add contact UI with URI paste, QR scan, and manual entry
Stage 2 of manual contact add feature:
- POST /api/contacts/manual-add endpoint (URI or raw params)
- New /contacts/add page with 3 input tabs (URI, QR code, Manual)
- QR scanning via html5-qrcode (camera + image upload fallback)
- Client-side URI parsing with preview before submission
- Nav card in Contact Management above Pending Contacts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 20:54:41 +01:00
MarekWo
9ee63188d2 feat(contacts): add push-to-device and move-to-cache operations
Enable moving contacts between device and cache directly from the
Existing Contacts UI:
- "To device" button on cache-only contacts (pushes to device)
- "To cache" button on device contacts (removes from device, keeps in DB)

This helps manage the 350-contact device limit by offloading inactive
contacts to cache and restoring them when needed.

- Add DeviceManager.push_to_device() and move_to_cache() methods
- Add API endpoints: POST /contacts/<pk>/push-to-device, move-to-cache
- Add UI buttons with confirm dialogs in contacts.js

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 18:06:26 +01:00
MarekWo
33a71bed17 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>
2026-03-21 14:37:30 +01:00
MarekWo
c48666843a fix(contacts): show ignored/blocked contacts in All Sources filter
Previously ignored and blocked contacts were hidden from the "All Sources"
view, making them only discoverable via dedicated Ignored/Blocked filters.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 21:22:52 +01:00
MarekWo
670715f57f fix(contacts): disable ignore/block buttons for protected contacts
- Existing Contacts: Ignore and Block buttons are now disabled when
  contact is protected, matching the existing Delete button behavior
- updateProtectionUI: toggling protection now also enables/disables
  Ignore, Block, and Delete buttons dynamically
- Chat: Ignore and Block buttons are hidden in message bubbles for
  protected contacts (loads protected pubkeys on init)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 09:15:44 +01:00
MarekWo
3337e3fdff feat(contacts): compact pending filters with batch ignore
- Remove redundant 'Contact Types:' label
- Move type badges above search input
- Place search, Approve, and Ignore buttons in single responsive row
- Add tooltip (i) on Filters header with usage hint
- Add batch Ignore button to ignore all filtered pending contacts
- Remove duplicate filtered count badge from Approve button

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 08:30:32 +01:00
MarekWo
f66e95ffa0 fix: contact delete by pubkey, cache contacts as pending, cache delete button
1. Delete button now sends public_key instead of name to avoid matching
   wrong contacts when multiple share similar names.
2. _on_advertisement adds cache-only contacts to mc.pending_contacts when
   manual approval is enabled, so they appear in the pending list after
   advertising (even if meshcore fires ADVERTISEMENT instead of NEW_CONTACT).
3. Added Delete button for cache-only contacts with dedicated
   /api/contacts/cached/delete endpoint and hard_delete_contact DB method.
4. approve_contact/reject_contact now handle DB-only pending contacts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 08:01:56 +01:00
MarekWo
3622619ba4 fix(contacts): decode path correctly using MeshCore V1 encoding
Path buffer from firmware contains trailing garbage bytes beyond the
actual hop data. out_path_len encodes both hop count (lower 6 bits)
and hash size (upper 2 bits). Now we:
- Truncate out_path to meaningful bytes (hop_count * hash_size)
- Format as readable E7→DE→54→54→D8 instead of raw hex string
- Show hop count derived from actual path arrows

Example: out_path_len=5 with out_path="e7de5454d81c49dfb86f8a"
now correctly displays as "E7→DE→54→54→D8 (5 hops)" instead of
showing the full 11-byte buffer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 21:26:06 +01:00
MarekWo
5f72f40742 feat(contacts): show path/route info in UI and split console commands
- Console `contacts` now shows device-only contacts with path info
  (matching meshcore-cli format: name, type, pubkey, path)
- New `contacts_all` command shows all contacts (device + cached from DB)
- Contact cards in UI now always show routing mode for device contacts
  (Flood, Direct 0 hop, or hex path with hop count)
- Fix path_or_mode computation: prioritize out_path over out_path_len
  to handle firmware edge case where out_path exists but out_path_len=-1

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 21:01:15 +01:00
MarekWo
833d01df9f fix(contacts): remove duplicate const declaration breaking contacts.js
applySortAndFilters() had duplicate const declarations for sourceFilter
and selectedSource, causing a SyntaxError that prevented the entire
contacts.js from loading. Both Pending and Existing pages were broken.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 21:14:10 +01:00
MarekWo
b0076c3739 feat(contacts): name-based blocking, fix CSS breakpoint
- New blocked_names table for blocking bots without known public_key
- get_blocked_contact_names() returns union of pubkey-blocked + name-blocked
- POST /api/contacts/block-name endpoint for name-based blocking
- GET /api/contacts/blocked-names-list for management UI
- Block button always visible in chat (falls back to name-based block)
- Blocked Names section shown in Existing Contacts Blocked filter
- CSS breakpoint for icon-only buttons: 768px → 428px (iPhone-sized)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 21:03:19 +01:00
MarekWo
0d5c021e40 fix(contacts): type label bug, responsive buttons, remove Copy Key
- 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 <noreply@anthropic.com>
2026-03-10 07:16:04 +01:00
MarekWo
2a3a48ed5f feat(contacts): add ignored and blocked contact lists
- New DB tables: ignored_contacts, blocked_contacts (keyed by pubkey)
- Ignored contacts: cached but excluded from pending/auto-add
- Blocked contacts: ignored + messages hidden from chat (stored in DB)
- Backend: filter in _on_new_contact, _on_channel_message, _on_dm_received
- API: /contacts/<pk>/ignore, /contacts/<pk>/block toggle endpoints
- API: filter blocked from /api/messages and /dm/conversations
- Frontend: Ignore/Block buttons on pending cards, existing cards, chat messages
- Frontend: source filter dropdown with Ignored/Blocked options
- Frontend: status icons (eye-slash, slash-circle) on contact cards
- Frontend: real-time blocked message filtering via socketio
- Name→pubkey mapping for chat window block/ignore buttons

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 21:10:21 +01:00
MarekWo
b709cc7b14 feat(contacts): add device/cache source icon to contact cards
Green chip icon for device contacts, grey cloud icon for cache-only.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 20:03:46 +01:00
MarekWo
09fbc56956 feat(contacts): complete cache functionality, fix display bugs
- _on_new_contact() in manual mode: upsert to DB as cache (source='advert')
  so contacts appear in @mentions and Cache filter before approval
- _on_advertisement(): check mc.pending_contacts for name/metadata fallback
- get_pending_contacts(): include last_advert in response
- /api/contacts/cached: return numeric last_advert timestamp
- contacts.js: fix adv_lat/adv_lon field names (was c.lat/c.lon),
  use last_advert timestamp instead of last_seen datetime string
- upsert_contact: source priority — never downgrade 'device' to 'advert'

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 08:51:25 +01:00
MarekWo
247b11e1e9 feat: Enrich contacts cache with GPS coordinates and node type
- Extract lat/lon from advert payloads (struct unpack from binary)
- Store type_label and lat/lon in cache from device seed and adverts
- Show Map button for cache contacts with GPS coordinates
- Show colored type badge (CLI/REP/ROOM/SENS) for typed cache contacts
- Type filter now works for cache contacts with known type
- Change counter label from "known" to "cached"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 12:40:42 +01:00
MarekWo
a5e767e5bf fix: Replace sort buttons with dropdown for mobile-friendly contact filters
Replaces two sort toggle buttons with a single <select> dropdown (e-commerce style)
so all 3 filter/sort controls fit on mobile screens.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 07:19:56 +01:00
MarekWo
de0108d6aa feat: Add persistent contacts cache for @mention autocomplete
Contacts cache accumulates all known node names from device contacts
and adverts into a JSONL file, so @mentions work even after contacts
are removed from the device. Background thread scans adverts every
45s and parses advert payloads to extract public keys and node names.

Existing Contacts page now shows merged view with "Cache" badge for
contacts not on device, plus source filter (All/On device/Cache only).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 17:13:36 +01:00
MarekWo
a4ef0fd497 feat: Use local timezone for scheduled cleanup instead of UTC
The scheduler now uses the timezone configured in .env (TZ variable)
instead of hardcoded UTC:
- Add get_local_timezone_name() helper to manager.py
- BackgroundScheduler uses system local timezone
- API returns timezone field in cleanup-settings response
- Frontend displays timezone next to hour selector and in status text
- Updated documentation to reflect timezone behavior

This makes the cleanup hour more intuitive for users in non-UTC timezones.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 10:46:08 +01:00
MarekWo
da31ab8794 feat: Add configurable hour for scheduled contact cleanup
Allow users to select the hour (0-23 UTC) when automatic contact
cleanup runs:
- Add hour selector dropdown in Advanced Filters (disabled until enabled)
- Hour field saved to .webui_settings.json with cleanup_settings
- API validates hour (0-23), scheduler uses CronTrigger with hour param
- Status text shows configured hour (e.g., "Enabled (runs daily at 03:00 UTC)")
- Documentation updated in user-guide.md

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 10:22:02 +01:00
MarekWo
a23eb2a5f4 feat: Add automatic scheduled contact cleanup
Add auto-cleanup feature that runs daily at 01:00 UTC using APScheduler:
- New cleanup settings stored in .webui_settings.json (enabled, types, date_field, days, name_filter)
- API endpoints: GET/POST /api/contacts/cleanup-settings
- Scheduler functions: _cleanup_job(), schedule_cleanup(), init_cleanup_schedule()
- UI toggle in Advanced Filters with validation (requires days > 0)
- Debounced auto-save for filter criteria changes
- Protected contacts are excluded from auto-cleanup

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 21:49:27 +01:00
MarekWo
bbc8b1db25 ui: Replace Copy Key button with clickable key
- Remove separate "Copy Key" button
- Make public key prefix clickable to copy
- Add fallback for HTTP contexts (execCommand)
- Add hover and copied state styling

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 20:16:12 +01:00
MarekWo
51c05f7794 feat: Add contact protection feature
Add ability to protect contacts from accidental deletion via Contact
Cleanup tool. Protected contacts are stored locally in settings file.

Changes:
- Add GET /api/contacts/protected endpoint
- Add POST /api/contacts/<key>/protect toggle endpoint
- Add is_protected field to /api/contacts/detailed response
- Exclude protected contacts from cleanup preview and deletion
- Add Protect toggle button to Existing Contacts list
- Show lock icon for protected contacts
- Disable Delete button for protected contacts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 14:30:38 +01:00
MarekWo
a9dd31b86e ui: Optimize Contact Management for mobile screens
- Replace type filter checkboxes with clickable toggle badges in Pending
  Contacts (CLI/REP/ROOM/SENS) - more compact and better mobile UX
- Make Pending Contacts buttons (Approve, Map, Copy Key) smaller and
  uniform, matching Existing Contacts button style
- Optimize Existing Contacts filter toolbar to fit in one row on mobile
  (narrower dropdown, more compact sort buttons)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 08:44:55 +01:00
MarekWo
d395656445 feat: Add colored markers and type filtering on contact map
- Use CircleMarker with different colors per contact type:
  - CLI (blue), REP (green), ROOM (purple), SENS (orange)
- Add type filter checkboxes in map modal header
- Dynamically update markers when filters change
- Hide filter panel for single contact view
- Reduce message action buttons to 32x32px

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 08:21:11 +01:00
MarekWo
6cb777e90c fix: Map buttons not working in contacts page and message bubbles
- Add Leaflet CSS/JS and map modal to contacts_base.html
- Add showContactOnMap function to contacts.js (contacts page has separate template)
- Load contactsGeoCache before messages to ensure Map buttons appear on bubbles

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 07:51:00 +01:00
MarekWo
72da96e647 feat: Add Leaflet map for contact locations
- Replace Google Maps with Leaflet + OpenStreetMap (free, no API key)
- Add Map button in main menu to show all contacts with GPS
- Add Map button on message bubbles (next to Reply) for senders with GPS
- Contact Management Map buttons now open modal instead of new tab
- Lazy map initialization with proper Bootstrap modal handling

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 22:46:36 +01:00
MarekWo
b00419ce25 fix: Update filtered count badge when type filter returns empty results
The filteredCountBadge in "Add Filtered" button was not updating when
unchecking type filter checkboxes resulted in zero matching contacts.
Now resets badge to '0' and clears filteredPendingContacts array.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 19:23:40 +01:00
MarekWo
009d3254b8 feat: Add persistent type filter for pending contacts
- Add query parameter 'types' to GET /api/contacts/pending endpoint
- Save user's type filter selection to localStorage (pendingContactsTypeFilter)
- Restore filter on page reload (Pending Contacts page)
- Contact Management badge shows count based on saved filter
- Default filter: CLI only (type=1)

Frontend changes:
- Add localStorage functions (save/load/set checkboxes)
- Modify loadPendingContacts() to use types from checkboxes
- Modify loadContactCounts() to use filter from localStorage
- Checkbox changes trigger save to localStorage + API reload

Backend changes:
- Add 'types' query parameter to GET /api/contacts/pending
- Filter pending contacts by type before returning
- Validate types parameter (must be 1-4)

This allows users to customize which contact types they want to see
in pending contacts list, and the selection persists across sessions.
The same filter is used consistently across all pages (Pending Contacts
page and Contact Management page).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-04 11:07:31 +01:00
MarekWo
fd2b9b1592 feat: Refactor pending contacts to JSON format with filtering and batch approval
- Change backend from 'pending_contacts' to '.pending_contacts' command
- Parse JSON response with enriched contact data (type, GPS, timestamps)
- Add type badges (CLI/REP/ROOM/SENS) with color coding
- Add Map button for contacts with GPS coordinates
- Add type filter (checkboxes, default: CLI only) and name search
- Add batch approval with confirmation modal
- Follow existing contacts UI pattern for consistency
- Mobile-first design with touch-friendly controls

Breaking change: /api/contacts/pending response format changed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-03 09:56:56 +01:00
MarekWo
11935d419a fix: Resolve PWA viewport corruption on page navigation
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>
2026-01-01 17:31:44 +01:00
MarekWo
4345456db7 refactor(contacts): Remove path_len filter from cleanup tool
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>
2026-01-01 15:18:40 +01:00
MarekWo
cd65125b40 feat(contacts): Redesign cleanup tool with advanced filtering
Replace hours-based cleanup with multi-criteria contact filtering system:
- Add name filter (partial match, case-insensitive)
- Add contact type selection (CLI, REP, ROOM, SENS)
- Add date field selector (last_advert vs lastmod)
- Add days of inactivity filter (0 = ignore)
- Add path length filter (> X, 0 = ignore)
- Implement preview modal before deletion
- Support all contact types (CLI, REP, ROOM, SENS)

Backend changes:
- Add POST /api/contacts/preview-cleanup endpoint
- Refactor POST /api/contacts/cleanup with new filter logic
- Implement _filter_contacts_by_criteria helper function
- Use last_advert (reliable) instead of lastmod (unreliable)

Frontend changes:
- Move cleanup section below Existing Contacts
- Add collapsible Advanced Filters section
- Replace handleCleanupInactive with handleCleanupPreview/Confirm
- Add confirmation modal with contact list preview
- Display deletion results (success/failure counts)

Documentation updates:
- Update API endpoints in CLAUDE.md
- Update README.md with new cleanup instructions
- Remove deprecated MC_INACTIVE_HOURS from docs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-01 14:25:29 +01:00
MarekWo
f8aedc5899 feat(contacts): Add Map button to open GPS location in Google Maps
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>
2025-12-30 12:43:50 +01:00
MarekWo
a53879df97 fix(ui): Move notifications to top-left corner and reduce display time
- 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>
2025-12-30 12:30:47 +01:00
MarekWo
c0d61650a1 fix(contacts): Use contact name for deletion instead of public key
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.
2025-12-30 09:56:58 +01:00
MarekWo
0d9fe53e53 fix(contacts): Use full public key for contact deletion
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.
2025-12-30 09:44:09 +01:00
MarekWo
cdc8be9eb4 refactor(contacts): Implement multi-page Contact Management with advanced sorting
Split Contact Management into 3 dedicated pages for improved mobile usability:
- /contacts/manage - Settings & navigation hub (manual approval + cleanup)
- /contacts/pending - Full-screen pending contacts view
- /contacts/existing - Full-screen existing contacts with search/filter/sort

New Features:
- Advanced sorting: Name (A-Z/Z-A) & Last advert (newest/oldest)
- URL-based sort state (?sort=name&order=asc)
- Activity indicators: 🟢 active, 🟡 recent, 🔴 inactive
- Changed terminology: "Last seen" → "Last advert" (more accurate)
- Cleanup tool moved from Settings modal to Contact Management page

Technical Changes:
- Created contacts_base.html standalone template
- Split contacts.html into 3 specialized templates
- Refactored contacts.js for multi-page support with page detection
- Added 2 new Flask routes: /contacts/pending, /contacts/existing
- Removed cleanup section from base.html Settings modal

Mobile-first design: Each page has full-screen space with touch-friendly
navigation and back buttons.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-30 08:40:22 +01:00
MarekWo
7f819b63c7 feat(contacts): Add 'Last Seen' timestamp display with activity indicators
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>
2025-12-29 13:03:15 +01:00
MarekWo
3e524bb0d2 refactor(ui): Optimize Contact Management layout for better space usage
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>
2025-12-29 12:34:35 +01:00
MarekWo
8b709b9136 feat(ui): Contact Management v2 - existing contacts display and delete
Implements MVP v2 requirements from docs/UI-Contact-Management-MVP-v2.md:
- Display all contact types (CLI, REP, ROOM, SENS)
- Delete contacts with confirmation modal
- Capacity counter with color-coded warnings (green/yellow/red)
- Search by name or public key
- Filter by contact type
- Mobile-first responsive design

Backend changes:
- Add get_all_contacts_detailed() parser for meshcli contacts output
  - Handles Unicode characters, emoji, spaces in names
  - Backward parsing strategy using public_key_prefix as anchor
  - Returns detailed metadata for all contact types
- Add delete_contact() wrapper for remove_contact command
- Add GET /api/contacts/detailed endpoint
- Add POST /api/contacts/delete endpoint

Frontend changes:
- Add Existing Contacts section to contacts.html
  - Real-time search input
  - Type filter dropdown (All/CLI/REP/ROOM/SENS)
  - Color-coded type badges
  - Capacity counter with pulse animation for critical levels
- Add delete confirmation modal with danger styling
- Add complete contact management logic to contacts.js
  - loadExistingContacts(), applyFilters(), confirmDelete()
  - Copy public key to clipboard functionality

Documentation:
- Update README.md with usage instructions
- Add technotes/UI-Contact-Management-MVP-v2-completed.md
- Add docs/UI-Contact-Management-MVP-v2.md (specification)
- Add technotes/UI-Contact-Management-MVP-v1-completed.md (retroactive)

Tested with 263 real contacts including Unicode and edge cases.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-29 11:45:47 +01:00
MarekWo
77c72ba62e feat: add contact management MVP (manual approval + pending)
Implements Contact Management UI with manual contact approval and pending contacts list.

**Backend changes (meshcore-bridge/bridge.py):**
- Remove forced manual_add_contacts on session init (was for testing only)
- Add _load_webui_settings() to read .webui_settings.json from MC_CONFIG_DIR
- Add /set_manual_add_contacts endpoint for persistent settings management
- Settings now persist across container restarts via .webui_settings.json

**Backend changes (app/meshcore/cli.py):**
- Add get_pending_contacts() - proxy to bridge /pending_contacts
- Add approve_pending_contact() - proxy to bridge /add_pending (always uses full public_key)
- Add get_device_settings() - read .webui_settings.json
- Add set_manual_add_contacts() - proxy to bridge /set_manual_add_contacts

**API changes (app/routes/api.py):**
- Add GET /api/contacts/pending - list pending contacts
- Add POST /api/contacts/pending/approve - approve contact by public_key
- Add GET /api/device/settings - get persistent settings
- Add POST /api/device/settings - update manual_add_contacts setting

**Frontend (app/routes/views.py, templates, js):**
- Add /contacts/manage route rendering contacts.html
- Add contacts.html template with mobile-first design
- Add contacts.js with settings toggle and pending list UI
- Add "Contact Management" menu item in base.html
- Features: manual approval toggle, pending list, approve/copy actions, toast notifications

**Documentation (README.md):**
- Add Contact Management section in Usage
- Add to Key Features list
- Add debugging instructions

**Key features:**
- Manual approval toggle (persists across restarts)
- Pending contacts list with name and public_key
- Approve button (always sends full public_key for compatibility)
- Copy full key button (clipboard API)
- Auto-refresh on page load
- Mobile-first responsive design
- Info badge when manual approval is disabled
- Toast notifications for user feedback

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-29 09:52:09 +01:00