From 5c9c49c35b70d4806f70ba56864ada4ed4a5e5b8 Mon Sep 17 00:00:00 2001 From: maziggy Date: Thu, 25 Jun 2026 08:30:50 +0200 Subject: [PATCH 1/5] =?UTF-8?q?=20=20fix(archives):=20correct=20#1812=20?= =?UTF-8?q?=E2=80=94=20Step=204=20wiki=20link=20host?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Banner pointed to bambuddy.cool/wiki/getting-started/... which 404s; the wiki lives under the wiki.bambuddy.cool subdomain. Anchor was correct (MkDocs slug matches the existing "Step 4: Enable Store sent files on external storage" heading). --- CHANGELOG.md | 2 ++ frontend/src/pages/ArchivesPage.tsx | 2 +- static/assets/{index-ClT8LTw_.js => index-C0VWlQxC.js} | 2 +- static/index.html | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) rename static/assets/{index-ClT8LTw_.js => index-C0VWlQxC.js} (99%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56d359485..9797ca04f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,8 @@ All notable changes to Bambuddy will be documented in this file. - **Per-printer Maintenance Mode toggle (#1476, requested by @IndividualGhost1905 / Ferdi SEVER)** — Operator-flipped "out of service" state per printer, surfaced as a wrench icon + amber pill on the card and a checkbox in the Edit Printer dialog. Requested for three real-world scenarios that all share the same shape: (1) parallel Bambuddy installs (dev + prod, primary + warm spare) where the printer rejects concurrent MQTT clients except one, leaving the others in a flicker-online state burning CPU and network; (2) printers under repair / awaiting spare parts that shouldn't accept queue jobs but should remain visible on the dashboard so they aren't forgotten; (3) temporary suspension during maintenance work. **What was already there, what was missing.** The backend field `Printer.is_active: bool` has shipped since the initial Bambuddy release — toggling it via `PATCH /printers/{id}` already disconnects MQTT (`printer_manager.disconnect_printer` at `printers.py:366`), stops the printer from being eligible for queue dispatch (`print_scheduler.py:520, 1588`, `print_queue.py:383`), excludes it from model-based filament lookups (`printers.py:197`), excludes it from metrics + diagnostic snapshots + scheduled-backup runs (`metrics.py:105`, `diagnostic_snapshot.py:126`, `github_backup.py:333`, `maintenance.py:457`), and is already honoured by PrinterSelector (filtered with a "show inactive" override, greyed + "(inactive)" label when shown). All three of Ferdi's use cases were structurally supported by `is_active` from day one. **The missing piece was UI exposure.** `grep is_active` on `PrintersPage.tsx` returned zero hits — no menu item, no edit field, no toggle. The only way to flip it was a direct API call. This change adds the surfaces that should have been there all along. **Card UI — replacement, not addition.** Per Ferdi-conversation feedback, the maintenance state replaces the print-status / cover-image container rather than stacking above it, so card heights stay identical across the grid: in expanded mode the same `` header renders an amber panel (wrench icon + "In Maintenance" + subtitle + Exit button) where the cover + progress would normally be; in compact mode a single amber pill replaces the progress bar. The header connection pill is also swapped — instead of the red "Offline" pill (which would be misleading because the disconnect is deliberate) the card shows an amber "Maintenance" pill, and the "Run Diagnostic" CTA is suppressed (that's reserved for involuntary offline triage). HMS / Queue / Firmware status pills are still gated by `status?.connected` so they fall away naturally with the MQTT disconnect. **Three entry points.** (1) Printer card three-dot overflow menu — `Enter maintenance mode` / `Exit maintenance mode` with a wrench icon, adjacent to the Edit and Reconnect actions. (2) Exit button inside the in-card amber panel, so a user noticing the card from across the room can flip back without opening the menu. (3) Checkbox in the EditPrinterModal — `Maintenance mode` with the same subtitle as the help line, so the toggle is discoverable from the edit dialog too (the checkbox is the inverse of `is_active` because the user-facing concept is "is this in maintenance" not "is it active"). **Mid-print safety prompt.** Entering maintenance mode on a printer in `RUNNING` / `PAUSE` state triggers a confirmation dialog before the toggle fires — disconnecting MQTT mid-print stops progress tracking + completion notifications for the in-flight job, which is usually NOT what the operator wants (they probably meant "after this print finishes"). Idle / FINISH / FAILED states skip the dialog and toggle directly. **What this does NOT change.** No backend change (`is_active` was already wired everywhere); no new permission (uses existing `printers:update`); no behaviour change for any other consumer (queue dispatch, scheduler, metrics, picker, backup — all already honoured `is_active`). The card stays visible on the Printers page (greyed temps/controls/fans below the amber banner) so the printer doesn't disappear from the operator's mental map — Ferdi explicitly wanted to remember it's there. Doesn't auto-pause Smart Plug logic or notification providers (would be a sensible follow-up if Ferdi asks; out of scope here to keep the diff bounded to "expose the existing gate"). The scheduled-maintenance dashboard at `/maintenance` (interval-tracked rod-cleaning / lube / belt tasks via the existing `MaintenanceHistory` and `PrinterMaintenance` models) is conceptually adjacent but operationally distinct — the dashboard tracks "this printer is due for cleaning"; Maintenance Mode tracks "this printer is currently out of service." A future "perform maintenance task → optionally enter maintenance mode while you do it" link is the natural connection but isn't wired here. **i18n.** Twelve new keys under `printers.maintenance.*` (title / subtitle / pillLabel / exitButton / menuEnter / menuExit / toastEntered / toastExited / confirmMidPrintTitle / confirmMidPrintMessage / editFieldLabel / editFieldHelp) — real translations in all 11 locales (de / en / es / fr / it / ja / ko / pt-BR / tr / zh-CN / zh-TW), parity 5228 leaves per locale, no English fallback. **Tests.** 4 new cases in `PrintersPage.test.tsx::'maintenance mode (#1476)'`: amber status panel renders with Exit button (and the regular "No active job" / "Ready to print" copy is absent — confirms the swap, not a stacked render); header pill swaps to amber Maintenance and the diagnostic CTA is suppressed; clicking Exit issues a `PATCH /printers/{id}` with `is_active: true`; active printers never show the maintenance panel. Existing test fixture (`mockPrinters`) got an explicit `is_active: true` to keep the existing 56 tests green on the new render path. **Type:** `PrinterCreate.is_active?: boolean` added to the TypeScript surface so the field flows cleanly through the existing `api.updatePrinter` helper. **Build + checks.** Full PrintersPage vitest 60/60 green; `npm run build` clean; ESLint clean; i18n parity 5228 × 11 locales green. ### Fixed +- **Archives "Step 4" docs link 404'd (#1812, reported by @Spanholz)** — The Archives page's "Some prints couldn't be archived with thumbnails" amber banner linked to `https://bambuddy.cool/wiki/getting-started/#step-4-enable-store-sent-files-on-external-storage` — the wiki lives at the `wiki.bambuddy.cool` subdomain, not under `bambuddy.cool/wiki/`, so the link 404'd. Anchor was already correct (MkDocs slugifies the existing "Step 4: Enable Store sent files on external storage" heading to that exact id). Single-line fix in `frontend/src/pages/ArchivesPage.tsx:3271`; no i18n / no tests touched. + - **Connection diagnostic reported false camera-port warning on A1 / A1 Mini / P1 (#1798, reported and fixed by @lesbass / Stefano Maffeis in #1799)** — The general Connection Diagnostic (`printer_diagnostic.py:124`) probed RTSPS port 322 unconditionally, even for printers that don't speak RTSP. A1, A1 Mini, and P1-family cameras use the chamber-image protocol on port 6000 — Bambuddy's live camera client already routes them there via `camera.py::get_camera_port(model)`. Result: a saved A1 Mini with a working live webcam still saw "Camera port (RTSPS 322) — Port 322 is unreachable" in the diagnostic, and overall status flipped to `warnings` for a healthy printer. Reporter confirmed: TCP probe from the container showed 6000 open, 322 refused; camera-specific diagnostic returned `protocol=chamber_image, port=6000, overall_status=ok`. **Fix.** The diagnostic now resolves the camera port via the same `get_camera_port()` the camera client uses (single source of truth — adding a new model in `camera.py` propagates here for free). Saved A1 / A1 Mini / P1 → probe 6000, render "Camera port (Chamber Image 6000)". Saved X1 / X2 / H2 / P2 → unchanged, still probe 322 / RTSPS. Pre-save Add-Printer diagnostic where the model isn't known yet falls back to 322 / RTSPS — same conservative default as before, so the Add-Printer flow doesn't regress for users on RTSP models. The diagnostic check id stays `port_rtsps` for backward compatibility with snapshot JSON consumers; the actual port / protocol now travel in `params` and the localized title and warn text interpolate `{{protocol}}` / `{{port}}`. **Frontend.** `ConnectionDiagnostic.tsx` interpolates the title (previously static) and merges defensive defaults (`{ protocol: 'RTSPS', port: 322, ...check.params }`) for `port_rtsps` so an older backend or cached response still renders sensibly. **i18n.** Title and warn strings updated in all 11 locales (en / de / es / fr / it / ja / ko / pt-BR / tr / zh-CN / zh-TW) to use `{{protocol}}` / `{{port}}` interpolation. `npm run check:i18n` clean. **Tests.** 2 new backend cases (A1 Mini → 6000 / Chamber Image with the 322 fallback closed asserting `port_rtsps=pass`; X1C → still probes 322 / RTSPS asserting the existing behavior is unchanged) and 1 new frontend case asserting the rendered "Camera port (Chamber Image 6000)" + "Port 6000 is unreachable" text. `_port_probe` defaults extended to include port 6000. Existing model-less tests unchanged — they go through the `printer.model is None` fallback path and still probe 322. - **Print-complete notification dropped the finish photo when the FINISH-state fallback fired (#1790, reported by @needo37)** — On the FINISH-state fallback path (`bambu_mqtt.py:3258-3297`, used when stage-22 doesn't fire — cancel, external-spool-only, HMS halt, firmware variants that skip the unload phase), `on_finish_photo_moment` and `on_print_complete` were dispatched as two **independent** asyncio tasks back-to-back from the same MQTT handler. The producer (`on_finish_photo_moment`) ran the RTSP grab (15s timeout) and stored the JPEG into `_stage22_finish_frames[printer_id]` only after the grab returned; the consumer (`_background_finish_photo`, spawned by `on_print_complete`) read the cache with a single `pop()` at `main.py:4681` — no wait, no retry. On the stage-22 happy path the producer fires seconds before FINISH-state arrives so the race is invisible; on the FINISH-state fallback the gap collapses to ~0 and the consumer always wins the empty pop. After the empty pop, the fallback chain called `capture_finish_photo()` at `main.py:4739` — but the producer's RTSP grab was still in flight against the same printer, and Bambu printers allow exactly one RTSP client at a time. The consumer's grab timed out at the camera service's 30s ceiling. Reporter's log shows it exactly: `[FINISH-PHOTO-MOMENT] captured RTSP frame (394037 bytes)` at 05:31:20, then `[PHOTO-NOTIFY] Photo task returned: None` at 05:31:49 — 30s after `[PHOTO-BG] Starting`. A 394 KB frame was captured, the notification went text-only. **Why this only surfaced after #1721:** before #1721, Bambuddy force-enabled timelapse at dispatch so a video always existed and the finish photo was extracted from its last frame regardless of timing. #1721 removed the force-on (it was causing per-layer nozzle parking on Smooth-mode slicer profiles) and made the racy stage-22 cache the only good framing source. For timelapse-off prints completing via the FINISH-state fallback, there was no resilient source left. **Fix.** New per-printer `_stage22_finish_in_flight: dict[int, asyncio.Event]` synchronizes producer→consumer. The producer registers an `asyncio.Event` BEFORE its first `await` (so the consumer always sees it the moment it polls — registration is purely synchronous before any await yields control), sets the event in a `finally` block on EVERY exit path (success, no-frame, setting-disabled early return, exception), and the consumer awaits the event with `asyncio.wait_for(event.wait(), timeout=20.0)` before reading the cache. The 20s ceiling is sized against the producer's 15s RTSP timeout — bounded headroom, can't hang notifications. The consumer pops the dict entry when it starts waiting so cleanup is a single side; the producer's `set()` works on a local ref. Side-effect win: because the consumer is blocked behind the producer's completion, the consumer's own RTSP fallback can no longer collide with the producer's in-flight grab — Failure 2 (concurrent RTSP timeout) is closed alongside Failure 1 (cache race) by the same change. **What this does NOT change.** The timelapse path (`timelapse_was_active=True`) returns before registering the event — the consumer takes the `_capture_finish_photo_from_timelapse` branch and never waits; no regression. Aborted / failed prints don't dispatch `on_finish_photo_moment` at all (status="completed" gate at `bambu_mqtt.py:3258`) — no event registered, consumer behaves as today. External-camera printers (`external_camera_enabled`) and printers with a live stream open in the UI (buffered RTSP frame) are unaffected — the producer still uses those non-contended sources first. No change to `camera.py` lock semantics. **Tests.** 7 new cases in `test_finish_photo_moment_sync.py` pin every limb of the contract: event is registered before the first await (uses a slow-capture stub to observe the dict mid-run), event is set after successful capture, event is set when the producer captured no frame, event is set even when the capture function raises (the `finally` is load-bearing), event is NOT registered on the `timelapse_was_active=True` early-return, event IS set when the `capture_finish_photo` setting is disabled (the late early return — important so the consumer doesn't hang on a no-op producer), and an end-to-end producer/consumer pair finishes promptly with the cached frame visible to the consumer. Adjacent tests (`test_finish_photo_from_timelapse.py`, `test_reprint_clears_stale_timelapse.py`) still green. Ruff clean. diff --git a/frontend/src/pages/ArchivesPage.tsx b/frontend/src/pages/ArchivesPage.tsx index 0953b2d0e..edd193146 100644 --- a/frontend/src/pages/ArchivesPage.tsx +++ b/frontend/src/pages/ArchivesPage.tsx @@ -3268,7 +3268,7 @@ export function ArchivesPage() {
{t('archives.no3mfBanner.body')}{' '} {let e=o.current;e&&(e.playbackRate=l)},[l]),(0,y.useEffect)(()=>{let e=e=>{e.key===`Escape`&&i()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[i]),(0,y.useEffect)(()=>{let e=o.current;if(!e)return;let t=()=>f(e.currentTime),n=()=>m(e.duration),r=()=>c(!0),i=()=>c(!1);return e.addEventListener(`timeupdate`,t),e.addEventListener(`durationchange`,n),e.addEventListener(`play`,r),e.addEventListener(`pause`,i),()=>{e.removeEventListener(`timeupdate`,t),e.removeEventListener(`durationchange`,n),e.removeEventListener(`play`,r),e.removeEventListener(`pause`,i)}},[]);let _=()=>{let e=o.current;e&&(s?e.pause():e.play())};return(0,K.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-black/80`,children:[(0,K.jsxs)(`div`,{className:`relative bg-bambu-dark-secondary rounded-xl max-w-4xl w-full mx-4 overflow-hidden`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between p-4 border-b border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`h3`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(rc,{className:`w-5 h-5 text-bambu-green`}),t]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[r&&(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>g(!0),children:[(0,K.jsx)(_l,{className:`w-4 h-4`}),`Edit`]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>{let t=document.createElement(`a`);t.href=e,t.download=n,t.click()},children:[(0,K.jsx)(Bs,{className:`w-4 h-4`}),`Download`]}),(0,K.jsx)(`button`,{onClick:i,className:`p-1 hover:bg-bambu-dark-tertiary rounded transition-colors`,children:(0,K.jsx)(Ru,{className:`w-5 h-5 text-bambu-gray`})})]})]}),(0,K.jsxs)(`div`,{className:`p-4`,children:[(0,K.jsx)(`video`,{ref:o,src:e,autoPlay:!0,className:`w-full rounded-lg`,onClick:_}),(0,K.jsxs)(`div`,{className:`mt-4 space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray w-12 text-right`,children:Tf(d)}),(0,K.jsx)(`input`,{type:`range`,min:0,max:p||100,value:d,onChange:e=>{let t=o.current;t&&(t.currentTime=parseFloat(e.target.value))},className:`flex-1 h-1 bg-bambu-dark-tertiary rounded-lg appearance-none cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:h-3 [&::-webkit-slider-thumb]:bg-bambu-green [&::-webkit-slider-thumb]:rounded-full - [&::-webkit-slider-thumb]:cursor-pointer`}),(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray w-12`,children:Tf(p)})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`button`,{onClick:()=>{let e=o.current;e&&(e.currentTime=Math.max(0,e.currentTime-5))},className:`p-2 hover:bg-bambu-dark-tertiary rounded-lg transition-colors`,title:`Skip back 5s`,children:(0,K.jsx)(Yl,{className:`w-5 h-5 text-bambu-gray`})}),(0,K.jsx)(`button`,{onClick:_,className:`p-2 bg-bambu-green hover:bg-bambu-green-dark rounded-lg transition-colors`,children:s?(0,K.jsx)(ml,{className:`w-5 h-5 text-white`}):(0,K.jsx)(yl,{className:`w-5 h-5 text-white`})}),(0,K.jsx)(`button`,{onClick:()=>{let e=o.current;e&&(e.currentTime=Math.min(p,e.currentTime+5))},className:`p-2 hover:bg-bambu-dark-tertiary rounded-lg transition-colors`,title:`Skip forward 5s`,children:(0,K.jsx)(Xl,{className:`w-5 h-5 text-bambu-gray`})})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`span`,{className:`text-sm text-bambu-gray`,children:`Speed:`}),(0,K.jsx)(`div`,{className:`flex gap-1`,children:HRe.map(e=>(0,K.jsxs)(`button`,{onClick:()=>u(e),className:`px-2 py-1 text-xs rounded transition-colors ${l===e?`bg-bambu-green text-white`:`bg-bambu-dark-tertiary text-bambu-gray hover:bg-bambu-dark-tertiary/80`}`,children:[e,`x`]},e))})]})]})]})]})]}),h&&r&&(0,K.jsx)(VRe,{archiveId:r,timelapseSrc:e,onClose:()=>g(!1),onSave:a})]})}function URe({archiveIds:e,onClose:t}){(0,y.useEffect)(()=>{let e=e=>{e.key===`Escape`&&t()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[t]);let{data:n,isLoading:r,error:i}=q({queryKey:[`archive-comparison`,e],queryFn:()=>Q.compareArchives(e)});return(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/80 flex items-center justify-center z-50 p-4`,onClick:t,children:(0,K.jsxs)(`div`,{className:`bg-bambu-dark-secondary rounded-lg max-w-4xl w-full max-h-[90vh] flex flex-col border border-bambu-dark-tertiary`,onClick:e=>e.stopPropagation(),children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between p-4 border-b border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`h3`,{className:`text-lg font-semibold text-white`,children:[`Compare Archives (`,e.length,`)`]}),(0,K.jsx)(`button`,{onClick:t,className:`text-bambu-gray hover:text-white p-1`,children:(0,K.jsx)(Ru,{className:`w-5 h-5`})})]}),(0,K.jsx)(`div`,{className:`flex-1 overflow-auto p-4 bg-bambu-dark-secondary`,children:r?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-12`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):i?(0,K.jsxs)(`div`,{className:`text-center py-12 text-red-400`,children:[(0,K.jsx)(Su,{className:`w-12 h-12 mx-auto mb-4 opacity-50`}),(0,K.jsx)(`p`,{children:`Failed to load comparison`}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-2`,children:i instanceof Error?i.message:`Unknown error`})]}):n?(0,K.jsx)(WRe,{comparison:n}):null}),(0,K.jsx)(`div`,{className:`p-4 border-t border-bambu-dark-tertiary`,children:(0,K.jsx)($,{variant:`secondary`,onClick:t,className:`w-full`,children:`Close`})})]})})}function WRe({comparison:e}){return(0,K.jsxs)(`div`,{className:`space-y-6`,children:[(0,K.jsx)(`div`,{className:`overflow-x-auto`,children:(0,K.jsxs)(`table`,{className:`w-full`,children:[(0,K.jsx)(`thead`,{children:(0,K.jsxs)(`tr`,{children:[(0,K.jsx)(`th`,{className:`text-left text-sm text-bambu-gray font-medium pb-2 pr-4 min-w-[150px]`,children:`Setting`}),e.archives.map(e=>(0,K.jsxs)(`th`,{className:`text-left text-sm font-medium pb-2 px-2 min-w-[120px]`,children:[(0,K.jsx)(`div`,{className:`text-white truncate max-w-[150px]`,title:e.print_name,children:e.print_name}),(0,K.jsx)(`div`,{className:`text-xs ${e.status===`completed`?`text-status-ok`:e.status===`failed`?`text-status-error`:`text-bambu-gray`}`,children:e.status})]},e.id))]})}),(0,K.jsx)(`tbody`,{className:`divide-y divide-bambu-gray/20`,children:e.comparison.map(e=>(0,K.jsxs)(`tr`,{className:e.has_difference?`bg-yellow-500/5`:``,children:[(0,K.jsx)(`td`,{className:`py-2 pr-4 text-sm`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[e.has_difference&&(0,K.jsx)(Su,{className:`w-3 h-3 text-yellow-400 flex-shrink-0`}),(0,K.jsx)(`span`,{className:e.has_difference?`text-yellow-400`:`text-bambu-gray`,children:e.label})]})}),e.values.map((t,n)=>(0,K.jsxs)(`td`,{className:`py-2 px-2 text-sm text-white`,children:[t??(0,K.jsx)(`span`,{className:`text-bambu-gray/50`,children:`-`}),e.unit&&t!==null&&(0,K.jsx)(`span`,{className:`text-bambu-gray ml-1`,children:e.unit})]},n))]},e.field))})]})}),e.differences.length>0&&(0,K.jsxs)(`div`,{className:`p-4 bg-yellow-500/10 border border-yellow-500/30 rounded-lg`,children:[(0,K.jsxs)(`h4`,{className:`text-sm font-medium text-yellow-400 mb-2 flex items-center gap-2`,children:[(0,K.jsx)(Su,{className:`w-4 h-4`}),e.differences.length,` Difference`,e.differences.length>1?`s`:``,` Found`]}),(0,K.jsxs)(`ul`,{className:`text-sm text-white/80 space-y-1`,children:[e.differences.slice(0,5).map(e=>(0,K.jsxs)(`li`,{children:[(0,K.jsx)(`span`,{className:`text-yellow-400`,children:e.label}),`: `,e.values.join(` vs `),` `,e.unit||``]},e.field)),e.differences.length>5&&(0,K.jsxs)(`li`,{className:`text-bambu-gray`,children:[`...and `,e.differences.length-5,` more`]})]})]}),e.success_correlation.has_both_outcomes?(0,K.jsxs)(`div`,{className:`p-4 bg-bambu-dark rounded-lg`,children:[(0,K.jsxs)(`h4`,{className:`text-sm font-medium text-white mb-3 flex items-center gap-2`,children:[(0,K.jsx)(rs,{className:`w-4 h-4 text-bambu-green`}),`Success/Failure Analysis`]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-4 text-sm mb-3`,children:[(0,K.jsxs)(`span`,{className:`text-bambu-green`,children:[e.success_correlation.successful_count,` successful`]}),(0,K.jsxs)(`span`,{className:`text-red-400`,children:[e.success_correlation.failed_count,` failed`]})]}),e.success_correlation.insights&&e.success_correlation.insights.length>0?(0,K.jsx)(`div`,{className:`space-y-2`,children:e.success_correlation.insights.map(e=>(0,K.jsxs)(`div`,{className:`text-sm p-2 bg-bambu-dark-secondary rounded`,children:[(0,K.jsxs)(`span`,{className:`text-white font-medium`,children:[e.label,`:`]}),` `,(0,K.jsx)(`span`,{className:`text-white/80`,children:e.insight})]},e.field))}):(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:`No clear correlations found between settings and outcomes.`})]}):(0,K.jsx)(`div`,{className:`p-4 bg-bambu-dark rounded-lg text-sm text-bambu-gray`,children:(0,K.jsx)(`p`,{children:e.success_correlation.message||`Need both successful and failed prints for correlation analysis.`})})]})}function GRe(e){let t=new Date(e),n=new Date().getTime()-t.getTime(),r=Math.floor(n/6e4);if(r<1)return`Just now`;if(r<60)return`${r}m ago`;let i=Math.floor(r/60);return i<24?`${i}h ago`:`${Math.floor(i/24)}d ago`}function KRe({upload:e,projects:t,onArchive:n,onDiscard:r,isArchiving:i,isDiscarding:a}){let[o,s]=(0,y.useState)(!1),[c,l]=(0,y.useState)(e.tags||``),[u,d]=(0,y.useState)(e.notes||``),[f,p]=(0,y.useState)(e.project_id),[m,h]=(0,y.useState)(!1);return(0,K.jsx)(_d,{children:(0,K.jsxs)(yd,{className:`py-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(Zs,{className:`w-8 h-8 text-bambu-green flex-shrink-0`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white font-medium`,title:e.filename,children:e.display_name||e.filename}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-xs text-bambu-gray`,children:[(0,K.jsx)(`span`,{children:Cd(e.file_size)}),(0,K.jsx)(`span`,{children:`·`}),(0,K.jsxs)(`span`,{className:`flex items-center gap-1`,children:[(0,K.jsx)(xs,{className:`w-3 h-3`}),GRe(e.uploaded_at)]}),e.source_ip&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`span`,{children:`·`}),(0,K.jsxs)(`span`,{children:[`from `,e.source_ip]})]})]})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`button`,{onClick:()=>s(!o),className:`p-1 text-bambu-gray hover:text-white transition-colors`,children:o?(0,K.jsx)(cs,{className:`w-5 h-5`}):(0,K.jsx)(is,{className:`w-5 h-5`})}),(0,K.jsx)($,{variant:`primary`,size:`sm`,onClick:()=>n(e.id,{tags:c,notes:u,project_id:f||void 0}),disabled:i,children:i?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Oo,{className:`w-4 h-4`}),`Archive`]})}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>h(!0),disabled:a,children:a?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(yu,{className:`w-4 h-4 text-red-400`})})]})]}),m&&(0,K.jsx)(Ad,{title:`Discard Upload`,message:`Are you sure you want to discard "${e.filename}"? This cannot be undone.`,confirmText:`Discard`,variant:`danger`,onConfirm:()=>{r(e.id),h(!1)},onCancel:()=>h(!1)}),o&&(0,K.jsxs)(`div`,{className:`mt-4 pt-4 border-t border-bambu-dark-tertiary space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:`Tags`}),(0,K.jsx)(`input`,{type:`text`,value:c,onChange:e=>l(e.target.value),placeholder:`e.g., functional, prototype, gift`,className:`w-full bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-md px-3 py-2 text-white placeholder-bambu-gray text-sm`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:`Notes`}),(0,K.jsx)(`textarea`,{value:u,onChange:e=>d(e.target.value),placeholder:`Add notes about this print...`,rows:2,className:`w-full bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-md px-3 py-2 text-white placeholder-bambu-gray text-sm resize-none`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:`Project`}),(0,K.jsxs)(`select`,{value:f||``,onChange:e=>p(e.target.value?Number(e.target.value):null),className:`w-full bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-md px-3 py-2 text-white text-sm`,children:[(0,K.jsx)(`option`,{value:``,children:`No project`}),t.map(e=>(0,K.jsx)(`option`,{value:e.id,children:e.name},e.id))]})]})]})]})})}function qRe(){let e=no(),{showToast:t}=Td(),[n,r]=(0,y.useState)(!1),[i,a]=(0,y.useState)(!1),[o,s]=(0,y.useState)(new Set),[c,l]=(0,y.useState)(new Set),{data:u,isLoading:d}=q({queryKey:[`pending-uploads`],queryFn:rd.list,refetchInterval:1e4}),{data:f}=q({queryKey:[`projects`],queryFn:()=>Q.getProjects(),select:e=>[...e].sort((e,t)=>e.name.localeCompare(t.name))}),p=J({mutationFn:({id:e,data:t})=>rd.archive(e,t),onMutate:({id:e})=>{s(t=>new Set(t).add(e))},onSettled:(e,t,{id:n})=>{s(e=>{let t=new Set(e);return t.delete(n),t})},onSuccess:n=>{e.invalidateQueries({queryKey:[`pending-uploads`]}),e.invalidateQueries({queryKey:[`archives`]}),t(`Archived: ${n.print_name}`)},onError:e=>{t(e.message||`Failed to archive`,`error`)}}),m=J({mutationFn:e=>rd.discard(e),onMutate:e=>{l(t=>new Set(t).add(e))},onSettled:(e,t,n)=>{l(e=>{let t=new Set(e);return t.delete(n),t})},onSuccess:()=>{e.invalidateQueries({queryKey:[`pending-uploads`]}),t(`Upload discarded`)},onError:e=>{t(e.message||`Failed to discard`,`error`)}}),h=J({mutationFn:rd.archiveAll,onSuccess:n=>{e.invalidateQueries({queryKey:[`pending-uploads`]}),e.invalidateQueries({queryKey:[`archives`]}),t(`Archived ${n.archived} files${n.failed>0?`, ${n.failed} failed`:``}`)},onError:e=>{t(e.message||`Failed to archive all`,`error`)}}),g=J({mutationFn:rd.discardAll,onSuccess:n=>{e.invalidateQueries({queryKey:[`pending-uploads`]}),t(`Discarded ${n.discarded} files`)},onError:e=>{t(e.message||`Failed to discard all`,`error`)}});return d?(0,K.jsx)(_d,{children:(0,K.jsx)(yd,{className:`py-8 flex justify-center`,children:(0,K.jsx)(X,{className:`w-6 h-6 animate-spin text-bambu-green`})})}):!u||u.length===0?null:(0,K.jsxs)(`div`,{className:`mb-6`,children:[(0,K.jsxs)(_d,{className:`border-l-4 border-l-yellow-500`,children:[(0,K.jsx)(vd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Eu,{className:`w-5 h-5 text-yellow-500`}),(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white`,children:[`Pending Uploads (`,u.length,`)`]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)($,{variant:`primary`,size:`sm`,onClick:()=>r(!0),disabled:h.isPending,children:h.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Oo,{className:`w-4 h-4`}),`Archive All`]})}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>a(!0),disabled:g.isPending,children:g.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(yu,{className:`w-4 h-4`}),`Discard All`]})})]})]})}),(0,K.jsxs)(yd,{children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mb-4`,children:`These files were uploaded via the virtual printer. Review and archive them to add to your collection.`}),(0,K.jsx)(`div`,{className:`space-y-3`,children:u.map(e=>(0,K.jsx)(KRe,{upload:e,projects:f||[],onArchive:(e,t)=>p.mutate({id:e,data:t}),onDiscard:e=>m.mutate(e),isArchiving:o.has(e.id),isDiscarding:c.has(e.id)},e.id))})]})]}),n&&(0,K.jsx)(Ad,{title:`Archive All Uploads`,message:`Are you sure you want to archive all ${u.length} pending uploads?`,confirmText:`Archive All`,onConfirm:()=>{h.mutate(),r(!1)},onCancel:()=>r(!1)}),i&&(0,K.jsx)(Ad,{title:`Discard All Uploads`,message:`Are you sure you want to discard all ${u.length} pending uploads? This cannot be undone.`,confirmText:`Discard All`,variant:`danger`,onConfirm:()=>{g.mutate(),a(!1)},onCancel:()=>a(!1)})]})}function JRe({onClose:e}){let t=no(),{showToast:n}=Td(),[r,i]=(0,y.useState)(``),[a,o]=(0,y.useState)(null),[s,c]=(0,y.useState)(``),[l,u]=(0,y.useState)(null),[d,f]=(0,y.useState)(`count`);(0,y.useEffect)(()=>{let t=t=>{t.key===`Escape`&&(a?o(null):l?u(null):e())};return window.addEventListener(`keydown`,t),()=>window.removeEventListener(`keydown`,t)},[e,a,l]);let{data:p,isLoading:m}=q({queryKey:[`tags`],queryFn:Q.getTags}),h=J({mutationFn:({oldName:e,newName:t})=>Q.renameTag(e,t),onSuccess:(e,{oldName:r,newName:i})=>{t.invalidateQueries({queryKey:[`tags`]}),t.invalidateQueries({queryKey:[`archives`]}),n(`Renamed "${r}" to "${i}" in ${e.affected} archive${e.affected===1?``:`s`}`),o(null)},onError:e=>{n(e.message||`Failed to rename tag`,`error`)}}),g=J({mutationFn:e=>Q.deleteTag(e),onSuccess:(e,r)=>{t.invalidateQueries({queryKey:[`tags`]}),t.invalidateQueries({queryKey:[`archives`]}),n(`Deleted "${r}" from ${e.affected} archive${e.affected===1?``:`s`}`),u(null)},onError:e=>{n(e.message||`Failed to delete tag`,`error`)}}),_=e=>{o(e.name),c(e.name),u(null)},v=()=>{o(null),c(``)},b=()=>{if(!a||!s.trim())return;let e=s.trim();if(e===a){v();return}h.mutate({oldName:a,newName:e})},x=e=>{e.key===`Enter`?(e.preventDefault(),b()):e.key===`Escape`&&(e.preventDefault(),v())},S=e=>{u(e),o(null)},C=()=>{l&&g.mutate(l)},w=p?.filter(e=>e.name.toLowerCase().includes(r.toLowerCase())).sort((e,t)=>d===`count`&&t.count-e.count||e.name.localeCompare(t.name)),T=p?.reduce((e,t)=>e+t.count,0)||0;return(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4`,children:(0,K.jsx)(_d,{className:`w-full max-w-lg max-h-[80vh] flex flex-col`,children:(0,K.jsxs)(yd,{className:`p-0 flex flex-col min-h-0`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between p-4 border-b border-bambu-dark-tertiary flex-shrink-0`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(du,{className:`w-5 h-5 text-bambu-green`}),(0,K.jsx)(`h2`,{className:`text-xl font-semibold text-white`,children:`Manage Tags`})]}),(0,K.jsx)(`button`,{onClick:e,className:`text-bambu-gray hover:text-white transition-colors`,children:(0,K.jsx)(Ru,{className:`w-5 h-5`})})]}),(0,K.jsxs)(`div`,{className:`p-4 border-b border-bambu-dark-tertiary flex-shrink-0`,children:[(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsxs)(`div`,{className:`relative flex-1`,children:[(0,K.jsx)(Ll,{className:`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray`}),(0,K.jsx)(`input`,{type:`text`,placeholder:`Search tags...`,className:`w-full pl-9 pr-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:border-bambu-green focus:outline-none`,value:r,onChange:e=>i(e.target.value)})]}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:border-bambu-green focus:outline-none`,value:d,onChange:e=>f(e.target.value),children:[(0,K.jsx)(`option`,{value:`count`,children:`Sort by Count`}),(0,K.jsx)(`option`,{value:`name`,children:`Sort by Name`})]})]}),p&&(0,K.jsxs)(`p`,{className:`text-xs text-bambu-gray mt-2`,children:[p.length,` tag`,p.length===1?``:`s`,` across `,T,` usage`,T===1?``:`s`]})]}),(0,K.jsx)(`div`,{className:`flex-1 overflow-y-auto min-h-0 p-4`,children:m?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-8`,children:(0,K.jsx)(X,{className:`w-6 h-6 animate-spin text-bambu-gray`})}):w?.length?(0,K.jsx)(`div`,{className:`space-y-2`,children:w.map(e=>(0,K.jsx)(`div`,{className:`flex items-center gap-2 p-2 rounded-lg bg-bambu-dark hover:bg-bambu-dark-tertiary transition-colors group`,children:a===e.name?(0,K.jsxs)(`div`,{className:`flex-1 flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`text`,className:`flex-1 px-2 py-1 bg-bambu-dark-tertiary border border-bambu-green rounded text-white text-sm focus:outline-none`,value:s,onChange:e=>c(e.target.value),onKeyDown:x,autoFocus:!0}),(0,K.jsx)($,{size:`sm`,variant:`primary`,onClick:b,disabled:!s.trim()||h.isPending,className:`p-1.5`,children:h.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(rs,{className:`w-4 h-4`})}),(0,K.jsx)($,{size:`sm`,variant:`ghost`,onClick:v,className:`p-1.5`,children:(0,K.jsx)(Ru,{className:`w-4 h-4`})})]}):l===e.name?(0,K.jsxs)(`div`,{className:`flex-1 flex items-center gap-2`,children:[(0,K.jsx)(Su,{className:`w-4 h-4 text-yellow-400 flex-shrink-0`}),(0,K.jsxs)(`span`,{className:`text-sm text-bambu-gray-light flex-1`,children:[`Delete "`,e.name,`" from `,e.count,` archive`,e.count===1?``:`s`,`?`]}),(0,K.jsx)($,{size:`sm`,variant:`danger`,onClick:C,disabled:g.isPending,className:`p-1.5`,children:g.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(yu,{className:`w-4 h-4`})}),(0,K.jsx)($,{size:`sm`,variant:`ghost`,onClick:()=>u(null),className:`p-1.5`,children:(0,K.jsx)(Ru,{className:`w-4 h-4`})})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(du,{className:`w-4 h-4 text-bambu-gray flex-shrink-0`}),(0,K.jsx)(`span`,{className:`text-white flex-1 truncate`,children:e.name}),(0,K.jsx)(`span`,{className:`px-2 py-0.5 rounded-full bg-bambu-dark-tertiary text-bambu-gray text-xs`,children:e.count}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity`,children:[(0,K.jsx)(`button`,{onClick:()=>_(e),className:`p-1.5 rounded hover:bg-bambu-dark text-bambu-gray hover:text-white transition-colors`,title:`Rename tag`,children:(0,K.jsx)(_l,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{onClick:()=>S(e.name),className:`p-1.5 rounded hover:bg-bambu-dark text-bambu-gray hover:text-red-400 transition-colors`,title:`Delete tag`,children:(0,K.jsx)(yu,{className:`w-4 h-4`})})]})]})},e.name))}):(0,K.jsx)(`div`,{className:`text-center py-8 text-bambu-gray`,children:r?`No tags match your search`:`No tags found`})}),(0,K.jsx)(`div`,{className:`flex gap-3 p-4 border-t border-bambu-dark-tertiary flex-shrink-0`,children:(0,K.jsx)($,{variant:`secondary`,onClick:e,className:`flex-1`,children:`Close`})})]})})})}function m2(e){let t=e.filename;if(t){let e=t.toLowerCase();if(e.endsWith(`.gcode`)||e.includes(`.gcode.`))return!0}return!!(e.total_layers||e.print_time_seconds)}async function h2(e,t,n,r){try{if(n===`source`){let{token:n}=await Q.createSourceSlicerToken(e),i=Q.getSourceSlicerDownloadUrl(e,n,t);nG(`${window.location.origin}${i}`,r)}else{let{token:n}=await Q.createArchiveSlicerToken(e),i=Q.getArchiveSlicerDownloadUrl(e,n,t);nG(`${window.location.origin}${i}`,r)}}catch{let i=n===`source`?Q.getSource3mfForSlicer(e,t):Q.getArchiveForSlicer(e,t);nG(`${window.location.origin}${i}`,r)}}function YRe({archive:e,printerName:t,isSelected:n,onSelect:r,selectionMode:i,projects:a,isHighlighted:o,timeFormat:s=`system`,preferredSlicer:c=`bambu_studio`,useSlicerApi:l=!1,currency:u,t:d,onNavigateToArchive:f}){o&&console.log(`ArchiveCard isHighlighted=true for archive:`,e.id);let p=no(),{showToast:m}=Td(),{hasPermission:h,canModify:g}=dd(),_=iG(),v=$n(),[b,x]=(0,y.useState)(!1),[S,C]=(0,y.useState)(!1),[w,T]=(0,y.useState)(!1),[E,D]=(0,y.useState)(!1),O=q({queryKey:[`archive`,e.id,`delete-impact`],queryFn:()=>Q.getArchiveDeleteImpact(e.id),enabled:w,staleTime:0}),[k,A]=(0,y.useState)(!1),[j,M]=(0,y.useState)(!1),[N,P]=(0,y.useState)(!1),[F,I]=(0,y.useState)(!1),[L,R]=(0,y.useState)([]),[z,B]=(0,y.useState)(!1),[V,ee]=(0,y.useState)(!1),[te,ne]=(0,y.useState)(!1),[re,ie]=(0,y.useState)(!1),[H,ae]=(0,y.useState)(!1),[oe,U]=(0,y.useState)(!1),[se,ce]=(0,y.useState)(!1),[le,ue]=(0,y.useState)(null),[de,fe]=(0,y.useState)(null),[pe,me]=(0,y.useState)(!1),[he,ge]=(0,y.useState)(null),_e=(0,y.useRef)(null),ve=(0,y.useRef)(null),ye=(0,y.useRef)(null),{data:be}=q({queryKey:[`archive-plates`,e.id],queryFn:()=>Q.getArchivePlates(e.id),enabled:pe,staleTime:300*1e3}),xe=e.duplicate_sequence??0,Se=e.original_archive_id??null,Ce=be?.plates??[],we=be?.is_multi_plate??!1,Te=de??0,Ee=async()=>{try{let t=await Q.getArchivePlates(e.id);if(t.has_gcode===!1){m(d(`archives.platePicker.noGcode`),`info`);return}if(t.is_multi_plate&&t.plates.length>1){ge(t.plates);return}}catch{}v(`/gcode-viewer?archive=${e.id}`)},De=J({mutationFn:()=>Q.deleteArchiveTimelapse(e.id),onSuccess:()=>{p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.timelapseRemoved`))},onError:e=>{m(e.message||d(`archives.toast.failedRemoveTimelapse`),`error`)}}),Oe=J({mutationFn:t=>Q.uploadArchiveTimelapse(e.id,t),onSuccess:e=>{p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.timelapseUploaded`,{filename:e.filename}))},onError:e=>{m(e.message||d(`archives.toast.failedUploadTimelapse`),`error`)}}),ke=J({mutationFn:t=>Q.uploadSource3mf(e.id,t),onSuccess:e=>{p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.source3mfAttached`,{filename:e.filename}))},onError:e=>{m(e.message||d(`archives.toast.failedUploadSource3mf`),`error`)}}),Ae=J({mutationFn:()=>Q.deleteSource3mf(e.id),onSuccess:()=>{p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.source3mfRemoved`))},onError:e=>{m(e.message||d(`archives.toast.failedRemoveSource3mf`),`error`)}}),je=J({mutationFn:t=>Q.uploadF3d(e.id,t),onSuccess:e=>{p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.f3dAttached`,{filename:e.filename}))},onError:e=>{m(e.message||d(`archives.toast.failedUploadF3d`),`error`)}}),Me=J({mutationFn:()=>Q.deleteF3d(e.id),onSuccess:()=>{p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.f3dRemoved`))},onError:e=>{m(e.message||d(`archives.toast.failedRemoveF3d`),`error`)}}),Ne=J({mutationFn:()=>Q.scanArchiveTimelapse(e.id),onSuccess:e=>{e.status===`attached`?(p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.timelapseAttached`,{filename:e.filename}))):e.status===`exists`?m(d(`archives.toast.timelapseAlreadyAttached`)):e.status===`not_found`&&e.available_files&&e.available_files.length>0?(R(e.available_files),I(!0)):m(e.message||d(`archives.toast.noMatchingTimelapse`),`warning`)},onError:e=>{m(e.message||d(`archives.toast.failedScanTimelapse`),`error`)}}),Pe=J({mutationFn:t=>Q.selectArchiveTimelapse(e.id,t),onSuccess:e=>{p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.timelapseAttached`,{filename:e.filename})),I(!1),R([])},onError:e=>{m(e.message||d(`archives.toast.failedAttachTimelapse`),`error`)}}),Fe=J({mutationFn:t=>Q.deleteArchive(e.id,t),onSuccess:()=>{p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.archiveDeleted`))},onError:()=>{m(d(`archives.toast.failedDeleteArchive`),`error`)}}),Ie=J({mutationFn:()=>Q.toggleFavorite(e.id),onSuccess:e=>{p.invalidateQueries({queryKey:[`archives`]}),m(e.is_favorite?d(`archives.toast.addedToFavorites`):d(`archives.toast.removedFromFavorites`))}}),{data:Le}=q({queryKey:[`archive-folders`,e.id],queryFn:()=>Q.getLibraryFoldersByArchive(e.id)}),Re=J({mutationFn:t=>Q.updateArchive(e.id,{project_id:t}),onSuccess:()=>{p.invalidateQueries({queryKey:[`archives`]}),p.invalidateQueries({queryKey:[`projects`]}),m(d(`archives.toast.projectUpdated`))},onError:()=>{m(d(`archives.toast.failedUpdateProject`),`error`)}}),ze=e=>{e.preventDefault(),ue({x:e.clientX,y:e.clientY})},Be=[...m2(e)?[{label:d(`archives.menu.print`),icon:(0,K.jsx)(wl,{className:`w-4 h-4`}),onClick:()=>x(!0),disabled:!e.file_path||!g(`archives`,`reprint`,e.created_by_id),title:e.file_path?g(`archives`,`reprint`,e.created_by_id)?void 0:d(`archives.permission.noReprint`):d(`archives.card.noFileForReprint`)},{label:d(`archives.menu.schedule`),icon:(0,K.jsx)(Zo,{className:`w-4 h-4`}),onClick:()=>ie(!0),disabled:!e.file_path||!h(`queue:create`),title:e.file_path?h(`queue:create`)?void 0:d(`archives.permission.noAddToQueue`):d(`archives.card.noFileForReprint`)},{label:d(`archives.menu.openInBambuStudio`),icon:(0,K.jsx)(qs,{className:`w-4 h-4`}),onClick:()=>{let t=e.print_name||e.filename||`model`;h2(e.id,t,`file`,c)},disabled:!e.file_path,title:e.file_path?void 0:d(`archives.card.noFileForReprint`)}]:[{label:d(`archives.menu.slice`),icon:l?(0,K.jsx)(Os,{className:`w-4 h-4`}):(0,K.jsx)(qs,{className:`w-4 h-4`}),onClick:()=>{if(l)C(!0);else{let t=e.print_name||e.filename||`model`;h2(e.id,t,`file`,c)}}}],{label:e.external_url?d(`archives.menu.externalLink`):d(`archives.menu.viewOnMakerWorld`),icon:(0,K.jsx)(yc,{className:`w-4 h-4`}),onClick:()=>{let t=e.external_url||e.makerworld_url;t&&window.open(t,`_blank`)},disabled:!e.external_url&&!e.makerworld_url},{label:``,divider:!0,onClick:()=>{}},{label:d(`archives.menu.preview3d`),icon:(0,K.jsx)(Wo,{className:`w-4 h-4`}),onClick:()=>{Ee()}},{label:d(`archives.menu.viewTimelapse`),icon:(0,K.jsx)(rc,{className:`w-4 h-4`}),onClick:()=>P(!0),disabled:!e.timelapse_path},{label:d(`archives.menu.scanForTimelapse`),icon:(0,K.jsx)(Fl,{className:`w-4 h-4`}),onClick:()=>Ne.mutate(),disabled:!e.printer_id||!!e.timelapse_path||Ne.isPending||!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)},{label:d(`archives.menu.uploadTimelapse`),icon:(0,K.jsx)(Eu,{className:`w-4 h-4`}),onClick:()=>ye.current?.click(),disabled:!!e.timelapse_path||!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)},...e.timelapse_path?[{label:d(`archives.menu.removeTimelapse`),icon:(0,K.jsx)(yu,{className:`w-4 h-4`}),onClick:()=>ce(!0),danger:!0,disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)}]:[],{label:``,divider:!0,onClick:()=>{}},{label:e.source_3mf_path?d(`archives.menu.downloadSource3mf`):d(`archives.menu.uploadSource3mf`),icon:(0,K.jsx)(Qs,{className:`w-4 h-4`}),onClick:()=>{e.source_3mf_path?Q.downloadSource3mf(e.id).catch(e=>{console.error(`Source 3MF download failed:`,e)}):_e.current?.click()},disabled:!e.source_3mf_path&&!g(`archives`,`update`,e.created_by_id),title:!e.source_3mf_path&&!g(`archives`,`update`,e.created_by_id)?d(`archives.permission.noUploadFiles`):void 0},...e.source_3mf_path?[{label:d(`archives.menu.replaceSource3mf`),icon:(0,K.jsx)(Eu,{className:`w-4 h-4`}),onClick:()=>_e.current?.click(),disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)},{label:d(`archives.menu.removeSource3mf`),icon:(0,K.jsx)(yu,{className:`w-4 h-4`}),onClick:()=>ae(!0),danger:!0,disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)}]:[],{label:e.f3d_path?d(`archives.menu.replaceF3d`):d(`archives.menu.uploadF3d`),icon:(0,K.jsx)(Wo,{className:`w-4 h-4`}),onClick:()=>ve.current?.click(),disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)},...e.f3d_path?[{label:d(`archives.menu.downloadF3d`),icon:(0,K.jsx)(Bs,{className:`w-4 h-4`}),onClick:()=>{Q.downloadF3d(e.id).catch(e=>{console.error(`F3D download failed:`,e)})}},{label:d(`archives.menu.removeF3d`),icon:(0,K.jsx)(yu,{className:`w-4 h-4`}),onClick:()=>U(!0),danger:!0,disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)}]:[],{label:``,divider:!0,onClick:()=>{}},{label:d(`archives.menu.download`),icon:(0,K.jsx)(Bs,{className:`w-4 h-4`}),onClick:()=>{Q.downloadArchive(e.id,`${e.print_name||e.filename}.3mf`).catch(e=>{console.error(`Archive download failed:`,e)})},disabled:!h(`archives:read`),title:h(`archives:read`)?void 0:d(`archives.permission.noDownload`)},{label:d(`archives.menu.copyDownloadLink`),icon:(0,K.jsx)(js,{className:`w-4 h-4`}),onClick:()=>{let t=`${window.location.origin}${Q.getArchiveDownload(e.id)}`;navigator.clipboard.writeText(t).then(()=>{m(d(`archives.toast.linkCopied`))}).catch(()=>{m(d(`archives.toast.failedCopyLink`),`error`)})},disabled:!h(`archives:read`),title:h(`archives:read`)?void 0:d(`archives.permission.noCopyLink`)},{label:d(`archives.menu.qrCode`),icon:(0,K.jsx)(Tl,{className:`w-4 h-4`}),onClick:()=>B(!0)},{label:e.photos?.length?d(`archives.menu.viewPhotosCount`,{count:e.photos.length}):d(`archives.menu.viewPhotos`),icon:(0,K.jsx)(Qo,{className:`w-4 h-4`}),onClick:()=>ee(!0),disabled:!e.photos?.length},{label:d(`archives.menu.projectPage`),icon:(0,K.jsx)(tc,{className:`w-4 h-4`}),onClick:()=>ne(!0)},{label:``,divider:!0,onClick:()=>{}},{label:e.is_favorite?d(`archives.menu.removeFromFavorites`):d(`archives.menu.addToFavorites`),icon:(0,K.jsx)(ou,{className:`w-4 h-4 ${e.is_favorite?`fill-yellow-400 text-yellow-400`:``}`}),onClick:()=>Ie.mutate(),disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)},{label:d(`archives.menu.edit`),icon:(0,K.jsx)(_l,{className:`w-4 h-4`}),onClick:()=>A(!0),disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)},{label:d(`archives.menu.printLog`),icon:(0,K.jsx)(Oc,{className:`w-4 h-4`}),onClick:()=>M(!0)},...e.project_id&&e.project_name?[{label:d(`archives.menu.goToProject`,{name:e.project_name}),icon:(0,K.jsx)(oc,{className:`w-4 h-4 text-bambu-green`}),onClick:()=>window.location.href=`/projects`}]:[],{label:d(`archives.menu.addToProject`),icon:(0,K.jsx)(oc,{className:`w-4 h-4`}),onClick:()=>{},disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`),submenuSearchPlaceholder:(a?.filter(e=>e.status===`active`).length??0)>5?d(`archives.menu.searchProjects`):void 0,submenu:(()=>{let t=[];if(e.project_id&&t.push({label:d(`archives.menu.removeFromProject`),icon:(0,K.jsx)(Ru,{className:`w-4 h-4`}),onClick:()=>Re.mutate(null),disabled:!g(`archives`,`update`,e.created_by_id)}),!a)t.push({label:d(`archives.menu.loading`),icon:(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}),onClick:()=>{},disabled:!0});else{let n=a.filter(e=>e.status===`active`).sort((e,t)=>e.name.localeCompare(t.name));n.length===0?t.push({label:d(`archives.menu.noProjectsAvailable`),icon:(0,K.jsx)(oc,{className:`w-4 h-4 opacity-50`}),onClick:()=>{},disabled:!0}):n.forEach(n=>{t.push({label:n.name,icon:(0,K.jsx)(`div`,{className:`w-3 h-3 rounded-full flex-shrink-0`,style:{backgroundColor:n.color||`#888`}}),onClick:()=>Re.mutate(n.id),disabled:e.project_id===n.id||!g(`archives`,`update`,e.created_by_id)})})}return t})()},{label:d(n?`archives.menu.deselect`:`archives.menu.select`),icon:n?(0,K.jsx)(ru,{className:`w-4 h-4`}):(0,K.jsx)(au,{className:`w-4 h-4`}),onClick:()=>r(e.id)},{label:``,divider:!0,onClick:()=>{}},{label:d(`archives.menu.delete`),icon:(0,K.jsx)(yu,{className:`w-4 h-4`}),onClick:()=>T(!0),danger:!0,disabled:!g(`archives`,`delete`,e.created_by_id),title:g(`archives`,`delete`,e.created_by_id)?void 0:d(`archives.permission.noDelete`)}];return(0,K.jsxs)(_d,{"data-archive-id":e.id,className:`relative flex flex-col group ${n?`ring-2 ring-bambu-green`:``} ${i?`cursor-pointer`:``}`,style:o?{outline:`4px solid #facc15`,outlineOffset:`2px`}:void 0,onContextMenu:ze,onClick:i?()=>r(e.id):void 0,children:[i&&(0,K.jsx)(`button`,{className:`absolute top-2 left-2 z-10 p-1 rounded bg-black/50 hover:bg-black/70 transition-colors`,onClick:t=>{t.stopPropagation(),r(e.id)},children:n?(0,K.jsx)(ru,{className:`w-5 h-5 text-bambu-green`}):(0,K.jsx)(au,{className:`w-5 h-5 text-white`})}),(0,K.jsxs)(`div`,{className:`aspect-video bg-bambu-dark relative flex-shrink-0 overflow-hidden rounded-t-xl`,onMouseEnter:()=>me(!0),onMouseLeave:()=>me(!1),children:[e.thumbnail_path?(0,K.jsx)(`img`,{src:de!==null&&Ce.length>0?Q.getArchivePlateThumbnail(e.id,Ce[Te]?.index??0):Q.getArchiveThumbnail(e.id),alt:e.print_name||e.filename,className:`w-full h-full object-cover`}):(0,K.jsx)(`div`,{className:`w-full h-full flex items-center justify-center`,children:(0,K.jsx)(jc,{className:`w-12 h-12 text-bambu-dark-tertiary`})}),we&&Ce.length>1&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`button`,{className:`absolute left-1 top-1/2 -translate-y-1/2 p-1 rounded-full bg-black/60 hover:bg-black/80 transition-all ${_?`opacity-100`:`opacity-0 group-hover:opacity-100`}`,onClick:e=>{e.stopPropagation(),fe(e=>{let t=e??0;return t>0?t-1:Ce.length-1})},title:d(`archives.card.previousPlate`),children:(0,K.jsx)(ss,{className:`w-4 h-4 text-white`})}),(0,K.jsx)(`button`,{className:`absolute right-1 top-1/2 -translate-y-1/2 p-1 rounded-full bg-black/60 hover:bg-black/80 transition-all ${_?`opacity-100`:`opacity-0 group-hover:opacity-100`}`,onClick:e=>{e.stopPropagation(),fe(e=>{let t=e??0;return t(0,K.jsx)(`button`,{className:`w-2 h-2 rounded-full transition-colors ${t===Te?`bg-bambu-green`:`bg-white/50 hover:bg-white/80`}`,onClick:e=>{e.stopPropagation(),fe(t)},title:e.name||d(`archives.card.plateNumber`,{index:e.index})},e.index))})]}),(0,K.jsx)(`button`,{className:`absolute top-2 left-2 p-1.5 rounded bg-black/50 hover:bg-black/70 transition-all ${_?`opacity-100`:`opacity-0 group-hover:opacity-100`} ${i?`left-10`:``}`,onClick:e=>{e.stopPropagation();let t=e.currentTarget.getBoundingClientRect();ue({x:t.left,y:t.bottom+4})},title:d(`archives.card.moreOptions`),children:(0,K.jsx)(Us,{className:`w-5 h-5 text-white`})}),(0,K.jsx)(`button`,{className:`absolute top-2 right-2 p-1 rounded transition-colors ${g(`archives`,`update`,e.created_by_id)?`bg-black/50 hover:bg-black/70`:`bg-black/30 cursor-not-allowed`}`,onClick:t=>{t.stopPropagation(),g(`archives`,`update`,e.created_by_id)&&Ie.mutate()},disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?e.is_favorite?d(`archives.card.removeFromFavorites`):d(`archives.card.addToFavorites`):d(`archives.permission.noUpdateArchives`),children:(0,K.jsx)(ou,{className:`w-5 h-5 ${e.is_favorite?`text-yellow-400 fill-yellow-400`:`text-white`} ${g(`archives`,`update`,e.created_by_id)?``:`opacity-50`}`})}),(e.status===`failed`||e.status===`aborted`)&&(0,K.jsx)(`div`,{className:`absolute top-2 left-12 px-2 py-1 rounded text-xs bg-status-error/80 text-white`,children:e.status===`aborted`?d(`archives.card.cancelled`):d(`archives.card.failed`)}),e.duplicate_count>0&&xe>0&&Se&&(0,K.jsxs)(`button`,{onClick:e=>{e.stopPropagation(),f?.(Se)},className:`absolute top-2 right-12 px-2 py-1 rounded text-xs bg-purple-500/80 hover:bg-purple-600/90 text-white flex items-center gap-1 transition-colors cursor-pointer`,title:d(`archives.viewOriginalPrint`,{id:Se}),children:[(0,K.jsx)(js,{className:`w-3 h-3`}),`#`,xe]}),e.duplicate_count>0&&xe===0&&(0,K.jsxs)(`span`,{className:`absolute top-2 right-12 px-2 py-1 rounded text-xs bg-purple-500/80 text-white flex items-center gap-1`,title:`${e.duplicate_count} reprint${e.duplicate_count===1?``:`s`}`,children:[(0,K.jsx)(gc,{className:`w-3 h-3`}),`+`,e.duplicate_count]}),e.source_3mf_path&&(0,K.jsx)(`button`,{className:`absolute bottom-2 left-2 p-1.5 rounded bg-black/60 hover:bg-black/80 transition-colors`,onClick:t=>{t.stopPropagation();let n=(e.print_name||e.filename||`source`).replace(/\.gcode\.3mf$/i,``)+`_source`;h2(e.id,n,`source`,c)},title:d(`archives.card.openSource3mf`),children:(0,K.jsx)(Qs,{className:`w-4 h-4 text-orange-400`})}),e.f3d_path&&(0,K.jsx)(`button`,{className:`absolute bottom-2 ${e.source_3mf_path?`left-12`:`left-2`} p-1.5 rounded bg-black/60 hover:bg-black/80 transition-colors`,onClick:t=>{t.stopPropagation(),Q.downloadF3d(e.id).catch(e=>{console.error(`F3D download failed:`,e)})},title:d(`archives.card.downloadF3d`),children:(0,K.jsx)(Wo,{className:`w-4 h-4 text-cyan-400`})}),(0,K.jsx)(`button`,{className:`absolute bottom-2 right-2 p-1.5 rounded bg-black/60 hover:bg-black/80 transition-colors`,onClick:e=>{e.stopPropagation(),Ee()},title:d(`archives.card.preview3d`),children:(0,K.jsx)(Lc,{className:`w-4 h-4 text-white`})}),e.timelapse_path&&(0,K.jsx)(`button`,{className:`absolute bottom-2 right-12 p-1.5 rounded bg-black/60 hover:bg-black/80 transition-colors`,onClick:e=>{e.stopPropagation(),P(!0)},title:d(`archives.card.viewTimelapse`),children:(0,K.jsx)(rc,{className:`w-4 h-4 text-bambu-green`})}),e.photos&&e.photos.length>0&&(0,K.jsxs)(`button`,{className:`absolute bottom-2 ${e.timelapse_path?`right-[5.5rem]`:`right-12`} p-1.5 rounded bg-black/60 hover:bg-black/80 transition-colors`,onClick:e=>{e.stopPropagation(),ee(!0)},title:e.photos.length===1?d(`archives.card.viewPhoto`):d(`archives.card.viewPhotos`,{count:e.photos.length}),children:[(0,K.jsx)(Qo,{className:`w-4 h-4 text-blue-400`}),e.photos.length>1&&(0,K.jsx)(`span`,{className:`absolute -top-1 -right-1 w-4 h-4 bg-blue-500 rounded-full text-[10px] text-white flex items-center justify-center`,children:e.photos.length})]}),Le&&Le.length>0&&(0,K.jsx)(wi,{to:`/files?folder=${Le[0].id}`,className:`absolute bottom-2 p-1.5 rounded bg-black/60 hover:bg-black/80 transition-colors`,onClick:e=>e.stopPropagation(),title:d(`archives.card.openFolder`,{name:Le[0].name}),style:{left:e.source_3mf_path?e.f3d_path?`5.5rem`:`3rem`:e.f3d_path?`3rem`:`0.5rem`},children:(0,K.jsx)(sc,{className:`w-4 h-4 text-yellow-400`})})]}),(0,K.jsxs)(yd,{className:`p-4 flex-1 flex flex-col`,children:[(0,K.jsxs)(`p`,{className:`text-[10px] text-bambu-gray/70 mb-1`,children:[`#`,e.id]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-2 mb-1`,children:[(0,K.jsx)(`h3`,{className:`min-w-0 font-medium text-white truncate`,children:e.print_name||e.filename}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,className:`p-1 sm:p-1.5 shrink-0`,onClick:()=>A(!0),disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?d(`archives.card.edit`):d(`archives.card.noPermissionEdit`),children:(0,K.jsx)(_l,{className:`w-3 h-3 sm:w-4 sm:h-4`})})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-3 flex-wrap`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:t}),(()=>{let t=pW(e.bed_type);return t?(0,K.jsx)(`img`,{src:t.icon,alt:t.label,title:t.label,className:`w-4 h-4 flex-shrink-0`}):null})(),(0,K.jsx)(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded font-medium ${m2(e)?`bg-bambu-green/20 text-bambu-green`:`bg-orange-500/20 text-orange-400`}`,title:m2(e)?d(`archives.card.slicedFile`):d(`archives.card.sourceFile`),children:m2(e)?d(`archives.card.gcode`):d(`archives.card.source`)}),e.content_hash&&(0,K.jsx)(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded font-mono bg-bambu-dark-tertiary/50 text-bambu-gray-light opacity-0 transition-opacity duration-150 group-hover:opacity-100`,title:`SHA256: ${e.content_hash}`,children:e.content_hash.slice(0,8).toUpperCase()}),e.project_name&&(0,K.jsx)(`span`,{className:`text-xs px-1.5 py-0.5 rounded-full truncate max-w-[120px]`,style:{backgroundColor:`${a?.find(t=>t.id===e.project_id)?.color||`#6b7280`}20`,color:a?.find(t=>t.id===e.project_id)?.color||`#6b7280`},title:d(`archives.card.project`,{name:e.project_name}),children:e.project_name}),e.run_count>1&&(0,K.jsx)(`button`,{className:`text-[10px] px-1.5 py-0.5 rounded font-medium bg-bambu-orange/20 text-bambu-orange hover:bg-bambu-orange/30 transition-colors cursor-pointer`,onClick:e=>{e.stopPropagation(),M(!0)},title:d(`archives.card.runsBadgeTitle`,{count:e.run_count,successful:e.successful_run_count,failed:e.failed_run_count}),children:d(`archives.card.runsBadge`,{count:e.run_count})})]}),(0,K.jsxs)(`div`,{className:`grid grid-cols-2 gap-2 text-xs mb-4 min-h-[48px]`,children:[(e.print_time_seconds||e.actual_time_seconds)&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-bambu-gray`,title:e.time_accuracy?`Estimated: ${Cf(e.print_time_seconds||0)}\nActual: ${Cf(e.actual_time_seconds||0)}\nAccuracy: ${e.time_accuracy.toFixed(0)}%`:e.actual_time_seconds?`Actual: ${Cf(e.actual_time_seconds)}`:`Estimated: ${Cf(e.print_time_seconds||0)}`,children:[(0,K.jsx)(xs,{className:`w-3 h-3`}),Cf(e.actual_time_seconds||e.print_time_seconds||0),e.time_accuracy&&(0,K.jsxs)(`span`,{className:`text-[10px] px-1 rounded ${e.time_accuracy>=95&&e.time_accuracy<=105?`bg-bambu-green/20 text-bambu-green`:e.time_accuracy>105?`bg-blue-500/20 text-blue-400`:`bg-orange-500/20 text-orange-400`}`,children:[e.time_accuracy>100?`+`:``,(e.time_accuracy-100).toFixed(0),`%`]})]}),e.filament_used_grams&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-bambu-gray`,children:[(0,K.jsx)(fl,{className:`w-3 h-3`}),e.filament_used_grams.toFixed(1),`g`]}),(e.cost!=null||e.energy_cost!=null)&&(0,K.jsxs)(`div`,{className:`flex items-center gap-3 text-bambu-gray`,children:[e.cost!=null&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,K.jsx)(Ds,{className:`w-3 h-3`}),u,e.cost.toFixed(2)]}),e.energy_cost!=null&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5`,title:`${d(`stats.energyUsed`)}: ${e.energy_kwh?.toFixed(3)||`N/A`} kWh`,children:[(0,K.jsx)(Bu,{className:`w-3 h-3`}),u,e.energy_cost.toFixed(2)]})]}),(e.layer_height||e.total_layers)&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-bambu-gray`,children:[(0,K.jsx)(Lc,{className:`w-3 h-3`}),e.total_layers&&(0,K.jsx)(`span`,{children:e.total_layers===1?d(`archives.card.layer`,{count:e.total_layers}):d(`archives.card.layers`,{count:e.total_layers})}),e.total_layers&&e.layer_height&&(0,K.jsx)(`span`,{className:`text-bambu-gray/50`,children:`·`}),e.layer_height&&(0,K.jsxs)(`span`,{children:[e.layer_height,`mm`]})]}),e.object_count!=null&&e.object_count>0&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-bambu-gray`,title:e.object_count===1?d(`archives.card.object`,{count:e.object_count}):d(`archives.card.objects`,{count:e.object_count}),children:[(0,K.jsx)(Wo,{className:`w-3 h-3`}),e.object_count===1?d(`archives.card.object`,{count:e.object_count}):d(`archives.card.objects`,{count:e.object_count})]}),e.sliced_for_model&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-bambu-gray`,title:d(`archives.card.slicedFor`,{model:e.sliced_for_model}),children:[(0,K.jsx)(wl,{className:`w-3 h-3`}),e.sliced_for_model]}),e.filament_type&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 col-span-2`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray text-xs`,children:e.filament_type}),e.filament_color&&(0,K.jsx)(`div`,{className:`flex items-center gap-0.5 flex-wrap`,children:e.filament_color.split(`,`).map((e,t)=>(0,K.jsx)(`div`,{className:`w-3 h-3 rounded-full border border-black/20`,style:{backgroundColor:e},title:e},t))})]})]}),(e.tags||e.notes)&&(0,K.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 mb-3`,children:[e.notes&&(0,K.jsx)(`div`,{className:`flex items-center gap-1 px-1.5 py-0.5 bg-blue-500/20 text-blue-400 rounded text-xs`,title:e.notes,children:(0,K.jsx)(cu,{className:`w-3 h-3`})}),e.tags?.split(`,`).map((e,t)=>(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-bambu-dark-tertiary text-bambu-gray-light rounded text-xs`,children:e.trim()},t))]}),(0,K.jsx)(`div`,{className:`flex-1`}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between text-xs text-bambu-gray border-t border-bambu-dark-tertiary pt-3`,children:[(0,K.jsx)(`span`,{children:bf(e.created_at,s)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[e.created_by_username&&(0,K.jsxs)(`span`,{className:`flex items-center gap-1`,title:d(`archives.card.uploadedBy`,{name:e.created_by_username}),children:[(0,K.jsx)(Du,{className:`w-3 h-3`}),e.created_by_username]}),(0,K.jsx)(`span`,{children:Cd(e.file_size)})]})]}),(0,K.jsxs)(`div`,{className:`flex gap-1 mt-3`,children:[m2(e)?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)($,{variant:`primary`,size:`sm`,className:`flex-1 min-w-0 overflow-hidden`,onClick:()=>x(!0),disabled:!e.file_path||!g(`archives`,`reprint`,e.created_by_id),title:e.file_path?g(`archives`,`reprint`,e.created_by_id)?void 0:d(`archives.card.noPermissionReprint`):d(`archives.card.noFileForReprint`),children:[(0,K.jsx)(wl,{className:`w-3 h-3 flex-shrink-0`}),(0,K.jsx)(`span`,{className:`hidden xl:inline truncate`,children:d(`archives.card.reprint`)})]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,className:`flex-1 min-w-0 overflow-hidden`,onClick:()=>ie(!0),disabled:!e.file_path||!h(`queue:create`),title:e.file_path?h(`queue:create`)?d(`archives.card.schedulePrint`):d(`archives.permission.noAddToQueue`):d(`archives.card.noFileForReprint`),children:[(0,K.jsx)(Zo,{className:`w-3 h-3 flex-shrink-0`}),(0,K.jsx)(`span`,{className:`hidden xl:inline truncate`,children:d(`archives.card.schedule`)})]}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,className:`min-w-0 p-1 sm:p-1.5`,onClick:()=>{let t=e.print_name||e.filename||`model`;h2(e.id,t,`file`,c)},title:d(`archives.card.openInBambuStudio`),children:(0,K.jsx)(qs,{className:`w-3 h-3 sm:w-4 sm:h-4`})})]}):(0,K.jsxs)($,{variant:`primary`,size:`sm`,className:`flex-1 min-w-0 overflow-hidden`,onClick:()=>{if(l)C(!0);else{let t=e.print_name||e.filename||`model`;h2(e.id,t,`file`,c)}},title:d(l?`slice.title`:`archives.card.openInBambuStudioToSlice`),children:[l?(0,K.jsx)(Os,{className:`w-3 h-3 flex-shrink-0`}):(0,K.jsx)(qs,{className:`w-3 h-3 flex-shrink-0`}),(0,K.jsx)(`span`,{className:`hidden xl:inline truncate`,children:d(`archives.card.slice`)})]}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,className:`min-w-0 p-1 sm:p-1.5`,onClick:()=>{let t=e.external_url||e.makerworld_url;t&&window.open(t,`_blank`)},disabled:!e.external_url&&!e.makerworld_url,title:e.external_url?d(`archives.card.externalLink`):e.makerworld_url?d(`archives.card.makerWorld`,{designer:e.designer||d(`archives.card.viewProject`)}):d(`archives.card.noExternalLink`),children:(0,K.jsx)(yc,{className:`w-3 h-3 sm:w-4 sm:h-4 ${!e.external_url&&!e.makerworld_url?`opacity-20`:``}`})}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,className:`min-w-0 p-1 sm:p-1.5`,onClick:()=>{Q.downloadArchive(e.id,`${e.print_name||e.filename}.3mf`).catch(e=>{console.error(`Archive download failed:`,e)})},title:d(`archives.card.download`),children:(0,K.jsx)(Bs,{className:`w-3 h-3 sm:w-4 sm:h-4`})}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,className:`min-w-0 p-1 sm:p-1.5`,onClick:()=>T(!0),disabled:!g(`archives`,`delete`,e.created_by_id),title:g(`archives`,`delete`,e.created_by_id)?d(`archives.card.delete`):d(`archives.card.noPermissionDelete`),children:(0,K.jsx)(yu,{className:`w-3 h-3 sm:w-4 sm:h-4 text-red-400`})})]})]}),k&&(0,K.jsx)(cG,{archive:e,onClose:()=>A(!1)}),j&&(0,K.jsx)(lG,{archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>M(!1)}),he&&(0,K.jsx)(JW,{plates:he,onSelect:t=>{ge(null),v(`/gcode-viewer?archive=${e.id}&plate=${t}`)},onClose:()=>ge(null)}),b&&(0,K.jsx)(xW,{mode:`reprint`,archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>x(!1)}),S&&(0,K.jsx)($W,{source:{kind:`archive`,id:e.id,filename:e.print_name||e.filename||`model`},onClose:()=>C(!1)}),w&&(0,K.jsxs)(Ad,{title:d(`archives.modal.deleteArchive`),message:d(`archives.modal.deleteConfirm`,{name:e.print_name||e.filename}),confirmText:d(`archives.modal.deleteButton`),variant:`danger`,confirmDisabled:(O.data?.currently_printing??0)>0,onConfirm:()=>{Fe.mutate(E),T(!1),D(!1)},onCancel:()=>{T(!1),D(!1)},children:[(O.data?.related_queue_items??0)>0&&(0,K.jsx)(`div`,{className:(O.data?.currently_printing??0)>0?`text-sm text-red-400 mb-2`:`text-sm text-amber-400 mb-2`,children:(O.data?.currently_printing??0)>0?d(`archives.modal.deleteBlockedByPrinting`,{count:O.data.currently_printing}):d(`archives.modal.deleteQueueItemsWarning`,{count:O.data.related_queue_items})}),(0,K.jsxs)(`label`,{className:`flex items-start gap-2 cursor-pointer text-sm text-bambu-gray`,children:[(0,K.jsx)(`input`,{type:`checkbox`,className:`mt-0.5 accent-red-500`,checked:E,onChange:e=>D(e.target.checked)}),(0,K.jsx)(`span`,{children:d(`archives.modal.deletePurgeStats`)})]})]}),H&&(0,K.jsx)(Ad,{title:d(`archives.modal.removeSource3mf`),message:d(`archives.modal.removeSource3mfConfirm`,{name:e.print_name||e.filename}),confirmText:d(`archives.modal.removeButton`),variant:`danger`,onConfirm:()=>{Ae.mutate(),ae(!1)},onCancel:()=>ae(!1)}),oe&&(0,K.jsx)(Ad,{title:d(`archives.modal.removeF3d`),message:d(`archives.modal.removeF3dConfirm`,{name:e.print_name||e.filename}),confirmText:d(`archives.modal.removeButton`),variant:`danger`,onConfirm:()=>{Me.mutate(),U(!1)},onCancel:()=>U(!1)}),se&&(0,K.jsx)(Ad,{title:d(`archives.modal.removeTimelapse`),message:d(`archives.modal.removeTimelapseConfirm`,{name:e.print_name||e.filename}),confirmText:d(`archives.modal.removeButton`),variant:`danger`,onConfirm:()=>{De.mutate(),ce(!1)},onCancel:()=>ce(!1)}),le&&(0,K.jsx)(uG,{x:le.x,y:le.y,items:Be,onClose:()=>ue(null)}),N&&e.timelapse_path&&(0,K.jsx)(p2,{src:Q.getArchiveTimelapse(e.id),title:d(`archives.modal.timelapse`,{name:e.print_name||e.filename}),downloadFilename:`${e.print_name||e.filename}_timelapse.mp4`,archiveId:e.id,onClose:()=>P(!1),onEdit:()=>{p.invalidateQueries({queryKey:[`archives`]}),P(!1)}}),F&&L.length>0&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/80 flex items-center justify-center z-50 p-4`,children:(0,K.jsxs)(`div`,{className:`bg-card-dark rounded-lg max-w-lg w-full max-h-[80vh] flex flex-col`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between p-4 border-b border-gray-700`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white`,children:d(`archives.modal.selectTimelapse`)}),(0,K.jsx)(`p`,{className:`text-sm text-gray-400 mt-1`,children:d(`archives.modal.selectTimelapseDesc`)})]}),(0,K.jsx)(`button`,{onClick:()=>{I(!1),R([])},className:`text-gray-400 hover:text-white p-1`,children:(0,K.jsx)(Ru,{className:`w-5 h-5`})})]}),(0,K.jsx)(`div`,{className:`overflow-y-auto flex-1 p-2`,children:L.map(e=>(0,K.jsxs)(`button`,{onClick:()=>Pe.mutate(e.name),disabled:Pe.isPending,className:`w-full text-left p-3 rounded-lg hover:bg-gray-700 transition-colors flex items-center gap-3 disabled:opacity-50`,children:[(0,K.jsx)(rc,{className:`w-8 h-8 text-bambu-green flex-shrink-0`}),(0,K.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,K.jsx)(`p`,{className:`text-white font-medium truncate`,children:e.name}),(0,K.jsxs)(`p`,{className:`text-sm text-gray-400`,children:[Cd(e.size),e.mtime&&` • ${bf(e.mtime,s)}`]})]})]},e.name))}),(0,K.jsx)(`div`,{className:`p-4 border-t border-gray-700`,children:(0,K.jsx)($,{variant:`secondary`,onClick:()=>{I(!1),R([])},className:`w-full`,children:`Cancel`})})]})}),z&&(0,K.jsx)(dG,{archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>B(!1)}),V&&e.photos&&e.photos.length>0&&(0,K.jsx)(fG,{archiveId:e.id,archiveName:e.print_name||e.filename,photos:e.photos,onClose:()=>ee(!1),onDelete:async t=>{try{await Q.deleteArchivePhoto(e.id,t),p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.photoDeleted`))}catch{m(d(`archives.toast.failedDeletePhoto`),`error`)}}}),te&&(0,K.jsx)(f2,{archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>ne(!1)}),re&&(0,K.jsx)(xW,{mode:`add-to-queue`,archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>ie(!1)}),(0,K.jsx)(`input`,{ref:_e,type:`file`,accept:`.3mf`,className:`hidden`,onChange:e=>{let t=e.target.files?.[0];t&&ke.mutate(t),e.target.value=``}}),(0,K.jsx)(`input`,{ref:ve,type:`file`,accept:`.f3d`,className:`hidden`,onChange:e=>{let t=e.target.files?.[0];t&&je.mutate(t),e.target.value=``}}),(0,K.jsx)(`input`,{ref:ye,type:`file`,accept:`.mp4,.avi,.mkv`,className:`hidden`,onChange:e=>{let t=e.target.files?.[0];t&&Oe.mutate(t),e.target.value=``}})]})}function XRe({archive:e,printerName:t,isSelected:n,onSelect:r,selectionMode:i,projects:a,isHighlighted:o,preferredSlicer:s=`bambu_studio`,useSlicerApi:c=!1,t:l,onNavigateToArchive:u}){let d=no(),{showToast:f}=Td(),{hasPermission:p,canModify:m}=dd(),[h,g]=(0,y.useState)(!1),[_,v]=(0,y.useState)(!1),[b,x]=(0,y.useState)(!1),[S,C]=(0,y.useState)(!1),w=q({queryKey:[`archive`,e.id,`delete-impact`],queryFn:()=>Q.getArchiveDeleteImpact(e.id),enabled:b,staleTime:0}),T=$n(),[E,D]=(0,y.useState)(!1),[O,k]=(0,y.useState)(!1),[A,j]=(0,y.useState)(!1),[M,N]=(0,y.useState)(!1),[P,F]=(0,y.useState)(!1),[I,L]=(0,y.useState)([]),[R,z]=(0,y.useState)(!1),[B,V]=(0,y.useState)(!1),[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)(null),ce=(0,y.useRef)(null),le=(0,y.useRef)(null),ue=(0,y.useRef)(null),[de,fe]=(0,y.useState)(null),pe=e.duplicate_sequence??0,me=e.original_archive_id??null,he=async()=>{try{let t=await Q.getArchivePlates(e.id);if(t.is_multi_plate&&t.plates.length>1){fe(t.plates);return}}catch{}T(`/gcode-viewer?archive=${e.id}`)},ge=J({mutationFn:()=>Q.deleteArchiveTimelapse(e.id),onSuccess:()=>{d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.timelapseRemoved`))},onError:e=>{f(e.message||l(`archives.toast.failedRemoveTimelapse`),`error`)}}),_e=J({mutationFn:t=>Q.uploadArchiveTimelapse(e.id,t),onSuccess:e=>{d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.timelapseUploaded`,{filename:e.filename}))},onError:e=>{f(e.message||l(`archives.toast.failedUploadTimelapse`),`error`)}}),ve=J({mutationFn:t=>Q.uploadSource3mf(e.id,t),onSuccess:e=>{d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.source3mfAttached`,{filename:e.filename}))},onError:e=>{f(e.message||l(`archives.toast.failedUploadSource3mf`),`error`)}}),ye=J({mutationFn:()=>Q.deleteSource3mf(e.id),onSuccess:()=>{d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.source3mfRemoved`))},onError:e=>{f(e.message||l(`archives.toast.failedRemoveSource3mf`),`error`)}}),be=J({mutationFn:t=>Q.uploadF3d(e.id,t),onSuccess:e=>{d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.f3dAttached`,{filename:e.filename}))},onError:e=>{f(e.message||l(`archives.toast.failedUploadF3d`),`error`)}}),xe=J({mutationFn:()=>Q.deleteF3d(e.id),onSuccess:()=>{d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.f3dRemoved`))},onError:e=>{f(e.message||l(`archives.toast.failedRemoveF3d`),`error`)}}),Se=J({mutationFn:()=>Q.scanArchiveTimelapse(e.id),onSuccess:e=>{e.status===`attached`?(d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.timelapseAttached`,{filename:e.filename}))):e.status===`exists`?f(l(`archives.toast.timelapseAlreadyAttached`)):e.status===`not_found`&&e.available_files&&e.available_files.length>0?(L(e.available_files),F(!0)):f(e.message||l(`archives.toast.noMatchingTimelapse`),`warning`)},onError:e=>{f(e.message||l(`archives.toast.failedScanTimelapse`),`error`)}}),Ce=J({mutationFn:t=>Q.selectArchiveTimelapse(e.id,t),onSuccess:e=>{d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.timelapseAttached`,{filename:e.filename})),F(!1),L([])},onError:e=>{f(e.message||l(`archives.toast.failedAttachTimelapse`),`error`)}}),we=J({mutationFn:t=>Q.deleteArchive(e.id,t),onSuccess:()=>{d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.archiveDeleted`))},onError:()=>{f(l(`archives.toast.failedDeleteArchive`),`error`)}}),Te=J({mutationFn:()=>Q.toggleFavorite(e.id),onSuccess:e=>{d.invalidateQueries({queryKey:[`archives`]}),f(e.is_favorite?l(`archives.toast.addedToFavorites`):l(`archives.toast.removedFromFavorites`))}}),{data:Ee}=q({queryKey:[`archive-folders`,e.id],queryFn:()=>Q.getLibraryFoldersByArchive(e.id)}),De=J({mutationFn:t=>Q.updateArchive(e.id,{project_id:t}),onSuccess:()=>{d.invalidateQueries({queryKey:[`archives`]}),d.invalidateQueries({queryKey:[`projects`]}),f(l(`archives.toast.projectUpdated`))},onError:()=>{f(l(`archives.toast.failedUpdateProject`),`error`)}}),Oe=e=>{e.preventDefault(),se({x:e.clientX,y:e.clientY})},ke=[...m2(e)?[{label:l(`archives.menu.print`),icon:(0,K.jsx)(wl,{className:`w-4 h-4`}),onClick:()=>D(!0),disabled:!e.file_path||!m(`archives`,`reprint`,e.created_by_id),title:e.file_path?m(`archives`,`reprint`,e.created_by_id)?void 0:l(`archives.permission.noReprint`):l(`archives.card.noFileForReprint`)},{label:l(`archives.menu.schedule`),icon:(0,K.jsx)(Zo,{className:`w-4 h-4`}),onClick:()=>j(!0),disabled:!e.file_path||!p(`queue:create`),title:e.file_path?p(`queue:create`)?void 0:l(`archives.permission.noAddToQueue`):l(`archives.card.noFileForReprint`)},{label:l(`archives.menu.openInBambuStudio`),icon:(0,K.jsx)(qs,{className:`w-4 h-4`}),onClick:()=>{let t=e.print_name||e.filename||`model`;h2(e.id,t,`file`,s)},disabled:!e.file_path,title:e.file_path?void 0:l(`archives.card.noFileForReprint`)}]:[{label:l(`archives.menu.slice`),icon:c?(0,K.jsx)(Os,{className:`w-4 h-4`}):(0,K.jsx)(qs,{className:`w-4 h-4`}),onClick:()=>{if(c)k(!0);else{let t=e.print_name||e.filename||`model`;h2(e.id,t,`file`,s)}}}],{label:e.external_url?l(`archives.menu.externalLink`):l(`archives.menu.viewOnMakerWorld`),icon:(0,K.jsx)(yc,{className:`w-4 h-4`}),onClick:()=>{let t=e.external_url||e.makerworld_url;t&&window.open(t,`_blank`)},disabled:!e.external_url&&!e.makerworld_url},{label:``,divider:!0,onClick:()=>{}},{label:l(`archives.menu.preview3d`),icon:(0,K.jsx)(Wo,{className:`w-4 h-4`}),onClick:()=>{he()}},{label:l(`archives.menu.viewTimelapse`),icon:(0,K.jsx)(rc,{className:`w-4 h-4`}),onClick:()=>N(!0),disabled:!e.timelapse_path},{label:l(`archives.menu.scanForTimelapse`),icon:(0,K.jsx)(Fl,{className:`w-4 h-4`}),onClick:()=>Se.mutate(),disabled:!e.printer_id||!!e.timelapse_path||Se.isPending||!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)},{label:l(`archives.menu.uploadTimelapse`),icon:(0,K.jsx)(Eu,{className:`w-4 h-4`}),onClick:()=>ue.current?.click(),disabled:!!e.timelapse_path||!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)},...e.timelapse_path?[{label:l(`archives.menu.removeTimelapse`),icon:(0,K.jsx)(yu,{className:`w-4 h-4`}),onClick:()=>oe(!0),danger:!0,disabled:!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)}]:[],{label:``,divider:!0,onClick:()=>{}},{label:e.source_3mf_path?l(`archives.menu.downloadSource3mf`):l(`archives.menu.uploadSource3mf`),icon:(0,K.jsx)(Qs,{className:`w-4 h-4`}),onClick:()=>{e.source_3mf_path?Q.downloadSource3mf(e.id).catch(e=>{console.error(`Source 3MF download failed:`,e)}):ce.current?.click()},disabled:!e.source_3mf_path&&!m(`archives`,`update`,e.created_by_id),title:!e.source_3mf_path&&!m(`archives`,`update`,e.created_by_id)?l(`archives.permission.noUploadFiles`):void 0},...e.source_3mf_path?[{label:l(`archives.menu.replaceSource3mf`),icon:(0,K.jsx)(Eu,{className:`w-4 h-4`}),onClick:()=>ce.current?.click(),disabled:!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)},{label:l(`archives.menu.removeSource3mf`),icon:(0,K.jsx)(yu,{className:`w-4 h-4`}),onClick:()=>re(!0),danger:!0,disabled:!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)}]:[],{label:e.f3d_path?l(`archives.menu.replaceF3d`):l(`archives.menu.uploadF3d`),icon:(0,K.jsx)(Wo,{className:`w-4 h-4`}),onClick:()=>le.current?.click(),disabled:!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)},...e.f3d_path?[{label:l(`archives.menu.downloadF3d`),icon:(0,K.jsx)(Bs,{className:`w-4 h-4`}),onClick:()=>{Q.downloadF3d(e.id).catch(e=>{console.error(`F3D download failed:`,e)})}},{label:l(`archives.menu.removeF3d`),icon:(0,K.jsx)(yu,{className:`w-4 h-4`}),onClick:()=>H(!0),danger:!0,disabled:!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)}]:[],{label:``,divider:!0,onClick:()=>{}},{label:l(`archives.menu.download`),icon:(0,K.jsx)(Bs,{className:`w-4 h-4`}),onClick:()=>{Q.downloadArchive(e.id,`${e.print_name||e.filename}.3mf`).catch(e=>{console.error(`Archive download failed:`,e)})},disabled:!p(`archives:read`),title:p(`archives:read`)?void 0:l(`archives.permission.noDownload`)},{label:l(`archives.menu.copyDownloadLink`),icon:(0,K.jsx)(js,{className:`w-4 h-4`}),onClick:()=>{let t=`${window.location.origin}${Q.getArchiveDownload(e.id)}`;navigator.clipboard.writeText(t).then(()=>{f(l(`archives.toast.linkCopied`))}).catch(()=>{f(l(`archives.toast.failedCopyLink`),`error`)})},disabled:!p(`archives:read`),title:p(`archives:read`)?void 0:l(`archives.permission.noCopyLink`)},{label:l(`archives.menu.qrCode`),icon:(0,K.jsx)(Tl,{className:`w-4 h-4`}),onClick:()=>z(!0)},{label:e.photos?.length?l(`archives.menu.viewPhotosCount`,{count:e.photos.length}):l(`archives.menu.viewPhotos`),icon:(0,K.jsx)(Qo,{className:`w-4 h-4`}),onClick:()=>V(!0),disabled:!e.photos?.length},{label:l(`archives.menu.projectPage`),icon:(0,K.jsx)(tc,{className:`w-4 h-4`}),onClick:()=>te(!0)},{label:``,divider:!0,onClick:()=>{}},{label:e.is_favorite?l(`archives.menu.removeFromFavorites`):l(`archives.menu.addToFavorites`),icon:(0,K.jsx)(ou,{className:`w-4 h-4 ${e.is_favorite?`fill-yellow-400 text-yellow-400`:``}`}),onClick:()=>Te.mutate(),disabled:!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)},{label:l(`archives.menu.edit`),icon:(0,K.jsx)(_l,{className:`w-4 h-4`}),onClick:()=>g(!0),disabled:!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)},{label:l(`archives.menu.printLog`),icon:(0,K.jsx)(Oc,{className:`w-4 h-4`}),onClick:()=>v(!0)},...e.project_id&&e.project_name?[{label:l(`archives.menu.goToProject`,{name:e.project_name}),icon:(0,K.jsx)(oc,{className:`w-4 h-4 text-bambu-green`}),onClick:()=>window.location.href=`/projects`}]:[],{label:l(`archives.menu.addToProject`),icon:(0,K.jsx)(oc,{className:`w-4 h-4`}),onClick:()=>{},submenuSearchPlaceholder:(a?.filter(e=>e.status===`active`).length??0)>5?l(`archives.menu.searchProjects`):void 0,submenu:(()=>{let t=[];if(e.project_id&&t.push({label:l(`archives.menu.removeFromProject`),icon:(0,K.jsx)(Ru,{className:`w-4 h-4`}),onClick:()=>De.mutate(null)}),!a)t.push({label:l(`archives.menu.loading`),icon:(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}),onClick:()=>{},disabled:!0});else{let n=a.filter(e=>e.status===`active`).sort((e,t)=>e.name.localeCompare(t.name));n.length===0?t.push({label:l(`archives.menu.noProjectsAvailable`),icon:(0,K.jsx)(oc,{className:`w-4 h-4 opacity-50`}),onClick:()=>{},disabled:!0}):n.forEach(n=>{t.push({label:n.name,icon:(0,K.jsx)(`div`,{className:`w-3 h-3 rounded-full flex-shrink-0`,style:{backgroundColor:n.color||`#888`}}),onClick:()=>De.mutate(n.id),disabled:e.project_id===n.id})})}return t})()},{label:l(n?`archives.menu.deselect`:`archives.menu.select`),icon:n?(0,K.jsx)(ru,{className:`w-4 h-4`}):(0,K.jsx)(au,{className:`w-4 h-4`}),onClick:()=>r(e.id)},{label:``,divider:!0,onClick:()=>{}},{label:l(`archives.menu.delete`),icon:(0,K.jsx)(yu,{className:`w-4 h-4`}),onClick:()=>x(!0),danger:!0,disabled:!m(`archives`,`delete`,e.created_by_id),title:m(`archives`,`delete`,e.created_by_id)?void 0:l(`archives.permission.noDelete`)}];return(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{"data-archive-id":e.id,className:`grid grid-cols-12 gap-4 px-4 py-3 items-center hover:bg-bambu-dark-tertiary/30 ${n?`bg-bambu-green/10`:``}`,style:o?{outline:`4px solid #facc15`,outlineOffset:`-4px`}:void 0,onContextMenu:Oe,children:[(0,K.jsxs)(`div`,{className:`col-span-1 flex items-center gap-2`,children:[i&&(0,K.jsx)(`button`,{onClick:()=>r(e.id),children:n?(0,K.jsx)(ru,{className:`w-4 h-4 text-bambu-green`}):(0,K.jsx)(au,{className:`w-4 h-4 text-bambu-gray`})}),e.thumbnail_path?(0,K.jsx)(`img`,{src:Q.getArchiveThumbnail(e.id),alt:``,className:`w-10 h-10 object-cover rounded`}):(0,K.jsx)(`div`,{className:`w-10 h-10 bg-bambu-dark rounded flex items-center justify-center`,children:(0,K.jsx)(jc,{className:`w-5 h-5 text-bambu-dark-tertiary`})})]}),(0,K.jsxs)(`div`,{className:`col-span-4`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`p`,{className:`text-white text-sm truncate`,children:e.print_name||e.filename}),(e.status===`failed`||e.status===`aborted`)&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 rounded text-[10px] leading-tight bg-status-error/80 text-white flex-shrink-0`,children:e.status===`aborted`?l(`archives.card.cancelled`):l(`archives.card.failed`)}),e.duplicate_count>0&&pe>0&&me&&(0,K.jsxs)(`button`,{onClick:e=>{e.stopPropagation(),u?.(me)},className:`px-1.5 py-0.5 rounded text-[10px] leading-tight bg-purple-500/80 hover:bg-purple-600/90 text-white flex-shrink-0 transition-colors flex items-center gap-1`,title:l(`archives.viewOriginalPrint`,{id:me}),children:[(0,K.jsx)(js,{className:`w-3 h-3`}),`#`,pe]}),e.duplicate_count>0&&pe===0&&(0,K.jsxs)(`span`,{className:`px-1.5 py-0.5 rounded text-[10px] leading-tight bg-purple-500/80 text-white flex-shrink-0 flex items-center gap-1`,title:`${e.duplicate_count} reprint${e.duplicate_count===1?``:`s`}`,children:[(0,K.jsx)(gc,{className:`w-3 h-3`}),`+`,e.duplicate_count]}),e.timelapse_path&&(0,K.jsx)(`span`,{title:l(`archives.list.hasTimelapse`),children:(0,K.jsx)(rc,{className:`w-3.5 h-3.5 text-bambu-green flex-shrink-0`})}),Ee&&Ee.length>0&&(0,K.jsx)(wi,{to:`/files?folder=${Ee[0].id}`,className:`flex-shrink-0`,title:l(`archives.card.openFolder`,{name:Ee[0].name}),onClick:e=>e.stopPropagation(),children:(0,K.jsx)(sc,{className:`w-3.5 h-3.5 text-yellow-400`})})]}),(e.filament_type||e.sliced_for_model)&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 mt-0.5`,children:[e.sliced_for_model&&(0,K.jsxs)(`span`,{className:`text-xs text-bambu-gray flex items-center gap-1`,title:l(`archives.card.slicedFor`,{model:e.sliced_for_model}),children:[(0,K.jsx)(wl,{className:`w-2.5 h-2.5`}),e.sliced_for_model]}),(()=>{let t=pW(e.bed_type);return t?(0,K.jsx)(`img`,{src:t.icon,alt:t.label,title:t.label,className:`w-3.5 h-3.5 flex-shrink-0`}):null})(),e.sliced_for_model&&e.filament_type&&(0,K.jsx)(`span`,{className:`text-bambu-gray/50`,children:`·`}),e.filament_type&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray`,children:e.filament_type}),e.filament_color&&(0,K.jsx)(`div`,{className:`flex items-center gap-0.5 flex-wrap`,children:e.filament_color.split(`,`).map((e,t)=>(0,K.jsx)(`div`,{className:`w-2.5 h-2.5 rounded-full border border-black/20`,style:{backgroundColor:e},title:e},t))})]})]}),(0,K.jsx)(`div`,{className:`col-span-2 text-sm text-bambu-gray truncate`,children:t}),(0,K.jsxs)(`div`,{className:`col-span-2 text-sm text-bambu-gray`,children:[(0,K.jsx)(`div`,{children:yf(e.created_at)}),e.created_by_username&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1 text-xs opacity-75`,title:l(`archives.card.uploadedBy`,{name:e.created_by_username}),children:[(0,K.jsx)(Du,{className:`w-3 h-3`}),e.created_by_username]})]}),(0,K.jsx)(`div`,{className:`col-span-1 text-sm text-bambu-gray`,children:Cd(e.file_size)}),(0,K.jsxs)(`div`,{className:`col-span-2 flex justify-end gap-1`,children:[m2(e)&&(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>D(!0),disabled:!m(`archives`,`reprint`,e.created_by_id),title:m(`archives`,`reprint`,e.created_by_id)?l(`archives.card.reprint`):l(`archives.card.noPermissionReprint`),className:`text-bambu-green hover:text-bambu-green-light hover:bg-bambu-green/10`,children:(0,K.jsx)(yl,{className:`w-4 h-4`})}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>{let t=e.print_name||e.filename||`model`;h2(e.id,t,`file`,s)},title:l(`archives.card.openInBambuStudio`),children:(0,K.jsx)(qs,{className:`w-4 h-4`})}),(e.external_url||e.makerworld_url)&&(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>window.open(e.external_url||e.makerworld_url,`_blank`),title:e.external_url?l(`archives.card.externalLink`):`MakerWorld`,children:(0,K.jsx)(yc,{className:`w-4 h-4`})}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>{Q.downloadArchive(e.id,`${e.print_name||e.filename}.3mf`).catch(e=>{console.error(`Archive download failed:`,e)})},title:l(`archives.card.download`),children:(0,K.jsx)(Bs,{className:`w-4 h-4`})}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>g(!0),disabled:!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?l(`archives.card.edit`):l(`archives.card.noPermissionEdit`),children:(0,K.jsx)(_l,{className:`w-4 h-4`})}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>x(!0),disabled:!m(`archives`,`delete`,e.created_by_id),title:m(`archives`,`delete`,e.created_by_id)?l(`archives.card.delete`):l(`archives.card.noPermissionDelete`),children:(0,K.jsx)(yu,{className:`w-4 h-4 text-red-400`})}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:e=>{let t=e.currentTarget.getBoundingClientRect();se({x:t.left,y:t.bottom+4})},title:l(`archives.card.moreOptions`),children:(0,K.jsx)(Us,{className:`w-4 h-4`})})]})]}),h&&(0,K.jsx)(cG,{archive:e,onClose:()=>g(!1)}),_&&(0,K.jsx)(lG,{archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>v(!1)}),de&&(0,K.jsx)(JW,{plates:de,onSelect:t=>{fe(null),T(`/gcode-viewer?archive=${e.id}&plate=${t}`)},onClose:()=>fe(null)}),E&&(0,K.jsx)(xW,{mode:`reprint`,archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>D(!1)}),O&&(0,K.jsx)($W,{source:{kind:`archive`,id:e.id,filename:e.print_name||e.filename||`model`},onClose:()=>k(!1)}),b&&(0,K.jsxs)(Ad,{title:l(`archives.modal.deleteArchive`),message:l(`archives.modal.deleteConfirm`,{name:e.print_name||e.filename}),confirmText:l(`archives.modal.deleteButton`),variant:`danger`,confirmDisabled:(w.data?.currently_printing??0)>0,onConfirm:()=>{we.mutate(S),x(!1),C(!1)},onCancel:()=>{x(!1),C(!1)},children:[(w.data?.related_queue_items??0)>0&&(0,K.jsx)(`div`,{className:(w.data?.currently_printing??0)>0?`text-sm text-red-400 mb-2`:`text-sm text-amber-400 mb-2`,children:(w.data?.currently_printing??0)>0?l(`archives.modal.deleteBlockedByPrinting`,{count:w.data.currently_printing}):l(`archives.modal.deleteQueueItemsWarning`,{count:w.data.related_queue_items})}),(0,K.jsxs)(`label`,{className:`flex items-start gap-2 cursor-pointer text-sm text-bambu-gray`,children:[(0,K.jsx)(`input`,{type:`checkbox`,className:`mt-0.5 accent-red-500`,checked:S,onChange:e=>C(e.target.checked)}),(0,K.jsx)(`span`,{children:l(`archives.modal.deletePurgeStats`)})]})]}),ne&&(0,K.jsx)(Ad,{title:l(`archives.modal.removeSource3mf`),message:l(`archives.modal.removeSource3mfConfirm`,{name:e.print_name||e.filename}),confirmText:l(`archives.modal.removeButton`),variant:`danger`,onConfirm:()=>{ye.mutate(),re(!1)},onCancel:()=>re(!1)}),ie&&(0,K.jsx)(Ad,{title:l(`archives.modal.removeF3d`),message:l(`archives.modal.removeF3dConfirm`,{name:e.print_name||e.filename}),confirmText:l(`archives.modal.removeButton`),variant:`danger`,onConfirm:()=>{xe.mutate(),H(!1)},onCancel:()=>H(!1)}),ae&&(0,K.jsx)(Ad,{title:l(`archives.modal.removeTimelapse`),message:l(`archives.modal.removeTimelapseConfirm`,{name:e.print_name||e.filename}),confirmText:l(`archives.modal.removeButton`),variant:`danger`,onConfirm:()=>{ge.mutate(),oe(!1)},onCancel:()=>oe(!1)}),U&&(0,K.jsx)(uG,{x:U.x,y:U.y,items:ke,onClose:()=>se(null)}),M&&e.timelapse_path&&(0,K.jsx)(p2,{src:Q.getArchiveTimelapse(e.id),title:l(`archives.modal.timelapse`,{name:e.print_name||e.filename}),downloadFilename:`${e.print_name||e.filename}_timelapse.mp4`,archiveId:e.id,onClose:()=>N(!1),onEdit:()=>{d.invalidateQueries({queryKey:[`archives`]}),N(!1)}}),P&&I.length>0&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/80 flex items-center justify-center z-50 p-4`,children:(0,K.jsxs)(`div`,{className:`bg-card-dark rounded-lg max-w-lg w-full max-h-[80vh] flex flex-col`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between p-4 border-b border-gray-700`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white`,children:l(`archives.modal.selectTimelapse`)}),(0,K.jsx)(`p`,{className:`text-sm text-gray-400 mt-1`,children:l(`archives.modal.selectTimelapseDesc`)})]}),(0,K.jsx)(`button`,{onClick:()=>{F(!1),L([])},className:`text-gray-400 hover:text-white p-1`,children:(0,K.jsx)(Ru,{className:`w-5 h-5`})})]}),(0,K.jsx)(`div`,{className:`overflow-y-auto flex-1 p-2`,children:I.map(e=>(0,K.jsxs)(`button`,{onClick:()=>Ce.mutate(e.name),disabled:Ce.isPending,className:`w-full text-left p-3 rounded-lg hover:bg-gray-700 transition-colors mb-1`,children:[(0,K.jsx)(`div`,{className:`font-medium text-white`,children:e.name}),(0,K.jsxs)(`div`,{className:`text-sm text-gray-400 flex gap-3`,children:[(0,K.jsx)(`span`,{children:Cd(e.size)}),e.mtime&&(0,K.jsx)(`span`,{children:yf(e.mtime)})]})]},e.name))})]})}),R&&(0,K.jsx)(dG,{archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>z(!1)}),B&&e.photos&&(0,K.jsx)(fG,{archiveId:e.id,archiveName:e.print_name||e.filename,photos:e.photos,onClose:()=>V(!1),onDelete:async t=>{try{await Q.deleteArchivePhoto(e.id,t),d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.photoDeleted`))}catch{f(l(`archives.toast.failedDeletePhoto`),`error`)}}}),ee&&(0,K.jsx)(f2,{archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>te(!1)}),A&&(0,K.jsx)(xW,{mode:`add-to-queue`,archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>j(!1)}),(0,K.jsx)(`input`,{ref:ce,type:`file`,accept:`.3mf`,className:`hidden`,onChange:e=>{let t=e.target.files?.[0];t&&ve.mutate(t),e.target.value=``}}),(0,K.jsx)(`input`,{ref:le,type:`file`,accept:`.f3d`,className:`hidden`,onChange:e=>{let t=e.target.files?.[0];t&&be.mutate(t),e.target.value=``}}),(0,K.jsx)(`input`,{ref:ue,type:`file`,accept:`.mp4,.avi,.mkv`,className:`hidden`,onChange:e=>{let t=e.target.files?.[0];t&&_e.mutate(t),e.target.value=``}})]})}var ZRe=[`completed`,`failed`,`aborted`,`cancelled`,`stopped`],QRe=[{id:`all`,label:`All Archives`,icon:(0,K.jsx)(sc,{className:`w-4 h-4`})},{id:`recent`,label:`Last 24 Hours`,icon:(0,K.jsx)(xs,{className:`w-4 h-4`})},{id:`this-week`,label:`This Week`,icon:(0,K.jsx)(Zo,{className:`w-4 h-4`})},{id:`this-month`,label:`This Month`,icon:(0,K.jsx)(Zo,{className:`w-4 h-4`})},{id:`favorites`,label:`Favorites`,icon:(0,K.jsx)(ou,{className:`w-4 h-4`})},{id:`not-printed`,label:`Not Printed`,icon:(0,K.jsx)(Eu,{className:`w-4 h-4`})},{id:`printed`,label:`Printed`,icon:(0,K.jsx)(wl,{className:`w-4 h-4`})},{id:`failed`,label:`Failed Prints`,icon:(0,K.jsx)(ds,{className:`w-4 h-4`})},{id:`duplicates`,label:`Duplicates`,icon:(0,K.jsx)(js,{className:`w-4 h-4`})}];function $Re(){let{t:e}=W(),t=no(),{showToast:n}=Td(),{hasPermission:r,hasAnyPermission:i}=dd(),a=(0,y.useRef)(null),[o,s]=(0,y.useState)(``),[c,l]=(0,y.useState)(()=>{let e=localStorage.getItem(`archiveFilterPrinter`);return e?Number(e):null}),[u,d]=(0,y.useState)(()=>localStorage.getItem(`archiveFilterMaterial`)),[f,p]=(0,y.useState)(()=>{let e=localStorage.getItem(`archiveFilterColors`);return e?new Set(JSON.parse(e)):new Set}),[m,h]=(0,y.useState)(()=>localStorage.getItem(`archiveColorFilterMode`)||`or`),[g,_]=(0,y.useState)(()=>localStorage.getItem(`archiveFilterFavorites`)===`true`),[v,b]=(0,y.useState)(()=>localStorage.getItem(`archiveHideFailed`)===`true`),[x,S]=(0,y.useState)(()=>localStorage.getItem(`archiveHideDuplicates`)===`true`),[C,w]=(0,y.useState)(()=>localStorage.getItem(`archiveFilterTag`)),[T,E]=(0,y.useState)(()=>localStorage.getItem(`archiveFilterFileType`)||`all`),[D,O]=(0,y.useState)(!1),[k,A]=(0,y.useState)([]),[j,M]=(0,y.useState)(new Set),[N,P]=(0,y.useState)(()=>localStorage.getItem(`archiveNo3MFWarningDismissed`)===`true`),{data:F}=q({queryKey:[`archives`,`no-3mf-warning`],queryFn:Q.getNo3MFWarning,staleTime:300*1e3,enabled:!N}),I=()=>{localStorage.setItem(`archiveNo3MFWarningDismissed`,`true`),P(!0)},[L,R]=(0,y.useState)(!1),[z,B]=(0,y.useState)(!1),[V,ee]=(0,y.useState)(!1),[te,ne]=(0,y.useState)(!1),[re,ie]=(0,y.useState)(()=>localStorage.getItem(`archiveViewMode`)||`grid`),[H,ae]=(0,y.useState)(()=>localStorage.getItem(`archiveSortBy`)||`date-desc`),[oe,U]=(0,y.useState)(()=>localStorage.getItem(`archiveCollection`)||`all`),[se,ce]=(0,y.useState)(0),[le,ue]=(0,y.useState)(()=>{try{let e=localStorage.getItem(`archivePageSize`);return e?Number(e):50}catch{return 50}}),[de,fe]=(0,y.useState)(!1),[pe,me]=(0,y.useState)(!1),[he,ge]=(0,y.useState)(!1),[_e,ve]=(0,y.useState)(!1),[ye,be]=(0,y.useState)(!1),[xe,Se]=(0,y.useState)(null),[Ce,we]=(0,y.useState)(null),[Te,Ee]=(0,y.useState)(()=>localStorage.getItem(`logFilterUser`)||null),[De,Oe]=(0,y.useState)(()=>localStorage.getItem(`logFilterStatus`)),[ke,Ae]=(0,y.useState)(()=>localStorage.getItem(`logFilterDateFrom`)||``),[je,Me]=(0,y.useState)(()=>localStorage.getItem(`logFilterDateTo`)||``),[Ne,Pe]=(0,y.useState)(()=>{let e=localStorage.getItem(`logOffset`);return e?Number(e):0}),[Fe,Ie]=(0,y.useState)(!1),[Le,Re]=(0,y.useState)(null),[ze,Be]=(0,y.useState)(null),[Ve,He]=(0,y.useState)(``),[Ue,We]=(0,y.useState)(``),[Ge,Ke]=(0,y.useState)(()=>{let e=localStorage.getItem(`logPageSize`);return e?Number(e):25}),qe=(0,y.useCallback)(e=>{we(e),Se(e)},[]);(0,y.useEffect)(()=>{if(xe){let t=setTimeout(()=>{let t=document.querySelector(`[data-archive-id="${xe}"]`);t?t.scrollIntoView({behavior:`smooth`,block:`center`}):Ce===xe&&n(e(`archives.originalPrintNotVisible`),`warning`),Ce===xe&&we(null)},100),r=setTimeout(()=>Se(null),5e3);return()=>{clearTimeout(t),clearTimeout(r)}}},[xe,Ce,n,e]);let{data:Je,isLoading:Ye}=q({queryKey:[`archives`,c],queryFn:()=>Q.getArchives(c||void 0)}),{data:Xe}=q({queryKey:[`printers`],queryFn:Q.getPrinters}),{data:Ze}=q({queryKey:[`projects`],queryFn:()=>Q.getProjects()}),{data:Qe}=q({queryKey:[`settings`],queryFn:Q.getSettings}),{data:$e}=q({queryKey:[`users`],queryFn:Q.getUsers,enabled:re===`log`}),{data:et,isLoading:tt}=q({queryKey:[`print-log`,c,Te,De,ke,je,o,Ne,Ge],queryFn:()=>Q.getPrintLog({search:o||void 0,printerId:c||void 0,username:Te||void 0,status:De||void 0,dateFrom:ke||void 0,dateTo:je||void 0,limit:Ge,offset:Ne}),enabled:re===`log`}),nt=Qe?.time_format||`system`,rt=Qe?.open_in_slicer||Qe?.preferred_slicer||`bambu_studio`,it=Qe?.use_slicer_api??!1,at=$d(Qe?.currency||`USD`),ot=J({mutationFn:async e=>(await Promise.all(e.map(e=>Q.deleteArchive(e))),e.length),onSuccess:e=>{t.invalidateQueries({queryKey:[`archives`]}),M(new Set),n(`${e} archive${e===1?``:`s`} deleted`)},onError:()=>{n(e(`archives.toast.failedDeleteArchives`),`error`)}}),st=J({mutationFn:()=>Q.clearPrintLog(),onSuccess:r=>{t.invalidateQueries({queryKey:[`print-log`]}),Pe(0),n(e(`archives.log.cleared`,{count:r.deleted}))},onError:()=>{n(e(`archives.log.clearFailed`),`error`)}}),ct=J({mutationFn:e=>Q.deletePrintLogEntry(e),onSuccess:()=>{t.invalidateQueries({queryKey:[`print-log`]}),t.invalidateQueries({queryKey:[`archives-stats`]}),n(e(`archives.log.entryDeleted`))},onError:()=>{n(e(`archives.log.entryDeleteFailed`),`error`)}}),lt=J({mutationFn:({id:e,body:t})=>Q.updatePrintLogEntry(e,t),onSuccess:()=>{t.invalidateQueries({queryKey:[`print-log`]}),t.invalidateQueries({queryKey:[`archives-stats`]}),Be(null),n(e(`archives.log.entryUpdated`))},onError:()=>{n(e(`archives.log.entryUpdateFailed`),`error`)}});(0,y.useEffect)(()=>{c===null?localStorage.removeItem(`archiveFilterPrinter`):localStorage.setItem(`archiveFilterPrinter`,c.toString())},[c]),(0,y.useEffect)(()=>{u?localStorage.setItem(`archiveFilterMaterial`,u):localStorage.removeItem(`archiveFilterMaterial`)},[u]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveFilterColors`,JSON.stringify([...f]))},[f]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveColorFilterMode`,m)},[m]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveFilterFavorites`,g.toString())},[g]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveHideFailed`,v.toString())},[v]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveHideDuplicates`,x.toString())},[x]),(0,y.useEffect)(()=>{C?localStorage.setItem(`archiveFilterTag`,C):localStorage.removeItem(`archiveFilterTag`)},[C]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveFilterFileType`,T)},[T]),(0,y.useEffect)(()=>{ce(0)},[o,c,u,f,m,g,v,x,C,T,H,oe]),(0,y.useEffect)(()=>{try{localStorage.setItem(`archivePageSize`,String(le))}catch{}},[le]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveViewMode`,re)},[re]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveSortBy`,H)},[H]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveCollection`,oe)},[oe]),(0,y.useEffect)(()=>{Te?localStorage.setItem(`logFilterUser`,Te):localStorage.removeItem(`logFilterUser`)},[Te]),(0,y.useEffect)(()=>{De?localStorage.setItem(`logFilterStatus`,De):localStorage.removeItem(`logFilterStatus`)},[De]),(0,y.useEffect)(()=>{ke?localStorage.setItem(`logFilterDateFrom`,ke):localStorage.removeItem(`logFilterDateFrom`)},[ke]),(0,y.useEffect)(()=>{je?localStorage.setItem(`logFilterDateTo`,je):localStorage.removeItem(`logFilterDateTo`)},[je]),(0,y.useEffect)(()=>{localStorage.setItem(`logOffset`,Ne.toString())},[Ne]),(0,y.useEffect)(()=>{localStorage.setItem(`logPageSize`,Ge.toString())},[Ge]);let ut=new Map(Xe?.map(e=>[e.id,e.name])||[]),dt=[...new Set(Je?.flatMap(e=>e.filament_type?.split(`, `)||[]).filter(Boolean)||[])].sort(),ft=[...new Set(Je?.flatMap(e=>e.filament_color?.split(`,`)||[]).filter(Boolean)||[])],pt=[...new Set(Je?.flatMap(e=>e.tags?.split(`,`).map(e=>e.trim())||[]).filter(Boolean)||[])].sort(),mt=Je?.filter(e=>{let t=new Date,n=vf(e.created_at)||new Date(0),r=!0;switch(oe){case`recent`:r=t.getTime()-n.getTime()<1440*60*1e3;break;case`this-week`:r=t.getTime()-n.getTime()<10080*60*1e3;break;case`this-month`:r=n.getMonth()===t.getMonth()&&n.getFullYear()===t.getFullYear();break;case`favorites`:r=e.is_favorite===!0;break;case`not-printed`:r=e.status===`archived`;break;case`printed`:r=ZRe.includes(e.status);break;case`failed`:r=e.status===`failed`||e.status===`aborted`;break;case`duplicates`:r=e.duplicate_count>0;break}let i=(e.print_name||e.filename).toLowerCase().includes(o.toLowerCase()),a=!u||e.filament_type?.split(`, `).includes(u),s=e.filament_color?.split(`,`)||[],c=f.size===0||(m===`or`?s.some(e=>f.has(e)):[...f].every(e=>s.includes(e))),l=oe===`favorites`||!g||e.is_favorite,d=oe===`failed`||!v||e.status!==`failed`&&e.status!==`aborted`,p=oe===`duplicates`||!x||e.duplicate_count===0||e.duplicate_sequence===0,h=e.tags?.split(`,`).map(e=>e.trim())||[],_=!C||h.includes(C),y=m2(e);return r&&i&&a&&c&&l&&d&&p&&_&&(T===`all`||T===`gcode`&&y||T===`source`&&!y)}).sort((e,t)=>{switch(H){case`date-desc`:return(vf(t.created_at)?.getTime()||0)-(vf(e.created_at)?.getTime()||0);case`date-asc`:return(vf(e.created_at)?.getTime()||0)-(vf(t.created_at)?.getTime()||0);case`name-asc`:return(e.print_name||e.filename).localeCompare(t.print_name||t.filename);case`name-desc`:return(t.print_name||t.filename).localeCompare(e.print_name||e.filename);case`size-desc`:return t.file_size-e.file_size;case`size-asc`:return e.file_size-t.file_size;default:return 0}}),ht=mt?.length||0,gt=le===-1,_t=gt?ht||1:le,vt=Math.max(1,Math.ceil(ht/_t)),yt=gt?mt:mt?.slice(se*_t,(se+1)*_t);(0,y.useEffect)(()=>{if(xe&&mt&&!gt){let e=mt.findIndex(e=>e.id===xe);if(e>=0){let t=Math.floor(e/_t);t!==se&&ce(t)}}},[xe]);let bt=L||j.size>0,xt=e=>{M(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},St=()=>{mt&&M(new Set(mt.map(e=>e.id)))},Ct=()=>{M(new Set),R(!1)},wt=e=>{p(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},Tt=()=>{p(new Set)},Et=()=>{s(``),l(null),d(null),_(!1),b(!1),S(!1),w(null),E(`all`)},Dt=o||c||u||g||v||x||C||T!==`all`,{isDraggingOver:Ot,dragHandlers:kt}=aG({disabled:D,extensions:[`.3mf`],onFiles:e=>{A(e),O(!0)},onRejected:()=>n(e(`archives.page.only3mfSupported`),`warning`)}),At=(0,y.useCallback)(e=>{let t=e.target;if(t.tagName===`INPUT`||t.tagName===`TEXTAREA`||t.isContentEditable){e.key===`Escape`&&t.blur();return}switch(e.key){case`/`:e.preventDefault(),a.current?.focus();break;case`u`:case`U`:!e.metaKey&&!e.ctrlKey&&(e.preventDefault(),O(!0));break;case`Escape`:bt&&Ct();break}},[bt]);return(0,y.useEffect)(()=>(document.addEventListener(`keydown`,At),()=>document.removeEventListener(`keydown`,At)),[At]),(0,K.jsxs)(`div`,{className:`p-4 md:p-8 relative`,...kt,children:[Ot&&(0,K.jsx)(`div`,{className:`fixed inset-0 z-50 bg-bambu-dark/90 flex items-center justify-center pointer-events-none`,children:(0,K.jsxs)(`div`,{className:`border-4 border-dashed border-bambu-green rounded-xl p-12 text-center`,children:[(0,K.jsx)(Eu,{className:`w-16 h-16 mx-auto mb-4 text-bambu-green`}),(0,K.jsx)(`p`,{className:`text-2xl font-semibold text-white mb-2`,children:e(`archives.page.dropFilesHere`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`archives.releaseToUpload`)})]})}),bt&&(0,K.jsxs)(`div`,{className:`fixed bottom-6 left-1/2 -translate-x-1/2 z-40 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-xl px-4 py-3 flex items-center gap-4`,children:[(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:Ct,children:[(0,K.jsx)(Ru,{className:`w-4 h-4`}),`Close`]}),(0,K.jsx)(`div`,{className:`w-px h-6 bg-bambu-dark-tertiary`}),(0,K.jsxs)(`span`,{className:`text-white font-medium`,children:[j.size,` selected`]}),(0,K.jsx)(`div`,{className:`w-px h-6 bg-bambu-dark-tertiary`}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:St,children:`Select All`}),(0,K.jsx)(`div`,{className:`w-px h-6 bg-bambu-dark-tertiary`}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>ee(!0),disabled:!i(`archives:update_own`,`archives:update_all`),title:i(`archives:update_own`,`archives:update_all`)?void 0:e(`archives.permission.noUpdateArchives`),children:[(0,K.jsx)(du,{className:`w-4 h-4`}),`Tags`]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>ne(!0),disabled:!i(`archives:update_own`,`archives:update_all`),title:i(`archives:update_own`,`archives:update_all`)?void 0:e(`archives.permission.noUpdateArchives`),children:[(0,K.jsx)(oc,{className:`w-4 h-4`}),`Project`]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,disabled:!i(`archives:update_own`,`archives:update_all`),title:i(`archives:update_own`,`archives:update_all`)?void 0:e(`archives.permission.noUpdateArchives`),onClick:()=>{let r=Array.from(j);Promise.all(r.map(e=>Q.toggleFavorite(e))).then(()=>{t.invalidateQueries({queryKey:[`archives`]}),n(`Toggled favorites for ${r.length} archive${r.length===1?``:`s`}`)}).catch(()=>{n(e(`archives.toast.failedUpdateFavorites`),`error`)})},children:[(0,K.jsx)(ou,{className:`w-4 h-4`}),`Favorite`]}),(0,K.jsxs)($,{size:`sm`,className:`bg-red-500 hover:bg-red-600`,onClick:()=>B(!0),disabled:!i(`archives:delete_own`,`archives:delete_all`),title:i(`archives:delete_own`,`archives:delete_all`)?void 0:e(`archives.permission.noDelete`),children:[(0,K.jsx)(yu,{className:`w-4 h-4`}),`Delete`]})]}),F?.has_fallback&&!N&&(0,K.jsxs)(`div`,{className:`mb-6 rounded-lg border border-amber-500/30 bg-amber-500/10 px-4 py-3 flex items-start gap-3`,children:[(0,K.jsx)(ds,{className:`w-5 h-5 text-amber-400 flex-shrink-0 mt-0.5`}),(0,K.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,K.jsx)(`div`,{className:`text-sm font-medium text-amber-200`,children:e(`archives.no3mfBanner.title`)}),(0,K.jsxs)(`div`,{className:`text-xs text-amber-200/80 mt-1`,children:[e(`archives.no3mfBanner.body`),` `,(0,K.jsxs)(`a`,{href:`https://bambuddy.cool/wiki/getting-started/#step-4-enable-store-sent-files-on-external-storage`,target:`_blank`,rel:`noreferrer`,className:`underline hover:text-amber-100 inline-flex items-center gap-1`,children:[e(`archives.no3mfBanner.docsLink`),(0,K.jsx)(qs,{className:`w-3 h-3`})]})]})]}),(0,K.jsx)(`button`,{onClick:I,className:`text-amber-200/60 hover:text-amber-200 flex-shrink-0 p-1 -m-1`,title:e(`archives.no3mfBanner.dismissLabel`),"aria-label":e(`archives.no3mfBanner.dismissLabel`),children:(0,K.jsx)(Ru,{className:`w-4 h-4`})})]}),(0,K.jsxs)(`div`,{className:`flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-8`,children:[(0,K.jsx)(`div`,{children:(0,K.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`h1`,{className:`text-2xl font-bold text-white flex items-center gap-3`,children:[(0,K.jsx)(Oo,{className:`w-7 h-7 text-bambu-green`}),`Archives`]}),(0,K.jsxs)(`p`,{className:`text-bambu-gray mt-1`,children:[mt?.length||0,` of `,Je?.length||0,` prints`]})]}),(0,K.jsx)(`select`,{className:`mt-0.5 px-3 py-1.5 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-bambu-gray-light text-sm focus:border-bambu-green focus:outline-none`,value:oe,onChange:e=>U(e.target.value),children:QRe.map(e=>(0,K.jsx)(`option`,{value:e.id,children:e.label},e.id))})]})}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 sm:gap-3 flex-wrap`,children:[(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsxs)($,{variant:`secondary`,onClick:()=>fe(!de),disabled:pe,children:[pe?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(ec,{className:`w-4 h-4`}),`Export`]}),de&&(0,K.jsxs)(`div`,{className:`absolute right-0 top-full mt-1 w-48 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-xl z-20`,children:[(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-white hover:bg-bambu-dark-tertiary transition-colors flex items-center gap-2 rounded-t-lg`,onClick:async()=>{fe(!1),me(!0);try{let{blob:t,filename:r}=await Q.exportArchives({format:`csv`,printerId:c||void 0,status:oe===`failed`?`failed`:void 0,search:o||void 0}),i=URL.createObjectURL(t),a=document.createElement(`a`);a.href=i,a.download=r,a.click(),URL.revokeObjectURL(i),n(e(`archives.toast.exportDownloaded`))}catch{n(e(`archives.toast.exportFailed`),`error`)}finally{me(!1)}},children:[(0,K.jsx)(tc,{className:`w-4 h-4`}),`Export as CSV`]}),(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-white hover:bg-bambu-dark-tertiary transition-colors flex items-center gap-2 rounded-b-lg`,onClick:async()=>{fe(!1),me(!0);try{let{blob:t,filename:r}=await Q.exportArchives({format:`xlsx`,printerId:c||void 0,status:oe===`failed`?`failed`:void 0,search:o||void 0}),i=URL.createObjectURL(t),a=document.createElement(`a`);a.href=i,a.download=r,a.click(),URL.revokeObjectURL(i),n(e(`archives.toast.exportDownloaded`))}catch{n(e(`archives.toast.exportFailed`),`error`)}finally{me(!1)}},children:[(0,K.jsx)(ec,{className:`w-4 h-4`}),`Export as Excel`]})]})]}),j.size>=2&&j.size<=5&&(0,K.jsxs)($,{variant:`secondary`,onClick:()=>ge(!0),children:[(0,K.jsx)(_c,{className:`w-4 h-4`}),`Compare (`,j.size,`)`]}),!bt&&(0,K.jsxs)($,{variant:`secondary`,onClick:()=>R(!0),children:[(0,K.jsx)(ru,{className:`w-4 h-4`}),`Select`]}),(0,K.jsxs)($,{onClick:()=>O(!0),disabled:!r(`archives:create`),title:r(`archives:create`)?void 0:e(`archives.permission.noCreate`),children:[(0,K.jsx)(Eu,{className:`w-4 h-4`}),`Upload 3MF`]}),r(`archives:purge`)&&(0,K.jsxs)($,{variant:`secondary`,onClick:()=>be(!0),title:e(`archivePurge.headerTooltip`),children:[(0,K.jsx)(yu,{className:`w-4 h-4 mr-2`}),e(`archivePurge.headerButton`)]})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center border border-bambu-dark-tertiary rounded-lg overflow-hidden flex-shrink-0 w-fit mb-4`,children:[(0,K.jsx)(`button`,{className:`p-2 ${re===`grid`?`bg-bambu-green text-white`:`bg-bambu-dark text-bambu-gray hover:text-white`}`,onClick:()=>ie(`grid`),title:e(`archives.gridView`),children:(0,K.jsx)(Rc,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{className:`p-2 ${re===`list`?`bg-bambu-green text-white`:`bg-bambu-dark text-bambu-gray hover:text-white`}`,onClick:()=>ie(`list`),title:e(`archives.listView`),children:(0,K.jsx)(Wc,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{className:`p-2 ${re===`calendar`?`bg-bambu-green text-white`:`bg-bambu-dark text-bambu-gray hover:text-white`}`,onClick:()=>ie(`calendar`),title:e(`archives.calendarView`),children:(0,K.jsx)(Yo,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{className:`p-2 ${re===`log`?`bg-bambu-green text-white`:`bg-bambu-dark text-bambu-gray hover:text-white`}`,onClick:()=>ie(`log`),title:e(`archives.logView`),children:(0,K.jsx)(bs,{className:`w-4 h-4`})})]}),re!==`log`&&(0,K.jsx)(_d,{className:`mb-6`,children:(0,K.jsxs)(yd,{className:`py-4`,children:[(0,K.jsxs)(`div`,{className:`flex flex-col md:flex-row gap-3 md:gap-4 md:items-center md:flex-wrap`,children:[(0,K.jsxs)(`div`,{className:`w-full md:flex-1 relative md:min-w-[200px]`,children:[(0,K.jsx)(Ll,{className:`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray`}),(0,K.jsx)(`input`,{ref:a,type:`text`,placeholder:e(`archives.searchPlaceholder`),className:`w-full pl-10 pr-4 py-3 md:py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,value:o,onChange:e=>s(e.target.value)})]}),(0,K.jsxs)(`div`,{className:`flex gap-2 md:gap-4 overflow-x-auto pb-1 md:pb-0 -mx-4 px-4 md:mx-0 md:px-0 md:flex-wrap scrollbar-hide`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 flex-shrink-0`,children:[(0,K.jsx)(pc,{className:`w-4 h-4 text-bambu-gray hidden md:block`}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,value:c||``,onChange:e=>l(e.target.value?Number(e.target.value):null),children:[(0,K.jsx)(`option`,{value:``,children:`All Printers`}),Xe?.map(e=>(0,K.jsx)(`option`,{value:e.id,children:e.name},e.id))]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 flex-shrink-0`,children:[(0,K.jsx)(fl,{className:`w-4 h-4 text-bambu-gray hidden md:block`}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,value:u||``,onChange:e=>d(e.target.value||null),children:[(0,K.jsx)(`option`,{value:``,children:`All Materials`}),dt.map(e=>(0,K.jsx)(`option`,{value:e,children:e},e))]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 flex-shrink-0`,children:[(0,K.jsx)(Qs,{className:`w-4 h-4 text-bambu-gray hidden md:block`}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,value:T,onChange:e=>E(e.target.value),children:[(0,K.jsx)(`option`,{value:`all`,children:`All Files`}),(0,K.jsx)(`option`,{value:`gcode`,children:`Sliced (GCODE)`}),(0,K.jsx)(`option`,{value:`source`,children:`Source Only`})]})]}),(0,K.jsxs)(`button`,{onClick:()=>_(!g),className:`flex items-center gap-2 px-3 py-2 rounded-lg border transition-colors flex-shrink-0 ${g?`bg-yellow-500/20 border-yellow-500 text-yellow-400`:`bg-bambu-dark border-bambu-dark-tertiary text-bambu-gray hover:text-white`}`,title:e(g?`archives.showAll`:`archives.showFavoritesOnly`),children:[(0,K.jsx)(ou,{className:`w-4 h-4 ${g?`fill-yellow-400`:``}`}),(0,K.jsx)(`span`,{className:`text-sm hidden md:inline`,children:`Favorites`})]}),(0,K.jsxs)(`button`,{onClick:()=>b(!v),className:`flex items-center gap-2 px-3 py-2 rounded-lg border transition-colors flex-shrink-0 ${v?`bg-red-500/20 border-red-500 text-red-400`:`bg-bambu-dark border-bambu-dark-tertiary text-bambu-gray hover:text-white`}`,title:e(v?`archives.showFailedPrints`:`archives.hideFailedPrints`),children:[(0,K.jsx)(ds,{className:`w-4 h-4 `}),(0,K.jsx)(`span`,{className:`text-sm hidden md:inline`,children:`Hide Failed`})]}),(0,K.jsxs)(`button`,{onClick:()=>S(!x),className:`flex items-center gap-2 px-3 py-2 rounded-lg border transition-colors flex-shrink-0 ${x?`bg-purple-500/20 border-purple-500 text-purple-400`:`bg-bambu-dark border-bambu-dark-tertiary text-bambu-gray hover:text-white`}`,title:e(`archives.hideDuplicates`),children:[(0,K.jsx)(js,{className:`w-4 h-4`}),(0,K.jsx)(`span`,{className:`text-sm hidden md:inline`,children:e(`archives.hideDuplicates`)})]}),pt.length>0&&(0,K.jsxs)(`div`,{className:`flex items-center gap-2 flex-shrink-0`,children:[(0,K.jsx)(du,{className:`w-4 h-4 text-bambu-gray hidden md:block`}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,value:C||``,onChange:e=>w(e.target.value||null),children:[(0,K.jsx)(`option`,{value:``,children:`All Tags`}),pt.map(e=>(0,K.jsx)(`option`,{value:e,children:e},e))]}),(0,K.jsx)(`button`,{onClick:()=>ve(!0),className:`p-2 rounded-lg bg-bambu-dark border border-bambu-dark-tertiary text-bambu-gray hover:text-white hover:border-bambu-green transition-colors`,title:e(`archives.manageTags`),children:(0,K.jsx)(Hl,{className:`w-4 h-4`})})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 flex-shrink-0`,children:[(0,K.jsx)(Po,{className:`w-4 h-4 text-bambu-gray hidden md:block`}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,value:H,onChange:e=>ae(e.target.value),children:[(0,K.jsx)(`option`,{value:`date-desc`,children:e(`archives.sortNewest`)}),(0,K.jsx)(`option`,{value:`date-asc`,children:e(`archives.sortOldest`)}),(0,K.jsxs)(`option`,{value:`name-asc`,children:[e(`archives.sortName`),` A-Z`]}),(0,K.jsxs)(`option`,{value:`name-desc`,children:[e(`archives.sortName`),` Z-A`]}),(0,K.jsx)(`option`,{value:`size-desc`,children:e(`archives.sortLargest`)}),(0,K.jsx)(`option`,{value:`size-asc`,children:e(`archives.sortSmallest`)})]})]})]}),Dt&&(0,K.jsxs)($,{variant:`ghost`,size:`sm`,onClick:Et,className:`text-bambu-gray hover:text-white`,children:[(0,K.jsx)(Ru,{className:`w-4 h-4`}),`Reset`]})]}),ft.length>0&&(0,K.jsxs)(`div`,{className:`flex items-center gap-3 mt-4 pt-4 border-t border-bambu-dark-tertiary`,children:[(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray`,children:`Colors:`}),f.size>1&&(0,K.jsx)(`button`,{onClick:()=>h(e=>e===`or`?`and`:`or`),className:`px-2 py-0.5 text-xs rounded transition-colors ${m===`and`?`bg-bambu-green text-white`:`bg-bambu-dark-tertiary text-bambu-gray hover:text-white`}`,title:m===`or`?`Match ANY selected color`:`Match ALL selected colors`,children:m.toUpperCase()}),(0,K.jsx)(`div`,{className:`flex items-center gap-1.5 flex-wrap`,children:ft.map(e=>(0,K.jsx)(`button`,{onClick:()=>wt(e),className:`w-6 h-6 rounded-full border-2 transition-all ${f.has(e)?`border-bambu-green scale-110`:`border-white/20 hover:border-white/40`}`,style:{backgroundColor:e},title:e},e))}),f.size>0&&(0,K.jsxs)(`button`,{onClick:Tt,className:`text-xs text-bambu-gray hover:text-white flex items-center gap-1`,children:[(0,K.jsx)(Ru,{className:`w-3 h-3`}),`Clear`]})]})]})}),(0,K.jsx)(qRe,{}),Ye?(0,K.jsx)(`div`,{className:`text-center py-12 text-bambu-gray`,children:e(`archives.loadingArchives`)}):mt?.length===0?(0,K.jsx)(_d,{children:(0,K.jsxs)(yd,{className:`text-center py-12`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(o?`archives.noArchivesSearch`:`archives.noArchivesYet`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-2`,children:`Archives are created automatically when prints complete`})]})}):re===`calendar`?(0,K.jsx)(_d,{className:`p-6`,children:(0,K.jsx)(aAe,{archives:mt||[],onArchiveClick:e=>{s(``),ie(`grid`),Se(e.id)},highlightedArchiveId:xe})}):re===`grid`?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6`,children:yt?.map(t=>(0,K.jsx)(YRe,{archive:t,printerName:t.printer_id?ut.get(t.printer_id)||`Unknown`:t.sliced_for_model||`No Printer`,isSelected:j.has(t.id),onSelect:xt,selectionMode:bt,projects:Ze,isHighlighted:t.id===xe,timeFormat:nt,preferredSlicer:rt,useSlicerApi:it,currency:at,t:e,onNavigateToArchive:qe},t.id))}),(0,K.jsx)(g2,{pageIndex:se,pageSize:le,totalRows:ht,totalPages:vt,onPageChange:ce,onPageSizeChange:e=>{ue(e),ce(0)},t:e})]}):re===`list`?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(_d,{children:(0,K.jsxs)(`div`,{className:`divide-y divide-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{className:`grid grid-cols-12 gap-4 px-4 py-3 text-xs text-bambu-gray font-medium`,children:[(0,K.jsx)(`div`,{className:`col-span-1`}),(0,K.jsx)(`div`,{className:`col-span-4`,children:`Name`}),(0,K.jsx)(`div`,{className:`col-span-2`,children:`Printer`}),(0,K.jsx)(`div`,{className:`col-span-2`,children:`Date`}),(0,K.jsx)(`div`,{className:`col-span-1`,children:`Size`}),(0,K.jsx)(`div`,{className:`col-span-2 text-right`,children:`Actions`})]}),yt?.map(t=>(0,K.jsx)(XRe,{archive:t,printerName:t.printer_id?ut.get(t.printer_id)||`Unknown`:t.sliced_for_model||`No Printer`,isSelected:j.has(t.id),onSelect:xt,selectionMode:bt,projects:Ze,isHighlighted:t.id===xe,preferredSlicer:rt,useSlicerApi:it,t:e,onNavigateToArchive:qe},t.id))]})}),(0,K.jsx)(g2,{pageIndex:se,pageSize:le,totalRows:ht,totalPages:vt,onPageChange:ce,onPageSizeChange:e=>{ue(e),ce(0)},t:e})]}):re===`log`?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(_d,{children:(0,K.jsx)(yd,{className:`py-3`,children:(0,K.jsxs)(`div`,{className:`flex flex-col md:flex-row gap-3 md:items-center md:flex-wrap`,children:[(0,K.jsxs)(`div`,{className:`flex-1 relative md:min-w-[200px]`,children:[(0,K.jsx)(Ll,{className:`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray`}),(0,K.jsx)(`input`,{type:`text`,placeholder:e(`archives.searchPlaceholder`),className:`w-full pl-10 pr-4 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none text-sm`,value:o,onChange:e=>{s(e.target.value),Pe(0)}})]}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none text-sm`,value:c||``,onChange:e=>{l(e.target.value?Number(e.target.value):null),Pe(0)},children:[(0,K.jsx)(`option`,{value:``,children:e(`archives.log.allPrinters`)}),Xe?.map(e=>(0,K.jsx)(`option`,{value:e.id,children:e.name},e.id))]}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none text-sm`,value:Te||``,onChange:e=>{Ee(e.target.value||null),Pe(0)},children:[(0,K.jsx)(`option`,{value:``,children:e(`archives.log.allUsers`)}),$e?.map(e=>(0,K.jsx)(`option`,{value:e.username,children:e.username},e.id))]}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none text-sm`,value:De||``,onChange:e=>{Oe(e.target.value||null),Pe(0)},children:[(0,K.jsx)(`option`,{value:``,children:e(`archives.log.allStatuses`)}),(0,K.jsx)(`option`,{value:`completed`,children:e(`archives.status.completed`)}),(0,K.jsx)(`option`,{value:`failed`,children:e(`archives.status.failed`)}),(0,K.jsx)(`option`,{value:`stopped`,children:e(`archives.status.stopped`)}),(0,K.jsx)(`option`,{value:`cancelled`,children:e(`archives.log.cancelled`)}),(0,K.jsx)(`option`,{value:`skipped`,children:e(`archives.log.skipped`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`label`,{className:`text-sm text-bambu-gray`,children:e(`archives.log.dateFrom`)}),(0,K.jsx)(`input`,{type:`date`,className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none text-sm`,value:ke,onChange:e=>{Ae(e.target.value),Pe(0)}})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`label`,{className:`text-sm text-bambu-gray`,children:e(`archives.log.dateTo`)}),(0,K.jsx)(`input`,{type:`date`,className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none text-sm`,value:je,onChange:e=>{Me(e.target.value),Pe(0)}})]}),(0,K.jsx)(`div`,{className:`ml-auto`,children:(0,K.jsxs)($,{variant:`danger`,size:`sm`,onClick:()=>Ie(!0),disabled:!r(`archives:delete_all`)||st.isPending,children:[(0,K.jsx)(yu,{className:`w-4 h-4`}),e(`archives.log.clearLog`)]})})]})})}),(0,K.jsx)(_d,{children:tt?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-12`,children:(0,K.jsx)(X,{className:`w-6 h-6 animate-spin text-bambu-green`})}):et?.items.length?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`div`,{className:`overflow-x-auto`,children:(0,K.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,K.jsx)(`thead`,{children:(0,K.jsxs)(`tr`,{className:`border-b border-bambu-dark-tertiary text-bambu-gray text-left`,children:[(0,K.jsx)(`th`,{className:`px-4 py-3 font-medium`,children:e(`archives.log.date`)}),(0,K.jsx)(`th`,{className:`px-4 py-3 font-medium`,children:e(`archives.log.printName`)}),(0,K.jsx)(`th`,{className:`px-4 py-3 font-medium`,children:e(`archives.log.printer`)}),(0,K.jsx)(`th`,{className:`px-4 py-3 font-medium`,children:e(`archives.log.user`)}),(0,K.jsx)(`th`,{className:`px-4 py-3 font-medium`,children:e(`archives.log.status`)}),(0,K.jsx)(`th`,{className:`px-4 py-3 font-medium`,children:e(`archives.log.duration`)}),(0,K.jsx)(`th`,{className:`px-4 py-3 font-medium`,children:e(`archives.log.filament`)}),(0,K.jsx)(`th`,{className:`px-4 py-3 font-medium w-10`,"aria-label":e(`common.actions`)})]})}),(0,K.jsx)(`tbody`,{className:`divide-y divide-bambu-dark-tertiary`,children:et.items.map(t=>(0,K.jsxs)(`tr`,{className:`hover:bg-bambu-dark-secondary/50`,children:[(0,K.jsx)(`td`,{className:`px-4 py-3 text-white whitespace-nowrap`,children:bf(t.started_at||t.created_at,nt)}),(0,K.jsx)(`td`,{className:`px-4 py-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[t.thumbnail_path&&(0,K.jsx)(`img`,{src:Q.getPrintLogThumbnail(t.id),alt:``,className:`w-8 h-8 rounded object-cover flex-shrink-0`,onError:e=>{e.target.style.display=`none`}}),(0,K.jsx)(`span`,{className:`text-white break-words`,title:t.print_name||``,children:t.print_name||`—`})]})}),(0,K.jsx)(`td`,{className:`px-4 py-3 text-bambu-gray-light`,children:t.printer_name||`—`}),(0,K.jsx)(`td`,{className:`px-4 py-3 text-bambu-gray-light`,children:t.created_by_username||`—`}),(0,K.jsxs)(`td`,{className:`px-4 py-3`,children:[(0,K.jsx)(`span`,{className:`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ${t.status===`completed`?`bg-green-500/20 text-green-400`:t.status===`failed`?`bg-red-500/20 text-red-400`:t.status===`stopped`?`bg-yellow-500/20 text-yellow-400`:t.status===`cancelled`?`bg-orange-500/20 text-orange-400`:t.status===`skipped`?`bg-blue-500/20 text-blue-400`:`bg-gray-500/20 text-gray-400`}`,children:t.status}),t.failure_reason&&(0,K.jsx)(`span`,{className:`block text-[10px] text-bambu-gray mt-0.5`,children:e(`editArchive.failureReasons.${t.failure_reason}`,{defaultValue:t.failure_reason})})]}),(0,K.jsx)(`td`,{className:`px-4 py-3 text-bambu-gray-light whitespace-nowrap`,children:t.duration_seconds?Cf(t.duration_seconds):`—`}),(0,K.jsx)(`td`,{className:`px-4 py-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[t.filament_color&&(0,K.jsx)(`div`,{className:`flex items-center gap-0.5 flex-wrap`,children:t.filament_color.split(`,`).map((e,t)=>{let n=e.trim();return(0,K.jsx)(`span`,{className:`w-3 h-3 rounded-full border border-black/20 flex-shrink-0`,style:{backgroundColor:n.startsWith(`#`)?n:void 0},title:n},t)})}),(0,K.jsx)(`span`,{className:`text-bambu-gray-light text-xs`,children:t.filament_type||`—`})]})}),(0,K.jsx)(`td`,{className:`px-4 py-3 text-right`,children:(0,K.jsxs)(`div`,{className:`inline-flex items-center gap-2`,children:[(0,K.jsx)(`button`,{type:`button`,onClick:()=>{Be(t),He(t.failure_reason||``),We(t.status)},disabled:lt.isPending||!(r(`archives:update_all`)||r(`archives:update_own`)),title:r(`archives:update_all`)||r(`archives:update_own`)?e(`archives.log.editEntryTitle`):e(`archives.permission.noEdit`),className:`text-bambu-gray hover:text-bambu-blue disabled:opacity-40 disabled:hover:text-bambu-gray transition-colors`,children:(0,K.jsx)(_l,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>Re(t.id),disabled:ct.isPending||!(r(`archives:delete_all`)||r(`archives:delete_own`)),title:r(`archives:delete_all`)||r(`archives:delete_own`)?e(`archives.log.deleteEntryTitle`):e(`archives.permission.noDelete`),className:`text-bambu-gray hover:text-red-400 disabled:opacity-40 disabled:hover:text-bambu-gray transition-colors`,children:(0,K.jsx)(yu,{className:`w-4 h-4`})})]})})]},t.id))})]})}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between px-4 py-3 border-t border-bambu-dark-tertiary flex-wrap gap-2`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(`span`,{className:`text-sm text-bambu-gray`,children:e(`archives.log.showing`,{count:Math.min(Ne+Ge,et.total),total:et.total})}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,K.jsx)(`label`,{className:`text-xs text-bambu-gray`,children:e(`archives.log.rowsPerPage`)}),(0,K.jsxs)(`select`,{className:`px-2 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-xs focus:border-bambu-green focus:outline-none`,value:Ge,onChange:e=>{Ke(Number(e.target.value)),Pe(0)},children:[(0,K.jsx)(`option`,{value:10,children:`10`}),(0,K.jsx)(`option`,{value:25,children:`25`}),(0,K.jsx)(`option`,{value:50,children:`50`}),(0,K.jsx)(`option`,{value:100,children:`100`})]})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsxs)(`span`,{className:`text-sm text-bambu-gray`,children:[e(`archives.log.page`),` `,Math.floor(Ne/Ge)+1,` / `,Math.max(1,Math.ceil(et.total/Ge))]}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>Pe(Math.max(0,Ne-Ge)),disabled:Ne===0,children:(0,K.jsx)(ss,{className:`w-4 h-4`})}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>Pe(Ne+Ge),disabled:Ne+Ge>=et.total,children:(0,K.jsx)(as,{className:`w-4 h-4`})})]})]})]}):(0,K.jsx)(`div`,{className:`text-center py-12 text-bambu-gray`,children:e(`archives.log.noEntries`)})})]}):null,D&&(0,K.jsx)(Kke,{onClose:()=>{O(!1),A([])},initialFiles:k}),ye&&(0,K.jsx)(Jke,{onClose:()=>be(!1)}),z&&(0,K.jsx)(Ad,{title:e(`archives.modal.deleteArchives`),message:e(`archives.modal.deleteArchivesConfirm`,{count:j.size}),confirmText:e(`archives.modal.deleteCount`,{count:j.size}),variant:`danger`,onConfirm:()=>{ot.mutate(Array.from(j)),B(!1)},onCancel:()=>B(!1)}),V&&(0,K.jsx)($ke,{selectedIds:Array.from(j),existingTags:pt,onClose:()=>ee(!1)}),te&&(0,K.jsx)(eAe,{selectedIds:Array.from(j),onClose:()=>ne(!1)}),he&&j.size>=2&&j.size<=5&&(0,K.jsx)(URe,{archiveIds:Array.from(j),onClose:()=>{ge(!1),M(new Set),R(!1)}}),_e&&(0,K.jsx)(JRe,{onClose:()=>ve(!1)}),Fe&&(0,K.jsx)(Ad,{title:e(`archives.log.clearLogTitle`),message:e(`archives.log.clearLogConfirm`),confirmText:e(`archives.log.clearLogButton`),variant:`danger`,onConfirm:()=>{st.mutate(),Ie(!1)},onCancel:()=>Ie(!1)}),Le!==null&&(0,K.jsx)(Ad,{title:e(`archives.log.deleteEntryTitle`),message:e(`archives.log.deleteEntryConfirm`),confirmText:e(`common.delete`),variant:`danger`,onConfirm:()=>{ct.mutate(Le),Re(null)},onCancel:()=>Re(null)}),ze!==null&&(0,K.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm`,onClick:()=>Be(null),children:(0,K.jsxs)(`div`,{className:`bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg w-full max-w-md mx-4 p-6`,onClick:e=>e.stopPropagation(),children:[(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white mb-4`,children:e(`archives.log.editEntryTitle`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mb-4`,children:e(`archives.log.editEntryDescription`)}),(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:e(`editArchive.status`)}),(0,K.jsxs)(`select`,{value:Ue,onChange:e=>We(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`completed`,children:e(`archives.log.statuses.completed`,{defaultValue:`completed`})}),(0,K.jsx)(`option`,{value:`failed`,children:e(`archives.log.statuses.failed`,{defaultValue:`failed`})}),(0,K.jsx)(`option`,{value:`stopped`,children:e(`archives.log.statuses.stopped`,{defaultValue:`stopped`})}),(0,K.jsx)(`option`,{value:`cancelled`,children:e(`archives.log.statuses.cancelled`,{defaultValue:`cancelled`})}),(0,K.jsx)(`option`,{value:`skipped`,children:e(`archives.log.statuses.skipped`,{defaultValue:`skipped`})})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:e(`editArchive.failureReason`)}),(0,K.jsxs)(`select`,{value:Ve,onChange:e=>He(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:``,children:e(`editArchive.selectReason`)}),sG.map(t=>(0,K.jsx)(`option`,{value:t,children:e(`editArchive.failureReasons.${t}`)},t))]})]})]}),(0,K.jsxs)(`div`,{className:`flex justify-end gap-2 mt-6`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>Be(null),children:e(`common.cancel`)}),(0,K.jsx)($,{variant:`primary`,onClick:()=>{let e={};if(Ve!==(ze.failure_reason||``)&&(e.failure_reason=Ve||null),Ue!==ze.status&&(e.status=Ue),Object.keys(e).length===0){Be(null);return}lt.mutate({id:ze.id,body:e})},disabled:lt.isPending,children:lt.isPending?e(`editArchive.saving`):e(`common.save`)})]})]})})]})}function g2({pageIndex:e,pageSize:t,totalRows:n,totalPages:r,onPageChange:i,onPageSizeChange:a,t:o}){let s=t===-1;if(r<=1&&!s)return null;let c=s?n||1:t;return(0,K.jsxs)(`div`,{className:`flex items-center justify-between pt-2 text-sm`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:s?`${n} ${o(`archives.prints`)}`:(0,K.jsxs)(K.Fragment,{children:[o(`archives.pagination.showing`),` `,e*c+1,` `,o(`archives.pagination.to`),` `,Math.min((e+1)*c,n),` `,o(`archives.pagination.of`),` `,n,` `,o(`archives.prints`)]})}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:o(`archives.pagination.show`)}),(0,K.jsxs)(`select`,{value:t,onChange:e=>a(Number(e.target.value)),className:`px-2 py-1 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded text-white text-sm focus:outline-none focus:border-bambu-green`,children:[[25,50,100,200].map(e=>(0,K.jsx)(`option`,{value:e,children:e},e)),(0,K.jsx)(`option`,{value:-1,children:o(`archives.pagination.all`)})]}),!s&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`button`,{onClick:()=>i(0),disabled:e===0,className:`p-1.5 rounded text-bambu-gray hover:text-white disabled:opacity-30 disabled:cursor-not-allowed transition-colors`,children:(0,K.jsx)(ls,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{onClick:()=>i(Math.max(0,e-1)),disabled:e===0,className:`p-1.5 rounded text-bambu-gray hover:text-white disabled:opacity-30 disabled:cursor-not-allowed transition-colors`,children:(0,K.jsx)(ss,{className:`w-4 h-4`})}),(0,K.jsxs)(`span`,{className:`text-bambu-gray px-2 whitespace-nowrap`,children:[o(`archives.pagination.page`),` `,e+1,` `,o(`archives.pagination.of`),` `,r]}),(0,K.jsx)(`button`,{onClick:()=>i(Math.min(r-1,e+1)),disabled:e>=r-1,className:`p-1.5 rounded text-bambu-gray hover:text-white disabled:opacity-30 disabled:cursor-not-allowed transition-colors`,children:(0,K.jsx)(as,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{onClick:()=>i(r-1),disabled:e>=r-1,className:`p-1.5 rounded text-bambu-gray hover:text-white disabled:opacity-30 disabled:cursor-not-allowed transition-colors`,children:(0,K.jsx)(us,{className:`w-4 h-4`})})]})]})]})}function eze(){var e=[...arguments];return(0,y.useMemo)(()=>t=>{e.forEach(e=>e(t))},e)}var _2=typeof window<`u`&&window.document!==void 0&&window.document.createElement!==void 0;function v2(e){let t=Object.prototype.toString.call(e);return t===`[object Window]`||t===`[object global]`}function y2(e){return`nodeType`in e}function b2(e){return e?v2(e)?e:y2(e)?e.ownerDocument?.defaultView??window:window:window}function x2(e){let{Document:t}=b2(e);return e instanceof t}function S2(e){return v2(e)?!1:e instanceof b2(e).HTMLElement}function C2(e){return e instanceof b2(e).SVGElement}function w2(e){return e?v2(e)?e.document:y2(e)?x2(e)?e:S2(e)||C2(e)?e.ownerDocument:document:document:document}var T2=_2?y.useLayoutEffect:y.useEffect;function E2(e){let t=(0,y.useRef)(e);return T2(()=>{t.current=e}),(0,y.useCallback)(function(){var e=[...arguments];return t.current==null?void 0:t.current(...e)},[])}function tze(){let e=(0,y.useRef)(null);return[(0,y.useCallback)((t,n)=>{e.current=setInterval(t,n)},[]),(0,y.useCallback)(()=>{e.current!==null&&(clearInterval(e.current),e.current=null)},[])]}function D2(e,t){t===void 0&&(t=[e]);let n=(0,y.useRef)(e);return T2(()=>{n.current!==e&&(n.current=e)},t),n}function O2(e,t){let n=(0,y.useRef)();return(0,y.useMemo)(()=>{let t=e(n.current);return n.current=t,t},[...t])}function k2(e){let t=E2(e),n=(0,y.useRef)(null);return[n,(0,y.useCallback)(e=>{e!==n.current&&t?.(e,n.current),n.current=e},[])]}function A2(e){let t=(0,y.useRef)();return(0,y.useEffect)(()=>{t.current=e},[e]),t.current}var j2={};function M2(e,t){return(0,y.useMemo)(()=>{if(t)return t;let n=j2[e]==null?0:j2[e]+1;return j2[e]=n,e+`-`+n},[e,t])}function N2(e){return function(t){return[...arguments].slice(1).reduce((t,n)=>{let r=Object.entries(n);for(let[n,i]of r){let r=t[n];r!=null&&(t[n]=r+e*i)}return t},{...t})}}var P2=N2(1),F2=N2(-1);function nze(e){return`clientX`in e&&`clientY`in e}function I2(e){if(!e)return!1;let{KeyboardEvent:t}=b2(e.target);return t&&e instanceof t}function rze(e){if(!e)return!1;let{TouchEvent:t}=b2(e.target);return t&&e instanceof t}function L2(e){if(rze(e)){if(e.touches&&e.touches.length){let{clientX:t,clientY:n}=e.touches[0];return{x:t,y:n}}else if(e.changedTouches&&e.changedTouches.length){let{clientX:t,clientY:n}=e.changedTouches[0];return{x:t,y:n}}}return nze(e)?{x:e.clientX,y:e.clientY}:null}var R2=Object.freeze({Translate:{toString(e){if(!e)return;let{x:t,y:n}=e;return`translate3d(`+(t?Math.round(t):0)+`px, `+(n?Math.round(n):0)+`px, 0)`}},Scale:{toString(e){if(!e)return;let{scaleX:t,scaleY:n}=e;return`scaleX(`+t+`) scaleY(`+n+`)`}},Transform:{toString(e){if(e)return[R2.Translate.toString(e),R2.Scale.toString(e)].join(` `)}},Transition:{toString(e){let{property:t,duration:n,easing:r}=e;return t+` `+n+`ms `+r}}}),z2=`a,frame,iframe,input:not([type=hidden]):not(:disabled),select:not(:disabled),textarea:not(:disabled),button:not(:disabled),*[tabindex]`;function ize(e){return e.matches(z2)?e:e.querySelector(z2)}var aze={display:`none`};function oze(e){let{id:t,value:n}=e;return y.createElement(`div`,{id:t,style:aze},n)}function sze(e){let{id:t,announcement:n,ariaLiveType:r=`assertive`}=e;return y.createElement(`div`,{id:t,style:{position:`fixed`,top:0,left:0,width:1,height:1,margin:-1,border:0,padding:0,overflow:`hidden`,clip:`rect(0 0 0 0)`,clipPath:`inset(100%)`,whiteSpace:`nowrap`},role:`status`,"aria-live":r,"aria-atomic":!0},n)}function cze(){let[e,t]=(0,y.useState)(``);return{announce:(0,y.useCallback)(e=>{e!=null&&t(e)},[]),announcement:e}}var B2=(0,y.createContext)(null);function lze(e){let t=(0,y.useContext)(B2);(0,y.useEffect)(()=>{if(!t)throw Error(`useDndMonitor must be used within a children of `);return t(e)},[e,t])}function uze(){let[e]=(0,y.useState)(()=>new Set),t=(0,y.useCallback)(t=>(e.add(t),()=>e.delete(t)),[e]);return[(0,y.useCallback)(t=>{let{type:n,event:r}=t;e.forEach(e=>e[n]?.call(e,r))},[e]),t]}var dze={draggable:` + [&::-webkit-slider-thumb]:cursor-pointer`}),(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray w-12`,children:Tf(p)})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`button`,{onClick:()=>{let e=o.current;e&&(e.currentTime=Math.max(0,e.currentTime-5))},className:`p-2 hover:bg-bambu-dark-tertiary rounded-lg transition-colors`,title:`Skip back 5s`,children:(0,K.jsx)(Yl,{className:`w-5 h-5 text-bambu-gray`})}),(0,K.jsx)(`button`,{onClick:_,className:`p-2 bg-bambu-green hover:bg-bambu-green-dark rounded-lg transition-colors`,children:s?(0,K.jsx)(ml,{className:`w-5 h-5 text-white`}):(0,K.jsx)(yl,{className:`w-5 h-5 text-white`})}),(0,K.jsx)(`button`,{onClick:()=>{let e=o.current;e&&(e.currentTime=Math.min(p,e.currentTime+5))},className:`p-2 hover:bg-bambu-dark-tertiary rounded-lg transition-colors`,title:`Skip forward 5s`,children:(0,K.jsx)(Xl,{className:`w-5 h-5 text-bambu-gray`})})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`span`,{className:`text-sm text-bambu-gray`,children:`Speed:`}),(0,K.jsx)(`div`,{className:`flex gap-1`,children:HRe.map(e=>(0,K.jsxs)(`button`,{onClick:()=>u(e),className:`px-2 py-1 text-xs rounded transition-colors ${l===e?`bg-bambu-green text-white`:`bg-bambu-dark-tertiary text-bambu-gray hover:bg-bambu-dark-tertiary/80`}`,children:[e,`x`]},e))})]})]})]})]})]}),h&&r&&(0,K.jsx)(VRe,{archiveId:r,timelapseSrc:e,onClose:()=>g(!1),onSave:a})]})}function URe({archiveIds:e,onClose:t}){(0,y.useEffect)(()=>{let e=e=>{e.key===`Escape`&&t()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[t]);let{data:n,isLoading:r,error:i}=q({queryKey:[`archive-comparison`,e],queryFn:()=>Q.compareArchives(e)});return(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/80 flex items-center justify-center z-50 p-4`,onClick:t,children:(0,K.jsxs)(`div`,{className:`bg-bambu-dark-secondary rounded-lg max-w-4xl w-full max-h-[90vh] flex flex-col border border-bambu-dark-tertiary`,onClick:e=>e.stopPropagation(),children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between p-4 border-b border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`h3`,{className:`text-lg font-semibold text-white`,children:[`Compare Archives (`,e.length,`)`]}),(0,K.jsx)(`button`,{onClick:t,className:`text-bambu-gray hover:text-white p-1`,children:(0,K.jsx)(Ru,{className:`w-5 h-5`})})]}),(0,K.jsx)(`div`,{className:`flex-1 overflow-auto p-4 bg-bambu-dark-secondary`,children:r?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-12`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):i?(0,K.jsxs)(`div`,{className:`text-center py-12 text-red-400`,children:[(0,K.jsx)(Su,{className:`w-12 h-12 mx-auto mb-4 opacity-50`}),(0,K.jsx)(`p`,{children:`Failed to load comparison`}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-2`,children:i instanceof Error?i.message:`Unknown error`})]}):n?(0,K.jsx)(WRe,{comparison:n}):null}),(0,K.jsx)(`div`,{className:`p-4 border-t border-bambu-dark-tertiary`,children:(0,K.jsx)($,{variant:`secondary`,onClick:t,className:`w-full`,children:`Close`})})]})})}function WRe({comparison:e}){return(0,K.jsxs)(`div`,{className:`space-y-6`,children:[(0,K.jsx)(`div`,{className:`overflow-x-auto`,children:(0,K.jsxs)(`table`,{className:`w-full`,children:[(0,K.jsx)(`thead`,{children:(0,K.jsxs)(`tr`,{children:[(0,K.jsx)(`th`,{className:`text-left text-sm text-bambu-gray font-medium pb-2 pr-4 min-w-[150px]`,children:`Setting`}),e.archives.map(e=>(0,K.jsxs)(`th`,{className:`text-left text-sm font-medium pb-2 px-2 min-w-[120px]`,children:[(0,K.jsx)(`div`,{className:`text-white truncate max-w-[150px]`,title:e.print_name,children:e.print_name}),(0,K.jsx)(`div`,{className:`text-xs ${e.status===`completed`?`text-status-ok`:e.status===`failed`?`text-status-error`:`text-bambu-gray`}`,children:e.status})]},e.id))]})}),(0,K.jsx)(`tbody`,{className:`divide-y divide-bambu-gray/20`,children:e.comparison.map(e=>(0,K.jsxs)(`tr`,{className:e.has_difference?`bg-yellow-500/5`:``,children:[(0,K.jsx)(`td`,{className:`py-2 pr-4 text-sm`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[e.has_difference&&(0,K.jsx)(Su,{className:`w-3 h-3 text-yellow-400 flex-shrink-0`}),(0,K.jsx)(`span`,{className:e.has_difference?`text-yellow-400`:`text-bambu-gray`,children:e.label})]})}),e.values.map((t,n)=>(0,K.jsxs)(`td`,{className:`py-2 px-2 text-sm text-white`,children:[t??(0,K.jsx)(`span`,{className:`text-bambu-gray/50`,children:`-`}),e.unit&&t!==null&&(0,K.jsx)(`span`,{className:`text-bambu-gray ml-1`,children:e.unit})]},n))]},e.field))})]})}),e.differences.length>0&&(0,K.jsxs)(`div`,{className:`p-4 bg-yellow-500/10 border border-yellow-500/30 rounded-lg`,children:[(0,K.jsxs)(`h4`,{className:`text-sm font-medium text-yellow-400 mb-2 flex items-center gap-2`,children:[(0,K.jsx)(Su,{className:`w-4 h-4`}),e.differences.length,` Difference`,e.differences.length>1?`s`:``,` Found`]}),(0,K.jsxs)(`ul`,{className:`text-sm text-white/80 space-y-1`,children:[e.differences.slice(0,5).map(e=>(0,K.jsxs)(`li`,{children:[(0,K.jsx)(`span`,{className:`text-yellow-400`,children:e.label}),`: `,e.values.join(` vs `),` `,e.unit||``]},e.field)),e.differences.length>5&&(0,K.jsxs)(`li`,{className:`text-bambu-gray`,children:[`...and `,e.differences.length-5,` more`]})]})]}),e.success_correlation.has_both_outcomes?(0,K.jsxs)(`div`,{className:`p-4 bg-bambu-dark rounded-lg`,children:[(0,K.jsxs)(`h4`,{className:`text-sm font-medium text-white mb-3 flex items-center gap-2`,children:[(0,K.jsx)(rs,{className:`w-4 h-4 text-bambu-green`}),`Success/Failure Analysis`]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-4 text-sm mb-3`,children:[(0,K.jsxs)(`span`,{className:`text-bambu-green`,children:[e.success_correlation.successful_count,` successful`]}),(0,K.jsxs)(`span`,{className:`text-red-400`,children:[e.success_correlation.failed_count,` failed`]})]}),e.success_correlation.insights&&e.success_correlation.insights.length>0?(0,K.jsx)(`div`,{className:`space-y-2`,children:e.success_correlation.insights.map(e=>(0,K.jsxs)(`div`,{className:`text-sm p-2 bg-bambu-dark-secondary rounded`,children:[(0,K.jsxs)(`span`,{className:`text-white font-medium`,children:[e.label,`:`]}),` `,(0,K.jsx)(`span`,{className:`text-white/80`,children:e.insight})]},e.field))}):(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:`No clear correlations found between settings and outcomes.`})]}):(0,K.jsx)(`div`,{className:`p-4 bg-bambu-dark rounded-lg text-sm text-bambu-gray`,children:(0,K.jsx)(`p`,{children:e.success_correlation.message||`Need both successful and failed prints for correlation analysis.`})})]})}function GRe(e){let t=new Date(e),n=new Date().getTime()-t.getTime(),r=Math.floor(n/6e4);if(r<1)return`Just now`;if(r<60)return`${r}m ago`;let i=Math.floor(r/60);return i<24?`${i}h ago`:`${Math.floor(i/24)}d ago`}function KRe({upload:e,projects:t,onArchive:n,onDiscard:r,isArchiving:i,isDiscarding:a}){let[o,s]=(0,y.useState)(!1),[c,l]=(0,y.useState)(e.tags||``),[u,d]=(0,y.useState)(e.notes||``),[f,p]=(0,y.useState)(e.project_id),[m,h]=(0,y.useState)(!1);return(0,K.jsx)(_d,{children:(0,K.jsxs)(yd,{className:`py-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(Zs,{className:`w-8 h-8 text-bambu-green flex-shrink-0`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white font-medium`,title:e.filename,children:e.display_name||e.filename}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-xs text-bambu-gray`,children:[(0,K.jsx)(`span`,{children:Cd(e.file_size)}),(0,K.jsx)(`span`,{children:`·`}),(0,K.jsxs)(`span`,{className:`flex items-center gap-1`,children:[(0,K.jsx)(xs,{className:`w-3 h-3`}),GRe(e.uploaded_at)]}),e.source_ip&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`span`,{children:`·`}),(0,K.jsxs)(`span`,{children:[`from `,e.source_ip]})]})]})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`button`,{onClick:()=>s(!o),className:`p-1 text-bambu-gray hover:text-white transition-colors`,children:o?(0,K.jsx)(cs,{className:`w-5 h-5`}):(0,K.jsx)(is,{className:`w-5 h-5`})}),(0,K.jsx)($,{variant:`primary`,size:`sm`,onClick:()=>n(e.id,{tags:c,notes:u,project_id:f||void 0}),disabled:i,children:i?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Oo,{className:`w-4 h-4`}),`Archive`]})}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>h(!0),disabled:a,children:a?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(yu,{className:`w-4 h-4 text-red-400`})})]})]}),m&&(0,K.jsx)(Ad,{title:`Discard Upload`,message:`Are you sure you want to discard "${e.filename}"? This cannot be undone.`,confirmText:`Discard`,variant:`danger`,onConfirm:()=>{r(e.id),h(!1)},onCancel:()=>h(!1)}),o&&(0,K.jsxs)(`div`,{className:`mt-4 pt-4 border-t border-bambu-dark-tertiary space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:`Tags`}),(0,K.jsx)(`input`,{type:`text`,value:c,onChange:e=>l(e.target.value),placeholder:`e.g., functional, prototype, gift`,className:`w-full bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-md px-3 py-2 text-white placeholder-bambu-gray text-sm`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:`Notes`}),(0,K.jsx)(`textarea`,{value:u,onChange:e=>d(e.target.value),placeholder:`Add notes about this print...`,rows:2,className:`w-full bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-md px-3 py-2 text-white placeholder-bambu-gray text-sm resize-none`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:`Project`}),(0,K.jsxs)(`select`,{value:f||``,onChange:e=>p(e.target.value?Number(e.target.value):null),className:`w-full bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-md px-3 py-2 text-white text-sm`,children:[(0,K.jsx)(`option`,{value:``,children:`No project`}),t.map(e=>(0,K.jsx)(`option`,{value:e.id,children:e.name},e.id))]})]})]})]})})}function qRe(){let e=no(),{showToast:t}=Td(),[n,r]=(0,y.useState)(!1),[i,a]=(0,y.useState)(!1),[o,s]=(0,y.useState)(new Set),[c,l]=(0,y.useState)(new Set),{data:u,isLoading:d}=q({queryKey:[`pending-uploads`],queryFn:rd.list,refetchInterval:1e4}),{data:f}=q({queryKey:[`projects`],queryFn:()=>Q.getProjects(),select:e=>[...e].sort((e,t)=>e.name.localeCompare(t.name))}),p=J({mutationFn:({id:e,data:t})=>rd.archive(e,t),onMutate:({id:e})=>{s(t=>new Set(t).add(e))},onSettled:(e,t,{id:n})=>{s(e=>{let t=new Set(e);return t.delete(n),t})},onSuccess:n=>{e.invalidateQueries({queryKey:[`pending-uploads`]}),e.invalidateQueries({queryKey:[`archives`]}),t(`Archived: ${n.print_name}`)},onError:e=>{t(e.message||`Failed to archive`,`error`)}}),m=J({mutationFn:e=>rd.discard(e),onMutate:e=>{l(t=>new Set(t).add(e))},onSettled:(e,t,n)=>{l(e=>{let t=new Set(e);return t.delete(n),t})},onSuccess:()=>{e.invalidateQueries({queryKey:[`pending-uploads`]}),t(`Upload discarded`)},onError:e=>{t(e.message||`Failed to discard`,`error`)}}),h=J({mutationFn:rd.archiveAll,onSuccess:n=>{e.invalidateQueries({queryKey:[`pending-uploads`]}),e.invalidateQueries({queryKey:[`archives`]}),t(`Archived ${n.archived} files${n.failed>0?`, ${n.failed} failed`:``}`)},onError:e=>{t(e.message||`Failed to archive all`,`error`)}}),g=J({mutationFn:rd.discardAll,onSuccess:n=>{e.invalidateQueries({queryKey:[`pending-uploads`]}),t(`Discarded ${n.discarded} files`)},onError:e=>{t(e.message||`Failed to discard all`,`error`)}});return d?(0,K.jsx)(_d,{children:(0,K.jsx)(yd,{className:`py-8 flex justify-center`,children:(0,K.jsx)(X,{className:`w-6 h-6 animate-spin text-bambu-green`})})}):!u||u.length===0?null:(0,K.jsxs)(`div`,{className:`mb-6`,children:[(0,K.jsxs)(_d,{className:`border-l-4 border-l-yellow-500`,children:[(0,K.jsx)(vd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Eu,{className:`w-5 h-5 text-yellow-500`}),(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white`,children:[`Pending Uploads (`,u.length,`)`]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)($,{variant:`primary`,size:`sm`,onClick:()=>r(!0),disabled:h.isPending,children:h.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Oo,{className:`w-4 h-4`}),`Archive All`]})}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>a(!0),disabled:g.isPending,children:g.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(yu,{className:`w-4 h-4`}),`Discard All`]})})]})]})}),(0,K.jsxs)(yd,{children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mb-4`,children:`These files were uploaded via the virtual printer. Review and archive them to add to your collection.`}),(0,K.jsx)(`div`,{className:`space-y-3`,children:u.map(e=>(0,K.jsx)(KRe,{upload:e,projects:f||[],onArchive:(e,t)=>p.mutate({id:e,data:t}),onDiscard:e=>m.mutate(e),isArchiving:o.has(e.id),isDiscarding:c.has(e.id)},e.id))})]})]}),n&&(0,K.jsx)(Ad,{title:`Archive All Uploads`,message:`Are you sure you want to archive all ${u.length} pending uploads?`,confirmText:`Archive All`,onConfirm:()=>{h.mutate(),r(!1)},onCancel:()=>r(!1)}),i&&(0,K.jsx)(Ad,{title:`Discard All Uploads`,message:`Are you sure you want to discard all ${u.length} pending uploads? This cannot be undone.`,confirmText:`Discard All`,variant:`danger`,onConfirm:()=>{g.mutate(),a(!1)},onCancel:()=>a(!1)})]})}function JRe({onClose:e}){let t=no(),{showToast:n}=Td(),[r,i]=(0,y.useState)(``),[a,o]=(0,y.useState)(null),[s,c]=(0,y.useState)(``),[l,u]=(0,y.useState)(null),[d,f]=(0,y.useState)(`count`);(0,y.useEffect)(()=>{let t=t=>{t.key===`Escape`&&(a?o(null):l?u(null):e())};return window.addEventListener(`keydown`,t),()=>window.removeEventListener(`keydown`,t)},[e,a,l]);let{data:p,isLoading:m}=q({queryKey:[`tags`],queryFn:Q.getTags}),h=J({mutationFn:({oldName:e,newName:t})=>Q.renameTag(e,t),onSuccess:(e,{oldName:r,newName:i})=>{t.invalidateQueries({queryKey:[`tags`]}),t.invalidateQueries({queryKey:[`archives`]}),n(`Renamed "${r}" to "${i}" in ${e.affected} archive${e.affected===1?``:`s`}`),o(null)},onError:e=>{n(e.message||`Failed to rename tag`,`error`)}}),g=J({mutationFn:e=>Q.deleteTag(e),onSuccess:(e,r)=>{t.invalidateQueries({queryKey:[`tags`]}),t.invalidateQueries({queryKey:[`archives`]}),n(`Deleted "${r}" from ${e.affected} archive${e.affected===1?``:`s`}`),u(null)},onError:e=>{n(e.message||`Failed to delete tag`,`error`)}}),_=e=>{o(e.name),c(e.name),u(null)},v=()=>{o(null),c(``)},b=()=>{if(!a||!s.trim())return;let e=s.trim();if(e===a){v();return}h.mutate({oldName:a,newName:e})},x=e=>{e.key===`Enter`?(e.preventDefault(),b()):e.key===`Escape`&&(e.preventDefault(),v())},S=e=>{u(e),o(null)},C=()=>{l&&g.mutate(l)},w=p?.filter(e=>e.name.toLowerCase().includes(r.toLowerCase())).sort((e,t)=>d===`count`&&t.count-e.count||e.name.localeCompare(t.name)),T=p?.reduce((e,t)=>e+t.count,0)||0;return(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4`,children:(0,K.jsx)(_d,{className:`w-full max-w-lg max-h-[80vh] flex flex-col`,children:(0,K.jsxs)(yd,{className:`p-0 flex flex-col min-h-0`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between p-4 border-b border-bambu-dark-tertiary flex-shrink-0`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(du,{className:`w-5 h-5 text-bambu-green`}),(0,K.jsx)(`h2`,{className:`text-xl font-semibold text-white`,children:`Manage Tags`})]}),(0,K.jsx)(`button`,{onClick:e,className:`text-bambu-gray hover:text-white transition-colors`,children:(0,K.jsx)(Ru,{className:`w-5 h-5`})})]}),(0,K.jsxs)(`div`,{className:`p-4 border-b border-bambu-dark-tertiary flex-shrink-0`,children:[(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsxs)(`div`,{className:`relative flex-1`,children:[(0,K.jsx)(Ll,{className:`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray`}),(0,K.jsx)(`input`,{type:`text`,placeholder:`Search tags...`,className:`w-full pl-9 pr-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:border-bambu-green focus:outline-none`,value:r,onChange:e=>i(e.target.value)})]}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:border-bambu-green focus:outline-none`,value:d,onChange:e=>f(e.target.value),children:[(0,K.jsx)(`option`,{value:`count`,children:`Sort by Count`}),(0,K.jsx)(`option`,{value:`name`,children:`Sort by Name`})]})]}),p&&(0,K.jsxs)(`p`,{className:`text-xs text-bambu-gray mt-2`,children:[p.length,` tag`,p.length===1?``:`s`,` across `,T,` usage`,T===1?``:`s`]})]}),(0,K.jsx)(`div`,{className:`flex-1 overflow-y-auto min-h-0 p-4`,children:m?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-8`,children:(0,K.jsx)(X,{className:`w-6 h-6 animate-spin text-bambu-gray`})}):w?.length?(0,K.jsx)(`div`,{className:`space-y-2`,children:w.map(e=>(0,K.jsx)(`div`,{className:`flex items-center gap-2 p-2 rounded-lg bg-bambu-dark hover:bg-bambu-dark-tertiary transition-colors group`,children:a===e.name?(0,K.jsxs)(`div`,{className:`flex-1 flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`text`,className:`flex-1 px-2 py-1 bg-bambu-dark-tertiary border border-bambu-green rounded text-white text-sm focus:outline-none`,value:s,onChange:e=>c(e.target.value),onKeyDown:x,autoFocus:!0}),(0,K.jsx)($,{size:`sm`,variant:`primary`,onClick:b,disabled:!s.trim()||h.isPending,className:`p-1.5`,children:h.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(rs,{className:`w-4 h-4`})}),(0,K.jsx)($,{size:`sm`,variant:`ghost`,onClick:v,className:`p-1.5`,children:(0,K.jsx)(Ru,{className:`w-4 h-4`})})]}):l===e.name?(0,K.jsxs)(`div`,{className:`flex-1 flex items-center gap-2`,children:[(0,K.jsx)(Su,{className:`w-4 h-4 text-yellow-400 flex-shrink-0`}),(0,K.jsxs)(`span`,{className:`text-sm text-bambu-gray-light flex-1`,children:[`Delete "`,e.name,`" from `,e.count,` archive`,e.count===1?``:`s`,`?`]}),(0,K.jsx)($,{size:`sm`,variant:`danger`,onClick:C,disabled:g.isPending,className:`p-1.5`,children:g.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(yu,{className:`w-4 h-4`})}),(0,K.jsx)($,{size:`sm`,variant:`ghost`,onClick:()=>u(null),className:`p-1.5`,children:(0,K.jsx)(Ru,{className:`w-4 h-4`})})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(du,{className:`w-4 h-4 text-bambu-gray flex-shrink-0`}),(0,K.jsx)(`span`,{className:`text-white flex-1 truncate`,children:e.name}),(0,K.jsx)(`span`,{className:`px-2 py-0.5 rounded-full bg-bambu-dark-tertiary text-bambu-gray text-xs`,children:e.count}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity`,children:[(0,K.jsx)(`button`,{onClick:()=>_(e),className:`p-1.5 rounded hover:bg-bambu-dark text-bambu-gray hover:text-white transition-colors`,title:`Rename tag`,children:(0,K.jsx)(_l,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{onClick:()=>S(e.name),className:`p-1.5 rounded hover:bg-bambu-dark text-bambu-gray hover:text-red-400 transition-colors`,title:`Delete tag`,children:(0,K.jsx)(yu,{className:`w-4 h-4`})})]})]})},e.name))}):(0,K.jsx)(`div`,{className:`text-center py-8 text-bambu-gray`,children:r?`No tags match your search`:`No tags found`})}),(0,K.jsx)(`div`,{className:`flex gap-3 p-4 border-t border-bambu-dark-tertiary flex-shrink-0`,children:(0,K.jsx)($,{variant:`secondary`,onClick:e,className:`flex-1`,children:`Close`})})]})})})}function m2(e){let t=e.filename;if(t){let e=t.toLowerCase();if(e.endsWith(`.gcode`)||e.includes(`.gcode.`))return!0}return!!(e.total_layers||e.print_time_seconds)}async function h2(e,t,n,r){try{if(n===`source`){let{token:n}=await Q.createSourceSlicerToken(e),i=Q.getSourceSlicerDownloadUrl(e,n,t);nG(`${window.location.origin}${i}`,r)}else{let{token:n}=await Q.createArchiveSlicerToken(e),i=Q.getArchiveSlicerDownloadUrl(e,n,t);nG(`${window.location.origin}${i}`,r)}}catch{let i=n===`source`?Q.getSource3mfForSlicer(e,t):Q.getArchiveForSlicer(e,t);nG(`${window.location.origin}${i}`,r)}}function YRe({archive:e,printerName:t,isSelected:n,onSelect:r,selectionMode:i,projects:a,isHighlighted:o,timeFormat:s=`system`,preferredSlicer:c=`bambu_studio`,useSlicerApi:l=!1,currency:u,t:d,onNavigateToArchive:f}){o&&console.log(`ArchiveCard isHighlighted=true for archive:`,e.id);let p=no(),{showToast:m}=Td(),{hasPermission:h,canModify:g}=dd(),_=iG(),v=$n(),[b,x]=(0,y.useState)(!1),[S,C]=(0,y.useState)(!1),[w,T]=(0,y.useState)(!1),[E,D]=(0,y.useState)(!1),O=q({queryKey:[`archive`,e.id,`delete-impact`],queryFn:()=>Q.getArchiveDeleteImpact(e.id),enabled:w,staleTime:0}),[k,A]=(0,y.useState)(!1),[j,M]=(0,y.useState)(!1),[N,P]=(0,y.useState)(!1),[F,I]=(0,y.useState)(!1),[L,R]=(0,y.useState)([]),[z,B]=(0,y.useState)(!1),[V,ee]=(0,y.useState)(!1),[te,ne]=(0,y.useState)(!1),[re,ie]=(0,y.useState)(!1),[H,ae]=(0,y.useState)(!1),[oe,U]=(0,y.useState)(!1),[se,ce]=(0,y.useState)(!1),[le,ue]=(0,y.useState)(null),[de,fe]=(0,y.useState)(null),[pe,me]=(0,y.useState)(!1),[he,ge]=(0,y.useState)(null),_e=(0,y.useRef)(null),ve=(0,y.useRef)(null),ye=(0,y.useRef)(null),{data:be}=q({queryKey:[`archive-plates`,e.id],queryFn:()=>Q.getArchivePlates(e.id),enabled:pe,staleTime:300*1e3}),xe=e.duplicate_sequence??0,Se=e.original_archive_id??null,Ce=be?.plates??[],we=be?.is_multi_plate??!1,Te=de??0,Ee=async()=>{try{let t=await Q.getArchivePlates(e.id);if(t.has_gcode===!1){m(d(`archives.platePicker.noGcode`),`info`);return}if(t.is_multi_plate&&t.plates.length>1){ge(t.plates);return}}catch{}v(`/gcode-viewer?archive=${e.id}`)},De=J({mutationFn:()=>Q.deleteArchiveTimelapse(e.id),onSuccess:()=>{p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.timelapseRemoved`))},onError:e=>{m(e.message||d(`archives.toast.failedRemoveTimelapse`),`error`)}}),Oe=J({mutationFn:t=>Q.uploadArchiveTimelapse(e.id,t),onSuccess:e=>{p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.timelapseUploaded`,{filename:e.filename}))},onError:e=>{m(e.message||d(`archives.toast.failedUploadTimelapse`),`error`)}}),ke=J({mutationFn:t=>Q.uploadSource3mf(e.id,t),onSuccess:e=>{p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.source3mfAttached`,{filename:e.filename}))},onError:e=>{m(e.message||d(`archives.toast.failedUploadSource3mf`),`error`)}}),Ae=J({mutationFn:()=>Q.deleteSource3mf(e.id),onSuccess:()=>{p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.source3mfRemoved`))},onError:e=>{m(e.message||d(`archives.toast.failedRemoveSource3mf`),`error`)}}),je=J({mutationFn:t=>Q.uploadF3d(e.id,t),onSuccess:e=>{p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.f3dAttached`,{filename:e.filename}))},onError:e=>{m(e.message||d(`archives.toast.failedUploadF3d`),`error`)}}),Me=J({mutationFn:()=>Q.deleteF3d(e.id),onSuccess:()=>{p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.f3dRemoved`))},onError:e=>{m(e.message||d(`archives.toast.failedRemoveF3d`),`error`)}}),Ne=J({mutationFn:()=>Q.scanArchiveTimelapse(e.id),onSuccess:e=>{e.status===`attached`?(p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.timelapseAttached`,{filename:e.filename}))):e.status===`exists`?m(d(`archives.toast.timelapseAlreadyAttached`)):e.status===`not_found`&&e.available_files&&e.available_files.length>0?(R(e.available_files),I(!0)):m(e.message||d(`archives.toast.noMatchingTimelapse`),`warning`)},onError:e=>{m(e.message||d(`archives.toast.failedScanTimelapse`),`error`)}}),Pe=J({mutationFn:t=>Q.selectArchiveTimelapse(e.id,t),onSuccess:e=>{p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.timelapseAttached`,{filename:e.filename})),I(!1),R([])},onError:e=>{m(e.message||d(`archives.toast.failedAttachTimelapse`),`error`)}}),Fe=J({mutationFn:t=>Q.deleteArchive(e.id,t),onSuccess:()=>{p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.archiveDeleted`))},onError:()=>{m(d(`archives.toast.failedDeleteArchive`),`error`)}}),Ie=J({mutationFn:()=>Q.toggleFavorite(e.id),onSuccess:e=>{p.invalidateQueries({queryKey:[`archives`]}),m(e.is_favorite?d(`archives.toast.addedToFavorites`):d(`archives.toast.removedFromFavorites`))}}),{data:Le}=q({queryKey:[`archive-folders`,e.id],queryFn:()=>Q.getLibraryFoldersByArchive(e.id)}),Re=J({mutationFn:t=>Q.updateArchive(e.id,{project_id:t}),onSuccess:()=>{p.invalidateQueries({queryKey:[`archives`]}),p.invalidateQueries({queryKey:[`projects`]}),m(d(`archives.toast.projectUpdated`))},onError:()=>{m(d(`archives.toast.failedUpdateProject`),`error`)}}),ze=e=>{e.preventDefault(),ue({x:e.clientX,y:e.clientY})},Be=[...m2(e)?[{label:d(`archives.menu.print`),icon:(0,K.jsx)(wl,{className:`w-4 h-4`}),onClick:()=>x(!0),disabled:!e.file_path||!g(`archives`,`reprint`,e.created_by_id),title:e.file_path?g(`archives`,`reprint`,e.created_by_id)?void 0:d(`archives.permission.noReprint`):d(`archives.card.noFileForReprint`)},{label:d(`archives.menu.schedule`),icon:(0,K.jsx)(Zo,{className:`w-4 h-4`}),onClick:()=>ie(!0),disabled:!e.file_path||!h(`queue:create`),title:e.file_path?h(`queue:create`)?void 0:d(`archives.permission.noAddToQueue`):d(`archives.card.noFileForReprint`)},{label:d(`archives.menu.openInBambuStudio`),icon:(0,K.jsx)(qs,{className:`w-4 h-4`}),onClick:()=>{let t=e.print_name||e.filename||`model`;h2(e.id,t,`file`,c)},disabled:!e.file_path,title:e.file_path?void 0:d(`archives.card.noFileForReprint`)}]:[{label:d(`archives.menu.slice`),icon:l?(0,K.jsx)(Os,{className:`w-4 h-4`}):(0,K.jsx)(qs,{className:`w-4 h-4`}),onClick:()=>{if(l)C(!0);else{let t=e.print_name||e.filename||`model`;h2(e.id,t,`file`,c)}}}],{label:e.external_url?d(`archives.menu.externalLink`):d(`archives.menu.viewOnMakerWorld`),icon:(0,K.jsx)(yc,{className:`w-4 h-4`}),onClick:()=>{let t=e.external_url||e.makerworld_url;t&&window.open(t,`_blank`)},disabled:!e.external_url&&!e.makerworld_url},{label:``,divider:!0,onClick:()=>{}},{label:d(`archives.menu.preview3d`),icon:(0,K.jsx)(Wo,{className:`w-4 h-4`}),onClick:()=>{Ee()}},{label:d(`archives.menu.viewTimelapse`),icon:(0,K.jsx)(rc,{className:`w-4 h-4`}),onClick:()=>P(!0),disabled:!e.timelapse_path},{label:d(`archives.menu.scanForTimelapse`),icon:(0,K.jsx)(Fl,{className:`w-4 h-4`}),onClick:()=>Ne.mutate(),disabled:!e.printer_id||!!e.timelapse_path||Ne.isPending||!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)},{label:d(`archives.menu.uploadTimelapse`),icon:(0,K.jsx)(Eu,{className:`w-4 h-4`}),onClick:()=>ye.current?.click(),disabled:!!e.timelapse_path||!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)},...e.timelapse_path?[{label:d(`archives.menu.removeTimelapse`),icon:(0,K.jsx)(yu,{className:`w-4 h-4`}),onClick:()=>ce(!0),danger:!0,disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)}]:[],{label:``,divider:!0,onClick:()=>{}},{label:e.source_3mf_path?d(`archives.menu.downloadSource3mf`):d(`archives.menu.uploadSource3mf`),icon:(0,K.jsx)(Qs,{className:`w-4 h-4`}),onClick:()=>{e.source_3mf_path?Q.downloadSource3mf(e.id).catch(e=>{console.error(`Source 3MF download failed:`,e)}):_e.current?.click()},disabled:!e.source_3mf_path&&!g(`archives`,`update`,e.created_by_id),title:!e.source_3mf_path&&!g(`archives`,`update`,e.created_by_id)?d(`archives.permission.noUploadFiles`):void 0},...e.source_3mf_path?[{label:d(`archives.menu.replaceSource3mf`),icon:(0,K.jsx)(Eu,{className:`w-4 h-4`}),onClick:()=>_e.current?.click(),disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)},{label:d(`archives.menu.removeSource3mf`),icon:(0,K.jsx)(yu,{className:`w-4 h-4`}),onClick:()=>ae(!0),danger:!0,disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)}]:[],{label:e.f3d_path?d(`archives.menu.replaceF3d`):d(`archives.menu.uploadF3d`),icon:(0,K.jsx)(Wo,{className:`w-4 h-4`}),onClick:()=>ve.current?.click(),disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)},...e.f3d_path?[{label:d(`archives.menu.downloadF3d`),icon:(0,K.jsx)(Bs,{className:`w-4 h-4`}),onClick:()=>{Q.downloadF3d(e.id).catch(e=>{console.error(`F3D download failed:`,e)})}},{label:d(`archives.menu.removeF3d`),icon:(0,K.jsx)(yu,{className:`w-4 h-4`}),onClick:()=>U(!0),danger:!0,disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)}]:[],{label:``,divider:!0,onClick:()=>{}},{label:d(`archives.menu.download`),icon:(0,K.jsx)(Bs,{className:`w-4 h-4`}),onClick:()=>{Q.downloadArchive(e.id,`${e.print_name||e.filename}.3mf`).catch(e=>{console.error(`Archive download failed:`,e)})},disabled:!h(`archives:read`),title:h(`archives:read`)?void 0:d(`archives.permission.noDownload`)},{label:d(`archives.menu.copyDownloadLink`),icon:(0,K.jsx)(js,{className:`w-4 h-4`}),onClick:()=>{let t=`${window.location.origin}${Q.getArchiveDownload(e.id)}`;navigator.clipboard.writeText(t).then(()=>{m(d(`archives.toast.linkCopied`))}).catch(()=>{m(d(`archives.toast.failedCopyLink`),`error`)})},disabled:!h(`archives:read`),title:h(`archives:read`)?void 0:d(`archives.permission.noCopyLink`)},{label:d(`archives.menu.qrCode`),icon:(0,K.jsx)(Tl,{className:`w-4 h-4`}),onClick:()=>B(!0)},{label:e.photos?.length?d(`archives.menu.viewPhotosCount`,{count:e.photos.length}):d(`archives.menu.viewPhotos`),icon:(0,K.jsx)(Qo,{className:`w-4 h-4`}),onClick:()=>ee(!0),disabled:!e.photos?.length},{label:d(`archives.menu.projectPage`),icon:(0,K.jsx)(tc,{className:`w-4 h-4`}),onClick:()=>ne(!0)},{label:``,divider:!0,onClick:()=>{}},{label:e.is_favorite?d(`archives.menu.removeFromFavorites`):d(`archives.menu.addToFavorites`),icon:(0,K.jsx)(ou,{className:`w-4 h-4 ${e.is_favorite?`fill-yellow-400 text-yellow-400`:``}`}),onClick:()=>Ie.mutate(),disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)},{label:d(`archives.menu.edit`),icon:(0,K.jsx)(_l,{className:`w-4 h-4`}),onClick:()=>A(!0),disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`)},{label:d(`archives.menu.printLog`),icon:(0,K.jsx)(Oc,{className:`w-4 h-4`}),onClick:()=>M(!0)},...e.project_id&&e.project_name?[{label:d(`archives.menu.goToProject`,{name:e.project_name}),icon:(0,K.jsx)(oc,{className:`w-4 h-4 text-bambu-green`}),onClick:()=>window.location.href=`/projects`}]:[],{label:d(`archives.menu.addToProject`),icon:(0,K.jsx)(oc,{className:`w-4 h-4`}),onClick:()=>{},disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?void 0:d(`archives.permission.noUpdateArchives`),submenuSearchPlaceholder:(a?.filter(e=>e.status===`active`).length??0)>5?d(`archives.menu.searchProjects`):void 0,submenu:(()=>{let t=[];if(e.project_id&&t.push({label:d(`archives.menu.removeFromProject`),icon:(0,K.jsx)(Ru,{className:`w-4 h-4`}),onClick:()=>Re.mutate(null),disabled:!g(`archives`,`update`,e.created_by_id)}),!a)t.push({label:d(`archives.menu.loading`),icon:(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}),onClick:()=>{},disabled:!0});else{let n=a.filter(e=>e.status===`active`).sort((e,t)=>e.name.localeCompare(t.name));n.length===0?t.push({label:d(`archives.menu.noProjectsAvailable`),icon:(0,K.jsx)(oc,{className:`w-4 h-4 opacity-50`}),onClick:()=>{},disabled:!0}):n.forEach(n=>{t.push({label:n.name,icon:(0,K.jsx)(`div`,{className:`w-3 h-3 rounded-full flex-shrink-0`,style:{backgroundColor:n.color||`#888`}}),onClick:()=>Re.mutate(n.id),disabled:e.project_id===n.id||!g(`archives`,`update`,e.created_by_id)})})}return t})()},{label:d(n?`archives.menu.deselect`:`archives.menu.select`),icon:n?(0,K.jsx)(ru,{className:`w-4 h-4`}):(0,K.jsx)(au,{className:`w-4 h-4`}),onClick:()=>r(e.id)},{label:``,divider:!0,onClick:()=>{}},{label:d(`archives.menu.delete`),icon:(0,K.jsx)(yu,{className:`w-4 h-4`}),onClick:()=>T(!0),danger:!0,disabled:!g(`archives`,`delete`,e.created_by_id),title:g(`archives`,`delete`,e.created_by_id)?void 0:d(`archives.permission.noDelete`)}];return(0,K.jsxs)(_d,{"data-archive-id":e.id,className:`relative flex flex-col group ${n?`ring-2 ring-bambu-green`:``} ${i?`cursor-pointer`:``}`,style:o?{outline:`4px solid #facc15`,outlineOffset:`2px`}:void 0,onContextMenu:ze,onClick:i?()=>r(e.id):void 0,children:[i&&(0,K.jsx)(`button`,{className:`absolute top-2 left-2 z-10 p-1 rounded bg-black/50 hover:bg-black/70 transition-colors`,onClick:t=>{t.stopPropagation(),r(e.id)},children:n?(0,K.jsx)(ru,{className:`w-5 h-5 text-bambu-green`}):(0,K.jsx)(au,{className:`w-5 h-5 text-white`})}),(0,K.jsxs)(`div`,{className:`aspect-video bg-bambu-dark relative flex-shrink-0 overflow-hidden rounded-t-xl`,onMouseEnter:()=>me(!0),onMouseLeave:()=>me(!1),children:[e.thumbnail_path?(0,K.jsx)(`img`,{src:de!==null&&Ce.length>0?Q.getArchivePlateThumbnail(e.id,Ce[Te]?.index??0):Q.getArchiveThumbnail(e.id),alt:e.print_name||e.filename,className:`w-full h-full object-cover`}):(0,K.jsx)(`div`,{className:`w-full h-full flex items-center justify-center`,children:(0,K.jsx)(jc,{className:`w-12 h-12 text-bambu-dark-tertiary`})}),we&&Ce.length>1&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`button`,{className:`absolute left-1 top-1/2 -translate-y-1/2 p-1 rounded-full bg-black/60 hover:bg-black/80 transition-all ${_?`opacity-100`:`opacity-0 group-hover:opacity-100`}`,onClick:e=>{e.stopPropagation(),fe(e=>{let t=e??0;return t>0?t-1:Ce.length-1})},title:d(`archives.card.previousPlate`),children:(0,K.jsx)(ss,{className:`w-4 h-4 text-white`})}),(0,K.jsx)(`button`,{className:`absolute right-1 top-1/2 -translate-y-1/2 p-1 rounded-full bg-black/60 hover:bg-black/80 transition-all ${_?`opacity-100`:`opacity-0 group-hover:opacity-100`}`,onClick:e=>{e.stopPropagation(),fe(e=>{let t=e??0;return t(0,K.jsx)(`button`,{className:`w-2 h-2 rounded-full transition-colors ${t===Te?`bg-bambu-green`:`bg-white/50 hover:bg-white/80`}`,onClick:e=>{e.stopPropagation(),fe(t)},title:e.name||d(`archives.card.plateNumber`,{index:e.index})},e.index))})]}),(0,K.jsx)(`button`,{className:`absolute top-2 left-2 p-1.5 rounded bg-black/50 hover:bg-black/70 transition-all ${_?`opacity-100`:`opacity-0 group-hover:opacity-100`} ${i?`left-10`:``}`,onClick:e=>{e.stopPropagation();let t=e.currentTarget.getBoundingClientRect();ue({x:t.left,y:t.bottom+4})},title:d(`archives.card.moreOptions`),children:(0,K.jsx)(Us,{className:`w-5 h-5 text-white`})}),(0,K.jsx)(`button`,{className:`absolute top-2 right-2 p-1 rounded transition-colors ${g(`archives`,`update`,e.created_by_id)?`bg-black/50 hover:bg-black/70`:`bg-black/30 cursor-not-allowed`}`,onClick:t=>{t.stopPropagation(),g(`archives`,`update`,e.created_by_id)&&Ie.mutate()},disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?e.is_favorite?d(`archives.card.removeFromFavorites`):d(`archives.card.addToFavorites`):d(`archives.permission.noUpdateArchives`),children:(0,K.jsx)(ou,{className:`w-5 h-5 ${e.is_favorite?`text-yellow-400 fill-yellow-400`:`text-white`} ${g(`archives`,`update`,e.created_by_id)?``:`opacity-50`}`})}),(e.status===`failed`||e.status===`aborted`)&&(0,K.jsx)(`div`,{className:`absolute top-2 left-12 px-2 py-1 rounded text-xs bg-status-error/80 text-white`,children:e.status===`aborted`?d(`archives.card.cancelled`):d(`archives.card.failed`)}),e.duplicate_count>0&&xe>0&&Se&&(0,K.jsxs)(`button`,{onClick:e=>{e.stopPropagation(),f?.(Se)},className:`absolute top-2 right-12 px-2 py-1 rounded text-xs bg-purple-500/80 hover:bg-purple-600/90 text-white flex items-center gap-1 transition-colors cursor-pointer`,title:d(`archives.viewOriginalPrint`,{id:Se}),children:[(0,K.jsx)(js,{className:`w-3 h-3`}),`#`,xe]}),e.duplicate_count>0&&xe===0&&(0,K.jsxs)(`span`,{className:`absolute top-2 right-12 px-2 py-1 rounded text-xs bg-purple-500/80 text-white flex items-center gap-1`,title:`${e.duplicate_count} reprint${e.duplicate_count===1?``:`s`}`,children:[(0,K.jsx)(gc,{className:`w-3 h-3`}),`+`,e.duplicate_count]}),e.source_3mf_path&&(0,K.jsx)(`button`,{className:`absolute bottom-2 left-2 p-1.5 rounded bg-black/60 hover:bg-black/80 transition-colors`,onClick:t=>{t.stopPropagation();let n=(e.print_name||e.filename||`source`).replace(/\.gcode\.3mf$/i,``)+`_source`;h2(e.id,n,`source`,c)},title:d(`archives.card.openSource3mf`),children:(0,K.jsx)(Qs,{className:`w-4 h-4 text-orange-400`})}),e.f3d_path&&(0,K.jsx)(`button`,{className:`absolute bottom-2 ${e.source_3mf_path?`left-12`:`left-2`} p-1.5 rounded bg-black/60 hover:bg-black/80 transition-colors`,onClick:t=>{t.stopPropagation(),Q.downloadF3d(e.id).catch(e=>{console.error(`F3D download failed:`,e)})},title:d(`archives.card.downloadF3d`),children:(0,K.jsx)(Wo,{className:`w-4 h-4 text-cyan-400`})}),(0,K.jsx)(`button`,{className:`absolute bottom-2 right-2 p-1.5 rounded bg-black/60 hover:bg-black/80 transition-colors`,onClick:e=>{e.stopPropagation(),Ee()},title:d(`archives.card.preview3d`),children:(0,K.jsx)(Lc,{className:`w-4 h-4 text-white`})}),e.timelapse_path&&(0,K.jsx)(`button`,{className:`absolute bottom-2 right-12 p-1.5 rounded bg-black/60 hover:bg-black/80 transition-colors`,onClick:e=>{e.stopPropagation(),P(!0)},title:d(`archives.card.viewTimelapse`),children:(0,K.jsx)(rc,{className:`w-4 h-4 text-bambu-green`})}),e.photos&&e.photos.length>0&&(0,K.jsxs)(`button`,{className:`absolute bottom-2 ${e.timelapse_path?`right-[5.5rem]`:`right-12`} p-1.5 rounded bg-black/60 hover:bg-black/80 transition-colors`,onClick:e=>{e.stopPropagation(),ee(!0)},title:e.photos.length===1?d(`archives.card.viewPhoto`):d(`archives.card.viewPhotos`,{count:e.photos.length}),children:[(0,K.jsx)(Qo,{className:`w-4 h-4 text-blue-400`}),e.photos.length>1&&(0,K.jsx)(`span`,{className:`absolute -top-1 -right-1 w-4 h-4 bg-blue-500 rounded-full text-[10px] text-white flex items-center justify-center`,children:e.photos.length})]}),Le&&Le.length>0&&(0,K.jsx)(wi,{to:`/files?folder=${Le[0].id}`,className:`absolute bottom-2 p-1.5 rounded bg-black/60 hover:bg-black/80 transition-colors`,onClick:e=>e.stopPropagation(),title:d(`archives.card.openFolder`,{name:Le[0].name}),style:{left:e.source_3mf_path?e.f3d_path?`5.5rem`:`3rem`:e.f3d_path?`3rem`:`0.5rem`},children:(0,K.jsx)(sc,{className:`w-4 h-4 text-yellow-400`})})]}),(0,K.jsxs)(yd,{className:`p-4 flex-1 flex flex-col`,children:[(0,K.jsxs)(`p`,{className:`text-[10px] text-bambu-gray/70 mb-1`,children:[`#`,e.id]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-2 mb-1`,children:[(0,K.jsx)(`h3`,{className:`min-w-0 font-medium text-white truncate`,children:e.print_name||e.filename}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,className:`p-1 sm:p-1.5 shrink-0`,onClick:()=>A(!0),disabled:!g(`archives`,`update`,e.created_by_id),title:g(`archives`,`update`,e.created_by_id)?d(`archives.card.edit`):d(`archives.card.noPermissionEdit`),children:(0,K.jsx)(_l,{className:`w-3 h-3 sm:w-4 sm:h-4`})})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-3 flex-wrap`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:t}),(()=>{let t=pW(e.bed_type);return t?(0,K.jsx)(`img`,{src:t.icon,alt:t.label,title:t.label,className:`w-4 h-4 flex-shrink-0`}):null})(),(0,K.jsx)(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded font-medium ${m2(e)?`bg-bambu-green/20 text-bambu-green`:`bg-orange-500/20 text-orange-400`}`,title:m2(e)?d(`archives.card.slicedFile`):d(`archives.card.sourceFile`),children:m2(e)?d(`archives.card.gcode`):d(`archives.card.source`)}),e.content_hash&&(0,K.jsx)(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded font-mono bg-bambu-dark-tertiary/50 text-bambu-gray-light opacity-0 transition-opacity duration-150 group-hover:opacity-100`,title:`SHA256: ${e.content_hash}`,children:e.content_hash.slice(0,8).toUpperCase()}),e.project_name&&(0,K.jsx)(`span`,{className:`text-xs px-1.5 py-0.5 rounded-full truncate max-w-[120px]`,style:{backgroundColor:`${a?.find(t=>t.id===e.project_id)?.color||`#6b7280`}20`,color:a?.find(t=>t.id===e.project_id)?.color||`#6b7280`},title:d(`archives.card.project`,{name:e.project_name}),children:e.project_name}),e.run_count>1&&(0,K.jsx)(`button`,{className:`text-[10px] px-1.5 py-0.5 rounded font-medium bg-bambu-orange/20 text-bambu-orange hover:bg-bambu-orange/30 transition-colors cursor-pointer`,onClick:e=>{e.stopPropagation(),M(!0)},title:d(`archives.card.runsBadgeTitle`,{count:e.run_count,successful:e.successful_run_count,failed:e.failed_run_count}),children:d(`archives.card.runsBadge`,{count:e.run_count})})]}),(0,K.jsxs)(`div`,{className:`grid grid-cols-2 gap-2 text-xs mb-4 min-h-[48px]`,children:[(e.print_time_seconds||e.actual_time_seconds)&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-bambu-gray`,title:e.time_accuracy?`Estimated: ${Cf(e.print_time_seconds||0)}\nActual: ${Cf(e.actual_time_seconds||0)}\nAccuracy: ${e.time_accuracy.toFixed(0)}%`:e.actual_time_seconds?`Actual: ${Cf(e.actual_time_seconds)}`:`Estimated: ${Cf(e.print_time_seconds||0)}`,children:[(0,K.jsx)(xs,{className:`w-3 h-3`}),Cf(e.actual_time_seconds||e.print_time_seconds||0),e.time_accuracy&&(0,K.jsxs)(`span`,{className:`text-[10px] px-1 rounded ${e.time_accuracy>=95&&e.time_accuracy<=105?`bg-bambu-green/20 text-bambu-green`:e.time_accuracy>105?`bg-blue-500/20 text-blue-400`:`bg-orange-500/20 text-orange-400`}`,children:[e.time_accuracy>100?`+`:``,(e.time_accuracy-100).toFixed(0),`%`]})]}),e.filament_used_grams&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-bambu-gray`,children:[(0,K.jsx)(fl,{className:`w-3 h-3`}),e.filament_used_grams.toFixed(1),`g`]}),(e.cost!=null||e.energy_cost!=null)&&(0,K.jsxs)(`div`,{className:`flex items-center gap-3 text-bambu-gray`,children:[e.cost!=null&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,K.jsx)(Ds,{className:`w-3 h-3`}),u,e.cost.toFixed(2)]}),e.energy_cost!=null&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5`,title:`${d(`stats.energyUsed`)}: ${e.energy_kwh?.toFixed(3)||`N/A`} kWh`,children:[(0,K.jsx)(Bu,{className:`w-3 h-3`}),u,e.energy_cost.toFixed(2)]})]}),(e.layer_height||e.total_layers)&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-bambu-gray`,children:[(0,K.jsx)(Lc,{className:`w-3 h-3`}),e.total_layers&&(0,K.jsx)(`span`,{children:e.total_layers===1?d(`archives.card.layer`,{count:e.total_layers}):d(`archives.card.layers`,{count:e.total_layers})}),e.total_layers&&e.layer_height&&(0,K.jsx)(`span`,{className:`text-bambu-gray/50`,children:`·`}),e.layer_height&&(0,K.jsxs)(`span`,{children:[e.layer_height,`mm`]})]}),e.object_count!=null&&e.object_count>0&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-bambu-gray`,title:e.object_count===1?d(`archives.card.object`,{count:e.object_count}):d(`archives.card.objects`,{count:e.object_count}),children:[(0,K.jsx)(Wo,{className:`w-3 h-3`}),e.object_count===1?d(`archives.card.object`,{count:e.object_count}):d(`archives.card.objects`,{count:e.object_count})]}),e.sliced_for_model&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-bambu-gray`,title:d(`archives.card.slicedFor`,{model:e.sliced_for_model}),children:[(0,K.jsx)(wl,{className:`w-3 h-3`}),e.sliced_for_model]}),e.filament_type&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 col-span-2`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray text-xs`,children:e.filament_type}),e.filament_color&&(0,K.jsx)(`div`,{className:`flex items-center gap-0.5 flex-wrap`,children:e.filament_color.split(`,`).map((e,t)=>(0,K.jsx)(`div`,{className:`w-3 h-3 rounded-full border border-black/20`,style:{backgroundColor:e},title:e},t))})]})]}),(e.tags||e.notes)&&(0,K.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 mb-3`,children:[e.notes&&(0,K.jsx)(`div`,{className:`flex items-center gap-1 px-1.5 py-0.5 bg-blue-500/20 text-blue-400 rounded text-xs`,title:e.notes,children:(0,K.jsx)(cu,{className:`w-3 h-3`})}),e.tags?.split(`,`).map((e,t)=>(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-bambu-dark-tertiary text-bambu-gray-light rounded text-xs`,children:e.trim()},t))]}),(0,K.jsx)(`div`,{className:`flex-1`}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between text-xs text-bambu-gray border-t border-bambu-dark-tertiary pt-3`,children:[(0,K.jsx)(`span`,{children:bf(e.created_at,s)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[e.created_by_username&&(0,K.jsxs)(`span`,{className:`flex items-center gap-1`,title:d(`archives.card.uploadedBy`,{name:e.created_by_username}),children:[(0,K.jsx)(Du,{className:`w-3 h-3`}),e.created_by_username]}),(0,K.jsx)(`span`,{children:Cd(e.file_size)})]})]}),(0,K.jsxs)(`div`,{className:`flex gap-1 mt-3`,children:[m2(e)?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)($,{variant:`primary`,size:`sm`,className:`flex-1 min-w-0 overflow-hidden`,onClick:()=>x(!0),disabled:!e.file_path||!g(`archives`,`reprint`,e.created_by_id),title:e.file_path?g(`archives`,`reprint`,e.created_by_id)?void 0:d(`archives.card.noPermissionReprint`):d(`archives.card.noFileForReprint`),children:[(0,K.jsx)(wl,{className:`w-3 h-3 flex-shrink-0`}),(0,K.jsx)(`span`,{className:`hidden xl:inline truncate`,children:d(`archives.card.reprint`)})]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,className:`flex-1 min-w-0 overflow-hidden`,onClick:()=>ie(!0),disabled:!e.file_path||!h(`queue:create`),title:e.file_path?h(`queue:create`)?d(`archives.card.schedulePrint`):d(`archives.permission.noAddToQueue`):d(`archives.card.noFileForReprint`),children:[(0,K.jsx)(Zo,{className:`w-3 h-3 flex-shrink-0`}),(0,K.jsx)(`span`,{className:`hidden xl:inline truncate`,children:d(`archives.card.schedule`)})]}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,className:`min-w-0 p-1 sm:p-1.5`,onClick:()=>{let t=e.print_name||e.filename||`model`;h2(e.id,t,`file`,c)},title:d(`archives.card.openInBambuStudio`),children:(0,K.jsx)(qs,{className:`w-3 h-3 sm:w-4 sm:h-4`})})]}):(0,K.jsxs)($,{variant:`primary`,size:`sm`,className:`flex-1 min-w-0 overflow-hidden`,onClick:()=>{if(l)C(!0);else{let t=e.print_name||e.filename||`model`;h2(e.id,t,`file`,c)}},title:d(l?`slice.title`:`archives.card.openInBambuStudioToSlice`),children:[l?(0,K.jsx)(Os,{className:`w-3 h-3 flex-shrink-0`}):(0,K.jsx)(qs,{className:`w-3 h-3 flex-shrink-0`}),(0,K.jsx)(`span`,{className:`hidden xl:inline truncate`,children:d(`archives.card.slice`)})]}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,className:`min-w-0 p-1 sm:p-1.5`,onClick:()=>{let t=e.external_url||e.makerworld_url;t&&window.open(t,`_blank`)},disabled:!e.external_url&&!e.makerworld_url,title:e.external_url?d(`archives.card.externalLink`):e.makerworld_url?d(`archives.card.makerWorld`,{designer:e.designer||d(`archives.card.viewProject`)}):d(`archives.card.noExternalLink`),children:(0,K.jsx)(yc,{className:`w-3 h-3 sm:w-4 sm:h-4 ${!e.external_url&&!e.makerworld_url?`opacity-20`:``}`})}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,className:`min-w-0 p-1 sm:p-1.5`,onClick:()=>{Q.downloadArchive(e.id,`${e.print_name||e.filename}.3mf`).catch(e=>{console.error(`Archive download failed:`,e)})},title:d(`archives.card.download`),children:(0,K.jsx)(Bs,{className:`w-3 h-3 sm:w-4 sm:h-4`})}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,className:`min-w-0 p-1 sm:p-1.5`,onClick:()=>T(!0),disabled:!g(`archives`,`delete`,e.created_by_id),title:g(`archives`,`delete`,e.created_by_id)?d(`archives.card.delete`):d(`archives.card.noPermissionDelete`),children:(0,K.jsx)(yu,{className:`w-3 h-3 sm:w-4 sm:h-4 text-red-400`})})]})]}),k&&(0,K.jsx)(cG,{archive:e,onClose:()=>A(!1)}),j&&(0,K.jsx)(lG,{archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>M(!1)}),he&&(0,K.jsx)(JW,{plates:he,onSelect:t=>{ge(null),v(`/gcode-viewer?archive=${e.id}&plate=${t}`)},onClose:()=>ge(null)}),b&&(0,K.jsx)(xW,{mode:`reprint`,archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>x(!1)}),S&&(0,K.jsx)($W,{source:{kind:`archive`,id:e.id,filename:e.print_name||e.filename||`model`},onClose:()=>C(!1)}),w&&(0,K.jsxs)(Ad,{title:d(`archives.modal.deleteArchive`),message:d(`archives.modal.deleteConfirm`,{name:e.print_name||e.filename}),confirmText:d(`archives.modal.deleteButton`),variant:`danger`,confirmDisabled:(O.data?.currently_printing??0)>0,onConfirm:()=>{Fe.mutate(E),T(!1),D(!1)},onCancel:()=>{T(!1),D(!1)},children:[(O.data?.related_queue_items??0)>0&&(0,K.jsx)(`div`,{className:(O.data?.currently_printing??0)>0?`text-sm text-red-400 mb-2`:`text-sm text-amber-400 mb-2`,children:(O.data?.currently_printing??0)>0?d(`archives.modal.deleteBlockedByPrinting`,{count:O.data.currently_printing}):d(`archives.modal.deleteQueueItemsWarning`,{count:O.data.related_queue_items})}),(0,K.jsxs)(`label`,{className:`flex items-start gap-2 cursor-pointer text-sm text-bambu-gray`,children:[(0,K.jsx)(`input`,{type:`checkbox`,className:`mt-0.5 accent-red-500`,checked:E,onChange:e=>D(e.target.checked)}),(0,K.jsx)(`span`,{children:d(`archives.modal.deletePurgeStats`)})]})]}),H&&(0,K.jsx)(Ad,{title:d(`archives.modal.removeSource3mf`),message:d(`archives.modal.removeSource3mfConfirm`,{name:e.print_name||e.filename}),confirmText:d(`archives.modal.removeButton`),variant:`danger`,onConfirm:()=>{Ae.mutate(),ae(!1)},onCancel:()=>ae(!1)}),oe&&(0,K.jsx)(Ad,{title:d(`archives.modal.removeF3d`),message:d(`archives.modal.removeF3dConfirm`,{name:e.print_name||e.filename}),confirmText:d(`archives.modal.removeButton`),variant:`danger`,onConfirm:()=>{Me.mutate(),U(!1)},onCancel:()=>U(!1)}),se&&(0,K.jsx)(Ad,{title:d(`archives.modal.removeTimelapse`),message:d(`archives.modal.removeTimelapseConfirm`,{name:e.print_name||e.filename}),confirmText:d(`archives.modal.removeButton`),variant:`danger`,onConfirm:()=>{De.mutate(),ce(!1)},onCancel:()=>ce(!1)}),le&&(0,K.jsx)(uG,{x:le.x,y:le.y,items:Be,onClose:()=>ue(null)}),N&&e.timelapse_path&&(0,K.jsx)(p2,{src:Q.getArchiveTimelapse(e.id),title:d(`archives.modal.timelapse`,{name:e.print_name||e.filename}),downloadFilename:`${e.print_name||e.filename}_timelapse.mp4`,archiveId:e.id,onClose:()=>P(!1),onEdit:()=>{p.invalidateQueries({queryKey:[`archives`]}),P(!1)}}),F&&L.length>0&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/80 flex items-center justify-center z-50 p-4`,children:(0,K.jsxs)(`div`,{className:`bg-card-dark rounded-lg max-w-lg w-full max-h-[80vh] flex flex-col`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between p-4 border-b border-gray-700`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white`,children:d(`archives.modal.selectTimelapse`)}),(0,K.jsx)(`p`,{className:`text-sm text-gray-400 mt-1`,children:d(`archives.modal.selectTimelapseDesc`)})]}),(0,K.jsx)(`button`,{onClick:()=>{I(!1),R([])},className:`text-gray-400 hover:text-white p-1`,children:(0,K.jsx)(Ru,{className:`w-5 h-5`})})]}),(0,K.jsx)(`div`,{className:`overflow-y-auto flex-1 p-2`,children:L.map(e=>(0,K.jsxs)(`button`,{onClick:()=>Pe.mutate(e.name),disabled:Pe.isPending,className:`w-full text-left p-3 rounded-lg hover:bg-gray-700 transition-colors flex items-center gap-3 disabled:opacity-50`,children:[(0,K.jsx)(rc,{className:`w-8 h-8 text-bambu-green flex-shrink-0`}),(0,K.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,K.jsx)(`p`,{className:`text-white font-medium truncate`,children:e.name}),(0,K.jsxs)(`p`,{className:`text-sm text-gray-400`,children:[Cd(e.size),e.mtime&&` • ${bf(e.mtime,s)}`]})]})]},e.name))}),(0,K.jsx)(`div`,{className:`p-4 border-t border-gray-700`,children:(0,K.jsx)($,{variant:`secondary`,onClick:()=>{I(!1),R([])},className:`w-full`,children:`Cancel`})})]})}),z&&(0,K.jsx)(dG,{archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>B(!1)}),V&&e.photos&&e.photos.length>0&&(0,K.jsx)(fG,{archiveId:e.id,archiveName:e.print_name||e.filename,photos:e.photos,onClose:()=>ee(!1),onDelete:async t=>{try{await Q.deleteArchivePhoto(e.id,t),p.invalidateQueries({queryKey:[`archives`]}),m(d(`archives.toast.photoDeleted`))}catch{m(d(`archives.toast.failedDeletePhoto`),`error`)}}}),te&&(0,K.jsx)(f2,{archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>ne(!1)}),re&&(0,K.jsx)(xW,{mode:`add-to-queue`,archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>ie(!1)}),(0,K.jsx)(`input`,{ref:_e,type:`file`,accept:`.3mf`,className:`hidden`,onChange:e=>{let t=e.target.files?.[0];t&&ke.mutate(t),e.target.value=``}}),(0,K.jsx)(`input`,{ref:ve,type:`file`,accept:`.f3d`,className:`hidden`,onChange:e=>{let t=e.target.files?.[0];t&&je.mutate(t),e.target.value=``}}),(0,K.jsx)(`input`,{ref:ye,type:`file`,accept:`.mp4,.avi,.mkv`,className:`hidden`,onChange:e=>{let t=e.target.files?.[0];t&&Oe.mutate(t),e.target.value=``}})]})}function XRe({archive:e,printerName:t,isSelected:n,onSelect:r,selectionMode:i,projects:a,isHighlighted:o,preferredSlicer:s=`bambu_studio`,useSlicerApi:c=!1,t:l,onNavigateToArchive:u}){let d=no(),{showToast:f}=Td(),{hasPermission:p,canModify:m}=dd(),[h,g]=(0,y.useState)(!1),[_,v]=(0,y.useState)(!1),[b,x]=(0,y.useState)(!1),[S,C]=(0,y.useState)(!1),w=q({queryKey:[`archive`,e.id,`delete-impact`],queryFn:()=>Q.getArchiveDeleteImpact(e.id),enabled:b,staleTime:0}),T=$n(),[E,D]=(0,y.useState)(!1),[O,k]=(0,y.useState)(!1),[A,j]=(0,y.useState)(!1),[M,N]=(0,y.useState)(!1),[P,F]=(0,y.useState)(!1),[I,L]=(0,y.useState)([]),[R,z]=(0,y.useState)(!1),[B,V]=(0,y.useState)(!1),[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)(null),ce=(0,y.useRef)(null),le=(0,y.useRef)(null),ue=(0,y.useRef)(null),[de,fe]=(0,y.useState)(null),pe=e.duplicate_sequence??0,me=e.original_archive_id??null,he=async()=>{try{let t=await Q.getArchivePlates(e.id);if(t.is_multi_plate&&t.plates.length>1){fe(t.plates);return}}catch{}T(`/gcode-viewer?archive=${e.id}`)},ge=J({mutationFn:()=>Q.deleteArchiveTimelapse(e.id),onSuccess:()=>{d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.timelapseRemoved`))},onError:e=>{f(e.message||l(`archives.toast.failedRemoveTimelapse`),`error`)}}),_e=J({mutationFn:t=>Q.uploadArchiveTimelapse(e.id,t),onSuccess:e=>{d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.timelapseUploaded`,{filename:e.filename}))},onError:e=>{f(e.message||l(`archives.toast.failedUploadTimelapse`),`error`)}}),ve=J({mutationFn:t=>Q.uploadSource3mf(e.id,t),onSuccess:e=>{d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.source3mfAttached`,{filename:e.filename}))},onError:e=>{f(e.message||l(`archives.toast.failedUploadSource3mf`),`error`)}}),ye=J({mutationFn:()=>Q.deleteSource3mf(e.id),onSuccess:()=>{d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.source3mfRemoved`))},onError:e=>{f(e.message||l(`archives.toast.failedRemoveSource3mf`),`error`)}}),be=J({mutationFn:t=>Q.uploadF3d(e.id,t),onSuccess:e=>{d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.f3dAttached`,{filename:e.filename}))},onError:e=>{f(e.message||l(`archives.toast.failedUploadF3d`),`error`)}}),xe=J({mutationFn:()=>Q.deleteF3d(e.id),onSuccess:()=>{d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.f3dRemoved`))},onError:e=>{f(e.message||l(`archives.toast.failedRemoveF3d`),`error`)}}),Se=J({mutationFn:()=>Q.scanArchiveTimelapse(e.id),onSuccess:e=>{e.status===`attached`?(d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.timelapseAttached`,{filename:e.filename}))):e.status===`exists`?f(l(`archives.toast.timelapseAlreadyAttached`)):e.status===`not_found`&&e.available_files&&e.available_files.length>0?(L(e.available_files),F(!0)):f(e.message||l(`archives.toast.noMatchingTimelapse`),`warning`)},onError:e=>{f(e.message||l(`archives.toast.failedScanTimelapse`),`error`)}}),Ce=J({mutationFn:t=>Q.selectArchiveTimelapse(e.id,t),onSuccess:e=>{d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.timelapseAttached`,{filename:e.filename})),F(!1),L([])},onError:e=>{f(e.message||l(`archives.toast.failedAttachTimelapse`),`error`)}}),we=J({mutationFn:t=>Q.deleteArchive(e.id,t),onSuccess:()=>{d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.archiveDeleted`))},onError:()=>{f(l(`archives.toast.failedDeleteArchive`),`error`)}}),Te=J({mutationFn:()=>Q.toggleFavorite(e.id),onSuccess:e=>{d.invalidateQueries({queryKey:[`archives`]}),f(e.is_favorite?l(`archives.toast.addedToFavorites`):l(`archives.toast.removedFromFavorites`))}}),{data:Ee}=q({queryKey:[`archive-folders`,e.id],queryFn:()=>Q.getLibraryFoldersByArchive(e.id)}),De=J({mutationFn:t=>Q.updateArchive(e.id,{project_id:t}),onSuccess:()=>{d.invalidateQueries({queryKey:[`archives`]}),d.invalidateQueries({queryKey:[`projects`]}),f(l(`archives.toast.projectUpdated`))},onError:()=>{f(l(`archives.toast.failedUpdateProject`),`error`)}}),Oe=e=>{e.preventDefault(),se({x:e.clientX,y:e.clientY})},ke=[...m2(e)?[{label:l(`archives.menu.print`),icon:(0,K.jsx)(wl,{className:`w-4 h-4`}),onClick:()=>D(!0),disabled:!e.file_path||!m(`archives`,`reprint`,e.created_by_id),title:e.file_path?m(`archives`,`reprint`,e.created_by_id)?void 0:l(`archives.permission.noReprint`):l(`archives.card.noFileForReprint`)},{label:l(`archives.menu.schedule`),icon:(0,K.jsx)(Zo,{className:`w-4 h-4`}),onClick:()=>j(!0),disabled:!e.file_path||!p(`queue:create`),title:e.file_path?p(`queue:create`)?void 0:l(`archives.permission.noAddToQueue`):l(`archives.card.noFileForReprint`)},{label:l(`archives.menu.openInBambuStudio`),icon:(0,K.jsx)(qs,{className:`w-4 h-4`}),onClick:()=>{let t=e.print_name||e.filename||`model`;h2(e.id,t,`file`,s)},disabled:!e.file_path,title:e.file_path?void 0:l(`archives.card.noFileForReprint`)}]:[{label:l(`archives.menu.slice`),icon:c?(0,K.jsx)(Os,{className:`w-4 h-4`}):(0,K.jsx)(qs,{className:`w-4 h-4`}),onClick:()=>{if(c)k(!0);else{let t=e.print_name||e.filename||`model`;h2(e.id,t,`file`,s)}}}],{label:e.external_url?l(`archives.menu.externalLink`):l(`archives.menu.viewOnMakerWorld`),icon:(0,K.jsx)(yc,{className:`w-4 h-4`}),onClick:()=>{let t=e.external_url||e.makerworld_url;t&&window.open(t,`_blank`)},disabled:!e.external_url&&!e.makerworld_url},{label:``,divider:!0,onClick:()=>{}},{label:l(`archives.menu.preview3d`),icon:(0,K.jsx)(Wo,{className:`w-4 h-4`}),onClick:()=>{he()}},{label:l(`archives.menu.viewTimelapse`),icon:(0,K.jsx)(rc,{className:`w-4 h-4`}),onClick:()=>N(!0),disabled:!e.timelapse_path},{label:l(`archives.menu.scanForTimelapse`),icon:(0,K.jsx)(Fl,{className:`w-4 h-4`}),onClick:()=>Se.mutate(),disabled:!e.printer_id||!!e.timelapse_path||Se.isPending||!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)},{label:l(`archives.menu.uploadTimelapse`),icon:(0,K.jsx)(Eu,{className:`w-4 h-4`}),onClick:()=>ue.current?.click(),disabled:!!e.timelapse_path||!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)},...e.timelapse_path?[{label:l(`archives.menu.removeTimelapse`),icon:(0,K.jsx)(yu,{className:`w-4 h-4`}),onClick:()=>oe(!0),danger:!0,disabled:!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)}]:[],{label:``,divider:!0,onClick:()=>{}},{label:e.source_3mf_path?l(`archives.menu.downloadSource3mf`):l(`archives.menu.uploadSource3mf`),icon:(0,K.jsx)(Qs,{className:`w-4 h-4`}),onClick:()=>{e.source_3mf_path?Q.downloadSource3mf(e.id).catch(e=>{console.error(`Source 3MF download failed:`,e)}):ce.current?.click()},disabled:!e.source_3mf_path&&!m(`archives`,`update`,e.created_by_id),title:!e.source_3mf_path&&!m(`archives`,`update`,e.created_by_id)?l(`archives.permission.noUploadFiles`):void 0},...e.source_3mf_path?[{label:l(`archives.menu.replaceSource3mf`),icon:(0,K.jsx)(Eu,{className:`w-4 h-4`}),onClick:()=>ce.current?.click(),disabled:!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)},{label:l(`archives.menu.removeSource3mf`),icon:(0,K.jsx)(yu,{className:`w-4 h-4`}),onClick:()=>re(!0),danger:!0,disabled:!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)}]:[],{label:e.f3d_path?l(`archives.menu.replaceF3d`):l(`archives.menu.uploadF3d`),icon:(0,K.jsx)(Wo,{className:`w-4 h-4`}),onClick:()=>le.current?.click(),disabled:!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)},...e.f3d_path?[{label:l(`archives.menu.downloadF3d`),icon:(0,K.jsx)(Bs,{className:`w-4 h-4`}),onClick:()=>{Q.downloadF3d(e.id).catch(e=>{console.error(`F3D download failed:`,e)})}},{label:l(`archives.menu.removeF3d`),icon:(0,K.jsx)(yu,{className:`w-4 h-4`}),onClick:()=>H(!0),danger:!0,disabled:!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)}]:[],{label:``,divider:!0,onClick:()=>{}},{label:l(`archives.menu.download`),icon:(0,K.jsx)(Bs,{className:`w-4 h-4`}),onClick:()=>{Q.downloadArchive(e.id,`${e.print_name||e.filename}.3mf`).catch(e=>{console.error(`Archive download failed:`,e)})},disabled:!p(`archives:read`),title:p(`archives:read`)?void 0:l(`archives.permission.noDownload`)},{label:l(`archives.menu.copyDownloadLink`),icon:(0,K.jsx)(js,{className:`w-4 h-4`}),onClick:()=>{let t=`${window.location.origin}${Q.getArchiveDownload(e.id)}`;navigator.clipboard.writeText(t).then(()=>{f(l(`archives.toast.linkCopied`))}).catch(()=>{f(l(`archives.toast.failedCopyLink`),`error`)})},disabled:!p(`archives:read`),title:p(`archives:read`)?void 0:l(`archives.permission.noCopyLink`)},{label:l(`archives.menu.qrCode`),icon:(0,K.jsx)(Tl,{className:`w-4 h-4`}),onClick:()=>z(!0)},{label:e.photos?.length?l(`archives.menu.viewPhotosCount`,{count:e.photos.length}):l(`archives.menu.viewPhotos`),icon:(0,K.jsx)(Qo,{className:`w-4 h-4`}),onClick:()=>V(!0),disabled:!e.photos?.length},{label:l(`archives.menu.projectPage`),icon:(0,K.jsx)(tc,{className:`w-4 h-4`}),onClick:()=>te(!0)},{label:``,divider:!0,onClick:()=>{}},{label:e.is_favorite?l(`archives.menu.removeFromFavorites`):l(`archives.menu.addToFavorites`),icon:(0,K.jsx)(ou,{className:`w-4 h-4 ${e.is_favorite?`fill-yellow-400 text-yellow-400`:``}`}),onClick:()=>Te.mutate(),disabled:!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)},{label:l(`archives.menu.edit`),icon:(0,K.jsx)(_l,{className:`w-4 h-4`}),onClick:()=>g(!0),disabled:!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?void 0:l(`archives.permission.noUpdateArchives`)},{label:l(`archives.menu.printLog`),icon:(0,K.jsx)(Oc,{className:`w-4 h-4`}),onClick:()=>v(!0)},...e.project_id&&e.project_name?[{label:l(`archives.menu.goToProject`,{name:e.project_name}),icon:(0,K.jsx)(oc,{className:`w-4 h-4 text-bambu-green`}),onClick:()=>window.location.href=`/projects`}]:[],{label:l(`archives.menu.addToProject`),icon:(0,K.jsx)(oc,{className:`w-4 h-4`}),onClick:()=>{},submenuSearchPlaceholder:(a?.filter(e=>e.status===`active`).length??0)>5?l(`archives.menu.searchProjects`):void 0,submenu:(()=>{let t=[];if(e.project_id&&t.push({label:l(`archives.menu.removeFromProject`),icon:(0,K.jsx)(Ru,{className:`w-4 h-4`}),onClick:()=>De.mutate(null)}),!a)t.push({label:l(`archives.menu.loading`),icon:(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}),onClick:()=>{},disabled:!0});else{let n=a.filter(e=>e.status===`active`).sort((e,t)=>e.name.localeCompare(t.name));n.length===0?t.push({label:l(`archives.menu.noProjectsAvailable`),icon:(0,K.jsx)(oc,{className:`w-4 h-4 opacity-50`}),onClick:()=>{},disabled:!0}):n.forEach(n=>{t.push({label:n.name,icon:(0,K.jsx)(`div`,{className:`w-3 h-3 rounded-full flex-shrink-0`,style:{backgroundColor:n.color||`#888`}}),onClick:()=>De.mutate(n.id),disabled:e.project_id===n.id})})}return t})()},{label:l(n?`archives.menu.deselect`:`archives.menu.select`),icon:n?(0,K.jsx)(ru,{className:`w-4 h-4`}):(0,K.jsx)(au,{className:`w-4 h-4`}),onClick:()=>r(e.id)},{label:``,divider:!0,onClick:()=>{}},{label:l(`archives.menu.delete`),icon:(0,K.jsx)(yu,{className:`w-4 h-4`}),onClick:()=>x(!0),danger:!0,disabled:!m(`archives`,`delete`,e.created_by_id),title:m(`archives`,`delete`,e.created_by_id)?void 0:l(`archives.permission.noDelete`)}];return(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{"data-archive-id":e.id,className:`grid grid-cols-12 gap-4 px-4 py-3 items-center hover:bg-bambu-dark-tertiary/30 ${n?`bg-bambu-green/10`:``}`,style:o?{outline:`4px solid #facc15`,outlineOffset:`-4px`}:void 0,onContextMenu:Oe,children:[(0,K.jsxs)(`div`,{className:`col-span-1 flex items-center gap-2`,children:[i&&(0,K.jsx)(`button`,{onClick:()=>r(e.id),children:n?(0,K.jsx)(ru,{className:`w-4 h-4 text-bambu-green`}):(0,K.jsx)(au,{className:`w-4 h-4 text-bambu-gray`})}),e.thumbnail_path?(0,K.jsx)(`img`,{src:Q.getArchiveThumbnail(e.id),alt:``,className:`w-10 h-10 object-cover rounded`}):(0,K.jsx)(`div`,{className:`w-10 h-10 bg-bambu-dark rounded flex items-center justify-center`,children:(0,K.jsx)(jc,{className:`w-5 h-5 text-bambu-dark-tertiary`})})]}),(0,K.jsxs)(`div`,{className:`col-span-4`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`p`,{className:`text-white text-sm truncate`,children:e.print_name||e.filename}),(e.status===`failed`||e.status===`aborted`)&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 rounded text-[10px] leading-tight bg-status-error/80 text-white flex-shrink-0`,children:e.status===`aborted`?l(`archives.card.cancelled`):l(`archives.card.failed`)}),e.duplicate_count>0&&pe>0&&me&&(0,K.jsxs)(`button`,{onClick:e=>{e.stopPropagation(),u?.(me)},className:`px-1.5 py-0.5 rounded text-[10px] leading-tight bg-purple-500/80 hover:bg-purple-600/90 text-white flex-shrink-0 transition-colors flex items-center gap-1`,title:l(`archives.viewOriginalPrint`,{id:me}),children:[(0,K.jsx)(js,{className:`w-3 h-3`}),`#`,pe]}),e.duplicate_count>0&&pe===0&&(0,K.jsxs)(`span`,{className:`px-1.5 py-0.5 rounded text-[10px] leading-tight bg-purple-500/80 text-white flex-shrink-0 flex items-center gap-1`,title:`${e.duplicate_count} reprint${e.duplicate_count===1?``:`s`}`,children:[(0,K.jsx)(gc,{className:`w-3 h-3`}),`+`,e.duplicate_count]}),e.timelapse_path&&(0,K.jsx)(`span`,{title:l(`archives.list.hasTimelapse`),children:(0,K.jsx)(rc,{className:`w-3.5 h-3.5 text-bambu-green flex-shrink-0`})}),Ee&&Ee.length>0&&(0,K.jsx)(wi,{to:`/files?folder=${Ee[0].id}`,className:`flex-shrink-0`,title:l(`archives.card.openFolder`,{name:Ee[0].name}),onClick:e=>e.stopPropagation(),children:(0,K.jsx)(sc,{className:`w-3.5 h-3.5 text-yellow-400`})})]}),(e.filament_type||e.sliced_for_model)&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 mt-0.5`,children:[e.sliced_for_model&&(0,K.jsxs)(`span`,{className:`text-xs text-bambu-gray flex items-center gap-1`,title:l(`archives.card.slicedFor`,{model:e.sliced_for_model}),children:[(0,K.jsx)(wl,{className:`w-2.5 h-2.5`}),e.sliced_for_model]}),(()=>{let t=pW(e.bed_type);return t?(0,K.jsx)(`img`,{src:t.icon,alt:t.label,title:t.label,className:`w-3.5 h-3.5 flex-shrink-0`}):null})(),e.sliced_for_model&&e.filament_type&&(0,K.jsx)(`span`,{className:`text-bambu-gray/50`,children:`·`}),e.filament_type&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray`,children:e.filament_type}),e.filament_color&&(0,K.jsx)(`div`,{className:`flex items-center gap-0.5 flex-wrap`,children:e.filament_color.split(`,`).map((e,t)=>(0,K.jsx)(`div`,{className:`w-2.5 h-2.5 rounded-full border border-black/20`,style:{backgroundColor:e},title:e},t))})]})]}),(0,K.jsx)(`div`,{className:`col-span-2 text-sm text-bambu-gray truncate`,children:t}),(0,K.jsxs)(`div`,{className:`col-span-2 text-sm text-bambu-gray`,children:[(0,K.jsx)(`div`,{children:yf(e.created_at)}),e.created_by_username&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1 text-xs opacity-75`,title:l(`archives.card.uploadedBy`,{name:e.created_by_username}),children:[(0,K.jsx)(Du,{className:`w-3 h-3`}),e.created_by_username]})]}),(0,K.jsx)(`div`,{className:`col-span-1 text-sm text-bambu-gray`,children:Cd(e.file_size)}),(0,K.jsxs)(`div`,{className:`col-span-2 flex justify-end gap-1`,children:[m2(e)&&(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>D(!0),disabled:!m(`archives`,`reprint`,e.created_by_id),title:m(`archives`,`reprint`,e.created_by_id)?l(`archives.card.reprint`):l(`archives.card.noPermissionReprint`),className:`text-bambu-green hover:text-bambu-green-light hover:bg-bambu-green/10`,children:(0,K.jsx)(yl,{className:`w-4 h-4`})}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>{let t=e.print_name||e.filename||`model`;h2(e.id,t,`file`,s)},title:l(`archives.card.openInBambuStudio`),children:(0,K.jsx)(qs,{className:`w-4 h-4`})}),(e.external_url||e.makerworld_url)&&(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>window.open(e.external_url||e.makerworld_url,`_blank`),title:e.external_url?l(`archives.card.externalLink`):`MakerWorld`,children:(0,K.jsx)(yc,{className:`w-4 h-4`})}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>{Q.downloadArchive(e.id,`${e.print_name||e.filename}.3mf`).catch(e=>{console.error(`Archive download failed:`,e)})},title:l(`archives.card.download`),children:(0,K.jsx)(Bs,{className:`w-4 h-4`})}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>g(!0),disabled:!m(`archives`,`update`,e.created_by_id),title:m(`archives`,`update`,e.created_by_id)?l(`archives.card.edit`):l(`archives.card.noPermissionEdit`),children:(0,K.jsx)(_l,{className:`w-4 h-4`})}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>x(!0),disabled:!m(`archives`,`delete`,e.created_by_id),title:m(`archives`,`delete`,e.created_by_id)?l(`archives.card.delete`):l(`archives.card.noPermissionDelete`),children:(0,K.jsx)(yu,{className:`w-4 h-4 text-red-400`})}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:e=>{let t=e.currentTarget.getBoundingClientRect();se({x:t.left,y:t.bottom+4})},title:l(`archives.card.moreOptions`),children:(0,K.jsx)(Us,{className:`w-4 h-4`})})]})]}),h&&(0,K.jsx)(cG,{archive:e,onClose:()=>g(!1)}),_&&(0,K.jsx)(lG,{archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>v(!1)}),de&&(0,K.jsx)(JW,{plates:de,onSelect:t=>{fe(null),T(`/gcode-viewer?archive=${e.id}&plate=${t}`)},onClose:()=>fe(null)}),E&&(0,K.jsx)(xW,{mode:`reprint`,archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>D(!1)}),O&&(0,K.jsx)($W,{source:{kind:`archive`,id:e.id,filename:e.print_name||e.filename||`model`},onClose:()=>k(!1)}),b&&(0,K.jsxs)(Ad,{title:l(`archives.modal.deleteArchive`),message:l(`archives.modal.deleteConfirm`,{name:e.print_name||e.filename}),confirmText:l(`archives.modal.deleteButton`),variant:`danger`,confirmDisabled:(w.data?.currently_printing??0)>0,onConfirm:()=>{we.mutate(S),x(!1),C(!1)},onCancel:()=>{x(!1),C(!1)},children:[(w.data?.related_queue_items??0)>0&&(0,K.jsx)(`div`,{className:(w.data?.currently_printing??0)>0?`text-sm text-red-400 mb-2`:`text-sm text-amber-400 mb-2`,children:(w.data?.currently_printing??0)>0?l(`archives.modal.deleteBlockedByPrinting`,{count:w.data.currently_printing}):l(`archives.modal.deleteQueueItemsWarning`,{count:w.data.related_queue_items})}),(0,K.jsxs)(`label`,{className:`flex items-start gap-2 cursor-pointer text-sm text-bambu-gray`,children:[(0,K.jsx)(`input`,{type:`checkbox`,className:`mt-0.5 accent-red-500`,checked:S,onChange:e=>C(e.target.checked)}),(0,K.jsx)(`span`,{children:l(`archives.modal.deletePurgeStats`)})]})]}),ne&&(0,K.jsx)(Ad,{title:l(`archives.modal.removeSource3mf`),message:l(`archives.modal.removeSource3mfConfirm`,{name:e.print_name||e.filename}),confirmText:l(`archives.modal.removeButton`),variant:`danger`,onConfirm:()=>{ye.mutate(),re(!1)},onCancel:()=>re(!1)}),ie&&(0,K.jsx)(Ad,{title:l(`archives.modal.removeF3d`),message:l(`archives.modal.removeF3dConfirm`,{name:e.print_name||e.filename}),confirmText:l(`archives.modal.removeButton`),variant:`danger`,onConfirm:()=>{xe.mutate(),H(!1)},onCancel:()=>H(!1)}),ae&&(0,K.jsx)(Ad,{title:l(`archives.modal.removeTimelapse`),message:l(`archives.modal.removeTimelapseConfirm`,{name:e.print_name||e.filename}),confirmText:l(`archives.modal.removeButton`),variant:`danger`,onConfirm:()=>{ge.mutate(),oe(!1)},onCancel:()=>oe(!1)}),U&&(0,K.jsx)(uG,{x:U.x,y:U.y,items:ke,onClose:()=>se(null)}),M&&e.timelapse_path&&(0,K.jsx)(p2,{src:Q.getArchiveTimelapse(e.id),title:l(`archives.modal.timelapse`,{name:e.print_name||e.filename}),downloadFilename:`${e.print_name||e.filename}_timelapse.mp4`,archiveId:e.id,onClose:()=>N(!1),onEdit:()=>{d.invalidateQueries({queryKey:[`archives`]}),N(!1)}}),P&&I.length>0&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/80 flex items-center justify-center z-50 p-4`,children:(0,K.jsxs)(`div`,{className:`bg-card-dark rounded-lg max-w-lg w-full max-h-[80vh] flex flex-col`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between p-4 border-b border-gray-700`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white`,children:l(`archives.modal.selectTimelapse`)}),(0,K.jsx)(`p`,{className:`text-sm text-gray-400 mt-1`,children:l(`archives.modal.selectTimelapseDesc`)})]}),(0,K.jsx)(`button`,{onClick:()=>{F(!1),L([])},className:`text-gray-400 hover:text-white p-1`,children:(0,K.jsx)(Ru,{className:`w-5 h-5`})})]}),(0,K.jsx)(`div`,{className:`overflow-y-auto flex-1 p-2`,children:I.map(e=>(0,K.jsxs)(`button`,{onClick:()=>Ce.mutate(e.name),disabled:Ce.isPending,className:`w-full text-left p-3 rounded-lg hover:bg-gray-700 transition-colors mb-1`,children:[(0,K.jsx)(`div`,{className:`font-medium text-white`,children:e.name}),(0,K.jsxs)(`div`,{className:`text-sm text-gray-400 flex gap-3`,children:[(0,K.jsx)(`span`,{children:Cd(e.size)}),e.mtime&&(0,K.jsx)(`span`,{children:yf(e.mtime)})]})]},e.name))})]})}),R&&(0,K.jsx)(dG,{archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>z(!1)}),B&&e.photos&&(0,K.jsx)(fG,{archiveId:e.id,archiveName:e.print_name||e.filename,photos:e.photos,onClose:()=>V(!1),onDelete:async t=>{try{await Q.deleteArchivePhoto(e.id,t),d.invalidateQueries({queryKey:[`archives`]}),f(l(`archives.toast.photoDeleted`))}catch{f(l(`archives.toast.failedDeletePhoto`),`error`)}}}),ee&&(0,K.jsx)(f2,{archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>te(!1)}),A&&(0,K.jsx)(xW,{mode:`add-to-queue`,archiveId:e.id,archiveName:e.print_name||e.filename,onClose:()=>j(!1)}),(0,K.jsx)(`input`,{ref:ce,type:`file`,accept:`.3mf`,className:`hidden`,onChange:e=>{let t=e.target.files?.[0];t&&ve.mutate(t),e.target.value=``}}),(0,K.jsx)(`input`,{ref:le,type:`file`,accept:`.f3d`,className:`hidden`,onChange:e=>{let t=e.target.files?.[0];t&&be.mutate(t),e.target.value=``}}),(0,K.jsx)(`input`,{ref:ue,type:`file`,accept:`.mp4,.avi,.mkv`,className:`hidden`,onChange:e=>{let t=e.target.files?.[0];t&&_e.mutate(t),e.target.value=``}})]})}var ZRe=[`completed`,`failed`,`aborted`,`cancelled`,`stopped`],QRe=[{id:`all`,label:`All Archives`,icon:(0,K.jsx)(sc,{className:`w-4 h-4`})},{id:`recent`,label:`Last 24 Hours`,icon:(0,K.jsx)(xs,{className:`w-4 h-4`})},{id:`this-week`,label:`This Week`,icon:(0,K.jsx)(Zo,{className:`w-4 h-4`})},{id:`this-month`,label:`This Month`,icon:(0,K.jsx)(Zo,{className:`w-4 h-4`})},{id:`favorites`,label:`Favorites`,icon:(0,K.jsx)(ou,{className:`w-4 h-4`})},{id:`not-printed`,label:`Not Printed`,icon:(0,K.jsx)(Eu,{className:`w-4 h-4`})},{id:`printed`,label:`Printed`,icon:(0,K.jsx)(wl,{className:`w-4 h-4`})},{id:`failed`,label:`Failed Prints`,icon:(0,K.jsx)(ds,{className:`w-4 h-4`})},{id:`duplicates`,label:`Duplicates`,icon:(0,K.jsx)(js,{className:`w-4 h-4`})}];function $Re(){let{t:e}=W(),t=no(),{showToast:n}=Td(),{hasPermission:r,hasAnyPermission:i}=dd(),a=(0,y.useRef)(null),[o,s]=(0,y.useState)(``),[c,l]=(0,y.useState)(()=>{let e=localStorage.getItem(`archiveFilterPrinter`);return e?Number(e):null}),[u,d]=(0,y.useState)(()=>localStorage.getItem(`archiveFilterMaterial`)),[f,p]=(0,y.useState)(()=>{let e=localStorage.getItem(`archiveFilterColors`);return e?new Set(JSON.parse(e)):new Set}),[m,h]=(0,y.useState)(()=>localStorage.getItem(`archiveColorFilterMode`)||`or`),[g,_]=(0,y.useState)(()=>localStorage.getItem(`archiveFilterFavorites`)===`true`),[v,b]=(0,y.useState)(()=>localStorage.getItem(`archiveHideFailed`)===`true`),[x,S]=(0,y.useState)(()=>localStorage.getItem(`archiveHideDuplicates`)===`true`),[C,w]=(0,y.useState)(()=>localStorage.getItem(`archiveFilterTag`)),[T,E]=(0,y.useState)(()=>localStorage.getItem(`archiveFilterFileType`)||`all`),[D,O]=(0,y.useState)(!1),[k,A]=(0,y.useState)([]),[j,M]=(0,y.useState)(new Set),[N,P]=(0,y.useState)(()=>localStorage.getItem(`archiveNo3MFWarningDismissed`)===`true`),{data:F}=q({queryKey:[`archives`,`no-3mf-warning`],queryFn:Q.getNo3MFWarning,staleTime:300*1e3,enabled:!N}),I=()=>{localStorage.setItem(`archiveNo3MFWarningDismissed`,`true`),P(!0)},[L,R]=(0,y.useState)(!1),[z,B]=(0,y.useState)(!1),[V,ee]=(0,y.useState)(!1),[te,ne]=(0,y.useState)(!1),[re,ie]=(0,y.useState)(()=>localStorage.getItem(`archiveViewMode`)||`grid`),[H,ae]=(0,y.useState)(()=>localStorage.getItem(`archiveSortBy`)||`date-desc`),[oe,U]=(0,y.useState)(()=>localStorage.getItem(`archiveCollection`)||`all`),[se,ce]=(0,y.useState)(0),[le,ue]=(0,y.useState)(()=>{try{let e=localStorage.getItem(`archivePageSize`);return e?Number(e):50}catch{return 50}}),[de,fe]=(0,y.useState)(!1),[pe,me]=(0,y.useState)(!1),[he,ge]=(0,y.useState)(!1),[_e,ve]=(0,y.useState)(!1),[ye,be]=(0,y.useState)(!1),[xe,Se]=(0,y.useState)(null),[Ce,we]=(0,y.useState)(null),[Te,Ee]=(0,y.useState)(()=>localStorage.getItem(`logFilterUser`)||null),[De,Oe]=(0,y.useState)(()=>localStorage.getItem(`logFilterStatus`)),[ke,Ae]=(0,y.useState)(()=>localStorage.getItem(`logFilterDateFrom`)||``),[je,Me]=(0,y.useState)(()=>localStorage.getItem(`logFilterDateTo`)||``),[Ne,Pe]=(0,y.useState)(()=>{let e=localStorage.getItem(`logOffset`);return e?Number(e):0}),[Fe,Ie]=(0,y.useState)(!1),[Le,Re]=(0,y.useState)(null),[ze,Be]=(0,y.useState)(null),[Ve,He]=(0,y.useState)(``),[Ue,We]=(0,y.useState)(``),[Ge,Ke]=(0,y.useState)(()=>{let e=localStorage.getItem(`logPageSize`);return e?Number(e):25}),qe=(0,y.useCallback)(e=>{we(e),Se(e)},[]);(0,y.useEffect)(()=>{if(xe){let t=setTimeout(()=>{let t=document.querySelector(`[data-archive-id="${xe}"]`);t?t.scrollIntoView({behavior:`smooth`,block:`center`}):Ce===xe&&n(e(`archives.originalPrintNotVisible`),`warning`),Ce===xe&&we(null)},100),r=setTimeout(()=>Se(null),5e3);return()=>{clearTimeout(t),clearTimeout(r)}}},[xe,Ce,n,e]);let{data:Je,isLoading:Ye}=q({queryKey:[`archives`,c],queryFn:()=>Q.getArchives(c||void 0)}),{data:Xe}=q({queryKey:[`printers`],queryFn:Q.getPrinters}),{data:Ze}=q({queryKey:[`projects`],queryFn:()=>Q.getProjects()}),{data:Qe}=q({queryKey:[`settings`],queryFn:Q.getSettings}),{data:$e}=q({queryKey:[`users`],queryFn:Q.getUsers,enabled:re===`log`}),{data:et,isLoading:tt}=q({queryKey:[`print-log`,c,Te,De,ke,je,o,Ne,Ge],queryFn:()=>Q.getPrintLog({search:o||void 0,printerId:c||void 0,username:Te||void 0,status:De||void 0,dateFrom:ke||void 0,dateTo:je||void 0,limit:Ge,offset:Ne}),enabled:re===`log`}),nt=Qe?.time_format||`system`,rt=Qe?.open_in_slicer||Qe?.preferred_slicer||`bambu_studio`,it=Qe?.use_slicer_api??!1,at=$d(Qe?.currency||`USD`),ot=J({mutationFn:async e=>(await Promise.all(e.map(e=>Q.deleteArchive(e))),e.length),onSuccess:e=>{t.invalidateQueries({queryKey:[`archives`]}),M(new Set),n(`${e} archive${e===1?``:`s`} deleted`)},onError:()=>{n(e(`archives.toast.failedDeleteArchives`),`error`)}}),st=J({mutationFn:()=>Q.clearPrintLog(),onSuccess:r=>{t.invalidateQueries({queryKey:[`print-log`]}),Pe(0),n(e(`archives.log.cleared`,{count:r.deleted}))},onError:()=>{n(e(`archives.log.clearFailed`),`error`)}}),ct=J({mutationFn:e=>Q.deletePrintLogEntry(e),onSuccess:()=>{t.invalidateQueries({queryKey:[`print-log`]}),t.invalidateQueries({queryKey:[`archives-stats`]}),n(e(`archives.log.entryDeleted`))},onError:()=>{n(e(`archives.log.entryDeleteFailed`),`error`)}}),lt=J({mutationFn:({id:e,body:t})=>Q.updatePrintLogEntry(e,t),onSuccess:()=>{t.invalidateQueries({queryKey:[`print-log`]}),t.invalidateQueries({queryKey:[`archives-stats`]}),Be(null),n(e(`archives.log.entryUpdated`))},onError:()=>{n(e(`archives.log.entryUpdateFailed`),`error`)}});(0,y.useEffect)(()=>{c===null?localStorage.removeItem(`archiveFilterPrinter`):localStorage.setItem(`archiveFilterPrinter`,c.toString())},[c]),(0,y.useEffect)(()=>{u?localStorage.setItem(`archiveFilterMaterial`,u):localStorage.removeItem(`archiveFilterMaterial`)},[u]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveFilterColors`,JSON.stringify([...f]))},[f]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveColorFilterMode`,m)},[m]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveFilterFavorites`,g.toString())},[g]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveHideFailed`,v.toString())},[v]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveHideDuplicates`,x.toString())},[x]),(0,y.useEffect)(()=>{C?localStorage.setItem(`archiveFilterTag`,C):localStorage.removeItem(`archiveFilterTag`)},[C]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveFilterFileType`,T)},[T]),(0,y.useEffect)(()=>{ce(0)},[o,c,u,f,m,g,v,x,C,T,H,oe]),(0,y.useEffect)(()=>{try{localStorage.setItem(`archivePageSize`,String(le))}catch{}},[le]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveViewMode`,re)},[re]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveSortBy`,H)},[H]),(0,y.useEffect)(()=>{localStorage.setItem(`archiveCollection`,oe)},[oe]),(0,y.useEffect)(()=>{Te?localStorage.setItem(`logFilterUser`,Te):localStorage.removeItem(`logFilterUser`)},[Te]),(0,y.useEffect)(()=>{De?localStorage.setItem(`logFilterStatus`,De):localStorage.removeItem(`logFilterStatus`)},[De]),(0,y.useEffect)(()=>{ke?localStorage.setItem(`logFilterDateFrom`,ke):localStorage.removeItem(`logFilterDateFrom`)},[ke]),(0,y.useEffect)(()=>{je?localStorage.setItem(`logFilterDateTo`,je):localStorage.removeItem(`logFilterDateTo`)},[je]),(0,y.useEffect)(()=>{localStorage.setItem(`logOffset`,Ne.toString())},[Ne]),(0,y.useEffect)(()=>{localStorage.setItem(`logPageSize`,Ge.toString())},[Ge]);let ut=new Map(Xe?.map(e=>[e.id,e.name])||[]),dt=[...new Set(Je?.flatMap(e=>e.filament_type?.split(`, `)||[]).filter(Boolean)||[])].sort(),ft=[...new Set(Je?.flatMap(e=>e.filament_color?.split(`,`)||[]).filter(Boolean)||[])],pt=[...new Set(Je?.flatMap(e=>e.tags?.split(`,`).map(e=>e.trim())||[]).filter(Boolean)||[])].sort(),mt=Je?.filter(e=>{let t=new Date,n=vf(e.created_at)||new Date(0),r=!0;switch(oe){case`recent`:r=t.getTime()-n.getTime()<1440*60*1e3;break;case`this-week`:r=t.getTime()-n.getTime()<10080*60*1e3;break;case`this-month`:r=n.getMonth()===t.getMonth()&&n.getFullYear()===t.getFullYear();break;case`favorites`:r=e.is_favorite===!0;break;case`not-printed`:r=e.status===`archived`;break;case`printed`:r=ZRe.includes(e.status);break;case`failed`:r=e.status===`failed`||e.status===`aborted`;break;case`duplicates`:r=e.duplicate_count>0;break}let i=(e.print_name||e.filename).toLowerCase().includes(o.toLowerCase()),a=!u||e.filament_type?.split(`, `).includes(u),s=e.filament_color?.split(`,`)||[],c=f.size===0||(m===`or`?s.some(e=>f.has(e)):[...f].every(e=>s.includes(e))),l=oe===`favorites`||!g||e.is_favorite,d=oe===`failed`||!v||e.status!==`failed`&&e.status!==`aborted`,p=oe===`duplicates`||!x||e.duplicate_count===0||e.duplicate_sequence===0,h=e.tags?.split(`,`).map(e=>e.trim())||[],_=!C||h.includes(C),y=m2(e);return r&&i&&a&&c&&l&&d&&p&&_&&(T===`all`||T===`gcode`&&y||T===`source`&&!y)}).sort((e,t)=>{switch(H){case`date-desc`:return(vf(t.created_at)?.getTime()||0)-(vf(e.created_at)?.getTime()||0);case`date-asc`:return(vf(e.created_at)?.getTime()||0)-(vf(t.created_at)?.getTime()||0);case`name-asc`:return(e.print_name||e.filename).localeCompare(t.print_name||t.filename);case`name-desc`:return(t.print_name||t.filename).localeCompare(e.print_name||e.filename);case`size-desc`:return t.file_size-e.file_size;case`size-asc`:return e.file_size-t.file_size;default:return 0}}),ht=mt?.length||0,gt=le===-1,_t=gt?ht||1:le,vt=Math.max(1,Math.ceil(ht/_t)),yt=gt?mt:mt?.slice(se*_t,(se+1)*_t);(0,y.useEffect)(()=>{if(xe&&mt&&!gt){let e=mt.findIndex(e=>e.id===xe);if(e>=0){let t=Math.floor(e/_t);t!==se&&ce(t)}}},[xe]);let bt=L||j.size>0,xt=e=>{M(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},St=()=>{mt&&M(new Set(mt.map(e=>e.id)))},Ct=()=>{M(new Set),R(!1)},wt=e=>{p(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},Tt=()=>{p(new Set)},Et=()=>{s(``),l(null),d(null),_(!1),b(!1),S(!1),w(null),E(`all`)},Dt=o||c||u||g||v||x||C||T!==`all`,{isDraggingOver:Ot,dragHandlers:kt}=aG({disabled:D,extensions:[`.3mf`],onFiles:e=>{A(e),O(!0)},onRejected:()=>n(e(`archives.page.only3mfSupported`),`warning`)}),At=(0,y.useCallback)(e=>{let t=e.target;if(t.tagName===`INPUT`||t.tagName===`TEXTAREA`||t.isContentEditable){e.key===`Escape`&&t.blur();return}switch(e.key){case`/`:e.preventDefault(),a.current?.focus();break;case`u`:case`U`:!e.metaKey&&!e.ctrlKey&&(e.preventDefault(),O(!0));break;case`Escape`:bt&&Ct();break}},[bt]);return(0,y.useEffect)(()=>(document.addEventListener(`keydown`,At),()=>document.removeEventListener(`keydown`,At)),[At]),(0,K.jsxs)(`div`,{className:`p-4 md:p-8 relative`,...kt,children:[Ot&&(0,K.jsx)(`div`,{className:`fixed inset-0 z-50 bg-bambu-dark/90 flex items-center justify-center pointer-events-none`,children:(0,K.jsxs)(`div`,{className:`border-4 border-dashed border-bambu-green rounded-xl p-12 text-center`,children:[(0,K.jsx)(Eu,{className:`w-16 h-16 mx-auto mb-4 text-bambu-green`}),(0,K.jsx)(`p`,{className:`text-2xl font-semibold text-white mb-2`,children:e(`archives.page.dropFilesHere`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`archives.releaseToUpload`)})]})}),bt&&(0,K.jsxs)(`div`,{className:`fixed bottom-6 left-1/2 -translate-x-1/2 z-40 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-xl px-4 py-3 flex items-center gap-4`,children:[(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:Ct,children:[(0,K.jsx)(Ru,{className:`w-4 h-4`}),`Close`]}),(0,K.jsx)(`div`,{className:`w-px h-6 bg-bambu-dark-tertiary`}),(0,K.jsxs)(`span`,{className:`text-white font-medium`,children:[j.size,` selected`]}),(0,K.jsx)(`div`,{className:`w-px h-6 bg-bambu-dark-tertiary`}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:St,children:`Select All`}),(0,K.jsx)(`div`,{className:`w-px h-6 bg-bambu-dark-tertiary`}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>ee(!0),disabled:!i(`archives:update_own`,`archives:update_all`),title:i(`archives:update_own`,`archives:update_all`)?void 0:e(`archives.permission.noUpdateArchives`),children:[(0,K.jsx)(du,{className:`w-4 h-4`}),`Tags`]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>ne(!0),disabled:!i(`archives:update_own`,`archives:update_all`),title:i(`archives:update_own`,`archives:update_all`)?void 0:e(`archives.permission.noUpdateArchives`),children:[(0,K.jsx)(oc,{className:`w-4 h-4`}),`Project`]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,disabled:!i(`archives:update_own`,`archives:update_all`),title:i(`archives:update_own`,`archives:update_all`)?void 0:e(`archives.permission.noUpdateArchives`),onClick:()=>{let r=Array.from(j);Promise.all(r.map(e=>Q.toggleFavorite(e))).then(()=>{t.invalidateQueries({queryKey:[`archives`]}),n(`Toggled favorites for ${r.length} archive${r.length===1?``:`s`}`)}).catch(()=>{n(e(`archives.toast.failedUpdateFavorites`),`error`)})},children:[(0,K.jsx)(ou,{className:`w-4 h-4`}),`Favorite`]}),(0,K.jsxs)($,{size:`sm`,className:`bg-red-500 hover:bg-red-600`,onClick:()=>B(!0),disabled:!i(`archives:delete_own`,`archives:delete_all`),title:i(`archives:delete_own`,`archives:delete_all`)?void 0:e(`archives.permission.noDelete`),children:[(0,K.jsx)(yu,{className:`w-4 h-4`}),`Delete`]})]}),F?.has_fallback&&!N&&(0,K.jsxs)(`div`,{className:`mb-6 rounded-lg border border-amber-500/30 bg-amber-500/10 px-4 py-3 flex items-start gap-3`,children:[(0,K.jsx)(ds,{className:`w-5 h-5 text-amber-400 flex-shrink-0 mt-0.5`}),(0,K.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,K.jsx)(`div`,{className:`text-sm font-medium text-amber-200`,children:e(`archives.no3mfBanner.title`)}),(0,K.jsxs)(`div`,{className:`text-xs text-amber-200/80 mt-1`,children:[e(`archives.no3mfBanner.body`),` `,(0,K.jsxs)(`a`,{href:`https://wiki.bambuddy.cool/getting-started/#step-4-enable-store-sent-files-on-external-storage`,target:`_blank`,rel:`noreferrer`,className:`underline hover:text-amber-100 inline-flex items-center gap-1`,children:[e(`archives.no3mfBanner.docsLink`),(0,K.jsx)(qs,{className:`w-3 h-3`})]})]})]}),(0,K.jsx)(`button`,{onClick:I,className:`text-amber-200/60 hover:text-amber-200 flex-shrink-0 p-1 -m-1`,title:e(`archives.no3mfBanner.dismissLabel`),"aria-label":e(`archives.no3mfBanner.dismissLabel`),children:(0,K.jsx)(Ru,{className:`w-4 h-4`})})]}),(0,K.jsxs)(`div`,{className:`flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-8`,children:[(0,K.jsx)(`div`,{children:(0,K.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`h1`,{className:`text-2xl font-bold text-white flex items-center gap-3`,children:[(0,K.jsx)(Oo,{className:`w-7 h-7 text-bambu-green`}),`Archives`]}),(0,K.jsxs)(`p`,{className:`text-bambu-gray mt-1`,children:[mt?.length||0,` of `,Je?.length||0,` prints`]})]}),(0,K.jsx)(`select`,{className:`mt-0.5 px-3 py-1.5 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-bambu-gray-light text-sm focus:border-bambu-green focus:outline-none`,value:oe,onChange:e=>U(e.target.value),children:QRe.map(e=>(0,K.jsx)(`option`,{value:e.id,children:e.label},e.id))})]})}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 sm:gap-3 flex-wrap`,children:[(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsxs)($,{variant:`secondary`,onClick:()=>fe(!de),disabled:pe,children:[pe?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(ec,{className:`w-4 h-4`}),`Export`]}),de&&(0,K.jsxs)(`div`,{className:`absolute right-0 top-full mt-1 w-48 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-xl z-20`,children:[(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-white hover:bg-bambu-dark-tertiary transition-colors flex items-center gap-2 rounded-t-lg`,onClick:async()=>{fe(!1),me(!0);try{let{blob:t,filename:r}=await Q.exportArchives({format:`csv`,printerId:c||void 0,status:oe===`failed`?`failed`:void 0,search:o||void 0}),i=URL.createObjectURL(t),a=document.createElement(`a`);a.href=i,a.download=r,a.click(),URL.revokeObjectURL(i),n(e(`archives.toast.exportDownloaded`))}catch{n(e(`archives.toast.exportFailed`),`error`)}finally{me(!1)}},children:[(0,K.jsx)(tc,{className:`w-4 h-4`}),`Export as CSV`]}),(0,K.jsxs)(`button`,{className:`w-full px-4 py-2 text-left text-white hover:bg-bambu-dark-tertiary transition-colors flex items-center gap-2 rounded-b-lg`,onClick:async()=>{fe(!1),me(!0);try{let{blob:t,filename:r}=await Q.exportArchives({format:`xlsx`,printerId:c||void 0,status:oe===`failed`?`failed`:void 0,search:o||void 0}),i=URL.createObjectURL(t),a=document.createElement(`a`);a.href=i,a.download=r,a.click(),URL.revokeObjectURL(i),n(e(`archives.toast.exportDownloaded`))}catch{n(e(`archives.toast.exportFailed`),`error`)}finally{me(!1)}},children:[(0,K.jsx)(ec,{className:`w-4 h-4`}),`Export as Excel`]})]})]}),j.size>=2&&j.size<=5&&(0,K.jsxs)($,{variant:`secondary`,onClick:()=>ge(!0),children:[(0,K.jsx)(_c,{className:`w-4 h-4`}),`Compare (`,j.size,`)`]}),!bt&&(0,K.jsxs)($,{variant:`secondary`,onClick:()=>R(!0),children:[(0,K.jsx)(ru,{className:`w-4 h-4`}),`Select`]}),(0,K.jsxs)($,{onClick:()=>O(!0),disabled:!r(`archives:create`),title:r(`archives:create`)?void 0:e(`archives.permission.noCreate`),children:[(0,K.jsx)(Eu,{className:`w-4 h-4`}),`Upload 3MF`]}),r(`archives:purge`)&&(0,K.jsxs)($,{variant:`secondary`,onClick:()=>be(!0),title:e(`archivePurge.headerTooltip`),children:[(0,K.jsx)(yu,{className:`w-4 h-4 mr-2`}),e(`archivePurge.headerButton`)]})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center border border-bambu-dark-tertiary rounded-lg overflow-hidden flex-shrink-0 w-fit mb-4`,children:[(0,K.jsx)(`button`,{className:`p-2 ${re===`grid`?`bg-bambu-green text-white`:`bg-bambu-dark text-bambu-gray hover:text-white`}`,onClick:()=>ie(`grid`),title:e(`archives.gridView`),children:(0,K.jsx)(Rc,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{className:`p-2 ${re===`list`?`bg-bambu-green text-white`:`bg-bambu-dark text-bambu-gray hover:text-white`}`,onClick:()=>ie(`list`),title:e(`archives.listView`),children:(0,K.jsx)(Wc,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{className:`p-2 ${re===`calendar`?`bg-bambu-green text-white`:`bg-bambu-dark text-bambu-gray hover:text-white`}`,onClick:()=>ie(`calendar`),title:e(`archives.calendarView`),children:(0,K.jsx)(Yo,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{className:`p-2 ${re===`log`?`bg-bambu-green text-white`:`bg-bambu-dark text-bambu-gray hover:text-white`}`,onClick:()=>ie(`log`),title:e(`archives.logView`),children:(0,K.jsx)(bs,{className:`w-4 h-4`})})]}),re!==`log`&&(0,K.jsx)(_d,{className:`mb-6`,children:(0,K.jsxs)(yd,{className:`py-4`,children:[(0,K.jsxs)(`div`,{className:`flex flex-col md:flex-row gap-3 md:gap-4 md:items-center md:flex-wrap`,children:[(0,K.jsxs)(`div`,{className:`w-full md:flex-1 relative md:min-w-[200px]`,children:[(0,K.jsx)(Ll,{className:`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray`}),(0,K.jsx)(`input`,{ref:a,type:`text`,placeholder:e(`archives.searchPlaceholder`),className:`w-full pl-10 pr-4 py-3 md:py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,value:o,onChange:e=>s(e.target.value)})]}),(0,K.jsxs)(`div`,{className:`flex gap-2 md:gap-4 overflow-x-auto pb-1 md:pb-0 -mx-4 px-4 md:mx-0 md:px-0 md:flex-wrap scrollbar-hide`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 flex-shrink-0`,children:[(0,K.jsx)(pc,{className:`w-4 h-4 text-bambu-gray hidden md:block`}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,value:c||``,onChange:e=>l(e.target.value?Number(e.target.value):null),children:[(0,K.jsx)(`option`,{value:``,children:`All Printers`}),Xe?.map(e=>(0,K.jsx)(`option`,{value:e.id,children:e.name},e.id))]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 flex-shrink-0`,children:[(0,K.jsx)(fl,{className:`w-4 h-4 text-bambu-gray hidden md:block`}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,value:u||``,onChange:e=>d(e.target.value||null),children:[(0,K.jsx)(`option`,{value:``,children:`All Materials`}),dt.map(e=>(0,K.jsx)(`option`,{value:e,children:e},e))]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 flex-shrink-0`,children:[(0,K.jsx)(Qs,{className:`w-4 h-4 text-bambu-gray hidden md:block`}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,value:T,onChange:e=>E(e.target.value),children:[(0,K.jsx)(`option`,{value:`all`,children:`All Files`}),(0,K.jsx)(`option`,{value:`gcode`,children:`Sliced (GCODE)`}),(0,K.jsx)(`option`,{value:`source`,children:`Source Only`})]})]}),(0,K.jsxs)(`button`,{onClick:()=>_(!g),className:`flex items-center gap-2 px-3 py-2 rounded-lg border transition-colors flex-shrink-0 ${g?`bg-yellow-500/20 border-yellow-500 text-yellow-400`:`bg-bambu-dark border-bambu-dark-tertiary text-bambu-gray hover:text-white`}`,title:e(g?`archives.showAll`:`archives.showFavoritesOnly`),children:[(0,K.jsx)(ou,{className:`w-4 h-4 ${g?`fill-yellow-400`:``}`}),(0,K.jsx)(`span`,{className:`text-sm hidden md:inline`,children:`Favorites`})]}),(0,K.jsxs)(`button`,{onClick:()=>b(!v),className:`flex items-center gap-2 px-3 py-2 rounded-lg border transition-colors flex-shrink-0 ${v?`bg-red-500/20 border-red-500 text-red-400`:`bg-bambu-dark border-bambu-dark-tertiary text-bambu-gray hover:text-white`}`,title:e(v?`archives.showFailedPrints`:`archives.hideFailedPrints`),children:[(0,K.jsx)(ds,{className:`w-4 h-4 `}),(0,K.jsx)(`span`,{className:`text-sm hidden md:inline`,children:`Hide Failed`})]}),(0,K.jsxs)(`button`,{onClick:()=>S(!x),className:`flex items-center gap-2 px-3 py-2 rounded-lg border transition-colors flex-shrink-0 ${x?`bg-purple-500/20 border-purple-500 text-purple-400`:`bg-bambu-dark border-bambu-dark-tertiary text-bambu-gray hover:text-white`}`,title:e(`archives.hideDuplicates`),children:[(0,K.jsx)(js,{className:`w-4 h-4`}),(0,K.jsx)(`span`,{className:`text-sm hidden md:inline`,children:e(`archives.hideDuplicates`)})]}),pt.length>0&&(0,K.jsxs)(`div`,{className:`flex items-center gap-2 flex-shrink-0`,children:[(0,K.jsx)(du,{className:`w-4 h-4 text-bambu-gray hidden md:block`}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,value:C||``,onChange:e=>w(e.target.value||null),children:[(0,K.jsx)(`option`,{value:``,children:`All Tags`}),pt.map(e=>(0,K.jsx)(`option`,{value:e,children:e},e))]}),(0,K.jsx)(`button`,{onClick:()=>ve(!0),className:`p-2 rounded-lg bg-bambu-dark border border-bambu-dark-tertiary text-bambu-gray hover:text-white hover:border-bambu-green transition-colors`,title:e(`archives.manageTags`),children:(0,K.jsx)(Hl,{className:`w-4 h-4`})})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 flex-shrink-0`,children:[(0,K.jsx)(Po,{className:`w-4 h-4 text-bambu-gray hidden md:block`}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,value:H,onChange:e=>ae(e.target.value),children:[(0,K.jsx)(`option`,{value:`date-desc`,children:e(`archives.sortNewest`)}),(0,K.jsx)(`option`,{value:`date-asc`,children:e(`archives.sortOldest`)}),(0,K.jsxs)(`option`,{value:`name-asc`,children:[e(`archives.sortName`),` A-Z`]}),(0,K.jsxs)(`option`,{value:`name-desc`,children:[e(`archives.sortName`),` Z-A`]}),(0,K.jsx)(`option`,{value:`size-desc`,children:e(`archives.sortLargest`)}),(0,K.jsx)(`option`,{value:`size-asc`,children:e(`archives.sortSmallest`)})]})]})]}),Dt&&(0,K.jsxs)($,{variant:`ghost`,size:`sm`,onClick:Et,className:`text-bambu-gray hover:text-white`,children:[(0,K.jsx)(Ru,{className:`w-4 h-4`}),`Reset`]})]}),ft.length>0&&(0,K.jsxs)(`div`,{className:`flex items-center gap-3 mt-4 pt-4 border-t border-bambu-dark-tertiary`,children:[(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray`,children:`Colors:`}),f.size>1&&(0,K.jsx)(`button`,{onClick:()=>h(e=>e===`or`?`and`:`or`),className:`px-2 py-0.5 text-xs rounded transition-colors ${m===`and`?`bg-bambu-green text-white`:`bg-bambu-dark-tertiary text-bambu-gray hover:text-white`}`,title:m===`or`?`Match ANY selected color`:`Match ALL selected colors`,children:m.toUpperCase()}),(0,K.jsx)(`div`,{className:`flex items-center gap-1.5 flex-wrap`,children:ft.map(e=>(0,K.jsx)(`button`,{onClick:()=>wt(e),className:`w-6 h-6 rounded-full border-2 transition-all ${f.has(e)?`border-bambu-green scale-110`:`border-white/20 hover:border-white/40`}`,style:{backgroundColor:e},title:e},e))}),f.size>0&&(0,K.jsxs)(`button`,{onClick:Tt,className:`text-xs text-bambu-gray hover:text-white flex items-center gap-1`,children:[(0,K.jsx)(Ru,{className:`w-3 h-3`}),`Clear`]})]})]})}),(0,K.jsx)(qRe,{}),Ye?(0,K.jsx)(`div`,{className:`text-center py-12 text-bambu-gray`,children:e(`archives.loadingArchives`)}):mt?.length===0?(0,K.jsx)(_d,{children:(0,K.jsxs)(yd,{className:`text-center py-12`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(o?`archives.noArchivesSearch`:`archives.noArchivesYet`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-2`,children:`Archives are created automatically when prints complete`})]})}):re===`calendar`?(0,K.jsx)(_d,{className:`p-6`,children:(0,K.jsx)(aAe,{archives:mt||[],onArchiveClick:e=>{s(``),ie(`grid`),Se(e.id)},highlightedArchiveId:xe})}):re===`grid`?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6`,children:yt?.map(t=>(0,K.jsx)(YRe,{archive:t,printerName:t.printer_id?ut.get(t.printer_id)||`Unknown`:t.sliced_for_model||`No Printer`,isSelected:j.has(t.id),onSelect:xt,selectionMode:bt,projects:Ze,isHighlighted:t.id===xe,timeFormat:nt,preferredSlicer:rt,useSlicerApi:it,currency:at,t:e,onNavigateToArchive:qe},t.id))}),(0,K.jsx)(g2,{pageIndex:se,pageSize:le,totalRows:ht,totalPages:vt,onPageChange:ce,onPageSizeChange:e=>{ue(e),ce(0)},t:e})]}):re===`list`?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(_d,{children:(0,K.jsxs)(`div`,{className:`divide-y divide-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{className:`grid grid-cols-12 gap-4 px-4 py-3 text-xs text-bambu-gray font-medium`,children:[(0,K.jsx)(`div`,{className:`col-span-1`}),(0,K.jsx)(`div`,{className:`col-span-4`,children:`Name`}),(0,K.jsx)(`div`,{className:`col-span-2`,children:`Printer`}),(0,K.jsx)(`div`,{className:`col-span-2`,children:`Date`}),(0,K.jsx)(`div`,{className:`col-span-1`,children:`Size`}),(0,K.jsx)(`div`,{className:`col-span-2 text-right`,children:`Actions`})]}),yt?.map(t=>(0,K.jsx)(XRe,{archive:t,printerName:t.printer_id?ut.get(t.printer_id)||`Unknown`:t.sliced_for_model||`No Printer`,isSelected:j.has(t.id),onSelect:xt,selectionMode:bt,projects:Ze,isHighlighted:t.id===xe,preferredSlicer:rt,useSlicerApi:it,t:e,onNavigateToArchive:qe},t.id))]})}),(0,K.jsx)(g2,{pageIndex:se,pageSize:le,totalRows:ht,totalPages:vt,onPageChange:ce,onPageSizeChange:e=>{ue(e),ce(0)},t:e})]}):re===`log`?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(_d,{children:(0,K.jsx)(yd,{className:`py-3`,children:(0,K.jsxs)(`div`,{className:`flex flex-col md:flex-row gap-3 md:items-center md:flex-wrap`,children:[(0,K.jsxs)(`div`,{className:`flex-1 relative md:min-w-[200px]`,children:[(0,K.jsx)(Ll,{className:`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray`}),(0,K.jsx)(`input`,{type:`text`,placeholder:e(`archives.searchPlaceholder`),className:`w-full pl-10 pr-4 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none text-sm`,value:o,onChange:e=>{s(e.target.value),Pe(0)}})]}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none text-sm`,value:c||``,onChange:e=>{l(e.target.value?Number(e.target.value):null),Pe(0)},children:[(0,K.jsx)(`option`,{value:``,children:e(`archives.log.allPrinters`)}),Xe?.map(e=>(0,K.jsx)(`option`,{value:e.id,children:e.name},e.id))]}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none text-sm`,value:Te||``,onChange:e=>{Ee(e.target.value||null),Pe(0)},children:[(0,K.jsx)(`option`,{value:``,children:e(`archives.log.allUsers`)}),$e?.map(e=>(0,K.jsx)(`option`,{value:e.username,children:e.username},e.id))]}),(0,K.jsxs)(`select`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none text-sm`,value:De||``,onChange:e=>{Oe(e.target.value||null),Pe(0)},children:[(0,K.jsx)(`option`,{value:``,children:e(`archives.log.allStatuses`)}),(0,K.jsx)(`option`,{value:`completed`,children:e(`archives.status.completed`)}),(0,K.jsx)(`option`,{value:`failed`,children:e(`archives.status.failed`)}),(0,K.jsx)(`option`,{value:`stopped`,children:e(`archives.status.stopped`)}),(0,K.jsx)(`option`,{value:`cancelled`,children:e(`archives.log.cancelled`)}),(0,K.jsx)(`option`,{value:`skipped`,children:e(`archives.log.skipped`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`label`,{className:`text-sm text-bambu-gray`,children:e(`archives.log.dateFrom`)}),(0,K.jsx)(`input`,{type:`date`,className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none text-sm`,value:ke,onChange:e=>{Ae(e.target.value),Pe(0)}})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`label`,{className:`text-sm text-bambu-gray`,children:e(`archives.log.dateTo`)}),(0,K.jsx)(`input`,{type:`date`,className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none text-sm`,value:je,onChange:e=>{Me(e.target.value),Pe(0)}})]}),(0,K.jsx)(`div`,{className:`ml-auto`,children:(0,K.jsxs)($,{variant:`danger`,size:`sm`,onClick:()=>Ie(!0),disabled:!r(`archives:delete_all`)||st.isPending,children:[(0,K.jsx)(yu,{className:`w-4 h-4`}),e(`archives.log.clearLog`)]})})]})})}),(0,K.jsx)(_d,{children:tt?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-12`,children:(0,K.jsx)(X,{className:`w-6 h-6 animate-spin text-bambu-green`})}):et?.items.length?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`div`,{className:`overflow-x-auto`,children:(0,K.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,K.jsx)(`thead`,{children:(0,K.jsxs)(`tr`,{className:`border-b border-bambu-dark-tertiary text-bambu-gray text-left`,children:[(0,K.jsx)(`th`,{className:`px-4 py-3 font-medium`,children:e(`archives.log.date`)}),(0,K.jsx)(`th`,{className:`px-4 py-3 font-medium`,children:e(`archives.log.printName`)}),(0,K.jsx)(`th`,{className:`px-4 py-3 font-medium`,children:e(`archives.log.printer`)}),(0,K.jsx)(`th`,{className:`px-4 py-3 font-medium`,children:e(`archives.log.user`)}),(0,K.jsx)(`th`,{className:`px-4 py-3 font-medium`,children:e(`archives.log.status`)}),(0,K.jsx)(`th`,{className:`px-4 py-3 font-medium`,children:e(`archives.log.duration`)}),(0,K.jsx)(`th`,{className:`px-4 py-3 font-medium`,children:e(`archives.log.filament`)}),(0,K.jsx)(`th`,{className:`px-4 py-3 font-medium w-10`,"aria-label":e(`common.actions`)})]})}),(0,K.jsx)(`tbody`,{className:`divide-y divide-bambu-dark-tertiary`,children:et.items.map(t=>(0,K.jsxs)(`tr`,{className:`hover:bg-bambu-dark-secondary/50`,children:[(0,K.jsx)(`td`,{className:`px-4 py-3 text-white whitespace-nowrap`,children:bf(t.started_at||t.created_at,nt)}),(0,K.jsx)(`td`,{className:`px-4 py-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[t.thumbnail_path&&(0,K.jsx)(`img`,{src:Q.getPrintLogThumbnail(t.id),alt:``,className:`w-8 h-8 rounded object-cover flex-shrink-0`,onError:e=>{e.target.style.display=`none`}}),(0,K.jsx)(`span`,{className:`text-white break-words`,title:t.print_name||``,children:t.print_name||`—`})]})}),(0,K.jsx)(`td`,{className:`px-4 py-3 text-bambu-gray-light`,children:t.printer_name||`—`}),(0,K.jsx)(`td`,{className:`px-4 py-3 text-bambu-gray-light`,children:t.created_by_username||`—`}),(0,K.jsxs)(`td`,{className:`px-4 py-3`,children:[(0,K.jsx)(`span`,{className:`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ${t.status===`completed`?`bg-green-500/20 text-green-400`:t.status===`failed`?`bg-red-500/20 text-red-400`:t.status===`stopped`?`bg-yellow-500/20 text-yellow-400`:t.status===`cancelled`?`bg-orange-500/20 text-orange-400`:t.status===`skipped`?`bg-blue-500/20 text-blue-400`:`bg-gray-500/20 text-gray-400`}`,children:t.status}),t.failure_reason&&(0,K.jsx)(`span`,{className:`block text-[10px] text-bambu-gray mt-0.5`,children:e(`editArchive.failureReasons.${t.failure_reason}`,{defaultValue:t.failure_reason})})]}),(0,K.jsx)(`td`,{className:`px-4 py-3 text-bambu-gray-light whitespace-nowrap`,children:t.duration_seconds?Cf(t.duration_seconds):`—`}),(0,K.jsx)(`td`,{className:`px-4 py-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[t.filament_color&&(0,K.jsx)(`div`,{className:`flex items-center gap-0.5 flex-wrap`,children:t.filament_color.split(`,`).map((e,t)=>{let n=e.trim();return(0,K.jsx)(`span`,{className:`w-3 h-3 rounded-full border border-black/20 flex-shrink-0`,style:{backgroundColor:n.startsWith(`#`)?n:void 0},title:n},t)})}),(0,K.jsx)(`span`,{className:`text-bambu-gray-light text-xs`,children:t.filament_type||`—`})]})}),(0,K.jsx)(`td`,{className:`px-4 py-3 text-right`,children:(0,K.jsxs)(`div`,{className:`inline-flex items-center gap-2`,children:[(0,K.jsx)(`button`,{type:`button`,onClick:()=>{Be(t),He(t.failure_reason||``),We(t.status)},disabled:lt.isPending||!(r(`archives:update_all`)||r(`archives:update_own`)),title:r(`archives:update_all`)||r(`archives:update_own`)?e(`archives.log.editEntryTitle`):e(`archives.permission.noEdit`),className:`text-bambu-gray hover:text-bambu-blue disabled:opacity-40 disabled:hover:text-bambu-gray transition-colors`,children:(0,K.jsx)(_l,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>Re(t.id),disabled:ct.isPending||!(r(`archives:delete_all`)||r(`archives:delete_own`)),title:r(`archives:delete_all`)||r(`archives:delete_own`)?e(`archives.log.deleteEntryTitle`):e(`archives.permission.noDelete`),className:`text-bambu-gray hover:text-red-400 disabled:opacity-40 disabled:hover:text-bambu-gray transition-colors`,children:(0,K.jsx)(yu,{className:`w-4 h-4`})})]})})]},t.id))})]})}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between px-4 py-3 border-t border-bambu-dark-tertiary flex-wrap gap-2`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(`span`,{className:`text-sm text-bambu-gray`,children:e(`archives.log.showing`,{count:Math.min(Ne+Ge,et.total),total:et.total})}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,K.jsx)(`label`,{className:`text-xs text-bambu-gray`,children:e(`archives.log.rowsPerPage`)}),(0,K.jsxs)(`select`,{className:`px-2 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-xs focus:border-bambu-green focus:outline-none`,value:Ge,onChange:e=>{Ke(Number(e.target.value)),Pe(0)},children:[(0,K.jsx)(`option`,{value:10,children:`10`}),(0,K.jsx)(`option`,{value:25,children:`25`}),(0,K.jsx)(`option`,{value:50,children:`50`}),(0,K.jsx)(`option`,{value:100,children:`100`})]})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsxs)(`span`,{className:`text-sm text-bambu-gray`,children:[e(`archives.log.page`),` `,Math.floor(Ne/Ge)+1,` / `,Math.max(1,Math.ceil(et.total/Ge))]}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>Pe(Math.max(0,Ne-Ge)),disabled:Ne===0,children:(0,K.jsx)(ss,{className:`w-4 h-4`})}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>Pe(Ne+Ge),disabled:Ne+Ge>=et.total,children:(0,K.jsx)(as,{className:`w-4 h-4`})})]})]})]}):(0,K.jsx)(`div`,{className:`text-center py-12 text-bambu-gray`,children:e(`archives.log.noEntries`)})})]}):null,D&&(0,K.jsx)(Kke,{onClose:()=>{O(!1),A([])},initialFiles:k}),ye&&(0,K.jsx)(Jke,{onClose:()=>be(!1)}),z&&(0,K.jsx)(Ad,{title:e(`archives.modal.deleteArchives`),message:e(`archives.modal.deleteArchivesConfirm`,{count:j.size}),confirmText:e(`archives.modal.deleteCount`,{count:j.size}),variant:`danger`,onConfirm:()=>{ot.mutate(Array.from(j)),B(!1)},onCancel:()=>B(!1)}),V&&(0,K.jsx)($ke,{selectedIds:Array.from(j),existingTags:pt,onClose:()=>ee(!1)}),te&&(0,K.jsx)(eAe,{selectedIds:Array.from(j),onClose:()=>ne(!1)}),he&&j.size>=2&&j.size<=5&&(0,K.jsx)(URe,{archiveIds:Array.from(j),onClose:()=>{ge(!1),M(new Set),R(!1)}}),_e&&(0,K.jsx)(JRe,{onClose:()=>ve(!1)}),Fe&&(0,K.jsx)(Ad,{title:e(`archives.log.clearLogTitle`),message:e(`archives.log.clearLogConfirm`),confirmText:e(`archives.log.clearLogButton`),variant:`danger`,onConfirm:()=>{st.mutate(),Ie(!1)},onCancel:()=>Ie(!1)}),Le!==null&&(0,K.jsx)(Ad,{title:e(`archives.log.deleteEntryTitle`),message:e(`archives.log.deleteEntryConfirm`),confirmText:e(`common.delete`),variant:`danger`,onConfirm:()=>{ct.mutate(Le),Re(null)},onCancel:()=>Re(null)}),ze!==null&&(0,K.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm`,onClick:()=>Be(null),children:(0,K.jsxs)(`div`,{className:`bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg w-full max-w-md mx-4 p-6`,onClick:e=>e.stopPropagation(),children:[(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white mb-4`,children:e(`archives.log.editEntryTitle`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mb-4`,children:e(`archives.log.editEntryDescription`)}),(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:e(`editArchive.status`)}),(0,K.jsxs)(`select`,{value:Ue,onChange:e=>We(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`completed`,children:e(`archives.log.statuses.completed`,{defaultValue:`completed`})}),(0,K.jsx)(`option`,{value:`failed`,children:e(`archives.log.statuses.failed`,{defaultValue:`failed`})}),(0,K.jsx)(`option`,{value:`stopped`,children:e(`archives.log.statuses.stopped`,{defaultValue:`stopped`})}),(0,K.jsx)(`option`,{value:`cancelled`,children:e(`archives.log.statuses.cancelled`,{defaultValue:`cancelled`})}),(0,K.jsx)(`option`,{value:`skipped`,children:e(`archives.log.statuses.skipped`,{defaultValue:`skipped`})})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:e(`editArchive.failureReason`)}),(0,K.jsxs)(`select`,{value:Ve,onChange:e=>He(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:``,children:e(`editArchive.selectReason`)}),sG.map(t=>(0,K.jsx)(`option`,{value:t,children:e(`editArchive.failureReasons.${t}`)},t))]})]})]}),(0,K.jsxs)(`div`,{className:`flex justify-end gap-2 mt-6`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>Be(null),children:e(`common.cancel`)}),(0,K.jsx)($,{variant:`primary`,onClick:()=>{let e={};if(Ve!==(ze.failure_reason||``)&&(e.failure_reason=Ve||null),Ue!==ze.status&&(e.status=Ue),Object.keys(e).length===0){Be(null);return}lt.mutate({id:ze.id,body:e})},disabled:lt.isPending,children:lt.isPending?e(`editArchive.saving`):e(`common.save`)})]})]})})]})}function g2({pageIndex:e,pageSize:t,totalRows:n,totalPages:r,onPageChange:i,onPageSizeChange:a,t:o}){let s=t===-1;if(r<=1&&!s)return null;let c=s?n||1:t;return(0,K.jsxs)(`div`,{className:`flex items-center justify-between pt-2 text-sm`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:s?`${n} ${o(`archives.prints`)}`:(0,K.jsxs)(K.Fragment,{children:[o(`archives.pagination.showing`),` `,e*c+1,` `,o(`archives.pagination.to`),` `,Math.min((e+1)*c,n),` `,o(`archives.pagination.of`),` `,n,` `,o(`archives.prints`)]})}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:o(`archives.pagination.show`)}),(0,K.jsxs)(`select`,{value:t,onChange:e=>a(Number(e.target.value)),className:`px-2 py-1 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded text-white text-sm focus:outline-none focus:border-bambu-green`,children:[[25,50,100,200].map(e=>(0,K.jsx)(`option`,{value:e,children:e},e)),(0,K.jsx)(`option`,{value:-1,children:o(`archives.pagination.all`)})]}),!s&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`button`,{onClick:()=>i(0),disabled:e===0,className:`p-1.5 rounded text-bambu-gray hover:text-white disabled:opacity-30 disabled:cursor-not-allowed transition-colors`,children:(0,K.jsx)(ls,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{onClick:()=>i(Math.max(0,e-1)),disabled:e===0,className:`p-1.5 rounded text-bambu-gray hover:text-white disabled:opacity-30 disabled:cursor-not-allowed transition-colors`,children:(0,K.jsx)(ss,{className:`w-4 h-4`})}),(0,K.jsxs)(`span`,{className:`text-bambu-gray px-2 whitespace-nowrap`,children:[o(`archives.pagination.page`),` `,e+1,` `,o(`archives.pagination.of`),` `,r]}),(0,K.jsx)(`button`,{onClick:()=>i(Math.min(r-1,e+1)),disabled:e>=r-1,className:`p-1.5 rounded text-bambu-gray hover:text-white disabled:opacity-30 disabled:cursor-not-allowed transition-colors`,children:(0,K.jsx)(as,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{onClick:()=>i(r-1),disabled:e>=r-1,className:`p-1.5 rounded text-bambu-gray hover:text-white disabled:opacity-30 disabled:cursor-not-allowed transition-colors`,children:(0,K.jsx)(us,{className:`w-4 h-4`})})]})]})]})}function eze(){var e=[...arguments];return(0,y.useMemo)(()=>t=>{e.forEach(e=>e(t))},e)}var _2=typeof window<`u`&&window.document!==void 0&&window.document.createElement!==void 0;function v2(e){let t=Object.prototype.toString.call(e);return t===`[object Window]`||t===`[object global]`}function y2(e){return`nodeType`in e}function b2(e){return e?v2(e)?e:y2(e)?e.ownerDocument?.defaultView??window:window:window}function x2(e){let{Document:t}=b2(e);return e instanceof t}function S2(e){return v2(e)?!1:e instanceof b2(e).HTMLElement}function C2(e){return e instanceof b2(e).SVGElement}function w2(e){return e?v2(e)?e.document:y2(e)?x2(e)?e:S2(e)||C2(e)?e.ownerDocument:document:document:document}var T2=_2?y.useLayoutEffect:y.useEffect;function E2(e){let t=(0,y.useRef)(e);return T2(()=>{t.current=e}),(0,y.useCallback)(function(){var e=[...arguments];return t.current==null?void 0:t.current(...e)},[])}function tze(){let e=(0,y.useRef)(null);return[(0,y.useCallback)((t,n)=>{e.current=setInterval(t,n)},[]),(0,y.useCallback)(()=>{e.current!==null&&(clearInterval(e.current),e.current=null)},[])]}function D2(e,t){t===void 0&&(t=[e]);let n=(0,y.useRef)(e);return T2(()=>{n.current!==e&&(n.current=e)},t),n}function O2(e,t){let n=(0,y.useRef)();return(0,y.useMemo)(()=>{let t=e(n.current);return n.current=t,t},[...t])}function k2(e){let t=E2(e),n=(0,y.useRef)(null);return[n,(0,y.useCallback)(e=>{e!==n.current&&t?.(e,n.current),n.current=e},[])]}function A2(e){let t=(0,y.useRef)();return(0,y.useEffect)(()=>{t.current=e},[e]),t.current}var j2={};function M2(e,t){return(0,y.useMemo)(()=>{if(t)return t;let n=j2[e]==null?0:j2[e]+1;return j2[e]=n,e+`-`+n},[e,t])}function N2(e){return function(t){return[...arguments].slice(1).reduce((t,n)=>{let r=Object.entries(n);for(let[n,i]of r){let r=t[n];r!=null&&(t[n]=r+e*i)}return t},{...t})}}var P2=N2(1),F2=N2(-1);function nze(e){return`clientX`in e&&`clientY`in e}function I2(e){if(!e)return!1;let{KeyboardEvent:t}=b2(e.target);return t&&e instanceof t}function rze(e){if(!e)return!1;let{TouchEvent:t}=b2(e.target);return t&&e instanceof t}function L2(e){if(rze(e)){if(e.touches&&e.touches.length){let{clientX:t,clientY:n}=e.touches[0];return{x:t,y:n}}else if(e.changedTouches&&e.changedTouches.length){let{clientX:t,clientY:n}=e.changedTouches[0];return{x:t,y:n}}}return nze(e)?{x:e.clientX,y:e.clientY}:null}var R2=Object.freeze({Translate:{toString(e){if(!e)return;let{x:t,y:n}=e;return`translate3d(`+(t?Math.round(t):0)+`px, `+(n?Math.round(n):0)+`px, 0)`}},Scale:{toString(e){if(!e)return;let{scaleX:t,scaleY:n}=e;return`scaleX(`+t+`) scaleY(`+n+`)`}},Transform:{toString(e){if(e)return[R2.Translate.toString(e),R2.Scale.toString(e)].join(` `)}},Transition:{toString(e){let{property:t,duration:n,easing:r}=e;return t+` `+n+`ms `+r}}}),z2=`a,frame,iframe,input:not([type=hidden]):not(:disabled),select:not(:disabled),textarea:not(:disabled),button:not(:disabled),*[tabindex]`;function ize(e){return e.matches(z2)?e:e.querySelector(z2)}var aze={display:`none`};function oze(e){let{id:t,value:n}=e;return y.createElement(`div`,{id:t,style:aze},n)}function sze(e){let{id:t,announcement:n,ariaLiveType:r=`assertive`}=e;return y.createElement(`div`,{id:t,style:{position:`fixed`,top:0,left:0,width:1,height:1,margin:-1,border:0,padding:0,overflow:`hidden`,clip:`rect(0 0 0 0)`,clipPath:`inset(100%)`,whiteSpace:`nowrap`},role:`status`,"aria-live":r,"aria-atomic":!0},n)}function cze(){let[e,t]=(0,y.useState)(``);return{announce:(0,y.useCallback)(e=>{e!=null&&t(e)},[]),announcement:e}}var B2=(0,y.createContext)(null);function lze(e){let t=(0,y.useContext)(B2);(0,y.useEffect)(()=>{if(!t)throw Error(`useDndMonitor must be used within a children of `);return t(e)},[e,t])}function uze(){let[e]=(0,y.useState)(()=>new Set),t=(0,y.useCallback)(t=>(e.add(t),()=>e.delete(t)),[e]);return[(0,y.useCallback)(t=>{let{type:n,event:r}=t;e.forEach(e=>e[n]?.call(e,r))},[e]),t]}var dze={draggable:` To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel. diff --git a/static/index.html b/static/index.html index cd51fabb2..47e9b3a8e 100644 --- a/static/index.html +++ b/static/index.html @@ -26,7 +26,7 @@ - + From 2fe9896917def99f7cd39d406cd3f1529f2c3d89 Mon Sep 17 00:00:00 2001 From: maziggy Date: Thu, 25 Jun 2026 09:00:57 +0200 Subject: [PATCH 2/5] =?UTF-8?q?=20=20fix(queue):=20close=20#1818=20?= =?UTF-8?q?=E2=80=94=20Resume=20after=20failure=20clears=20the=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Single failure on a printer with require_previous_success queue items permanently skipped every downstream + every new item — the _check_previous_success lookback always walked back to the original failed row (skipped is excluded from the lookback), and no code path could dismiss that failure. Three pieces: 1. PrintQueueItem.gate_acknowledged Boolean column (default False). SQLite/Postgres-safe ALTER, dialect-branched DEFAULT. 2. _check_previous_success skips rows where gate_acknowledged=True so acknowledged failures walk past the lookback. Fresh post-resume failures still gate independently. 3. POST /api/v1/queue/printer/{printer_id}/resume — gated on QUEUE_UPDATE_ALL — acknowledges failed/aborted items for that printer AND restores items where status='skipped' AND error_message='Previous print failed or was aborted' back to pending in one transaction. Returns {acknowledged, restored}. Frontend banner above the active Queue tab surfaces blocked printers, fires a warning-variant ConfirmModal, and shows a precise toast on success. --- CHANGELOG.md | 2 + backend/app/api/routes/print_queue.py | 58 +++ backend/app/core/database.py | 9 + backend/app/models/print_queue.py | 9 + backend/app/services/print_scheduler.py | 6 + .../tests/integration/test_print_queue_api.py | 244 +++++++++++++ .../tests/unit/test_check_previous_success.py | 48 ++- frontend/src/api/client.ts | 11 + frontend/src/i18n/locales/de.ts | 9 + frontend/src/i18n/locales/en.ts | 9 + frontend/src/i18n/locales/es.ts | 9 + frontend/src/i18n/locales/fr.ts | 9 + frontend/src/i18n/locales/it.ts | 9 + frontend/src/i18n/locales/ja.ts | 9 + frontend/src/i18n/locales/ko.ts | 9 + frontend/src/i18n/locales/pt-BR.ts | 9 + frontend/src/i18n/locales/tr.ts | 9 + frontend/src/i18n/locales/zh-CN.ts | 9 + frontend/src/i18n/locales/zh-TW.ts | 9 + frontend/src/pages/QueuePage.tsx | 111 ++++++ static/assets/index-DNsDLric.css | 2 + static/assets/index-Dteqqsyc.css | 2 - .../{index-C0VWlQxC.js => index-Nmah4kx-.js} | 334 +++++++++--------- static/index.html | 4 +- 24 files changed, 767 insertions(+), 172 deletions(-) create mode 100644 static/assets/index-DNsDLric.css delete mode 100644 static/assets/index-Dteqqsyc.css rename static/assets/{index-C0VWlQxC.js => index-Nmah4kx-.js} (67%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9797ca04f..c2577e806 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,8 @@ All notable changes to Bambuddy will be documented in this file. - **Per-printer Maintenance Mode toggle (#1476, requested by @IndividualGhost1905 / Ferdi SEVER)** — Operator-flipped "out of service" state per printer, surfaced as a wrench icon + amber pill on the card and a checkbox in the Edit Printer dialog. Requested for three real-world scenarios that all share the same shape: (1) parallel Bambuddy installs (dev + prod, primary + warm spare) where the printer rejects concurrent MQTT clients except one, leaving the others in a flicker-online state burning CPU and network; (2) printers under repair / awaiting spare parts that shouldn't accept queue jobs but should remain visible on the dashboard so they aren't forgotten; (3) temporary suspension during maintenance work. **What was already there, what was missing.** The backend field `Printer.is_active: bool` has shipped since the initial Bambuddy release — toggling it via `PATCH /printers/{id}` already disconnects MQTT (`printer_manager.disconnect_printer` at `printers.py:366`), stops the printer from being eligible for queue dispatch (`print_scheduler.py:520, 1588`, `print_queue.py:383`), excludes it from model-based filament lookups (`printers.py:197`), excludes it from metrics + diagnostic snapshots + scheduled-backup runs (`metrics.py:105`, `diagnostic_snapshot.py:126`, `github_backup.py:333`, `maintenance.py:457`), and is already honoured by PrinterSelector (filtered with a "show inactive" override, greyed + "(inactive)" label when shown). All three of Ferdi's use cases were structurally supported by `is_active` from day one. **The missing piece was UI exposure.** `grep is_active` on `PrintersPage.tsx` returned zero hits — no menu item, no edit field, no toggle. The only way to flip it was a direct API call. This change adds the surfaces that should have been there all along. **Card UI — replacement, not addition.** Per Ferdi-conversation feedback, the maintenance state replaces the print-status / cover-image container rather than stacking above it, so card heights stay identical across the grid: in expanded mode the same `` header renders an amber panel (wrench icon + "In Maintenance" + subtitle + Exit button) where the cover + progress would normally be; in compact mode a single amber pill replaces the progress bar. The header connection pill is also swapped — instead of the red "Offline" pill (which would be misleading because the disconnect is deliberate) the card shows an amber "Maintenance" pill, and the "Run Diagnostic" CTA is suppressed (that's reserved for involuntary offline triage). HMS / Queue / Firmware status pills are still gated by `status?.connected` so they fall away naturally with the MQTT disconnect. **Three entry points.** (1) Printer card three-dot overflow menu — `Enter maintenance mode` / `Exit maintenance mode` with a wrench icon, adjacent to the Edit and Reconnect actions. (2) Exit button inside the in-card amber panel, so a user noticing the card from across the room can flip back without opening the menu. (3) Checkbox in the EditPrinterModal — `Maintenance mode` with the same subtitle as the help line, so the toggle is discoverable from the edit dialog too (the checkbox is the inverse of `is_active` because the user-facing concept is "is this in maintenance" not "is it active"). **Mid-print safety prompt.** Entering maintenance mode on a printer in `RUNNING` / `PAUSE` state triggers a confirmation dialog before the toggle fires — disconnecting MQTT mid-print stops progress tracking + completion notifications for the in-flight job, which is usually NOT what the operator wants (they probably meant "after this print finishes"). Idle / FINISH / FAILED states skip the dialog and toggle directly. **What this does NOT change.** No backend change (`is_active` was already wired everywhere); no new permission (uses existing `printers:update`); no behaviour change for any other consumer (queue dispatch, scheduler, metrics, picker, backup — all already honoured `is_active`). The card stays visible on the Printers page (greyed temps/controls/fans below the amber banner) so the printer doesn't disappear from the operator's mental map — Ferdi explicitly wanted to remember it's there. Doesn't auto-pause Smart Plug logic or notification providers (would be a sensible follow-up if Ferdi asks; out of scope here to keep the diff bounded to "expose the existing gate"). The scheduled-maintenance dashboard at `/maintenance` (interval-tracked rod-cleaning / lube / belt tasks via the existing `MaintenanceHistory` and `PrinterMaintenance` models) is conceptually adjacent but operationally distinct — the dashboard tracks "this printer is due for cleaning"; Maintenance Mode tracks "this printer is currently out of service." A future "perform maintenance task → optionally enter maintenance mode while you do it" link is the natural connection but isn't wired here. **i18n.** Twelve new keys under `printers.maintenance.*` (title / subtitle / pillLabel / exitButton / menuEnter / menuExit / toastEntered / toastExited / confirmMidPrintTitle / confirmMidPrintMessage / editFieldLabel / editFieldHelp) — real translations in all 11 locales (de / en / es / fr / it / ja / ko / pt-BR / tr / zh-CN / zh-TW), parity 5228 leaves per locale, no English fallback. **Tests.** 4 new cases in `PrintersPage.test.tsx::'maintenance mode (#1476)'`: amber status panel renders with Exit button (and the regular "No active job" / "Ready to print" copy is absent — confirms the swap, not a stacked render); header pill swaps to amber Maintenance and the diagnostic CTA is suppressed; clicking Exit issues a `PATCH /printers/{id}` with `is_active: true`; active printers never show the maintenance panel. Existing test fixture (`mockPrinters`) got an explicit `is_active: true` to keep the existing 56 tests green on the new render path. **Type:** `PrinterCreate.is_active?: boolean` added to the TypeScript surface so the field flows cleanly through the existing `api.updatePrinter` helper. **Build + checks.** Full PrintersPage vitest 60/60 green; `npm run build` clean; ESLint clean; i18n parity 5228 × 11 locales green. ### Fixed +- **`require_previous_success` permanently blocked a printer's queue after one failure (#1818, reported by @jmassardo)** — Reporter scenario (P1S, farm-style queue): every queued job had "Only start if previous print succeeded" set; the first job failed (filament tangle / runout / clog); every subsequent job — including brand-new ones added after the printer was fixed and back online — was silently marked `skipped` with no path back. The only workaround was to delete each item and re-create it through PrintModal, impractical at farm scale. **Root cause** in `print_scheduler.py::_check_previous_success`: the lookback query returned the most recent terminal item in (`completed`, `failed`, `cancelled`, `aborted`) — `skipped` is intentionally excluded (#1667). Once the original failure landed, the lookback always walked back to that same failed item — every new skip is excluded from the lookback so it doesn't shift the window. With no code path to dismiss the originating failure, the gate stayed closed forever. "Clear Plate" only resolved the orthogonal plate-clear gate (`_is_printer_idle`); nothing in Bambuddy acknowledged a resolved failure. **Fix.** New `PrintQueueItem.gate_acknowledged: bool` column (default False). Postgres/SQLite-safe ALTER following the existing #1794 / stock-alert migration shape (`DEFAULT 0` on SQLite, `DEFAULT false` on Postgres). `_check_previous_success` adds `AND gate_acknowledged == False` to its lookback so acknowledged failures are walked past — back to whatever real predecessor came before, or to the no-predecessor-passes case. **New per-printer endpoint.** `POST /api/v1/queue/printer/{printer_id}/resume` (gated on `QUEUE_UPDATE_ALL`) does both halves of the resume in one atomic transaction: (1) `gate_acknowledged=True` on every failed/aborted item for that printer that's still gating; (2) flips items where `status='skipped' AND error_message='Previous print failed or was aborted'` back to `pending`, clears `error_message` + `completed_at`. Returns `{acknowledged, restored}` counts so the UI can render a precise toast. Per-printer scoped — a resume on printer A never touches printer B. Per-item acknowledgement is independent — a fresh failure AFTER a resume re-gates downstream items, so users don't silently steamroll past a new real problem. The endpoint is idempotent (second call after the first sees acknowledged=0, restored=0). Also intentionally narrow: skipped items whose `error_message` is something OTHER than the exact gate string (e.g. future skip reasons, manual UI skips) are left untouched — those encode different user intent. **Frontend.** Per-printer alert banner at the top of the Queue tab (above the layout / filter row) shown when a printer has at least one skipped item with the gate `error_message`. Banner is permission-gated on `queue:update_all` so viewers don't see a button they can't use. Each blocked printer gets its own row: an `AlertCircle` icon, a one-line "{printer} is blocked by a previous-print failure — N job(s) skipped" headline, a "Fix the printer issue, then resume to restore the skipped jobs and clear the gate." hint, and a "Resume after failure" button on the right that opens a warning-variant `ConfirmModal` with the printer name + count. Confirm fires the new mutation, invalidates `['queue']`, and shows a toast — "Resumed queue — N job(s) restored to pending". Banner disappears the moment the action lands. Visible on the active Queue tab regardless of layout (`position` or `printer`); History/Timeline tabs unchanged. **Backend tests** (12 new): 4 new `_check_previous_success` cases in `test_check_previous_success.py` covering acknowledged failure ignored, acknowledged aborted ignored, fresh failure after ack STILL gates (independence guarantee), acknowledged failure walks back to the prior completed predecessor. 7 new `TestResumeQueueAfterFailure` cases in `test_print_queue_api.py` covering unknown printer 404, clean-queue no-op, reporter's failed+N-skipped scenario, scoped to the requested printer only, aborted-status acknowledgement, narrow `error_message` filter (don't touch other skip reasons), second call is a no-op. Full backend `pytest -n 30`: 6398/6398 green, 75 s. `ruff check backend/` clean. **Frontend** — 1 new API client method (`resumeQueueAfterFailure`), parity check 5352 × 11 locales green (no English fallback). `npm run build` clean, `npm run lint` clean. **i18n.** 7 new keys (`queue.toast.resumedAfterFailure`, `queue.toast.resumeAfterFailureFailed`, `queue.resumeAfterFailure.banner` / `bannerHint` / `button` / `confirmTitle` / `confirmMessage`) translated in all 11 locales (de / en / es / fr / it / ja / ko / pt-BR / tr / zh-CN / zh-TW). **Scope.** No change to `_is_printer_idle` (Clear Plate stays orthogonal). No change to `#1667` `skipped`-excluded-from-lookback semantics — those are still load-bearing for the cancellation-cascade fix. No change to filament-deficit-skip path (different error_message → untouched). One legacy column carries a row state where `gate_acknowledged=True`; the column never gets written by anything except the resume endpoint, so it's effectively an opt-in row marker. No new permission — `QUEUE_UPDATE_ALL` already exists and is the appropriate scope for a printer-level operation that may affect items the user doesn't own. + - **Archives "Step 4" docs link 404'd (#1812, reported by @Spanholz)** — The Archives page's "Some prints couldn't be archived with thumbnails" amber banner linked to `https://bambuddy.cool/wiki/getting-started/#step-4-enable-store-sent-files-on-external-storage` — the wiki lives at the `wiki.bambuddy.cool` subdomain, not under `bambuddy.cool/wiki/`, so the link 404'd. Anchor was already correct (MkDocs slugifies the existing "Step 4: Enable Store sent files on external storage" heading to that exact id). Single-line fix in `frontend/src/pages/ArchivesPage.tsx:3271`; no i18n / no tests touched. - **Connection diagnostic reported false camera-port warning on A1 / A1 Mini / P1 (#1798, reported and fixed by @lesbass / Stefano Maffeis in #1799)** — The general Connection Diagnostic (`printer_diagnostic.py:124`) probed RTSPS port 322 unconditionally, even for printers that don't speak RTSP. A1, A1 Mini, and P1-family cameras use the chamber-image protocol on port 6000 — Bambuddy's live camera client already routes them there via `camera.py::get_camera_port(model)`. Result: a saved A1 Mini with a working live webcam still saw "Camera port (RTSPS 322) — Port 322 is unreachable" in the diagnostic, and overall status flipped to `warnings` for a healthy printer. Reporter confirmed: TCP probe from the container showed 6000 open, 322 refused; camera-specific diagnostic returned `protocol=chamber_image, port=6000, overall_status=ok`. **Fix.** The diagnostic now resolves the camera port via the same `get_camera_port()` the camera client uses (single source of truth — adding a new model in `camera.py` propagates here for free). Saved A1 / A1 Mini / P1 → probe 6000, render "Camera port (Chamber Image 6000)". Saved X1 / X2 / H2 / P2 → unchanged, still probe 322 / RTSPS. Pre-save Add-Printer diagnostic where the model isn't known yet falls back to 322 / RTSPS — same conservative default as before, so the Add-Printer flow doesn't regress for users on RTSP models. The diagnostic check id stays `port_rtsps` for backward compatibility with snapshot JSON consumers; the actual port / protocol now travel in `params` and the localized title and warn text interpolate `{{protocol}}` / `{{port}}`. **Frontend.** `ConnectionDiagnostic.tsx` interpolates the title (previously static) and merges defensive defaults (`{ protocol: 'RTSPS', port: 322, ...check.params }`) for `port_rtsps` so an older backend or cached response still renders sensibly. **i18n.** Title and warn strings updated in all 11 locales (en / de / es / fr / it / ja / ko / pt-BR / tr / zh-CN / zh-TW) to use `{{protocol}}` / `{{port}}` interpolation. `npm run check:i18n` clean. **Tests.** 2 new backend cases (A1 Mini → 6000 / Chamber Image with the 322 fallback closed asserting `port_rtsps=pass`; X1C → still probes 322 / RTSPS asserting the existing behavior is unchanged) and 1 new frontend case asserting the rendered "Camera port (Chamber Image 6000)" + "Port 6000 is unreachable" text. `_port_probe` defaults extended to include port 6000. Existing model-less tests unchanged — they go through the `printer.model is None` fallback path and still probe 322. diff --git a/backend/app/api/routes/print_queue.py b/backend/app/api/routes/print_queue.py index f2c9534a4..2e34f033e 100644 --- a/backend/app/api/routes/print_queue.py +++ b/backend/app/api/routes/print_queue.py @@ -1091,6 +1091,64 @@ async def reorder_queue( return {"message": f"Reordered {len(data.items)} items"} +@router.post("/printer/{printer_id}/resume") +async def resume_queue_after_failure( + printer_id: int, + db: AsyncSession = Depends(get_db), + _: User | None = RequirePermissionIfAuthEnabled(Permission.QUEUE_UPDATE_ALL), +): + """Clear the previous-success gate for a printer and restore skipped items. + + Single atomic op (#1818): + + * Sets ``gate_acknowledged=True`` on every ``failed`` / ``aborted`` queue + item for this printer that's still in the scheduler's lookback window, + so the next ``_check_previous_success`` call ignores them. + * Restores ``skipped`` items whose ``error_message`` matches the + scheduler's exact "Previous print failed or was aborted" gate string + back to ``pending`` (clears ``error_message`` + ``completed_at``). + + Returns counts so the UI can render a precise toast. No-op endpoint + (zero counts) when called against a printer with no gate to clear. + """ + result = await db.execute(select(Printer).where(Printer.id == printer_id)) + printer = result.scalar_one_or_none() + if not printer: + raise HTTPException(404, "Printer not found") + + ack_result = await db.execute( + select(PrintQueueItem) + .where(PrintQueueItem.printer_id == printer_id) + .where(PrintQueueItem.status.in_(["failed", "aborted"])) + .where(PrintQueueItem.gate_acknowledged == False) # noqa: E712 + ) + to_ack = ack_result.scalars().all() + for failed_item in to_ack: + failed_item.gate_acknowledged = True + + restore_result = await db.execute( + select(PrintQueueItem) + .where(PrintQueueItem.printer_id == printer_id) + .where(PrintQueueItem.status == "skipped") + .where(PrintQueueItem.error_message == "Previous print failed or was aborted") + ) + to_restore = restore_result.scalars().all() + for skipped_item in to_restore: + skipped_item.status = "pending" + skipped_item.error_message = None + skipped_item.completed_at = None + + await db.commit() + + logger.info( + "Resume after failure on printer %s: acknowledged %d failure(s), restored %d skipped item(s)", + printer_id, + len(to_ack), + len(to_restore), + ) + return {"acknowledged": len(to_ack), "restored": len(to_restore)} + + @router.post("/{item_id}/cancel") async def cancel_queue_item( item_id: int, diff --git a/backend/app/core/database.py b/backend/app/core/database.py index a3540eea4..f6e2b8dc6 100644 --- a/backend/app/core/database.py +++ b/backend/app/core/database.py @@ -3079,6 +3079,15 @@ async def run_migrations(conn): "ALTER TABLE notification_providers ADD COLUMN on_ai_failure_detection BOOLEAN DEFAULT false", ) + # Migration: Add gate_acknowledged column to print_queue (#1818). Cleared + # by the per-printer "Resume after failure" action so the scheduler's + # `_check_previous_success` lookback skips this row. Postgres rejects + # `DEFAULT 0` for BOOLEAN columns. + if is_sqlite(): + await _safe_execute(conn, "ALTER TABLE print_queue ADD COLUMN gate_acknowledged BOOLEAN DEFAULT 0") + else: + await _safe_execute(conn, "ALTER TABLE print_queue ADD COLUMN gate_acknowledged BOOLEAN DEFAULT false") + # Migration: Disambiguate the four ``user_print_*`` notification template # names by appending " Email" (#1792). See ``_migrate_rename_user_print_template_names``. await _migrate_rename_user_print_template_names(conn) diff --git a/backend/app/models/print_queue.py b/backend/app/models/print_queue.py index bc4a7b771..59a6878a4 100644 --- a/backend/app/models/print_queue.py +++ b/backend/app/models/print_queue.py @@ -90,6 +90,15 @@ class PrintQueueItem(Base): # Status: pending, printing, completed, failed, skipped, cancelled status: Mapped[str] = mapped_column(String(20), default="pending") + # Cleared by the per-printer "Resume after failure" action (#1818) so the + # scheduler's `_check_previous_success` lookback skips this row. Without + # this, a single `failed` or `aborted` print poisoned every later + # `require_previous_success` item on the same printer forever — the + # lookback excluded `skipped` but had no way to dismiss the originating + # failure. The flag is per-item, not per-printer, so a fresh failure + # after a resume re-gates downstream items independently. + gate_acknowledged: Mapped[bool] = mapped_column(Boolean, default=False) + # Set by the dispatch scheduler when the assigned spool can't satisfy # this print's per-slot filament weight (#1496). Display-only flag — the # actual deficit is recomputed live every time the user clicks ▶, so diff --git a/backend/app/services/print_scheduler.py b/backend/app/services/print_scheduler.py index c5ea2f7f4..82c5bdf4d 100644 --- a/backend/app/services/print_scheduler.py +++ b/backend/app/services/print_scheduler.py @@ -1901,12 +1901,18 @@ class PrintScheduler: items — counting it as a failed predecessor was the cascade bug that let a single cancellation block 18 items over 3 days for the reporter. Only `failed` and `aborted` — real print-attempt failures — block. + + Failures with `gate_acknowledged=True` (set by the per-printer Resume + action — #1818) are also excluded from the lookback so the user can + clear the gate after fixing the physical issue without having to + re-queue every downstream job. """ result = await db.execute( select(PrintQueueItem) .where(PrintQueueItem.printer_id == item.printer_id) .where(PrintQueueItem.id != item.id) .where(PrintQueueItem.status.in_(["completed", "failed", "cancelled", "aborted"])) + .where(PrintQueueItem.gate_acknowledged == False) # noqa: E712 .order_by(PrintQueueItem.completed_at.desc()) .limit(1) ) diff --git a/backend/tests/integration/test_print_queue_api.py b/backend/tests/integration/test_print_queue_api.py index bec2f39bc..ef41dd240 100644 --- a/backend/tests/integration/test_print_queue_api.py +++ b/backend/tests/integration/test_print_queue_api.py @@ -2247,3 +2247,247 @@ class TestAbortedStatusNormalisation: assert row["archive_deleted"] is False assert row["archive_name"] == "Live Archive" assert row["archive_thumbnail"] == "archives/test/live/thumbnail.png" + + +class TestResumeQueueAfterFailure: + """Integration tests for POST /api/v1/queue/printer/{id}/resume (#1818).""" + + @pytest.fixture + async def printer_factory(self, db_session): + _counter = [0] + + async def _create_printer(**kwargs): + from backend.app.models.printer import Printer + + _counter[0] += 1 + counter = _counter[0] + defaults = { + "name": f"Resume Printer {counter}", + "ip_address": f"192.168.42.{100 + counter}", + "serial_number": f"RESUMESERIAL{counter:04d}", + "access_code": "12345678", + "model": "P1S", + } + defaults.update(kwargs) + printer = Printer(**defaults) + db_session.add(printer) + await db_session.commit() + await db_session.refresh(printer) + return printer + + return _create_printer + + @pytest.fixture + async def archive_factory(self, db_session): + _counter = [0] + + async def _create_archive(**kwargs): + from backend.app.models.archive import PrintArchive + + _counter[0] += 1 + counter = _counter[0] + defaults = { + "filename": f"resume_print_{counter}.3mf", + "print_name": f"Resume Print {counter}", + "file_path": f"/tmp/resume_print_{counter}.3mf", + "file_size": 1024, + "content_hash": f"resumehash{counter:08d}", + "status": "completed", + } + defaults.update(kwargs) + archive = PrintArchive(**defaults) + db_session.add(archive) + await db_session.commit() + await db_session.refresh(archive) + return archive + + return _create_archive + + async def _add_item(self, db_session, printer, archive_factory, **kwargs): + from backend.app.models.print_queue import PrintQueueItem + + archive = await archive_factory() + defaults = { + "printer_id": printer.id, + "archive_id": archive.id, + "status": "pending", + "require_previous_success": True, + } + defaults.update(kwargs) + item = PrintQueueItem(**defaults) + db_session.add(item) + await db_session.commit() + await db_session.refresh(item) + return item + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_resume_unknown_printer_returns_404(self, async_client: AsyncClient): + resp = await async_client.post("/api/v1/queue/printer/999999/resume") + assert resp.status_code == 404 + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_resume_no_op_on_clean_queue(self, async_client: AsyncClient, printer_factory): + """Calling resume on a printer with no failures and no skipped items + returns zero counts — endpoint is idempotent and safe to spam.""" + printer = await printer_factory() + resp = await async_client.post(f"/api/v1/queue/printer/{printer.id}/resume") + assert resp.status_code == 200 + assert resp.json() == {"acknowledged": 0, "restored": 0} + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_resume_acknowledges_failed_and_restores_skipped( + self, async_client: AsyncClient, printer_factory, archive_factory, db_session + ): + """Reporter's scenario: failed predecessor + N skipped downstream items. + Resume sets gate_acknowledged on the failure and flips skipped → pending.""" + from sqlalchemy import select + + from backend.app.models.print_queue import PrintQueueItem + + printer = await printer_factory() + failed = await self._add_item(db_session, printer, archive_factory, status="failed") + skipped_1 = await self._add_item( + db_session, + printer, + archive_factory, + status="skipped", + error_message="Previous print failed or was aborted", + ) + skipped_2 = await self._add_item( + db_session, + printer, + archive_factory, + status="skipped", + error_message="Previous print failed or was aborted", + ) + + resp = await async_client.post(f"/api/v1/queue/printer/{printer.id}/resume") + assert resp.status_code == 200 + assert resp.json() == {"acknowledged": 1, "restored": 2} + + failed_id = failed.id + skipped_ids = [skipped_1.id, skipped_2.id] + db_session.expire_all() + + result = await db_session.execute(select(PrintQueueItem).where(PrintQueueItem.id == failed_id)) + assert result.scalar_one().gate_acknowledged is True + + for sid in skipped_ids: + result = await db_session.execute(select(PrintQueueItem).where(PrintQueueItem.id == sid)) + row = result.scalar_one() + assert row.status == "pending" + assert row.error_message is None + assert row.completed_at is None + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_resume_preserves_skipped_items_with_other_reasons( + self, async_client: AsyncClient, printer_factory, archive_factory, db_session + ): + """Skipped items whose error_message is something OTHER than the + gate string (e.g. filament-deficit promotion, future skip reasons) + must not be touched — they encode different user intent.""" + from sqlalchemy import select + + from backend.app.models.print_queue import PrintQueueItem + + printer = await printer_factory() + gate_skip = await self._add_item( + db_session, + printer, + archive_factory, + status="skipped", + error_message="Previous print failed or was aborted", + ) + other_skip = await self._add_item( + db_session, + printer, + archive_factory, + status="skipped", + error_message="User skipped via UI", + ) + + gate_id = gate_skip.id + other_id = other_skip.id + resp = await async_client.post(f"/api/v1/queue/printer/{printer.id}/resume") + assert resp.json() == {"acknowledged": 0, "restored": 1} + + db_session.expire_all() + result = await db_session.execute(select(PrintQueueItem).where(PrintQueueItem.id == gate_id)) + assert result.scalar_one().status == "pending" + result = await db_session.execute(select(PrintQueueItem).where(PrintQueueItem.id == other_id)) + assert result.scalar_one().status == "skipped" + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_resume_scoped_to_printer( + self, async_client: AsyncClient, printer_factory, archive_factory, db_session + ): + """A resume on printer A must not clear printer B's gate — farms run + each printer's queue independently.""" + from sqlalchemy import select + + from backend.app.models.print_queue import PrintQueueItem + + p1 = await printer_factory() + p2 = await printer_factory() + failed_p1 = await self._add_item(db_session, p1, archive_factory, status="failed") + failed_p2 = await self._add_item(db_session, p2, archive_factory, status="failed") + + failed_p1_id = failed_p1.id + failed_p2_id = failed_p2.id + resp = await async_client.post(f"/api/v1/queue/printer/{p1.id}/resume") + assert resp.json() == {"acknowledged": 1, "restored": 0} + + db_session.expire_all() + result = await db_session.execute(select(PrintQueueItem).where(PrintQueueItem.id == failed_p1_id)) + assert result.scalar_one().gate_acknowledged is True + result = await db_session.execute(select(PrintQueueItem).where(PrintQueueItem.id == failed_p2_id)) + assert result.scalar_one().gate_acknowledged is False + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_resume_handles_aborted_status( + self, async_client: AsyncClient, printer_factory, archive_factory, db_session + ): + """Aborted prints (printer-detected mid-print failure) gate the same + way failed prints do and must also be acknowledgeable.""" + from sqlalchemy import select + + from backend.app.models.print_queue import PrintQueueItem + + printer = await printer_factory() + aborted = await self._add_item(db_session, printer, archive_factory, status="aborted") + aborted_id = aborted.id + resp = await async_client.post(f"/api/v1/queue/printer/{printer.id}/resume") + assert resp.json() == {"acknowledged": 1, "restored": 0} + + db_session.expire_all() + result = await db_session.execute(select(PrintQueueItem).where(PrintQueueItem.id == aborted_id)) + assert result.scalar_one().gate_acknowledged is True + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_resume_idempotent_second_call_is_no_op( + self, async_client: AsyncClient, printer_factory, archive_factory, db_session + ): + """Calling resume twice on the same printer doesn't re-acknowledge + the same failure — the second call sees acknowledged=0, restored=0.""" + printer = await printer_factory() + await self._add_item(db_session, printer, archive_factory, status="failed") + await self._add_item( + db_session, + printer, + archive_factory, + status="skipped", + error_message="Previous print failed or was aborted", + ) + + first = await async_client.post(f"/api/v1/queue/printer/{printer.id}/resume") + assert first.json() == {"acknowledged": 1, "restored": 1} + + second = await async_client.post(f"/api/v1/queue/printer/{printer.id}/resume") + assert second.json() == {"acknowledged": 0, "restored": 0} diff --git a/backend/tests/unit/test_check_previous_success.py b/backend/tests/unit/test_check_previous_success.py index 3a4d06ac7..3556f871b 100644 --- a/backend/tests/unit/test_check_previous_success.py +++ b/backend/tests/unit/test_check_previous_success.py @@ -47,7 +47,11 @@ def queue_factory(db_session, printer_factory): printer_holder["p"] = await printer_factory() return printer_holder["p"] - async def _add(status: str, error_message: str | None = None) -> PrintQueueItem: + async def _add( + status: str, + error_message: str | None = None, + gate_acknowledged: bool = False, + ) -> PrintQueueItem: printer = await _make_printer() counter["n"] += 1 item = PrintQueueItem( @@ -56,6 +60,7 @@ def queue_factory(db_session, printer_factory): error_message=error_message, completed_at=base_time + timedelta(minutes=counter["n"]), require_previous_success=True, + gate_acknowledged=gate_acknowledged, ) db_session.add(item) await db_session.commit() @@ -170,3 +175,44 @@ async def test_completed_then_failed_blocks(scheduler, db_session, queue_factory await queue_factory["add"]("failed") pending = await queue_factory["add_pending"]() assert await scheduler._check_previous_success(db_session, pending) is False + + +# ---- #1818: per-printer Resume-after-failure gate acknowledgement ---- + + +@pytest.mark.asyncio +async def test_acknowledged_failure_is_excluded(scheduler, db_session, queue_factory): + """The reporter scenario: failure with gate_acknowledged=True must NOT + block. Without the acknowledge filter, a single failure poisons every + later require_previous_success item forever.""" + await queue_factory["add"]("failed", gate_acknowledged=True) + pending = await queue_factory["add_pending"]() + assert await scheduler._check_previous_success(db_session, pending) is True + + +@pytest.mark.asyncio +async def test_acknowledged_aborted_is_excluded(scheduler, db_session, queue_factory): + await queue_factory["add"]("aborted", gate_acknowledged=True) + pending = await queue_factory["add_pending"]() + assert await scheduler._check_previous_success(db_session, pending) is True + + +@pytest.mark.asyncio +async def test_fresh_failure_after_ack_still_blocks(scheduler, db_session, queue_factory): + """Per-item acknowledgement is independent — a NEW failure after the + user resumed the queue must re-gate downstream items so they don't + silently steamroll past a real problem.""" + await queue_factory["add"]("failed", gate_acknowledged=True) # the old one + await queue_factory["add"]("failed", gate_acknowledged=False) # fresh post-resume + pending = await queue_factory["add_pending"]() + assert await scheduler._check_previous_success(db_session, pending) is False + + +@pytest.mark.asyncio +async def test_acknowledged_failure_walks_back_to_completed(scheduler, db_session, queue_factory): + """After acknowledging the failure, the next real predecessor (a + completed print prior to the failure) governs the gate.""" + await queue_factory["add"]("completed") + await queue_factory["add"]("failed", gate_acknowledged=True) + pending = await queue_factory["add_pending"]() + assert await scheduler._check_previous_success(db_session, pending) is True diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 791192f0a..90bea3d2a 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -4771,6 +4771,17 @@ export const api = { const qs = opts?.skipFilamentCheck ? '?skip_filament_check=true' : ''; return request(`/queue/${id}/start${qs}`, { method: 'POST' }); }, + /** + * Clear the `require_previous_success` gate for a printer after the user + * resolves the failure. Acknowledges any failed/aborted predecessors and + * restores skipped items whose error_message matches the gate string + * back to pending. Returns counts so the UI can render a precise toast. + */ + resumeQueueAfterFailure: (printerId: number) => + request<{ acknowledged: number; restored: number }>( + `/queue/printer/${printerId}/resume`, + { method: 'POST' }, + ), bulkUpdateQueue: (data: PrintQueueBulkUpdate) => request('/queue/bulk', { method: 'PATCH', diff --git a/frontend/src/i18n/locales/de.ts b/frontend/src/i18n/locales/de.ts index 0459bafad..4adeef12f 100644 --- a/frontend/src/i18n/locales/de.ts +++ b/frontend/src/i18n/locales/de.ts @@ -1229,6 +1229,15 @@ export default { batchCreateFailed: 'Stapel konnte nicht erstellt werden', batchUngrouped: '{{count}} Eintrag/Einträge aus Stapel gelöst', batchUngroupFailed: 'Stapel konnte nicht aufgelöst werden', + resumedAfterFailure: 'Warteschlange fortgesetzt — {{restored}} Auftrag/Aufträge wieder eingereiht', + resumeAfterFailureFailed: 'Warteschlange konnte nicht fortgesetzt werden', + }, + resumeAfterFailure: { + banner: '{{printer}} ist durch einen vorherigen Druckfehler blockiert — {{count}} Auftrag/Aufträge übersprungen', + bannerHint: 'Behebe das Druckerproblem und setze die Warteschlange dann fort, um die übersprungenen Aufträge wiederherzustellen und die Sperre aufzuheben.', + button: 'Nach Fehler fortsetzen', + confirmTitle: 'Warteschlange nach Fehler fortsetzen?', + confirmMessage: 'Setze {{count}} übersprungenen Auftrag/Aufträge auf {{printer}} wieder auf „Ausstehend“ und hebe die Vorgängersperre auf. Stelle vorher sicher, dass der Drucker bereit ist.', }, // Timeline view timeline: { diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index d0c78568a..35d8c7f8f 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -1239,6 +1239,15 @@ export default { batchCreateFailed: 'Failed to create batch', batchUngrouped: 'Ungrouped {{count}} item(s)', batchUngroupFailed: 'Failed to ungroup batch', + resumedAfterFailure: 'Resumed queue — {{restored}} job(s) restored to pending', + resumeAfterFailureFailed: 'Failed to resume queue', + }, + resumeAfterFailure: { + banner: '{{printer}} is blocked by a previous-print failure — {{count}} job(s) skipped', + bannerHint: 'Fix the printer issue, then resume to restore the skipped jobs and clear the gate.', + button: 'Resume after failure', + confirmTitle: 'Resume queue after failure?', + confirmMessage: 'Restore {{count}} skipped job(s) on {{printer}} to pending and clear the previous-print gate. Make sure the printer is ready before continuing.', }, // Timeline view timeline: { diff --git a/frontend/src/i18n/locales/es.ts b/frontend/src/i18n/locales/es.ts index 1de1c3868..7b8d20ece 100644 --- a/frontend/src/i18n/locales/es.ts +++ b/frontend/src/i18n/locales/es.ts @@ -1229,6 +1229,15 @@ export default { batchCreateFailed: 'Error al crear el lote', batchUngrouped: '{{count}} elemento(s) desagrupado(s)', batchUngroupFailed: 'Error al desagrupar el lote', + resumedAfterFailure: 'Cola reanudada — {{restored}} trabajo(s) restaurado(s) a pendientes', + resumeAfterFailureFailed: 'Error al reanudar la cola', + }, + resumeAfterFailure: { + banner: '{{printer}} está bloqueado por un fallo de impresión previo — {{count}} trabajo(s) omitido(s)', + bannerHint: 'Soluciona el problema de la impresora y reanuda para restaurar los trabajos omitidos y limpiar el bloqueo.', + button: 'Reanudar tras fallo', + confirmTitle: '¿Reanudar la cola tras el fallo?', + confirmMessage: 'Restaurar {{count}} trabajo(s) omitido(s) en {{printer}} a pendientes y limpiar el bloqueo del trabajo anterior. Asegúrate de que la impresora esté lista antes de continuar.', }, // Timeline view timeline: { diff --git a/frontend/src/i18n/locales/fr.ts b/frontend/src/i18n/locales/fr.ts index 9ca02de9e..94ed495a2 100644 --- a/frontend/src/i18n/locales/fr.ts +++ b/frontend/src/i18n/locales/fr.ts @@ -1229,6 +1229,15 @@ export default { batchCreateFailed: 'Échec de la création du lot', batchUngrouped: '{{count}} élément(s) dégroupé(s)', batchUngroupFailed: 'Échec du dégroupement du lot', + resumedAfterFailure: 'File reprise — {{restored}} tâche(s) restaurée(s) en attente', + resumeAfterFailureFailed: 'Échec de la reprise de la file', + }, + resumeAfterFailure: { + banner: '{{printer}} est bloquée par un échec d\'impression précédent — {{count}} tâche(s) ignorée(s)', + bannerHint: 'Résolvez le problème de l\'imprimante, puis reprenez la file pour restaurer les tâches ignorées et lever le blocage.', + button: 'Reprendre après échec', + confirmTitle: 'Reprendre la file après l\'échec ?', + confirmMessage: 'Restaurer {{count}} tâche(s) ignorée(s) sur {{printer}} en attente et lever le blocage de l\'impression précédente. Assurez-vous que l\'imprimante est prête avant de continuer.', }, // Timeline view timeline: { diff --git a/frontend/src/i18n/locales/it.ts b/frontend/src/i18n/locales/it.ts index bcc671564..c765eadc9 100644 --- a/frontend/src/i18n/locales/it.ts +++ b/frontend/src/i18n/locales/it.ts @@ -1229,6 +1229,15 @@ export default { batchCreateFailed: 'Creazione lotto non riuscita', batchUngrouped: '{{count}} elemento/i separato/i', batchUngroupFailed: 'Separazione del lotto non riuscita', + resumedAfterFailure: 'Coda ripresa — {{restored}} processo/i ripristinato/i come in attesa', + resumeAfterFailureFailed: 'Ripresa della coda non riuscita', + }, + resumeAfterFailure: { + banner: '{{printer}} è bloccata da un errore di stampa precedente — {{count}} processo/i saltato/i', + bannerHint: 'Risolvi il problema della stampante, poi riprendi per ripristinare i processi saltati e rimuovere il blocco.', + button: 'Riprendi dopo errore', + confirmTitle: 'Riprendere la coda dopo l\'errore?', + confirmMessage: 'Ripristinare {{count}} processo/i saltato/i su {{printer}} come in attesa e rimuovere il blocco della stampa precedente. Assicurati che la stampante sia pronta prima di continuare.', }, // Timeline view timeline: { diff --git a/frontend/src/i18n/locales/ja.ts b/frontend/src/i18n/locales/ja.ts index 62e3fc40b..8a887ceb6 100644 --- a/frontend/src/i18n/locales/ja.ts +++ b/frontend/src/i18n/locales/ja.ts @@ -1228,6 +1228,15 @@ export default { batchCreateFailed: 'バッチの作成に失敗しました', batchUngrouped: '{{count}}件のグループを解除しました', batchUngroupFailed: 'バッチのグループ解除に失敗しました', + resumedAfterFailure: 'キューを再開しました — {{restored}}件のジョブを保留状態に戻しました', + resumeAfterFailureFailed: 'キューの再開に失敗しました', + }, + resumeAfterFailure: { + banner: '{{printer}} は前回の印刷失敗によりブロックされています — {{count}}件のジョブをスキップしました', + bannerHint: 'プリンターの問題を解決してから再開すると、スキップされたジョブを復元してブロックを解除できます。', + button: '失敗後に再開', + confirmTitle: '失敗後にキューを再開しますか?', + confirmMessage: '{{printer}} のスキップされた {{count}} 件のジョブを保留状態に戻し、前回の印刷ブロックを解除します。続行する前にプリンターが準備完了していることを確認してください。', }, // Timeline view timeline: { diff --git a/frontend/src/i18n/locales/ko.ts b/frontend/src/i18n/locales/ko.ts index 593444e68..637095278 100644 --- a/frontend/src/i18n/locales/ko.ts +++ b/frontend/src/i18n/locales/ko.ts @@ -1161,6 +1161,15 @@ export default { batchCreateFailed: '배치 만들기에 실패했습니다', batchUngrouped: '{{count}}개 항목의 그룹을 해제했습니다', batchUngroupFailed: '배치 그룹 해제에 실패했습니다', + resumedAfterFailure: '큐를 재개했습니다 — {{restored}}개 작업을 대기 상태로 복원했습니다', + resumeAfterFailureFailed: '큐 재개에 실패했습니다', + }, + resumeAfterFailure: { + banner: '{{printer}}이(가) 이전 인쇄 실패로 인해 차단되었습니다 — {{count}}개 작업이 건너뛰어졌습니다', + bannerHint: '프린터 문제를 해결한 후 재개하여 건너뛴 작업을 복원하고 차단을 해제하세요.', + button: '실패 후 재개', + confirmTitle: '실패 후 큐를 재개하시겠습니까?', + confirmMessage: '{{printer}}에서 건너뛴 {{count}}개 작업을 대기 상태로 복원하고 이전 인쇄 차단을 해제합니다. 계속하기 전에 프린터가 준비되었는지 확인하세요.', }, timeline: { listView: '목록', diff --git a/frontend/src/i18n/locales/pt-BR.ts b/frontend/src/i18n/locales/pt-BR.ts index 4730f4db5..5a8cf9990 100644 --- a/frontend/src/i18n/locales/pt-BR.ts +++ b/frontend/src/i18n/locales/pt-BR.ts @@ -1229,6 +1229,15 @@ export default { batchCreateFailed: 'Falha ao criar o lote', batchUngrouped: '{{count}} item(ns) desagrupado(s)', batchUngroupFailed: 'Falha ao desagrupar o lote', + resumedAfterFailure: 'Fila retomada — {{restored}} trabalho(s) restaurado(s) para pendente', + resumeAfterFailureFailed: 'Falha ao retomar a fila', + }, + resumeAfterFailure: { + banner: '{{printer}} está bloqueada por uma falha de impressão anterior — {{count}} trabalho(s) ignorado(s)', + bannerHint: 'Resolva o problema da impressora e retome para restaurar os trabalhos ignorados e remover o bloqueio.', + button: 'Retomar após falha', + confirmTitle: 'Retomar a fila após a falha?', + confirmMessage: 'Restaurar {{count}} trabalho(s) ignorado(s) em {{printer}} para pendente e remover o bloqueio da impressão anterior. Verifique se a impressora está pronta antes de continuar.', }, // Timeline view timeline: { diff --git a/frontend/src/i18n/locales/tr.ts b/frontend/src/i18n/locales/tr.ts index b50214a2d..a6a608827 100644 --- a/frontend/src/i18n/locales/tr.ts +++ b/frontend/src/i18n/locales/tr.ts @@ -1229,6 +1229,15 @@ export default { batchCreateFailed: 'Yığın oluşturma başarısız', batchUngrouped: '{{count}} öğe gruptan çıkarıldı', batchUngroupFailed: 'Yığını gruptan çıkarma başarısız', + resumedAfterFailure: 'Kuyruk devam ettirildi — {{restored}} iş bekleyene geri alındı', + resumeAfterFailureFailed: 'Kuyruk devam ettirilemedi', + }, + resumeAfterFailure: { + banner: '{{printer}} önceki bir baskı hatası nedeniyle engellendi — {{count}} iş atlandı', + bannerHint: 'Yazıcı sorununu çözün, ardından atlanan işleri geri yüklemek ve engellemeyi kaldırmak için devam ettirin.', + button: 'Hatadan sonra devam et', + confirmTitle: 'Hatadan sonra kuyruğa devam edilsin mi?', + confirmMessage: '{{printer}} üzerindeki {{count}} atlanan işi bekleyene geri yükleyin ve önceki baskı engelini kaldırın. Devam etmeden önce yazıcının hazır olduğundan emin olun.', }, // Zaman çizelgesi görünümü timeline: { diff --git a/frontend/src/i18n/locales/zh-CN.ts b/frontend/src/i18n/locales/zh-CN.ts index b80bc9760..de97a8405 100644 --- a/frontend/src/i18n/locales/zh-CN.ts +++ b/frontend/src/i18n/locales/zh-CN.ts @@ -1229,6 +1229,15 @@ export default { batchCreateFailed: '创建批次失败', batchUngrouped: '已取消分组 {{count}} 项', batchUngroupFailed: '取消批次分组失败', + resumedAfterFailure: '已恢复队列 — {{restored}} 个任务已恢复为待处理', + resumeAfterFailureFailed: '恢复队列失败', + }, + resumeAfterFailure: { + banner: '{{printer}} 因之前的打印失败而被阻塞 — 已跳过 {{count}} 个任务', + bannerHint: '解决打印机问题后恢复队列,以还原跳过的任务并清除阻塞。', + button: '失败后恢复', + confirmTitle: '失败后恢复队列?', + confirmMessage: '将 {{printer}} 上的 {{count}} 个跳过的任务恢复为待处理,并清除上一个打印的阻塞。继续之前请确保打印机已就绪。', }, // Timeline view timeline: { diff --git a/frontend/src/i18n/locales/zh-TW.ts b/frontend/src/i18n/locales/zh-TW.ts index 49564514d..399cb895a 100644 --- a/frontend/src/i18n/locales/zh-TW.ts +++ b/frontend/src/i18n/locales/zh-TW.ts @@ -1229,6 +1229,15 @@ export default { batchCreateFailed: '建立批次失敗', batchUngrouped: '已取消分組 {{count}} 項', batchUngroupFailed: '取消批次分組失敗', + resumedAfterFailure: '已恢復佇列 — {{restored}} 個工作已恢復為待處理', + resumeAfterFailureFailed: '恢復佇列失敗', + }, + resumeAfterFailure: { + banner: '{{printer}} 因先前的列印失敗而被阻擋 — 已跳過 {{count}} 個工作', + bannerHint: '解決印表機問題後恢復佇列,以還原跳過的工作並清除阻擋。', + button: '失敗後恢復', + confirmTitle: '失敗後恢復佇列?', + confirmMessage: '將 {{printer}} 上的 {{count}} 個跳過的工作恢復為待處理,並清除上一個列印的阻擋。繼續前請確認印表機已就緒。', }, // Timeline view timeline: { diff --git a/frontend/src/pages/QueuePage.tsx b/frontend/src/pages/QueuePage.tsx index 4dbe9f5d0..d7932452e 100644 --- a/frontend/src/pages/QueuePage.tsx +++ b/frontend/src/pages/QueuePage.tsx @@ -58,6 +58,7 @@ import { PackageOpen, Ungroup, Ban, + PlayCircle, } from 'lucide-react'; import { api, ApiError } from '../api/client'; import { type TimeFormat, formatETA, formatDuration, formatRelativeTime, parseUTCDate } from '../utils/date'; @@ -1208,6 +1209,13 @@ export function QueuePage() { } | null>(null); const [selectedItems, setSelectedItems] = useState([]); const [showBulkEditModal, setShowBulkEditModal] = useState(false); + // #1818: per-printer Resume-after-failure confirm modal. Tracks which + // printer's gate the user is about to clear; null when no modal is open. + const [resumeConfirm, setResumeConfirm] = useState<{ + printerId: number; + printerName: string; + skippedCount: number; + } | null>(null); const [historySortBy, setHistorySortBy] = useState<'date' | 'name' | 'printer'>(() => { const saved = localStorage.getItem('queue.historySortBy'); return (saved as 'date' | 'name' | 'printer') || 'date'; @@ -1431,6 +1439,21 @@ export function QueuePage() { onError: () => showToast(t('queue.toast.bulkCancelFailed'), 'error'), }); + const resumeAfterFailureMutation = useMutation({ + mutationFn: (printerId: number) => api.resumeQueueAfterFailure(printerId), + onSuccess: (result) => { + queryClient.invalidateQueries({ queryKey: ['queue'] }); + setResumeConfirm(null); + showToast( + t('queue.toast.resumedAfterFailure', { + restored: result.restored, + acknowledged: result.acknowledged, + }), + ); + }, + onError: () => showToast(t('queue.toast.resumeAfterFailureFailed'), 'error'), + }); + const createBatchMutation = useMutation({ mutationFn: (data: { name: string; item_ids: number[] }) => api.createBatch(data), onSuccess: (batch) => { @@ -1823,6 +1846,42 @@ export function QueuePage() { }); }, [groupedRows, t]); + // #1818: printers whose queue is gated by a prior failure that's poisoning + // downstream `require_previous_success` items. We surface a per-printer + // Resume banner above the active queue so the user can clear the gate + + // restore the skipped jobs in one click, without re-queuing each one. + // Detection key: skipped + the scheduler's exact gate string. Other skip + // reasons (filament deficit, etc.) get their own UX and stay untouched. + const gateBlockedPrinters = useMemo< + Array<{ printerId: number; printerName: string; skippedCount: number }> + >(() => { + const counts = new Map(); + queue?.forEach((item) => { + if ( + item.status === 'skipped' && + item.error_message === 'Previous print failed or was aborted' && + item.printer_id + ) { + const existing = counts.get(item.printer_id); + if (existing) { + existing.count += 1; + } else { + counts.set(item.printer_id, { + name: item.printer_name || `Printer #${item.printer_id}`, + count: 1, + }); + } + } + }); + return Array.from(counts.entries()) + .map(([printerId, { name, count }]) => ({ + printerId, + printerName: name, + skippedCount: count, + })) + .sort((a, b) => a.printerName.localeCompare(b.printerName)); + }, [queue]); + const aggregateForRows = (rows: QueueRow[]) => { let count = 0; let time = 0; @@ -1891,6 +1950,43 @@ export function QueuePage() { t={t} /> + {/* #1818: Resume-after-failure banner. One row per printer whose queue + is gated by a prior failed/aborted print. Visible regardless of + tab/layout so the user can clear the gate without hunting for + skipped items. Hidden entirely when no gates are active. */} + {activeTab === 'queue' && gateBlockedPrinters.length > 0 && hasPermission('queue:update_all' as Permission) && ( +
+ {gateBlockedPrinters.map(({ printerId, printerName, skippedCount }) => ( +
+ +
+
+ {t('queue.resumeAfterFailure.banner', { + printer: printerName, + count: skippedCount, + })} +
+
+ {t('queue.resumeAfterFailure.bannerHint')} +
+
+ +
+ ))} +
+ )} + {/* Filters */}
without a
`);let s=e.getAttribute(`formaction`)||o.getAttribute(`action`);if(r=s?dn(s,t):null,n=e.getAttribute(`formmethod`)||o.getAttribute(`method`)||Pr,i=qr(e.getAttribute(`formenctype`))||qr(o.getAttribute(`enctype`))||Fr,a=new FormData(o,e),!Gr()){let{name:t,type:n,value:r}=e;if(n===`image`){let e=t?`${t}.`:``;a.append(`${e}x`,`0`),a.append(`${e}y`,`0`)}else t&&a.append(t,r)}}else if(Ir(e))throw Error(`Cannot submit element that is not ,