Przeglądaj źródła

Split multi-material types on the comma alone in statistics and the material filter (#3262)

maziggy 4 dni temu
rodzic
commit
30b7513bf0
62 zmienionych plików z 171 dodań i 18 usunięć
  1. 1 0
      CHANGELOG.md
  2. 94 0
      frontend/src/__tests__/pages/ArchivesMaterialFilter.test.tsx
  3. 32 0
      frontend/src/__tests__/utils/filamentTypes.test.ts
  4. 12 8
      frontend/src/components/FilamentTrends.tsx
  5. 9 5
      frontend/src/pages/ArchivesPage.tsx
  6. 19 0
      frontend/src/utils/filamentTypes.ts
  7. 0 0
      static/assets/AdditionalSection-CQLJ4IHC.js
  8. 0 0
      static/assets/AmsUnitCard-0oMOsost.js
  9. 0 0
      static/assets/ArchivesPage-BSb_MB9S.js
  10. 0 0
      static/assets/ArchivesPage-DPq1Gehh.js
  11. 0 0
      static/assets/AssignToAmsModal-7j6MLCKH.js
  12. 0 0
      static/assets/CamWallPage-C73p7iVX.js
  13. 0 0
      static/assets/CameraDiagnoseModal-Ckpf5A9U.js
  14. 0 0
      static/assets/CameraPage-DBGyP4tu.js
  15. 0 0
      static/assets/CameraWall-BdatIGJs.js
  16. 0 0
      static/assets/ColumnConfigModal-D9ot5fd_.js
  17. 0 0
      static/assets/ConfigureAmsSlotModal-DX4oXmzT.js
  18. 0 0
      static/assets/ConnectAuthorizePage-C2cY13VE.js
  19. 0 0
      static/assets/ContextMenu-BVYxDFvf.js
  20. 0 0
      static/assets/ExternalLinkPage-CRccWrGJ.js
  21. 0 1
      static/assets/FileManagerPage-ZMQJHAkV.js
  22. 0 0
      static/assets/FileUploadModal-DfKGV0qu.js
  23. 0 0
      static/assets/FinancePage-1_FzUI4P.js
  24. 0 0
      static/assets/GCodeViewerPage-CqHPk_o-.js
  25. 0 0
      static/assets/GroupEditPage-Cr0OHBE3.js
  26. 0 0
      static/assets/ImagePreviewModal-kbbJSk44.js
  27. 0 0
      static/assets/InventoryPage-BLBZoEYd.js
  28. 0 0
      static/assets/LibraryTrashPage-ULJ14l58.js
  29. 0 0
      static/assets/LoginPage-DuZTbhAO.js
  30. 0 0
      static/assets/MaintenancePage-BVrgPrym.js
  31. 0 0
      static/assets/ModelSourcesPage-N6_2aJy3.js
  32. 0 0
      static/assets/NotificationsPage-B-6BvYgs.js
  33. 0 1
      static/assets/PdfPreviewModal-DSim_AJc.js
  34. 0 0
      static/assets/PhotoGalleryModal-DIrTkEw_.js
  35. 0 0
      static/assets/PrinterLocationsPage-wzI9VkgW.js
  36. 0 0
      static/assets/PrintersPage-CIZBwwUQ.js
  37. 0 0
      static/assets/ProfilesPage-v1drfQ01.js
  38. 0 0
      static/assets/ProjectDetailPage-Dxt4vo_Y.js
  39. 0 0
      static/assets/ProjectsPage-BH4lIFv4.js
  40. 0 0
      static/assets/QueuePage-bp2WcaGg.js
  41. 0 0
      static/assets/RichTextEditor-CvxzYgcv.js
  42. 0 0
      static/assets/SettingsPage-CybY3BKt.js
  43. 0 0
      static/assets/SetupPage-B7aIMxx7.js
  44. 0 0
      static/assets/SliceModal-C_D5egPX.js
  45. 0 0
      static/assets/SpoolBuddyAmsPage-k7ghDTtR.js
  46. 0 0
      static/assets/SpoolBuddyCalibrationPage-DwOCSQ8t.js
  47. 0 0
      static/assets/SpoolBuddyDashboard-CqNtWSpo.js
  48. 0 0
      static/assets/SpoolBuddyInventoryPage-Di_dqTFb.js
  49. 1 1
      static/assets/SpoolBuddySettingsPage-_CDdt4ek.js
  50. 0 0
      static/assets/SpoolBuddyWriteTagPage-CpeICzHm.js
  51. 0 0
      static/assets/SpreadsheetPreviewModal-DSTZsH_X.js
  52. 0 0
      static/assets/StatsPage-BdTapXHV.js
  53. 0 0
      static/assets/StatsPage-dBitjkMN.js
  54. 0 0
      static/assets/StreamOverlayPage-z0O3rbRn.js
  55. 0 0
      static/assets/SystemInfoPage-BU9Ysi5p.js
  56. 1 0
      static/assets/filamentTypes-Dysa4k6j.js
  57. 0 0
      static/assets/index-ggB_TpPo.js
  58. 1 1
      static/assets/inventorySearch-CqDFyHRc.js
  59. 0 0
      static/assets/locationSensorDefaults-D85td_im.js
  60. 0 0
      static/assets/pdf-Cvgl8N9R.js
  61. 0 0
      static/assets/utils--AXHSbgQ.js
  62. 1 1
      static/index.html

+ 1 - 0
CHANGELOG.md

@@ -149,6 +149,7 @@ 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
+- **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).
 - **Slicing failed with a printer preset saved under a name of its own (#3250, reported by @bobobo1618)** — A printer preset copied from a stock one and renamed, such as "Bambu Lab H2D 0.4 nozzle - Apply Skew Calibration", failed every slice with "The selected printer is not compatible with the process preset in the 3mf", even with a stock process the stock printer slices fine.

+ 94 - 0
frontend/src/__tests__/pages/ArchivesMaterialFilter.test.tsx

@@ -0,0 +1,94 @@
+/**
+ * The Archives material filter offers each material once and matches a
+ * multi-material archive under every one of its materials, whichever separator
+ * its `filament_type` was written with (#3262).
+ */
+
+import { describe, it, expect, beforeEach } from 'vitest';
+import { screen, waitFor, fireEvent } from '@testing-library/react';
+import { render } from '../utils';
+import { ArchivesPage } from '../../pages/ArchivesPage';
+import { http, HttpResponse } from 'msw';
+import { server } from '../mocks/server';
+import { setAuthToken } from '../../api/client';
+
+const base = {
+  printer_id: 1,
+  printer_name: 'H2S',
+  print_time_seconds: 3600,
+  filament_used_grams: 9,
+  thumbnail_path: null,
+  notes: null,
+  rating: null,
+  project_id: null,
+  project_name: null,
+  project_color: null,
+  print_count: 1,
+  tags: '',
+  has_f3d: false,
+  status: 'completed',
+  started_at: '2026-10-07T10:00:00Z',
+  completed_at: '2026-10-07T11:00:00Z',
+  created_at: '2026-10-07T10:00:00Z',
+  updated_at: '2026-10-07T11:00:00Z',
+};
+
+const archives = [
+  { ...base, id: 1, filename: 'a.gcode.3mf', print_name: 'FromSpools', filament_type: 'PLA Basic,PLA' },
+  { ...base, id: 2, filename: 'b.gcode.3mf', print_name: 'FromSlicer', filament_type: 'PLA, PLA-S' },
+  { ...base, id: 3, filename: 'c.gcode.3mf', print_name: 'PetgOnly', filament_type: 'PETG' },
+];
+
+const materialSelect = () =>
+  screen.getAllByRole('combobox').find((el) => el.querySelector('option[value=""]')?.textContent === 'All Materials')!;
+
+describe('Archives material filter (#3262)', () => {
+  beforeEach(() => {
+    localStorage.removeItem('archiveFilterMaterial');
+    setAuthToken(null);
+    server.use(
+      http.get('/api/v1/archives/', () => HttpResponse.json(archives)),
+      http.get('/api/v1/archives/stats', () =>
+        HttpResponse.json({
+          total_archives: 3,
+          total_print_time_seconds: 10800,
+          total_filament_grams: 27,
+          prints_this_week: 3,
+          prints_this_month: 3,
+        })
+      ),
+      http.get('/api/v1/printers/', () => HttpResponse.json([{ id: 1, name: 'H2S' }])),
+      http.get('/api/v1/projects/', () => HttpResponse.json([])),
+      http.get('/api/v1/archives/tags', () => HttpResponse.json([]))
+    );
+  });
+
+  it('lists each material once, not the joined string', async () => {
+    render(<ArchivesPage />);
+    await waitFor(() => expect(screen.getByText('PetgOnly')).toBeInTheDocument());
+
+    const options = Array.from(materialSelect().querySelectorAll('option')).map((o) => o.getAttribute('value'));
+    expect(options).toEqual(['', 'PETG', 'PLA', 'PLA Basic', 'PLA-S']);
+  });
+
+  it('matches archives under each of their materials, whatever the separator', async () => {
+    render(<ArchivesPage />);
+    await waitFor(() => expect(screen.getByText('PetgOnly')).toBeInTheDocument());
+
+    fireEvent.change(materialSelect(), { target: { value: 'PLA' } });
+
+    await waitFor(() => expect(screen.queryByText('PetgOnly')).not.toBeInTheDocument());
+    expect(screen.getByText('FromSpools')).toBeInTheDocument();
+    expect(screen.getByText('FromSlicer')).toBeInTheDocument();
+  });
+
+  it('drops a saved joined material from before the fix instead of hiding everything', async () => {
+    localStorage.setItem('archiveFilterMaterial', 'PLA Basic,PLA');
+
+    render(<ArchivesPage />);
+
+    await waitFor(() => expect(screen.getByText('PetgOnly')).toBeInTheDocument());
+    expect(screen.getByText('FromSpools')).toBeInTheDocument();
+    expect((materialSelect() as HTMLSelectElement).value).toBe('');
+  });
+});

+ 32 - 0
frontend/src/__tests__/utils/filamentTypes.test.ts

@@ -0,0 +1,32 @@
+/**
+ * Multi-material `filament_type` arrives joined two ways: `", "` from the 3MF
+ * parser and `","` from the spool-based rewrites. Both must split the same way
+ * the backend's /archives/stats does (#3262).
+ */
+
+import { describe, it, expect } from 'vitest';
+import { splitFilamentTypes } from '../../utils/filamentTypes';
+
+describe('splitFilamentTypes (#3262)', () => {
+  it('splits a value written from spools (no space)', () => {
+    expect(splitFilamentTypes('PLA Basic,PLA')).toEqual(['PLA Basic', 'PLA']);
+  });
+
+  it('splits a value written by the 3MF parser (comma + space)', () => {
+    expect(splitFilamentTypes('PLA, PLA-S')).toEqual(['PLA', 'PLA-S']);
+  });
+
+  it('keeps a single material, including one with a space in its name', () => {
+    expect(splitFilamentTypes('PLA Basic')).toEqual(['PLA Basic']);
+  });
+
+  it('drops empty parts and repeats', () => {
+    expect(splitFilamentTypes(' PLA ,, PETG, PLA,')).toEqual(['PLA', 'PETG']);
+  });
+
+  it('returns nothing for a missing value', () => {
+    expect(splitFilamentTypes(null)).toEqual([]);
+    expect(splitFilamentTypes(undefined)).toEqual([]);
+    expect(splitFilamentTypes('')).toEqual([]);
+  });
+});

+ 12 - 8
frontend/src/components/FilamentTrends.tsx

@@ -16,6 +16,7 @@ import type { ArchiveSlim } from '../api/client';
 import { MetricToggle, type Metric } from './MetricToggle';
 import { parseUTCDate } from '../utils/date';
 import { formatWeight } from '../utils/weight';
+import { splitFilamentTypes } from '../utils/filamentTypes';
 
 interface FilamentTrendsProps {
   archives: ArchiveSlim[];
@@ -24,6 +25,12 @@ interface FilamentTrendsProps {
   dateTo?: string;
 }
 
+/** An archive's materials, or 'Unknown' when it has none (#3262). */
+function archiveFilamentTypes(filamentType: string | null | undefined): string[] {
+  const types = splitFilamentTypes(filamentType);
+  return types.length ? types : ['Unknown'];
+}
+
 const COLORS = ['#00ae42', '#3b82f6', '#f59e0b', '#ef4444', '#8b5cf6', '#ec4899', '#14b8a6', '#f97316'];
 
 const DAY_NAMES = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
@@ -139,9 +146,8 @@ export function FilamentTrends({ archives, currency = '$', dateFrom, dateTo }: F
     const dataMap = new Map<string, number>();
 
     archives.forEach(archive => {
-      const type = archive.filament_type || 'Unknown';
-      // Handle multiple types (e.g., "PLA, PETG")
-      const types = type.split(', ');
+      // Multiple types (e.g. "PLA, PETG" or "PLA Basic,PLA") share the print
+      const types = archiveFilamentTypes(archive.filament_type);
       types.forEach(t => {
         const grams = (archive.filament_used_grams || 0) / types.length;
         dataMap.set(t, (dataMap.get(t) || 0) + grams);
@@ -157,8 +163,7 @@ export function FilamentTrends({ archives, currency = '$', dateFrom, dateTo }: F
   const filamentTypePrintData = useMemo(() => {
     const dataMap = new Map<string, number>();
     archives.forEach(archive => {
-      const type = archive.filament_type || 'Unknown';
-      const types = type.split(', ');
+      const types = archiveFilamentTypes(archive.filament_type);
       types.forEach(t => {
         dataMap.set(t, (dataMap.get(t) || 0) + 1);
       });
@@ -172,8 +177,7 @@ export function FilamentTrends({ archives, currency = '$', dateFrom, dateTo }: F
   const filamentTypeTimeData = useMemo(() => {
     const dataMap = new Map<string, number>();
     archives.forEach(archive => {
-      const type = archive.filament_type || 'Unknown';
-      const types = type.split(', ');
+      const types = archiveFilamentTypes(archive.filament_type);
       const seconds = (archive.actual_time_seconds || archive.print_time_seconds || 0) / types.length;
       types.forEach(t => {
         dataMap.set(t, (dataMap.get(t) || 0) + seconds);
@@ -189,7 +193,7 @@ export function FilamentTrends({ archives, currency = '$', dateFrom, dateTo }: F
     const map = new Map<string, { completed: number; failed: number }>();
     archives.forEach(a => {
       if (a.status !== 'completed' && a.status !== 'failed') return;
-      const types = (a.filament_type || 'Unknown').split(', ');
+      const types = archiveFilamentTypes(a.filament_type);
       types.forEach(type => {
         const entry = map.get(type) || { completed: 0, failed: 0 };
         if (a.status === 'completed') entry.completed++;

+ 9 - 5
frontend/src/pages/ArchivesPage.tsx

@@ -72,6 +72,7 @@ import { openInSlicer, resolveDesktopSlicer, type SlicerType } from '../utils/sl
 import { formatDateTime, formatDateOnly, parseUTCDate, type TimeFormat, formatDuration } from '../utils/date';
 import { getCurrencySymbol } from '../utils/currency';
 import { getBedTypeInfo } from '../utils/bedType';
+import { splitFilamentTypes } from '../utils/filamentTypes';
 import { invalidateArchiveAndProjectViews } from '../utils/projectQueries';
 import { assignableProjects } from '../utils/projectTree';
 import { verdictSourceKey } from '../utils/verdictSource';
@@ -2962,9 +2963,12 @@ export function ArchivesPage() {
     const saved = localStorage.getItem('archiveFilterPrinter');
     return saved ? Number(saved) : null;
   });
-  const [filterMaterial, setFilterMaterial] = useState<string | null>(() =>
-    localStorage.getItem('archiveFilterMaterial')
-  );
+  const [filterMaterial, setFilterMaterial] = useState<string | null>(() => {
+    // A saved joined value ("PLA Basic,PLA") was once offered as a material of
+    // its own (#3262); it matches nothing now, and would hide every archive.
+    const saved = localStorage.getItem('archiveFilterMaterial');
+    return saved && !saved.includes(',') ? saved : null;
+  });
   const [filterColors, setFilterColors] = useState<Set<string>>(() => {
     const saved = localStorage.getItem('archiveFilterColors');
     return saved ? new Set(JSON.parse(saved)) : new Set();
@@ -3556,7 +3560,7 @@ export function ArchivesPage() {
 
   // Extract unique materials and colors from archives
   const uniqueMaterials = [...new Set(
-    archives?.flatMap(a => a.filament_type?.split(', ') || []).filter(Boolean) || []
+    archives?.flatMap(a => splitFilamentTypes(a.filament_type)) || []
   )].sort();
 
   const uniqueColors = [...new Set(
@@ -3606,7 +3610,7 @@ export function ArchivesPage() {
 
       // Material filter
       const matchesMaterial = !filterMaterial ||
-        (a.filament_type?.split(', ').includes(filterMaterial));
+        splitFilamentTypes(a.filament_type).includes(filterMaterial);
 
       // Color filter (AND: must have all selected colors, OR: must have any selected color)
       const archiveColors = a.filament_color?.split(',') || [];

+ 19 - 0
frontend/src/utils/filamentTypes.ts

@@ -0,0 +1,19 @@
+/**
+ * The materials in an archive's `filament_type`.
+ *
+ * A multi-material print stores them comma-joined, but with two separators:
+ * the 3MF parser writes `", "` and the spool-based rewrites (#2563) write
+ * `","`. Splitting on `", "` alone left `"PLA Basic,PLA"` as one material in
+ * the statistics and the Archives material filter (#3262). Splits on the
+ * comma and trims, like the backend's `/archives/stats`, and drops empty and
+ * repeated entries so a print is never counted twice for one material.
+ */
+export function splitFilamentTypes(value: string | null | undefined): string[] {
+  if (!value) return [];
+  const types: string[] = [];
+  for (const part of value.split(',')) {
+    const type = part.trim();
+    if (type && !types.includes(type)) types.push(type);
+  }
+  return types;
+}

Plik diff jest za duży
+ 0 - 0
static/assets/AdditionalSection-CQLJ4IHC.js


Plik diff jest za duży
+ 0 - 0
static/assets/AmsUnitCard-0oMOsost.js


Plik diff jest za duży
+ 0 - 0
static/assets/ArchivesPage-BSb_MB9S.js


Plik diff jest za duży
+ 0 - 0
static/assets/ArchivesPage-DPq1Gehh.js


Plik diff jest za duży
+ 0 - 0
static/assets/AssignToAmsModal-7j6MLCKH.js


Plik diff jest za duży
+ 0 - 0
static/assets/CamWallPage-C73p7iVX.js


Plik diff jest za duży
+ 0 - 0
static/assets/CameraDiagnoseModal-Ckpf5A9U.js


Plik diff jest za duży
+ 0 - 0
static/assets/CameraPage-DBGyP4tu.js


Plik diff jest za duży
+ 0 - 0
static/assets/CameraWall-BdatIGJs.js


Plik diff jest za duży
+ 0 - 0
static/assets/ColumnConfigModal-D9ot5fd_.js


Plik diff jest za duży
+ 0 - 0
static/assets/ConfigureAmsSlotModal-DX4oXmzT.js


Plik diff jest za duży
+ 0 - 0
static/assets/ConnectAuthorizePage-C2cY13VE.js


Plik diff jest za duży
+ 0 - 0
static/assets/ContextMenu-BVYxDFvf.js


Plik diff jest za duży
+ 0 - 0
static/assets/ExternalLinkPage-CRccWrGJ.js


Plik diff jest za duży
+ 0 - 1
static/assets/FileManagerPage-ZMQJHAkV.js


Plik diff jest za duży
+ 0 - 0
static/assets/FileUploadModal-DfKGV0qu.js


Plik diff jest za duży
+ 0 - 0
static/assets/FinancePage-1_FzUI4P.js


Plik diff jest za duży
+ 0 - 0
static/assets/GCodeViewerPage-CqHPk_o-.js


Plik diff jest za duży
+ 0 - 0
static/assets/GroupEditPage-Cr0OHBE3.js


Plik diff jest za duży
+ 0 - 0
static/assets/ImagePreviewModal-kbbJSk44.js


Plik diff jest za duży
+ 0 - 0
static/assets/InventoryPage-BLBZoEYd.js


Plik diff jest za duży
+ 0 - 0
static/assets/LibraryTrashPage-ULJ14l58.js


Plik diff jest za duży
+ 0 - 0
static/assets/LoginPage-DuZTbhAO.js


Plik diff jest za duży
+ 0 - 0
static/assets/MaintenancePage-BVrgPrym.js


Plik diff jest za duży
+ 0 - 0
static/assets/ModelSourcesPage-N6_2aJy3.js


Plik diff jest za duży
+ 0 - 0
static/assets/NotificationsPage-B-6BvYgs.js


Plik diff jest za duży
+ 0 - 1
static/assets/PdfPreviewModal-DSim_AJc.js


Plik diff jest za duży
+ 0 - 0
static/assets/PhotoGalleryModal-DIrTkEw_.js


Plik diff jest za duży
+ 0 - 0
static/assets/PrinterLocationsPage-wzI9VkgW.js


Plik diff jest za duży
+ 0 - 0
static/assets/PrintersPage-CIZBwwUQ.js


Plik diff jest za duży
+ 0 - 0
static/assets/ProfilesPage-v1drfQ01.js


Plik diff jest za duży
+ 0 - 0
static/assets/ProjectDetailPage-Dxt4vo_Y.js


Plik diff jest za duży
+ 0 - 0
static/assets/ProjectsPage-BH4lIFv4.js


Plik diff jest za duży
+ 0 - 0
static/assets/QueuePage-bp2WcaGg.js


Plik diff jest za duży
+ 0 - 0
static/assets/RichTextEditor-CvxzYgcv.js


Plik diff jest za duży
+ 0 - 0
static/assets/SettingsPage-CybY3BKt.js


Plik diff jest za duży
+ 0 - 0
static/assets/SetupPage-B7aIMxx7.js


Plik diff jest za duży
+ 0 - 0
static/assets/SliceModal-C_D5egPX.js


Plik diff jest za duży
+ 0 - 0
static/assets/SpoolBuddyAmsPage-k7ghDTtR.js


Plik diff jest za duży
+ 0 - 0
static/assets/SpoolBuddyCalibrationPage-DwOCSQ8t.js


Plik diff jest za duży
+ 0 - 0
static/assets/SpoolBuddyDashboard-CqNtWSpo.js


Plik diff jest za duży
+ 0 - 0
static/assets/SpoolBuddyInventoryPage-Di_dqTFb.js


Plik diff jest za duży
+ 1 - 1
static/assets/SpoolBuddySettingsPage-_CDdt4ek.js


Plik diff jest za duży
+ 0 - 0
static/assets/SpoolBuddyWriteTagPage-CpeICzHm.js


Plik diff jest za duży
+ 0 - 0
static/assets/SpreadsheetPreviewModal-DSTZsH_X.js


Plik diff jest za duży
+ 0 - 0
static/assets/StatsPage-BdTapXHV.js


Plik diff jest za duży
+ 0 - 0
static/assets/StatsPage-dBitjkMN.js


Plik diff jest za duży
+ 0 - 0
static/assets/StreamOverlayPage-z0O3rbRn.js


Plik diff jest za duży
+ 0 - 0
static/assets/SystemInfoPage-BU9Ysi5p.js


+ 1 - 0
static/assets/filamentTypes-Dysa4k6j.js

@@ -0,0 +1 @@
+function e(e){if(!e)return[];let t=[];for(let n of e.split(`,`)){let e=n.trim();e&&!t.includes(e)&&t.push(e)}return t}export{e as t};

Plik diff jest za duży
+ 0 - 0
static/assets/index-ggB_TpPo.js


+ 1 - 1
static/assets/inventorySearch-C82dQp2B.js → static/assets/inventorySearch-CqDFyHRc.js

@@ -1 +1 @@
-import{ft as e}from"./index-Bw-_P2Fg.js";function t(t,n){let r=n.trim().toLowerCase();if(!r)return!0;let i=r.match(/^#(\d+)$/);return i?t.id===Number(i[1]):String(t.id).includes(r)||t.material.toLowerCase().includes(r)||(t.brand?.toLowerCase().includes(r)??!1)||(t.color_name?.toLowerCase().includes(r)??!1)||(e(t.color_name,t.rgba,t.color_name_is_synthesized)?.toLowerCase().includes(r)??!1)||(t.subtype?.toLowerCase().includes(r)??!1)||(t.note?.toLowerCase().includes(r)??!1)||(t.slicer_filament_name?.toLowerCase().includes(r)??!1)||(t.storage_location?.toLowerCase().includes(r)??!1)||(t.material_number?.toLowerCase().includes(r)??!1)||(t.suppliers?.some(e=>e.supplier_name.toLowerCase().includes(r)||(e.supplier_article_number?.toLowerCase().includes(r)??!1))??!1)}function n(e,n){return n?e.filter(e=>t(e,n)):e}export{n as t};
+import{ft as e}from"./index-ggB_TpPo.js";function t(t,n){let r=n.trim().toLowerCase();if(!r)return!0;let i=r.match(/^#(\d+)$/);return i?t.id===Number(i[1]):String(t.id).includes(r)||t.material.toLowerCase().includes(r)||(t.brand?.toLowerCase().includes(r)??!1)||(t.color_name?.toLowerCase().includes(r)??!1)||(e(t.color_name,t.rgba,t.color_name_is_synthesized)?.toLowerCase().includes(r)??!1)||(t.subtype?.toLowerCase().includes(r)??!1)||(t.note?.toLowerCase().includes(r)??!1)||(t.slicer_filament_name?.toLowerCase().includes(r)??!1)||(t.storage_location?.toLowerCase().includes(r)??!1)||(t.material_number?.toLowerCase().includes(r)??!1)||(t.suppliers?.some(e=>e.supplier_name.toLowerCase().includes(r)||(e.supplier_article_number?.toLowerCase().includes(r)??!1))??!1)}function n(e,n){return n?e.filter(e=>t(e,n)):e}export{n as t};

Plik diff jest za duży
+ 0 - 0
static/assets/locationSensorDefaults-D85td_im.js


Plik diff jest za duży
+ 0 - 0
static/assets/pdf-Cvgl8N9R.js


Plik diff jest za duży
+ 0 - 0
static/assets/utils--AXHSbgQ.js


+ 1 - 1
static/index.html

@@ -26,7 +26,7 @@
 
     <!-- Splash screens for iOS -->
     <link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
-    <script type="module" crossorigin src="/assets/index-Bw-_P2Fg.js"></script>
+    <script type="module" crossorigin src="/assets/index-ggB_TpPo.js"></script>
     <link rel="modulepreload" crossorigin href="/assets/chunk-aKtaBQYM.js">
     <link rel="modulepreload" crossorigin href="/assets/client-BdOyoZJz.js">
     <link rel="modulepreload" crossorigin href="/assets/QueryClientProvider-Clbyr4Jg.js">

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików