Przeglądaj źródła

Report the selected plate on the archives API (#2796) (#2871)

sgiffhorn 2 tygodni temu
rodzic
commit
937440f956

Plik diff jest za duży
+ 1 - 0
CHANGELOG.md


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

@@ -324,6 +324,7 @@ def archive_to_response(
         "duplicate_sequence": duplicate_sequence,
         "original_archive_id": original_archive_id,
         "print_name": archive.print_name,
+        "plate_id": archive.plate_id,
         "print_time_seconds": archive.print_time_seconds,
         "filament_used_grams": archive.filament_used_grams,
         "filament_type": archive.filament_type,

+ 28 - 0
backend/tests/integration/test_archives_api.py

@@ -215,6 +215,34 @@ class TestArchivesAPI:
         assert result["id"] == archive.id
         assert result["print_name"] == "Get Test Archive"
 
+    @pytest.mark.asyncio
+    @pytest.mark.integration
+    async def test_archive_response_exposes_selected_plate(
+        self, async_client: AsyncClient, archive_factory, printer_factory
+    ):
+        """Both archive endpoints must report the stored plate (#2796).
+
+        archive_to_response builds its response dict field by field and left
+        plate_id out. ArchiveResponse.plate_id defaults to None, so every
+        archive came back as plate_id: null and nothing raised an error.
+
+        List and detail share the helper, so both are checked here. The archive
+        without a plate guards a fix that substitutes a fallback plate.
+        """
+        printer = await printer_factory()
+        with_plate = await archive_factory(printer.id, print_name="Plate 22 of a multi-plate 3MF", plate_id=22)
+        without_plate = await archive_factory(printer.id, print_name="Single-plate print")
+
+        listed = await async_client.get("/api/v1/archives/")
+        assert listed.status_code == 200
+        rows = {a["id"]: a for a in listed.json()}
+        assert rows[with_plate.id]["plate_id"] == 22
+        assert rows[without_plate.id]["plate_id"] is None
+
+        detail = await async_client.get(f"/api/v1/archives/{with_plate.id}")
+        assert detail.status_code == 200
+        assert detail.json()["plate_id"] == 22
+
     @pytest.mark.asyncio
     @pytest.mark.integration
     async def test_get_archive_not_found(self, async_client: AsyncClient):

+ 31 - 0
frontend/src/__tests__/pages/ArchivesPage.test.tsx

@@ -306,6 +306,37 @@ describe('ArchivesPage', () => {
       // Archives with multi-plate support will show navigation on hover
       // The plates API is called lazily when hovering
     });
+
+    it('names the plate in the card title when it is not the first one', async () => {
+      server.use(
+        http.get('/api/v1/archives/', () =>
+          HttpResponse.json([{ ...mockArchives[1], plate_id: 3 }])
+        )
+      );
+
+      render(<ArchivesPage />);
+
+      await waitFor(() => {
+        expect(screen.getByText('Bracket v2 \u2014 Plate 3')).toBeInTheDocument();
+      });
+    });
+
+    it('leaves the title alone for a print on plate 1', async () => {
+      // The queue records a plate for single-plate files too, so an ungated
+      // label reads "Plate 1" on ordinary prints (#2796).
+      server.use(
+        http.get('/api/v1/archives/', () =>
+          HttpResponse.json([{ ...mockArchives[0], plate_id: 1 }])
+        )
+      );
+
+      render(<ArchivesPage />);
+
+      await waitFor(() => {
+        expect(screen.getByText('Benchy')).toBeInTheDocument();
+      });
+      expect(screen.queryByText(/Plate 1/)).not.toBeInTheDocument();
+    });
   });
 
   describe('timelapse management', () => {

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

@@ -1087,7 +1087,15 @@ function ArchiveCard({
         <div className="flex items-center justify-between gap-2 mb-1">
           <h3 className="min-w-0 font-medium text-white truncate">
             {archive.print_name || archive.filename}
-            {archive.plate_id != null && ` — ${t('printers.plateNumber', { number: archive.plate_id })}`}
+            {/* Only a plate past the first says anything. The queue records a
+                plate for single-plate files too -- the print dialog auto-selects
+                the only plate there is -- so an ungated label reads "Plate 1" on
+                ordinary prints, and eats room from the truncated name (#2796).
+                The plate carousel is the one place a multi-plate archive printed
+                from plate 1 still identifies itself; it already gates on
+                is_multi_plate, which this title cannot read without waiting for
+                the hover-lazy plates request. */}
+            {archive.plate_id != null && archive.plate_id > 1 && ` — ${t('printers.plateNumber', { number: archive.plate_id })}`}
           </h3>
           <Button
             variant="ghost"

Plik diff jest za duży
+ 0 - 0
static/assets/index-C59zYWAT.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-FZchC7_S.js"></script>
+    <script type="module" crossorigin src="/assets/index-C59zYWAT.js"></script>
     <link rel="stylesheet" crossorigin href="/assets/index-DynWy-72.css">
   </head>
   <body>

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