Kaynağa Gözat

fix(printers): Clear-Plate button delayed 30s–5min after print completes (#939 follow-up)

  PR #939 added the awaiting_plate_clear gate but stored it on
  PrinterManager, not on PrinterState. printer_state_to_dict() — which
  builds every WebSocket printer_status payload — never emitted the flag,
  so the frontend's WS merge preserved the stale false value. The only
  path that surfaced true was the 30s HTTP fallback poll, and incoming WS
  ticks kept bumping React Query's dataUpdatedAt, pushing the refetch out
  further on chatty printers.

  Emit awaiting_plate_clear from printer_state_to_dict by reading
  printer_manager.is_awaiting_plate_clear(printer_id) directly; returns
  False when no id is passed. No frontend change needed — the existing WS
  merge carries the flag end-to-end and the button now appears the instant
  the printer transitions to FINISH.

  Regression tests assert the WS dict always contains the key and surfaces
  True when the manager has the flag set for that printer_id.

  Affects every printer (A1/H2D/X1C) equally — transport-agnostic path.
maziggy 1 ay önce
ebeveyn
işleme
4e86e8c

Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
CHANGELOG.md


+ 4 - 0
backend/app/services/printer_manager.py

@@ -861,6 +861,10 @@ def printer_state_to_dict(state: PrinterState, printer_id: int | None = None, mo
         # current_archive_id is intentionally REST-only — it's stable for the life
         # of a print and needs a DB lookup the WebSocket path shouldn't pay for.
         "current_plate_id": parse_plate_id(state.gcode_file),
+        # Plate-clear gate (#939). Lives on the PrinterManager rather than PrinterState,
+        # so surface it here — without this, WebSocket merges drop the flag and the
+        # "Clear Plate" button only appears when the 30 s REST fallback poll runs.
+        "awaiting_plate_clear": printer_manager.is_awaiting_plate_clear(printer_id) if printer_id else False,
     }
     # Add cover URL if there's an active print and printer_id is provided
     # Include PAUSE state so skip objects modal can show cover

+ 20 - 0
backend/tests/unit/services/test_printer_manager.py

@@ -966,6 +966,26 @@ class TestPrinterStateToDict:
         assert tray["drying_temp"] == 55
         assert tray["drying_time"] == 240
 
+    def test_awaiting_plate_clear_defaults_false(self, mock_state):
+        """Without a printer_id, awaiting_plate_clear is False (no lookup possible)."""
+        result = printer_state_to_dict(mock_state)
+        assert result["awaiting_plate_clear"] is False
+
+    def test_awaiting_plate_clear_surfaced_when_set(self, mock_state):
+        """With printer_id, awaiting_plate_clear reflects PrinterManager state.
+
+        Regression: PR #939 left this flag off the WebSocket payload, so the
+        "Clear Plate" button only appeared after the 30 s REST fallback poll.
+        """
+        from backend.app.services.printer_manager import printer_manager
+
+        printer_manager.set_awaiting_plate_clear(12345, True)
+        try:
+            result = printer_state_to_dict(mock_state, printer_id=12345)
+            assert result["awaiting_plate_clear"] is True
+        finally:
+            printer_manager.set_awaiting_plate_clear(12345, False)
+
 
 class TestStatusKeyDryingDedup:
     """Regression tests for WebSocket dedup including drying fields.

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor