Align web message status wording and evidence#1251
Conversation
|
@RCGV1 is attempting to deploy a commit to the Meshtastic Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughThis PR adds relayed message-state and routing-error tracking across SDK contracts, persistence, ChatClient routing, web delivery-status rendering, retry wiring, and localized delivery-status strings. ChangesMessage delivery status and retry
Estimated code review effort: 4 (Complex) | ~75 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
There was a problem hiding this comment.
Pull request overview
This PR aligns chat message delivery status semantics and wording across the SDK and web UI, including persisting richer routing error context so historical messages can render the correct state and failure reason after reload.
Changes:
- Added a
Relayedintermediate message state plus precedence rules to prevent state “downgrades” (e.g.,Ack→Relayed). - Persisted
routingErroralongside message state (in-memory + sqlocal storage), including schema/migration updates to dedupe and re-key legacy direct-message conversation buckets. - Updated the web Messages UI to display expanded delivery/failure wording (with SR-friendly labels) and added a “Retry” affordance for retryable states.
Reviewed changes
Copilot reviewed 30 out of 53 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/sdk/src/features/chat/state/chatStore.ts | Adds message lookup and state/routing-error update gating (precedence + no-op detection). |
| packages/sdk/src/features/chat/infrastructure/repositories/InMemoryMessageRepository.ts | Supports explicit conversation keys, preserves direct-message bucketing via localNodeNum, and persists routingError. |
| packages/sdk/src/features/chat/infrastructure/repositories/InMemoryMessageRepository.test.ts | Extends tests to cover routingError persistence, state precedence, and direct bucketing rules. |
| packages/sdk/src/features/chat/infrastructure/MessageMapper.ts | Initializes mapped messages with routingError: undefined. |
| packages/sdk/src/features/chat/index.ts | Re-exports message-state precedence helpers for downstream usage. |
| packages/sdk/src/features/chat/domain/MessageState.ts | Introduces Relayed and precedence/upgrade helpers. |
| packages/sdk/src/features/chat/domain/MessageRepository.ts | Extends repository contract to accept optional conversation key + routingError on updates. |
| packages/sdk/src/features/chat/domain/Message.ts | Adds optional routingError to the message domain model. |
| packages/sdk/src/features/chat/ChatClient.ts | Tracks requestId vs packet id, computes Relayed vs Ack, and serializes persistence of append vs state updates. |
| packages/sdk/src/features/chat/ChatClient.send.test.ts | Adds coverage for requestId matching, relayed-vs-recipient ACK semantics, and routing error persistence. |
| packages/sdk/src/features/chat/ChatClient.persistence.test.ts | Adds ordering tests to ensure final state wins in persistence races. |
| packages/sdk/src/core/types.ts | Adds optional requestId to PacketMetadata. |
| packages/sdk/src/core/packet-codec/decodePacket.ts | Populates PacketMetadata.requestId from decoded data packets. |
| packages/sdk/mod.ts | Exposes message-state precedence helpers at the SDK top-level exports. |
| packages/sdk-storage-sqlocal/src/schema/migrations.ts | Adds routing_error, dedupes by state precedence, creates unique index, and re-keys legacy outbound direct conversations. |
| packages/sdk-storage-sqlocal/src/schema/migrations.test.ts | Adds tests for the new unique index and direct-message re-keying behaviors (including ambiguous-history no-op cases). |
| packages/sdk-storage-sqlocal/src/schema/chat.ts | Extends messages schema with relayed + routing_error and defines a unique device+id index. |
| packages/sdk-storage-sqlocal/src/chat/SqlocalMessageRepository.ts | Stores routingError, infers direct conversation by local node, prevents state downgrades at update time, and uses explicit conv keys for inserts/notifications. |
| packages/sdk-storage-sqlocal/src/chat/SqlocalMessageRepository.test.ts | Adds routingError/state precedence tests and direct-message reload/bucketing tests. |
| apps/web/src/pages/Messages.tsx | Adds a retry callback and passes it through to chat rendering. |
| apps/web/src/core/subscriptions.ts | Removes legacy refreshKeys dialog trigger for routing errors now handled elsewhere. |
| apps/web/src/core/subscriptions.test.ts | Adds regression test ensuring refreshKeys is not opened for NO_CHANNEL/PKI_UNKNOWN_PUBKEY. |
| apps/web/src/core/stores/messageStore/index.ts | Extends legacy message shape with Relayed + optional routingError. |
| apps/web/src/core/hooks/useChatLegacy.ts | Maps SDK message routingError + relayed state into legacy message shape. |
| apps/web/src/core/hooks/useChatAsLegacyMessages.ts | Same as above for the adapter used by Messages UI. |
| apps/web/src/components/PageComponents/Messages/MessageItem.tsx | Switches to centralized delivery-status mapping, displays detail text in tooltip, and adds a Retry button. |
| apps/web/src/components/PageComponents/Messages/messageDeliveryStatus.ts | New mapping layer from message state/routing error to visible text, tooltip detail, icon, and retryability. |
| apps/web/src/components/PageComponents/Messages/messageDeliveryStatus.test.ts | Unit tests for the new delivery-status mapping and per-error wording. |
| apps/web/src/components/PageComponents/Messages/ChannelChat.tsx | Plumbs retry handler down to MessageItem. |
| apps/web/public/i18n/locales/en/messages.json | Replaces legacy delivery status strings with expanded, design-aligned wording and retry labels. |
| const isSender = myNodeNum !== undefined && message.from === myNodeNum; | ||
| const isOnPrimaryChannel = message.channel === Types.ChannelNumber.Primary; // Use the enum | ||
| const shouldShowStatusIcon = isSender && isOnPrimaryChannel; | ||
| const shouldShowStatus = isSender; | ||
| const canRetry = shouldShowStatus && messageStatusInfo.canRetry && onRetry; | ||
|
|
| size="sm" | ||
| className="h-5 px-1.5 text-xs text-slate-600 hover:text-slate-950 dark:text-slate-300 dark:hover:text-white" | ||
| onClick={() => onRetry(message)} | ||
| aria-label={t("deliveryStatus.retryAriaLabel", { |
| <TooltipContent className="bg-slate-800 dark:bg-slate-600 text-white px-4 py-1 rounded text-xs"> | ||
| {statusInfo.displayText} | ||
| {statusInfo.detailText} | ||
| <TooltipArrow className="fill-slate-800" /> | ||
| </TooltipContent> |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (6)
packages/sdk-storage-sqlocal/src/schema/migrations.ts (1)
103-119: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUnused aggregates in
direct_buckets.
peer_node(MIN(to_node)) andmessage_count(COUNT(*)) are computed but never referenced by the downstream CTEs or theUPDATE. Onlyrecipient_countandactionable_countare used. Dropping the unused aggregates keeps the migration lean.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/sdk-storage-sqlocal/src/schema/migrations.ts` around lines 103 - 119, The direct_buckets CTE in migrations.ts is computing aggregates that are never used downstream; remove the unused peer_node and message_count fields from the SELECT while keeping recipient_count and actionable_count. Update the direct_buckets query so it only projects values referenced by the later CTEs and UPDATE, using the existing direct_buckets symbol as the place to make the cleanup.packages/sdk-storage-sqlocal/src/schema/chat.ts (1)
32-37: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueRedundant index on
(device_id, id).
pk: index("messages_pk")anddeviceMessageUnique: uniqueIndex("idx_messages_device_id_id_unique")cover the exact same columns. The unique index fully serves any lookup the plain index would, somessages_pkis now dead weight (extra storage and per-write maintenance). Consider dropping it from the schema (plus aDROP INDEXin a migration for existing DBs).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/sdk-storage-sqlocal/src/schema/chat.ts` around lines 32 - 37, The schema in chat.ts defines two indexes on the same `(deviceId, id)` columns: `pk` and `deviceMessageUnique`, making `messages_pk` redundant. Remove the plain `pk: index("messages_pk")` from the table definition and keep the unique index `deviceMessageUnique` as the sole lookup/index for those columns. If existing databases already have `messages_pk`, add a migration to drop that index so the schema and on-disk DB stay aligned.packages/sdk-storage-sqlocal/src/chat/SqlocalMessageRepository.ts (1)
205-217: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueReuse the schema-inferred
MessageRowtype.packages/sdk-storage-sqlocal/src/schema/chat.tsalready exportsMessageRow = typeof messages.$inferSelect, so this local interface can drift from the schema. Import the shared type instead.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/sdk-storage-sqlocal/src/chat/SqlocalMessageRepository.ts` around lines 205 - 217, The local MessageRow interface in SqlocalMessageRepository should not duplicate the chat schema. Remove the inline interface and import the shared MessageRow type exported from schema/chat.ts so the repository uses the schema-inferred shape directly. Update any references in SqlocalMessageRepository to rely on that imported type and keep the repository aligned with the messages table definition.packages/sdk/src/features/chat/domain/MessageState.ts (1)
8-17: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDocument the precedence rule here. The Pending < Relayed < Failed < Ack order is easy to misread; a short note explaining that Failed can replace Relayed while Ack remains terminal would help prevent accidental reordering.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/sdk/src/features/chat/domain/MessageState.ts` around lines 8 - 17, Document the ordering rule in getMessageStatePrecedence and the messageStatePrecedence map so the intent is explicit: Pending < Relayed < Failed < Ack, with Failed allowed to replace Relayed while Ack stays terminal. Add a short comment near the MessageState precedence table in MessageState.ts explaining that the numeric values are deliberate and should not be reordered without preserving this transition behavior.apps/web/src/core/subscriptions.test.ts (1)
30-49: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low valueTest only verifies the negative case; consider also asserting the dialog still opens for the case(s) meant to keep triggering it.
As written, this test would pass even if
setDialogOpenwere never called fromonRoutingPacketat all (i.e., if the refreshKeys trigger were removed outright rather than being correctly scoped away fromNO_CHANNEL/PKI_UNKNOWN_PUBKEY). Consider adding a companion case that still exercises the intended remaining refreshKeys trigger to guard against accidental full removal.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/src/core/subscriptions.test.ts` around lines 30 - 49, The subscribeAll routing error test only checks that refreshKeys is not opened for NO_CHANNEL and PKI_UNKNOWN_PUBKEY, so it could still pass if the onRoutingPacket path stopped opening the dialog entirely. Update the tests in subscriptions.test.ts to keep the existing negative assertions and add a companion case that dispatches a routing reason meant to still trigger refreshKeys, then assert device.setDialogOpen is called. Use subscribeAll, onRoutingPacket, and setDialogOpen to anchor the new coverage.packages/sdk/src/features/chat/ChatClient.ts (1)
315-360: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winConsider logging persistence failures instead of silently swallowing them.
persistAppend/persistStateUpdateintentionally swallow repository errors "to avoid breaking reactive UI updates," but a silentcatch {}means ifrepository.appendfails, the subsequentpersistStateUpdatefor that message id becomes a no-op (row never existed to update), and the failure is invisible until the user reloads and finds the message/state missing or stale. A minimalthis.client.log.error(...)(or similar) inside each catch would preserve the "don't break reactive flow" behavior while making silent data-loss diagnosable.♻️ Suggested logging addition
try { await this.repository.append(message, conv); if (this.retention) await this.repository.prune(this.retention); - } catch { + } catch (err) { + this.client.log.error("ChatClient", `persistAppend failed: ${err}`); // persistence failure must not break reactive flow }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/sdk/src/features/chat/ChatClient.ts` around lines 315 - 360, Both persistAppend and persistStateUpdate currently swallow repository errors, which hides data-loss and makes failed persistence impossible to diagnose. Update the catch blocks in ChatClient.persistAppend and ChatClient.persistStateUpdate to log the failure through the existing client logging mechanism (for example, this.client.log.error) while still preserving the non-throwing reactive flow. Include enough context to identify the operation and message/conversation identifiers, and keep the pendingMessagePersistence and pendingStatePersistence cleanup logic unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web/public/i18n/locales/en/messages.json`:
- Around line 22-101: Update the locale message catalogs to match the new nested
deliveryStatus structure in messages.json, since the current translations still
expose the old flat keys and will fall back to English. In each non-English
messages.json, replace the old delivery status entries with the new nested
symbols such as deliveryStatus.deliveredToMesh,
deliveryStatus.deliveredToRecipient, deliveryStatus.encryptedSendFailed,
deliveryStatus.failedToMesh, deliveryStatus.noChannel, deliveryStatus.sending,
and deliveryStatus.unknown so the UI can resolve localized strings correctly.
Keep the same displayText/detailText shape and ensure every locale mirrors the
English key set exactly.
---
Nitpick comments:
In `@apps/web/src/core/subscriptions.test.ts`:
- Around line 30-49: The subscribeAll routing error test only checks that
refreshKeys is not opened for NO_CHANNEL and PKI_UNKNOWN_PUBKEY, so it could
still pass if the onRoutingPacket path stopped opening the dialog entirely.
Update the tests in subscriptions.test.ts to keep the existing negative
assertions and add a companion case that dispatches a routing reason meant to
still trigger refreshKeys, then assert device.setDialogOpen is called. Use
subscribeAll, onRoutingPacket, and setDialogOpen to anchor the new coverage.
In `@packages/sdk-storage-sqlocal/src/chat/SqlocalMessageRepository.ts`:
- Around line 205-217: The local MessageRow interface in
SqlocalMessageRepository should not duplicate the chat schema. Remove the inline
interface and import the shared MessageRow type exported from schema/chat.ts so
the repository uses the schema-inferred shape directly. Update any references in
SqlocalMessageRepository to rely on that imported type and keep the repository
aligned with the messages table definition.
In `@packages/sdk-storage-sqlocal/src/schema/chat.ts`:
- Around line 32-37: The schema in chat.ts defines two indexes on the same
`(deviceId, id)` columns: `pk` and `deviceMessageUnique`, making `messages_pk`
redundant. Remove the plain `pk: index("messages_pk")` from the table definition
and keep the unique index `deviceMessageUnique` as the sole lookup/index for
those columns. If existing databases already have `messages_pk`, add a migration
to drop that index so the schema and on-disk DB stay aligned.
In `@packages/sdk-storage-sqlocal/src/schema/migrations.ts`:
- Around line 103-119: The direct_buckets CTE in migrations.ts is computing
aggregates that are never used downstream; remove the unused peer_node and
message_count fields from the SELECT while keeping recipient_count and
actionable_count. Update the direct_buckets query so it only projects values
referenced by the later CTEs and UPDATE, using the existing direct_buckets
symbol as the place to make the cleanup.
In `@packages/sdk/src/features/chat/ChatClient.ts`:
- Around line 315-360: Both persistAppend and persistStateUpdate currently
swallow repository errors, which hides data-loss and makes failed persistence
impossible to diagnose. Update the catch blocks in ChatClient.persistAppend and
ChatClient.persistStateUpdate to log the failure through the existing client
logging mechanism (for example, this.client.log.error) while still preserving
the non-throwing reactive flow. Include enough context to identify the operation
and message/conversation identifiers, and keep the pendingMessagePersistence and
pendingStatePersistence cleanup logic unchanged.
In `@packages/sdk/src/features/chat/domain/MessageState.ts`:
- Around line 8-17: Document the ordering rule in getMessageStatePrecedence and
the messageStatePrecedence map so the intent is explicit: Pending < Relayed <
Failed < Ack, with Failed allowed to replace Relayed while Ack stays terminal.
Add a short comment near the MessageState precedence table in MessageState.ts
explaining that the numeric values are deliberate and should not be reordered
without preserving this transition behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 3416d911-6fdb-441d-9b0a-d139d4a181db
⛔ Files ignored due to path filters (23)
validation-artifacts/message-status/admin-key-not-authorized.pngis excluded by!**/*.pngvalidation-artifacts/message-status/admin-session-expired.pngis excluded by!**/*.pngvalidation-artifacts/message-status/channel-implicit-ack.pngis excluded by!**/*.pngvalidation-artifacts/message-status/delivered-to-mesh.pngis excluded by!**/*.pngvalidation-artifacts/message-status/delivered-to-recipient.pngis excluded by!**/*.pngvalidation-artifacts/message-status/dm-implicit-ack.pngis excluded by!**/*.pngvalidation-artifacts/message-status/duty-cycle-limit.pngis excluded by!**/*.pngvalidation-artifacts/message-status/encrypted-send-failed.pngis excluded by!**/*.pngvalidation-artifacts/message-status/explicit-ack.pngis excluded by!**/*.pngvalidation-artifacts/message-status/failed-to-mesh.pngis excluded by!**/*.pngvalidation-artifacts/message-status/invalid-request.pngis excluded by!**/*.pngvalidation-artifacts/message-status/message-too-large.pngis excluded by!**/*.pngvalidation-artifacts/message-status/no-ack.pngis excluded by!**/*.pngvalidation-artifacts/message-status/no-app-response.pngis excluded by!**/*.pngvalidation-artifacts/message-status/no-channel.pngis excluded by!**/*.pngvalidation-artifacts/message-status/no-radio-interface.pngis excluded by!**/*.pngvalidation-artifacts/message-status/not-authorized.pngis excluded by!**/*.pngvalidation-artifacts/message-status/overview.pngis excluded by!**/*.pngvalidation-artifacts/message-status/rate-limited.pngis excluded by!**/*.pngvalidation-artifacts/message-status/recipient-key-unavailable.pngis excluded by!**/*.pngvalidation-artifacts/message-status/recipient-needs-your-key.pngis excluded by!**/*.pngvalidation-artifacts/message-status/relayed.pngis excluded by!**/*.pngvalidation-artifacts/message-status/sending.pngis excluded by!**/*.png
📒 Files selected for processing (30)
apps/web/public/i18n/locales/en/messages.jsonapps/web/src/components/PageComponents/Messages/ChannelChat.tsxapps/web/src/components/PageComponents/Messages/MessageItem.tsxapps/web/src/components/PageComponents/Messages/messageDeliveryStatus.test.tsapps/web/src/components/PageComponents/Messages/messageDeliveryStatus.tsapps/web/src/core/hooks/useChatAsLegacyMessages.tsapps/web/src/core/hooks/useChatLegacy.tsapps/web/src/core/stores/messageStore/index.tsapps/web/src/core/subscriptions.test.tsapps/web/src/core/subscriptions.tsapps/web/src/pages/Messages.tsxpackages/sdk-storage-sqlocal/src/chat/SqlocalMessageRepository.test.tspackages/sdk-storage-sqlocal/src/chat/SqlocalMessageRepository.tspackages/sdk-storage-sqlocal/src/schema/chat.tspackages/sdk-storage-sqlocal/src/schema/migrations.test.tspackages/sdk-storage-sqlocal/src/schema/migrations.tspackages/sdk/mod.tspackages/sdk/src/core/packet-codec/decodePacket.tspackages/sdk/src/core/types.tspackages/sdk/src/features/chat/ChatClient.persistence.test.tspackages/sdk/src/features/chat/ChatClient.send.test.tspackages/sdk/src/features/chat/ChatClient.tspackages/sdk/src/features/chat/domain/Message.tspackages/sdk/src/features/chat/domain/MessageRepository.tspackages/sdk/src/features/chat/domain/MessageState.tspackages/sdk/src/features/chat/index.tspackages/sdk/src/features/chat/infrastructure/MessageMapper.tspackages/sdk/src/features/chat/infrastructure/repositories/InMemoryMessageRepository.test.tspackages/sdk/src/features/chat/infrastructure/repositories/InMemoryMessageRepository.tspackages/sdk/src/features/chat/state/chatStore.ts
💤 Files with no reviewable changes (1)
- apps/web/src/core/subscriptions.ts
| "deliveryStatus": { | ||
| "delivered": { | ||
| "label": "Message delivered", | ||
| "displayText": "Message delivered" | ||
| "retry": "Retry", | ||
| "retryAriaLabel": "Retry message: {{status}}", | ||
| "deliveredToMesh": { | ||
| "displayText": "Delivered to mesh", | ||
| "detailText": "At least one node heard this channel message." | ||
| }, | ||
| "failed": { | ||
| "label": "Message delivery failed", | ||
| "displayText": "Delivery failed" | ||
| "deliveredToRecipient": { | ||
| "displayText": "Delivered to recipient", | ||
| "detailText": "The recipient confirmed this direct message." | ||
| }, | ||
| "unknown": { | ||
| "label": "Message status unknown", | ||
| "displayText": "Unknown state" | ||
| "encryptedSendFailed": { | ||
| "displayText": "Could not send encrypted message", | ||
| "detailText": "The radio could not create the encrypted path for this message. Let node info sync, then try again." | ||
| }, | ||
| "adminKeyNotAuthorized": { | ||
| "displayText": "Admin key not authorized", | ||
| "detailText": "The admin public key is not authorized on the destination." | ||
| }, | ||
| "adminSessionExpired": { | ||
| "displayText": "Admin session expired", | ||
| "detailText": "The admin session key is missing, invalid, or expired. Start a new admin session, then try again." | ||
| }, | ||
| "dutyCycleLimit": { | ||
| "displayText": "Duty cycle limit", | ||
| "detailText": "The radio is temporarily blocked by the regional airtime limit. Try again later." | ||
| }, | ||
| "failedToMesh": { | ||
| "displayText": "Failed to deliver to mesh", | ||
| "detailText": "No node confirmed this message. Try again when you have better signal or more mesh coverage." | ||
| }, | ||
| "invalidRequest": { | ||
| "displayText": "Invalid request", | ||
| "detailText": "The receiving app rejected the request. Check the message or command and try again." | ||
| }, | ||
| "messageTooLarge": { | ||
| "displayText": "Message is too large to send", | ||
| "detailText": "Shorten the message and send it again." | ||
| }, | ||
| "noAppResponse": { | ||
| "displayText": "No app response", | ||
| "detailText": "The destination received the request, but no app or module responded." | ||
| }, | ||
| "noChannel": { | ||
| "displayText": "Channel/key mismatch", | ||
| "detailText": "This message could not be encoded or decoded with a matching channel/key. Check the channel and key, then try again." | ||
| }, | ||
| "waiting": { | ||
| "label": "Sending message", | ||
| "displayText": "Waiting for delivery" | ||
| "noRadioInterface": { | ||
| "displayText": "No radio interface", | ||
| "detailText": "The radio does not have a usable interface for this send." | ||
| }, | ||
| "notAuthorized": { | ||
| "displayText": "Not authorized", | ||
| "detailText": "The destination refused permission for this request." | ||
| }, | ||
| "rateLimited": { | ||
| "displayText": "Rate limited", | ||
| "detailText": "Messages are being sent too quickly. Wait a moment, then try again." | ||
| }, | ||
| "recipientKeyUnavailable": { | ||
| "displayText": "Recipient key unavailable", | ||
| "detailText": "Your node does not have the recipient's public key yet. Wait for node info to sync, then try again." | ||
| }, | ||
| "recipientNeedsYourKey": { | ||
| "displayText": "Recipient needs your key", | ||
| "detailText": "The recipient does not know your public key yet. Your node may share its info automatically; try again after it syncs." | ||
| }, | ||
| "relayed": { | ||
| "displayText": "Relayed, not confirmed by recipient", | ||
| "detailText": "A node relayed this message, but the recipient has not confirmed it." | ||
| }, | ||
| "sending": { | ||
| "displayText": "Sending...", | ||
| "detailText": "The radio is still trying to send this message." | ||
| }, | ||
| "unknown": { | ||
| "displayText": "Message status unknown", | ||
| "detailText": "The message status is not available." | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check whether other locales still use the old deliveryStatus schema.
fd messages.json apps/web/public/i18n/locales -x sh -c 'echo "== {} =="; jq ".deliveryStatus" {}'Repository: meshtastic/web
Length of output: 12686
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== deliveryStatus usages ==\n'
rg -n '"deliveryStatus"|deliveryStatus\.' apps/web -g '!**/node_modules/**'
printf '\n== locale lookup / fallback hints ==\n'
rg -n 'fallback|i18n|locales/' apps/web/src apps/web/public -g '!**/node_modules/**' | head -n 200Repository: meshtastic/web
Length of output: 31712
🏁 Script executed:
#!/bin/bash
set -euo pipefail
cat -n apps/web/src/i18n-config.ts | sed -n '1,120p'Repository: meshtastic/web
Length of output: 2387
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== en/ui deliveryStatus ==\n'
jq '.deliveryStatus' apps/web/public/i18n/locales/en/ui.json
printf '\n== de-DE/ui deliveryStatus ==\n'
jq '.deliveryStatus' apps/web/public/i18n/locales/de-DE/ui.json
printf '\n== zh-TW/ui deliveryStatus ==\n'
jq '.deliveryStatus' apps/web/public/i18n/locales/zh-TW/ui.jsonRepository: meshtastic/web
Length of output: 257
Update the localized deliveryStatus entries in the other messages.json files.
Several locales still use the old flat keys (delivered/failed/waiting/unknown), so these new nested lookups will fall back to English for non-English users.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/public/i18n/locales/en/messages.json` around lines 22 - 101, Update
the locale message catalogs to match the new nested deliveryStatus structure in
messages.json, since the current translations still expose the old flat keys and
will fall back to English. In each non-English messages.json, replace the old
delivery status entries with the new nested symbols such as
deliveryStatus.deliveredToMesh, deliveryStatus.deliveredToRecipient,
deliveryStatus.encryptedSendFailed, deliveryStatus.failedToMesh,
deliveryStatus.noChannel, deliveryStatus.sending, and deliveryStatus.unknown so
the UI can resolve localized strings correctly. Keep the same
displayText/detailText shape and ensure every locale mirrors the English key set
exactly.
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web/public/i18n/locales/bg-BG/messages.json`:
- Around line 22-98: Translate the `deliveryStatus` entries in `messages.json`
to Bulgarian so the locale is consistent with the rest of the file; update the
string values for the related status objects such as `retry`, `deliveredToMesh`,
`encryptedSendFailed`, `failedToMesh`, `recipientKeyUnavailable`, `sending`, and
`unknown` while preserving the existing keys and placeholders like `{{status}}`.
In `@apps/web/public/i18n/locales/it-IT/messages.json`:
- Around line 22-98: The delivery-status entries in messages.json are still in
English, so replace the untranslated values for keys like retry, retryAriaLabel,
deliveredToMesh, deliveredToRecipient, encryptedSendFailed, and the other status
objects in this locale file with proper Italian text. Keep the existing JSON
structure and update both displayText and detailText strings consistently across
all affected message status keys.
In `@apps/web/public/i18n/locales/nl-NL/messages.json`:
- Around line 22-98: The deliveryStatus entries in messages.json are still in
English and need Dutch localization. Replace the displayText and detailText
values for each status key under this block with Dutch translations, keeping the
existing keys and structure intact. Use the deliveryStatus object in
nl-NL/messages.json to update all affected status strings consistently.
In `@apps/web/public/i18n/locales/sv-SE/messages.json`:
- Around line 22-98: The delivery-status strings in the sv-SE locale are still
in English, so update the message entries in the translation object to Swedish
before merging. Translate each delivery-related label and detail text
consistently in the messages JSON, keeping the existing keys such as retry,
deliveredToMesh, deliveredToRecipient, encryptedSendFailed, failedToMesh,
noChannel, and unknown unchanged while replacing only the user-facing copy.
In `@apps/web/public/i18n/locales/zh-TW/messages.json`:
- Around line 22-98: The new deliveryStatus entries in messages.json are still
in English and need Traditional Chinese translations before merge. Update the
localized strings for the status labels and detail text in this block, keeping
the existing keys and structure intact, and make sure the translations are
applied consistently across all entries such as retry, deliveredToMesh,
failedToMesh, and unknown.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: facc19cc-4ef4-4ccf-a4e6-68c928ef55cf
📒 Files selected for processing (21)
apps/web/public/i18n/locales/be-BY/messages.jsonapps/web/public/i18n/locales/bg-BG/messages.jsonapps/web/public/i18n/locales/cs-CZ/messages.jsonapps/web/public/i18n/locales/de-DE/messages.jsonapps/web/public/i18n/locales/es-ES/messages.jsonapps/web/public/i18n/locales/fi-FI/messages.jsonapps/web/public/i18n/locales/fr-FR/messages.jsonapps/web/public/i18n/locales/hu-HU/messages.jsonapps/web/public/i18n/locales/it-IT/messages.jsonapps/web/public/i18n/locales/ja-JP/messages.jsonapps/web/public/i18n/locales/ko-KR/messages.jsonapps/web/public/i18n/locales/nl-NL/messages.jsonapps/web/public/i18n/locales/pl-PL/messages.jsonapps/web/public/i18n/locales/pt-BR/messages.jsonapps/web/public/i18n/locales/pt-PT/messages.jsonapps/web/public/i18n/locales/ru-RU/messages.jsonapps/web/public/i18n/locales/sv-SE/messages.jsonapps/web/public/i18n/locales/tr-TR/messages.jsonapps/web/public/i18n/locales/uk-UA/messages.jsonapps/web/public/i18n/locales/zh-CN/messages.jsonapps/web/public/i18n/locales/zh-TW/messages.json
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
@RCGV1 Wanted to check in on these draft PR's. Do you think you'll have time to get them over the line or did you need a hand? |
|
If you can help me test it that would be great. I don't want to make it ready without fully testing. |
Source issues
Summary
deliveryStatuskey structure across locale catalogs.UI validation
Local UI screenshots for all status states were generated and reviewed. Evidence image is embedded below from an evidence-only branch; screenshot files are intentionally not committed to this PR branch.
Validation
pnpm exec vitest run apps/web/src/components/PageComponents/Messages/messageDeliveryStatus.test.tspassed: 1 file, 19 tests.pnpm exec vitest run packages/sdk-storage-sqlocal/src/schema/migrations.test.tspassed: 1 file, 9 tests.pnpm run lintpassed with existing warnings.NODE_OPTIONS=--no-webstorage pnpm run testpassed: 71 files, 434 tests.pnpm --filter "./apps/web" run buildpassed locally.Hardware verification
Not yet performed. This PR is draft until hardware/real-device verification is complete.
Notes