From 9920aba6ebec50f30e5705a7b7ea9ab7815bd64f Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Mon, 5 Oct 2026 11:26:03 -0400 Subject: [PATCH] feat(ui): open Database-mode nests from a larger saved-nest browser File > Open in Database mode now shows a resizable browser instead of the small list dialog. The upper Nests grid keeps the server-side search, sort and paging (row numbers count through the filtered list; the title shows the server and the range). Below it, Details tabs list the highlighted nest's plates and drawings, read from its archive after the highlight rests for 250 ms; moving back to a nest already shown reuses its result, and a missing archive is reported in the details line. Enter opens the highlighted nest (in the Find box it runs the search at once instead) and Esc closes. Double-click opens a nest, and a context menu offers Open, Delete (after confirmation) and Refresh. It only browses saved nests; new nests are still created from the main window. Windows tests drive the real form: page load, details for two nests, Enter opening the highlighted one, the missing-archive message and Esc. --- .../Forms/SavedNestsFormTests.cs | 169 ++++++ OpenNest/Forms/MainForm.cs | 2 +- OpenNest/Forms/SavedNestsForm.cs | 573 ++++++++++++++---- docs/nest-storage.md | 29 +- 4 files changed, 628 insertions(+), 145 deletions(-) create mode 100644 OpenNest.WinForms.Tests/Forms/SavedNestsFormTests.cs diff --git a/OpenNest.WinForms.Tests/Forms/SavedNestsFormTests.cs b/OpenNest.WinForms.Tests/Forms/SavedNestsFormTests.cs new file mode 100644 index 0000000..2f89efa --- /dev/null +++ b/OpenNest.WinForms.Tests/Forms/SavedNestsFormTests.cs @@ -0,0 +1,169 @@ +using System.Reflection; +using System.Windows.Forms; +using OpenNest.CNC; +using OpenNest.Data; +using OpenNest.Forms; +using OpenNest.Geometry; +using OpenNest.IO; + +namespace OpenNest.WinForms.Tests.Forms; + +public class SavedNestsFormTests +{ + private static readonly TimeSpan TestTimeout = TimeSpan.FromSeconds(60); + + [Fact] + public void HighlightedNestShowsItsPlatesAndDrawings_AndEnterOpensIt() + { + StaTestThread.Run( + () => + { + 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); + + using var form = new SavedNestsForm(repository, "http://nest-server:5000"); + form.Show(); + var nests = Field(form, "nestGrid"); + var plates = Field(form, "platesGrid"); + var drawings = Field(form, "drawingsGrid"); + + PumpUntil(() => nests.Rows.Count == 2, "the nest page"); + Assert.Equal("First job", nests.Rows[0].Cells[0].Value); + Assert.Equal("1", nests.Rows[0].HeaderCell.Value); + Assert.Contains("http://nest-server:5000", form.Text); + Assert.Contains("Showing 1-2 of 2 nests", form.Text); + + PumpUntil(() => plates.Rows.Count == 1, "the first nest's plates"); + Assert.Equal(2, plates.Rows[0].Cells["Duplicates"].Value); + Assert.Equal(3, plates.Rows[0].Cells["Parts"].Value); + Assert.Equal("Plate size (in)", plates.Columns["PlateSize"].HeaderText); + Assert.Equal(6, drawings.Rows[0].Cells["Nested"].Value); + + nests.CurrentCell = nests.Rows[1].Cells[0]; + PumpUntil( + () => plates.Rows.Count == 1 && Equals(plates.Rows[0].Cells["Duplicates"].Value, 1), + "the second nest's plates"); + Assert.Equal(1, drawings.Rows[0].Cells["Nested"].Value); + + Assert.True(ProcessKey(form, Keys.Enter)); + Assert.Equal(DialogResult.OK, form.DialogResult); + Assert.Equal(second.Id, form.SelectedId); + }, + TestTimeout, + "The saved-nest dialog test did not complete."); + } + + [Fact] + public void MissingArchive_ShowsTheErrorInTheDetailsLine_AndEscapeCancels() + { + StaTestThread.Run( + () => + { + var gone = Record("Deleted elsewhere"); + using var form = new SavedNestsForm(new FakeRepository(gone)); + form.Show(); + var status = Field