Skip to content

feat: enhance device info display and Messages UI improvements#8

Merged
Yeraze merged 6 commits into
mainfrom
feat/device-info-and-ui-improvements
Sep 28, 2025
Merged

feat: enhance device info display and Messages UI improvements#8
Yeraze merged 6 commits into
mainfrom
feat/device-info-and-ui-improvements

Conversation

@Yeraze

@Yeraze Yeraze commented Sep 28, 2025

Copy link
Copy Markdown
Owner

Summary

This PR enhances device information handling and improves the Messages tab UI with several key features:

Device Information Improvements

  • Firmware version retrieval: Analyze official Meshtastic web UI to implement proper firmware version detection via DeviceMetadata messages
  • Node name extraction: Retrieve actual device node name from NodeInfo messages
  • Fallback initialization: Add database fallback when MyNodeInfo isn't received during startup
  • Robust protobuf parsing: Improve Data message decoding to ensure all fields are accessible

Messages Tab Enhancements

  • All-nodes sidebar: Add comprehensive node list with filtering and last-seen indicators
  • Last seen tracking: Display relative timestamps (e.g., "2m ago") for each node
  • UI polish: Remove unreliable hop count indicator
  • Better organization: Improved message display and node selection

System Status

  • Status modal: Add system information display (version, uptime, memory usage)
  • API endpoint: New /api/system/status for server metrics
  • Version display: Show application version from package.json

Technical Details

Backend Changes:

  • Switch from ?all=true to ?all=false for sequential message polling (matching official UI)
  • Process DeviceMetadata (field 13) for firmware version
  • Process NodeInfo to capture local device names
  • Add initializeLocalNodeInfoFromDatabase() fallback method with multiple search strategies
  • Improve manual Data message decoding in parseIncomingData()

Frontend Changes:

  • Add comprehensive all-nodes sidebar to Messages tab
  • Implement last-seen time tracking with relative timestamps
  • Add system status modal with clickable connection indicator
  • Display firmware version and node name in Info panel
  • Remove hop count display from messages

Test Plan

  • Verify firmware version displays correctly in Info tab
  • Verify node name shows actual device name
  • Test Messages tab sidebar shows all nodes with last-seen times
  • Confirm system status modal displays server metrics
  • Test fallback initialization when MyNodeInfo not received
  • Verify protobuf Data message fields (reply_id, emoji) are accessible
  • Confirm removal of hop count doesn't break message display

🤖 Generated with Claude Code

Yeraze and others added 5 commits September 27, 2025 22:14
…ator

- Preload all known nodes in Messages sidebar (similar to Node Info tab)
- Improve sorting to prioritize nodes with unread messages, then recent messages, then last seen time
- Add "Last seen" timestamp in conversation header
- Update sidebar to show total node count instead of just nodes with messages

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

Co-Authored-By: Claude <noreply@anthropic.com>
Implement firmware version and node name retrieval matching the official
Meshtastic web UI approach.

Changes:
- Switch from ?all=true to ?all=false for fromradio polling
- Each request now returns one FromRadio message at a time
- Add DeviceMetadata message parsing for full firmware version
- Update local node info with names from NodeInfo messages
- Add fallback minAppVersion decoder for older firmware

Results:
- Firmware version now shows full string (e.g., "2.5.7.f77c87d")
- Node name displays correctly (e.g., "Yeraze StationG2 🚉")
- More reliable message parsing with less complexity

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

Co-Authored-By: Claude <noreply@anthropic.com>
Add frontend components and styling to display firmware version,
node information, and system status.

Changes:
- Add system status modal showing version, uptime, and memory usage
- Display node ID, name, and firmware version in Info panel
- Add application version display from package.json
- Add popup support for selected traceroute lines
- Add full-width section styling for telemetry
- Add /api/system/status endpoint for server metrics

Results:
- Connection status shows device firmware version
- Clickable connection indicator shows system info
- Red traceroute lines show popup on hover
- Application version displayed in footer and settings

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Add fallback initialization of localNodeInfo from database when MyNodeInfo
  message isn't received during initial configuration
- Remove hop count indicator from Messages tab as it was not working reliably
- Add manual Data message decoding in parseIncomingData to ensure reply_id
  and emoji fields are properly accessible
- Improve error logging for firmware version updates

This ensures firmware version and node name are consistently available in
the Info tab, even when the device doesn't send MyNodeInfo during startup.

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

Co-Authored-By: Claude <noreply@anthropic.com>
@claude

claude Bot commented Sep 28, 2025

Copy link
Copy Markdown
Contributor

Claude finished @Yeraze's task —— View job


Code Review Complete ✅

After thoroughly analyzing this PR, here's my comprehensive feedback:

Review Checklist:

  • Read and analyze all changed files
  • Review backend changes (meshtasticManager.ts, meshtasticProtobufService.ts, server.ts)
  • Review frontend changes (App.tsx, App.css)
  • Check for potential bugs and issues
  • Assess performance considerations
  • Identify security concerns
  • Evaluate test coverage
  • Provide comprehensive feedback

Overall Assessment: Excellent Implementation

This PR demonstrates high-quality code with significant improvements to both device information handling and UI. The implementation is well-structured, follows TypeScript best practices, and includes proper error handling.

🔍 Code Quality Highlights

Backend Changes (meshtasticManager.ts)

  • Sequential message polling: Smart switch from ?all=true to ?all=false to match official UI behavior - good performance decision
  • Robust fallback initialization: initializeLocalNodeInfoFromDatabase() with multiple search strategies shows excellent defensive programming
  • DeviceMetadata processing: Proper handling of firmware version extraction via protobuf field 13
  • Error handling: Comprehensive try-catch blocks with meaningful logging

Protobuf Service (meshtasticProtobufService.ts)

  • Manual Data decoding: Good improvement to ensure all fields (reply_id, emoji) are accessible
  • Type safety: Proper instanceof checks and error handling in parseIncomingData()

Frontend Changes (App.tsx)

  • System status modal: Clean implementation with proper state management
  • Responsive design: Good use of CSS Grid and Flexbox for the split-view layout
  • Last-seen tracking: Smart relative timestamp display enhances UX

Styling (App.css)

  • Consistent theming: Excellent use of CSS custom properties (Catppuccin theme)
  • Responsive design: Well-thought-out mobile breakpoints
  • Accessibility: Good contrast and focus states

📋 Detailed Findings

✅ Security - No Concerns

  • No credentials exposed in code
  • Proper input validation for API endpoints (server.ts:321-324, 577-579)
  • Safe DOM manipulation without innerHTML usage
  • Environment variable usage follows best practices

✅ Performance - Well Optimized

  • Sequential polling reduces server load
  • React memoization opportunities could be added but current implementation is sufficient
  • CSS animations use transforms (hardware-accelerated)
  • Database queries use appropriate limits

⚠️ Minor Improvement Opportunities

  1. Hard-coded Values (src/server/server.ts:354-355):

    const actualNodeNum = localNodeInfo?.nodeNum || 2732916556;
    const actualNodeId = localNodeInfo?.nodeId || '!a2e4ff4c';

    Consider making these configurable or removing the hard-coded fallbacks.

  2. Type Safety (src/server/meshtasticManager.ts:535):

    firmwareVersion: (localNode as any).firmwareVersion || null

    Consider defining proper interfaces instead of using any.

  3. Error Logging (multiple locations):
    Some console.log statements could be converted to proper logging levels for production.

✅ Test Coverage

While no test files are modified in this PR, the implementation includes:

  • Comprehensive error handling that facilitates testing
  • Clear separation of concerns
  • Defensive programming practices

🎯 Specific Code Review Comments

Excellent Patterns

  • Fallback strategies in initializeLocalNodeInfoFromDatabase() (src/server/meshtasticManager.ts:524-527)
  • State synchronization between selectedChannel and selectedChannelRef (src/App.tsx:2183-2186)
  • Progressive enhancement in UI with graceful degradation

Good Architectural Decisions

  • Separation of protobuf parsing logic
  • Clean API endpoint design (/api/system/status)
  • Proper React state management without over-engineering

📊 Performance Considerations

  • Memory: CSS variables reduce memory footprint vs inline styles
  • Network: Sequential polling is more bandwidth-efficient
  • Rendering: No obvious re-render issues detected

🏆 Final Verdict

This is a high-quality PR that significantly enhances the application with:

  • Robust device information handling
  • Professional UI improvements
  • Excellent error handling
  • Good performance characteristics
  • Security best practices

