Browse Source

Show the last print on printer cards and lazy-load file thumbnails

The printer card called getArchives(printer.id, 1, 0), which sends
project_id=1&limit=0, so every card got an empty list: no "Last:" line
and no Good/Reject prompt from #1898. Cards now share one request to the
new GET /archives/last-per-printer, which returns the archive each
printer ran last (by run start, since a reprint reuses its archive row)
without the duplicate scan the full listing runs.

File Manager and Archives thumbnails load lazily instead of all at once.
maziggy 2 days ago
parent
commit
7d46baea65
100 changed files with 290 additions and 39 deletions
  1. 3 0
      CHANGELOG.md
  2. 59 0
      backend/app/api/routes/archives.py
  3. 164 0
      backend/tests/integration/test_archives_last_per_printer.py
  4. 1 0
      frontend/src/__tests__/mocks/handlers.ts
  5. 20 2
      frontend/src/__tests__/pages/PrintersPageCardVerdict.test.tsx
  6. 2 0
      frontend/src/api/client.ts
  7. 2 0
      frontend/src/pages/ArchivesPage.tsx
  8. 4 0
      frontend/src/pages/FileManagerPage.tsx
  9. 6 6
      frontend/src/pages/PrintersPage.tsx
  10. 0 0
      static/assets/AdditionalSection-CtnbDT0n.js
  11. 0 0
      static/assets/AmsUnitCard-CdKb_G_9.js
  12. 0 0
      static/assets/ArchivesPage-DuXjoXFE.js
  13. 0 0
      static/assets/AreaChart-5Jo0NTVy.js
  14. 0 0
      static/assets/AssignToAmsModal-MATupGfA.js
  15. 1 1
      static/assets/Button-BAwcIdV7.js
  16. 0 0
      static/assets/CamWallPage-7LOH3GGc.js
  17. 0 0
      static/assets/CameraDiagnoseModal-CfEhlk-3.js
  18. 0 0
      static/assets/CameraPage-1gEpM7YE.js
  19. 0 0
      static/assets/CameraWall-DFHo23uI.js
  20. 1 1
      static/assets/Card-Bs7yK0-y.js
  21. 0 0
      static/assets/CartesianChart-CkznuDC2.js
  22. 0 0
      static/assets/ColumnConfigModal-Bkb2EWX8.js
  23. 0 0
      static/assets/ConfigureAmsSlotModal-C8Vb6jND.js
  24. 0 0
      static/assets/ConnectAuthorizePage-BOrVE2dw.js
  25. 0 0
      static/assets/ContextMenu-B4p7RmJK.js
  26. 0 0
      static/assets/CopyButton-DKdfYD-W.js
  27. 0 0
      static/assets/ErrorBarContext-BH62r7Af.js
  28. 0 0
      static/assets/ExternalLinkPage-Dcal4COV.js
  29. 0 1
      static/assets/FileManagerPage-ChtsL-ib.js
  30. 0 0
      static/assets/FileUploadModal-BIO_Tg0j.js
  31. 0 0
      static/assets/FinancePage-DqPYqSQw.js
  32. 0 0
      static/assets/GCodeViewerPage-D3DIVv_o.js
  33. 0 0
      static/assets/GcodeToolpathViewer-DG-G795p.js
  34. 0 0
      static/assets/GroupEditPage-C5Z1fwVG.js
  35. 0 0
      static/assets/ImagePreviewModal-0kUOGDQR.js
  36. 0 0
      static/assets/InventoryPage-tEyY2-BI.js
  37. 0 0
      static/assets/LibraryTrashPage-C_dj2Ay-.js
  38. 0 0
      static/assets/LoginPage-CSpD-Tv8.js
  39. 0 0
      static/assets/MaintenancePage-GGpHlk7X.js
  40. 0 0
      static/assets/ModelSourcesPage-CRS2vJpg.js
  41. 0 0
      static/assets/NotificationsPage-TaC-DXAi.js
  42. 1 1
      static/assets/OverlayFrame-BJ-Bdt_w.js
  43. 0 1
      static/assets/PdfPreviewModal-DEN6pYx-.js
  44. 0 0
      static/assets/PhotoGalleryModal-ytbp2Lrq.js
  45. 0 0
      static/assets/PrinterLocationsPage-Dilmz8B6.js
  46. 0 0
      static/assets/PrintersPage-BUOWC7Nf.js
  47. 0 0
      static/assets/ProfilesPage-DG48uW4z.js
  48. 0 0
      static/assets/ProjectDetailPage-BCid3Jam.js
  49. 0 0
      static/assets/ProjectsPage-C35W0r_D.js
  50. 0 0
      static/assets/QueryClientProvider-CsMjD-7g.js
  51. 0 0
      static/assets/QueuePage-Kv8gGfNb.js
  52. 0 0
      static/assets/ReferenceLine-ytCyPKIK.js
  53. 0 0
      static/assets/RichTextEditor-BNxt1eBM.js
  54. 0 0
      static/assets/SettingsPage-D5v6IZ1Y.js
  55. 0 0
      static/assets/SetupPage-DsXlcXZ-.js
  56. 0 0
      static/assets/SliceModal-C00u-1ny.js
  57. 0 0
      static/assets/SpoolBuddyAmsPage-DFgy2Ic8.js
  58. 0 0
      static/assets/SpoolBuddyCalibrationPage-CuPYbkCV.js
  59. 0 0
      static/assets/SpoolBuddyDashboard-C00DI1mz.js
  60. 0 0
      static/assets/SpoolBuddyInventoryPage-N471Fx9x.js
  61. 1 1
      static/assets/SpoolBuddySettingsPage-DDNvVsrG.js
  62. 0 0
      static/assets/SpoolBuddyWriteTagPage-BWqB5s__.js
  63. 1 1
      static/assets/SpoolIcon-vvNL1rED.js
  64. 0 0
      static/assets/SpreadsheetPreviewModal-Cv7mkQF1.js
  65. 0 0
      static/assets/StatsPage-D7sKI4LP.js
  66. 0 0
      static/assets/StreamOverlayPage-DP6GThH2.js
  67. 0 0
      static/assets/SystemInfoPage-rtf4xILj.js
  68. 0 0
      static/assets/ToastContext-DvXi5snE.js
  69. 1 1
      static/assets/Toggle-I-VDBGwl.js
  70. 1 0
      static/assets/arrow-down--cYuQXi2.js
  71. 0 1
      static/assets/arrow-down-C4OBNDqJ.js
  72. 1 0
      static/assets/arrow-left-DMgVJlsY.js
  73. 0 1
      static/assets/arrow-left-MSgMxOFV.js
  74. 1 0
      static/assets/arrow-right-BHLBfK4j.js
  75. 0 1
      static/assets/arrow-right-Da96kh4S.js
  76. 1 0
      static/assets/arrow-up-DAnOQUuf.js
  77. 0 1
      static/assets/arrow-up-Dam8cLfE.js
  78. 1 1
      static/assets/arrow-up-down-MZZbOqYJ.js
  79. 1 1
      static/assets/box-9OC1sZAb.js
  80. 1 1
      static/assets/briefcase-Yoce9QZe.js
  81. 1 1
      static/assets/calendar-CLfoE-ho.js
  82. 0 1
      static/assets/check-D1Pn8T1J.js
  83. 1 0
      static/assets/check-lecuNcPc.js
  84. 1 1
      static/assets/chevrons-right-BtGjiArF.js
  85. 0 0
      static/assets/client-BdOyoZJz.js
  86. 0 0
      static/assets/client-D0Q3EIO2.js
  87. 1 1
      static/assets/cloud-off-CvdQNl0K.js
  88. 1 1
      static/assets/cog-rWTLMCB1.js
  89. 1 1
      static/assets/coins-dkDEbZk6.js
  90. 1 0
      static/assets/columns-2-4ppMhNZX.js
  91. 0 1
      static/assets/columns-2-CGEUxYp_.js
  92. 1 1
      static/assets/copy-BSydjjpn.js
  93. 1 1
      static/assets/cpu-BsH-qpUx.js
  94. 1 1
      static/assets/createLucideIcon-BTg337Gy.js
  95. 1 1
      static/assets/dollar-sign-Cn5pcyDA.js
  96. 1 1
      static/assets/droplet-Bpovh5p6.js
  97. 1 1
      static/assets/ellipsis-vertical-BXVT5eVX.js
  98. 1 1
      static/assets/eye-off-Bq05MYzN.js
  99. 1 1
      static/assets/fan-BZ0HFoG4.js
  100. 1 1
      static/assets/file-box-DGWntDxa.js

+ 3 - 0
CHANGELOG.md

@@ -149,6 +149,9 @@ All notable changes to Bambuddy will be documented in this file.
 - **The frontend build no longer warns about `path` and `crypto` being externalized for the STEP previewer (#2976)** — `occt-import-js`, the Emscripten build behind STEP previews, requires both modules, but only inside its `ENVIRONMENT_IS_NODE` branches; in the browser it loads its `.wasm` from the URL the preview worker passes and draws randomness from `crypto.getRandomValues`. Vite still externalized both and printed two warnings on every build. `vite.config.ts` now drops exactly those two warnings for that one package through `build.rolldownOptions.onLog`, so an externalization anywhere else, or of any other module, still shows.
 
 ### Fixed
+- **Printer cards never showed the last print, nor the Good / Reject prompt for it** — Each card asked for its printer's archives with the arguments in the wrong order, so it requested none and always got an empty list. The **Last:** line on an idle card and the outcome prompt from #1898 never appeared there.
+  - **One request for every card:** the cards now share a single request that returns the archive each printer printed last (a reprint of an older archive counts), instead of one per card. On a farm with 59 printers that was 59 requests on every page load and after every finished print, each scanning the whole archive table for duplicates.
+- **The File Manager and Archives page loaded every thumbnail at once** — With a few hundred files every thumbnail was requested on page load, and the queue of requests slowed down everything else on the server for several seconds. Thumbnails now load as they scroll into view.
 - **Statistics counted a multi-material print written from spools as one material (#3262, reported by @ojimpo)** — A print's materials are stored comma-joined, as `PLA, PLA-S` from the sliced file but as `PLA Basic,PLA` once they are taken from the spools that fed it. The Statistics page split on comma plus space only, so those prints showed as one `PLA Basic,PLA` row in the material weight, print count, time and success-rate charts, and the Archives material filter offered the joined string as a material of its own and missed those prints when filtering by `PLA`. Both now split on the comma alone, as the statistics API already did, so existing archives are counted under each of their materials.
 - **A running print's cost used the default rate instead of its spools, then changed without notice at completion (#3261, reported by @ojimpo)** — The archive was priced at creation from the Filament catalogue or **Default Filament Cost**, and the spools that fed the print only priced it once it finished, in both Spoolman mode and the built-in inventory. Anyone noting the cost while a long print ran recorded a placeholder. A print is now priced from its spools when it starts, from the sliced file's per-slot estimate and the spool in each mapped tray, with the same default-rate cover for grams no spool prices; a reprint still keeps its first run's cost. The archive card marks a running print's cost with `~` and a tooltip, since the final figure comes from what was actually used. A print whose slots can't be matched to trays at the start keeps the placeholder until it finishes.
 - **AMS Filament Backup showed "?" on the P1S, P1P, A1 and A1 Mini (#3259, reported by @HopNotch)** — These printers never send the `cfg` field Bambuddy read the setting from; they carry it in `home_flag` bit 10, where Bambu Studio reads it for every printer. Bambuddy now falls back to that bit, so the badge shows the printer's real setting and the prefer-lowest-remaining gate follows it. Before 1.2.5.6 the badge seemed to work on these printers only because it read Bambuddy's own print command echoed back, which always said off (#3040).

+ 59 - 0
backend/app/api/routes/archives.py

@@ -548,6 +548,65 @@ async def list_archives(
     return result
 
 
+@router.get("/last-per-printer", response_model=list[ArchiveResponse])
+async def list_last_archive_per_printer(
+    db: AsyncSession = Depends(get_db),
+    auth_result: tuple[User | None, bool] = Depends(
+        require_ownership_permission(
+            Permission.ARCHIVES_READ_ALL,
+            Permission.ARCHIVES_READ_OWN,
+        )
+    ),
+    printer_scope: PrinterScope = RequestPrinterScope,
+):
+    """The most recent archive of every printer, for the printer cards.
+
+    One query for the whole Printers page instead of one list request per card.
+    Leaves out the duplicate detection the full listing does: the card shows a
+    name and an outcome prompt, and on a farm that scan ran once per printer
+    on every page load.
+    """
+    user, can_read_all = auth_result
+    filters = [PrintArchive.deleted_at.is_(None), PrintArchive.printer_id.isnot(None)]
+    if user is not None and not can_read_all:
+        filters.append(PrintArchive.created_by_id == user.id)
+    # Only printers the caller may see (#1727)
+    if (clause := printer_scope.where(PrintArchive.printer_id)) is not None:
+        filters.append(clause)
+
+    ranked = (
+        select(
+            PrintArchive.id,
+            func.row_number()
+            .over(
+                partition_by=PrintArchive.printer_id,
+                # A reprint reuses its archive row, moving it to the printer it
+                # runs on with a fresh started_at, so the latest run start, not
+                # the row's age, tells which print a printer ran last.
+                order_by=(
+                    func.coalesce(PrintArchive.started_at, PrintArchive.created_at).desc(),
+                    PrintArchive.id.desc(),
+                ),
+            )
+            .label("rn"),
+        )
+        .where(*filters)
+        .subquery()
+    )
+
+    from sqlalchemy.orm import selectinload
+
+    result = await db.execute(
+        select(PrintArchive)
+        .options(selectinload(PrintArchive.project), selectinload(PrintArchive.created_by))
+        .where(PrintArchive.id.in_(select(ranked.c.id).where(ranked.c.rn == 1)))
+        .order_by(PrintArchive.printer_id)
+    )
+    archives = list(result.scalars().all())
+    run_aggregates = await _load_run_aggregates(db, [a.id for a in archives])
+    return [archive_to_response(a, run_aggregate=run_aggregates.get(a.id)) for a in archives]
+
+
 @router.get("/no-3mf-warning")
 async def no_3mf_warning(
     db: AsyncSession = Depends(get_db),

+ 164 - 0
backend/tests/integration/test_archives_last_per_printer.py

@@ -0,0 +1,164 @@
+"""GET /archives/last-per-printer -- the printer cards' "last print" in one request.
+
+The cards used to ask the full listing once per printer, with the arguments in
+the wrong order, so every answer was empty. The endpoint replaces those calls
+and must hand each printer its newest live archive, nothing hidden from the
+caller, and nothing another printer's card could mistake for its own.
+"""
+
+from __future__ import annotations
+
+from datetime import datetime, timedelta, timezone
+
+import pytest
+from httpx import AsyncClient
+
+pytestmark = [pytest.mark.asyncio, pytest.mark.integration]
+
+URL = "/api/v1/archives/last-per-printer"
+T0 = datetime(2026, 10, 1, 12, 0, tzinfo=timezone.utc)
+
+
+def _auth(jwt: str) -> dict[str, str]:
+    return {"Authorization": f"Bearer {jwt}"}
+
+
+async def _admin_token(async_client: AsyncClient) -> str:
+    await async_client.post(
+        "/api/v1/auth/setup",
+        json={"auth_enabled": True, "admin_username": "lastadmin", "admin_password": "AdminPass1!"},
+    )
+    login = await async_client.post("/api/v1/auth/login", json={"username": "lastadmin", "password": "AdminPass1!"})
+    assert login.status_code == 200, login.text
+    return login.json()["access_token"]
+
+
+async def _user(
+    async_client: AsyncClient,
+    admin_jwt: str,
+    username: str,
+    permissions: list[str],
+    printer_ids: list[int] | None = None,
+) -> tuple[str, int]:
+    group_ids = []
+    perms = await async_client.post(
+        "/api/v1/groups/", headers=_auth(admin_jwt), json={"name": f"perms_{username}", "permissions": permissions}
+    )
+    assert perms.status_code == 201, perms.text
+    group_ids.append(perms.json()["id"])
+    if printer_ids is not None:
+        team = await async_client.post(
+            "/api/v1/groups/",
+            headers=_auth(admin_jwt),
+            json={"name": f"team_{username}", "permissions": [], "restrict_printers": True, "printer_ids": printer_ids},
+        )
+        assert team.status_code == 201, team.text
+        group_ids.append(team.json()["id"])
+    created = await async_client.post(
+        "/api/v1/users/",
+        headers=_auth(admin_jwt),
+        json={"username": username, "password": "UserPass1!", "group_ids": group_ids},
+    )
+    assert created.status_code in (200, 201), created.text
+    login = await async_client.post("/api/v1/auth/login", json={"username": username, "password": "UserPass1!"})
+    assert login.status_code == 200, login.text
+    return login.json()["access_token"], created.json()["id"]
+
+
+async def test_newest_archive_of_each_printer(async_client, printer_factory, archive_factory):
+    a, b = await printer_factory(name="A"), await printer_factory(name="B")
+    await archive_factory(a.id, print_name="A old", created_at=T0)
+    await archive_factory(a.id, print_name="A new", created_at=T0 + timedelta(hours=2))
+    await archive_factory(a.id, print_name="A middle", created_at=T0 + timedelta(hours=1))
+    await archive_factory(b.id, print_name="B only", created_at=T0)
+
+    response = await async_client.get(URL)
+
+    assert response.status_code == 200, response.text
+    assert {row["printer_id"]: row["print_name"] for row in response.json()} == {a.id: "A new", b.id: "B only"}
+    assert len(response.json()) == 2
+
+
+async def test_reprint_of_an_older_archive_counts_as_last(async_client, printer_factory, archive_factory):
+    # A reprint reuses the archive row and only sets a fresh started_at, so the
+    # row's age says nothing about which print ran last.
+    printer = await printer_factory()
+    await archive_factory(printer.id, print_name="first", created_at=T0, started_at=T0 + timedelta(hours=5))
+    await archive_factory(
+        printer.id, print_name="second", created_at=T0 + timedelta(hours=1), started_at=T0 + timedelta(hours=1)
+    )
+
+    response = await async_client.get(URL)
+
+    assert response.status_code == 200, response.text
+    assert [row["print_name"] for row in response.json()] == ["first"]
+
+
+async def test_archive_never_started_ranks_by_creation(async_client, printer_factory, archive_factory):
+    printer = await printer_factory()
+    await archive_factory(printer.id, print_name="started", created_at=T0, started_at=T0)
+    await archive_factory(printer.id, print_name="never started", created_at=T0 + timedelta(hours=1))
+
+    response = await async_client.get(URL)
+
+    assert response.status_code == 200, response.text
+    assert [row["print_name"] for row in response.json()] == ["never started"]
+
+
+async def test_skips_soft_deleted_and_printerless_archives(async_client, printer_factory, archive_factory):
+    printer = await printer_factory()
+    await archive_factory(printer.id, print_name="kept", created_at=T0)
+    await archive_factory(printer.id, print_name="deleted", created_at=T0 + timedelta(hours=1), deleted_at=T0)
+    await archive_factory(None, print_name="no printer", created_at=T0 + timedelta(hours=2))
+
+    response = await async_client.get(URL)
+
+    assert response.status_code == 200, response.text
+    assert [(row["printer_id"], row["print_name"]) for row in response.json()] == [(printer.id, "kept")]
+
+
+async def test_printer_without_archives_is_absent(async_client, printer_factory):
+    await printer_factory()
+
+    response = await async_client.get(URL)
+
+    assert response.status_code == 200, response.text
+    assert response.json() == []
+
+
+async def test_team_member_gets_only_team_printers(async_client, printer_factory, archive_factory):
+    a, b = await printer_factory(name="A"), await printer_factory(name="B")
+    await archive_factory(a.id, print_name="team print", created_at=T0)
+    await archive_factory(b.id, print_name="hidden print", created_at=T0)
+    admin = await _admin_token(async_client)
+    jwt, _ = await _user(async_client, admin, "member", ["archives:read_all"], printer_ids=[a.id])
+
+    response = await async_client.get(URL, headers=_auth(jwt))
+
+    assert response.status_code == 200, response.text
+    assert [row["print_name"] for row in response.json()] == ["team print"]
+
+
+async def test_read_own_gets_its_newest_own_archive(async_client, printer_factory, archive_factory):
+    printer = await printer_factory()
+    admin = await _admin_token(async_client)
+    jwt, user_id = await _user(async_client, admin, "owner", ["archives:read_own"])
+    _, other_id = await _user(async_client, admin, "other", ["archives:read_own"])
+    await archive_factory(printer.id, print_name="mine", created_by_id=user_id, created_at=T0)
+    await archive_factory(printer.id, print_name="theirs", created_by_id=other_id, created_at=T0 + timedelta(hours=1))
+
+    response = await async_client.get(URL, headers=_auth(jwt))
+
+    assert response.status_code == 200, response.text
+    assert [row["print_name"] for row in response.json()] == ["mine"]
+
+
+async def test_needs_archive_read_permission(async_client, printer_factory, archive_factory):
+    printer = await printer_factory()
+    await archive_factory(printer.id, created_at=T0)
+    admin = await _admin_token(async_client)
+    jwt, _ = await _user(async_client, admin, "noarchives", ["printers:read"])
+
+    response = await async_client.get(URL, headers=_auth(jwt))
+
+    assert response.status_code == 403, response.text

+ 1 - 0
frontend/src/__tests__/mocks/handlers.ts

@@ -442,6 +442,7 @@ export const handlers = [
 
   // Lists → empty arrays
   http.get('/api/v1/archives/', () => HttpResponse.json([])),
+  http.get('/api/v1/archives/last-per-printer', () => HttpResponse.json([])),
   http.get('/api/v1/auth/oidc/providers', () => HttpResponse.json([])),
   http.get('/api/v1/auth/oidc/providers/all', () => HttpResponse.json([])),
   // OIDC icon proxy (#1333). Default returns a tiny PNG; individual tests

+ 20 - 2
frontend/src/__tests__/pages/PrintersPageCardVerdict.test.tsx

@@ -83,7 +83,7 @@ describe('PrintersPage — verdict on the card', () => {
       http.get('/api/v1/printers/:id/status', () => HttpResponse.json(status)),
       http.get('/api/v1/settings/ui-preferences', () => HttpResponse.json(uiPreferences)),
       http.get('/api/v1/settings/', () => HttpResponse.json({ ...uiPreferences, auto_archive: true })),
-      http.get('/api/v1/archives/', () => HttpResponse.json([finishedPrint])),
+      http.get('/api/v1/archives/last-per-printer', () => HttpResponse.json([finishedPrint])),
       http.patch('/api/v1/archives/:id', async ({ request }) => {
         const body = (await request.json()) as Record<string, unknown>;
         patched.push(body);
@@ -104,6 +104,24 @@ describe('PrintersPage — verdict on the card', () => {
     expect(await screen.findByText('Marked as good part')).toBeInTheDocument();
   });
 
+  // The card reads its row out of one page-wide answer; another printer's
+  // archive must not stand in for its own.
+  it('ignores the last print of another printer', async () => {
+    let served = false;
+    server.use(
+      http.get('/api/v1/archives/last-per-printer', () => {
+        served = true;
+        return HttpResponse.json([{ ...finishedPrint, id: 43, printer_id: 2 }]);
+      }),
+    );
+    render(<PrintersPage />);
+
+    await waitFor(() => expect(served).toBe(true));
+    expect(await screen.findByRole('button', { name: 'Mark plate as cleared' })).toBeInTheDocument();
+    expect(screen.queryByTitle('Good')).toBeNull();
+    expect(screen.queryByText(/Last: Bracket/)).toBeNull();
+  });
+
   it('sends the reject to the dialog and records nothing on its own', async () => {
     const user = userEvent.setup();
     render(<PrintersPage />);
@@ -146,7 +164,7 @@ describe('PrintersPage — verdict on the card', () => {
             created_at: '2026-08-18T00:00:00Z',
           });
         }),
-        http.get('/api/v1/archives/', () => {
+        http.get('/api/v1/archives/last-per-printer', () => {
           archiveServed = true;
           return HttpResponse.json([archive]);
         }),

+ 2 - 0
frontend/src/api/client.ts

@@ -5445,6 +5445,8 @@ export const api = {
     if (dateTo) params.set('date_to', dateTo);
     return request<Archive[]>(`/archives/?${params}`);
   },
+  // Latest archive of every printer in one request, for the printer cards.
+  getLastArchivePerPrinter: () => request<Archive[]>('/archives/last-per-printer'),
   getArchivesSlim: (dateFrom?: string, dateTo?: string, createdById?: number) => {
     const params = new URLSearchParams();
     if (dateFrom) params.set('date_from', dateFrom);

+ 2 - 0
frontend/src/pages/ArchivesPage.tsx

@@ -915,6 +915,7 @@ function ArchiveCard({
                 ? api.getArchivePlateThumbnail(archive.id, plates[displayPlateIndex]?.index ?? 0)
                 : api.getArchiveThumbnail(archive.id)
             }
+            loading="lazy"
             alt={archive.print_name || archive.filename}
             className="w-full h-full object-cover"
           />
@@ -2385,6 +2386,7 @@ function ArchiveListRow({
           {archive.thumbnail_path ? (
             <img
               src={api.getArchiveThumbnail(archive.id)}
+              loading="lazy"
               alt=""
               className="w-10 h-10 object-cover rounded"
             />

+ 4 - 0
frontend/src/pages/FileManagerPage.tsx

@@ -1183,6 +1183,7 @@ function FileCard({ file, isSelected, onSelect, onDelete, onDownload, onPrint, o
         {file.thumbnail_path ? (
           <img
             src={`${api.getLibraryFileThumbnailUrl(file.id)}${thumbnailVersion ? ((api.getLibraryFileThumbnailUrl(file.id).includes('?') ? '&' : '?') + `v=${thumbnailVersion}`) : ''}`}
+            loading="lazy"
             alt={file.filename}
             className="w-full h-full object-cover"
           />
@@ -1559,6 +1560,7 @@ function ColumnFileRow({ file, isSelected, isFocused, showModified, thumbnailVer
         {file.thumbnail_path ? (
           <img
             src={`${thumbnailUrl}${thumbnailVersion ? ((thumbnailUrl.includes('?') ? '&' : '?') + `v=${thumbnailVersion}`) : ''}`}
+            loading="lazy"
             alt=""
             className="w-full h-full object-cover"
           />
@@ -3734,6 +3736,7 @@ export function FileManagerPage() {
                           {file.thumbnail_path ? (
                             <img
                               src={`${api.getLibraryFileThumbnailUrl(file.id)}${thumbnailVersions[file.id] ? ((api.getLibraryFileThumbnailUrl(file.id).includes('?') ? '&' : '?') + `v=${thumbnailVersions[file.id]}`) : ''}`}
+                              loading="lazy"
                               alt=""
                               className="w-full h-full object-cover"
                             />
@@ -3749,6 +3752,7 @@ export function FileManagerPage() {
                             <div className="w-48 h-48 rounded-lg bg-bambu-dark-secondary border border-bambu-dark-tertiary shadow-xl overflow-hidden">
                               <img
                                 src={`${api.getLibraryFileThumbnailUrl(file.id)}${thumbnailVersions[file.id] ? ((api.getLibraryFileThumbnailUrl(file.id).includes('?') ? '&' : '?') + `v=${thumbnailVersions[file.id]}`) : ''}`}
+                                loading="lazy"
                                 alt={file.filename}
                                 className="w-full h-full object-contain"
                               />

+ 6 - 6
frontend/src/pages/PrintersPage.tsx

@@ -2598,13 +2598,13 @@ function PrinterCard({
   // Combine both sources: queue item user takes precedence, then reprint user
   const currentPrintUser = printingQueueItems?.[0]?.created_by_username || reprintUser?.username;
 
-  // Fetch last completed print for this printer
-  const { data: lastPrints } = useQuery({
-    queryKey: ['archives', printer.id, 'last'],
-    queryFn: () => api.getArchives(printer.id, 1, 0),
-    enabled: status?.connected && status?.state !== 'RUNNING',
+  // Last print of this printer. One shared request for every card on the page
+  // (the key is the same for all of them); each card picks its own row.
+  const { data: lastPrint } = useQuery({
+    queryKey: ['archives', 'last-per-printer'],
+    queryFn: () => api.getLastArchivePerPrinter(),
+    select: (archives) => archives.find((a) => a.printer_id === printer.id),
   });
-  const lastPrint = lastPrints?.[0];
   const isPrintingOrPaused = status?.state === 'RUNNING' || status?.state === 'PAUSE';
   const needsPlateClear = requirePlateClear && status?.awaiting_plate_clear === true;
   // Post-print outcome confirmation on the card (#1898): while the plate-clear

File diff suppressed because it is too large
+ 0 - 0
static/assets/AdditionalSection-CtnbDT0n.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/AmsUnitCard-CdKb_G_9.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/ArchivesPage-DuXjoXFE.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/AreaChart-5Jo0NTVy.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/AssignToAmsModal-MATupGfA.js


+ 1 - 1
static/assets/Button-pwVKPiYn.js → static/assets/Button-BAwcIdV7.js

@@ -1 +1 @@
-import{C as e}from"./client-BdOyoZJz.js";var t=e();function n({variant:e=`primary`,size:n=`md`,className:r=``,children:i,...a}){return(0,t.jsx)(`button`,{className:`inline-flex items-center justify-center font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-bambu-dark disabled:opacity-50 disabled:cursor-not-allowed ${{primary:`bg-bambu-green hover:bg-bambu-green-light text-white focus:ring-bambu-green`,secondary:`bg-bambu-dark-tertiary hover:bg-bambu-gray-dark text-white focus:ring-bambu-gray`,danger:`bg-red-600 hover:bg-red-700 text-white focus:ring-red-500`,ghost:`bg-transparent hover:bg-bambu-dark-tertiary text-bambu-gray-light hover:text-white`}[e]} ${{sm:`px-3 py-1.5 text-sm gap-1.5 min-h-[44px] md:min-h-0`,md:`px-4 py-2 text-sm gap-2 min-h-[44px] md:min-h-0`,lg:`px-6 py-3 text-base gap-2 min-h-[48px] md:min-h-0`}[n]} ${r}`,...a,children:i})}export{n as t};
+import{C as e}from"./client-D0Q3EIO2.js";var t=e();function n({variant:e=`primary`,size:n=`md`,className:r=``,children:i,...a}){return(0,t.jsx)(`button`,{className:`inline-flex items-center justify-center font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-bambu-dark disabled:opacity-50 disabled:cursor-not-allowed ${{primary:`bg-bambu-green hover:bg-bambu-green-light text-white focus:ring-bambu-green`,secondary:`bg-bambu-dark-tertiary hover:bg-bambu-gray-dark text-white focus:ring-bambu-gray`,danger:`bg-red-600 hover:bg-red-700 text-white focus:ring-red-500`,ghost:`bg-transparent hover:bg-bambu-dark-tertiary text-bambu-gray-light hover:text-white`}[e]} ${{sm:`px-3 py-1.5 text-sm gap-1.5 min-h-[44px] md:min-h-0`,md:`px-4 py-2 text-sm gap-2 min-h-[44px] md:min-h-0`,lg:`px-6 py-3 text-base gap-2 min-h-[48px] md:min-h-0`}[n]} ${r}`,...a,children:i})}export{n as t};

File diff suppressed because it is too large
+ 0 - 0
static/assets/CamWallPage-7LOH3GGc.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/CameraDiagnoseModal-CfEhlk-3.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/CameraPage-1gEpM7YE.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/CameraWall-DFHo23uI.js


+ 1 - 1
static/assets/Card-OUAj0Ayh.js → static/assets/Card-Bs7yK0-y.js

@@ -1 +1 @@
-import{i as e}from"./chunk-aKtaBQYM.js";import{C as t,D as n}from"./client-BdOyoZJz.js";var r=e(n(),1),i=t(),a=(0,r.createContext)(`normal`);function o({density:e,children:t}){return(0,i.jsx)(a.Provider,{value:e,children:t})}function s({children:e,className:t=``,onClick:n,onContextMenu:r,...a}){return(0,i.jsx)(`div`,{className:`bg-bambu-dark-secondary rounded-xl border border-bambu-dark-tertiary card-shadow ${n?`cursor-pointer`:``} ${t}`,onClick:n,onContextMenu:r,...a,children:e})}function c({children:e,className:t=``,dense:n}){let o=(0,r.useContext)(a)===`dense`;return(0,i.jsx)(`div`,{className:`${n??o?`px-4 py-2.5`:`px-6 py-4`} border-b border-bambu-dark-tertiary ${t}`,children:e})}function l({children:e,className:t=``,dense:n}){let o=(0,r.useContext)(a)===`dense`;return(0,i.jsx)(`div`,{className:`${n??o?`p-4`:`p-6`} ${t}`,children:e})}export{c as i,l as n,o as r,s as t};
+import{i as e}from"./chunk-aKtaBQYM.js";import{C as t,D as n}from"./client-D0Q3EIO2.js";var r=e(n(),1),i=t(),a=(0,r.createContext)(`normal`);function o({density:e,children:t}){return(0,i.jsx)(a.Provider,{value:e,children:t})}function s({children:e,className:t=``,onClick:n,onContextMenu:r,...a}){return(0,i.jsx)(`div`,{className:`bg-bambu-dark-secondary rounded-xl border border-bambu-dark-tertiary card-shadow ${n?`cursor-pointer`:``} ${t}`,onClick:n,onContextMenu:r,...a,children:e})}function c({children:e,className:t=``,dense:n}){let o=(0,r.useContext)(a)===`dense`;return(0,i.jsx)(`div`,{className:`${n??o?`px-4 py-2.5`:`px-6 py-4`} border-b border-bambu-dark-tertiary ${t}`,children:e})}function l({children:e,className:t=``,dense:n}){let o=(0,r.useContext)(a)===`dense`;return(0,i.jsx)(`div`,{className:`${n??o?`p-4`:`p-6`} ${t}`,children:e})}export{c as i,l as n,o as r,s as t};

File diff suppressed because it is too large
+ 0 - 0
static/assets/CartesianChart-CkznuDC2.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/ColumnConfigModal-Bkb2EWX8.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/ConfigureAmsSlotModal-C8Vb6jND.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/ConnectAuthorizePage-BOrVE2dw.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/ContextMenu-B4p7RmJK.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/CopyButton-DKdfYD-W.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/ErrorBarContext-BH62r7Af.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/ExternalLinkPage-Dcal4COV.js


File diff suppressed because it is too large
+ 0 - 1
static/assets/FileManagerPage-ChtsL-ib.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/FileUploadModal-BIO_Tg0j.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/FinancePage-DqPYqSQw.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/GCodeViewerPage-D3DIVv_o.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/GcodeToolpathViewer-DG-G795p.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/GroupEditPage-C5Z1fwVG.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/ImagePreviewModal-0kUOGDQR.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/InventoryPage-tEyY2-BI.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/LibraryTrashPage-C_dj2Ay-.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/LoginPage-CSpD-Tv8.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/MaintenancePage-GGpHlk7X.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/ModelSourcesPage-CRS2vJpg.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/NotificationsPage-TaC-DXAi.js


+ 1 - 1
static/assets/OverlayFrame-BUFy7NI1.js → static/assets/OverlayFrame-BJ-Bdt_w.js

@@ -1 +1 @@
-import{i as e}from"./chunk-aKtaBQYM.js";import{C as t,D as n,a as r}from"./client-BdOyoZJz.js";var i=e(n(),1);function a(e,t=null,n=0){let[a,o]=(0,i.useState)(null);return(0,i.useEffect)(()=>{if(!e)return;let i=new AbortController,a;return r.getOverlayLogo(t,i.signal).then(e=>{i.signal.aborted||(e?(a=URL.createObjectURL(e),o({url:a,token:t,revision:n})):o(null))}).catch(()=>{i.signal.aborted||o(null)}),()=>{i.abort(),a&&URL.revokeObjectURL(a)}},[e,t,n]),e&&a?.token===t&&a.revision===n?a.url:null}var o={logo:!1,logoRevision:0,from:``,to:``};function s(e){return/^#[0-9a-f]{6}$/i.test(e)}function c(e,t){return e&&t&&s(e)&&s(t)?`linear-gradient(to right, ${e}, ${t})`:void 0}function l(e){if(e)return{backgroundImage:e,backgroundClip:`text`,WebkitBackgroundClip:`text`,color:`transparent`,WebkitTextFillColor:`transparent`}}var u={landscape:{width:1920,height:1080},portrait:{width:1080,height:1920}},d=t();function f({layout:e,preview:t=!1,children:n}){let r=(0,i.useRef)(null),[a,o]=(0,i.useState)(0),{width:s,height:c}=u[e];(0,i.useLayoutEffect)(()=>{let e=r.current;if(!e)return;let t=()=>o(Math.min(e.clientWidth/s,e.clientHeight/c));if(t(),typeof ResizeObserver>`u`)return window.addEventListener(`resize`,t),()=>window.removeEventListener(`resize`,t);let n=new ResizeObserver(t);return n.observe(e),()=>n.disconnect()},[s,c]);let l={width:s,height:c,"--overlay-vmin":`10.8px`,"--overlay-height":`${c}px`,position:`absolute`,top:`50%`,left:`50%`,transform:`translate(-50%, -50%) scale(${a})`,transformOrigin:`center`};return(0,d.jsx)(`div`,{ref:r,className:t?`relative w-full overflow-hidden`:`fixed inset-0 overflow-hidden`,style:t?{aspectRatio:`${s} / ${c}`}:void 0,children:(0,d.jsx)(`div`,{style:l,children:n})})}export{c as a,s as i,u as n,l as o,o as r,a as s,f as t};
+import{i as e}from"./chunk-aKtaBQYM.js";import{C as t,D as n,a as r}from"./client-D0Q3EIO2.js";var i=e(n(),1);function a(e,t=null,n=0){let[a,o]=(0,i.useState)(null);return(0,i.useEffect)(()=>{if(!e)return;let i=new AbortController,a;return r.getOverlayLogo(t,i.signal).then(e=>{i.signal.aborted||(e?(a=URL.createObjectURL(e),o({url:a,token:t,revision:n})):o(null))}).catch(()=>{i.signal.aborted||o(null)}),()=>{i.abort(),a&&URL.revokeObjectURL(a)}},[e,t,n]),e&&a?.token===t&&a.revision===n?a.url:null}var o={logo:!1,logoRevision:0,from:``,to:``};function s(e){return/^#[0-9a-f]{6}$/i.test(e)}function c(e,t){return e&&t&&s(e)&&s(t)?`linear-gradient(to right, ${e}, ${t})`:void 0}function l(e){if(e)return{backgroundImage:e,backgroundClip:`text`,WebkitBackgroundClip:`text`,color:`transparent`,WebkitTextFillColor:`transparent`}}var u={landscape:{width:1920,height:1080},portrait:{width:1080,height:1920}},d=t();function f({layout:e,preview:t=!1,children:n}){let r=(0,i.useRef)(null),[a,o]=(0,i.useState)(0),{width:s,height:c}=u[e];(0,i.useLayoutEffect)(()=>{let e=r.current;if(!e)return;let t=()=>o(Math.min(e.clientWidth/s,e.clientHeight/c));if(t(),typeof ResizeObserver>`u`)return window.addEventListener(`resize`,t),()=>window.removeEventListener(`resize`,t);let n=new ResizeObserver(t);return n.observe(e),()=>n.disconnect()},[s,c]);let l={width:s,height:c,"--overlay-vmin":`10.8px`,"--overlay-height":`${c}px`,position:`absolute`,top:`50%`,left:`50%`,transform:`translate(-50%, -50%) scale(${a})`,transformOrigin:`center`};return(0,d.jsx)(`div`,{ref:r,className:t?`relative w-full overflow-hidden`:`fixed inset-0 overflow-hidden`,style:t?{aspectRatio:`${s} / ${c}`}:void 0,children:(0,d.jsx)(`div`,{style:l,children:n})})}export{c as a,s as i,u as n,l as o,o as r,a as s,f as t};

File diff suppressed because it is too large
+ 0 - 1
static/assets/PdfPreviewModal-DEN6pYx-.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/PhotoGalleryModal-ytbp2Lrq.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/PrinterLocationsPage-Dilmz8B6.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/PrintersPage-BUOWC7Nf.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/ProfilesPage-DG48uW4z.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/ProjectDetailPage-BCid3Jam.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/ProjectsPage-C35W0r_D.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/QueryClientProvider-CsMjD-7g.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/QueuePage-Kv8gGfNb.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/ReferenceLine-ytCyPKIK.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/RichTextEditor-BNxt1eBM.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/SettingsPage-D5v6IZ1Y.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/SetupPage-DsXlcXZ-.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/SliceModal-C00u-1ny.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/SpoolBuddyAmsPage-DFgy2Ic8.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/SpoolBuddyCalibrationPage-CuPYbkCV.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/SpoolBuddyDashboard-C00DI1mz.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/SpoolBuddyInventoryPage-N471Fx9x.js


File diff suppressed because it is too large
+ 1 - 1
static/assets/SpoolBuddySettingsPage-DDNvVsrG.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/SpoolBuddyWriteTagPage-BWqB5s__.js


+ 1 - 1
static/assets/SpoolIcon-OZKzbEc8.js → static/assets/SpoolIcon-vvNL1rED.js

@@ -1 +1 @@
-import{i as e}from"./chunk-aKtaBQYM.js";import{C as t,D as n}from"./client-BdOyoZJz.js";import{n as r}from"./filamentSwatchHelpers-D3oXQSGk.js";import{t as i}from"./spoolPaint-CrvpHqdD.js";var a=e(n(),1),o=t();function s({spool:e,inset:t,size:n,border:i}){let s=n>=80?`card`:`preview`,c=(0,a.useMemo)(()=>r({effectSize:s,rgba:e.rgba,extraColors:e.extra_colors,effectType:e.effect_type,subtype:e.subtype}),[s,e.rgba,e.extra_colors,e.effect_type,e.subtype]),l=`${t*100}%`;return(0,o.jsx)(`div`,{"data-testid":`spool-paint`,className:`absolute rounded-full box-border`,style:{top:l,left:l,right:l,bottom:l,...c,backgroundPosition:`center`,border:i}})}function c({inset:e}){let t=`${e*100}%`;return(0,o.jsx)(`div`,{"data-testid":`spool-shade`,className:`absolute rounded-full`,style:{top:t,left:t,right:t,bottom:t,backgroundColor:`rgba(0, 0, 0, 0.15)`}})}function l({color:e,isEmpty:t,size:n=32,spool:r}){return t?(0,o.jsx)(`div`,{className:`rounded-full border-2 border-dashed border-zinc-500 flex items-center justify-center`,style:{width:n,height:n},children:(0,o.jsx)(`div`,{className:`w-2 h-2 rounded-full bg-zinc-600`})}):i(r)?(0,o.jsxs)(`div`,{className:`relative shrink-0`,style:{width:n,height:n},children:[(0,o.jsx)(s,{spool:r,size:n,inset:2/32,border:`${1.5*n/32}px solid rgba(255, 255, 255, 0.7)`}),(0,o.jsx)(c,{inset:5/32})]}):(0,o.jsxs)(`svg`,{width:n,height:n,viewBox:`0 0 32 32`,children:[(0,o.jsx)(`circle`,{cx:`16`,cy:`16`,r:`14`,fill:e,stroke:`white`,strokeWidth:`1.5`,strokeOpacity:`0.7`}),(0,o.jsx)(`circle`,{cx:`16`,cy:`16`,r:`11`,fill:e,style:{filter:`brightness(0.85)`}})]})}export{s as n,c as r,l as t};
+import{i as e}from"./chunk-aKtaBQYM.js";import{C as t,D as n}from"./client-D0Q3EIO2.js";import{n as r}from"./filamentSwatchHelpers-D3oXQSGk.js";import{t as i}from"./spoolPaint-CrvpHqdD.js";var a=e(n(),1),o=t();function s({spool:e,inset:t,size:n,border:i}){let s=n>=80?`card`:`preview`,c=(0,a.useMemo)(()=>r({effectSize:s,rgba:e.rgba,extraColors:e.extra_colors,effectType:e.effect_type,subtype:e.subtype}),[s,e.rgba,e.extra_colors,e.effect_type,e.subtype]),l=`${t*100}%`;return(0,o.jsx)(`div`,{"data-testid":`spool-paint`,className:`absolute rounded-full box-border`,style:{top:l,left:l,right:l,bottom:l,...c,backgroundPosition:`center`,border:i}})}function c({inset:e}){let t=`${e*100}%`;return(0,o.jsx)(`div`,{"data-testid":`spool-shade`,className:`absolute rounded-full`,style:{top:t,left:t,right:t,bottom:t,backgroundColor:`rgba(0, 0, 0, 0.15)`}})}function l({color:e,isEmpty:t,size:n=32,spool:r}){return t?(0,o.jsx)(`div`,{className:`rounded-full border-2 border-dashed border-zinc-500 flex items-center justify-center`,style:{width:n,height:n},children:(0,o.jsx)(`div`,{className:`w-2 h-2 rounded-full bg-zinc-600`})}):i(r)?(0,o.jsxs)(`div`,{className:`relative shrink-0`,style:{width:n,height:n},children:[(0,o.jsx)(s,{spool:r,size:n,inset:2/32,border:`${1.5*n/32}px solid rgba(255, 255, 255, 0.7)`}),(0,o.jsx)(c,{inset:5/32})]}):(0,o.jsxs)(`svg`,{width:n,height:n,viewBox:`0 0 32 32`,children:[(0,o.jsx)(`circle`,{cx:`16`,cy:`16`,r:`14`,fill:e,stroke:`white`,strokeWidth:`1.5`,strokeOpacity:`0.7`}),(0,o.jsx)(`circle`,{cx:`16`,cy:`16`,r:`11`,fill:e,style:{filter:`brightness(0.85)`}})]})}export{s as n,c as r,l as t};

File diff suppressed because it is too large
+ 0 - 0
static/assets/SpreadsheetPreviewModal-Cv7mkQF1.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/StatsPage-D7sKI4LP.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/StreamOverlayPage-DP6GThH2.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/SystemInfoPage-rtf4xILj.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/ToastContext-DvXi5snE.js


+ 1 - 1
static/assets/Toggle-CwMiiK0g.js → static/assets/Toggle-I-VDBGwl.js

@@ -1 +1 @@
-import{C as e}from"./client-BdOyoZJz.js";var t=e();function n({checked:e,onChange:n,disabled:r}){return(0,t.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":e,disabled:r,onClick:t=>{t.preventDefault(),t.stopPropagation(),r||n(!e)},className:`relative inline-flex w-11 h-7 md:w-9 md:h-5 rounded-full transition-colors flex-shrink-0 focus:outline-none focus:ring-2 focus:ring-bambu-green focus:ring-offset-2 focus:ring-offset-bambu-dark ${r?`bg-bambu-dark-tertiary/50 cursor-not-allowed opacity-50`:e?`bg-bambu-green cursor-pointer`:`bg-bambu-dark-tertiary cursor-pointer hover:bg-bambu-dark-tertiary/80`}`,children:(0,t.jsx)(`span`,{className:`pointer-events-none absolute top-[3px] md:top-[2px] left-[3px] md:left-[2px] w-5 h-5 md:w-4 md:h-4 bg-white rounded-full shadow transition-transform duration-200 ease-in-out ${e?`translate-x-4`:`translate-x-0`}`})})}export{n as t};
+import{C as e}from"./client-D0Q3EIO2.js";var t=e();function n({checked:e,onChange:n,disabled:r}){return(0,t.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":e,disabled:r,onClick:t=>{t.preventDefault(),t.stopPropagation(),r||n(!e)},className:`relative inline-flex w-11 h-7 md:w-9 md:h-5 rounded-full transition-colors flex-shrink-0 focus:outline-none focus:ring-2 focus:ring-bambu-green focus:ring-offset-2 focus:ring-offset-bambu-dark ${r?`bg-bambu-dark-tertiary/50 cursor-not-allowed opacity-50`:e?`bg-bambu-green cursor-pointer`:`bg-bambu-dark-tertiary cursor-pointer hover:bg-bambu-dark-tertiary/80`}`,children:(0,t.jsx)(`span`,{className:`pointer-events-none absolute top-[3px] md:top-[2px] left-[3px] md:left-[2px] w-5 h-5 md:w-4 md:h-4 bg-white rounded-full shadow transition-transform duration-200 ease-in-out ${e?`translate-x-4`:`translate-x-0`}`})})}export{n as t};

+ 1 - 0
static/assets/arrow-down--cYuQXi2.js

@@ -0,0 +1 @@
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`arrow-down`,[[`path`,{d:`M12 5v14`,key:`s699le`}],[`path`,{d:`m19 12-7 7-7-7`,key:`1idqje`}]]);export{t};

+ 0 - 1
static/assets/arrow-down-C4OBNDqJ.js

@@ -1 +0,0 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`arrow-down`,[[`path`,{d:`M12 5v14`,key:`s699le`}],[`path`,{d:`m19 12-7 7-7-7`,key:`1idqje`}]]);export{t};

+ 1 - 0
static/assets/arrow-left-DMgVJlsY.js

@@ -0,0 +1 @@
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`arrow-left`,[[`path`,{d:`m12 19-7-7 7-7`,key:`1l729n`}],[`path`,{d:`M19 12H5`,key:`x3x0zl`}]]);export{t};

+ 0 - 1
static/assets/arrow-left-MSgMxOFV.js

@@ -1 +0,0 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`arrow-left`,[[`path`,{d:`m12 19-7-7 7-7`,key:`1l729n`}],[`path`,{d:`M19 12H5`,key:`x3x0zl`}]]);export{t};

+ 1 - 0
static/assets/arrow-right-BHLBfK4j.js

@@ -0,0 +1 @@
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`arrow-right`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`m12 5 7 7-7 7`,key:`xquz4c`}]]);export{t};

+ 0 - 1
static/assets/arrow-right-Da96kh4S.js

@@ -1 +0,0 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`arrow-right`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`m12 5 7 7-7 7`,key:`xquz4c`}]]);export{t};

+ 1 - 0
static/assets/arrow-up-DAnOQUuf.js

@@ -0,0 +1 @@
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`arrow-up`,[[`path`,{d:`m5 12 7-7 7 7`,key:`hav0vg`}],[`path`,{d:`M12 19V5`,key:`x0mq9r`}]]);export{t};

+ 0 - 1
static/assets/arrow-up-Dam8cLfE.js

@@ -1 +0,0 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`arrow-up`,[[`path`,{d:`m5 12 7-7 7 7`,key:`hav0vg`}],[`path`,{d:`M12 19V5`,key:`x0mq9r`}]]);export{t};

+ 1 - 1
static/assets/arrow-up-down-C-1Kkt1x.js → static/assets/arrow-up-down-MZZbOqYJ.js

@@ -1 +1 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`arrow-up-down`,[[`path`,{d:`m21 16-4 4-4-4`,key:`f6ql7i`}],[`path`,{d:`M17 20V4`,key:`1ejh1v`}],[`path`,{d:`m3 8 4-4 4 4`,key:`11wl7u`}],[`path`,{d:`M7 4v16`,key:`1glfcx`}]]);export{t};
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`arrow-up-down`,[[`path`,{d:`m21 16-4 4-4-4`,key:`f6ql7i`}],[`path`,{d:`M17 20V4`,key:`1ejh1v`}],[`path`,{d:`m3 8 4-4 4 4`,key:`11wl7u`}],[`path`,{d:`M7 4v16`,key:`1glfcx`}]]);export{t};

+ 1 - 1
static/assets/box-BIRPxdgi.js → static/assets/box-9OC1sZAb.js

@@ -1 +1 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`box`,[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]);export{t};
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`box`,[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]);export{t};

+ 1 - 1
static/assets/briefcase-BmuFBTLZ.js → static/assets/briefcase-Yoce9QZe.js

@@ -1 +1 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`briefcase`,[[`path`,{d:`M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16`,key:`jecpp`}],[`rect`,{width:`20`,height:`14`,x:`2`,y:`6`,rx:`2`,key:`i6l2r4`}]]);export{t};
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`briefcase`,[[`path`,{d:`M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16`,key:`jecpp`}],[`rect`,{width:`20`,height:`14`,x:`2`,y:`6`,rx:`2`,key:`i6l2r4`}]]);export{t};

+ 1 - 1
static/assets/calendar-DiVEdzUw.js → static/assets/calendar-CLfoE-ho.js

@@ -1 +1 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`calendar`,[[`path`,{d:`M8 2v4`,key:`1cmpym`}],[`path`,{d:`M16 2v4`,key:`4m81vk`}],[`rect`,{width:`18`,height:`18`,x:`3`,y:`4`,rx:`2`,key:`1hopcy`}],[`path`,{d:`M3 10h18`,key:`8toen8`}]]);export{t};
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`calendar`,[[`path`,{d:`M8 2v4`,key:`1cmpym`}],[`path`,{d:`M16 2v4`,key:`4m81vk`}],[`rect`,{width:`18`,height:`18`,x:`3`,y:`4`,rx:`2`,key:`1hopcy`}],[`path`,{d:`M3 10h18`,key:`8toen8`}]]);export{t};

+ 0 - 1
static/assets/check-D1Pn8T1J.js

@@ -1 +0,0 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`check`,[[`path`,{d:`M20 6 9 17l-5-5`,key:`1gmf2c`}]]);export{t};

+ 1 - 0
static/assets/check-lecuNcPc.js

@@ -0,0 +1 @@
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`check`,[[`path`,{d:`M20 6 9 17l-5-5`,key:`1gmf2c`}]]);export{t};

+ 1 - 1
static/assets/chevrons-right-OnQ-9jKz.js → static/assets/chevrons-right-BtGjiArF.js

@@ -1 +1 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`chevrons-left`,[[`path`,{d:`m11 17-5-5 5-5`,key:`13zhaf`}],[`path`,{d:`m18 17-5-5 5-5`,key:`h8a8et`}]]),n=e(`chevrons-right`,[[`path`,{d:`m6 17 5-5-5-5`,key:`xnjwq`}],[`path`,{d:`m13 17 5-5-5-5`,key:`17xmmf`}]]);export{t as n,n as t};
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`chevrons-left`,[[`path`,{d:`m11 17-5-5 5-5`,key:`13zhaf`}],[`path`,{d:`m18 17-5-5 5-5`,key:`h8a8et`}]]),n=e(`chevrons-right`,[[`path`,{d:`m6 17 5-5-5-5`,key:`xnjwq`}],[`path`,{d:`m13 17 5-5-5-5`,key:`17xmmf`}]]);export{t as n,n as t};

File diff suppressed because it is too large
+ 0 - 0
static/assets/client-BdOyoZJz.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/client-D0Q3EIO2.js


+ 1 - 1
static/assets/cloud-off-DmnG-KIw.js → static/assets/cloud-off-CvdQNl0K.js

@@ -1 +1 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`cloud-off`,[[`path`,{d:`m2 2 20 20`,key:`1ooewy`}],[`path`,{d:`M5.782 5.782A7 7 0 0 0 9 19h8.5a4.5 4.5 0 0 0 1.307-.193`,key:`yfwify`}],[`path`,{d:`M21.532 16.5A4.5 4.5 0 0 0 17.5 10h-1.79A7.008 7.008 0 0 0 10 5.07`,key:`jlfiyv`}]]);export{t};
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`cloud-off`,[[`path`,{d:`m2 2 20 20`,key:`1ooewy`}],[`path`,{d:`M5.782 5.782A7 7 0 0 0 9 19h8.5a4.5 4.5 0 0 0 1.307-.193`,key:`yfwify`}],[`path`,{d:`M21.532 16.5A4.5 4.5 0 0 0 17.5 10h-1.79A7.008 7.008 0 0 0 10 5.07`,key:`jlfiyv`}]]);export{t};

+ 1 - 1
static/assets/cog-pa-nvQzt.js → static/assets/cog-rWTLMCB1.js

@@ -1 +1 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`cog`,[[`path`,{d:`M11 10.27 7 3.34`,key:`16pf9h`}],[`path`,{d:`m11 13.73-4 6.93`,key:`794ttg`}],[`path`,{d:`M12 22v-2`,key:`1osdcq`}],[`path`,{d:`M12 2v2`,key:`tus03m`}],[`path`,{d:`M14 12h8`,key:`4f43i9`}],[`path`,{d:`m17 20.66-1-1.73`,key:`eq3orb`}],[`path`,{d:`m17 3.34-1 1.73`,key:`2wel8s`}],[`path`,{d:`M2 12h2`,key:`1t8f8n`}],[`path`,{d:`m20.66 17-1.73-1`,key:`sg0v6f`}],[`path`,{d:`m20.66 7-1.73 1`,key:`1ow05n`}],[`path`,{d:`m3.34 17 1.73-1`,key:`nuk764`}],[`path`,{d:`m3.34 7 1.73 1`,key:`1ulond`}],[`circle`,{cx:`12`,cy:`12`,r:`2`,key:`1c9p78`}],[`circle`,{cx:`12`,cy:`12`,r:`8`,key:`46899m`}]]);export{t};
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`cog`,[[`path`,{d:`M11 10.27 7 3.34`,key:`16pf9h`}],[`path`,{d:`m11 13.73-4 6.93`,key:`794ttg`}],[`path`,{d:`M12 22v-2`,key:`1osdcq`}],[`path`,{d:`M12 2v2`,key:`tus03m`}],[`path`,{d:`M14 12h8`,key:`4f43i9`}],[`path`,{d:`m17 20.66-1-1.73`,key:`eq3orb`}],[`path`,{d:`m17 3.34-1 1.73`,key:`2wel8s`}],[`path`,{d:`M2 12h2`,key:`1t8f8n`}],[`path`,{d:`m20.66 17-1.73-1`,key:`sg0v6f`}],[`path`,{d:`m20.66 7-1.73 1`,key:`1ow05n`}],[`path`,{d:`m3.34 17 1.73-1`,key:`nuk764`}],[`path`,{d:`m3.34 7 1.73 1`,key:`1ulond`}],[`circle`,{cx:`12`,cy:`12`,r:`2`,key:`1c9p78`}],[`circle`,{cx:`12`,cy:`12`,r:`8`,key:`46899m`}]]);export{t};

+ 1 - 1
static/assets/coins-6tqy9spE.js → static/assets/coins-dkDEbZk6.js

@@ -1 +1 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`coins`,[[`circle`,{cx:`8`,cy:`8`,r:`6`,key:`3yglwk`}],[`path`,{d:`M18.09 10.37A6 6 0 1 1 10.34 18`,key:`t5s6rm`}],[`path`,{d:`M7 6h1v4`,key:`1obek4`}],[`path`,{d:`m16.71 13.88.7.71-2.82 2.82`,key:`1rbuyh`}]]);export{t};
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`coins`,[[`circle`,{cx:`8`,cy:`8`,r:`6`,key:`3yglwk`}],[`path`,{d:`M18.09 10.37A6 6 0 1 1 10.34 18`,key:`t5s6rm`}],[`path`,{d:`M7 6h1v4`,key:`1obek4`}],[`path`,{d:`m16.71 13.88.7.71-2.82 2.82`,key:`1rbuyh`}]]);export{t};

+ 1 - 0
static/assets/columns-2-4ppMhNZX.js

@@ -0,0 +1 @@
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`columns-2`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`M12 3v18`,key:`108xh3`}]]);export{t};

+ 0 - 1
static/assets/columns-2-CGEUxYp_.js

@@ -1 +0,0 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`columns-2`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`M12 3v18`,key:`108xh3`}]]);export{t};

