Skip to content

feat: support Android apps in worker heartbeat and UI#14

Merged
GeiserX merged 6 commits intomainfrom
feat/android-apps-display
Apr 4, 2026
Merged

feat: support Android apps in worker heartbeat and UI#14
GeiserX merged 6 commits intomainfrom
feat/android-apps-display

Conversation

@GeiserX
Copy link
Copy Markdown
Owner

@GeiserX GeiserX commented Apr 4, 2026

Summary

  • Accept top-level apps array in worker heartbeat payload (alongside containers), matching the schema change in CashPilot-android PR Test: verify database schema creation and earnings CRUD #6
  • New apps column on workers table (auto-migrated via ALTER TABLE on startup)
  • Android workers (system_info.device_type == "android") have their apps converted to service entries for the main dashboard — they appear like any other deployed service with running/stopped status
  • Fleet summary counts Android apps the same as Docker containers
  • Fleet page shows an "Android" badge on Android workers and renders app pills instead of container pills
  • Dashboard disables Docker actions (restart/stop/logs) for Android instances
  • Also: centers the sun in favicon, icon, and logo SVGs (was offset upward)

Companion PR

CashPilot-android #6 — moves apps from being faked as containers to a proper top-level apps field

Test plan

  • Existing Docker workers continue to work unchanged
  • Android heartbeat with apps array stores and displays correctly
  • Fleet summary counts Android apps in totals
  • Fleet page shows "Android" badge for Android workers
  • Dashboard shows Android services with correct running/stopped status
  • Docker action buttons are disabled for Android instances
  • DB migration adds apps column on existing databases without data loss

Summary by CodeRabbit

  • New Features

    • Added support for Android workers and showing installed apps (instead of containers) in fleet and services views.
    • Android instances show network usage (24h TX/RX) and are marked with an “Android” badge.
    • Container action buttons are disabled for Android workers.
  • UI / Content

    • Fleet page now shows OS version where available and updated deployment/help text to mention the Android app vs Docker env vars.

GeiserX added 2 commits April 4, 2026 22:04
- Accept top-level `apps` array in heartbeat (alongside `containers`)
- Store apps in new `apps` column on workers table (auto-migrated)
- Convert Android app statuses to service entries for the dashboard
- Fleet summary counts apps for Android workers
- Fleet UI shows "Android" badge and renders apps distinctly
- Dashboard disables Docker actions for Android instances
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 4, 2026

Warning

Rate limit exceeded

@GeiserX has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 11 minutes and 28 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 11 minutes and 28 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 88290be7-59e1-4c70-b5b6-c3d932f6867c

📥 Commits

Reviewing files that changed from the base of the PR and between f187a6f and 866a8a3.

📒 Files selected for processing (5)
  • app/database.py
  • app/main.py
  • app/static/js/app.js
  • app/templates/fleet.html
  • tests/test_workers.py
📝 Walkthrough

Walkthrough

Adds Android worker support: database gains an apps column and online migration, backend parses and persists per-worker apps with Android-specific metrics and exposes them in APIs, and frontend templates/scripts render Android apps (with network metrics) instead of Docker containers.

Changes

Cohort / File(s) Summary
Database Schema
app/database.py
Added apps TEXT NOT NULL DEFAULT '[]' to _SCHEMA with an online migration path; upsert_worker() signature and SQL updated to accept and persist apps.
Backend Logic & API
app/main.py
Added _safe_json() and _parse_worker_json(); extended WorkerHeartbeat with apps; heartbeat persistence updated to store apps; parsing now emits Android app instances with _is_android, net_tx_24h/net_rx_24h, and computes counts from apps for Android or containers otherwise; /api/services/deployed refactored to reuse container/app collection logic; fleet summary aggregation updated.
Frontend JS
app/static/js/app.js
Added fmtNetBytes() helper; disabled container action buttons for Android instances (is_android) and !has_docker; multi-instance rows render network TX/RX (formatted) for Android instances instead of CPU/memory and hide container name.
Frontend Template
app/templates/fleet.html
Renamed “total” card label to “Services”; copy updated to mention Android app for workers; renderWorkers detects sysInfo.device_type === 'android', selects w.apps vs w.containers, shows an “Android” badge, appends sysInfo.os_version when present, and adds renderApps() to display per-app running state and 24h network tooltips.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.92% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly summarizes the main change: adding Android app support to worker heartbeat collection and UI rendering, which is the primary focus of the entire changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/android-apps-display

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
app/main.py (1)

