Explorar o código

fix(print-modal): allow cross-extruder AMS slot picks on dual-nozzle (#1722)

  Before this change, the Re-print and Schedule modals' per-filament
  slot dropdown hid every slot whose extruder didn't match the filament's
  slicer-assigned nozzle. On H2D with AMS A+C on the left and B on the
  right, an L-assigned filament could only pick A or C and an R-assigned
  one could only pick B — locking the user out of cross-extruder picks
  even when they'd intentionally loaded the required filament into the
  other AMS.

  The slicer wasn't the source of the asymmetry: BambuStudio Desktop,
  OrcaSlicer Desktop, and the Bambuddy sidecar all produced identical
  filament_map values for the same source 3MF. Bambuddy's UI filter was.

  Drop the f.extruderId === item.nozzle_id clause in FilamentMapping's
  loadedFilaments filter. Single-nozzle and FTS short-circuits stay; the
  L/R row badge stays as a hint to the slicer's intent. Printer firmware
  decides at start-print whether the cross-extruder ams_mapping is valid.
maziggy hai 2 meses
pai
achega
61df0b68d2

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
CHANGELOG.md


+ 14 - 6
frontend/src/__tests__/components/FilamentMapping.test.tsx

@@ -193,7 +193,15 @@ describe('FilamentMapping — FTS routing', () => {
     expect(screen.queryByLabelText(/Force color match/i)).not.toBeInTheDocument();
     expect(screen.queryByLabelText(/Force color match/i)).not.toBeInTheDocument();
   });
   });
 
 
-  it('still applies the per-nozzle filter when FTS is null', async () => {
+  it('offers cross-extruder slots in the dropdown without FTS (#1722)', async () => {
+    // Before #1722 the dropdown filtered to only slots whose extruder matched
+    // the filament's slicer-assigned nozzle. On a dual-nozzle printer with one
+    // AMS per side, that prevented the user from picking a slot on the OTHER
+    // extruder even when they'd intentionally loaded the required filament
+    // there. The fix: trust the user, show every loaded slot regardless of
+    // which extruder it's wired to. The L/R badge on the filament row still
+    // tells the user what the slicer planned; the printer firmware accepts
+    // or rejects the cross-extruder ams_mapping at start-print.
     server.use(
     server.use(
       http.get(
       http.get(
         '/api/v1/printers/:id/status',
         '/api/v1/printers/:id/status',
@@ -219,13 +227,13 @@ describe('FilamentMapping — FTS routing', () => {
       />,
       />,
     );
     );
 
 
-    // Required nozzle is 1 (LEFT) but AMS 0 is on extruder 0 (RIGHT) — neither
-    // slot should appear in the dropdown.
+    // Required nozzle is 1 (LEFT) and AMS 0 is wired to extruder 0 (RIGHT).
+    // Both slots must STILL appear so the user can pick them — explicitly the
+    // cross-extruder scenario the #1722 fix unblocks.
     await waitFor(() => {
     await waitFor(() => {
-      // Wait for component to render — the slot label should NOT be present
-      expect(screen.queryByText(/Bambu PLA/)).not.toBeInTheDocument();
-      expect(screen.queryByText(/Bambu PETG/)).not.toBeInTheDocument();
+      expect(screen.getByText(/Bambu PLA/)).toBeInTheDocument();
     });
     });
+    expect(screen.getByText(/Bambu PETG/)).toBeInTheDocument();
   });
   });
 
 
   it('renders sub-brand + material-disambiguated colour on the required side (#1718)', async () => {
   it('renders sub-brand + material-disambiguated colour on the required side (#1718)', async () => {

+ 14 - 8
frontend/src/components/PrintModal/FilamentMapping.tsx

@@ -245,14 +245,20 @@ export function FilamentMapping({
                   <option value="" className="bg-bambu-dark text-bambu-gray">
                   <option value="" className="bg-bambu-dark text-bambu-gray">
                     -- Select slot --
                     -- Select slot --
                   </option>
                   </option>
-                  {loadedFilaments
-                    .filter(
-                      (f) =>
-                        item.nozzle_id == null ||
-                        ftsInstalled ||
-                        f.extruderId === item.nozzle_id,
-                    )
-                    .map((f) => {
+                  {/*
+                    #1722: every loaded slot is offered for every filament row,
+                    regardless of which extruder the slot is wired to. Before this
+                    change a slot was only listed when its extruder matched the
+                    filament's slicer-assigned nozzle (item.nozzle_id), which
+                    locked users out of cross-extruder picks even when they'd
+                    intentionally loaded the required filament into the "other"
+                    AMS. The L/R badge on the filament row still tells the user
+                    what the slicer planned; the dropdown now trusts the user to
+                    pick based on their physical setup. Printer firmware accepts
+                    or rejects the ams_mapping at start-print — failure is loud,
+                    not silent.
+                  */}
+                  {loadedFilaments.map((f) => {
                       const remainingWeight = trayRemainingWeightMap.get(f.globalTrayId);
                       const remainingWeight = trayRemainingWeightMap.get(f.globalTrayId);
                       const remainingLabel = remainingWeight != null
                       const remainingLabel = remainingWeight != null
                         ? t('printModal.slotRemainingShort', {
                         ? t('printModal.slotRemainingShort', {

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
static/assets/index-I24jNRag.js


+ 1 - 1
static/index.html

@@ -26,7 +26,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-C-AWhT3K.js"></script>
+    <script type="module" crossorigin src="/assets/index-I24jNRag.js"></script>
     <link rel="stylesheet" crossorigin href="/assets/index-45eedLWT.css">
     <link rel="stylesheet" crossorigin href="/assets/index-45eedLWT.css">
   </head>
   </head>
   <body>
   <body>

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio