Просмотр исходного кода

Show inventory sidebar item for both Spoolman and internal inventory

Previously the Inventory sidebar item was hidden when Spoolman was
enabled. Now it always shows — when Spoolman is active, /inventory
embeds the Spoolman web UI in the content area via iframe; when
disabled, it renders the internal inventory page as before.
maziggy 3 месяцев назад
Родитель
Сommit
3c72f7cb22

+ 1 - 0
CHANGELOG.md

@@ -43,6 +43,7 @@ All notable changes to Bambuddy will be documented in this file.
 
 
 ### Improved
 ### Improved
 - **Clear Plate Dot Indicator on Sidebar** — When the print queue is active and a printer finishes or fails with a pending next job, a small yellow dot now appears on the Printers sidebar icon to signal that user action (clearing the build plate) is needed. The indicator reuses the existing WebSocket-driven printer status cache, so no additional API polling is required. The dot disappears once the plate is cleared or the queue empties.
 - **Clear Plate Dot Indicator on Sidebar** — When the print queue is active and a printer finishes or fails with a pending next job, a small yellow dot now appears on the Printers sidebar icon to signal that user action (clearing the build plate) is needed. The indicator reuses the existing WebSocket-driven printer status cache, so no additional API polling is required. The dot disappears once the plate is cleared or the queue empties.
+- **Inventory Sidebar Always Visible** — The Inventory sidebar item is no longer hidden when Spoolman is enabled. Instead, clicking it embeds the Spoolman web UI in the main content area via iframe (same approach as external links). When Spoolman is disabled, the internal inventory page is shown as before. Both modes use the same `/inventory` route and sidebar position.
 - **Filament Override Test Coverage** — Added 11 backend unit tests: 6 for `_count_override_color_matches` (no status, exact match, no match, partial match, color normalization, external spool) and 5 for override application in filament matching (color override, tray_info_idx clearing, type change, partial override, nozzle filtering with override). Added 12 frontend tests for the `FilamentOverride` component: 5 rendering tests (null guards, slot display, dropdown count), 2 type filtering tests (same-type only, all colors), 3 nozzle filtering tests (extruder_id matching, single-nozzle passthrough, null extruder_id inclusion), and 2 interaction tests (select override, reset to original).
 - **Filament Override Test Coverage** — Added 11 backend unit tests: 6 for `_count_override_color_matches` (no status, exact match, no match, partial match, color normalization, external spool) and 5 for override application in filament matching (color override, tray_info_idx clearing, type change, partial override, nozzle filtering with override). Added 12 frontend tests for the `FilamentOverride` component: 5 rendering tests (null guards, slot display, dropdown count), 2 type filtering tests (same-type only, all colors), 3 nozzle filtering tests (extruder_id matching, single-nozzle passthrough, null extruder_id inclusion), and 2 interaction tests (select override, reset to original).
 - **P2S Dual-AMS tray_now Test Coverage** — Added 14 integration tests for multi-AMS tray_now disambiguation on single-nozzle printers (resolving AMS-B slots via mapping field, AMS-A passthrough, multi-color mapping, ambiguous/missing mapping fallbacks, last_loaded_tray tracking). Added 9 unit tests for `_resolve_local_slot_from_mapping` (snow decoding, unmapped entry filtering, ambiguity detection, AMS-HT slot matching). All 66 tray_now-related tests pass.
 - **P2S Dual-AMS tray_now Test Coverage** — Added 14 integration tests for multi-AMS tray_now disambiguation on single-nozzle printers (resolving AMS-B slots via mapping field, AMS-A passthrough, multi-color mapping, ambiguous/missing mapping fallbacks, last_loaded_tray tracking). Added 9 unit tests for `_resolve_local_slot_from_mapping` (snow decoding, unmapped entry filtering, ambiguity detection, AMS-HT slot matching). All 66 tray_now-related tests pass.
 - **Bulk Spool, Stock & Grouping Test Coverage** — Added 13 backend unit tests covering `SpoolBulkCreate` schema validation (quantity bounds, field preservation, stock vs configured distinction) and bulk endpoint logic (correct spool count, single quantity, identical fields). Added 29 frontend tests: 13 for `SpoolFormModal` covering `validateForm` with `quickAdd` flag (6 tests), quick-add toggle visibility, PA Profile tab hiding, quantity field gating (hidden by default, visible only in quick-add, hidden in edit mode), and brand/subtype optional asterisk removal in quick-add; 16 for inventory grouping logic covering `spoolGroupKey` identity/differentiation (7 tests) and `computeDisplayItems` grouping rules (9 tests for identical/different/used/assigned/single/order/mixed/empty scenarios).
 - **Bulk Spool, Stock & Grouping Test Coverage** — Added 13 backend unit tests covering `SpoolBulkCreate` schema validation (quantity bounds, field preservation, stock vs configured distinction) and bulk endpoint logic (correct spool count, single quantity, identical fields). Added 29 frontend tests: 13 for `SpoolFormModal` covering `validateForm` with `quickAdd` flag (6 tests), quick-add toggle visibility, PA Profile tab hiding, quantity field gating (hidden by default, visible only in quick-add, hidden in edit mode), and brand/subtype optional asterisk removal in quick-add; 16 for inventory grouping logic covering `spoolGroupKey` identity/differentiation (7 tests) and `computeDisplayItems` grouping rules (9 tests for identical/different/used/assigned/single/order/mixed/empty scenarios).