1562-1571: Consider extracting duplicate JSON parsing logic.

The fleet summary duplicates the JSON parsing and count logic that _parse_worker_json() already handles. Consider reusing it:

Suggested refactor
     for w in workers:
-        sys_info = json.loads(w.get("system_info", "{}"))
-        is_android = sys_info.get("device_type") == "android"
-        if is_android:
-            apps = json.loads(w.get("apps", "[]"))
-            total_containers += len(apps)
-            total_running += sum(1 for a in apps if a.get("running"))
-        else:
-            containers = json.loads(w.get("containers", "[]"))
-            total_containers += len(containers)
-            total_running += sum(1 for c in containers if c.get("status") == "running")
+        _parse_worker_json(w)
+        total_containers += w["container_count"]
+        total_running += w["running_count"]
         if w["status"] == "online":
             online_workers += 1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/main.py` around lines 1562 - 1571, The code duplicates JSON parsing and
counting for workers; instead call the existing helper _parse_worker_json(w) (or
adapt it to return both a list of containers/apps and the running count) and use
its outputs to increment total_containers and total_running; replace the
sys_info/json.loads blocks and the is_android branch with a single call to
_parse_worker_json(w) and then do total_containers += len(containers) and
total_running += running_count (or derive running_count from the returned
containers), ensuring _parse_worker_json handles both "apps" and "containers"
and returns a consistent structure.
app/database.py (1)

181-185: Consider logging when migration adds the new column.

The migration silently adds the apps column. Adding a log statement would help operators understand schema changes during upgrades.

Suggested improvement
         if "apps" not in cols:
             await db.execute("ALTER TABLE workers ADD COLUMN apps TEXT NOT NULL DEFAULT '[]'")
+            _logger.info("Migrated workers table: added 'apps' column")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/database.py` around lines 181 - 185, The migration silently adds the apps
column; update the block that checks PRAGMA table_info(workers) and executes
ALTER TABLE workers ADD COLUMN apps ... to emit a log entry when the column is
added. Use the project's existing logger (e.g., logger or process_logger) and
log at info/debug level with a clear message like "Added 'apps' column to
workers table during migration" and include the default value and SQL executed;
keep the log right after the await db.execute(...) that adds the column so
operators can see schema changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/database.py`:
- Around line 181-185: The migration silently adds the apps column; update the
block that checks PRAGMA table_info(workers) and executes ALTER TABLE workers
ADD COLUMN apps ... to emit a log entry when the column is added. Use the
project's existing logger (e.g., logger or process_logger) and log at info/debug
level with a clear message like "Added 'apps' column to workers table during
migration" and include the default value and SQL executed; keep the log right
after the await db.execute(...) that adds the column so operators can see schema
changes.

In `@app/main.py`:
- Around line 1562-1571: The code duplicates JSON parsing and counting for
workers; instead call the existing helper _parse_worker_json(w) (or adapt it to
return both a list of containers/apps and the running count) and use its outputs
to increment total_containers and total_running; replace the sys_info/json.loads
blocks and the is_android branch with a single call to _parse_worker_json(w) and
then do total_containers += len(containers) and total_running += running_count
(or derive running_count from the returned containers), ensuring
_parse_worker_json handles both "apps" and "containers" and returns a consistent
structure.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 33aa87db-04d6-478f-b0cf-6fed8bffb861

📥 Commits

Reviewing files that changed from the base of the PR and between a09b095 and b52175a.

⛔ Files ignored due to path filters (3)
  • app/static/favicon.svg is excluded by !**/*.svg
  • docs/icon.svg is excluded by !**/*.svg
  • docs/logo.svg is excluded by !**/*.svg
📒 Files selected for processing (4)
  • app/database.py
  • app/main.py
  • app/static/js/app.js
  • app/templates/fleet.html

- Resilient JSON parsing: _safe_json() helper so one malformed DB row
  degrades that worker instead of 500-ing the whole fleet/services UI
- Fleet summary now filters offline workers (was counting stale data)
- Fleet UI: "Containers" label → "Services", onboarding text mentions
  Android app, app pills show 24h net traffic on hover tooltip
- Dashboard sub-rows show net_tx/rx for Android instances instead of
  CPU/memory placeholders
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
app/templates/fleet.html (1)

142-147: Inconsistency with fmtNetBytes in app.js — missing null guard.

Line 143 returns b + ' B' which would produce "undefined B" or "null B" if called with falsy non-zero values. The equivalent function in app/static/js/app.js:77 uses (b || 0) + ' B'.

Currently safe because lines 156-157 pre-default values with || 0, but the function isn't robust standalone. Also consider extracting this to a shared utility to avoid duplication.

Proposed fix
   function fmtBytes(b) {
-    if (!b || b < 1024) return b + ' B';
+    if (!b || b < 1024) return (b || 0) + ' B';
     if (b < 1048576) return (b / 1024).toFixed(1) + ' KB';
     if (b < 1073741824) return (b / 1048576).toFixed(1) + ' MB';
     return (b / 1073741824).toFixed(2) + ' GB';
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/templates/fleet.html` around lines 142 - 147, The fmtBytes function can
produce "undefined B" or "null B" for falsy non-zero inputs; update fmtBytes to
defensively default b to 0 (e.g., treat b as (b || 0)) at the start of the
function so it mirrors fmtNetBytes behavior and never returns "undefined B", and
then consider extracting fmtBytes (and fmtNetBytes) into a shared utility to
remove duplication and keep formatting logic consistent across
app/templates/fleet.html and app/static/js/app.js.
app/static/js/app.js (1)

