Add node operator tray app and browser extension#7
Conversation
Scaffold a BOINC-style desktop tray application for volunteer node operators and a Manifest V3 browser extension for monitoring. Tray app (tray/src-tauri/): Rust backend with Tauri 2, system tray menu, health poller, resource allocation controls, cartridge management, and a dark-themed HTML dashboard frontend. Browser extension (extension/): polls boj-server health, shows badge status (ON/OFF), popup dashboard with status/cartridges/settings tabs, configurable server URL. Works in Chrome and Firefox. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ccface98a1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| pub async fn fetch_cartridges() -> Result<Vec<CartridgeSubscription>, Box<dyn std::error::Error>> { | ||
| let client = reqwest::Client::new(); | ||
| let resp = client | ||
| .get(format!("{BASE_URL}/api/cartridges")) |
There was a problem hiding this comment.
Use existing cartridge route instead of /api namespace
This client call targets "/api/cartridges", but the server router only exposes cartridge APIs at /cartridges and /cartridge/{name} (see adapter/v/src/main.v around RestHandler.handle), so this request path will 404 and the tray cartridge list/toggles cannot work against the current boj-server API. The same /api/* assumption appears in related tray calls, so this is a functional mismatch rather than a transient network failure.
Useful? React with 👍 / 👎.
| pub async fn fetch_status() -> Result<ServerStatus, Box<dyn std::error::Error>> { | ||
| let client = reqwest::Client::new(); | ||
| let resp = client | ||
| .get(format!("{BASE_URL}/health")) |
There was a problem hiding this comment.
Fetch status from endpoint that returns expected schema
This code deserializes /health into ServerStatus, but /health currently returns only {"status":"ok"} while detailed metrics are served by /status (see adapter/v/src/main.v route handling and docs/API-CONTRACT.md entries for /health vs /status), so successful health responses still fail deserialization and the tray will repeatedly show the server as offline.
Useful? React with 👍 / 👎.
| /// Background service worker — polls boj-server health and updates | ||
| /// the extension badge to reflect current server status. | ||
|
|
||
| const SERVER_URL = "http://localhost:7700"; |
There was a problem hiding this comment.
Read server URL from storage in background poller
The background worker hardcodes http://localhost:7700, but the popup allows saving a custom serverUrl in chrome.storage.local; after users change the URL, badge polling and poll-now still hit localhost, so the toolbar status can disagree with the popup and report the wrong node health whenever the server is not on the default address.
Useful? React with 👍 / 👎.
| "http://localhost:7700/*", | ||
| "http://[::1]:7700/*" |
There was a problem hiding this comment.
Grant host permissions for configurable server URL
The settings UI advertises changing host/port, but host_permissions only allow requests to localhost:7700 and [::1]:7700; in MV3 this blocks fetches to any other configured host or port, so saved non-default server URLs in the popup will fail due to permission denial rather than connectivity.
Useful? React with 👍 / 👎.
Summary
What's included
Tray app (
tray/)Browser extension (
extension/)/healthevery minute, sets toolbar badge (green ON / red OFF)Test plan
chrome://extensions→ Load unpacked) and verify badge updatesabout:debugging→ Load Temporary Add-on) and verify popup renderscd tray/src-tauri && cargo checkto verify Rust compiles🤖 Generated with Claude Code