+ 1 - 1
static/assets/copy-3N5VKzXz.js → static/assets/copy-BSydjjpn.js

@@ -1 +1 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`copy`,[[`rect`,{width:`14`,height:`14`,x:`8`,y:`8`,rx:`2`,ry:`2`,key:`17jyea`}],[`path`,{d:`M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2`,key:`zix9uf`}]]);export{t};
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`copy`,[[`rect`,{width:`14`,height:`14`,x:`8`,y:`8`,rx:`2`,ry:`2`,key:`17jyea`}],[`path`,{d:`M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2`,key:`zix9uf`}]]);export{t};

+ 1 - 1
static/assets/cpu-DAX4KhDZ.js → static/assets/cpu-BsH-qpUx.js

@@ -1 +1 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`cpu`,[[`path`,{d:`M12 20v2`,key:`1lh1kg`}],[`path`,{d:`M12 2v2`,key:`tus03m`}],[`path`,{d:`M17 20v2`,key:`1rnc9c`}],[`path`,{d:`M17 2v2`,key:`11trls`}],[`path`,{d:`M2 12h2`,key:`1t8f8n`}],[`path`,{d:`M2 17h2`,key:`7oei6x`}],[`path`,{d:`M2 7h2`,key:`asdhe0`}],[`path`,{d:`M20 12h2`,key:`1q8mjw`}],[`path`,{d:`M20 17h2`,key:`1fpfkl`}],[`path`,{d:`M20 7h2`,key:`1o8tra`}],[`path`,{d:`M7 20v2`,key:`4gnj0m`}],[`path`,{d:`M7 2v2`,key:`1i4yhu`}],[`rect`,{x:`4`,y:`4`,width:`16`,height:`16`,rx:`2`,key:`1vbyd7`}],[`rect`,{x:`8`,y:`8`,width:`8`,height:`8`,rx:`1`,key:`z9xiuo`}]]);export{t};
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`cpu`,[[`path`,{d:`M12 20v2`,key:`1lh1kg`}],[`path`,{d:`M12 2v2`,key:`tus03m`}],[`path`,{d:`M17 20v2`,key:`1rnc9c`}],[`path`,{d:`M17 2v2`,key:`11trls`}],[`path`,{d:`M2 12h2`,key:`1t8f8n`}],[`path`,{d:`M2 17h2`,key:`7oei6x`}],[`path`,{d:`M2 7h2`,key:`asdhe0`}],[`path`,{d:`M20 12h2`,key:`1q8mjw`}],[`path`,{d:`M20 17h2`,key:`1fpfkl`}],[`path`,{d:`M20 7h2`,key:`1o8tra`}],[`path`,{d:`M7 20v2`,key:`4gnj0m`}],[`path`,{d:`M7 2v2`,key:`1i4yhu`}],[`rect`,{x:`4`,y:`4`,width:`16`,height:`16`,rx:`2`,key:`1vbyd7`}],[`rect`,{x:`8`,y:`8`,width:`8`,height:`8`,rx:`1`,key:`z9xiuo`}]]);export{t};

+ 1 - 1
static/assets/createLucideIcon-Yo2YoYjm.js → static/assets/createLucideIcon-BTg337Gy.js

@@ -1 +1 @@
-import{i as e}from"./chunk-aKtaBQYM.js";import{D as t}from"./client-BdOyoZJz.js";var n=e(t()),r=e=>e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase(),i=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,t,n)=>n?n.toUpperCase():t.toLowerCase()),a=e=>{let t=i(e);return t.charAt(0).toUpperCase()+t.slice(1)},o=(...e)=>e.filter((e,t,n)=>!!e&&e.trim()!==``&&n.indexOf(e)===t).join(` `).trim(),s=e=>{for(let t in e)if(t.startsWith(`aria-`)||t===`role`||t===`title`)return!0},c={xmlns:`http://www.w3.org/2000/svg`,width:24,height:24,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:2,strokeLinecap:`round`,strokeLinejoin:`round`},l=(0,n.forwardRef)(({color:e=`currentColor`,size:t=24,strokeWidth:r=2,absoluteStrokeWidth:i,className:a=``,children:l,iconNode:u,...d},f)=>(0,n.createElement)(`svg`,{ref:f,...c,width:t,height:t,stroke:e,strokeWidth:i?Number(r)*24/Number(t):r,className:o(`lucide`,a),...!l&&!s(d)&&{"aria-hidden":`true`},...d},[...u.map(([e,t])=>(0,n.createElement)(e,t)),...Array.isArray(l)?l:[l]])),u=(e,t)=>{let i=(0,n.forwardRef)(({className:i,...s},c)=>(0,n.createElement)(l,{ref:c,iconNode:t,className:o(`lucide-${r(a(e))}`,`lucide-${e}`,i),...s}));return i.displayName=a(e),i};export{u as t};
+import{i as e}from"./chunk-aKtaBQYM.js";import{D as t}from"./client-D0Q3EIO2.js";var n=e(t()),r=e=>e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase(),i=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,t,n)=>n?n.toUpperCase():t.toLowerCase()),a=e=>{let t=i(e);return t.charAt(0).toUpperCase()+t.slice(1)},o=(...e)=>e.filter((e,t,n)=>!!e&&e.trim()!==``&&n.indexOf(e)===t).join(` `).trim(),s=e=>{for(let t in e)if(t.startsWith(`aria-`)||t===`role`||t===`title`)return!0},c={xmlns:`http://www.w3.org/2000/svg`,width:24,height:24,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:2,strokeLinecap:`round`,strokeLinejoin:`round`},l=(0,n.forwardRef)(({color:e=`currentColor`,size:t=24,strokeWidth:r=2,absoluteStrokeWidth:i,className:a=``,children:l,iconNode:u,...d},f)=>(0,n.createElement)(`svg`,{ref:f,...c,width:t,height:t,stroke:e,strokeWidth:i?Number(r)*24/Number(t):r,className:o(`lucide`,a),...!l&&!s(d)&&{"aria-hidden":`true`},...d},[...u.map(([e,t])=>(0,n.createElement)(e,t)),...Array.isArray(l)?l:[l]])),u=(e,t)=>{let i=(0,n.forwardRef)(({className:i,...s},c)=>(0,n.createElement)(l,{ref:c,iconNode:t,className:o(`lucide-${r(a(e))}`,`lucide-${e}`,i),...s}));return i.displayName=a(e),i};export{u as t};

