fix(print-modal): disable printers between dispatch-accept and PRINT_START

Reported off-list by a corporate supporter running a multi-operator
  farm shift. Backend already rejects double-sends with HTTP 409 (see
  background_dispatch._dispatch at lines 283-290), so no double-print
  was possible, but PrinterSelector consulted only PrinterStatus.state
  ({IDLE, FINISH, FAILED}) to decide whether a printer was selectable.
  PRINT_START is the only signal that flips the printer out of IDLE, so
  during the upload + print-command + firmware-ack window the card
  stayed clickable and operators only found out after submitting.

  New useDispatchedPrinterIds hook subscribes to the existing
  background-dispatch WebSocket event (already consumed for the toast
  overlay), collects printer_ids from dispatched_jobs + active_jobs,
  and exposes them via useSyncExternalStore so every PrinterSelector
  instance shares one snapshot. OR'd into isPrinterBusy; badge label
  flips to "Dispatching..." instead of a misleading "Idle".

  No backend change — the reservation already exists, the UI just
  didn't reflect it. No behaviour change for add-to-queue / edit-queue
  modes (disableBusy stays false for those).
This commit is contained in:
maziggy
2026-06-20 20:45:22 +02:00
parent a5fe5cb3d4
commit 37b9bbfaaf
6 changed files with 332 additions and 131 deletions
@@ -12,6 +12,7 @@ import {
Users,
} from 'lucide-react';
import { api, type PrinterStatus } from '../../api/client';
import { useDispatchedPrinterIds } from '../../hooks/useDispatchedPrinterIds';
import { getColorName } from '../../utils/colors';
import {
normalizeColorForCompare,
@@ -255,7 +256,14 @@ export function PrinterSelector({
return map;
}, [activePrinters, statusQueries]);
// Printers with a queued/active background dispatch — accepted by Bambuddy
// but not yet reflected in PrinterStatus.state (which only flips on
// PRINT_START from the printer itself). Backend rejects double-sends with
// 409 anyway; this just stops the operator from picking them in the modal.
const dispatchedPrinterIds = useDispatchedPrinterIds();
const isPrinterBusy = (printerId: number): boolean => {
if (dispatchedPrinterIds.has(printerId)) return true;
const status = printerStatusMap.get(printerId);
if (!status) return false; // Unknown state — don't block
if (!status.connected) return true;
@@ -263,6 +271,7 @@ export function PrinterSelector({
};
const getPrinterStateLabel = (printerId: number): string | null => {
if (dispatchedPrinterIds.has(printerId)) return 'Dispatching...';
const status = printerStatusMap.get(printerId);
if (!status) return null;
if (!status.connected) return 'Offline';