Skip to content

feat: power on/off machines in order of manufacture year#4

Merged
wpietri merged 2 commits intomainfrom
feat/power-order-by-year
Mar 24, 2026
Merged

feat: power on/off machines in order of manufacture year#4
wpietri merged 2 commits intomainfrom
feat/power-order-by-year

Conversation

@wpietri
Copy link
Copy Markdown
Contributor

@wpietri wpietri commented Mar 24, 2026

Summary

  • Fetch manufacture year from FlipFix API (model.year field)
  • All On / All Off now powers machines oldest-first (nulls first) instead of outlet order
  • All other behavior preserved: 2s delay for on, 1s for off, skip playing machines on off

Changes

  • juice/flipfix.pyget_machines() returns {asset_id: {name, year}}
  • juice/recorder.py — threads year through to RecorderState
  • juice/server.py — API includes year, JS sorts by it
  • Tests updated for new data format + new null/missing model cases

Test plan

  • CI passes
  • uv run pytest — 105 tests pass
  • Manual: All On powers oldest machine first, newest last

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Machine entries now include manufacturing year; dashboard "all on/off" sorts machines by year (oldest first).
  • Bug Fixes
    • Graceful handling of missing or null year values in machine data.
  • Tests
    • Updated and added tests to verify year handling (present, null, or missing) and assignment behavior.

Fetch manufacture year from FlipFix API and sort machines oldest-first
(nulls first) when using All On / All Off buttons.

- get_machines() now returns {asset_id: {name, year}} from FlipFix
- Year flows through recorder → state → API response
- allPower() JS sorts by year instead of outlet order

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 24, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f39a3ebf-ad86-48e0-ad55-52680dc2627a

📥 Commits

Reviewing files that changed from the base of the PR and between 7d73b6d and 30a05e5.

📒 Files selected for processing (2)
  • juice/flipfix.py
  • juice/recorder.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • juice/flipfix.py
  • juice/recorder.py

📝 Walkthrough

Walkthrough

The get_machines return shape changed from name strings to objects containing name and year; recorder and server code were updated to accept and propagate the new MachineInfo shape, assignments now store (name, asset_tag, year), and the dashboard sorts targets by year for all on/off actions.

Changes

Cohort / File(s) Summary
API Data Structure
juice/flipfix.py
Changed get_machines to return dict[str, MachineInfo] where `MachineInfo = TypedDict{name: str; year: int
Recorder Metadata
juice/recorder.py
Updated refresh_metadata signature to accept machines: dict[str, MachineInfo]; assignments now store a 3-tuple (name, asset_tag, year) and record uses the new machines shape.
Server State & UI Logic
juice/server.py
RecorderState.assignments updated to `dict[int, tuple[str, str, int
Tests
tests/test_flipfix.py, tests/test_recorder.py
Tests updated to expect MachineInfo objects; added tests for null year and missing model field; adjusted fixtures to use {"name": ..., "year": ...} mappings.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Dashboard
    participant Server as API Server
    participant Recorder as Recorder
    participant Flipfix as Flipfix API

    Client->>Server: Request machines / all-on-off
    Server->>Flipfix: get_machines(api_url, api_key)
    Flipfix-->>Server: dict[asset_id -> {name, year}]
    Server->>Recorder: refresh_metadata(account, store, machines)
    Recorder-->>Server: updated RecorderState.assignments (name, asset_tag, year)
    Server->>Client: Respond with machines list (sorted by year)
    Client->>Server: Toggle power for selected machines
    Server->>Recorder: apply toggles to assignments
    Recorder-->>Server: status updates
    Server-->>Client: operation result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through code, with a twiddle and cheer,
I tucked in the years so the machines keep them near.
Names now come dressed with a vintage or none,
I sort them by age and then hop off—job done!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% 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 PR title accurately reflects the main feature: sorting machines by manufacture year for power on/off operations, which is the central change across flipfix.py, recorder.py, and server.py.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/power-order-by-year

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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 (1)
juice/flipfix.py (1)

12-16: Consider a more specific return type annotation.

The return type dict[str, dict] is generic. For improved type safety with mypy, consider using a TypedDict:

💡 Optional: Use TypedDict for stronger typing
+from typing import TypedDict
+
+class MachineInfo(TypedDict):
+    name: str
+    year: int | None
+
-async def get_machines(api_url: str, api_key: str) -> dict[str, dict]:
+async def get_machines(api_url: str, api_key: str) -> dict[str, MachineInfo]:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@juice/flipfix.py` around lines 12 - 16, The return type of get_machines is
too generic (dict[str, dict])—define a TypedDict (e.g., MachineInfo with keys
"name": str and "year": int | None) and update get_machines' signature to return
dict[str, MachineInfo]; ensure any internal construction (in get_machines)
builds/returns objects matching MachineInfo so mypy can validate the structure.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@juice/flipfix.py`:
- Around line 12-16: The return type of get_machines is too generic (dict[str,
dict])—define a TypedDict (e.g., MachineInfo with keys "name": str and "year":
int | None) and update get_machines' signature to return dict[str, MachineInfo];
ensure any internal construction (in get_machines) builds/returns objects
matching MachineInfo so mypy can validate the structure.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8ec1d45c-1ace-475f-872e-eb148cf87fdb

📥 Commits

Reviewing files that changed from the base of the PR and between 1b9890d and 7d73b6d.

📒 Files selected for processing (5)
  • juice/flipfix.py
  • juice/recorder.py
  • juice/server.py
  • tests/test_flipfix.py
  • tests/test_recorder.py

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@wpietri wpietri merged commit a18c0be into main Mar 24, 2026
2 checks passed
@wpietri wpietri deleted the feat/power-order-by-year branch March 24, 2026 01:39
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