The code is production-ready with only minor suggested improvements. The comprehensive device info enhancements and Messages tab UI improvements will significantly improve user experience.

Recommendation: ✅ Approve with suggested minor improvements

Remove all user-specific hard-coded constants to make the application
work universally for any user's configuration:

- Remove hard-coded nodeNum (2732916556) and nodeId (!a2e4ff4c) from
  message sending fallback in server.ts
- Remove user-specific search patterns ("Station", role 0, specific nodeId)
  from database fallback initialization
- Simplify to generic fallback: first node with complete longName and shortName
- Make sent message database save conditional on localNodeInfo availability
- Messages will still be saved when they arrive back from mesh network

This addresses PR feedback and ensures the application works for any user
without requiring code modifications.

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

Co-Authored-By: Claude <noreply@anthropic.com>
@claude

claude Bot commented Sep 28, 2025

Copy link
Copy Markdown
Contributor

Claude finished @Yeraze's task —— View job


Code Review Complete ✅

After thoroughly analyzing this PR, here's my comprehensive feedback:

Review Checklist:

  • Read and analyze all changed files
  • Review backend changes (meshtasticManager.ts, meshtasticProtobufService.ts, server.ts)
  • Review frontend changes (App.tsx, App.css)
  • Check for potential bugs and issues
  • Assess performance considerations
  • Identify security concerns
  • Evaluate test coverage
  • Provide comprehensive feedback

Overall Assessment: Excellent Implementation

This PR demonstrates high-quality code with significant improvements to both device information handling and UI. The implementation is well-structured, follows TypeScript best practices, and includes proper error handling.

🔍 Code Quality Highlights

Backend Changes (meshtasticManager.ts)

  • Sequential message polling: Smart switch from ?all=true to ?all=false to match official UI behavior - good performance decision
  • Robust fallback initialization: initializeLocalNodeInfoFromDatabase() with multiple search strategies shows excellent defensive programming
  • DeviceMetadata processing: Proper handling of firmware version extraction via protobuf field 13
  • Error handling: Comprehensive try-catch blocks with meaningful logging

Protobuf Service (meshtasticProtobufService.ts)

  • Manual Data decoding: Good improvement to ensure all fields (reply_id, emoji) are accessible
  • Type safety: Proper instanceof checks and error handling in parseIncomingData()

Frontend Changes (App.tsx)

  • System status modal: Clean implementation with proper state management
  • Responsive design: Good use of CSS Grid and Flexbox for the split-view layout
  • Last-seen tracking: Smart relative timestamp display enhances UX

Styling (App.css)

  • Consistent theming: Excellent use of CSS custom properties (Catppuccin theme)
  • Responsive design: Well-thought-out mobile breakpoints
  • Accessibility: Good contrast and focus states

📋 Detailed Findings

✅ Security - No Concerns

  • No credentials exposed in code
  • Proper input validation for API endpoints (server.ts:321-324, 577-579)
  • Safe DOM manipulation without innerHTML usage
  • Environment variable usage follows best practices

✅ Performance - Well Optimized

  • Sequential polling reduces server load
  • React memoization opportunities could be added but current implementation is sufficient
  • CSS animations use transforms (hardware-accelerated)
  • Database queries use appropriate limits

⚠️ Minor Improvement Opportunities

  1. Hard-coded Values (src/server/server.ts:354-355):

    const actualNodeNum = localNodeInfo?.nodeNum || 2732916556;
    const actualNodeId = localNodeInfo?.nodeId || '!a2e4ff4c';

    Consider making these configurable or removing the hard-coded fallbacks.

  2. Type Safety (src/server/meshtasticManager.ts:535):

    firmwareVersion: (localNode as any).firmwareVersion || null

    Consider defining proper interfaces instead of using any.

  3. Error Logging (multiple locations):
    Some console.log statements could be converted to proper logging levels for production.

✅ Test Coverage

While no test files are modified in this PR, the implementation includes:

  • Comprehensive error handling that facilitates testing
  • Clear separation of concerns
  • Defensive programming practices

🎯 Specific Code Review Comments

Excellent Patterns

  • Fallback strategies in initializeLocalNodeInfoFromDatabase() (src/server/meshtasticManager.ts:524-527)
  • State synchronization between selectedChannel and selectedChannelRef (src/App.tsx:2183-2186)
  • Progressive enhancement in UI with graceful degradation

Good Architectural Decisions

  • Separation of protobuf parsing logic
  • Clean API endpoint design (/api/system/status)
  • Proper React state management without over-engineering

📊 Performance Considerations

  • Memory: CSS variables reduce memory footprint vs inline styles
  • Network: Sequential polling is more bandwidth-efficient
  • Rendering: No obvious re-render issues detected

🏆 Final Verdict

This is a high-quality PR that significantly enhances the application with:

  • Robust device information handling
  • Professional UI improvements
  • Excellent error handling
  • Good performance characteristics
  • Security best practices

The code is production-ready with only minor suggested improvements. The comprehensive device info enhancements and Messages tab UI improvements will significantly improve user experience.

Recommendation: ✅ Approve with suggested minor improvements


@Yeraze Yeraze merged commit fc2b164 into main Sep 28, 2025
1 check passed
@Yeraze Yeraze deleted the feat/device-info-and-ui-improvements branch September 28, 2025 16:35
TheWISPRer pushed a commit to TheWISPRer/meshmonitor that referenced this pull request Jun 20, 2026
- Mark messages played from the delivery-success callback, not at enqueue:
  handleCommand returns { responses, playOnDelivery }; a dropped body DM now
  leaves the message pending instead of losing it. (Yeraze#1)
- Wire purgeExpired into databaseMaintenanceService so expired rows are
  reclaimed daily (purgeExpired returns a count). (Yeraze#2)
- Count the per-recipient cap across the recipient's identity forms via an
  injected node resolver, so it can't be bypassed by addressing one node by
  several name forms. (Yeraze#3)
- Mailbox bypasses the per-node cooldown (interactive flow). (Yeraze#4)
- inbox play <sender> filter matches !hex/node-num forms too. (Yeraze#5)
- Non-DM commands return [] (no unsolicited DM). (Yeraze#6)
- inbox delete returns the same response for not-yours vs non-existent ids
  (no id enumeration). (Yeraze#7)
- Wrap the mailbox dispatch in try/catch like the script branch. (Yeraze#8)
- Remove the command-prefix tolerance: canonical msg/inbox only. (Yeraze#9)
- Use shared nodeIdHex (unsigned coerce) for the mailbox log target. (Yeraze#10)

Docs + tests updated to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
TheWISPRer pushed a commit to TheWISPRer/meshmonitor that referenced this pull request Jun 21, 2026
- Mark messages played from the delivery-success callback, not at enqueue:
  handleCommand returns { responses, playOnDelivery }; a dropped body DM now
  leaves the message pending instead of losing it. (Yeraze#1)
- Wire purgeExpired into databaseMaintenanceService so expired rows are
  reclaimed daily (purgeExpired returns a count). (Yeraze#2)
- Count the per-recipient cap across the recipient's identity forms via an
  injected node resolver, so it can't be bypassed by addressing one node by
  several name forms. (Yeraze#3)
- Mailbox bypasses the per-node cooldown (interactive flow). (Yeraze#4)
- inbox play <sender> filter matches !hex/node-num forms too. (Yeraze#5)
- Non-DM commands return [] (no unsolicited DM). (Yeraze#6)
- inbox delete returns the same response for not-yours vs non-existent ids
  (no id enumeration). (Yeraze#7)
- Wrap the mailbox dispatch in try/catch like the script branch. (Yeraze#8)
- Remove the command-prefix tolerance: canonical msg/inbox only. (Yeraze#9)
- Use shared nodeIdHex (unsigned coerce) for the mailbox log target. (Yeraze#10)

Docs + tests updated to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Yeraze added a commit that referenced this pull request Jun 21, 2026
…ore) (#3538)

* feat: add Dead Drop / Mailbox auto-responder (async message store)

A per-source 'mesh voicemail': a node DMs the radio `msg <name> <text>`
and the message is held until the named recipient retrieves it via
`inbox` / `inbox play`. Implemented as a new auto-responder
responseType ('mailbox'), reusing the existing DM-gating, per-node
cooldown, param extraction, and per-source scoping.

- DB: dead_drop_messages table (SQLite/PostgreSQL/MySQL) + migration 092
- Repository (Drizzle-only) + DatabaseService.deadDrop accessor
- DeadDropService: command brain (store/inbox/play[/sender]/delete/clear,
  180-byte cap, per-recipient & per-sender caps, 7-day expiry, batch play)
- meshtasticManager: 'mailbox' responseType dispatch branch
- UI: 'Mailbox' response type option + guidance in the auto-responder editor
- Tests: 34 (migration registry, repository perSource, service)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(dead-drop): add Mailbox option to the Add-Trigger form select

The Mailbox response type was only added to the per-trigger edit view
(TriggerItem); the separate Add-Trigger form in AutoResponderSection had
its own type <select> (Text/HTTP/Script) that was missed, so new mailbox
triggers couldn't be created from the UI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(dead-drop): don't require response text to add a Mailbox trigger

The Add button's disabled gate required a non-empty response field for
all types; Mailbox has no response, so the button stayed greyed out.
Exempt mailbox from the response-required check (matches validateResponse).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(dead-drop): accept mailbox responseType in settings save validation

The settings-save validator required a non-empty response for every
trigger and only allowed text/http/script responseTypes, so saving a
Mailbox trigger failed with a generic 400. Exempt mailbox from the
response-required check and add it to the responseType allowlist.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test(dead-drop): settings-save accepts mailbox triggers without response text

Regression coverage for the mailbox responseType in the autoResponderTriggers
validator: a mailbox trigger with empty response now saves (200), while
non-mailbox empty responses and unknown responseTypes still 400.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(dead-drop): tolerate optional command keyword prefix

The mailbox service parsed hardcoded msg/inbox, but a trigger configured with
prefixed keywords (e.g. betamsg/betainbox, to coexist with another responder
already using msg/inbox) would fire the handler yet fall through to help. Strip
an optional non-space prefix from the leading verb so prefixed keywords parse
correctly; no-op for plain msg/inbox. Caught by live over-the-air testing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(dead-drop): add Mailbox feature docs + live testing brief

- automation.md: Mailbox response type + 'Mailbox (Dead Drop)' section
  (commands, recipient matching, delivery format, limits, command-prefix
  coexistence, configuration).
- dev-notes/DEAD_DROP_TESTING.md: architecture, automated coverage, and the
  over-the-air validation results (ALTO MF / ALTO LF / ZN Office).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(dead-drop): register dead_drop_messages in migrate-db table lists

The cross-database migrate-db CLI tracks every schema table in TABLE_ORDER /
SKIP_TABLES; migrationTables.test.ts fails if a new schema table isn't listed.
Add dead_drop_messages to TABLE_ORDER and SOURCE_SCOPED_TABLES (it carries a
sourceId, like auto_favorite_targets). Caught by the full Vitest suite.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(dead-drop): address PR review feedback

- Mark messages played from the delivery-success callback, not at enqueue:
  handleCommand returns { responses, playOnDelivery }; a dropped body DM now
  leaves the message pending instead of losing it. (#1)
- Wire purgeExpired into databaseMaintenanceService so expired rows are
  reclaimed daily (purgeExpired returns a count). (#2)
- Count the per-recipient cap across the recipient's identity forms via an
  injected node resolver, so it can't be bypassed by addressing one node by
  several name forms. (#3)
- Mailbox bypasses the per-node cooldown (interactive flow). (#4)
- inbox play <sender> filter matches !hex/node-num forms too. (#5)
- Non-DM commands return [] (no unsolicited DM). (#6)
- inbox delete returns the same response for not-yours vs non-existent ids
  (no id enumeration). (#7)
- Wrap the mailbox dispatch in try/catch like the script branch. (#8)
- Remove the command-prefix tolerance: canonical msg/inbox only. (#9)
- Use shared nodeIdHex (unsigned coerce) for the mailbox log target. (#10)

Docs + tests updated to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(dead-drop): recommend enabling Verify response on the mailbox trigger

Played-state is committed from the delivery-success callback; with Verify
response off (maxAttempts=1) a single unacked send could mark a voicemail
played on transmit. Document enabling Verify response so undelivered bodies
resurface. (PR #3538 review follow-up)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: chrisn <chrisn@DebDev1.corp.tlclocal.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Randall Hand <randall.hand@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant