mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-07 05:16:06 -05:00
Tabs suit thin plate, but on anything thicker than 0.25 in the parts are too hard to break out of the sheet, and the Cutting Parameters dialog was one global set for every job. Its settings now live on the nest's machine thickness: leads on the existing Outside/Inside Cuts tabs, and lead-in angle rounding, tabs and pierce on a new Tabs & Pierce tab (ThicknessConfig.Cutting). In Database mode every workstation gets the same settings through the shared machine. The dialog and the Place Lead-in panel say what they edit, and save back to that thickness (MachineCuttingDefaults.WriteTo, converted to the machine's units). A thickness with no Tabs & Pierce of its own, or a nest the machine has no thickness for, keeps this PC's settings as before. If the machine can't be saved (server offline, a conflict), the edit is kept on this PC for that job and the user is told. Machine Configuration can copy one thickness's Tabs & Pierce to thinner or thicker ones, so the 0.25 in rule takes a few clicks. An older desktop saving a shared machine would silently erase these settings, since it doesn't know them. Machine configuration classes now keep unknown fields, and the server refuses a machine save that leaves out a field the stored machine has a value for, telling the user to update OpenNest. The Plan Cutting status line now reports tabs from SupportTabs; since "Tab every part" was retired it always said off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
88 lines
4.2 KiB
C#
88 lines
4.2 KiB
C#
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
using OpenNest.Data;
|
|
|
|
namespace OpenNest.Server;
|
|
|
|
/// <summary>
|
|
/// <c>/api/settings</c>: the settings every workstation shares (machines, post settings, clamps
|
|
/// and nest defaults), one JSON document per kind and key. Creating returns 201, or 200 when the
|
|
/// same document is already stored; changes and deletes follow the If-Match contract (428
|
|
/// missing, 400 malformed, 409 stale with the current document).
|
|
/// </summary>
|
|
internal static class SettingRoutes
|
|
{
|
|
private static readonly JsonSerializerOptions WriteOptions = new(JsonSerializerDefaults.Web)
|
|
{
|
|
PropertyNameCaseInsensitive = true,
|
|
UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow,
|
|
};
|
|
|
|
public static void MapSettings(this IEndpointRouteBuilder app)
|
|
{
|
|
app.MapGet("/api/settings", (NestDatabase db) => Results.Ok(db.ListSharedSettings()));
|
|
|
|
app.MapGet("/api/settings/{kind}/{key}", (string kind, string key, NestDatabase db) =>
|
|
!SharedSettingKinds.IsKnown(kind) ? Results.BadRequest($"Unknown settings kind '{kind}'.") :
|
|
db.GetSharedSetting(kind, key) is { } record ? Results.Ok(record) : Results.NotFound());
|
|
|
|
app.MapPost("/api/settings/{kind}/{key}", async (string kind, string key, HttpRequest request, NestDatabase db) =>
|
|
{
|
|
var (write, error) = await ReadWrite(request, kind, key);
|
|
if (error is not null) return error;
|
|
try
|
|
{
|
|
var (record, created) = db.CreateSharedSetting(kind, key, write!);
|
|
return created ? Results.Created($"/api/settings/{kind}/{record.Key}", record) : Results.Ok(record);
|
|
}
|
|
catch (SharedSettingConflictException conflict) { return Conflict(conflict); }
|
|
});
|
|
|
|
app.MapPut("/api/settings/{kind}/{key}", async (string kind, string key, HttpRequest request, NestDatabase db) =>
|
|
{
|
|
var precondition = IfMatch.Read(request, out var expected);
|
|
if (precondition is not null) return precondition;
|
|
var (write, error) = await ReadWrite(request, kind, key);
|
|
if (error is not null) return error;
|
|
try
|
|
{
|
|
var updated = db.UpdateSharedSetting(kind, key, write!, expected);
|
|
return updated is null ? Results.NotFound() : Results.Ok(updated);
|
|
}
|
|
catch (SharedSettingConflictException conflict) { return Conflict(conflict); }
|
|
catch (InvalidOperationException refused) { return Results.BadRequest(refused.Message); }
|
|
});
|
|
|
|
app.MapDelete("/api/settings/{kind}/{key}", (string kind, string key, string? savedBy, HttpRequest request, NestDatabase db) =>
|
|
{
|
|
var precondition = IfMatch.Read(request, out var expected);
|
|
if (precondition is not null) return precondition;
|
|
if (SharedSettingRules.NormalizeKey(kind, key) is null)
|
|
return Results.BadRequest($"Invalid {kind} settings key.");
|
|
if ((savedBy ?? "").Length > SharedSettingRules.MaxSavedByLength)
|
|
return Results.BadRequest("savedBy is too long.");
|
|
try
|
|
{
|
|
return db.DeleteSharedSetting(kind, key, savedBy ?? "", expected) ? Results.NoContent() : Results.NotFound();
|
|
}
|
|
catch (SharedSettingConflictException conflict) { return Conflict(conflict); }
|
|
});
|
|
}
|
|
|
|
private static IResult Conflict(SharedSettingConflictException conflict) =>
|
|
Results.Json(conflict.Current, statusCode: StatusCodes.Status409Conflict);
|
|
|
|
private static async Task<(SharedSettingWrite? Write, IResult? Error)> ReadWrite(HttpRequest request, string kind, string key)
|
|
{
|
|
var (json, error) = await DrawingSetRoutes.ReadJson(request, "settings document");
|
|
if (error is not null) return (null, error);
|
|
|
|
SharedSettingWrite? write;
|
|
try { write = JsonSerializer.Deserialize<SharedSettingWrite>(json!, WriteOptions); }
|
|
catch (JsonException) { return (null, Results.BadRequest("Invalid settings JSON.")); }
|
|
return SharedSettingRules.GetError(kind, key, write) is { } invalid
|
|
? (null, Results.BadRequest(invalid))
|
|
: (write, null);
|
|
}
|
|
}
|