From da0c54f2805a0b48d7ff4f8275a4f2b7c785c945 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Mon, 5 Oct 2026 11:44:22 -0400 Subject: [PATCH] feat(ui): preview the highlighted nest's plates in the Open dialog The Details area of the Database-mode Open dialog now has a plate preview beside the Plates/Drawings tabs, with a draggable divider. It draws one plate of the highlighted nest; the arrow buttons below it step through the plates ("Plate 2 of 5"), and choosing a row on the Plates tab shows that plate, so the table and the preview stay on the same plate. The preview is read-only (no selection or drop) and refits when resized. NestDetails keeps the downloaded nest's plates (PlateLayouts) beside its rows, so the preview draws the copy already read for the tables with no second download. Tests: NestDetails keeps every plate in nest order (fails with the assignment removed). The Windows form test steps forward with the button, checks the row follows, and selects a row back. --- OpenNest.Data/NestDetails.cs | 14 ++- OpenNest.Tests/Data/NestDetailsTests.cs | 17 ++++ .../Forms/SavedNestsFormTests.cs | 61 ++++++++++-- OpenNest/Forms/SavedNestsForm.cs | 97 ++++++++++++++++++- docs/nest-storage.md | 21 ++-- 5 files changed, 189 insertions(+), 21 deletions(-) diff --git a/OpenNest.Data/NestDetails.cs b/OpenNest.Data/NestDetails.cs index 6af06a4..b726823 100644 --- a/OpenNest.Data/NestDetails.cs +++ b/OpenNest.Data/NestDetails.cs @@ -17,6 +17,12 @@ public sealed class NestDetails /// One row per drawing (cutoffs excluded), in nest order. public IReadOnlyList Drawings { get; init; } = Array.Empty(); + /// + /// The plates themselves, in the same order as , for the plate + /// preview. They belong to the downloaded copy of the nest, never to an open document. + /// + public IReadOnlyList PlateLayouts { get; init; } = Array.Empty(); + public static NestDetails FromNest(Nest nest) { ArgumentNullException.ThrowIfNull(nest); @@ -52,7 +58,13 @@ public sealed class NestDetails Area: drawing.Area)) .ToList(); - return new NestDetails { Units = nest.Units, Plates = plates, Drawings = drawings }; + return new NestDetails + { + Units = nest.Units, + Plates = plates, + Drawings = drawings, + PlateLayouts = nest.Plates.ToList(), + }; } } diff --git a/OpenNest.Tests/Data/NestDetailsTests.cs b/OpenNest.Tests/Data/NestDetailsTests.cs index 1a27559..d93c021 100644 --- a/OpenNest.Tests/Data/NestDetailsTests.cs +++ b/OpenNest.Tests/Data/NestDetailsTests.cs @@ -54,6 +54,23 @@ public class NestDetailsTests }); } + [Fact] + public void FromNest_KeepsEachPlateForThePreview_InNestOrder() + { + var nest = new Nest("Job"); + var first = nest.CreatePlate(); + var second = nest.CreatePlate(); + var third = nest.CreatePlate(); + + var details = NestDetails.FromNest(nest); + + Assert.Collection( + details.PlateLayouts, + plate => Assert.Same(first, plate), + plate => Assert.Same(second, plate), + plate => Assert.Same(third, plate)); + } + [Fact] public void FromNest_CountsNestedDrawingsAcrossPlateDuplicates_AndSkipsCutoffs() { diff --git a/OpenNest.WinForms.Tests/Forms/SavedNestsFormTests.cs b/OpenNest.WinForms.Tests/Forms/SavedNestsFormTests.cs index 2f89efa..64295ca 100644 --- a/OpenNest.WinForms.Tests/Forms/SavedNestsFormTests.cs +++ b/OpenNest.WinForms.Tests/Forms/SavedNestsFormTests.cs @@ -21,8 +21,8 @@ public class SavedNestsFormTests var first = Record("First job"); var second = Record("Second job"); var repository = new FakeRepository(first, second); - repository.Files[first.Id] = NestFile(plateQuantity: 2, partsOnPlate: 3); - repository.Files[second.Id] = NestFile(plateQuantity: 1, partsOnPlate: 1); + repository.Files[first.Id] = NestFile((Quantity: 2, Parts: 3)); + repository.Files[second.Id] = NestFile((Quantity: 1, Parts: 1)); using var form = new SavedNestsForm(repository, "http://nest-server:5000"); form.Show(); @@ -56,6 +56,46 @@ public class SavedNestsFormTests "The saved-nest dialog test did not complete."); } + [Fact] + public void PlatePreview_StepsThroughThePlates_AndFollowsThePlatesTable() + { + StaTestThread.Run( + () => + { + var job = Record("Two plates"); + var repository = new FakeRepository(job); + repository.Files[job.Id] = NestFile((Quantity: 1, Parts: 3), (Quantity: 1, Parts: 1)); + + using var form = new SavedNestsForm(repository); + form.Show(); + var plates = Field(form, "platesGrid"); + var preview = Field(form, "platePreview"); + var label = Field