+ 0 - 12
frontend/src/components/Layout.tsx

@@ -119,13 +119,6 @@ export function Layout() {
     refetchInterval: 60 * 60 * 1000, // Check every hour
     refetchInterval: 60 * 60 * 1000, // Check every hour
   });
   });
 
 
-  // Fetch Spoolman settings to determine if inventory should be hidden
-  const { data: spoolmanSettings } = useQuery({
-    queryKey: ['spoolman-settings'],
-    queryFn: api.getSpoolmanSettings,
-    staleTime: 5 * 60 * 1000,
-  });
-
   // Fetch external links for sidebar
   // Fetch external links for sidebar
   const { data: externalLinks } = useQuery({
   const { data: externalLinks } = useQuery({
     queryKey: ['external-links'],
     queryKey: ['external-links'],
@@ -229,13 +222,9 @@ export function Layout() {
 
 
     // Determine if settings should be hidden (user role and auth enabled)
     // Determine if settings should be hidden (user role and auth enabled)
     const hideSettings = authEnabled && user?.role === 'user';
     const hideSettings = authEnabled && user?.role === 'user';
-    // Hide inventory when Spoolman mode is active
-    const hideInventory = spoolmanSettings?.spoolman_enabled === 'true';
-
     // Add items in stored order
     // Add items in stored order
     for (const id of sidebarOrder) {
     for (const id of sidebarOrder) {
       if (hideSettings && id === 'settings') continue;
       if (hideSettings && id === 'settings') continue;
-      if (hideInventory && id === 'inventory') continue;
       if (navItemsMap.has(id) || extLinksMap.has(id)) {
       if (navItemsMap.has(id) || extLinksMap.has(id)) {
         result.push(id);
         result.push(id);
         seen.add(id);
         seen.add(id);
@@ -245,7 +234,6 @@ export function Layout() {
     // Add any new internal nav items not in stored order
     // Add any new internal nav items not in stored order
     for (const item of defaultNavItems) {
     for (const item of defaultNavItems) {
       if (hideSettings && item.id === 'settings') continue;
       if (hideSettings && item.id === 'settings') continue;
-      if (hideInventory && item.id === 'inventory') continue;
       if (!seen.has(item.id)) {
       if (!seen.has(item.id)) {
         result.push(item.id);
         result.push(item.id);
         seen.add(item.id);
         seen.add(item.id);

+ 23 - 1
frontend/src/pages/InventoryPage.tsx

@@ -337,7 +337,29 @@ function saveSortState(state: SortState) {
   } catch { /* ignore */ }
   } catch { /* ignore */ }
 }
 }
 
 
-export default function InventoryPage() {
+// Wrapper: when Spoolman is enabled, embed its UI; otherwise show internal inventory
+export default function InventoryPageRouter() {
+  const { data: spoolmanSettings } = useQuery({
+    queryKey: ['spoolman-settings'],
+    queryFn: api.getSpoolmanSettings,
+    staleTime: 5 * 60 * 1000,
+  });
+
+  if (spoolmanSettings?.spoolman_enabled === 'true' && spoolmanSettings?.spoolman_url) {
+    return (
+      <iframe
+        src={spoolmanSettings.spoolman_url}
+        className="h-full w-full border-0"
+        title="Spoolman"
+        sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"
+      />
+    );
+  }
+
+  return <InventoryPage />;
+}
+
+function InventoryPage() {
   const { t } = useTranslation();
   const { t } = useTranslation();
   const queryClient = useQueryClient();
   const queryClient = useQueryClient();
   const { showToast } = useToast();
   const { showToast } = useToast();

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
static/assets/index-D_M_iIn2.js


+ 1 - 1
static/index.html

@@ -23,7 +23,7 @@
 
 
     <!-- Splash screens for iOS -->
     <!-- Splash screens for iOS -->
     <link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
     <link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
-    <script type="module" crossorigin src="/assets/index-Cxub00Jo.js"></script>
+    <script type="module" crossorigin src="/assets/index-D_M_iIn2.js"></script>
     <link rel="stylesheet" crossorigin href="/assets/index-COFMpymr.css">
     <link rel="stylesheet" crossorigin href="/assets/index-COFMpymr.css">
   </head>
   </head>
   <body>
   <body>

Некоторые файлы не были показаны из-за большого количества измененных файлов