Skip to content

armer-button: Show offline state when vehicle is disconnected#2620

Merged
rafaellehmkuhl merged 2 commits intobluerobotics:masterfrom
rafaellehmkuhl:gray-arm-button-on-disconnect
Apr 22, 2026
Merged

armer-button: Show offline state when vehicle is disconnected#2620
rafaellehmkuhl merged 2 commits intobluerobotics:masterfrom
rafaellehmkuhl:gray-arm-button-on-disconnect

Conversation

@rafaellehmkuhl
Copy link
Copy Markdown
Member

Render a gray "Offline" pill and block arm/disarm interactions while the vehicle is unreachable, so the widget no longer implies a stale armed state after a GCS disconnection.

Cap.2026-04-22.at.18.36.00.mp4

Fix #2619

@github-actions
Copy link
Copy Markdown

Automated PR Review (Claude)

0. Summary

Verdict: MINOR SUGGESTIONS

Minor items to consider: 1.1, 6.1, 9.1.

This PR adds an offline state to the ArmerButton mini-widget. When the vehicle is disconnected (isVehicleOnline === false), the button displays a gray "Offline" pill, blocks arm/disarm interactions, and shows a snackbar error if clicked. This prevents the widget from displaying a stale armed/disarmed state after GCS disconnection. The change is clean, small (1 file, +24/−3), and follows existing patterns well.

1. Correctness & Implementation Bugs

1.1 (minor) — isArmed retains its stale value when the vehicle goes offline. The new stateLabel computed correctly masks this by checking isVehicleOnline first, and handleClick also guards against it. However, there's a subtle edge case: if the vehicle reconnects, isVehicleOnline becomes true before a new onArm callback fires, so for a brief moment the button could show the previous armed state (e.g., "Armed" from the prior session). This is pre-existing behavior not introduced by this PR, but worth noting since the PR partially addresses stale state. No action required unless the team wants to reset isArmed to undefined on disconnect in the store.

No other correctness issues found. The reactivity pattern is correct — stateLabel is a proper computed, handleClick correctly checks both editingMode and isVehicleOnline, and the ternary chain in the template :class binding is evaluated in the right order (offline → undefined → armed → disarmed).

2. AGENTS.md Adherence

No findings. The PR:

  • Uses computed from Vue (existing dependency) — no new dependencies added.
  • Does not add comments explaining "what" (correct per comment policy).
  • handleClick is an arrow function assigned to a const (allowed by .eslintrc.cjs func-style rule with allowArrowFunctions: true), so JSDoc is not required by the jsdoc/require-jsdoc rule.
  • No new local-storage keys.
  • No Lite vs. Standalone divergence.

3. Security

  • 3.1 No obfuscated or intentionally unreadable code.
  • 3.2 No base64/hex/encoded blobs or binary-like strings.
  • 3.3 No hidden Unicode, zero-width characters, RTL overrides, or homoglyph attacks.
  • 3.4 No new network calls, fetch/XHR/websocket to unknown hosts, or exfiltration patterns.
  • 3.5 No changes to build scripts, CI workflows, Dockerfiles, or Electron main-process code.
  • 3.6 No secret handling changes, no eval, Function(), or v-html usage.
  • 3.7 No new dependencies added.
  • 3.8 No other suspicious patterns. The change is straightforward UI logic.

4. Performance

No findings. The stateLabel computed is trivially cheap. No new watchers, intervals, timers, or subscriptions are introduced. The handleClick function short-circuits early when offline, avoiding unnecessary async work.

5. UI / UX

No findings. The offline state uses a gray pill (bg-slate-600/60, text-slate-300) centered at left-[15%] which visually differentiates it from the unknown/loading state (bg-slate-800/60, left-[4%]). The cursor-not-allowed class and descriptive title attribute provide appropriate affordance. The snackbar on click gives clear feedback. The approach is consistent with how MissionPlanningView.vue handles the disconnected state (:disabled, cursor-not-allowed).

6. Code Quality & Style

6.1 (nit) — In handleClick, the expression vehicleStore.isArmed ? disarm() : arm() uses a ternary as a statement. While this matches the original template expression, extracting it to handleClick was an opportunity to use an if/else for clarity:

if (vehicleStore.isArmed) {
  disarm()
} else {
  arm()
}

This is purely stylistic and the existing form works fine.

7. Tests

No findings. The existing file has no unit tests, and this PR doesn't change that. The change is a small UI behavior addition that would be best validated visually (as the PR video demonstrates).

8. Documentation

No findings. No README update needed — this is a bug fix for an existing widget with no Lite/Standalone divergence.

9. Nitpicks / Optional

9.1 (nit) — The nested ternary chain in the :class binding is now 4 levels deep (offline → undefined → armed → disarmed). It's still readable, but if another state is ever added, consider extracting it to a computed property (similar to stateLabel) for maintainability. Not needed for this PR.

Generated by Claude. This is advisory; a human reviewer must still approve.

Render a gray "Offline" pill and block arm/disarm interactions while the
vehicle is unreachable, so the widget no longer implies a stale armed
state after a GCS disconnection.
Clear the cached `isArmed` value on vehicle disconnection so the UI no
longer briefly shows the previous armed state when the vehicle comes
back online before a fresh arm callback fires.
@rafaellehmkuhl rafaellehmkuhl force-pushed the gray-arm-button-on-disconnect branch from 53618c7 to c2b3fe9 Compare April 22, 2026 22:17
@rafaellehmkuhl rafaellehmkuhl merged commit 2943e38 into bluerobotics:master Apr 22, 2026
11 checks passed
@rafaellehmkuhl rafaellehmkuhl deleted the gray-arm-button-on-disconnect branch April 22, 2026 23:10
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.

frontend: The vehicle shows as ARMED while the GCS is disconnected

2 participants