diff --git a/CHANGELOG.md b/CHANGELOG.md index 78f88b160..30e28715a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ All notable changes to Bambuddy will be documented in this file. - **Preheat & Heat Soak before queued prints — per-item override + per-filament chamber targets (#1468, reporter @embed-3d)** — New scheduler stage that heats the bed (and the chamber, on printers that support it) and holds at temperature before each queued print starts, intended for engineering filaments (PA, ABS) where adhesion and warp depend on a warm chamber. **Why it doesn't already work in the slicer.** BambuStudio / OrcaSlicer can emit `M191` (wait-for-chamber-temp) in start-G-code, but Bambu firmware silently ignores `M191`, so any "wait for chamber" line in the slicer's start sequence is a no-op. The reporter confirmed this by trying the [MakerWorld chamber-heating G-code](https://makerworld.com/de/models/1200262-g-code-for-x1c-chamber-heating-and-heat-soak) in OrcaSlicer and finding the chamber-heating step wouldn't fire. Implementing this at the orchestration layer — Bambuddy waiting on `state.temperatures` between FTP upload and `start_print` — is the right architectural place; the slicer side is a dead end. **Where it fires.** `print_scheduler._preheat_and_soak()`, called from `_start_print()` immediately before the FTP upload section (`print_scheduler.py:2306`-ish). Best-effort: any failure (printer drops, gcode refused, no bed temp in metadata) logs and returns rather than failing the queue item — the normal upload + start path runs straight after. **Hardware-tier behaviour (three branches; the OP collapsed two of them and we kept them distinct):** (1) Active chamber heater — `H2C / H2D / H2D Pro / H2S / X2D / X1E` (`supports_chamber_heater()` true) — dispatches `M141 Sx` for the configured target then polls `state.temperatures["chamber"]` against it. (2) Chamber sensor only — `X1C / P2S` (`supports_chamber_temp()` true but `supports_chamber_heater()` false) — no `M141`, polls the chamber sensor and considers the chamber phase satisfied when bed radiation has driven the sensor to target. Radiant warm-up to ABS-friendly temps on a cold X1C is 20-30 min — the `max_wait_seconds` cap (default 900 s, range 60-3600) is a hard ceiling so a cold room can't stall the queue indefinitely; falls through to the soak phase if the chamber never converges. (3) No chamber sensor — `P1S / P1P / A1 / A1 Mini` — no chamber wait possible (the `chamber_temper` value these models report is meaningless per `printer_manager.supports_chamber_temp`), so only the bed phase + soak timer apply. **Bed target** is read from the archive's parsed `bed_temperature` metadata (the same `bed_temperature_initial_layer` / `bed_temperature` field `archive.py:438` already extracts from the 3MF); if missing the preheat stage skips and logs rather than guessing a default that might wreck a non-PLA print. **Settings — Settings → Workflow → Queue & Dispatch → Preheat & Heat Soak card.** Master toggle (`preheat_enabled`, default off — disabled installs see no behavioural change), `preheat_chamber_target` (°C, 0-60, default 0 = chamber phase disabled; PA: 50, ABS: 45, PETG-CF: 40), `preheat_max_wait_seconds` (60-3600, default 900), `preheat_soak_seconds` (0-1800, default 300). The numeric fields auto-disable in the UI when the master toggle is off so they read as "config that's not currently doing anything." A static helper line under the inputs spells out the three hardware tiers so users don't have to consult the wiki to know what their printer will do. **Tests.** Eight new cases in `backend/tests/unit/test_scheduler_preheat.py`: disabled-setting skip (no M140 / M141 dispatched), no-bed-temp-in-archive skip, `H2D` dispatches both `M140` and `M141`, `X1C` dispatches only `M140` (the explicit chamber-sensor-but-no-heater regression guard — wiring this to `supports_chamber_temp()` alone would have falsely fired `M141` on the entire X1 family), `P1S` ignores its meaningless `chamber` reading and lets only the soak timer run, `preheat_chamber_target=0` keeps the bed phase but skips chamber even on a heater-capable printer, lost-client mid-flow returns silently, lost-state mid-wait exits the poll loop gracefully and still soaks. `asyncio.sleep` patched to `AsyncMock` so the soak phase doesn't actually wait — assertions are on what was scheduled, not wall-clock. 8/8 green. **Wiki.** `bambuddy-wiki/docs/features/monitoring.md` gains a new "Preheat & Heat Soak" subsection under the queue/scheduling area documenting the three hardware tiers and the four-setting interface, so users with X1C or P1S know upfront what the feature can and cannot do for their printer. **i18n.** 13 new keys × 11 locales (en/de/es/fr/it/ja/ko/pt-BR/tr/zh-CN/zh-TW), real translations everywhere — no English fallback. **Scope.** Backend (scheduler + schema + settings route) + frontend (settings card + AppSettings type) + tests + wiki. No DB migration (uses the existing key/value `Settings` table). No new permission (Settings → Workflow already gates on the same admin scope). The OP's "select option per print" UX is not part of this drop — preheat is a global default applied to every queued item that has a parseable bed temperature; per-queue-item override would need a `PrintQueueItem` schema migration plus print-modal and queue-modify UI work that would have widened the change beyond the scope agreed with the user. **Rework on user review.** First cut shipped a global-only design: one single `preheat_chamber_target` int in Settings → Workflow, no per-print override. User flagged two gaps on review: (1) you can't enable preheat for a single queue item, (2) different filaments need different chamber temps but the setting was a single value. Both are fair: PA needs 50, PETG-CF wants 40, PLA wants 0, but the global single-int forced one number across all of them. Reworked the data shape: replaced the single `preheat_chamber_target` int with `preheat_filament_targets` (JSON map of normalised filament type → °C, user-editable in the same card via the new `PreheatFilamentTargetsEditor` component) and added two columns to `PrintQueueItem` — `preheat_override` (`inherit` / `on` / `off`, default `inherit`) and `preheat_chamber_target_override` (nullable int, beats the filament-map derivation). The scheduler's resolution order: `item.preheat_override == 'off'` skips entirely; `'inherit'` falls back to the global `preheat_enabled` master toggle; `'on'` forces the stage even when the global is off. Chamber target: `item.preheat_chamber_target_override` (explicit °C) > max of `preheat_filament_targets[normalize(t.tray_type)]` across loaded AMS slots > 0. Mixed PA+PLA load picks PA's 50 (max-across-slots, NOT lowest-common-denominator — PA's chamber requirement is the binding constraint, PLA doesn't suffer from being warm). PLA-only prints derive 0 and skip the chamber phase automatically without the user touching anything. The per-print UI lives in `PrintModal`'s "Print Options" panel — tri-state segmented control (Inherit / On / Off) plus an optional chamber-target override input (shown only when override ≠ Off, blank = use filament map). Same control in edit-queue-item mode so you can flip preheat on an already-queued print. Tests grew from 8 cases to 15 across three categories — override resolution (3), chamber-target derivation (5), hardware-tier branching (5), plus 2 helper-fn tests — all green. DB migration added: `preheat_override VARCHAR(10) DEFAULT 'inherit'` and `preheat_chamber_target_override INTEGER NULL` on `print_queue`, idempotent via `_safe_execute`. Existing rows behave exactly as before (inherit + null = use global). i18n grew from 13 keys to 19 × 11 locales — real translations for the new override radio + per-filament editor strings, no English fallback. Frontend `PrintQueueItem` TS interface and `PrintQueueItemCreate` / `PrintQueueItemUpdate` shapes updated to carry the new fields end-to-end. **PrintOptions.tsx now uses `options[key as 'bed_levelling']` for the boolean rows since `options[key]` would type-error against the new non-boolean preheat keys** — minor TS-only adjustment, no behavioural change. **Airduct flap follows the resolved chamber target — bidirectional, idempotent.** Reported by user mid-test on H2D: preheat ran M141 for ABS but the cooling/heating airduct flap stayed in cooling, the open exhaust vent actively fought the heater and the chamber crawled toward target. The H-series (H2C/H2D/H2D Pro/H2S), X2D, and P2S all have a motorised flap with two modes: cooling (modeId=0, open exhaust, vents heat — right for PLA/PETG/TPU) and heating (modeId=1, closed exhaust, recirculates warm air — right for ABS/ASA/PC/PA). Bambu's firmware does **not** auto-switch the flap based on M141; whatever mode the user last left it in persists. So a PLA→ABS workflow inherits PLA's cooling-mode flap and the heater never wins; conversely an ABS→PLA workflow inherits ABS's heating-mode recirculation and runs PLA's chamber hot. **Fix.** New `supports_airduct(model)` helper in `printer_manager.py` mirrors the frontend whitelist (`P2S`, `X2D`, `H2C`, `H2D`, `H2D Pro`, `H2S` plus their internal codes). In `_preheat_and_soak`, after the bed dispatch and BEFORE the chamber M141: read the printer's current `state.airduct_mode`, derive the desired mode from the resolved chamber target (`chamber_target > 0` → heating, `chamber_target == 0` → cooling), and only fire `set_airduct_mode` when current ≠ desired. **The bidirectional switch is the load-bearing part** per Martin: when the resolved chamber target is 0 (PLA-only print, or per-item override disables chamber), the flap MUST switch to cooling even on a heater-capable printer that was previously running ABS, otherwise the closed-flap recirculation cooks PLA. The idempotency check (read `state.airduct_mode`, compare against desired before sending) keeps the flap motor from cycling needlessly when it's already where we want it. **Gating** is on `supports_airduct(model)` only — distinct from `supports_chamber_heater(model)`: X1E has a chamber heater but no flap (skipped), P2S has a flap but no active heater (still flipped, because even a passive-sensor printer benefits from the right airflow for its filament); the intersection that needs both is H2C/H2D/H2D Pro/H2S/X2D and they all work. **No post-print restoration** per Martin's preference — once a preheat sets the flap, it stays there for the print's duration (the print itself wants the same mode the preheat picked) and for any subsequent prints until the next preheat decision flips it. Best-effort: any `set_airduct_mode` failure logs and continues; M141 still fires regardless so a stuck flap doesn't kill the print. **Tests.** Four new cases in `test_scheduler_preheat.py`: `test_h2d_chamber_heat_switches_airduct_to_heating` (the OP scenario — cooling→heating before M141 for ABS), `test_h2d_chamber_zero_switches_airduct_to_cooling` (heating→cooling for a PLA print on a previously-warm flap), `test_h2d_airduct_already_correct_idempotent` (no command sent when current mode matches desired), `test_x1c_no_airduct_flap_never_fires_set_airduct` (gate regression guard — X1C has chamber sensor + chamber heater logic adjacent but no flap, must not leak the command). 21/21 in the file now. ### Fixed +- **P1S / P1P printer card no longer shows a bogus "Door Closed" badge (#1866, reporter @MartinNYHC)** — The enclosure-door badge in `frontend/src/pages/PrintersPage.tsx` gated visibility on a model whitelist that included `P1S` and `P1P`, but neither has a door sensor: P1S has an enclosure door with no hall sensor behind it, P1P has no enclosure at all. Backend `bambu_mqtt.py:2876-2907` unconditionally parses bit 23 of the `stat` field for every non-X1 model, and the bit stays 0 on P1S/P1P firmware — so the card rendered a permanent green "Door Closed" chip that couldn't reflect real state. **Fix.** Drop `P1S` and `P1P` from the frontend whitelist. Whitelist now reads `['X1C', 'X1', 'X1E', 'X2D', 'P2S', 'H2D', 'H2D Pro', 'H2C', 'H2S']` — the models that ship with a hall sensor for the door (and, on X1 family, top glass). Corrected the stale `X1/P1S/P2S/H2*` comment in `frontend/src/api/client.ts:473` (TypeScript `PrinterStatus` interface) and `backend/app/services/bambu_mqtt.py:295` (`PrinterState` dataclass) to match reality — those comments were what led the whitelist astray in the first place. Backend parsing left as-is: the bit read is cheap and if Bambu ever ships firmware that wires the P-series enclosure into a door sensor, the state gets picked up for free without a Bambuddy change. **Scope.** Two-line frontend whitelist change plus two comment corrections. No test change (no unit tests existed for the frontend gate). No i18n key change (`printers.door.open`/`printers.door.closed` still used for the models that keep the badge). No DB migration. No new permission. No backend behavioural change. + - **Bambu Cloud custom filament preset lookup restored — SpoolBuddy "Assign to AMS" now surfaces the real custom profile in BambuStudio (#1815, reporter @Bgabor997)** — Symptom: SpoolBuddy scans a tag for a spool whose slicer_filament is a Bambu Cloud user preset (PFUS-prefix, "PFUS12f68b29a18aa4" etc.), Bambuddy applies the assignment, and BambuStudio's AMS panel shows "Generic PETG" / "Generic PLA" instead of the user's custom profile. Manual AMS-card configure with the same profile worked. **Root cause.** `BambuCloudService.get_setting_detail` at `backend/app/services/bambu_cloud.py:393` hits `GET /v1/iot-service/api/slicer/setting/{setting_id}` without the `?version=XX.YY.ZZ.WW` query parameter — Bambu's API answers `HTTP 400 "field 'version' is not set"` for every call. The plural GET five methods above (`get_slicer_settings`, line 362) *does* send `params={"version": _SLICER_API_VERSION}` and the source comment at line 69-77 documents precisely this contract for the endpoint subtree; the singular GET and the sibling DELETE (`delete_setting`, line 545) were left uncovered when the `_SLICER_API_VERSION` placeholder landed in #1013's compliance rework 2026-05-12. `slicer_filament_resolver.resolve_slicer_filament` swallowed the 400 as a warning and fell through to `normalize_slicer_filament`; the caller in `inventory.py:146-165` then generic-material-fell-back tray_info_idx to `GFL99`/`GFG99`, and BambuStudio's AMS panel reads the printer's `tray_info_idx` echo → Generic. **Why nobody caught this in 50 days.** Two rescue paths mask the bug in 99% of real assigns: (1) if the target slot already carries a P-prefix filament_id from any prior configure, `current_tray_info_idx` reuse at `inventory.py:147-156` reuses it; (2) if the spool has a stored `spool_k_profile` matching a live `state.kprofiles` entry on the printer, `printer_kp.filament_id` realigns tray_info_idx at line 216-230 (`Spool assign: realigning tray_info_idx 'GFL99' → 'P…' (source=printer)`). Reporter's spool 54 → tray 2 assign at 2026-06-30 09:21:18 was the rare case with neither rescue — fresh spool, no prior K-profile calibration, slot didn't hold a valid P-prefix — and fell all the way to generic. Every other PFUS assign in his same log shipped a valid P-prefix. Owner reproduced the WARNING line in his own log on the H2D after a Reset-Slot + rescan cycle; his display was rescued by the K-profile realign path, not by cloud. **Fix.** `get_setting_detail` and `delete_setting` now both send `params={"version": _SLICER_API_VERSION}` — same neutral `"1.0.0.0"` placeholder the plural GET has always used (Bambu accepts any XX.YY.ZZ.WW value, doesn't validate against a release manifest, so no impersonation). Once cloud returns 200, the resolver reads `detail["filament_id"]` at line 108-113 and the P-prefix lands on tray_info_idx directly — no reliance on slot reuse or K-profile realign. The endpoint-subtree comment at line 69-77 updated to name the singular GET, DELETE, and POST variants explicitly so the next sibling method added to this class doesn't silently regress. `get_setting_detail` also includes the truncated response body in the raised `BambuCloudError` message, so a future contract change is self-diagnostic from support-bundle logs (this bug cost 50 days precisely because the error was an opaque `"400"`). **Adjacent surfaces that were also silently broken and are now fixed.** `preset_resolver.resolve_preset`'s cloud branch, `cloud.py`'s three UI-facing routes (`get_setting_detail` at `:534`, `import_setting` chain at `:784`, forecast at `:1120`), `cloud.py`'s delete-cloud-preset route (`:1016`), and internally `BambuCloudService.update_setting` at `:483` (which calls `get_setting_detail` then `delete_setting` then POSTs a replacement — every UI-driven edit of a cloud preset was 400ing at step 1). **Tests.** Three new cases in `TestSlicerSettingVersionParam` (`backend/tests/unit/services/test_bambu_cloud.py`) pinning the contract as a unit-testable invariant so the next sibling method can't silently omit the param: `test_get_setting_detail_sends_version_param` asserts `params.get("version")` is truthy on the GET call; `test_get_setting_detail_error_includes_response_body` pins the reporter's exact 400 body shape (`"field 'version' is not set"`) making it into the raised exception message; `test_delete_setting_sends_version_param` mirrors the invariant for DELETE. 26/26 in `test_bambu_cloud.py` (was 23 + 3 new). `ruff check backend/app/services/bambu_cloud.py backend/tests/unit/services/test_bambu_cloud.py` clean. **Scope.** Backend-only. Two API-call edits, one comment edit, three tests. No DB migration. No new permission. No frontend change. No new i18n key. Users on 0.2.5b1 and earlier who hit this: the fix takes effect on the next Bambuddy restart with no data migration required — reassigning the affected spool via SpoolBuddy after upgrade lands the correct tray_info_idx and the AMS panel in BambuStudio updates to the actual custom profile name. - **Cancel during queue dispatch actually cancels — no more "pressed cancel and the print started" (#1853, reporter @guy-blotnick)** — Symptom: user queued a batch of 10 print jobs of the same item across two P2S printers (Windows installation, v0.2.4.8), clicked Cancel on a pending row, and the print started anyway. Repeated consecutively. Support-bundle log scan reported 15× `sqlite3.OperationalError: database is locked` from the printer sensor history recorder in the same 8-minute window — a tell-tale that something was holding the SQLite WAL writer lock for the full 15 s `busy_timeout`. **Root cause (the race).** `_start_print()` in `backend/app/services/print_scheduler.py` carried a check-then-act window of several seconds between "scheduler's `check_queue` snapshotted this row as pending" and "scheduler sent the MQTT start_print command". The scheduler reads `item` via its session, then does FTP delete + FTP upload of the 3MF (5-30 s on a typical archive) before the unconditional `item.status = "printing"; await db.commit()` at line 2792. If the user pressed Cancel in that window, `/cancel` (a separate session) saw `status == 'pending'`, flipped to `cancelled`, and returned 200 — but the scheduler's stale in-memory write overwrote the cancellation in the very next commit. Then `printer_manager.start_print` shipped to the printer and the print commenced. The `cancel_queue_item` route at `print_queue.py:1245` correctly guards against late cancels (`status not in ("pending",)` → 400) but is useless if the scheduler races back to `pending → printing` AFTER the cancel commit. **Root cause (the lock contention amplifier).** `_start_print()` did `await db.flush()` at line 2555 immediately after writing `item.archive_id = archive.id` and `await db.delete(library_file)` (the library-file-to-archive promotion path) — `flush()` opens the SQLite write transaction but doesn't commit, holding the WAL writer lock through the FTP upload below. Every other writer in the process (sensor history task every 60 s, runtime tracking every 30 s, MQTT state UPDATEs from the live H2D/P2S, the user's own concurrent /cancel commits) blocks behind that lock for the full upload duration. With 15 s `busy_timeout` and FTP uploads regularly exceeding 15 s on larger 3MFs, the sensor history task hit its first lock error → logged + slept 60 s → next tick still blocked → repeat. The lock contention also widened the cancel-race window (the user's cancel commit was queued behind the scheduler's held write), making the race that much easier to lose. **Fix is three guards layered in defence-in-depth.** **(1) Atomic CAS at the pending→printing transition.** Replaced `item.status = "printing"; await db.commit()` with `UPDATE print_queue SET status='printing', started_at=NOW() WHERE id=:id AND status='pending'`. If `rowcount == 0` the user already won the race; log the abort, best-effort `delete_file_async` the file we just FTP'd up to the printer's SD card (no leftover that would surface in BambuStudio's file picker), send a `queue_item_failed{reason: "cancelled_mid_dispatch"}` WebSocket event so the user sees their cancel actually took effect, and return WITHOUT calling `printer_manager.start_print`. The in-memory `item.status` / `item.started_at` are synced from the CAS values so the rest of `_start_print` reads consistent state for notifications. **(2) Early refresh + bail before FTP I/O.** Right after the printer-connectivity check (~line 2487) the scheduler now `await db.refresh(item)` and returns early if `item.status != "pending"`. Saves the wasted 5-30 s FTP upload when the user cancelled BEFORE the scheduler tick reached this row (the snapshot is taken at the top of `check_queue` but iterated through serially; with 10 items in the batch the last item can be picked up minutes after the snapshot, by which time it may already be `cancelled`). Not load-bearing for correctness — guard (1) catches the same case at the CAS point — but cuts wasted FTP bandwidth, printer SD writes, and downstream cleanup work. **(3) `flush()` → `commit()` before FTP.** Replaced the `await db.flush()` at line 2555 with `await db.commit()` so the library-file-to-archive promotion's writes (`item.archive_id` set, `library_file` deleted) commit cleanly before the FTP block. SQLite WAL writer lock releases immediately; concurrent writers — the sensor history task, the user's /cancel commit, the MQTT UPDATE path — stop queueing behind the scheduler's session. The flush-not-commit pattern existed because the original code wanted to roll back the archive promotion if a later step failed, but `archive_service.archive_print()` (called four lines above) had already committed the `PrintArchive` row in its own session, so the rollback was only ever rolling back the `item.archive_id` pointer back to NULL — which doesn't actually undo the archive creation. The new behaviour matches reality: archive is created (committed), pointer is set (committed), FTP runs without writer-lock contention. Subsequent failure paths still mark the item as `failed` correctly; they don't try to un-create the archive. **Tests.** Three new cases in `backend/tests/unit/test_scheduler_cancel_race.py`: `test_cancel_during_ftp_upload_aborts_before_mqtt` simulates the headline scenario (cancel commits in a separate session inside `upload_file_async`'s mock side-effect, then the CAS sees rowcount==0 → `start_print` mock asserted not-called → row stays `cancelled` → `started_at` stays `None` → two `delete_file_async` calls, one pre-upload sweep and one post-CAS cleanup); `test_cancel_before_ftp_upload_skips_dispatch` mirrors the early-bail path (row pre-cancelled before `_start_print` runs → upload never awaited → `start_print` never called); `test_happy_path_still_dispatches` is the regression guard so the CAS doesn't accidentally block normal dispatch on a row that was always pending. 3/3 green + 140/140 in the wider scheduler suite (`test_scheduler_cleanup_library.py`, `test_scheduler_preheat.py`, `test_scheduler_dispatch_hold.py`, `test_scheduler_watchdog.py`, `test_scheduler_ams_mapping.py`) regression-clean. **Scope.** Backend-only. No DB migration. No schema change. No new permission. No new i18n key. No frontend change — the existing `queue_item_failed` WebSocket toast already renders for the new `cancelled_mid_dispatch` reason via its generic display path. The `database is locked` errors are addressed structurally by guard (3); a more invasive session-lifetime restructure inside `_start_print` was considered and deferred — flush→commit catches the dominant offender (library-file-promoted dispatches, which the OP's 10-item batch hits per copy) without widening the change beyond what #1853 needs. diff --git a/backend/app/services/bambu_mqtt.py b/backend/app/services/bambu_mqtt.py index c608828e2..0bc261d7f 100644 --- a/backend/app/services/bambu_mqtt.py +++ b/backend/app/services/bambu_mqtt.py @@ -292,7 +292,7 @@ class PrinterState: ipcam: bool = False # Live view / camera streaming enabled wifi_signal: int | None = None # WiFi signal strength in dBm wired_network: bool = False # Ethernet connection detected (home_flag bit 18) - door_open: bool = False # Enclosure door open (home_flag bit 23, X1/P1S/P2S/H2*) + door_open: bool = False # Enclosure door open (home_flag bit 23; models with a door sensor: X1/X1C/X1E/X2D/P2S/H2*) # Nozzle hardware info (for dual nozzle printers, index 0 = left, 1 = right) nozzles: list = field(default_factory=lambda: [NozzleInfo(), NozzleInfo()]) # AI detection and print options diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index bd3634137..598f1cac0 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -470,7 +470,7 @@ export interface PrinterStatus { ipcam: boolean; // Live view enabled wifi_signal: number | null; // WiFi signal strength in dBm wired_network: boolean; // Ethernet connection detected - door_open: boolean; // Enclosure door open (X1/P1S/P2S/H2*) + door_open: boolean; // Enclosure door open (models with a door sensor: X1/X1C/X1E/X2D/P2S/H2*) nozzles: NozzleInfo[]; // Nozzle hardware info (index 0=left/primary, 1=right) nozzle_rack: NozzleRackSlot[]; // H2C 6-nozzle tool-changer rack print_options: PrintOptions | null; // AI detection and print options diff --git a/frontend/src/pages/PrintersPage.tsx b/frontend/src/pages/PrintersPage.tsx index 82b513a5b..cea6f410e 100644 --- a/frontend/src/pages/PrintersPage.tsx +++ b/frontend/src/pages/PrintersPage.tsx @@ -3391,8 +3391,9 @@ function PrinterCard({ ) : null} - {/* Enclosure Door Badge (X1/X2D/P1S/P2S/H2*) */} - {status?.connected && ['X1C', 'X1', 'X1E', 'X2D', 'P1S', 'P1P', 'P2S', 'H2D', 'H2D Pro', 'H2C', 'H2S'].includes(printer.model ?? '') && ( + {/* Enclosure Door Badge — models with an actual door sensor. + P1S has an enclosure door but no sensor; P1P has no enclosure at all. */} + {status?.connected && ['X1C', 'X1', 'X1E', 'X2D', 'P2S', 'H2D', 'H2D Pro', 'H2C', 'H2S'].includes(printer.model ?? '') && ( i&&p(e.target.value),onKeyDown:e=>e.key===`Enter`&&E(),onFocus:()=>b(!0),onBlur:()=>{b(!1),C.current&&clearTimeout(C.current),C.current=setTimeout(()=>l(!1),200)},placeholder:i?s(`printers.amsPopup.friendlyNamePlaceholder`):r?.[e.id]||`—`,disabled:!i,title:i?void 0:s(`printers.amsPopup.noEditPermission`),className:`w-full bg-bambu-dark border border-bambu-dark-tertiary rounded px-2 py-1 text-xs text-white placeholder-bambu-gray/60 focus:outline-none focus:border-bambu-green disabled:opacity-50 disabled:cursor-not-allowed`,maxLength:100}),i&&(0,K.jsxs)(`div`,{className:`space-y-1`,children:[g&&(0,K.jsx)(`p`,{className:`text-[10px] text-red-400 break-words`,children:g}),(0,K.jsxs)(`div`,{className:`flex gap-1 justify-end`,children:[(0,K.jsx)(`button`,{onClick:E,disabled:m,className:`px-2 py-0.5 text-[10px] bg-bambu-green text-white rounded hover:bg-bambu-green/80 disabled:opacity-50`,children:s(`printers.amsPopup.save`)}),r?.[e.id]&&(0,K.jsx)(`button`,{onClick:async()=>{if(i){h(!0),_(null);try{await Q.deleteAmsLabel(t,e.id,e.serial_number),a(),l(!1)}catch(e){_(e instanceof Error?e.message:String(e))}finally{h(!1)}}},disabled:m,className:`px-2 py-0.5 text-[10px] bg-bambu-dark-tertiary text-bambu-gray rounded hover:bg-bambu-dark-tertiary/70 disabled:opacity-50`,children:s(`printers.amsPopup.clear`)})]})]})]})]})})]})}var kW={PLA:{n3f:45,n3s:45,n3f_hours:12,n3s_hours:12},PETG:{n3f:65,n3s:65,n3f_hours:12,n3s_hours:12},TPU:{n3f:65,n3s:75,n3f_hours:12,n3s_hours:18},ABS:{n3f:65,n3s:80,n3f_hours:12,n3s_hours:8},ASA:{n3f:65,n3s:80,n3f_hours:12,n3s_hours:8},PA:{n3f:65,n3s:85,n3f_hours:12,n3s_hours:12},PC:{n3f:65,n3s:80,n3f_hours:12,n3s_hours:8},PVA:{n3f:65,n3s:85,n3f_hours:12,n3s_hours:18}};function AW({printer:e,hideIfDisconnected:t,maintenanceInfo:n,viewMode:r=`expanded`,cardSize:i=2,amsThresholds:a,spoolmanEnabled:o=!1,linkedSpools:s,spoolmanUrl:c,spoolmanSyncMode:l,onGetAssignment:u,onUnassignSpool:d,spoolmanSpools:f,spoolmanSlotAssignments:p,spoolmanLoading:m=!1,onUnassignSpoolmanSpool:h,timeFormat:g=`system`,cameraViewMode:_=`window`,onOpenEmbeddedCamera:v,checkPrinterFirmware:b=!0,dryingPresets:x=kW,requirePlateClear:S=!1,selectionMode:C=!1,isSelected:w=!1,onToggleSelect:T,onOpenCompactCard:E,nozzleTempPresets:D=zp,bedTempPresets:O=Bp,chamberTempPresets:k=Vp,fanSpeedPresets:A=Hp}){let{t:j}=W(),M=no(),N=$n(),{showToast:P}=Dd(),{hasPermission:F}=pd(),[I,L]=(0,y.useState)(!1),[R,z]=(0,y.useState)(!1),[B,V]=(0,y.useState)(!0),[ee,te]=(0,y.useState)(!1),[ne,re]=(0,y.useState)(!1),[ie,H]=(0,y.useState)(!1),[ae,oe]=(0,y.useState)(!1),[U,se]=(0,y.useState)(!1),[ce,le]=(0,y.useState)(null),[ue,de]=(0,y.useState)(!1),[fe,pe]=(0,y.useState)(!1),[me,he]=(0,y.useState)(!1),[ge,_e]=(0,y.useState)(!1),[ve,ye]=(0,y.useState)(null),[be,xe]=(0,y.useState)(null),[Se,Ce]=(0,y.useState)(null),[we,Te]=(0,y.useState)(null),[Ee,De]=(0,y.useState)(10),[Oe,ke]=(0,y.useState)(null),[Ae,je]=(0,y.useState)(!1),[Me,Ne]=(0,y.useState)(!1),[Pe,Fe]=(0,y.useState)(!1),[Ie,Le]=(0,y.useState)(!1),[Re,ze]=(0,y.useState)(!1),Be=(0,y.useCallback)(()=>Le(!1),[]),[Ve,He]=(0,y.useState)(null),[Ue,We]=(0,y.useState)(null),[Ge,Ke]=(0,y.useState)(`n3f`),[qe,Je]=(0,y.useState)(`PLA`),[Ye,Xe]=(0,y.useState)(50),[Ze,Qe]=(0,y.useState)(4),[$e,et]=(0,y.useState)(!1),[tt,nt]=(0,y.useState)(null),[rt,it]=(0,y.useState)(!1),[at,ot]=(0,y.useState)(!1),st=(0,y.useRef)(null),ct=(0,y.useRef)(0),[lt,ut]=(0,y.useState)(null),[dt,ft]=(0,y.useState)(null),[pt,mt]=(0,y.useState)(null),[ht,gt]=(0,y.useState)(null),[_t,vt]=(0,y.useState)(null),[yt,bt]=(0,y.useState)(!1),[xt,St]=(0,y.useState)(null),[Ct,wt]=(0,y.useState)(!1),[Tt,Et]=(0,y.useState)(!1),[Dt,Ot]=(0,y.useState)(null),[kt,At]=(0,y.useState)(!1),[jt,Mt]=(0,y.useState)(!1),{data:G}=q({queryKey:[`printerStatus`,e.id],queryFn:()=>Q.getPrinterStatus(e.id),refetchInterval:3e4}),{data:Nt}=q({queryKey:[`firmwareUpdate`,e.id],queryFn:()=>od.checkPrinterUpdate(e.id),staleTime:300*1e3,refetchInterval:300*1e3,enabled:b&&F(`firmware:read`)}),Pt=(0,y.useMemo)(()=>{let e=new Set;if(G?.ams)for(let t of G.ams)for(let n of t.tray||[])n.tray_info_idx&&e.add(n.tray_info_idx);for(let t of G?.vt_tray??[])t.tray_info_idx&&e.add(t.tray_info_idx);if(G?.nozzle_rack)for(let t of G.nozzle_rack)t.filament_id&&e.add(t.filament_id);return Array.from(e)},[G?.ams,G?.vt_tray,G?.nozzle_rack]),Ft=(0,y.useMemo)(()=>{let e=new Set;if(G?.ams)for(let t of G.ams)for(let n of t.tray||[])n.tray_type&&e.add(n.tray_type.toUpperCase());for(let t of G?.vt_tray??[])t.tray_type&&e.add(t.tray_type.toUpperCase());return e},[G?.ams,G?.vt_tray]),It=(0,y.useMemo)(()=>{let e=new Set;if(G?.ams){for(let t of G.ams)for(let n of t.tray||[])if(n.tray_type&&n.tray_color){let t=n.tray_color.replace(`#`,``).toLowerCase().slice(0,6);e.add(`${n.tray_type.toUpperCase()}:${t}`)}}for(let t of G?.vt_tray??[])if(t.tray_type&&t.tray_color){let n=t.tray_color.replace(`#`,``).toLowerCase().slice(0,6);e.add(`${t.tray_type.toUpperCase()}:${n}`)}return e},[G?.ams,G?.vt_tray]),{data:Lt}=q({queryKey:[`filamentInfo`,Pt],queryFn:()=>Q.getFilamentInfo(Pt),enabled:Pt.length>0,staleTime:300*1e3}),{data:Rt}=q({queryKey:[`slotPresets`,e.id],queryFn:()=>Q.getSlotPresets(e.id),staleTime:120*1e3}),zt=G?.state===`RUNNING`||G?.state===`PAUSE`?G?.current_archive_id??null:null,{data:Bt}=q({queryKey:[`archive-plates`,zt],queryFn:()=>Q.getArchivePlates(zt),enabled:zt!=null,staleTime:300*1e3}),Vt=!Bt?.is_multi_plate||G?.current_plate_id==null?null:Bt.plates.find(e=>e.index===G.current_plate_id)?.name||j(`printers.plateNumber`,`Plate {{number}}`,{number:G.current_plate_id}),{data:Ht,refetch:Ut}=q({queryKey:[`amsLabels`,e.id],queryFn:()=>Q.getAmsLabels(e.id),staleTime:300*1e3}),[Wt,Gt]=(0,y.useState)(null);(0,y.useEffect)(()=>{G?.wifi_signal!=null&&Gt(G.wifi_signal)},[G?.wifi_signal]);let Kt=G?.wifi_signal??Wt,qt=(0,y.useRef)(void 0);(0,y.useEffect)(()=>{G?.connected!==void 0&&(qt.current=G.connected)},[G?.connected]);let Jt=G?.connected??qt.current,Yt=(0,y.useRef)({});(0,y.useEffect)(()=>{G?.ams_extruder_map&&Object.keys(G.ams_extruder_map).length>0&&(Yt.current=G.ams_extruder_map)},[G?.ams_extruder_map]);let Xt=G?.ams_extruder_map&&Object.keys(G.ams_extruder_map).length>0?G.ams_extruder_map:Yt.current,Zt=(0,y.useRef)([]);(0,y.useEffect)(()=>{G?.ams&&G.ams.length>0&&(Zt.current=G.ams)},[G?.ams]);let Qt=G?.ams&&G.ams.length>0?G.ams:Zt.current,$t=(0,y.useRef)(void 0),en=G?.tray_now;en!==void 0&&en!==255?$t.current=en:en===255&&($t.current=void 0);let tn=en!==void 0&&en!==255?en:$t.current,{data:nn}=q({queryKey:[`smartPlugByPrinter`,e.id],queryFn:()=>Q.getSmartPlugByPrinter(e.id)}),{data:rn}=q({queryKey:[`scriptPlugsByPrinter`,e.id],queryFn:()=>Q.getScriptPlugsByPrinter(e.id)}),{data:an}=q({queryKey:[`smartPlugStatus`,nn?.id],queryFn:()=>nn?Q.getSmartPlugStatus(nn.id):null,enabled:!!nn,refetchInterval:1e4}),{data:on}=q({queryKey:[`queue`,e.id,`pending`],queryFn:()=>Q.getQueue(e.id,`pending`)}),sn=(0,y.useMemo)(()=>on?.length?ST(on,Ft,It).length:0,[on,Ft,It]),{data:cn}=q({queryKey:[`queue`,e.id,`printing`],queryFn:()=>Q.getQueue(e.id,`printing`),enabled:G?.state===`RUNNING`}),{data:ln}=q({queryKey:[`currentPrintUser`,e.id],queryFn:()=>Q.getCurrentPrintUser(e.id),enabled:G?.state===`RUNNING`}),un=cn?.[0]?.created_by_username||ln?.username,{data:dn}=q({queryKey:[`archives`,e.id,`last`],queryFn:()=>Q.getArchives(e.id,1,0),enabled:G?.connected&&G?.state!==`RUNNING`}),fn=dn?.[0],pn=G?.state===`RUNNING`||G?.state===`PAUSE`,mn=S&&G?.awaiting_plate_clear===!0,hn=G?.connected&&mn&&!pn,gn=G?.current_print&&pn?Lp(G.subtask_name||G.current_print||null,G.gcode_file,j,Vt):null,[_n,vn]=(0,y.useState)(null);(0,y.useEffect)(()=>{gn?vn({name:gn,coverUrl:G?.cover_url??null}):mn||vn(null)},[gn,mn,G?.cover_url]);let yn=!S||!G?.connected?null:pn?{label:j(`printers.plateStatus.inUse`),className:`bg-blue-500/20 text-blue-400`}:G.awaiting_plate_clear?{label:j(`printers.plateStatus.notCleared`),className:`bg-yellow-500/20 text-yellow-400`}:{label:j(`printers.plateStatus.cleared`),className:`bg-status-ok/20 text-status-ok`},bn=yn?(0,K.jsx)(`span`,{className:`inline-flex flex-shrink-0 items-center rounded-full px-2 py-0.5 text-[10px] font-medium ${yn.className}`,children:yn.label}):null,xn=t&&Jt===!1,Sn=J({mutationFn:t=>Q.deletePrinter(e.id,t.deleteArchives),onSuccess:()=>{M.invalidateQueries({queryKey:[`printers`]}),M.invalidateQueries({queryKey:[`archives`]}),M.invalidateQueries({queryKey:[`maintenanceOverview`]})},onError:e=>P(e.message||j(`printers.toast.failedToDelete`),`error`)}),Cn=J({mutationFn:()=>Q.connectPrinter(e.id),onSuccess:()=>{M.invalidateQueries({queryKey:[`printerStatus`,e.id]})}}),wn=J({mutationFn:()=>Q.refreshPrinterStatus(e.id),onSuccess:()=>{M.invalidateQueries({queryKey:[`printerStatus`,e.id]}),P(j(`printers.forceRefreshSuccess`),`success`)},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),Tn=J({mutationFn:e=>Q.unlinkSpool(e),onSuccess:e=>{P(j(`spoolman.unlinkSuccess`)||e?.message,`success`),M.invalidateQueries({queryKey:[`linked-spools`]}),M.invalidateQueries({queryKey:[`unlinked-spools`]}),M.invalidateQueries({queryKey:[`spoolman-slot-assignments`]})},onError:e=>{P(e.message||j(`spoolman.unlinkFailed`),`error`)}}),En=J({mutationFn:({amsId:t,temp:n,duration:r,filament:i,rotateTray:a})=>Q.startDrying(e.id,t,n,r,i,a),onSuccess:()=>{We(null),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),Dn=J({mutationFn:t=>Q.stopDrying(e.id,t),onSuccess:()=>{M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),On=J({mutationFn:t=>Q.setAmsFilamentBackup(e.id,t),onSuccess:(t,n)=>{M.invalidateQueries({queryKey:[`printerStatus`,e.id]}),M.invalidateQueries({queryKey:[`printer-status`,e.id]}),P(j(n?`printers.amsBackup.toastEnabled`:`printers.amsBackup.toastDisabled`),`success`)},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),kn=J({mutationFn:e=>nn?Q.controlSmartPlug(nn.id,e):Promise.reject(`No plug`),onSuccess:()=>{M.invalidateQueries({queryKey:[`smartPlugStatus`,nn?.id]})}}),An=J({mutationFn:e=>nn?Q.updateSmartPlug(nn.id,{auto_off:e}):Promise.reject(`No plug`),onSuccess:()=>{M.invalidateQueries({queryKey:[`smartPlugByPrinter`,e.id]}),M.invalidateQueries({queryKey:[`smart-plugs`]})}}),jn=J({mutationFn:({id:e,action:t})=>Q.controlSmartPlug(e,t),onSuccess:()=>{P(j(`printers.toast.scriptTriggered`))},onError:e=>P(e.message||j(`printers.toast.failedToRunScript`),`error`)}),Mn=J({mutationFn:()=>Q.stopPrint(e.id),onSuccess:()=>{P(j(`printers.toast.printStopped`)),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToStopPrint`),`error`)}),Nn=J({mutationFn:()=>Q.pausePrint(e.id),onSuccess:()=>{P(j(`printers.toast.printPaused`)),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToPausePrint`),`error`)}),Pn=J({mutationFn:()=>Q.resumePrint(e.id),onSuccess:()=>{P(j(`printers.toast.printResumed`)),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToResumePrint`),`error`)}),Fn=J({mutationFn:()=>Q.clearPlate(e.id),onSuccess:()=>{P(j(`queue.clearPlateSuccess`)),M.setQueryData([`printerStatus`,e.id],e=>e&&{...e,awaiting_plate_clear:!1}),M.invalidateQueries({queryKey:[`printerStatus`,e.id]}),M.invalidateQueries({queryKey:[`queue`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),In=J({mutationFn:({target:t,nozzle:n})=>Q.setNozzleTemperature(e.id,t,n),onSuccess:t=>{Te(null),P(t.message),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),Ln=J({mutationFn:t=>Q.setBedTemperature(e.id,t),onSuccess:t=>{Te(null),P(t.message),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),Rn=J({mutationFn:t=>Q.setChamberTemperature(e.id,t),onSuccess:t=>{Te(null),P(t.message),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),zn=J({mutationFn:({fan:t,speed:n})=>Q.setFanSpeed(e.id,t,n),onMutate:async({fan:t,speed:n})=>{await M.cancelQueries({queryKey:[`printerStatus`,e.id]});let r=M.getQueryData([`printerStatus`,e.id]),i={part:`cooling_fan_speed`,aux:`big_fan1_speed`,chamber:`big_fan2_speed`}[t];return M.setQueryData([`printerStatus`,e.id],e=>e&&{...e,[i]:n}),{previousStatus:r}},onSuccess:t=>{Te(null),P(t.message),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:(t,n,r)=>{r?.previousStatus&&M.setQueryData([`printerStatus`,e.id],r.previousStatus),P(t.message||j(`printers.toast.failedToSendCommand`),`error`)}}),Bn=J({mutationFn:t=>Q.selectExtruder(e.id,t),onMutate:async t=>{await M.cancelQueries({queryKey:[`printerStatus`,e.id]});let n=M.getQueryData([`printerStatus`,e.id]);return M.setQueryData([`printerStatus`,e.id],e=>e&&{...e,active_extruder:t}),{previousStatus:n}},onSuccess:t=>{Te(null),P(t.message),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:(t,n,r)=>{r?.previousStatus&&M.setQueryData([`printerStatus`,e.id],r.previousStatus),P(t.message||j(`printers.toast.failedToSendCommand`),`error`)}}),Vn=J({mutationFn:t=>Q.setChamberLight(e.id,t),onMutate:async t=>{await M.cancelQueries({queryKey:[`printerStatus`,e.id]});let n=M.getQueryData([`printerStatus`,e.id]);return M.setQueryData([`printerStatus`,e.id],e=>({...e,chamber_light:t})),{previousStatus:n}},onSuccess:(e,t)=>{P(`Chamber light ${t?`on`:`off`}`)},onError:(t,n,r)=>{r?.previousStatus&&M.setQueryData([`printerStatus`,e.id],r.previousStatus),P(t.message||j(`printers.toast.failedToControlChamberLight`),`error`)}}),Hn=J({mutationFn:t=>Q.setPrintSpeed(e.id,t),onMutate:async t=>{await M.cancelQueries({queryKey:[`printerStatus`,e.id]});let n=M.getQueryData([`printerStatus`,e.id]);return M.setQueryData([`printerStatus`,e.id],e=>({...e,speed_level:t})),{previousStatus:n}},onError:(t,n,r)=>{r?.previousStatus&&M.setQueryData([`printerStatus`,e.id],r.previousStatus),P(t.message||j(`printers.toast.failedToSetSpeed`),`error`)}}),Un=J({mutationFn:t=>Q.setAirductMode(e.id,t),onMutate:async t=>{await M.cancelQueries({queryKey:[`printerStatus`,e.id]});let n=M.getQueryData([`printerStatus`,e.id]);return M.setQueryData([`printerStatus`,e.id],e=>({...e,airduct_mode:t===`cooling`?0:1})),{previousStatus:n}},onError:(t,n,r)=>{r?.previousStatus&&M.setQueryData([`printerStatus`,e.id],r.previousStatus),P(t.message||j(`printers.toast.failedToSendCommand`),`error`)}}),Wn=J({mutationFn:({distance:t,force:n})=>Q.bedJog(e.id,t,n??!1),onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),Gn=J({mutationFn:({x:t,y:n})=>Q.xyJog(e.id,t,n),onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),Kn=J({mutationFn:t=>Q.extruderJog(e.id,t),onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),qn=J({mutationFn:t=>Q.homeAxes(e.id,t),onSuccess:()=>{try{sessionStorage.setItem(`bambuddy.bedJog.warned.${e.id}`,`1`)}catch{}P(j(`printers.bedJog.homingStarted`))},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),Jn=J({mutationFn:t=>Q.updatePrinter(e.id,{plate_detection_enabled:t}),onSuccess:()=>{M.invalidateQueries({queryKey:[`printers`]}),P(Jn.variables?j(`printers.toast.plateCheckEnabled`):j(`printers.toast.plateCheckDisabled`))},onError:e=>P(e.message||j(`printers.toast.failedToUpdateSetting`),`error`)}),Yn=J({mutationFn:t=>Q.updatePrinter(e.id,{is_active:t}),onSuccess:(t,n)=>{M.invalidateQueries({queryKey:[`printers`]}),M.invalidateQueries({queryKey:[`printerStatus`,e.id]}),P(j(n?`printers.maintenance.toastExited`:`printers.maintenance.toastEntered`,{name:e.name}),`success`)},onError:e=>P(e.message||j(`printers.toast.failedToUpdateSetting`),`error`)}),[Xn,Zn]=(0,y.useState)(!1),Qn=()=>{G?.state===`RUNNING`||G?.state===`PAUSE`?Zn(!0):Yn.mutate(!1)},er=(G?.state===`RUNNING`||G?.state===`PAUSE`)&&(G?.printable_objects_count??0)>=2,{data:tr}=q({queryKey:[`printableObjects`,e.id],queryFn:()=>Q.getPrintableObjects(e.id),enabled:Me||er,refetchInterval:Me?5e3:er?3e4:!1}),[nr,rr]=(0,y.useState)(null),ir=(0,y.useRef)(!1),ar=(0,y.useRef)(null),or=(0,y.useRef)(!1),sr=J({mutationFn:({amsId:t,slotId:n})=>Q.refreshAmsSlot(e.id,t,n),onMutate:({amsId:e,slotId:t})=>{ar.current&&clearTimeout(ar.current),ir.current=!1,or.current=!1,rr({amsId:e,slotId:t}),setTimeout(()=>{or.current=!0},2e3),ar.current=setTimeout(()=>{rr(null)},3e4)},onSuccess:e=>{P(e.message||j(`printers.toast.rfidRereadInitiated`))},onError:e=>{P(e.message||j(`printers.toast.failedToRereadRfid`),`error`),ar.current&&clearTimeout(ar.current),rr(null)}}),cr=J({mutationFn:({trayId:t})=>Q.loadAmsTray(e.id,t),onSuccess:e=>{P(e.message||j(`printers.toast.loadInitiated`))},onError:e=>{P(e.message||j(`printers.toast.failedToLoad`),`error`)}}),lr=J({mutationFn:()=>Q.unloadAms(e.id),onSuccess:e=>{P(e.message||j(`printers.toast.unloadInitiated`))},onError:e=>{P(e.message||j(`printers.toast.failedToUnload`),`error`)}}),[ur,dr]=(0,y.useState)(null),[fr,pr]=(0,y.useState)(null),mr=async()=>{try{dr(await Q.getPlateReferences(e.id))}catch{}},hr=()=>{Jn.mutate(!e.plate_detection_enabled)},gr=async()=>{wt(!0),St(null);let t=G?.chamber_light===!1;Mt(t),t&&(await Q.setChamberLight(e.id,!0),await new Promise(e=>setTimeout(e,2500)));try{St(await Q.checkPlateEmpty(e.id,{includeDebugImage:!0})),mr()}catch(n){P(n instanceof Error?n.message:j(`printers.toast.failedToCheckPlate`),`error`),t&&(await Q.setChamberLight(e.id,!1),Mt(!1))}finally{wt(!1)}},_r=(0,y.useCallback)(async()=>{St(null),jt&&(await Q.setChamberLight(e.id,!1),Mt(!1))},[jt,e.id]),vr=async t=>{Et(!0);try{let n=await Q.calibratePlateDetection(e.id,{label:t});n.success?(P(n.message||j(`printers.toast.calibrationSaved`),`success`),mr(),St(await Q.checkPlateEmpty(e.id,{includeDebugImage:!0}))):P(n.message||j(`printers.toast.calibrationFailed`),`error`)}catch(e){P(e instanceof Error?e.message:j(`printers.toast.calibrationFailed`),`error`)}finally{Et(!1)}},yr=async(t,n)=>{try{await Q.updatePlateReferenceLabel(e.id,t,n),pr(null),mr()}catch(e){P(e instanceof Error?e.message:j(`printers.toast.failedToUpdateLabel`),`error`)}},br=async t=>{try{await Q.deletePlateReference(e.id,t),P(j(`printers.toast.referenceDeleted`),`success`),mr(),St(await Q.checkPlateEmpty(e.id,{includeDebugImage:!0}))}catch(e){P(e instanceof Error?e.message:j(`printers.toast.failedToDeleteReference`),`error`)}},xr=async()=>{if(Dt){At(!0);try{await Q.updatePrinter(e.id,{plate_detection_roi:Dt}),P(j(`printers.toast.detectionAreaSaved`),`success`),Ot(null),St(await Q.checkPlateEmpty(e.id,{includeDebugImage:!0}))}catch(e){P(e instanceof Error?e.message:j(`printers.toast.failedToSaveDetectionArea`),`error`)}finally{At(!1)}}};(0,y.useEffect)(()=>{let e=e=>{e.key===`Escape`&&xt&&_r()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[xt,_r]);let Sr=(0,y.useRef)(null);if((0,y.useEffect)(()=>{if(!nr)return;let e=G?.ams_status_main??0;return e!==0&&(ir.current=!0,Sr.current&&=(clearTimeout(Sr.current),null)),ir.current&&e===0&&(or.current?(ar.current&&clearTimeout(ar.current),rr(null)):Sr.current||=setTimeout(()=>{ar.current&&clearTimeout(ar.current),rr(null)},2e3)),()=>{Sr.current&&clearTimeout(Sr.current)}},[G?.ams_status_main,nr]),(0,y.useEffect)(()=>{if(!I)return;let e=e=>{let t=e.target;st.current?.contains(t)||L(!1)};return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[I]),xn)return null;let Cr=()=>{switch(i){case 1:return`w-10 h-10`;case 2:return`w-14 h-14`;case 3:return`w-16 h-16`;case 4:return`w-20 h-20`;default:return`w-14 h-14`}},wr=()=>{switch(i){case 1:return`text-base truncate`;case 2:return`text-lg`;case 3:return`text-xl`;case 4:return`text-2xl`;default:return`text-lg`}},Tr=()=>{switch(i){case 1:return`mb-2`;case 2:return`mb-4`;case 3:return`mb-5`;case 4:return`mb-6`;default:return`mb-4`}},Er=Jt&&G?.state!==`RUNNING`&&G?.state!==`PAUSE`&&F(`printers:control`),Dr=e=>{e.preventDefault(),ct.current++,ct.current===1&&it(!0)},Or=e=>{e.preventDefault(),e.dataTransfer.dropEffect=Er?`copy`:`none`},kr=e=>{e.preventDefault(),ct.current--,ct.current===0&&it(!1)},Ar=async t=>{if(t.preventDefault(),ct.current=0,it(!1),!Er)return;let n=Array.from(t.dataTransfer.files)[0];if(!n)return;let r=n.name.toLowerCase();if(!r.endsWith(`.gcode`)&&!r.includes(`.gcode.`)){P(j(`printers.dropNotPrintable`,`Only .gcode and .gcode.3mf files can be printed`),`error`);return}ot(!0);try{let t=await Q.uploadLibraryFile(n,null),r=t.metadata?.sliced_for_model,i=DW(e.model);if(r&&i&&r.toLowerCase()!==i.toLowerCase()){await Q.deleteLibraryFile(t.id).catch(()=>{}),P(j(`printers.incompatibleFile`,`This file was sliced for {{slicedFor}}, but this printer is a {{printerModel}}`,{slicedFor:r,printerModel:i}),`error`);return}He({id:t.id,filename:t.filename})}catch{P(j(`common.uploadFailed`,`Upload failed`),`error`)}finally{ot(!1)}},jr=t=>{r!==`compact`||C||t.target.closest(`button, a, input, select, textarea, [role="button"]`)||E?.(e.id)},Mr=`!h-8 !min-h-8 !w-8 !px-0 !py-0`,Nr=({amsId:e,slotId:t,loadTrayId:n,isRefreshing:r,includeRfid:i=!0})=>{let a=G?.state===`RUNNING`;return(0,K.jsxs)(K.Fragment,{children:[i&&(0,K.jsxs)(`button`,{className:`w-full px-2 py-1.5 text-left text-xs flex items-center gap-2 rounded transition-colors ${F(`printers:ams_rfid`)?`text-white hover:bg-bambu-dark-tertiary`:`text-bambu-gray/50 cursor-not-allowed`}`,onClick:n=>{n.stopPropagation(),!(a||!F(`printers:ams_rfid`))&&sr.mutate({amsId:e,slotId:t})},disabled:a||r||!F(`printers:ams_rfid`),title:a?j(`printers.bedJog.disabledWhilePrinting`):F(`printers:ams_rfid`)?void 0:j(`printers.permission.noAmsRfid`),children:[(0,K.jsx)(Dl,{className:`w-3 h-3 ${r?`animate-spin`:``}`}),j(`printers.rfid.reread`)]}),(0,K.jsxs)(`button`,{className:`w-full px-2 py-1.5 text-left text-xs flex items-center gap-2 rounded transition-colors ${F(`printers:control`)?`text-white hover:bg-bambu-dark-tertiary`:`text-bambu-gray/50 cursor-not-allowed`}`,onClick:e=>{e.stopPropagation(),!(a||!F(`printers:control`))&&cr.mutate({trayId:n})},disabled:a||!F(`printers:control`),title:a?j(`printers.bedJog.disabledWhilePrinting`):F(`printers:control`)?void 0:j(`printers.permission.noControl`),children:[(0,K.jsx)(qc,{className:`w-3 h-3`}),j(`printers.ams.load`)]}),(0,K.jsxs)(`button`,{className:`w-full px-2 py-1.5 text-left text-xs flex items-center gap-2 rounded transition-colors ${F(`printers:control`)?`text-white hover:bg-bambu-dark-tertiary`:`text-bambu-gray/50 cursor-not-allowed`}`,onClick:e=>{e.stopPropagation(),!(a||!F(`printers:control`))&&lr.mutate()},disabled:a||!F(`printers:control`),title:a?j(`printers.bedJog.disabledWhilePrinting`):F(`printers:control`)?void 0:j(`printers.permission.noControl`),children:[(0,K.jsx)(Jc,{className:`w-3 h-3`}),j(`printers.ams.unload`)]})]})},Pr=(0,K.jsxs)(`div`,{ref:st,className:`relative flex-shrink-0`,children:[(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>L(!I),title:j(`common.more`,`More`),className:Mr,children:(0,K.jsx)(Us,{className:`w-4 h-4`})}),I&&(0,K.jsxs)(`div`,{className:`absolute left-0 bottom-full mb-2 w-48 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-lg z-20`,children:[(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-sm flex items-center gap-2 ${F(`printers:update`)?`hover:bg-bambu-dark-tertiary`:`opacity-50 cursor-not-allowed`}`,onClick:()=>{F(`printers:update`)&&(te(!0),L(!1))},title:F(`printers:update`)?void 0:j(`printers.permission.noEdit`),children:[(0,K.jsx)(_l,{className:`w-4 h-4`}),j(`common.edit`)]}),(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-sm hover:bg-bambu-dark-tertiary flex items-center gap-2`,onClick:()=>{Le(!0),L(!1)},children:[(0,K.jsx)(Nc,{className:`w-4 h-4`}),j(`printers.printerInformation`)]}),(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-sm flex items-center gap-2 ${F(`printers:update`)?`hover:bg-bambu-dark-tertiary`:`opacity-50 cursor-not-allowed`}`,disabled:Yn.isPending||!F(`printers:update`),onClick:()=>{F(`printers:update`)&&(L(!1),e.is_active===!1?Yn.mutate(!0):Qn())},title:F(`printers:update`)?void 0:j(`printers.permission.noEdit`),children:[(0,K.jsx)(zu,{className:`w-4 h-4`}),e.is_active===!1?j(`printers.maintenance.menuExit`):j(`printers.maintenance.menuEnter`)]}),(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-sm hover:bg-bambu-dark-tertiary flex items-center gap-2`,onClick:()=>{Cn.mutate(),L(!1)},children:[(0,K.jsx)(Dl,{className:`w-4 h-4`}),j(`printers.reconnect`)]}),(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-sm hover:bg-bambu-dark-tertiary flex items-center gap-2 disabled:opacity-50`,disabled:wn.isPending,onClick:()=>{wn.mutate(),L(!1)},children:[(0,K.jsx)(Al,{className:`w-4 h-4 ${wn.isPending?`animate-spin`:``}`}),j(`printers.forceRefresh`)]}),(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-sm hover:bg-bambu-dark-tertiary flex items-center gap-2`,onClick:()=>{H(!0),L(!1)},children:[(0,K.jsx)(pu,{className:`w-4 h-4`}),j(`printers.mqttDebug`)]}),(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-sm hover:bg-bambu-dark-tertiary flex items-center gap-2`,onClick:()=>{ze(!0),L(!1)},children:[(0,K.jsx)(su,{className:`w-4 h-4`}),j(`diagnostic.runButton`)]}),(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-sm flex items-center gap-2 ${F(`printers:delete`)?`text-red-400 hover:bg-bambu-dark-tertiary`:`text-red-400/50 cursor-not-allowed`}`,onClick:()=>{F(`printers:delete`)&&(z(!0),L(!1))},title:F(`printers:delete`)?void 0:j(`printers.permission.noDelete`),children:[(0,K.jsx)(yu,{className:`w-4 h-4`}),j(`common.delete`)]})]})]});return(0,K.jsxs)(yd,{id:`printer-card-${e.id}`,className:`relative flex h-full flex-col ${w?`ring-2 ring-bambu-green`:``} ${C||r===`compact`?`cursor-pointer`:``}`,onClick:jr,onDragEnter:Dr,onDragOver:Or,onDragLeave:kr,onDrop:Ar,children:[C&&(0,K.jsx)(`div`,{className:`absolute inset-0 z-20 flex items-start p-2`,onClick:t=>{t.stopPropagation(),T?.(e.id)},children:w?(0,K.jsx)(ru,{className:`w-5 h-5 text-bambu-green`}):(0,K.jsx)(au,{className:`w-5 h-5 text-bambu-gray`})}),(rt||at)&&(0,K.jsx)(`div`,{className:`absolute inset-0 z-10 rounded-xl border-2 border-dashed flex items-center justify-center transition-colors ${at?`bg-bambu-green/10 border-bambu-green/50`:Er?`bg-bambu-green/10 border-bambu-green`:`bg-red-500/10 border-red-500/50`}`,children:(0,K.jsx)(`div`,{className:`text-center`,children:at?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(X,{className:`w-8 h-8 mx-auto mb-2 text-bambu-green animate-spin`}),(0,K.jsx)(`p`,{className:`text-sm font-medium text-bambu-green`,children:j(`common.uploading`,`Uploading...`)})]}):Er?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(wl,{className:`w-8 h-8 mx-auto mb-2 text-bambu-green`}),(0,K.jsx)(`p`,{className:`text-sm font-medium text-bambu-green`,children:j(`printers.dropToPrint`,`Drop to print`)})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Bu,{className:`w-8 h-8 mx-auto mb-2 text-red-400`}),(0,K.jsx)(`p`,{className:`text-sm font-medium text-red-400`,children:j(`printers.cannotPrint`,`Printer busy`)})]})})}),(0,K.jsxs)(xd,{className:`${i>=3?`p-5`:``} flex flex-1 flex-col`,children:[(0,K.jsxs)(`div`,{className:Tr(),children:[(0,K.jsx)(`div`,{className:`flex items-start justify-between gap-2`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-3 min-w-0 flex-1`,children:[(0,K.jsx)(`img`,{src:bT(e.model),alt:e.model||j(`common.printer`),className:`object-contain rounded-lg flex-shrink-0 ${Cr()}`}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,K.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2`,children:[(0,K.jsx)(`h3`,{className:`font-semibold text-white ${wr()}`,children:e.name}),r===`compact`&&(()=>{let e=G?.connected&&G.hms_errors?qp(G.hms_errors):[],t=e.some(e=>e.severity<=2),n=e.length>0,r=G?.connected?t?`bg-status-error`:n?`bg-status-warning`:`bg-status-ok`:`bg-status-error`,i=G?.connected?n?`${e.length} HMS ${e.length===1?`error`:`errors`}`:j(`printers.connection.connected`):j(`printers.connection.offline`);return(0,K.jsx)(`div`,{className:`w-2 h-2 rounded-full flex-shrink-0 ${r}`,title:i})})()]}),r===`compact`&&hn&&(0,K.jsx)(`button`,{type:`button`,onClick:()=>Fn.mutate(),disabled:Fn.isPending||!F(`printers:clear_plate`),"aria-label":j(`printers.plateStatus.markCleared`),className:`inline-flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-md bg-yellow-500/20 border border-yellow-400/40 text-yellow-400 hover:bg-yellow-500/30 transition-colors disabled:opacity-50`,title:F(`printers:clear_plate`)?j(`printers.plateStatus.markCleared`):j(`printers.permission.noControl`),children:Fn.isPending?(0,K.jsx)(X,{className:`w-3 h-3 animate-spin`}):(0,K.jsx)(XU,{className:`w-3 h-3`})})]}),(0,K.jsxs)(`p`,{className:`text-sm text-bambu-gray`,children:[e.model||`Unknown Model`,r===`expanded`&&G?.nozzles&&G.nozzles[0]?.nozzle_diameter&&(0,K.jsxs)(`span`,{className:`ml-1.5 text-bambu-gray`,title:G.nozzles[0].nozzle_type||`Nozzle`,children:[`• `,G.nozzles[0].nozzle_diameter,`mm`]}),r===`expanded`&&n&&n.total_print_hours>0&&(0,K.jsxs)(`span`,{className:`ml-2 text-bambu-gray`,children:[(0,K.jsx)(xs,{className:`w-3 h-3 inline-block mr-1`}),Math.round(n.total_print_hours),`h`]})]})]})]})}),r===`expanded`&&(0,K.jsx)(`div`,{className:`mt-2`,children:(0,K.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[e.is_active===!1?(0,K.jsxs)(`span`,{className:`flex items-center gap-1.5 px-2 py-1 rounded-full text-xs bg-amber-500/20 text-amber-400`,title:j(`printers.maintenance.subtitle`),children:[(0,K.jsx)(zu,{className:`w-3 h-3`}),j(`printers.maintenance.pillLabel`)]}):(0,K.jsxs)(`span`,{className:`flex items-center gap-1.5 px-2 py-1 rounded-full text-xs ${G?.connected?`bg-status-ok/20 text-status-ok`:`bg-status-error/20 text-status-error`}`,children:[G?.connected?(0,K.jsx)(Vc,{className:`w-3 h-3`}):(0,K.jsx)(Tu,{className:`w-3 h-3`}),G?.connected?j(`printers.connection.connected`):j(`printers.connection.offline`)]}),e.is_active!==!1&&!G?.connected&&(0,K.jsxs)(`button`,{onClick:()=>ze(!0),className:`flex items-center gap-1 px-2 py-1 rounded-full text-xs cursor-pointer bg-bambu-dark-tertiary text-bambu-gray hover:text-white transition-colors`,title:j(`diagnostic.runButton`),children:[(0,K.jsx)(su,{className:`w-3 h-3`}),j(`diagnostic.runButton`)]}),G?.connected&&G?.wired_network&&(0,K.jsxs)(`span`,{className:`flex items-center gap-1 px-2 py-1 rounded-full text-xs bg-status-ok/20 text-status-ok`,title:j(`printers.connection.ethernet`,`Ethernet`),children:[(0,K.jsx)(qo,{className:`w-3 h-3`}),j(`printers.connection.ethernet`,`Ethernet`)]}),G?.connected&&!G?.wired_network&&Kt!=null&&(0,K.jsxs)(`span`,{className:`flex items-center gap-1 px-2 py-1 rounded-full text-xs ${Kt>=-50||Kt>=-60?`bg-status-ok/20 text-status-ok`:Kt>=-70?`bg-status-warning/20 text-status-warning`:Kt>=-80?`bg-orange-500/20 text-orange-600`:`bg-status-error/20 text-status-error`}`,title:`WiFi: ${Kt} dBm - ${j(xT(Kt).labelKey)}`,children:[(0,K.jsx)(Jl,{className:`w-3 h-3`}),Kt,`dBm`]}),G?.connected&&(()=>{let e=G.hms_errors?qp(G.hms_errors):[];return(0,K.jsxs)(`button`,{onClick:()=>de(!0),className:`flex items-center gap-1 px-2 py-1 rounded-full text-xs cursor-pointer hover:opacity-80 transition-opacity ${e.length>0?e.some(e=>e.severity<=2)?`bg-status-error/20 text-status-error`:`bg-status-warning/20 text-status-warning`:`bg-status-ok/20 text-status-ok`}`,title:j(`printers.clickToViewHmsErrors`),children:[(0,K.jsx)(Su,{className:`w-3 h-3`}),e.length>0?e.length:`OK`]})})(),n&&(0,K.jsxs)(`button`,{onClick:()=>N(`/maintenance`),className:`flex items-center gap-1 px-2 py-1 rounded-full text-xs cursor-pointer hover:opacity-80 transition-opacity ${n.due_count>0?`bg-status-error/20 text-status-error`:n.warning_count>0?`bg-status-warning/20 text-status-warning`:`bg-status-ok/20 text-status-ok`}`,title:n.due_count>0||n.warning_count>0?`${n.due_count>0?`${n.due_count} maintenance due`:``}${n.due_count>0&&n.warning_count>0?`, `:``}${n.warning_count>0?`${n.warning_count} due soon`:``} - Click to view`:j(`printers.maintenanceUpToDate`),children:[(0,K.jsx)(zu,{className:`w-3 h-3`}),n.due_count>0||n.warning_count>0?n.due_count+n.warning_count:`OK`]}),sn>0&&(0,K.jsxs)(`button`,{onClick:()=>N(`/queue`),className:`flex items-center gap-1 px-2 py-1 rounded-full text-xs bg-indigo-500/20 text-indigo-400 hover:opacity-80 transition-opacity`,title:j(`printers.queue.inQueue`,{count:sn}),children:[(0,K.jsx)(Lc,{className:`w-3 h-3`}),sn]}),b&&Nt?.current_version&&Nt?.latest_version?(0,K.jsxs)(`button`,{onClick:()=>bt(!0),className:`flex items-center gap-1 px-2 py-1 rounded-full text-xs hover:opacity-80 transition-opacity ${Nt.update_available?`bg-orange-500/20 text-orange-400`:`bg-status-ok/20 text-status-ok`}`,title:Nt.update_available?j(`printers.firmwareUpdateAvailable`,{current:Nt.current_version,latest:Nt.latest_version}):j(`printers.firmwareUpToDate`,{version:Nt.current_version}),children:[Nt.update_available?(0,K.jsx)(Bs,{className:`w-3 h-3`}):(0,K.jsx)(fs,{className:`w-3 h-3`}),Nt.current_version]}):G?.firmware_version?(0,K.jsx)(`span`,{className:`flex items-center gap-1 px-2 py-1 rounded-full text-xs bg-bambu-dark-tertiary/50 text-bambu-gray`,children:G.firmware_version}):null,G?.connected&&[`X1C`,`X1`,`X1E`,`X2D`,`P1S`,`P1P`,`P2S`,`H2D`,`H2D Pro`,`H2C`,`H2S`].includes(e.model??``)&&(0,K.jsx)(`span`,{className:`flex items-center px-2 py-1 rounded-full text-xs ${G.door_open?`bg-yellow-500/20 text-yellow-400`:`bg-status-ok/20 text-status-ok`}`,title:G.door_open?j(`printers.door.open`):j(`printers.door.closed`),children:G.door_open?(0,K.jsx)(zs,{className:`w-3 h-3`}):(0,K.jsx)(Rs,{className:`w-3 h-3`})})]})})]}),R&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/50 flex items-center justify-center z-50`,children:(0,K.jsx)(yd,{className:`w-full max-w-md mx-4`,children:(0,K.jsxs)(xd,{children:[(0,K.jsxs)(`div`,{className:`flex items-start gap-3 mb-4`,children:[(0,K.jsx)(`div`,{className:`p-2 rounded-full bg-red-500/20`,children:(0,K.jsx)(Su,{className:`w-5 h-5 text-red-400`})}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white`,children:j(`printers.confirm.deleteTitle`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1`,children:j(`printers.confirm.deleteMessage`,{name:e.name})})]})]}),(0,K.jsx)(`div`,{className:`bg-bambu-dark rounded-lg p-3 mb-4`,children:(0,K.jsxs)(`label`,{className:`flex items-start gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:B,onChange:e=>V(e.target.checked),className:`mt-0.5 w-4 h-4 rounded border-bambu-gray bg-bambu-dark-secondary text-bambu-green focus:ring-bambu-green focus:ring-offset-0`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-sm text-white`,children:j(`printers.deleteArchives`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:j(B?`printers.confirm.deleteArchivesNote`:`printers.confirm.keepArchivesNote`)})]})]})}),(0,K.jsxs)(`div`,{className:`flex justify-end gap-2`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>{z(!1),V(!0)},children:j(`common.cancel`)}),(0,K.jsx)($,{variant:`danger`,onClick:()=>{Sn.mutate({deleteArchives:B}),z(!1),V(!0)},children:`Delete`})]})]})})}),e.is_active===!1?(0,K.jsx)(K.Fragment,{children:r===`compact`?(0,K.jsxs)(`div`,{className:`mt-2 flex items-center gap-2 px-2 py-1.5 rounded-full bg-amber-500/15 border border-amber-500/30`,children:[(0,K.jsx)(zu,{className:`w-3 h-3 text-amber-400 shrink-0`}),(0,K.jsx)(`span`,{className:`text-[11px] text-amber-400 font-medium truncate`,children:j(`printers.maintenance.pillLabel`)})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-2`,children:[(0,K.jsx)(`span`,{className:`text-[10px] uppercase tracking-wider text-bambu-gray font-medium`,children:j(`printers.status.title`,`Status`)}),(0,K.jsx)(`div`,{className:`flex-1 h-[2px] bg-bambu-dark-tertiary`})]}),(0,K.jsxs)(`div`,{className:`p-3 bg-amber-500/10 border border-amber-500/30 rounded-[10px] flex items-center gap-3`,children:[(0,K.jsx)(zu,{className:`w-6 h-6 text-amber-400 shrink-0`}),(0,K.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,K.jsx)(`p`,{className:`text-sm text-amber-400 font-medium`,children:j(`printers.maintenance.title`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:j(`printers.maintenance.subtitle`)})]}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,disabled:Yn.isPending||!F(`printers:update`),onClick:()=>Yn.mutate(!0),title:F(`printers:update`)?void 0:j(`printers.permission.noEdit`),children:j(`printers.maintenance.exitButton`)})]})]})}):G?.connected&&(0,K.jsxs)(K.Fragment,{children:[r===`compact`?(()=>{let e=G.hms_errors?qp(G.hms_errors):[],t=G.state===`FAILED`||e.length>0,n=G.state===`RUNNING`||G.state===`PAUSE`?Math.max(0,Math.min(100,G.progress||0)):hn||t?100:0,r=G.state===`RUNNING`||G.state===`PAUSE`;return(0,K.jsxs)(`div`,{className:`relative mt-2 flex items-center gap-2`,children:[(0,K.jsx)(`div`,{className:`h-1.5 min-w-0 flex-1 overflow-hidden rounded-full bg-bambu-dark-tertiary`,children:(0,K.jsx)(`div`,{className:`${t?`bg-status-error`:G.state===`PAUSE`?`bg-status-warning`:`bg-bambu-green`} h-1.5 rounded-full transition-all`,style:{width:`${n}%`}})}),(0,K.jsx)(`span`,{className:`w-9 shrink-0 text-right text-[11px] leading-none ${r?`text-white`:`text-bambu-gray`}`,children:r?`${Math.round(n)}%`:`---%`})]})})():(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-2`,children:[(0,K.jsx)(`span`,{className:`text-[10px] uppercase tracking-wider text-bambu-gray font-medium`,children:j(`printers.status.title`,`Status`)}),(0,K.jsx)(`div`,{className:`flex-1 h-[2px] bg-bambu-dark-tertiary`})]}),(()=>{let t=!!(G.current_print&&(G.state===`RUNNING`||G.state===`PAUSE`)),n=!t&&mn&&_n,r=t?gn:n?_n.name:null,i=t?G.cover_url:n?_n.coverUrl:null,a=t?G.progress||0:n?100:0;return(0,K.jsxs)(`div`,{className:`p-2 bg-bambu-dark rounded-[10px] relative overflow-hidden`,children:[(0,K.jsxs)(`button`,{onClick:()=>Ne(!0),disabled:!t||(G.printable_objects_count??0)<2||!F(`printers:control`),className:`absolute top-2 right-2 p-1.5 rounded transition-colors z-10 ${t&&(G.printable_objects_count??0)>=2&&F(`printers:control`)?`text-bambu-gray hover:text-white hover:bg-white/10`:`text-bambu-gray/30 cursor-not-allowed`}`,title:F(`printers:control`)?t?(G.printable_objects_count??0)>=2?j(`printers.skipObjects.tooltip`):j(`printers.skipObjects.requiresMultiple`):j(`printers.skipObjects.onlyWhilePrinting`):j(`printers.permission.noControl`),children:[(0,K.jsx)(dT,{className:`w-4 h-4`}),tr&&tr.skipped_count>0&&(0,K.jsx)(`span`,{className:`absolute -top-1 -right-1 min-w-[16px] h-4 px-1 flex items-center justify-center text-[10px] font-bold bg-red-500 text-white rounded-full`,children:tr.skipped_count})]}),(0,K.jsxs)(`div`,{className:`flex items-stretch gap-2`,children:[(0,K.jsx)(Bke,{url:i,printName:r||void 0,className:`w-24 h-24 max-[520px]:w-20 max-[520px]:h-20`}),(0,K.jsxs)(`div`,{className:`flex h-24 max-[520px]:h-20 min-w-0 flex-1 flex-col justify-between pt-1`,children:[(0,K.jsxs)(`div`,{className:`flex min-h-[18px] items-center gap-2 pr-8`,children:[(0,K.jsx)(`p`,{className:`min-w-0 truncate text-sm text-bambu-gray`,children:Wke(G.state,G.stg_cur_name)}),bn]}),(0,K.jsx)(`p`,{className:`min-h-[18px] truncate pr-8 text-sm ${r?`text-white`:`text-bambu-gray/70`}`,children:r||j(`printers.noActiveJob`,`No active job`)}),(0,K.jsxs)(`div`,{className:`flex h-3 items-center gap-2 text-sm`,children:[(0,K.jsx)(`div`,{className:`h-1.5 min-w-0 flex-1 rounded-full bg-bambu-dark-tertiary`,children:(0,K.jsx)(`div`,{className:`${t?G.state===`PAUSE`?`bg-status-warning`:`bg-bambu-green`:n?`bg-bambu-green`:`bg-bambu-dark-tertiary`} h-1.5 rounded-full transition-all`,style:{width:`${a}%`}})}),(0,K.jsx)(`span`,{className:`w-9 shrink-0 pr-1 text-right text-[11px] leading-none ${t||n?`text-white`:`text-bambu-gray`}`,children:t||n?`${Math.round(a)}%`:`---%`})]}),(0,K.jsx)(`div`,{className:`flex min-h-[16px] items-center gap-2 text-xs text-bambu-gray`,children:t?(0,K.jsxs)(K.Fragment,{children:[G.remaining_time!=null&&G.remaining_time>0&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`span`,{className:`flex items-center gap-1`,children:[(0,K.jsx)(xs,{className:`w-3 h-3`}),kf(G.remaining_time*60)]}),(0,K.jsxs)(`span`,{className:`text-bambu-green font-medium`,title:j(`printers.estimatedCompletion`),children:[`ETA `,Of(G.remaining_time,g,j)]})]}),G.layer_num!=null&&G.total_layers!=null&&G.total_layers>0&&(0,K.jsxs)(`span`,{className:`flex items-center gap-1`,children:[(0,K.jsx)(Lc,{className:`w-3 h-3`}),G.layer_num,`/`,G.total_layers]}),un&&(0,K.jsxs)(`span`,{className:`flex items-center gap-1`,title:`Started by ${un}`,children:[(0,K.jsx)(Du,{className:`w-3 h-3`}),un]})]}):fn?(0,K.jsxs)(`p`,{className:`truncate`,title:fn.print_name||fn.filename,children:[`Last: `,fn.print_name||fn.filename,fn.completed_at&&(0,K.jsxs)(`span`,{className:`ml-1 text-bambu-gray/60`,children:[`• `,Tf(fn.completed_at,{month:`short`,day:`numeric`})]})]}):(0,K.jsx)(`span`,{children:j(`printers.readyToPrint`)})})]})]}),(0,K.jsx)(Tle,{printerId:e.id,printerModel:e.model,loadedFilamentTypes:Ft,loadedFilaments:It,variant:`panelExtension`})]})})()]}),G.temperatures&&r===`expanded`&&(()=>{let t=G.temperatures.nozzle_heating||G.temperatures.nozzle_2_heating||!1,n=G.temperatures.bed_heating||!1,r=G.temperatures.chamber_heating||!1,i=e.nozzle_count===2||G.temperatures.nozzle_2!==void 0,a=(()=>{let e=[`nozzle`];return G.temperatures.nozzle_2!==void 0&&e.push(`nozzle_2`),e.push(`bed`),G.temperatures.chamber!==void 0&&e.push(`chamber`),e})(),o=G.active_extruder===1?`L`:`R`,s=G.nozzle_rack?.find(e=>e.id===1),c=G.nozzle_rack?.find(e=>e.id===0),l=c||s,u=G.connected&&F(`printers:control`),d=u?void 0:j(`printers.permission.noControl`),f=`relative text-center px-2 py-1.5 bg-bambu-dark rounded-lg flex-1 flex flex-col justify-center items-center transition-colors ${u?`cursor-pointer hover:bg-bambu-dark-tertiary`:`cursor-default opacity-80`}`,p=Gke.has(e.model??``),m=[{key:`part`,label:j(`printers.fans.partCooling`),value:G.cooling_fan_speed??0,Icon:Xs,activeClass:`text-cyan-400`},{key:`aux`,label:j(`printers.fans.auxiliary`),value:G.big_fan1_speed??0,Icon:Lu,activeClass:`text-blue-400`},...p?[{key:`chamber`,label:j(`printers.fans.chamber`),value:G.big_fan2_speed??0,Icon:Do,activeClass:`text-green-400`}]:[]];return(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`mt-2 flex items-stretch gap-1.5 flex-wrap`,children:[(0,K.jsxs)(`div`,{className:f,title:d,onClick:()=>u&&Te(we===`nozzle-temp`?null:`nozzle-temp`),children:[(0,K.jsx)(`button`,{type:`button`,className:`absolute top-0.5 right-0.5 p-0.5 rounded text-bambu-gray hover:text-white hover:bg-white/10 transition-colors`,title:j(`printers.heaterHistory.openLabel`,`View heater history`),onClick:e=>{e.stopPropagation(),ft({initialKind:`nozzle`,availableKinds:a})},children:(0,K.jsx)($o,{className:`w-2.5 h-2.5`})}),(0,K.jsx)(_W,{className:`w-3.5 h-3.5 mb-0.5`,color:`text-orange-400`,isHeating:t}),G.temperatures.nozzle_2===void 0?l?(0,K.jsx)(gW,{slot:l,index:0,activeStatus:!0,filamentName:l.filament_id?Lt?.[l.filament_id]?.name:void 0,children:(0,K.jsxs)(`div`,{className:`cursor-default`,children:[(0,K.jsx)(`p`,{className:`text-[9px] text-bambu-gray`,children:j(`printers.temperatures.nozzle`)}),(0,K.jsxs)(`p`,{className:`text-[11px] text-white`,children:[Math.round(G.temperatures.nozzle||0),`°C`]})]})}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`p`,{className:`text-[9px] text-bambu-gray`,children:j(`printers.temperatures.nozzle`)}),(0,K.jsxs)(`p`,{className:`text-[11px] text-white`,children:[Math.round(G.temperatures.nozzle||0),`°C`]})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`p`,{className:`text-[9px] text-bambu-gray`,children:`L / R`}),(0,K.jsxs)(`p`,{className:`text-[11px] text-white`,children:[Math.round(G.temperatures.nozzle||0),`° / `,Math.round(G.temperatures.nozzle_2||0),`°`]})]}),we===`nozzle-temp`&&(i?(0,K.jsx)(CW,{title:`Set Nozzle Temperatures`,widthClass:`w-[300px]`,popoverWidth:300,popoverHeight:260,isPending:In.isPending,onClose:()=>Te(null),children:(0,K.jsxs)(`div`,{className:`grid grid-cols-2 gap-2 px-3 py-2.5`,children:[(0,K.jsx)(wW,{label:`Left Temp`,current:G.temperatures.nozzle,target:G.temperatures.nozzle_target,isActive:o===`L`,isPending:In.isPending,onSubmit:e=>In.mutate({target:e,nozzle:1}),options:Wp(D,`C`)}),(0,K.jsx)(wW,{label:`Right Temp`,current:G.temperatures.nozzle_2,target:G.temperatures.nozzle_2_target,isActive:o===`R`,isPending:In.isPending,onSubmit:e=>In.mutate({target:e,nozzle:0}),options:Wp(D,`C`)})]})}):(0,K.jsx)(CW,{title:`Set Nozzle Temperature`,unit:`°C`,customMin:0,customMax:320,isPending:In.isPending,options:Wp(D,`C`),onClose:()=>Te(null),onSubmit:e=>In.mutate({target:e,nozzle:G.active_extruder??0})}))]}),(0,K.jsxs)(`div`,{className:f,title:d,onClick:()=>u&&Te(we===`bed-temp`?null:`bed-temp`),children:[(0,K.jsx)(`button`,{type:`button`,className:`absolute top-0.5 right-0.5 p-0.5 rounded text-bambu-gray hover:text-white hover:bg-white/10 transition-colors`,title:j(`printers.heaterHistory.openLabel`,`View heater history`),onClick:e=>{e.stopPropagation(),ft({initialKind:`bed`,availableKinds:a})},children:(0,K.jsx)($o,{className:`w-2.5 h-2.5`})}),(0,K.jsx)(_W,{className:`w-3.5 h-3.5 mb-0.5`,color:`text-blue-400`,isHeating:n}),(0,K.jsx)(`p`,{className:`text-[9px] text-bambu-gray`,children:j(`printers.temperatures.bed`)}),(0,K.jsxs)(`p`,{className:`text-[11px] text-white`,children:[Math.round(G.temperatures.bed||0),`°C`]}),we===`bed-temp`&&(0,K.jsx)(CW,{title:`Set Bed Temperature`,unit:`°C`,customMin:0,customMax:140,isPending:Ln.isPending,options:Wp(O,`C`),onClose:()=>Te(null),onSubmit:e=>Ln.mutate(e)})]}),G.temperatures.chamber!==void 0&&(()=>{let e=G.supports_chamber_heater===!0;return(0,K.jsxs)(`div`,{className:e?f:`relative text-center px-2 py-1.5 bg-bambu-dark rounded-lg flex-1 flex flex-col justify-center items-center`,title:e?d:void 0,onClick:e?()=>u&&Te(we===`chamber-temp`?null:`chamber-temp`):void 0,children:[(0,K.jsx)(`button`,{type:`button`,className:`absolute top-0.5 right-0.5 p-0.5 rounded text-bambu-gray hover:text-white hover:bg-white/10 transition-colors`,title:j(`printers.heaterHistory.openLabel`,`View heater history`),onClick:e=>{e.stopPropagation(),ft({initialKind:`chamber`,availableKinds:a})},children:(0,K.jsx)($o,{className:`w-2.5 h-2.5`})}),(0,K.jsx)(_W,{className:`w-3.5 h-3.5 mb-0.5`,color:`text-green-400`,isHeating:r}),(0,K.jsx)(`p`,{className:`text-[9px] text-bambu-gray`,children:j(`printers.temperatures.chamber`)}),(0,K.jsxs)(`p`,{className:`text-[11px] text-white`,children:[Math.round(G.temperatures.chamber||0),`°C`]}),e&&we===`chamber-temp`&&(0,K.jsx)(CW,{title:`Set Chamber Temperature`,unit:`°C`,customMin:0,customMax:60,isPending:Rn.isPending,options:Wp(k,`C`),onClose:()=>Te(null),onSubmit:e=>Rn.mutate(e)})]})})(),i&&(0,K.jsx)(Ake,{leftSlot:s,rightSlot:c,activeNozzle:o,filamentInfo:Lt,children:(0,K.jsxs)(`div`,{className:`relative text-center px-3 py-1.5 bg-bambu-dark rounded-lg h-full flex flex-col justify-center items-center transition-colors ${u?`cursor-pointer hover:bg-bambu-dark-tertiary`:`cursor-default opacity-80`}`,title:u?j(`printers.activeNozzle`,{nozzle:j(o===`L`?`common.left`:`common.right`)}):d,onClick:()=>u&&Te(we===`nozzle-select`?null:`nozzle-select`),children:[(0,K.jsx)(Rke,{className:`w-3.5 h-3.5 mb-0.5 text-amber-400`}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsxs)(`span`,{className:`text-[11px] font-bold ${o===`L`?`text-amber-400`:`text-gray-500`}`,children:[`L`,s?.nozzle_diameter?` ${s.nozzle_diameter}`:``]}),(0,K.jsx)(`span`,{className:`text-[9px] text-bambu-gray/40`,children:`·`}),(0,K.jsxs)(`span`,{className:`text-[11px] font-bold ${o===`R`?`text-amber-400`:`text-gray-500`}`,children:[`R`,c?.nozzle_diameter?` ${c.nozzle_diameter}`:``]})]}),(0,K.jsx)(`p`,{className:`text-[9px] text-bambu-gray`,children:j(`printers.temperatures.nozzle`)}),we===`nozzle-select`&&(0,K.jsx)(CW,{title:`Set Nozzle Selection`,widthClass:`w-[300px]`,popoverWidth:300,popoverHeight:140,isPending:Bn.isPending,options:[{label:`Left`,value:1},{label:`Right`,value:0}],onClose:()=>Te(null),onSubmit:e=>Bn.mutate(e)})]})}),G.nozzle_rack&&G.nozzle_rack.some(e=>e.id>=2)&&(0,K.jsx)(jke,{slots:G.nozzle_rack,filamentInfo:Lt})]}),(0,K.jsx)(`div`,{className:`mt-2 flex items-center gap-1.5`,children:m.map(({key:e,label:t,value:n,Icon:r,activeClass:i})=>{let a=n>0;return(0,K.jsxs)(`div`,{className:`relative px-2 py-1.5 bg-bambu-dark rounded-lg flex-1 min-w-0 flex items-center justify-center gap-1 transition-colors ${u?`cursor-pointer hover:bg-bambu-dark-tertiary`:`cursor-default opacity-80`}`,title:u?t:d,onClick:()=>u&&Te(we===`fan-${e}`?null:`fan-${e}`),children:[(0,K.jsx)(r,{className:`w-3 h-3 shrink-0 ${a?i:`text-bambu-gray/50`}`}),(0,K.jsxs)(`span`,{className:`text-[10px] leading-none ${a?`text-white`:`text-bambu-gray/50`}`,children:[n,`%`]}),we===`fan-${e}`&&(0,K.jsx)(CW,{title:`Set ${t} Speed`,unit:`%`,customMin:0,customMax:100,isPending:zn.isPending,options:Wp(A,`%`),onClose:()=>Te(null),onSubmit:t=>zn.mutate({fan:e,speed:t})})]},e)})})]})})(),r===`expanded`&&hn&&(0,K.jsxs)(`button`,{type:`button`,onClick:()=>Fn.mutate(),disabled:Fn.isPending||!F(`printers:clear_plate`),className:`mt-2 w-full inline-flex items-center justify-center gap-2 px-3 py-1.5 rounded-lg bg-yellow-500/20 border border-yellow-400/40 text-yellow-400 hover:bg-yellow-500/30 transition-colors text-xs font-medium disabled:opacity-50`,title:F(`printers:clear_plate`)?j(`printers.plateStatus.markCleared`):j(`printers.permission.noControl`),children:[Fn.isPending?(0,K.jsx)(X,{className:`w-3 h-3 animate-spin`}):(0,K.jsx)(XU,{className:`w-4 h-4`}),j(`printers.plateStatus.markCleared`)]}),r===`expanded`&&(()=>{let t=G.state===`RUNNING`,n=G.state===`PAUSE`,r=t||n,i=Mn.isPending||Nn.isPending||Pn.isPending,a=`bg-bambu-dark text-bambu-gray/50 cursor-not-allowed opacity-50`,o=`flex h-8 w-8 items-center justify-center rounded-lg text-xs font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed`,s=`flex h-8 w-20 items-center justify-center gap-1 px-2 rounded-lg text-xs font-medium transition-colors`;return(0,K.jsxs)(`div`,{className:`mt-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-2`,children:[(0,K.jsx)(`span`,{className:`text-[10px] uppercase tracking-wider text-bambu-gray font-medium`,children:j(`printers.controls`)}),(0,K.jsx)(`div`,{className:`flex-1 h-[2px] bg-bambu-dark-tertiary`})]}),(0,K.jsxs)(`div`,{className:`flex flex-wrap items-start justify-between gap-x-2 gap-y-2`,children:[(0,K.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 min-w-0`,children:[(0,K.jsx)(`button`,{onClick:()=>Vn.mutate(!G.chamber_light),disabled:!G.connected||Vn.isPending||!F(`printers:control`),className:`${o} ${G.chamber_light?`bg-yellow-500/10 text-yellow-400 hover:bg-yellow-500/20`:`bg-bambu-dark text-bambu-gray/50 hover:bg-bambu-dark-tertiary hover:text-white`}`,title:F(`printers:control`)?G.chamber_light?j(`printers.chamberLightOff`):j(`printers.chamberLightOn`):j(`printers.permission.noControl`),children:(0,K.jsx)(uT,{on:G.chamber_light??!1,className:`w-4 h-4`})}),[`P2S`,`X2D`,`H2D`,`H2C`,`H2S`].includes(e.model??``)&&(()=>{let t=G.airduct_mode===1,n=t?ic:tu,r=t?`text-orange-400`:`text-sky-400`,i=t?`bg-orange-500/10 text-orange-400 hover:bg-orange-500/20`:`bg-sky-500/10 text-sky-400 hover:bg-sky-500/20`;return(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`button`,{onClick:()=>xe(be===e.id?null:e.id),disabled:!F(`printers:control`),className:`${o} ${i}`,title:`${j(`printers.airduct.title`)}: ${j(t?`printers.airduct.heating`:`printers.airduct.cooling`)}`,children:(0,K.jsx)(n,{className:`w-4 h-4 ${r}`})}),be===e.id&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`div`,{className:`fixed inset-0 z-40`,onClick:()=>xe(null)}),(0,K.jsx)(`div`,{className:`absolute bottom-full left-0 mb-1 z-50 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-lg py-1 min-w-[130px]`,children:[{mode:`cooling`,label:j(`printers.airduct.cooling`),modeId:0},{mode:`heating`,label:j(`printers.airduct.heating`),modeId:1}].map(({mode:e,label:t,modeId:n})=>(0,K.jsxs)(`button`,{onClick:()=>{Un.mutate(e),xe(null)},className:`w-full text-left px-3 py-1.5 text-xs transition-colors flex items-center gap-2 ${G.airduct_mode===n?`text-bambu-green bg-bambu-green/10`:`text-white hover:bg-bambu-dark-tertiary`}`,children:[e===`heating`?(0,K.jsx)(ic,{className:`w-3 h-3`}):(0,K.jsx)(tu,{className:`w-3 h-3`}),t]},e))})]})]})})(),(()=>{let t=F(`printers:control`),n=r||!t,i=`flex h-8 w-8 items-center justify-center rounded bg-indigo-500/15 text-indigo-300 transition-colors hover:bg-indigo-500/30 disabled:cursor-not-allowed disabled:opacity-50`,a=t=>{let n=t*Ee*1,r=`bambuddy.bedJog.warned.${e.id}`;(()=>{try{return sessionStorage.getItem(r)===`1`}catch{return!1}})()?Wn.mutate({distance:n,force:!0}):ke({distance:n})},s=(e,t)=>{Gn.mutate({x:e,y:t})},c=e=>{Kn.mutate(e)};return(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`button`,{onClick:()=>Ce(Se===e.id?null:e.id),disabled:n,className:`${o} ${n?`bg-bambu-dark text-bambu-gray/50 cursor-not-allowed`:`bg-indigo-500/10 text-indigo-400 hover:bg-indigo-500/20`}`,title:j(t?r?`printers.bedJog.disabledWhilePrinting`:`printers.bedJog.title`:`printers.permission.noControl`),children:(0,K.jsx)(cl,{className:`w-4 h-4`})}),Se===e.id&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`div`,{className:`fixed inset-0 z-40`,onClick:()=>Ce(null)}),(0,K.jsxs)(`div`,{className:`absolute bottom-full left-0 mb-1 z-50 flex w-[216px] flex-col overflow-hidden rounded-xl border border-bambu-dark-tertiary bg-bambu-dark-secondary shadow-2xl`,children:[(0,K.jsx)(`div`,{className:`shrink-0 px-3 py-2.5 text-center text-sm font-medium text-white`,children:j(`printers.bedJog.title`)}),(0,K.jsx)(`div`,{className:`h-px bg-bambu-dark-tertiary`}),(0,K.jsx)(`div`,{className:`flex justify-center px-3 py-2.5`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-center gap-3`,children:[(0,K.jsxs)(`div`,{className:`grid grid-cols-3 gap-1`,children:[(0,K.jsx)(`div`,{}),(0,K.jsx)(`button`,{onClick:()=>s(0,Ee),disabled:Gn.isPending,className:i,"aria-label":`Move Y forward`,children:(0,K.jsx)(Io,{className:`w-4 h-4`})}),(0,K.jsx)(`div`,{}),(0,K.jsx)(`button`,{onClick:()=>s(-Ee,0),disabled:Gn.isPending,className:i,"aria-label":`Move X left`,children:(0,K.jsx)(jo,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{onClick:()=>{Ce(null),qn.mutate(`all`)},disabled:qn.isPending,className:i,"aria-label":j(`printers.bedJog.homeZ`),children:(0,K.jsx)(kc,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{onClick:()=>s(Ee,0),disabled:Gn.isPending,className:i,"aria-label":`Move X right`,children:(0,K.jsx)(No,{className:`w-4 h-4`})}),(0,K.jsx)(`div`,{}),(0,K.jsx)(`button`,{onClick:()=>s(0,-Ee),disabled:Gn.isPending,className:i,"aria-label":`Move Y back`,children:(0,K.jsx)(Ao,{className:`w-4 h-4`})}),(0,K.jsx)(`div`,{})]}),(0,K.jsxs)(`div`,{className:`flex flex-col items-center gap-1`,children:[(0,K.jsx)(`button`,{onClick:()=>a(-1),disabled:Wn.isPending,className:i,"aria-label":j(`printers.bedJog.up`),children:(0,K.jsx)(Io,{className:`w-4 h-4`})}),(0,K.jsx)(`div`,{className:`flex h-8 w-8 items-center justify-center text-bambu-gray/80`,children:(0,K.jsx)(Lc,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{onClick:()=>a(1),disabled:Wn.isPending,className:i,"aria-label":j(`printers.bedJog.down`),children:(0,K.jsx)(Ao,{className:`w-4 h-4`})})]}),(0,K.jsxs)(`div`,{className:`flex flex-col items-center gap-1`,children:[(0,K.jsx)(`button`,{onClick:()=>c(-Ee),disabled:Kn.isPending,className:i,"aria-label":`Retract filament`,children:(0,K.jsx)(Io,{className:`w-4 h-4`})}),(0,K.jsx)(`div`,{className:`flex h-8 w-8 items-center justify-center text-bambu-gray/80`,children:(0,K.jsx)(`span`,{className:`text-sm font-semibold leading-none`,children:`E`})}),(0,K.jsx)(`button`,{onClick:()=>c(Ee),disabled:Kn.isPending,className:i,"aria-label":`Extrude filament`,children:(0,K.jsx)(Ao,{className:`w-4 h-4`})})]})]})}),(0,K.jsx)(`div`,{className:`h-px bg-bambu-dark-tertiary`}),(0,K.jsxs)(`div`,{className:`px-3 pt-2.5 pb-3`,children:[(0,K.jsx)(`div`,{className:`mb-1 text-[9px] uppercase tracking-wider text-bambu-gray/70`,children:j(`printers.bedJog.step`)}),(0,K.jsx)(`div`,{className:`flex gap-1`,children:[1,10,50].map(e=>(0,K.jsx)(`button`,{onClick:()=>De(e),className:`flex-1 px-1 py-1 rounded text-[10px] transition-colors ${Ee===e?`bg-bambu-green/20 text-bambu-green`:`bg-bambu-dark text-bambu-gray hover:bg-bambu-dark-tertiary`}`,children:e},e))})]})]})]})]})})(),(0,K.jsxs)(`div`,{className:`inline-flex rounded-lg ${e.plate_detection_enabled?`ring-1 ring-green-500`:``}`,children:[(0,K.jsx)(`button`,{onClick:hr,disabled:!G.connected||Jn.isPending||!F(`printers:update`),className:`${o} rounded-r-none ${e.plate_detection_enabled?`bg-green-500/10 text-green-400 hover:bg-green-500/20`:`bg-bambu-dark text-bambu-gray/50 hover:bg-bambu-dark-tertiary hover:text-white`}`,title:F(`printers:update`)?e.plate_detection_enabled?j(`printers.plateDetection.enabledClick`):j(`printers.plateDetection.disabledClick`):j(`printers.plateDetection.noPermission`),children:Jn.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Fl,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{onClick:gr,disabled:!G.connected||Ct||!F(`printers:update`),className:`flex h-8 w-8 items-center justify-center rounded-r-lg border-l border-bambu-dark-tertiary transition-colors disabled:opacity-50 disabled:cursor-not-allowed ${e.plate_detection_enabled?`bg-green-500/10 text-green-400 hover:bg-green-500/20`:`bg-bambu-dark text-bambu-gray/50 hover:bg-bambu-dark-tertiary hover:text-white`}`,title:F(`printers:update`)?j(`printers.plateDetection.manageCalibration`):j(`printers.plateDetection.noPermission`),children:Ct?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(rs,{className:`w-4 h-4`})})]}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`button`,{"data-testid":`speed-control`,onClick:()=>ye(ve===e.id?null:e.id),disabled:!r||!F(`printers:control`),className:`${o} ${r?`bg-amber-500/10 text-amber-400 hover:bg-amber-500/20`:`bg-bambu-dark text-bambu-gray/50 cursor-not-allowed`}`,title:r?j(`printers.speed.title`):void 0,children:(0,K.jsx)(mc,{className:`w-4 h-4`})}),ve===e.id&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`div`,{className:`fixed inset-0 z-40`,onClick:()=>ye(null)}),(0,K.jsx)(`div`,{className:`absolute bottom-full left-0 mb-1 z-50 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-lg py-1 min-w-[130px]`,children:[{mode:1,label:j(`printers.speed.silent`)},{mode:2,label:j(`printers.speed.standard`)},{mode:3,label:j(`printers.speed.sport`)},{mode:4,label:j(`printers.speed.ludicrous`)}].map(({mode:e,label:t})=>(0,K.jsx)(`button`,{onClick:()=>{Hn.mutate(e),ye(null)},className:`w-full text-left px-3 py-1.5 text-xs transition-colors ${G.speed_level===e?`text-bambu-green bg-bambu-green/10`:`text-white hover:bg-bambu-dark-tertiary`}`,children:t},e))})]})]})]}),(0,K.jsxs)(`div`,{className:`ml-auto flex items-center justify-end gap-2 flex-shrink-0`,children:[(()=>{let e=!r||i||!F(`printers:control`);return(0,K.jsxs)(`button`,{onClick:()=>n?je(!0):_e(!0),disabled:e,className:` + `,style:{maxWidth:`calc(100vw - 24px)`},onMouseEnter:w,onMouseLeave:T,children:(0,K.jsxs)(`div`,{className:`w-52 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-xl overflow-hidden backdrop-blur-sm p-2.5 space-y-2`,children:[(0,K.jsx)(`div`,{className:`text-[10px] uppercase tracking-wider text-bambu-gray font-medium`,children:n}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,K.jsx)(`span`,{className:`text-[10px] tracking-wide text-bambu-gray font-medium shrink-0`,children:s(`printers.amsPopup.serialNumber`)}),(0,K.jsx)(`span`,{className:`text-[10px] text-white font-mono truncate`,children:e.serial_number||`—`})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,K.jsx)(`span`,{className:`text-[10px] tracking-wide text-bambu-gray font-medium shrink-0`,children:s(`printers.amsPopup.firmwareVersion`)}),(0,K.jsx)(`span`,{className:`text-[10px] text-white font-mono truncate`,children:e.sw_ver||`—`})]}),(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`span`,{className:`text-[10px] text-bambu-gray font-medium shrink-0`,children:s(`printers.amsPopup.friendlyName`)}),(0,K.jsx)(`div`,{className:`flex-1 h-[2px] bg-bambu-dark-tertiary/50`})]}),(0,K.jsx)(`input`,{type:`text`,value:f,onChange:e=>i&&p(e.target.value),onKeyDown:e=>e.key===`Enter`&&E(),onFocus:()=>b(!0),onBlur:()=>{b(!1),C.current&&clearTimeout(C.current),C.current=setTimeout(()=>l(!1),200)},placeholder:i?s(`printers.amsPopup.friendlyNamePlaceholder`):r?.[e.id]||`—`,disabled:!i,title:i?void 0:s(`printers.amsPopup.noEditPermission`),className:`w-full bg-bambu-dark border border-bambu-dark-tertiary rounded px-2 py-1 text-xs text-white placeholder-bambu-gray/60 focus:outline-none focus:border-bambu-green disabled:opacity-50 disabled:cursor-not-allowed`,maxLength:100}),i&&(0,K.jsxs)(`div`,{className:`space-y-1`,children:[g&&(0,K.jsx)(`p`,{className:`text-[10px] text-red-400 break-words`,children:g}),(0,K.jsxs)(`div`,{className:`flex gap-1 justify-end`,children:[(0,K.jsx)(`button`,{onClick:E,disabled:m,className:`px-2 py-0.5 text-[10px] bg-bambu-green text-white rounded hover:bg-bambu-green/80 disabled:opacity-50`,children:s(`printers.amsPopup.save`)}),r?.[e.id]&&(0,K.jsx)(`button`,{onClick:async()=>{if(i){h(!0),_(null);try{await Q.deleteAmsLabel(t,e.id,e.serial_number),a(),l(!1)}catch(e){_(e instanceof Error?e.message:String(e))}finally{h(!1)}}},disabled:m,className:`px-2 py-0.5 text-[10px] bg-bambu-dark-tertiary text-bambu-gray rounded hover:bg-bambu-dark-tertiary/70 disabled:opacity-50`,children:s(`printers.amsPopup.clear`)})]})]})]})]})})]})}var kW={PLA:{n3f:45,n3s:45,n3f_hours:12,n3s_hours:12},PETG:{n3f:65,n3s:65,n3f_hours:12,n3s_hours:12},TPU:{n3f:65,n3s:75,n3f_hours:12,n3s_hours:18},ABS:{n3f:65,n3s:80,n3f_hours:12,n3s_hours:8},ASA:{n3f:65,n3s:80,n3f_hours:12,n3s_hours:8},PA:{n3f:65,n3s:85,n3f_hours:12,n3s_hours:12},PC:{n3f:65,n3s:80,n3f_hours:12,n3s_hours:8},PVA:{n3f:65,n3s:85,n3f_hours:12,n3s_hours:18}};function AW({printer:e,hideIfDisconnected:t,maintenanceInfo:n,viewMode:r=`expanded`,cardSize:i=2,amsThresholds:a,spoolmanEnabled:o=!1,linkedSpools:s,spoolmanUrl:c,spoolmanSyncMode:l,onGetAssignment:u,onUnassignSpool:d,spoolmanSpools:f,spoolmanSlotAssignments:p,spoolmanLoading:m=!1,onUnassignSpoolmanSpool:h,timeFormat:g=`system`,cameraViewMode:_=`window`,onOpenEmbeddedCamera:v,checkPrinterFirmware:b=!0,dryingPresets:x=kW,requirePlateClear:S=!1,selectionMode:C=!1,isSelected:w=!1,onToggleSelect:T,onOpenCompactCard:E,nozzleTempPresets:D=zp,bedTempPresets:O=Bp,chamberTempPresets:k=Vp,fanSpeedPresets:A=Hp}){let{t:j}=W(),M=no(),N=$n(),{showToast:P}=Dd(),{hasPermission:F}=pd(),[I,L]=(0,y.useState)(!1),[R,z]=(0,y.useState)(!1),[B,V]=(0,y.useState)(!0),[ee,te]=(0,y.useState)(!1),[ne,re]=(0,y.useState)(!1),[ie,H]=(0,y.useState)(!1),[ae,oe]=(0,y.useState)(!1),[U,se]=(0,y.useState)(!1),[ce,le]=(0,y.useState)(null),[ue,de]=(0,y.useState)(!1),[fe,pe]=(0,y.useState)(!1),[me,he]=(0,y.useState)(!1),[ge,_e]=(0,y.useState)(!1),[ve,ye]=(0,y.useState)(null),[be,xe]=(0,y.useState)(null),[Se,Ce]=(0,y.useState)(null),[we,Te]=(0,y.useState)(null),[Ee,De]=(0,y.useState)(10),[Oe,ke]=(0,y.useState)(null),[Ae,je]=(0,y.useState)(!1),[Me,Ne]=(0,y.useState)(!1),[Pe,Fe]=(0,y.useState)(!1),[Ie,Le]=(0,y.useState)(!1),[Re,ze]=(0,y.useState)(!1),Be=(0,y.useCallback)(()=>Le(!1),[]),[Ve,He]=(0,y.useState)(null),[Ue,We]=(0,y.useState)(null),[Ge,Ke]=(0,y.useState)(`n3f`),[qe,Je]=(0,y.useState)(`PLA`),[Ye,Xe]=(0,y.useState)(50),[Ze,Qe]=(0,y.useState)(4),[$e,et]=(0,y.useState)(!1),[tt,nt]=(0,y.useState)(null),[rt,it]=(0,y.useState)(!1),[at,ot]=(0,y.useState)(!1),st=(0,y.useRef)(null),ct=(0,y.useRef)(0),[lt,ut]=(0,y.useState)(null),[dt,ft]=(0,y.useState)(null),[pt,mt]=(0,y.useState)(null),[ht,gt]=(0,y.useState)(null),[_t,vt]=(0,y.useState)(null),[yt,bt]=(0,y.useState)(!1),[xt,St]=(0,y.useState)(null),[Ct,wt]=(0,y.useState)(!1),[Tt,Et]=(0,y.useState)(!1),[Dt,Ot]=(0,y.useState)(null),[kt,At]=(0,y.useState)(!1),[jt,Mt]=(0,y.useState)(!1),{data:G}=q({queryKey:[`printerStatus`,e.id],queryFn:()=>Q.getPrinterStatus(e.id),refetchInterval:3e4}),{data:Nt}=q({queryKey:[`firmwareUpdate`,e.id],queryFn:()=>od.checkPrinterUpdate(e.id),staleTime:300*1e3,refetchInterval:300*1e3,enabled:b&&F(`firmware:read`)}),Pt=(0,y.useMemo)(()=>{let e=new Set;if(G?.ams)for(let t of G.ams)for(let n of t.tray||[])n.tray_info_idx&&e.add(n.tray_info_idx);for(let t of G?.vt_tray??[])t.tray_info_idx&&e.add(t.tray_info_idx);if(G?.nozzle_rack)for(let t of G.nozzle_rack)t.filament_id&&e.add(t.filament_id);return Array.from(e)},[G?.ams,G?.vt_tray,G?.nozzle_rack]),Ft=(0,y.useMemo)(()=>{let e=new Set;if(G?.ams)for(let t of G.ams)for(let n of t.tray||[])n.tray_type&&e.add(n.tray_type.toUpperCase());for(let t of G?.vt_tray??[])t.tray_type&&e.add(t.tray_type.toUpperCase());return e},[G?.ams,G?.vt_tray]),It=(0,y.useMemo)(()=>{let e=new Set;if(G?.ams){for(let t of G.ams)for(let n of t.tray||[])if(n.tray_type&&n.tray_color){let t=n.tray_color.replace(`#`,``).toLowerCase().slice(0,6);e.add(`${n.tray_type.toUpperCase()}:${t}`)}}for(let t of G?.vt_tray??[])if(t.tray_type&&t.tray_color){let n=t.tray_color.replace(`#`,``).toLowerCase().slice(0,6);e.add(`${t.tray_type.toUpperCase()}:${n}`)}return e},[G?.ams,G?.vt_tray]),{data:Lt}=q({queryKey:[`filamentInfo`,Pt],queryFn:()=>Q.getFilamentInfo(Pt),enabled:Pt.length>0,staleTime:300*1e3}),{data:Rt}=q({queryKey:[`slotPresets`,e.id],queryFn:()=>Q.getSlotPresets(e.id),staleTime:120*1e3}),zt=G?.state===`RUNNING`||G?.state===`PAUSE`?G?.current_archive_id??null:null,{data:Bt}=q({queryKey:[`archive-plates`,zt],queryFn:()=>Q.getArchivePlates(zt),enabled:zt!=null,staleTime:300*1e3}),Vt=!Bt?.is_multi_plate||G?.current_plate_id==null?null:Bt.plates.find(e=>e.index===G.current_plate_id)?.name||j(`printers.plateNumber`,`Plate {{number}}`,{number:G.current_plate_id}),{data:Ht,refetch:Ut}=q({queryKey:[`amsLabels`,e.id],queryFn:()=>Q.getAmsLabels(e.id),staleTime:300*1e3}),[Wt,Gt]=(0,y.useState)(null);(0,y.useEffect)(()=>{G?.wifi_signal!=null&&Gt(G.wifi_signal)},[G?.wifi_signal]);let Kt=G?.wifi_signal??Wt,qt=(0,y.useRef)(void 0);(0,y.useEffect)(()=>{G?.connected!==void 0&&(qt.current=G.connected)},[G?.connected]);let Jt=G?.connected??qt.current,Yt=(0,y.useRef)({});(0,y.useEffect)(()=>{G?.ams_extruder_map&&Object.keys(G.ams_extruder_map).length>0&&(Yt.current=G.ams_extruder_map)},[G?.ams_extruder_map]);let Xt=G?.ams_extruder_map&&Object.keys(G.ams_extruder_map).length>0?G.ams_extruder_map:Yt.current,Zt=(0,y.useRef)([]);(0,y.useEffect)(()=>{G?.ams&&G.ams.length>0&&(Zt.current=G.ams)},[G?.ams]);let Qt=G?.ams&&G.ams.length>0?G.ams:Zt.current,$t=(0,y.useRef)(void 0),en=G?.tray_now;en!==void 0&&en!==255?$t.current=en:en===255&&($t.current=void 0);let tn=en!==void 0&&en!==255?en:$t.current,{data:nn}=q({queryKey:[`smartPlugByPrinter`,e.id],queryFn:()=>Q.getSmartPlugByPrinter(e.id)}),{data:rn}=q({queryKey:[`scriptPlugsByPrinter`,e.id],queryFn:()=>Q.getScriptPlugsByPrinter(e.id)}),{data:an}=q({queryKey:[`smartPlugStatus`,nn?.id],queryFn:()=>nn?Q.getSmartPlugStatus(nn.id):null,enabled:!!nn,refetchInterval:1e4}),{data:on}=q({queryKey:[`queue`,e.id,`pending`],queryFn:()=>Q.getQueue(e.id,`pending`)}),sn=(0,y.useMemo)(()=>on?.length?ST(on,Ft,It).length:0,[on,Ft,It]),{data:cn}=q({queryKey:[`queue`,e.id,`printing`],queryFn:()=>Q.getQueue(e.id,`printing`),enabled:G?.state===`RUNNING`}),{data:ln}=q({queryKey:[`currentPrintUser`,e.id],queryFn:()=>Q.getCurrentPrintUser(e.id),enabled:G?.state===`RUNNING`}),un=cn?.[0]?.created_by_username||ln?.username,{data:dn}=q({queryKey:[`archives`,e.id,`last`],queryFn:()=>Q.getArchives(e.id,1,0),enabled:G?.connected&&G?.state!==`RUNNING`}),fn=dn?.[0],pn=G?.state===`RUNNING`||G?.state===`PAUSE`,mn=S&&G?.awaiting_plate_clear===!0,hn=G?.connected&&mn&&!pn,gn=G?.current_print&&pn?Lp(G.subtask_name||G.current_print||null,G.gcode_file,j,Vt):null,[_n,vn]=(0,y.useState)(null);(0,y.useEffect)(()=>{gn?vn({name:gn,coverUrl:G?.cover_url??null}):mn||vn(null)},[gn,mn,G?.cover_url]);let yn=!S||!G?.connected?null:pn?{label:j(`printers.plateStatus.inUse`),className:`bg-blue-500/20 text-blue-400`}:G.awaiting_plate_clear?{label:j(`printers.plateStatus.notCleared`),className:`bg-yellow-500/20 text-yellow-400`}:{label:j(`printers.plateStatus.cleared`),className:`bg-status-ok/20 text-status-ok`},bn=yn?(0,K.jsx)(`span`,{className:`inline-flex flex-shrink-0 items-center rounded-full px-2 py-0.5 text-[10px] font-medium ${yn.className}`,children:yn.label}):null,xn=t&&Jt===!1,Sn=J({mutationFn:t=>Q.deletePrinter(e.id,t.deleteArchives),onSuccess:()=>{M.invalidateQueries({queryKey:[`printers`]}),M.invalidateQueries({queryKey:[`archives`]}),M.invalidateQueries({queryKey:[`maintenanceOverview`]})},onError:e=>P(e.message||j(`printers.toast.failedToDelete`),`error`)}),Cn=J({mutationFn:()=>Q.connectPrinter(e.id),onSuccess:()=>{M.invalidateQueries({queryKey:[`printerStatus`,e.id]})}}),wn=J({mutationFn:()=>Q.refreshPrinterStatus(e.id),onSuccess:()=>{M.invalidateQueries({queryKey:[`printerStatus`,e.id]}),P(j(`printers.forceRefreshSuccess`),`success`)},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),Tn=J({mutationFn:e=>Q.unlinkSpool(e),onSuccess:e=>{P(j(`spoolman.unlinkSuccess`)||e?.message,`success`),M.invalidateQueries({queryKey:[`linked-spools`]}),M.invalidateQueries({queryKey:[`unlinked-spools`]}),M.invalidateQueries({queryKey:[`spoolman-slot-assignments`]})},onError:e=>{P(e.message||j(`spoolman.unlinkFailed`),`error`)}}),En=J({mutationFn:({amsId:t,temp:n,duration:r,filament:i,rotateTray:a})=>Q.startDrying(e.id,t,n,r,i,a),onSuccess:()=>{We(null),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),Dn=J({mutationFn:t=>Q.stopDrying(e.id,t),onSuccess:()=>{M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),On=J({mutationFn:t=>Q.setAmsFilamentBackup(e.id,t),onSuccess:(t,n)=>{M.invalidateQueries({queryKey:[`printerStatus`,e.id]}),M.invalidateQueries({queryKey:[`printer-status`,e.id]}),P(j(n?`printers.amsBackup.toastEnabled`:`printers.amsBackup.toastDisabled`),`success`)},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),kn=J({mutationFn:e=>nn?Q.controlSmartPlug(nn.id,e):Promise.reject(`No plug`),onSuccess:()=>{M.invalidateQueries({queryKey:[`smartPlugStatus`,nn?.id]})}}),An=J({mutationFn:e=>nn?Q.updateSmartPlug(nn.id,{auto_off:e}):Promise.reject(`No plug`),onSuccess:()=>{M.invalidateQueries({queryKey:[`smartPlugByPrinter`,e.id]}),M.invalidateQueries({queryKey:[`smart-plugs`]})}}),jn=J({mutationFn:({id:e,action:t})=>Q.controlSmartPlug(e,t),onSuccess:()=>{P(j(`printers.toast.scriptTriggered`))},onError:e=>P(e.message||j(`printers.toast.failedToRunScript`),`error`)}),Mn=J({mutationFn:()=>Q.stopPrint(e.id),onSuccess:()=>{P(j(`printers.toast.printStopped`)),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToStopPrint`),`error`)}),Nn=J({mutationFn:()=>Q.pausePrint(e.id),onSuccess:()=>{P(j(`printers.toast.printPaused`)),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToPausePrint`),`error`)}),Pn=J({mutationFn:()=>Q.resumePrint(e.id),onSuccess:()=>{P(j(`printers.toast.printResumed`)),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToResumePrint`),`error`)}),Fn=J({mutationFn:()=>Q.clearPlate(e.id),onSuccess:()=>{P(j(`queue.clearPlateSuccess`)),M.setQueryData([`printerStatus`,e.id],e=>e&&{...e,awaiting_plate_clear:!1}),M.invalidateQueries({queryKey:[`printerStatus`,e.id]}),M.invalidateQueries({queryKey:[`queue`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),In=J({mutationFn:({target:t,nozzle:n})=>Q.setNozzleTemperature(e.id,t,n),onSuccess:t=>{Te(null),P(t.message),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),Ln=J({mutationFn:t=>Q.setBedTemperature(e.id,t),onSuccess:t=>{Te(null),P(t.message),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),Rn=J({mutationFn:t=>Q.setChamberTemperature(e.id,t),onSuccess:t=>{Te(null),P(t.message),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),zn=J({mutationFn:({fan:t,speed:n})=>Q.setFanSpeed(e.id,t,n),onMutate:async({fan:t,speed:n})=>{await M.cancelQueries({queryKey:[`printerStatus`,e.id]});let r=M.getQueryData([`printerStatus`,e.id]),i={part:`cooling_fan_speed`,aux:`big_fan1_speed`,chamber:`big_fan2_speed`}[t];return M.setQueryData([`printerStatus`,e.id],e=>e&&{...e,[i]:n}),{previousStatus:r}},onSuccess:t=>{Te(null),P(t.message),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:(t,n,r)=>{r?.previousStatus&&M.setQueryData([`printerStatus`,e.id],r.previousStatus),P(t.message||j(`printers.toast.failedToSendCommand`),`error`)}}),Bn=J({mutationFn:t=>Q.selectExtruder(e.id,t),onMutate:async t=>{await M.cancelQueries({queryKey:[`printerStatus`,e.id]});let n=M.getQueryData([`printerStatus`,e.id]);return M.setQueryData([`printerStatus`,e.id],e=>e&&{...e,active_extruder:t}),{previousStatus:n}},onSuccess:t=>{Te(null),P(t.message),M.invalidateQueries({queryKey:[`printerStatus`,e.id]})},onError:(t,n,r)=>{r?.previousStatus&&M.setQueryData([`printerStatus`,e.id],r.previousStatus),P(t.message||j(`printers.toast.failedToSendCommand`),`error`)}}),Vn=J({mutationFn:t=>Q.setChamberLight(e.id,t),onMutate:async t=>{await M.cancelQueries({queryKey:[`printerStatus`,e.id]});let n=M.getQueryData([`printerStatus`,e.id]);return M.setQueryData([`printerStatus`,e.id],e=>({...e,chamber_light:t})),{previousStatus:n}},onSuccess:(e,t)=>{P(`Chamber light ${t?`on`:`off`}`)},onError:(t,n,r)=>{r?.previousStatus&&M.setQueryData([`printerStatus`,e.id],r.previousStatus),P(t.message||j(`printers.toast.failedToControlChamberLight`),`error`)}}),Hn=J({mutationFn:t=>Q.setPrintSpeed(e.id,t),onMutate:async t=>{await M.cancelQueries({queryKey:[`printerStatus`,e.id]});let n=M.getQueryData([`printerStatus`,e.id]);return M.setQueryData([`printerStatus`,e.id],e=>({...e,speed_level:t})),{previousStatus:n}},onError:(t,n,r)=>{r?.previousStatus&&M.setQueryData([`printerStatus`,e.id],r.previousStatus),P(t.message||j(`printers.toast.failedToSetSpeed`),`error`)}}),Un=J({mutationFn:t=>Q.setAirductMode(e.id,t),onMutate:async t=>{await M.cancelQueries({queryKey:[`printerStatus`,e.id]});let n=M.getQueryData([`printerStatus`,e.id]);return M.setQueryData([`printerStatus`,e.id],e=>({...e,airduct_mode:t===`cooling`?0:1})),{previousStatus:n}},onError:(t,n,r)=>{r?.previousStatus&&M.setQueryData([`printerStatus`,e.id],r.previousStatus),P(t.message||j(`printers.toast.failedToSendCommand`),`error`)}}),Wn=J({mutationFn:({distance:t,force:n})=>Q.bedJog(e.id,t,n??!1),onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),Gn=J({mutationFn:({x:t,y:n})=>Q.xyJog(e.id,t,n),onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),Kn=J({mutationFn:t=>Q.extruderJog(e.id,t),onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),qn=J({mutationFn:t=>Q.homeAxes(e.id,t),onSuccess:()=>{try{sessionStorage.setItem(`bambuddy.bedJog.warned.${e.id}`,`1`)}catch{}P(j(`printers.bedJog.homingStarted`))},onError:e=>P(e.message||j(`printers.toast.failedToSendCommand`),`error`)}),Jn=J({mutationFn:t=>Q.updatePrinter(e.id,{plate_detection_enabled:t}),onSuccess:()=>{M.invalidateQueries({queryKey:[`printers`]}),P(Jn.variables?j(`printers.toast.plateCheckEnabled`):j(`printers.toast.plateCheckDisabled`))},onError:e=>P(e.message||j(`printers.toast.failedToUpdateSetting`),`error`)}),Yn=J({mutationFn:t=>Q.updatePrinter(e.id,{is_active:t}),onSuccess:(t,n)=>{M.invalidateQueries({queryKey:[`printers`]}),M.invalidateQueries({queryKey:[`printerStatus`,e.id]}),P(j(n?`printers.maintenance.toastExited`:`printers.maintenance.toastEntered`,{name:e.name}),`success`)},onError:e=>P(e.message||j(`printers.toast.failedToUpdateSetting`),`error`)}),[Xn,Zn]=(0,y.useState)(!1),Qn=()=>{G?.state===`RUNNING`||G?.state===`PAUSE`?Zn(!0):Yn.mutate(!1)},er=(G?.state===`RUNNING`||G?.state===`PAUSE`)&&(G?.printable_objects_count??0)>=2,{data:tr}=q({queryKey:[`printableObjects`,e.id],queryFn:()=>Q.getPrintableObjects(e.id),enabled:Me||er,refetchInterval:Me?5e3:er?3e4:!1}),[nr,rr]=(0,y.useState)(null),ir=(0,y.useRef)(!1),ar=(0,y.useRef)(null),or=(0,y.useRef)(!1),sr=J({mutationFn:({amsId:t,slotId:n})=>Q.refreshAmsSlot(e.id,t,n),onMutate:({amsId:e,slotId:t})=>{ar.current&&clearTimeout(ar.current),ir.current=!1,or.current=!1,rr({amsId:e,slotId:t}),setTimeout(()=>{or.current=!0},2e3),ar.current=setTimeout(()=>{rr(null)},3e4)},onSuccess:e=>{P(e.message||j(`printers.toast.rfidRereadInitiated`))},onError:e=>{P(e.message||j(`printers.toast.failedToRereadRfid`),`error`),ar.current&&clearTimeout(ar.current),rr(null)}}),cr=J({mutationFn:({trayId:t})=>Q.loadAmsTray(e.id,t),onSuccess:e=>{P(e.message||j(`printers.toast.loadInitiated`))},onError:e=>{P(e.message||j(`printers.toast.failedToLoad`),`error`)}}),lr=J({mutationFn:()=>Q.unloadAms(e.id),onSuccess:e=>{P(e.message||j(`printers.toast.unloadInitiated`))},onError:e=>{P(e.message||j(`printers.toast.failedToUnload`),`error`)}}),[ur,dr]=(0,y.useState)(null),[fr,pr]=(0,y.useState)(null),mr=async()=>{try{dr(await Q.getPlateReferences(e.id))}catch{}},hr=()=>{Jn.mutate(!e.plate_detection_enabled)},gr=async()=>{wt(!0),St(null);let t=G?.chamber_light===!1;Mt(t),t&&(await Q.setChamberLight(e.id,!0),await new Promise(e=>setTimeout(e,2500)));try{St(await Q.checkPlateEmpty(e.id,{includeDebugImage:!0})),mr()}catch(n){P(n instanceof Error?n.message:j(`printers.toast.failedToCheckPlate`),`error`),t&&(await Q.setChamberLight(e.id,!1),Mt(!1))}finally{wt(!1)}},_r=(0,y.useCallback)(async()=>{St(null),jt&&(await Q.setChamberLight(e.id,!1),Mt(!1))},[jt,e.id]),vr=async t=>{Et(!0);try{let n=await Q.calibratePlateDetection(e.id,{label:t});n.success?(P(n.message||j(`printers.toast.calibrationSaved`),`success`),mr(),St(await Q.checkPlateEmpty(e.id,{includeDebugImage:!0}))):P(n.message||j(`printers.toast.calibrationFailed`),`error`)}catch(e){P(e instanceof Error?e.message:j(`printers.toast.calibrationFailed`),`error`)}finally{Et(!1)}},yr=async(t,n)=>{try{await Q.updatePlateReferenceLabel(e.id,t,n),pr(null),mr()}catch(e){P(e instanceof Error?e.message:j(`printers.toast.failedToUpdateLabel`),`error`)}},br=async t=>{try{await Q.deletePlateReference(e.id,t),P(j(`printers.toast.referenceDeleted`),`success`),mr(),St(await Q.checkPlateEmpty(e.id,{includeDebugImage:!0}))}catch(e){P(e instanceof Error?e.message:j(`printers.toast.failedToDeleteReference`),`error`)}},xr=async()=>{if(Dt){At(!0);try{await Q.updatePrinter(e.id,{plate_detection_roi:Dt}),P(j(`printers.toast.detectionAreaSaved`),`success`),Ot(null),St(await Q.checkPlateEmpty(e.id,{includeDebugImage:!0}))}catch(e){P(e instanceof Error?e.message:j(`printers.toast.failedToSaveDetectionArea`),`error`)}finally{At(!1)}}};(0,y.useEffect)(()=>{let e=e=>{e.key===`Escape`&&xt&&_r()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[xt,_r]);let Sr=(0,y.useRef)(null);if((0,y.useEffect)(()=>{if(!nr)return;let e=G?.ams_status_main??0;return e!==0&&(ir.current=!0,Sr.current&&=(clearTimeout(Sr.current),null)),ir.current&&e===0&&(or.current?(ar.current&&clearTimeout(ar.current),rr(null)):Sr.current||=setTimeout(()=>{ar.current&&clearTimeout(ar.current),rr(null)},2e3)),()=>{Sr.current&&clearTimeout(Sr.current)}},[G?.ams_status_main,nr]),(0,y.useEffect)(()=>{if(!I)return;let e=e=>{let t=e.target;st.current?.contains(t)||L(!1)};return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[I]),xn)return null;let Cr=()=>{switch(i){case 1:return`w-10 h-10`;case 2:return`w-14 h-14`;case 3:return`w-16 h-16`;case 4:return`w-20 h-20`;default:return`w-14 h-14`}},wr=()=>{switch(i){case 1:return`text-base truncate`;case 2:return`text-lg`;case 3:return`text-xl`;case 4:return`text-2xl`;default:return`text-lg`}},Tr=()=>{switch(i){case 1:return`mb-2`;case 2:return`mb-4`;case 3:return`mb-5`;case 4:return`mb-6`;default:return`mb-4`}},Er=Jt&&G?.state!==`RUNNING`&&G?.state!==`PAUSE`&&F(`printers:control`),Dr=e=>{e.preventDefault(),ct.current++,ct.current===1&&it(!0)},Or=e=>{e.preventDefault(),e.dataTransfer.dropEffect=Er?`copy`:`none`},kr=e=>{e.preventDefault(),ct.current--,ct.current===0&&it(!1)},Ar=async t=>{if(t.preventDefault(),ct.current=0,it(!1),!Er)return;let n=Array.from(t.dataTransfer.files)[0];if(!n)return;let r=n.name.toLowerCase();if(!r.endsWith(`.gcode`)&&!r.includes(`.gcode.`)){P(j(`printers.dropNotPrintable`,`Only .gcode and .gcode.3mf files can be printed`),`error`);return}ot(!0);try{let t=await Q.uploadLibraryFile(n,null),r=t.metadata?.sliced_for_model,i=DW(e.model);if(r&&i&&r.toLowerCase()!==i.toLowerCase()){await Q.deleteLibraryFile(t.id).catch(()=>{}),P(j(`printers.incompatibleFile`,`This file was sliced for {{slicedFor}}, but this printer is a {{printerModel}}`,{slicedFor:r,printerModel:i}),`error`);return}He({id:t.id,filename:t.filename})}catch{P(j(`common.uploadFailed`,`Upload failed`),`error`)}finally{ot(!1)}},jr=t=>{r!==`compact`||C||t.target.closest(`button, a, input, select, textarea, [role="button"]`)||E?.(e.id)},Mr=`!h-8 !min-h-8 !w-8 !px-0 !py-0`,Nr=({amsId:e,slotId:t,loadTrayId:n,isRefreshing:r,includeRfid:i=!0})=>{let a=G?.state===`RUNNING`;return(0,K.jsxs)(K.Fragment,{children:[i&&(0,K.jsxs)(`button`,{className:`w-full px-2 py-1.5 text-left text-xs flex items-center gap-2 rounded transition-colors ${F(`printers:ams_rfid`)?`text-white hover:bg-bambu-dark-tertiary`:`text-bambu-gray/50 cursor-not-allowed`}`,onClick:n=>{n.stopPropagation(),!(a||!F(`printers:ams_rfid`))&&sr.mutate({amsId:e,slotId:t})},disabled:a||r||!F(`printers:ams_rfid`),title:a?j(`printers.bedJog.disabledWhilePrinting`):F(`printers:ams_rfid`)?void 0:j(`printers.permission.noAmsRfid`),children:[(0,K.jsx)(Dl,{className:`w-3 h-3 ${r?`animate-spin`:``}`}),j(`printers.rfid.reread`)]}),(0,K.jsxs)(`button`,{className:`w-full px-2 py-1.5 text-left text-xs flex items-center gap-2 rounded transition-colors ${F(`printers:control`)?`text-white hover:bg-bambu-dark-tertiary`:`text-bambu-gray/50 cursor-not-allowed`}`,onClick:e=>{e.stopPropagation(),!(a||!F(`printers:control`))&&cr.mutate({trayId:n})},disabled:a||!F(`printers:control`),title:a?j(`printers.bedJog.disabledWhilePrinting`):F(`printers:control`)?void 0:j(`printers.permission.noControl`),children:[(0,K.jsx)(qc,{className:`w-3 h-3`}),j(`printers.ams.load`)]}),(0,K.jsxs)(`button`,{className:`w-full px-2 py-1.5 text-left text-xs flex items-center gap-2 rounded transition-colors ${F(`printers:control`)?`text-white hover:bg-bambu-dark-tertiary`:`text-bambu-gray/50 cursor-not-allowed`}`,onClick:e=>{e.stopPropagation(),!(a||!F(`printers:control`))&&lr.mutate()},disabled:a||!F(`printers:control`),title:a?j(`printers.bedJog.disabledWhilePrinting`):F(`printers:control`)?void 0:j(`printers.permission.noControl`),children:[(0,K.jsx)(Jc,{className:`w-3 h-3`}),j(`printers.ams.unload`)]})]})},Pr=(0,K.jsxs)(`div`,{ref:st,className:`relative flex-shrink-0`,children:[(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>L(!I),title:j(`common.more`,`More`),className:Mr,children:(0,K.jsx)(Us,{className:`w-4 h-4`})}),I&&(0,K.jsxs)(`div`,{className:`absolute left-0 bottom-full mb-2 w-48 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-lg z-20`,children:[(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-sm flex items-center gap-2 ${F(`printers:update`)?`hover:bg-bambu-dark-tertiary`:`opacity-50 cursor-not-allowed`}`,onClick:()=>{F(`printers:update`)&&(te(!0),L(!1))},title:F(`printers:update`)?void 0:j(`printers.permission.noEdit`),children:[(0,K.jsx)(_l,{className:`w-4 h-4`}),j(`common.edit`)]}),(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-sm hover:bg-bambu-dark-tertiary flex items-center gap-2`,onClick:()=>{Le(!0),L(!1)},children:[(0,K.jsx)(Nc,{className:`w-4 h-4`}),j(`printers.printerInformation`)]}),(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-sm flex items-center gap-2 ${F(`printers:update`)?`hover:bg-bambu-dark-tertiary`:`opacity-50 cursor-not-allowed`}`,disabled:Yn.isPending||!F(`printers:update`),onClick:()=>{F(`printers:update`)&&(L(!1),e.is_active===!1?Yn.mutate(!0):Qn())},title:F(`printers:update`)?void 0:j(`printers.permission.noEdit`),children:[(0,K.jsx)(zu,{className:`w-4 h-4`}),e.is_active===!1?j(`printers.maintenance.menuExit`):j(`printers.maintenance.menuEnter`)]}),(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-sm hover:bg-bambu-dark-tertiary flex items-center gap-2`,onClick:()=>{Cn.mutate(),L(!1)},children:[(0,K.jsx)(Dl,{className:`w-4 h-4`}),j(`printers.reconnect`)]}),(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-sm hover:bg-bambu-dark-tertiary flex items-center gap-2 disabled:opacity-50`,disabled:wn.isPending,onClick:()=>{wn.mutate(),L(!1)},children:[(0,K.jsx)(Al,{className:`w-4 h-4 ${wn.isPending?`animate-spin`:``}`}),j(`printers.forceRefresh`)]}),(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-sm hover:bg-bambu-dark-tertiary flex items-center gap-2`,onClick:()=>{H(!0),L(!1)},children:[(0,K.jsx)(pu,{className:`w-4 h-4`}),j(`printers.mqttDebug`)]}),(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-sm hover:bg-bambu-dark-tertiary flex items-center gap-2`,onClick:()=>{ze(!0),L(!1)},children:[(0,K.jsx)(su,{className:`w-4 h-4`}),j(`diagnostic.runButton`)]}),(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-sm flex items-center gap-2 ${F(`printers:delete`)?`text-red-400 hover:bg-bambu-dark-tertiary`:`text-red-400/50 cursor-not-allowed`}`,onClick:()=>{F(`printers:delete`)&&(z(!0),L(!1))},title:F(`printers:delete`)?void 0:j(`printers.permission.noDelete`),children:[(0,K.jsx)(yu,{className:`w-4 h-4`}),j(`common.delete`)]})]})]});return(0,K.jsxs)(yd,{id:`printer-card-${e.id}`,className:`relative flex h-full flex-col ${w?`ring-2 ring-bambu-green`:``} ${C||r===`compact`?`cursor-pointer`:``}`,onClick:jr,onDragEnter:Dr,onDragOver:Or,onDragLeave:kr,onDrop:Ar,children:[C&&(0,K.jsx)(`div`,{className:`absolute inset-0 z-20 flex items-start p-2`,onClick:t=>{t.stopPropagation(),T?.(e.id)},children:w?(0,K.jsx)(ru,{className:`w-5 h-5 text-bambu-green`}):(0,K.jsx)(au,{className:`w-5 h-5 text-bambu-gray`})}),(rt||at)&&(0,K.jsx)(`div`,{className:`absolute inset-0 z-10 rounded-xl border-2 border-dashed flex items-center justify-center transition-colors ${at?`bg-bambu-green/10 border-bambu-green/50`:Er?`bg-bambu-green/10 border-bambu-green`:`bg-red-500/10 border-red-500/50`}`,children:(0,K.jsx)(`div`,{className:`text-center`,children:at?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(X,{className:`w-8 h-8 mx-auto mb-2 text-bambu-green animate-spin`}),(0,K.jsx)(`p`,{className:`text-sm font-medium text-bambu-green`,children:j(`common.uploading`,`Uploading...`)})]}):Er?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(wl,{className:`w-8 h-8 mx-auto mb-2 text-bambu-green`}),(0,K.jsx)(`p`,{className:`text-sm font-medium text-bambu-green`,children:j(`printers.dropToPrint`,`Drop to print`)})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Bu,{className:`w-8 h-8 mx-auto mb-2 text-red-400`}),(0,K.jsx)(`p`,{className:`text-sm font-medium text-red-400`,children:j(`printers.cannotPrint`,`Printer busy`)})]})})}),(0,K.jsxs)(xd,{className:`${i>=3?`p-5`:``} flex flex-1 flex-col`,children:[(0,K.jsxs)(`div`,{className:Tr(),children:[(0,K.jsx)(`div`,{className:`flex items-start justify-between gap-2`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-3 min-w-0 flex-1`,children:[(0,K.jsx)(`img`,{src:bT(e.model),alt:e.model||j(`common.printer`),className:`object-contain rounded-lg flex-shrink-0 ${Cr()}`}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,K.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2`,children:[(0,K.jsx)(`h3`,{className:`font-semibold text-white ${wr()}`,children:e.name}),r===`compact`&&(()=>{let e=G?.connected&&G.hms_errors?qp(G.hms_errors):[],t=e.some(e=>e.severity<=2),n=e.length>0,r=G?.connected?t?`bg-status-error`:n?`bg-status-warning`:`bg-status-ok`:`bg-status-error`,i=G?.connected?n?`${e.length} HMS ${e.length===1?`error`:`errors`}`:j(`printers.connection.connected`):j(`printers.connection.offline`);return(0,K.jsx)(`div`,{className:`w-2 h-2 rounded-full flex-shrink-0 ${r}`,title:i})})()]}),r===`compact`&&hn&&(0,K.jsx)(`button`,{type:`button`,onClick:()=>Fn.mutate(),disabled:Fn.isPending||!F(`printers:clear_plate`),"aria-label":j(`printers.plateStatus.markCleared`),className:`inline-flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-md bg-yellow-500/20 border border-yellow-400/40 text-yellow-400 hover:bg-yellow-500/30 transition-colors disabled:opacity-50`,title:F(`printers:clear_plate`)?j(`printers.plateStatus.markCleared`):j(`printers.permission.noControl`),children:Fn.isPending?(0,K.jsx)(X,{className:`w-3 h-3 animate-spin`}):(0,K.jsx)(XU,{className:`w-3 h-3`})})]}),(0,K.jsxs)(`p`,{className:`text-sm text-bambu-gray`,children:[e.model||`Unknown Model`,r===`expanded`&&G?.nozzles&&G.nozzles[0]?.nozzle_diameter&&(0,K.jsxs)(`span`,{className:`ml-1.5 text-bambu-gray`,title:G.nozzles[0].nozzle_type||`Nozzle`,children:[`• `,G.nozzles[0].nozzle_diameter,`mm`]}),r===`expanded`&&n&&n.total_print_hours>0&&(0,K.jsxs)(`span`,{className:`ml-2 text-bambu-gray`,children:[(0,K.jsx)(xs,{className:`w-3 h-3 inline-block mr-1`}),Math.round(n.total_print_hours),`h`]})]})]})]})}),r===`expanded`&&(0,K.jsx)(`div`,{className:`mt-2`,children:(0,K.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[e.is_active===!1?(0,K.jsxs)(`span`,{className:`flex items-center gap-1.5 px-2 py-1 rounded-full text-xs bg-amber-500/20 text-amber-400`,title:j(`printers.maintenance.subtitle`),children:[(0,K.jsx)(zu,{className:`w-3 h-3`}),j(`printers.maintenance.pillLabel`)]}):(0,K.jsxs)(`span`,{className:`flex items-center gap-1.5 px-2 py-1 rounded-full text-xs ${G?.connected?`bg-status-ok/20 text-status-ok`:`bg-status-error/20 text-status-error`}`,children:[G?.connected?(0,K.jsx)(Vc,{className:`w-3 h-3`}):(0,K.jsx)(Tu,{className:`w-3 h-3`}),G?.connected?j(`printers.connection.connected`):j(`printers.connection.offline`)]}),e.is_active!==!1&&!G?.connected&&(0,K.jsxs)(`button`,{onClick:()=>ze(!0),className:`flex items-center gap-1 px-2 py-1 rounded-full text-xs cursor-pointer bg-bambu-dark-tertiary text-bambu-gray hover:text-white transition-colors`,title:j(`diagnostic.runButton`),children:[(0,K.jsx)(su,{className:`w-3 h-3`}),j(`diagnostic.runButton`)]}),G?.connected&&G?.wired_network&&(0,K.jsxs)(`span`,{className:`flex items-center gap-1 px-2 py-1 rounded-full text-xs bg-status-ok/20 text-status-ok`,title:j(`printers.connection.ethernet`,`Ethernet`),children:[(0,K.jsx)(qo,{className:`w-3 h-3`}),j(`printers.connection.ethernet`,`Ethernet`)]}),G?.connected&&!G?.wired_network&&Kt!=null&&(0,K.jsxs)(`span`,{className:`flex items-center gap-1 px-2 py-1 rounded-full text-xs ${Kt>=-50||Kt>=-60?`bg-status-ok/20 text-status-ok`:Kt>=-70?`bg-status-warning/20 text-status-warning`:Kt>=-80?`bg-orange-500/20 text-orange-600`:`bg-status-error/20 text-status-error`}`,title:`WiFi: ${Kt} dBm - ${j(xT(Kt).labelKey)}`,children:[(0,K.jsx)(Jl,{className:`w-3 h-3`}),Kt,`dBm`]}),G?.connected&&(()=>{let e=G.hms_errors?qp(G.hms_errors):[];return(0,K.jsxs)(`button`,{onClick:()=>de(!0),className:`flex items-center gap-1 px-2 py-1 rounded-full text-xs cursor-pointer hover:opacity-80 transition-opacity ${e.length>0?e.some(e=>e.severity<=2)?`bg-status-error/20 text-status-error`:`bg-status-warning/20 text-status-warning`:`bg-status-ok/20 text-status-ok`}`,title:j(`printers.clickToViewHmsErrors`),children:[(0,K.jsx)(Su,{className:`w-3 h-3`}),e.length>0?e.length:`OK`]})})(),n&&(0,K.jsxs)(`button`,{onClick:()=>N(`/maintenance`),className:`flex items-center gap-1 px-2 py-1 rounded-full text-xs cursor-pointer hover:opacity-80 transition-opacity ${n.due_count>0?`bg-status-error/20 text-status-error`:n.warning_count>0?`bg-status-warning/20 text-status-warning`:`bg-status-ok/20 text-status-ok`}`,title:n.due_count>0||n.warning_count>0?`${n.due_count>0?`${n.due_count} maintenance due`:``}${n.due_count>0&&n.warning_count>0?`, `:``}${n.warning_count>0?`${n.warning_count} due soon`:``} - Click to view`:j(`printers.maintenanceUpToDate`),children:[(0,K.jsx)(zu,{className:`w-3 h-3`}),n.due_count>0||n.warning_count>0?n.due_count+n.warning_count:`OK`]}),sn>0&&(0,K.jsxs)(`button`,{onClick:()=>N(`/queue`),className:`flex items-center gap-1 px-2 py-1 rounded-full text-xs bg-indigo-500/20 text-indigo-400 hover:opacity-80 transition-opacity`,title:j(`printers.queue.inQueue`,{count:sn}),children:[(0,K.jsx)(Lc,{className:`w-3 h-3`}),sn]}),b&&Nt?.current_version&&Nt?.latest_version?(0,K.jsxs)(`button`,{onClick:()=>bt(!0),className:`flex items-center gap-1 px-2 py-1 rounded-full text-xs hover:opacity-80 transition-opacity ${Nt.update_available?`bg-orange-500/20 text-orange-400`:`bg-status-ok/20 text-status-ok`}`,title:Nt.update_available?j(`printers.firmwareUpdateAvailable`,{current:Nt.current_version,latest:Nt.latest_version}):j(`printers.firmwareUpToDate`,{version:Nt.current_version}),children:[Nt.update_available?(0,K.jsx)(Bs,{className:`w-3 h-3`}):(0,K.jsx)(fs,{className:`w-3 h-3`}),Nt.current_version]}):G?.firmware_version?(0,K.jsx)(`span`,{className:`flex items-center gap-1 px-2 py-1 rounded-full text-xs bg-bambu-dark-tertiary/50 text-bambu-gray`,children:G.firmware_version}):null,G?.connected&&[`X1C`,`X1`,`X1E`,`X2D`,`P2S`,`H2D`,`H2D Pro`,`H2C`,`H2S`].includes(e.model??``)&&(0,K.jsx)(`span`,{className:`flex items-center px-2 py-1 rounded-full text-xs ${G.door_open?`bg-yellow-500/20 text-yellow-400`:`bg-status-ok/20 text-status-ok`}`,title:G.door_open?j(`printers.door.open`):j(`printers.door.closed`),children:G.door_open?(0,K.jsx)(zs,{className:`w-3 h-3`}):(0,K.jsx)(Rs,{className:`w-3 h-3`})})]})})]}),R&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/50 flex items-center justify-center z-50`,children:(0,K.jsx)(yd,{className:`w-full max-w-md mx-4`,children:(0,K.jsxs)(xd,{children:[(0,K.jsxs)(`div`,{className:`flex items-start gap-3 mb-4`,children:[(0,K.jsx)(`div`,{className:`p-2 rounded-full bg-red-500/20`,children:(0,K.jsx)(Su,{className:`w-5 h-5 text-red-400`})}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white`,children:j(`printers.confirm.deleteTitle`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1`,children:j(`printers.confirm.deleteMessage`,{name:e.name})})]})]}),(0,K.jsx)(`div`,{className:`bg-bambu-dark rounded-lg p-3 mb-4`,children:(0,K.jsxs)(`label`,{className:`flex items-start gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:B,onChange:e=>V(e.target.checked),className:`mt-0.5 w-4 h-4 rounded border-bambu-gray bg-bambu-dark-secondary text-bambu-green focus:ring-bambu-green focus:ring-offset-0`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-sm text-white`,children:j(`printers.deleteArchives`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:j(B?`printers.confirm.deleteArchivesNote`:`printers.confirm.keepArchivesNote`)})]})]})}),(0,K.jsxs)(`div`,{className:`flex justify-end gap-2`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>{z(!1),V(!0)},children:j(`common.cancel`)}),(0,K.jsx)($,{variant:`danger`,onClick:()=>{Sn.mutate({deleteArchives:B}),z(!1),V(!0)},children:`Delete`})]})]})})}),e.is_active===!1?(0,K.jsx)(K.Fragment,{children:r===`compact`?(0,K.jsxs)(`div`,{className:`mt-2 flex items-center gap-2 px-2 py-1.5 rounded-full bg-amber-500/15 border border-amber-500/30`,children:[(0,K.jsx)(zu,{className:`w-3 h-3 text-amber-400 shrink-0`}),(0,K.jsx)(`span`,{className:`text-[11px] text-amber-400 font-medium truncate`,children:j(`printers.maintenance.pillLabel`)})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-2`,children:[(0,K.jsx)(`span`,{className:`text-[10px] uppercase tracking-wider text-bambu-gray font-medium`,children:j(`printers.status.title`,`Status`)}),(0,K.jsx)(`div`,{className:`flex-1 h-[2px] bg-bambu-dark-tertiary`})]}),(0,K.jsxs)(`div`,{className:`p-3 bg-amber-500/10 border border-amber-500/30 rounded-[10px] flex items-center gap-3`,children:[(0,K.jsx)(zu,{className:`w-6 h-6 text-amber-400 shrink-0`}),(0,K.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,K.jsx)(`p`,{className:`text-sm text-amber-400 font-medium`,children:j(`printers.maintenance.title`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:j(`printers.maintenance.subtitle`)})]}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,disabled:Yn.isPending||!F(`printers:update`),onClick:()=>Yn.mutate(!0),title:F(`printers:update`)?void 0:j(`printers.permission.noEdit`),children:j(`printers.maintenance.exitButton`)})]})]})}):G?.connected&&(0,K.jsxs)(K.Fragment,{children:[r===`compact`?(()=>{let e=G.hms_errors?qp(G.hms_errors):[],t=G.state===`FAILED`||e.length>0,n=G.state===`RUNNING`||G.state===`PAUSE`?Math.max(0,Math.min(100,G.progress||0)):hn||t?100:0,r=G.state===`RUNNING`||G.state===`PAUSE`;return(0,K.jsxs)(`div`,{className:`relative mt-2 flex items-center gap-2`,children:[(0,K.jsx)(`div`,{className:`h-1.5 min-w-0 flex-1 overflow-hidden rounded-full bg-bambu-dark-tertiary`,children:(0,K.jsx)(`div`,{className:`${t?`bg-status-error`:G.state===`PAUSE`?`bg-status-warning`:`bg-bambu-green`} h-1.5 rounded-full transition-all`,style:{width:`${n}%`}})}),(0,K.jsx)(`span`,{className:`w-9 shrink-0 text-right text-[11px] leading-none ${r?`text-white`:`text-bambu-gray`}`,children:r?`${Math.round(n)}%`:`---%`})]})})():(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-2`,children:[(0,K.jsx)(`span`,{className:`text-[10px] uppercase tracking-wider text-bambu-gray font-medium`,children:j(`printers.status.title`,`Status`)}),(0,K.jsx)(`div`,{className:`flex-1 h-[2px] bg-bambu-dark-tertiary`})]}),(()=>{let t=!!(G.current_print&&(G.state===`RUNNING`||G.state===`PAUSE`)),n=!t&&mn&&_n,r=t?gn:n?_n.name:null,i=t?G.cover_url:n?_n.coverUrl:null,a=t?G.progress||0:n?100:0;return(0,K.jsxs)(`div`,{className:`p-2 bg-bambu-dark rounded-[10px] relative overflow-hidden`,children:[(0,K.jsxs)(`button`,{onClick:()=>Ne(!0),disabled:!t||(G.printable_objects_count??0)<2||!F(`printers:control`),className:`absolute top-2 right-2 p-1.5 rounded transition-colors z-10 ${t&&(G.printable_objects_count??0)>=2&&F(`printers:control`)?`text-bambu-gray hover:text-white hover:bg-white/10`:`text-bambu-gray/30 cursor-not-allowed`}`,title:F(`printers:control`)?t?(G.printable_objects_count??0)>=2?j(`printers.skipObjects.tooltip`):j(`printers.skipObjects.requiresMultiple`):j(`printers.skipObjects.onlyWhilePrinting`):j(`printers.permission.noControl`),children:[(0,K.jsx)(dT,{className:`w-4 h-4`}),tr&&tr.skipped_count>0&&(0,K.jsx)(`span`,{className:`absolute -top-1 -right-1 min-w-[16px] h-4 px-1 flex items-center justify-center text-[10px] font-bold bg-red-500 text-white rounded-full`,children:tr.skipped_count})]}),(0,K.jsxs)(`div`,{className:`flex items-stretch gap-2`,children:[(0,K.jsx)(Bke,{url:i,printName:r||void 0,className:`w-24 h-24 max-[520px]:w-20 max-[520px]:h-20`}),(0,K.jsxs)(`div`,{className:`flex h-24 max-[520px]:h-20 min-w-0 flex-1 flex-col justify-between pt-1`,children:[(0,K.jsxs)(`div`,{className:`flex min-h-[18px] items-center gap-2 pr-8`,children:[(0,K.jsx)(`p`,{className:`min-w-0 truncate text-sm text-bambu-gray`,children:Wke(G.state,G.stg_cur_name)}),bn]}),(0,K.jsx)(`p`,{className:`min-h-[18px] truncate pr-8 text-sm ${r?`text-white`:`text-bambu-gray/70`}`,children:r||j(`printers.noActiveJob`,`No active job`)}),(0,K.jsxs)(`div`,{className:`flex h-3 items-center gap-2 text-sm`,children:[(0,K.jsx)(`div`,{className:`h-1.5 min-w-0 flex-1 rounded-full bg-bambu-dark-tertiary`,children:(0,K.jsx)(`div`,{className:`${t?G.state===`PAUSE`?`bg-status-warning`:`bg-bambu-green`:n?`bg-bambu-green`:`bg-bambu-dark-tertiary`} h-1.5 rounded-full transition-all`,style:{width:`${a}%`}})}),(0,K.jsx)(`span`,{className:`w-9 shrink-0 pr-1 text-right text-[11px] leading-none ${t||n?`text-white`:`text-bambu-gray`}`,children:t||n?`${Math.round(a)}%`:`---%`})]}),(0,K.jsx)(`div`,{className:`flex min-h-[16px] items-center gap-2 text-xs text-bambu-gray`,children:t?(0,K.jsxs)(K.Fragment,{children:[G.remaining_time!=null&&G.remaining_time>0&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`span`,{className:`flex items-center gap-1`,children:[(0,K.jsx)(xs,{className:`w-3 h-3`}),kf(G.remaining_time*60)]}),(0,K.jsxs)(`span`,{className:`text-bambu-green font-medium`,title:j(`printers.estimatedCompletion`),children:[`ETA `,Of(G.remaining_time,g,j)]})]}),G.layer_num!=null&&G.total_layers!=null&&G.total_layers>0&&(0,K.jsxs)(`span`,{className:`flex items-center gap-1`,children:[(0,K.jsx)(Lc,{className:`w-3 h-3`}),G.layer_num,`/`,G.total_layers]}),un&&(0,K.jsxs)(`span`,{className:`flex items-center gap-1`,title:`Started by ${un}`,children:[(0,K.jsx)(Du,{className:`w-3 h-3`}),un]})]}):fn?(0,K.jsxs)(`p`,{className:`truncate`,title:fn.print_name||fn.filename,children:[`Last: `,fn.print_name||fn.filename,fn.completed_at&&(0,K.jsxs)(`span`,{className:`ml-1 text-bambu-gray/60`,children:[`• `,Tf(fn.completed_at,{month:`short`,day:`numeric`})]})]}):(0,K.jsx)(`span`,{children:j(`printers.readyToPrint`)})})]})]}),(0,K.jsx)(Tle,{printerId:e.id,printerModel:e.model,loadedFilamentTypes:Ft,loadedFilaments:It,variant:`panelExtension`})]})})()]}),G.temperatures&&r===`expanded`&&(()=>{let t=G.temperatures.nozzle_heating||G.temperatures.nozzle_2_heating||!1,n=G.temperatures.bed_heating||!1,r=G.temperatures.chamber_heating||!1,i=e.nozzle_count===2||G.temperatures.nozzle_2!==void 0,a=(()=>{let e=[`nozzle`];return G.temperatures.nozzle_2!==void 0&&e.push(`nozzle_2`),e.push(`bed`),G.temperatures.chamber!==void 0&&e.push(`chamber`),e})(),o=G.active_extruder===1?`L`:`R`,s=G.nozzle_rack?.find(e=>e.id===1),c=G.nozzle_rack?.find(e=>e.id===0),l=c||s,u=G.connected&&F(`printers:control`),d=u?void 0:j(`printers.permission.noControl`),f=`relative text-center px-2 py-1.5 bg-bambu-dark rounded-lg flex-1 flex flex-col justify-center items-center transition-colors ${u?`cursor-pointer hover:bg-bambu-dark-tertiary`:`cursor-default opacity-80`}`,p=Gke.has(e.model??``),m=[{key:`part`,label:j(`printers.fans.partCooling`),value:G.cooling_fan_speed??0,Icon:Xs,activeClass:`text-cyan-400`},{key:`aux`,label:j(`printers.fans.auxiliary`),value:G.big_fan1_speed??0,Icon:Lu,activeClass:`text-blue-400`},...p?[{key:`chamber`,label:j(`printers.fans.chamber`),value:G.big_fan2_speed??0,Icon:Do,activeClass:`text-green-400`}]:[]];return(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`mt-2 flex items-stretch gap-1.5 flex-wrap`,children:[(0,K.jsxs)(`div`,{className:f,title:d,onClick:()=>u&&Te(we===`nozzle-temp`?null:`nozzle-temp`),children:[(0,K.jsx)(`button`,{type:`button`,className:`absolute top-0.5 right-0.5 p-0.5 rounded text-bambu-gray hover:text-white hover:bg-white/10 transition-colors`,title:j(`printers.heaterHistory.openLabel`,`View heater history`),onClick:e=>{e.stopPropagation(),ft({initialKind:`nozzle`,availableKinds:a})},children:(0,K.jsx)($o,{className:`w-2.5 h-2.5`})}),(0,K.jsx)(_W,{className:`w-3.5 h-3.5 mb-0.5`,color:`text-orange-400`,isHeating:t}),G.temperatures.nozzle_2===void 0?l?(0,K.jsx)(gW,{slot:l,index:0,activeStatus:!0,filamentName:l.filament_id?Lt?.[l.filament_id]?.name:void 0,children:(0,K.jsxs)(`div`,{className:`cursor-default`,children:[(0,K.jsx)(`p`,{className:`text-[9px] text-bambu-gray`,children:j(`printers.temperatures.nozzle`)}),(0,K.jsxs)(`p`,{className:`text-[11px] text-white`,children:[Math.round(G.temperatures.nozzle||0),`°C`]})]})}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`p`,{className:`text-[9px] text-bambu-gray`,children:j(`printers.temperatures.nozzle`)}),(0,K.jsxs)(`p`,{className:`text-[11px] text-white`,children:[Math.round(G.temperatures.nozzle||0),`°C`]})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`p`,{className:`text-[9px] text-bambu-gray`,children:`L / R`}),(0,K.jsxs)(`p`,{className:`text-[11px] text-white`,children:[Math.round(G.temperatures.nozzle||0),`° / `,Math.round(G.temperatures.nozzle_2||0),`°`]})]}),we===`nozzle-temp`&&(i?(0,K.jsx)(CW,{title:`Set Nozzle Temperatures`,widthClass:`w-[300px]`,popoverWidth:300,popoverHeight:260,isPending:In.isPending,onClose:()=>Te(null),children:(0,K.jsxs)(`div`,{className:`grid grid-cols-2 gap-2 px-3 py-2.5`,children:[(0,K.jsx)(wW,{label:`Left Temp`,current:G.temperatures.nozzle,target:G.temperatures.nozzle_target,isActive:o===`L`,isPending:In.isPending,onSubmit:e=>In.mutate({target:e,nozzle:1}),options:Wp(D,`C`)}),(0,K.jsx)(wW,{label:`Right Temp`,current:G.temperatures.nozzle_2,target:G.temperatures.nozzle_2_target,isActive:o===`R`,isPending:In.isPending,onSubmit:e=>In.mutate({target:e,nozzle:0}),options:Wp(D,`C`)})]})}):(0,K.jsx)(CW,{title:`Set Nozzle Temperature`,unit:`°C`,customMin:0,customMax:320,isPending:In.isPending,options:Wp(D,`C`),onClose:()=>Te(null),onSubmit:e=>In.mutate({target:e,nozzle:G.active_extruder??0})}))]}),(0,K.jsxs)(`div`,{className:f,title:d,onClick:()=>u&&Te(we===`bed-temp`?null:`bed-temp`),children:[(0,K.jsx)(`button`,{type:`button`,className:`absolute top-0.5 right-0.5 p-0.5 rounded text-bambu-gray hover:text-white hover:bg-white/10 transition-colors`,title:j(`printers.heaterHistory.openLabel`,`View heater history`),onClick:e=>{e.stopPropagation(),ft({initialKind:`bed`,availableKinds:a})},children:(0,K.jsx)($o,{className:`w-2.5 h-2.5`})}),(0,K.jsx)(_W,{className:`w-3.5 h-3.5 mb-0.5`,color:`text-blue-400`,isHeating:n}),(0,K.jsx)(`p`,{className:`text-[9px] text-bambu-gray`,children:j(`printers.temperatures.bed`)}),(0,K.jsxs)(`p`,{className:`text-[11px] text-white`,children:[Math.round(G.temperatures.bed||0),`°C`]}),we===`bed-temp`&&(0,K.jsx)(CW,{title:`Set Bed Temperature`,unit:`°C`,customMin:0,customMax:140,isPending:Ln.isPending,options:Wp(O,`C`),onClose:()=>Te(null),onSubmit:e=>Ln.mutate(e)})]}),G.temperatures.chamber!==void 0&&(()=>{let e=G.supports_chamber_heater===!0;return(0,K.jsxs)(`div`,{className:e?f:`relative text-center px-2 py-1.5 bg-bambu-dark rounded-lg flex-1 flex flex-col justify-center items-center`,title:e?d:void 0,onClick:e?()=>u&&Te(we===`chamber-temp`?null:`chamber-temp`):void 0,children:[(0,K.jsx)(`button`,{type:`button`,className:`absolute top-0.5 right-0.5 p-0.5 rounded text-bambu-gray hover:text-white hover:bg-white/10 transition-colors`,title:j(`printers.heaterHistory.openLabel`,`View heater history`),onClick:e=>{e.stopPropagation(),ft({initialKind:`chamber`,availableKinds:a})},children:(0,K.jsx)($o,{className:`w-2.5 h-2.5`})}),(0,K.jsx)(_W,{className:`w-3.5 h-3.5 mb-0.5`,color:`text-green-400`,isHeating:r}),(0,K.jsx)(`p`,{className:`text-[9px] text-bambu-gray`,children:j(`printers.temperatures.chamber`)}),(0,K.jsxs)(`p`,{className:`text-[11px] text-white`,children:[Math.round(G.temperatures.chamber||0),`°C`]}),e&&we===`chamber-temp`&&(0,K.jsx)(CW,{title:`Set Chamber Temperature`,unit:`°C`,customMin:0,customMax:60,isPending:Rn.isPending,options:Wp(k,`C`),onClose:()=>Te(null),onSubmit:e=>Rn.mutate(e)})]})})(),i&&(0,K.jsx)(Ake,{leftSlot:s,rightSlot:c,activeNozzle:o,filamentInfo:Lt,children:(0,K.jsxs)(`div`,{className:`relative text-center px-3 py-1.5 bg-bambu-dark rounded-lg h-full flex flex-col justify-center items-center transition-colors ${u?`cursor-pointer hover:bg-bambu-dark-tertiary`:`cursor-default opacity-80`}`,title:u?j(`printers.activeNozzle`,{nozzle:j(o===`L`?`common.left`:`common.right`)}):d,onClick:()=>u&&Te(we===`nozzle-select`?null:`nozzle-select`),children:[(0,K.jsx)(Rke,{className:`w-3.5 h-3.5 mb-0.5 text-amber-400`}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsxs)(`span`,{className:`text-[11px] font-bold ${o===`L`?`text-amber-400`:`text-gray-500`}`,children:[`L`,s?.nozzle_diameter?` ${s.nozzle_diameter}`:``]}),(0,K.jsx)(`span`,{className:`text-[9px] text-bambu-gray/40`,children:`·`}),(0,K.jsxs)(`span`,{className:`text-[11px] font-bold ${o===`R`?`text-amber-400`:`text-gray-500`}`,children:[`R`,c?.nozzle_diameter?` ${c.nozzle_diameter}`:``]})]}),(0,K.jsx)(`p`,{className:`text-[9px] text-bambu-gray`,children:j(`printers.temperatures.nozzle`)}),we===`nozzle-select`&&(0,K.jsx)(CW,{title:`Set Nozzle Selection`,widthClass:`w-[300px]`,popoverWidth:300,popoverHeight:140,isPending:Bn.isPending,options:[{label:`Left`,value:1},{label:`Right`,value:0}],onClose:()=>Te(null),onSubmit:e=>Bn.mutate(e)})]})}),G.nozzle_rack&&G.nozzle_rack.some(e=>e.id>=2)&&(0,K.jsx)(jke,{slots:G.nozzle_rack,filamentInfo:Lt})]}),(0,K.jsx)(`div`,{className:`mt-2 flex items-center gap-1.5`,children:m.map(({key:e,label:t,value:n,Icon:r,activeClass:i})=>{let a=n>0;return(0,K.jsxs)(`div`,{className:`relative px-2 py-1.5 bg-bambu-dark rounded-lg flex-1 min-w-0 flex items-center justify-center gap-1 transition-colors ${u?`cursor-pointer hover:bg-bambu-dark-tertiary`:`cursor-default opacity-80`}`,title:u?t:d,onClick:()=>u&&Te(we===`fan-${e}`?null:`fan-${e}`),children:[(0,K.jsx)(r,{className:`w-3 h-3 shrink-0 ${a?i:`text-bambu-gray/50`}`}),(0,K.jsxs)(`span`,{className:`text-[10px] leading-none ${a?`text-white`:`text-bambu-gray/50`}`,children:[n,`%`]}),we===`fan-${e}`&&(0,K.jsx)(CW,{title:`Set ${t} Speed`,unit:`%`,customMin:0,customMax:100,isPending:zn.isPending,options:Wp(A,`%`),onClose:()=>Te(null),onSubmit:t=>zn.mutate({fan:e,speed:t})})]},e)})})]})})(),r===`expanded`&&hn&&(0,K.jsxs)(`button`,{type:`button`,onClick:()=>Fn.mutate(),disabled:Fn.isPending||!F(`printers:clear_plate`),className:`mt-2 w-full inline-flex items-center justify-center gap-2 px-3 py-1.5 rounded-lg bg-yellow-500/20 border border-yellow-400/40 text-yellow-400 hover:bg-yellow-500/30 transition-colors text-xs font-medium disabled:opacity-50`,title:F(`printers:clear_plate`)?j(`printers.plateStatus.markCleared`):j(`printers.permission.noControl`),children:[Fn.isPending?(0,K.jsx)(X,{className:`w-3 h-3 animate-spin`}):(0,K.jsx)(XU,{className:`w-4 h-4`}),j(`printers.plateStatus.markCleared`)]}),r===`expanded`&&(()=>{let t=G.state===`RUNNING`,n=G.state===`PAUSE`,r=t||n,i=Mn.isPending||Nn.isPending||Pn.isPending,a=`bg-bambu-dark text-bambu-gray/50 cursor-not-allowed opacity-50`,o=`flex h-8 w-8 items-center justify-center rounded-lg text-xs font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed`,s=`flex h-8 w-20 items-center justify-center gap-1 px-2 rounded-lg text-xs font-medium transition-colors`;return(0,K.jsxs)(`div`,{className:`mt-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-2`,children:[(0,K.jsx)(`span`,{className:`text-[10px] uppercase tracking-wider text-bambu-gray font-medium`,children:j(`printers.controls`)}),(0,K.jsx)(`div`,{className:`flex-1 h-[2px] bg-bambu-dark-tertiary`})]}),(0,K.jsxs)(`div`,{className:`flex flex-wrap items-start justify-between gap-x-2 gap-y-2`,children:[(0,K.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 min-w-0`,children:[(0,K.jsx)(`button`,{onClick:()=>Vn.mutate(!G.chamber_light),disabled:!G.connected||Vn.isPending||!F(`printers:control`),className:`${o} ${G.chamber_light?`bg-yellow-500/10 text-yellow-400 hover:bg-yellow-500/20`:`bg-bambu-dark text-bambu-gray/50 hover:bg-bambu-dark-tertiary hover:text-white`}`,title:F(`printers:control`)?G.chamber_light?j(`printers.chamberLightOff`):j(`printers.chamberLightOn`):j(`printers.permission.noControl`),children:(0,K.jsx)(uT,{on:G.chamber_light??!1,className:`w-4 h-4`})}),[`P2S`,`X2D`,`H2D`,`H2C`,`H2S`].includes(e.model??``)&&(()=>{let t=G.airduct_mode===1,n=t?ic:tu,r=t?`text-orange-400`:`text-sky-400`,i=t?`bg-orange-500/10 text-orange-400 hover:bg-orange-500/20`:`bg-sky-500/10 text-sky-400 hover:bg-sky-500/20`;return(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`button`,{onClick:()=>xe(be===e.id?null:e.id),disabled:!F(`printers:control`),className:`${o} ${i}`,title:`${j(`printers.airduct.title`)}: ${j(t?`printers.airduct.heating`:`printers.airduct.cooling`)}`,children:(0,K.jsx)(n,{className:`w-4 h-4 ${r}`})}),be===e.id&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`div`,{className:`fixed inset-0 z-40`,onClick:()=>xe(null)}),(0,K.jsx)(`div`,{className:`absolute bottom-full left-0 mb-1 z-50 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-lg py-1 min-w-[130px]`,children:[{mode:`cooling`,label:j(`printers.airduct.cooling`),modeId:0},{mode:`heating`,label:j(`printers.airduct.heating`),modeId:1}].map(({mode:e,label:t,modeId:n})=>(0,K.jsxs)(`button`,{onClick:()=>{Un.mutate(e),xe(null)},className:`w-full text-left px-3 py-1.5 text-xs transition-colors flex items-center gap-2 ${G.airduct_mode===n?`text-bambu-green bg-bambu-green/10`:`text-white hover:bg-bambu-dark-tertiary`}`,children:[e===`heating`?(0,K.jsx)(ic,{className:`w-3 h-3`}):(0,K.jsx)(tu,{className:`w-3 h-3`}),t]},e))})]})]})})(),(()=>{let t=F(`printers:control`),n=r||!t,i=`flex h-8 w-8 items-center justify-center rounded bg-indigo-500/15 text-indigo-300 transition-colors hover:bg-indigo-500/30 disabled:cursor-not-allowed disabled:opacity-50`,a=t=>{let n=t*Ee*1,r=`bambuddy.bedJog.warned.${e.id}`;(()=>{try{return sessionStorage.getItem(r)===`1`}catch{return!1}})()?Wn.mutate({distance:n,force:!0}):ke({distance:n})},s=(e,t)=>{Gn.mutate({x:e,y:t})},c=e=>{Kn.mutate(e)};return(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`button`,{onClick:()=>Ce(Se===e.id?null:e.id),disabled:n,className:`${o} ${n?`bg-bambu-dark text-bambu-gray/50 cursor-not-allowed`:`bg-indigo-500/10 text-indigo-400 hover:bg-indigo-500/20`}`,title:j(t?r?`printers.bedJog.disabledWhilePrinting`:`printers.bedJog.title`:`printers.permission.noControl`),children:(0,K.jsx)(cl,{className:`w-4 h-4`})}),Se===e.id&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`div`,{className:`fixed inset-0 z-40`,onClick:()=>Ce(null)}),(0,K.jsxs)(`div`,{className:`absolute bottom-full left-0 mb-1 z-50 flex w-[216px] flex-col overflow-hidden rounded-xl border border-bambu-dark-tertiary bg-bambu-dark-secondary shadow-2xl`,children:[(0,K.jsx)(`div`,{className:`shrink-0 px-3 py-2.5 text-center text-sm font-medium text-white`,children:j(`printers.bedJog.title`)}),(0,K.jsx)(`div`,{className:`h-px bg-bambu-dark-tertiary`}),(0,K.jsx)(`div`,{className:`flex justify-center px-3 py-2.5`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-center gap-3`,children:[(0,K.jsxs)(`div`,{className:`grid grid-cols-3 gap-1`,children:[(0,K.jsx)(`div`,{}),(0,K.jsx)(`button`,{onClick:()=>s(0,Ee),disabled:Gn.isPending,className:i,"aria-label":`Move Y forward`,children:(0,K.jsx)(Io,{className:`w-4 h-4`})}),(0,K.jsx)(`div`,{}),(0,K.jsx)(`button`,{onClick:()=>s(-Ee,0),disabled:Gn.isPending,className:i,"aria-label":`Move X left`,children:(0,K.jsx)(jo,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{onClick:()=>{Ce(null),qn.mutate(`all`)},disabled:qn.isPending,className:i,"aria-label":j(`printers.bedJog.homeZ`),children:(0,K.jsx)(kc,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{onClick:()=>s(Ee,0),disabled:Gn.isPending,className:i,"aria-label":`Move X right`,children:(0,K.jsx)(No,{className:`w-4 h-4`})}),(0,K.jsx)(`div`,{}),(0,K.jsx)(`button`,{onClick:()=>s(0,-Ee),disabled:Gn.isPending,className:i,"aria-label":`Move Y back`,children:(0,K.jsx)(Ao,{className:`w-4 h-4`})}),(0,K.jsx)(`div`,{})]}),(0,K.jsxs)(`div`,{className:`flex flex-col items-center gap-1`,children:[(0,K.jsx)(`button`,{onClick:()=>a(-1),disabled:Wn.isPending,className:i,"aria-label":j(`printers.bedJog.up`),children:(0,K.jsx)(Io,{className:`w-4 h-4`})}),(0,K.jsx)(`div`,{className:`flex h-8 w-8 items-center justify-center text-bambu-gray/80`,children:(0,K.jsx)(Lc,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{onClick:()=>a(1),disabled:Wn.isPending,className:i,"aria-label":j(`printers.bedJog.down`),children:(0,K.jsx)(Ao,{className:`w-4 h-4`})})]}),(0,K.jsxs)(`div`,{className:`flex flex-col items-center gap-1`,children:[(0,K.jsx)(`button`,{onClick:()=>c(-Ee),disabled:Kn.isPending,className:i,"aria-label":`Retract filament`,children:(0,K.jsx)(Io,{className:`w-4 h-4`})}),(0,K.jsx)(`div`,{className:`flex h-8 w-8 items-center justify-center text-bambu-gray/80`,children:(0,K.jsx)(`span`,{className:`text-sm font-semibold leading-none`,children:`E`})}),(0,K.jsx)(`button`,{onClick:()=>c(Ee),disabled:Kn.isPending,className:i,"aria-label":`Extrude filament`,children:(0,K.jsx)(Ao,{className:`w-4 h-4`})})]})]})}),(0,K.jsx)(`div`,{className:`h-px bg-bambu-dark-tertiary`}),(0,K.jsxs)(`div`,{className:`px-3 pt-2.5 pb-3`,children:[(0,K.jsx)(`div`,{className:`mb-1 text-[9px] uppercase tracking-wider text-bambu-gray/70`,children:j(`printers.bedJog.step`)}),(0,K.jsx)(`div`,{className:`flex gap-1`,children:[1,10,50].map(e=>(0,K.jsx)(`button`,{onClick:()=>De(e),className:`flex-1 px-1 py-1 rounded text-[10px] transition-colors ${Ee===e?`bg-bambu-green/20 text-bambu-green`:`bg-bambu-dark text-bambu-gray hover:bg-bambu-dark-tertiary`}`,children:e},e))})]})]})]})]})})(),(0,K.jsxs)(`div`,{className:`inline-flex rounded-lg ${e.plate_detection_enabled?`ring-1 ring-green-500`:``}`,children:[(0,K.jsx)(`button`,{onClick:hr,disabled:!G.connected||Jn.isPending||!F(`printers:update`),className:`${o} rounded-r-none ${e.plate_detection_enabled?`bg-green-500/10 text-green-400 hover:bg-green-500/20`:`bg-bambu-dark text-bambu-gray/50 hover:bg-bambu-dark-tertiary hover:text-white`}`,title:F(`printers:update`)?e.plate_detection_enabled?j(`printers.plateDetection.enabledClick`):j(`printers.plateDetection.disabledClick`):j(`printers.plateDetection.noPermission`),children:Jn.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Fl,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{onClick:gr,disabled:!G.connected||Ct||!F(`printers:update`),className:`flex h-8 w-8 items-center justify-center rounded-r-lg border-l border-bambu-dark-tertiary transition-colors disabled:opacity-50 disabled:cursor-not-allowed ${e.plate_detection_enabled?`bg-green-500/10 text-green-400 hover:bg-green-500/20`:`bg-bambu-dark text-bambu-gray/50 hover:bg-bambu-dark-tertiary hover:text-white`}`,title:F(`printers:update`)?j(`printers.plateDetection.manageCalibration`):j(`printers.plateDetection.noPermission`),children:Ct?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(rs,{className:`w-4 h-4`})})]}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`button`,{"data-testid":`speed-control`,onClick:()=>ye(ve===e.id?null:e.id),disabled:!r||!F(`printers:control`),className:`${o} ${r?`bg-amber-500/10 text-amber-400 hover:bg-amber-500/20`:`bg-bambu-dark text-bambu-gray/50 cursor-not-allowed`}`,title:r?j(`printers.speed.title`):void 0,children:(0,K.jsx)(mc,{className:`w-4 h-4`})}),ve===e.id&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`div`,{className:`fixed inset-0 z-40`,onClick:()=>ye(null)}),(0,K.jsx)(`div`,{className:`absolute bottom-full left-0 mb-1 z-50 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-lg py-1 min-w-[130px]`,children:[{mode:1,label:j(`printers.speed.silent`)},{mode:2,label:j(`printers.speed.standard`)},{mode:3,label:j(`printers.speed.sport`)},{mode:4,label:j(`printers.speed.ludicrous`)}].map(({mode:e,label:t})=>(0,K.jsx)(`button`,{onClick:()=>{Hn.mutate(e),ye(null)},className:`w-full text-left px-3 py-1.5 text-xs transition-colors ${G.speed_level===e?`text-bambu-green bg-bambu-green/10`:`text-white hover:bg-bambu-dark-tertiary`}`,children:t},e))})]})]})]}),(0,K.jsxs)(`div`,{className:`ml-auto flex items-center justify-end gap-2 flex-shrink-0`,children:[(()=>{let e=!r||i||!F(`printers:control`);return(0,K.jsxs)(`button`,{onClick:()=>n?je(!0):_e(!0),disabled:e,className:` ${s} ${e?a:n?`bg-bambu-green/20 text-bambu-green hover:bg-bambu-green/30`:`bg-yellow-500/20 text-yellow-400 hover:bg-yellow-500/30`} `,title:F(`printers:control`)?j(n?`printers.resume`:`printers.pause`):j(`printers.permission.noControl`),children:[n?(0,K.jsx)(yl,{className:`w-3 h-3`}):(0,K.jsx)(ml,{className:`w-3 h-3`}),j(n?`printers.resume`:`printers.pause`)]})})(),(()=>{let e=!r||i||!F(`printers:control`);return(0,K.jsxs)(`button`,{onClick:()=>he(!0),disabled:e,className:` diff --git a/static/index.html b/static/index.html index 9cf03d828..bc775df0b 100644 --- a/static/index.html +++ b/static/index.html @@ -26,7 +26,7 @@ - +