Commit Graph

454 Commits

Author SHA1 Message Date
MarekWo
8ba5381921 fix(settings): add note clarifying retry count includes initial send
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 13:57:23 +01:00
MarekWo
9e90e30d9f refactor(settings): compact table layout with tooltip info icons
Replace vertical form fields with table rows for less screen space.
Descriptions moved to (i) tooltip icons on hover/touch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 13:33:19 +01:00
MarekWo
6f1a5462e9 feat(settings): add Settings modal with configurable DM retry parameters
Replace hardcoded DM retry logic with user-configurable settings stored
in app_settings DB. Settings modal opens from menu with tab-based UI
(ready for future settings tabs). Defaults: 3 direct + 1 flood retries
(was 8+2), 30s/60s intervals, 60s grace period.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 13:18:03 +01:00
MarekWo
0108ea9149 refactor(menu): reorganize menu into logical sections + larger touch targets
Reorganize menu from 2 sections (Network Commands, Configuration) into 4:
- Messages (top, no header) - daily actions
- Network - advert commands
- Tools - Map, Console
- System - Device Info, System Log, Backup, Settings placeholder

Increase navbar button/select touch targets (min 40px) for mobile usability.
Widen offcanvas menu from 280px to 300px.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 07:55:59 +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
a1f2a1c5ef feat: name database file after device name for multi-device support
Database file is now named {device_name}.db (e.g. MarWoj.db) instead of
the generic mc-webui.db. On first boot, mc-webui.db is automatically
renamed once the device name is detected. On subsequent boots, the
existing device-named DB is found by scanning the config directory.

This enables future multi-device support where each MeshCore device
has its own separate database file.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 21:07:58 +01:00
MarekWo
ca0ba37be5 fix(logs): open System Log as fullscreen modal like Console
Changed from target="_blank" link to fullscreen modal with iframe,
matching the pattern used by Console, DM, and Contacts modals.
Iframe loads on open and clears on close to manage WebSocket lifecycle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 20:41:20 +01:00
MarekWo
0110e65b97 feat: add System Log viewer with real-time streaming
In-memory ring buffer (2000 entries) captures all Python log records.
New /logs page streams entries via WebSocket in real-time with:
- Level filter (DEBUG/INFO/WARNING/ERROR)
- Module filter (auto-populated from seen loggers)
- Text search with highlighting
- Auto-scroll with pause/resume
- Dark theme matching Console style

Menu entry added under Configuration section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 20:34:29 +01:00
MarekWo
4f25d244b1 refactor: migrate .webui_settings.json to database + fix NEW_CONTACT edge case
All settings (protected_contacts, cleanup_settings, retention_settings,
manual_add_contacts) moved from .webui_settings.json file to SQLite database.
Startup migration auto-imports existing file and renames it to .json.bak.

Added safeguard in _on_new_contact: if firmware fires NEW_CONTACT for a
contact already on the device, skip pending and log a warning. Also added
diagnostic logging showing previous DB state (source, protected) when
contacts reappear as pending.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 20:14:15 +01:00
MarekWo
e106b5493b fix(contacts): dynamic list height and tighter card spacing
- Replace fixed calc() heights with flexbox layout so the contact list
  fills all remaining viewport space on any screen size
- Make body/main/container chain flex columns so the list can grow
- Reduce vertical spacing between contact name, public key, and
  last advert rows for more compact cards

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 12:55:33 +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
39a0e944a7 fix(console): correct trace display order
SNR precedes the hop hash: 12.50 > [5e]12.25 > [d1]-8.25 > [e7]-3.00
(each SNR shows link quality, hash shows the next relay node)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 17:29:53 +01:00
MarekWo
4b4e71f5bd fix(console): correct trace output format
Format: 12.50 > [5e]12.25 > [d1]-8.25 > [e7]-3.00
(SNR first, then each hop shows [hash]SNR)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 17:17:40 +01:00
MarekWo
20924d134d fix(console): trace path support, stats field names, self_telemetry format
- trace: accepts comma-separated hex path (e.g. "trace 5e,d1,e7"),
  waits for TRACE_DATA response with proper timeout from device
- stats: fix field names (uptime_secs, queue_len, battery_mv, etc.),
  show all radio/packet stats with detail breakdown
- self_telemetry: format LPP sensor data nicely instead of raw dict

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 17:03:35 +01:00
MarekWo
019d351ab7 fix(console): req_regions and req_owner output formatting
- req_regions: library returns string, not dict — was crashing
  with "'str' object has no attribute 'items'"
- req_owner: format like meshcore-cli ("X is owned by Y")

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 16:17:42 +01:00
MarekWo
3057882f20 fix(console): get/set help formatting, fix get path_hash_mode
- get help / set help: detailed parameter descriptions with
  explanations, matching meshcore-cli style
- get path_hash_mode: library returns int not Event, fixed check
- set help: now reachable (was behind len(args)>=3 guard)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 13:42:31 +01:00
MarekWo
5a4c259c0b fix(console): ver command now queries firmware info properly
Was using self_info (which has no firmware data). Now uses
send_device_query() like meshcore-cli, showing model, version,
build date and repeat mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 13:23:56 +01:00
MarekWo
3acdc7a402 feat(console): fix req_clock format, add req_neighbours command
- req_clock: parse timestamp from binary hex data (little-endian)
  and display as human-readable datetime, matching meshcore-cli
- req_neighbours: new command that fetches neighbour list from
  repeater with formatted output (name resolution from device
  contacts and DB cache, time ago, SNR)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 12:25:28 +01:00
MarekWo
3f9b6e54c8 fix(console): repeater req_* return value check
meshcore _sync methods return dict (data) or None (error/timeout),
not Event objects. hasattr(dict, 'payload') is always False, causing
instant "timeout" errors. Changed to check `result is not None`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 12:08:11 +01:00
MarekWo
fe7c67ee9a fix(console): human-readable clock, fix repeater timeouts
- Clock command now shows datetime like meshcore-cli: "Current time: 2026-03-19 11:39:07 (1773916747)"
- Repeater req_* commands: pass timeout=0 to meshcore library so it uses
  device's suggested_timeout instead of hardcoded 30s (matching meshcore-cli behavior)
- Execute timeout raised to 120s to accommodate slow repeater responses

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 11:58:46 +01:00
MarekWo
4f64cc92e5 feat(console): add device/channel management commands (Etap 3)
Add device management: get/set params, clock/clock sync, time,
reboot, ver, scope, self_telemetry, node_discover.
Add channel management: get_channel, set_channel, add_channel,
remove_channel. Update help text with all command categories.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 08:10:46 +01:00
MarekWo
d80f9a7b3a feat(console): add contact management commands (Etap 2)
Add 14 console commands for contact management: contact_info,
path, disc_path, reset_path, change_path, advert_path,
share_contact, export_contact, import_contact, remove_contact,
change_flags, pending_contacts, add_pending, flush_pending.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 08:09:03 +01:00
MarekWo
d6b92e2754 feat(console): add repeater management commands (Etap 1)
Add 9 new console commands for repeater management:
login, logout, cmd, req_status, req_regions, req_owner,
req_acl, req_clock, req_mma. Add resolve_contact helper
and _parse_time_arg utility. Update help text with categories.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 08:07:22 +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
eb19f3cf76 feat(dm): add clear search button (x) next to contact info
Shows an X button when a conversation is selected, allowing quick
clearing of the search field to find another contact.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 19:35:31 +01:00
MarekWo
e1d3534624 fix(dm): resolve contact names from device, not backend pubkeys
- Add resolveConversationName() that prioritizes device contacts over
  backend display_name (which falls back to pubkey when DB JOIN fails)
- Add isPubkey() guard to prevent overwriting good names with hex strings
- Add arrow key navigation (Up/Down) in searchable contact dropdown
- Auto-focus message input after selecting contact from dropdown
- Skip filtering when search input contains a pubkey (show all contacts)
- Keep search input and placeholder in sync with best known name

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 19:13:03 +01:00
MarekWo
50fdee05ed fix(dm): prevent dropdown close on mouse hover, ensure name after select
- Prevent mousedown on dropdown from stealing focus (which closed the
  dropdown before click could register on desktop)