523-528: Consider adding a visual indicator that CPU/Memory columns show network metrics for Android.

The table headers remain "CPU" and "Memory" (lines 342-343), but Android sub-rows display network TX/RX. Users may be confused seeing byte values in these columns. A small inline label or tooltip on the cells could clarify this.

Otherwise the logic is sound — Android instances correctly show network metrics while non-Android instances retain CPU/memory display.

Also applies to: 532-532, 538-539

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/static/js/app.js` around lines 523 - 528, The CPU/Memory columns show
network metrics for Android instances (inst.is_android) but lack any visual cue;
update the code that builds cpuCell and memCell so when inst.is_android you
append a short inline indicator or tooltip (e.g., " (net TX)" / " (net RX)" or a
span with title attribute) to the displayed fmtNetBytes value, and ensure the
same change is applied where cpuCell/memCell are used (refer to variables
cpuCell, memCell and the inst.is_android branch); keep the existing formatting
for non-Android instances.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/static/js/app.js`:
- Around line 523-528: The CPU/Memory columns show network metrics for Android
instances (inst.is_android) but lack any visual cue; update the code that builds
cpuCell and memCell so when inst.is_android you append a short inline indicator
or tooltip (e.g., " (net TX)" / " (net RX)" or a span with title attribute) to
the displayed fmtNetBytes value, and ensure the same change is applied where
cpuCell/memCell are used (refer to variables cpuCell, memCell and the
inst.is_android branch); keep the existing formatting for non-Android instances.

In `@app/templates/fleet.html`:
- Around line 142-147: The fmtBytes function can produce "undefined B" or "null
B" for falsy non-zero inputs; update fmtBytes to defensively default b to 0
(e.g., treat b as (b || 0)) at the start of the function so it mirrors
fmtNetBytes behavior and never returns "undefined B", and then consider
extracting fmtBytes (and fmtNetBytes) into a shared utility to remove
duplication and keep formatting logic consistent across app/templates/fleet.html
and app/static/js/app.js.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: de118c8a-2260-4e6f-a36a-a641bda51266

📥 Commits

Reviewing files that changed from the base of the PR and between b52175a and f187a6f.

📒 Files selected for processing (3)
  • app/main.py
  • app/static/js/app.js
  • app/templates/fleet.html
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/main.py

GeiserX added 3 commits April 4, 2026 22:24
Workers are now identified by client_id (UNIQUE) instead of name.
Existing workers are migrated with client_id = name for backward
compat. The heartbeat accepts an optional client_id field; when
absent, name is used as fallback. This prevents two devices with the
same display name from overwriting each other's state.

Also adds 8 tests covering heartbeat identity, fleet summary
(online-only filtering, Android app counting, malformed JSON
resilience), and worker list (Android vs Docker counting).
- Migration now recreates the idx_workers_status index after table
  rebuild (was lost on upgraded installs)
- Log migration with _logger.info for observability
- Fleet summary reuses _parse_worker_json() instead of inline parsing
- fmtBytes() null-safe for undefined/zero values
Show ↑/↓ prefixes so it's clear the CPU/Memory columns display
network traffic for Android instances.
@GeiserX GeiserX merged commit 76a6daa into main Apr 4, 2026
4 of 5 checks passed
@GeiserX GeiserX deleted the feat/android-apps-display branch April 4, 2026 20:33
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