+ 1 - 1
static/assets/dollar-sign-ChtX2KHo.js → static/assets/dollar-sign-Cn5pcyDA.js

@@ -1 +1 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`dollar-sign`,[[`line`,{x1:`12`,x2:`12`,y1:`2`,y2:`22`,key:`7eqyqh`}],[`path`,{d:`M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6`,key:`1b0p4s`}]]);export{t};
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`dollar-sign`,[[`line`,{x1:`12`,x2:`12`,y1:`2`,y2:`22`,key:`7eqyqh`}],[`path`,{d:`M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6`,key:`1b0p4s`}]]);export{t};

+ 1 - 1
static/assets/droplet-PpnaB65N.js → static/assets/droplet-Bpovh5p6.js

@@ -1 +1 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`droplet`,[[`path`,{d:`M12 22a7 7 0 0 0 7-7c0-2-1-3.9-3-5.5s-3.5-4-4-6.5c-.5 2.5-2 4.9-4 6.5C6 11.1 5 13 5 15a7 7 0 0 0 7 7z`,key:`c7niix`}]]);export{t};
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`droplet`,[[`path`,{d:`M12 22a7 7 0 0 0 7-7c0-2-1-3.9-3-5.5s-3.5-4-4-6.5c-.5 2.5-2 4.9-4 6.5C6 11.1 5 13 5 15a7 7 0 0 0 7 7z`,key:`c7niix`}]]);export{t};

+ 1 - 1
static/assets/ellipsis-vertical-So0E77JK.js → static/assets/ellipsis-vertical-BXVT5eVX.js

@@ -1 +1 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`ellipsis-vertical`,[[`circle`,{cx:`12`,cy:`12`,r:`1`,key:`41hilf`}],[`circle`,{cx:`12`,cy:`5`,r:`1`,key:`gxeob9`}],[`circle`,{cx:`12`,cy:`19`,r:`1`,key:`lyex9k`}]]);export{t};
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`ellipsis-vertical`,[[`circle`,{cx:`12`,cy:`12`,r:`1`,key:`41hilf`}],[`circle`,{cx:`12`,cy:`5`,r:`1`,key:`gxeob9`}],[`circle`,{cx:`12`,cy:`19`,r:`1`,key:`lyex9k`}]]);export{t};

+ 1 - 1
static/assets/eye-off-B6dY82pM.js → static/assets/eye-off-Bq05MYzN.js

@@ -1 +1 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`eye-off`,[[`path`,{d:`M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49`,key:`ct8e1f`}],[`path`,{d:`M14.084 14.158a3 3 0 0 1-4.242-4.242`,key:`151rxh`}],[`path`,{d:`M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143`,key:`13bj9a`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}]]);export{t};
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`eye-off`,[[`path`,{d:`M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49`,key:`ct8e1f`}],[`path`,{d:`M14.084 14.158a3 3 0 0 1-4.242-4.242`,key:`151rxh`}],[`path`,{d:`M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143`,key:`13bj9a`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}]]);export{t};

+ 1 - 1
static/assets/fan-DSlOeWAh.js → static/assets/fan-BZ0HFoG4.js

@@ -1 +1 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`cable`,[[`path`,{d:`M17 19a1 1 0 0 1-1-1v-2a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2a1 1 0 0 1-1 1z`,key:`trhst0`}],[`path`,{d:`M17 21v-2`,key:`ds4u3f`}],[`path`,{d:`M19 14V6.5a1 1 0 0 0-7 0v11a1 1 0 0 1-7 0V10`,key:`1mo9zo`}],[`path`,{d:`M21 21v-2`,key:`eo0ou`}],[`path`,{d:`M3 5V3`,key:`1k5hjh`}],[`path`,{d:`M4 10a2 2 0 0 1-2-2V6a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2a2 2 0 0 1-2 2z`,key:`1dd30t`}],[`path`,{d:`M7 5V3`,key:`1t1388`}]]),n=e(`fan`,[[`path`,{d:`M10.827 16.379a6.082 6.082 0 0 1-8.618-7.002l5.412 1.45a6.082 6.082 0 0 1 7.002-8.618l-1.45 5.412a6.082 6.082 0 0 1 8.618 7.002l-5.412-1.45a6.082 6.082 0 0 1-7.002 8.618l1.45-5.412Z`,key:`484a7f`}],[`path`,{d:`M12 12v.01`,key:`u5ubse`}]]);export{t as n,n as t};
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`cable`,[[`path`,{d:`M17 19a1 1 0 0 1-1-1v-2a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2a1 1 0 0 1-1 1z`,key:`trhst0`}],[`path`,{d:`M17 21v-2`,key:`ds4u3f`}],[`path`,{d:`M19 14V6.5a1 1 0 0 0-7 0v11a1 1 0 0 1-7 0V10`,key:`1mo9zo`}],[`path`,{d:`M21 21v-2`,key:`eo0ou`}],[`path`,{d:`M3 5V3`,key:`1k5hjh`}],[`path`,{d:`M4 10a2 2 0 0 1-2-2V6a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2a2 2 0 0 1-2 2z`,key:`1dd30t`}],[`path`,{d:`M7 5V3`,key:`1t1388`}]]),n=e(`fan`,[[`path`,{d:`M10.827 16.379a6.082 6.082 0 0 1-8.618-7.002l5.412 1.45a6.082 6.082 0 0 1 7.002-8.618l-1.45 5.412a6.082 6.082 0 0 1 8.618 7.002l-5.412-1.45a6.082 6.082 0 0 1-7.002 8.618l1.45-5.412Z`,key:`484a7f`}],[`path`,{d:`M12 12v.01`,key:`u5ubse`}]]);export{t as n,n as t};