- After selecting from dropdown, override search input with the known
  name to guarantee correct display even if prefix match fails

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 08:43:48 +01:00
MarekWo
1ecf2f60f0 fix(dm): resolve conversation name via prefix match for saved IDs
When restoring a conversation from localStorage, the saved ID may have
a different pubkey prefix length than the API returns (e.g. pk_e4ce0a07
vs pk_e4ce0a075359459f...). Now selectConversation() does prefix
matching against dmConversations and upgrades the stored ID, so the
display name is resolved correctly instead of showing raw pubkey prefix.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 08:35:40 +01:00
MarekWo
8ce5fa85ba feat(dm): searchable contact selector, contact info modal, device-only contacts
Redesign DM chat contact selector:
- Replace <select> dropdown with searchable text input + filtered dropdown
- Show only device contacts (from /api/contacts/detailed), not all cached
- Sort contacts alphabetically, conversations by recency
- Type badge (CLI/REP/ROOM/SENS) shown in dropdown items
- Keyboard support: Enter selects first match, Escape closes

Add Contact Info modal (replaces Retry toggle in header):
- Shows contact name, type, public key, last advert, path/route, GPS
- Auto Retry toggle moved into modal footer
- Designed for future extensibility (manual path setting etc.)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 08:27:01 +01:00
MarekWo
21b1c0510f fix(dm): emit original expected_ack on retry ACK for frontend matching
When a DM is retried, the retry send generates a NEW ack code. The
backend correctly maps retry ack → dm_id via _pending_acks, but
the WebSocket emit was sending the retry ack code. The frontend DOM
still has data-ack="<original_ack>" from the first send, so it could
never match retry ACKs → delivery checkmark never appeared.

Now both _on_ack() and _confirm_delivery() look up the original
expected_ack from the database before emitting to the frontend.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 21:54:50 +01:00
MarekWo
5ecb48c772 fix(api): fix NameError on out_path variable rename
Variable was renamed to out_path_raw but one reference was missed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 21:30:32 +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
fa8190923f fix(dm): adjust retry strategy based on DIRECT vs FLOOD routing
- DIRECT (known path): 10 attempts (8 DIRECT + 2 FLOOD), 30s wait between
- FLOOD (no path): 3 attempts only, 60s wait between
- Prevents flooding the mesh with rapid retries when no path is known
- Longer DIRECT wait gives ACKs more time to return through multi-hop paths
- Log retry mode at task start for easier debugging

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 11:21:02 +01:00
MarekWo
e473cbf495 fix(dm): cancel retry on early ACK/PATH, add 60s grace period for late ACKs
- Cancel retry task immediately when _on_ack or PATH handler confirms delivery
- Keep pending_acks for 60s after retry exhaustion so late ACKs are matched
- Prevents orphaned ACKs (no dm_id) when ACK arrives shortly after exhaustion

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 11:10:10 +01:00
MarekWo
3a26da18fd fix(websocket): update message metadata in-place without full chat reload
Instead of reloading the entire message list when echo data arrives,
now updates only the affected message elements in the DOM:

- Add data-msg-id attribute to message wrappers for targeted lookup
- Add GET /api/messages/<id>/meta endpoint returning metadata for a
  single message (computes pkt_payload, looks up echoes, analyzer URL)
- Replace loadMessages() echo handler with refreshMessagesMeta() that
  finds messages missing metadata and updates them individually
- Fix path_len=0 treated as falsy (use ?? instead of ||)

Flow: message appears instantly via WebSocket (with SNR + hops), then
~2s later echo data triggers targeted meta fetch → route info and
analyzer button appear smoothly without any chat window reload.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 12:49:56 +01:00
MarekWo
0e15df430f fix(websocket): listen for echo events to update message metadata in real-time
The backend already emits 'echo' SocketIO events when RX_LOG_DATA arrives
with route/path data, but the frontend wasn't listening. Now the frontend
handles echo events with a debounced loadMessages() refresh (2s delay) to
pick up computed pkt_payload, analyzer_url, hops, and route info.

This fixes messages appearing without metadata until manual page refresh.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 12:38:46 +01:00
MarekWo
e817181261 fix(websocket): include SNR, hops, route and analyzer URL in channel message events
The SocketIO new_message emit for channel messages was missing snr,
path_len, pkt_payload and analyzer_url fields, causing messages received
via WebSocket to render without metadata until a full page refresh.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 12:12:41 +01:00
MarekWo
9a0d05ae93 fix(search): remove double hash in channel names, add FTS5 syntax help
Channel names from device already include # prefix — removed hardcoded #
from search results badge. Added (?) help button with search syntax
examples and link to FTS5 docs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 07:38:37 +01:00
MarekWo
d74a1572bb feat(dm): increase retry attempts to 10, delay flood fallback to attempt 8
Keep direct path retries longer before falling back to flood mode,
giving more time for ACK delivery on known routes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 21:26:58 +01:00
MarekWo
6fcbcb7d4f fix(ui): fix [object Object] in device info/stats, soften search button color
- Stats: battery fallback used ${bat} on an object — now uses battery_mv
  from core stats when dedicated get_bat returns null
- Info: remove old v1 regex JSON parsing, use v2 dict response directly
- Search FAB: change from bright orange to muted teal

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 20:14:25 +01:00
MarekWo
65b33b4af6 fix(phase3): fix database/device access in search, backup, stats, map endpoints
- Search, backup, stats endpoints used current_app.config.get('DEVICE_MANAGER')
  which doesn't exist — replaced with _get_dm()/_get_db() helpers
- /api/device/info used old v1 CLI — replaced with DeviceManager.get_device_info()
  returning structured dict instead of string (fixes map own device marker)
- Moved search button from navbar to FAB menu (between filter and DM buttons)
- Bump SW cache to v7

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 20:02:23 +01:00
MarekWo
e4a1e75cc0 fix(socketio): register /chat namespace handler to fix real-time message delivery
The /chat namespace had no server-side connect handler registered. With
python-socketio 5.x (always_connect=False), client connections to
unregistered namespaces are silently rejected. This caused all SocketIO
events (new_message, ack, echo) to never reach the frontend — messages
only appeared via the 60s polling fallback.

Fixes:
- Add @socketio.on('connect', namespace='/chat') handler in main.py
- Add optimistic message append: sent messages appear instantly before
  API round-trip (eliminates 3-4s serial command delay)
- Skip own-message SocketIO events to prevent duplicates
- Add connect_error handler for frontend debugging
- Bump SW cache to v6

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 08:15:43 +01:00
MarekWo
c6a2444249 fix(backup): allow backup job scheduling before db reference is set
The _db reference is set by init_retention_schedule() which runs after
schedule_daily_archiving(). The backup job checks _db at runtime.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 07:29:30 +01:00
MarekWo
3f9d096ed0 chore(sw): bump cache to v5, add filter-utils.js to cached assets
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 07:28:02 +01:00
MarekWo
ec383bf8e9 feat(map): add own device marker, last seen info, and formatTimeAgo
- Own device shown as red star marker on map (from self_info GPS)
- Contact popups now show "Last seen: X min ago" from last_advert
- New formatTimeAgo() utility for relative timestamps

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 07:27:37 +01:00
MarekWo
ab01e6f17a feat(stats): add device statistics dashboard with Info/Stats tabs
- New GET /api/device/stats endpoint (core, radio, packets, DB stats)
- Device Info modal now has Info and Stats tabs
- Stats tab shows: battery, uptime, TX/RX air time, packet counts,
  DB row counts, and database size

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 07:25:45 +01:00
MarekWo
6fba37c609 feat(console): add stats, telemetry, neighbors, trace commands
- stats: device uptime, TX/RX air time, packet counts, errors
- telemetry <name>: request sensor data from remote node
- neighbors <name>: list neighbors of a remote node
- trace [tag]: send trace packet for mesh topology discovery

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 07:24:08 +01:00
MarekWo
4ecab9b307 feat(backup): add backup API endpoints and UI
- POST /api/backup/create — trigger immediate backup
- GET /api/backup/list — list backups with sizes
- GET /api/backup/download — download backup file
- Backup modal accessible from menu with create/download buttons
- Daily automatic backup via APScheduler (configurable hour/retention)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 07:22:50 +01:00