feat(desktop): ask for a new nest name on database Save As

Database Save As uploaded the copy under the same name as the original,
so the saved nests list showed two indistinguishable entries. It now
prompts for the copy's name first (prefilled with the current one) and
cancelling aborts the save. The prompt is skipped while a lost upload
is being reconciled, since that click never writes. If the upload fails
outright the original name is restored, so a later Save cannot rename
the original nest; it is kept only while the copy may still be pending.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ajandClaude Opus 5.5 committed 2026-10-16 11:18:28 -04:00
1 parent 37ddf1b7b2
commit 4e95a09706
2 files changed
+99 -3

No files matched your search

+23 -3
View File
@@ -884,13 +884,27 @@ namespace OpenNest.Forms
if (form == null || databaseSaveInProgress)
return;
if (NestStorage.Settings.Mode == NestStorageMode.File)
{
form.SaveAs();
else
await SaveDatabaseAsync(form, saveCopy: true);
return;
}
// A pending upload is reconciled without writing, so only ask for a name
// when this click will actually create the copy.
string copyName = null;
if (!form.Document.PendingCreateRequiresReconciliation)
{
using var dlg = new NestNameForm(form.Nest.Name);
if (dlg.ShowDialog(this) != DialogResult.OK)
return;
copyName = dlg.NestName;
}
await SaveDatabaseAsync(form, saveCopy: true, copyName);
}
private async Task SaveDatabaseAsync(EditNestForm form, bool saveCopy)
private async Task SaveDatabaseAsync(EditNestForm form, bool saveCopy, string copyName = null)
{
var originalName = form.Nest.Name;
databaseSaveInProgress = true;
storageModeMenu.Enabled = false;
mnuToolsOptions.Enabled = false;
@@ -908,6 +922,8 @@ namespace OpenNest.Forms
: $"Found saved version {reconciled.Revision}. Review the current nest before saving again.";
return; // Never combine reconciliation with a write in the same click.
}
if (copyName != null)
form.Nest.Name = copyName;
var saved = await form.Document.SaveToDatabaseAsync(
repository, serverUrl, saveCopy);
if (!form.IsDisposed)
@@ -917,6 +933,10 @@ namespace OpenNest.Forms
}
catch (Exception ex)
{
// Keep the new name only while its copy may still be pending on the server;
// otherwise a later Save would rename the original nest.
if (copyName != null && !form.Document.PendingCreateWasCopy)
form.Nest.Name = originalName;
if (!IsDisposed)
ShowStorageError("save", ex);
}
+76
View File
@@ -0,0 +1,76 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace OpenNest.Forms;
/// <summary>
/// Database-mode Save As: asks for the name of the new nest copy, since there is no
/// file dialog to supply one.
/// </summary>
public sealed class NestNameForm : Form
{
private readonly TextBox nameBox;
public NestNameForm(string currentName)
{
Text = "Save As";
StartPosition = FormStartPosition.CenterParent;
ClientSize = new Size(380, 110);
MinimizeBox = false;
MaximizeBox = false;
ShowInTaskbar = false;
FormBorderStyle = FormBorderStyle.FixedDialog;
var label = new Label
{
Text = "New nest name:",
AutoSize = true,
Location = new Point(12, 16),
};
nameBox = new TextBox
{
Location = new Point(12, 36),
Width = 356,
Text = currentName ?? "",
};
var buttons = new FlowLayoutPanel
{
Dock = DockStyle.Bottom,
Height = 44,
FlowDirection = FlowDirection.RightToLeft,
Padding = new Padding(6),
};
var cancel = new Button { Text = "Cancel", AutoSize = true, DialogResult = DialogResult.Cancel };
var ok = new Button { Text = "Save", AutoSize = true };
ok.Click += Ok_Click;
buttons.Controls.Add(cancel);
buttons.Controls.Add(ok);
Controls.Add(nameBox);
Controls.Add(label);
Controls.Add(buttons);
AcceptButton = ok;
CancelButton = cancel;
Shown += (_, _) => nameBox.SelectAll();
}
public string NestName => nameBox.Text.Trim();
private void Ok_Click(object sender, EventArgs e)
{
if (NestName.Length == 0)
{
MessageBox.Show(this, "Enter a name for the new nest.", Text,
MessageBoxButtons.OK, MessageBoxIcon.Warning);
nameBox.Focus();
return;
}
DialogResult = DialogResult.OK;
Close();
}
}