+ 1 - 1
static/assets/file-box-BjB1o93N.js → static/assets/file-box-DGWntDxa.js

@@ -1 +1 @@
-import{t as e}from"./createLucideIcon-Yo2YoYjm.js";var t=e(`file-box`,[[`path`,{d:`M14.5 22H18a2 2 0 0 0 2-2V8a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 14 2H6a2 2 0 0 0-2 2v3.8`,key:`1kchwa`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`M11.7 14.2 7 17l-4.7-2.8`,key:`1yk8tc`}],[`path`,{d:`M3 13.1a2 2 0 0 0-.999 1.76v3.24a2 2 0 0 0 .969 1.78L6 21.7a2 2 0 0 0 2.03.01L11 19.9a2 2 0 0 0 1-1.76V14.9a2 2 0 0 0-.97-1.78L8 11.3a2 2 0 0 0-2.03-.01z`,key:`19flxy`}],[`path`,{d:`M7 17v5`,key:`1yj1jh`}]]);export{t};
+import{t as e}from"./createLucideIcon-BTg337Gy.js";var t=e(`file-box`,[[`path`,{d:`M14.5 22H18a2 2 0 0 0 2-2V8a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 14 2H6a2 2 0 0 0-2 2v3.8`,key:`1kchwa`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`M11.7 14.2 7 17l-4.7-2.8`,key:`1yk8tc`}],[`path`,{d:`M3 13.1a2 2 0 0 0-.999 1.76v3.24a2 2 0 0 0 .969 1.78L6 21.7a2 2 0 0 0 2.03.01L11 19.9a2 2 0 0 0 1-1.76V14.9a2 2 0 0 0-.97-1.78L8 11.3a2 2 0 0 0-2.03-.01z`,key:`19flxy`}],[`path`,{d:`M7 17v5`,key:`1yj1jh`}]]);export{t};

Some files were not shown because too many files changed in this diff