diff --git a/PlotLine/Services/CoreServices.cs b/PlotLine/Services/CoreServices.cs index 1632a2e..8db386a 100644 --- a/PlotLine/Services/CoreServices.cs +++ b/PlotLine/Services/CoreServices.cs @@ -7563,6 +7563,7 @@ public sealed class FloorPlanService( } var projectLocations = await locations.ListByProjectAsync(project.ProjectID); + var orderedFloors = data.Floors.OrderBy(x => x.SortOrder).ThenBy(x => x.Name).ToList(); return new FloorPlanEditorViewModel { Project = project, @@ -7576,27 +7577,27 @@ public sealed class FloorPlanService( Name = data.FloorPlan.Name, Description = data.FloorPlan.Description }, - Floors = data.Floors.Select(ToFloorEdit).ToList(), + Floors = orderedFloors.Select(ToFloorEdit).ToList(), Blocks = data.Blocks.Select(ToBlockEdit).ToList(), Transitions = data.Transitions.Select(ToTransitionEdit).ToList(), NewFloor = new FloorPlanFloorEditViewModel { FloorPlanID = data.FloorPlan.FloorPlanID, Name = "New floor", - SortOrder = data.Floors.Any() ? data.Floors.Max(x => x.SortOrder) + 10 : 10, + SortOrder = orderedFloors.Any() ? orderedFloors.Max(x => x.SortOrder) + 1 : 0, GridWidth = 24, GridHeight = 16 }, NewBlock = new FloorPlanBlockEditViewModel { - FloorPlanFloorID = data.Floors.FirstOrDefault()?.FloorPlanFloorID ?? 0, + FloorPlanFloorID = orderedFloors.FirstOrDefault()?.FloorPlanFloorID ?? 0, BlockType = FloorPlanBlockTypes.Room, WidthCells = 2, HeightCells = 1 }, NewTransition = new FloorPlanTransitionEditViewModel { - FloorPlanFloorID = data.Floors.FirstOrDefault()?.FloorPlanFloorID ?? 0, + FloorPlanFloorID = orderedFloors.FirstOrDefault()?.FloorPlanFloorID ?? 0, TransitionType = FloorPlanTransitionTypes.Door }, LocationOptions = ToOptionalLocationOptions(projectLocations, "Create/link automatically"), @@ -7627,7 +7628,7 @@ public sealed class FloorPlanService( FloorPlanID = floorPlanId, LocationID = floorLocationId, Name = "Ground Floor", - SortOrder = 10, + SortOrder = 0, GridWidth = 24, GridHeight = 16 }); @@ -8005,6 +8006,11 @@ public sealed class FloorPlanService( private static void ValidateFloor(FloorPlanFloorEditViewModel model) { + if (model.SortOrder is < -10 or > 50) + { + throw new InvalidOperationException("Floor level must be between -10 and 50."); + } + if (model.GridWidth is < 8 or > 80 || model.GridHeight is < 8 or > 80) { throw new InvalidOperationException("Grid width and height must be between 8 and 80."); diff --git a/PlotLine/Sql/076_FloorPlanFloorLevels.sql b/PlotLine/Sql/076_FloorPlanFloorLevels.sql new file mode 100644 index 0000000..f0f087a --- /dev/null +++ b/PlotLine/Sql/076_FloorPlanFloorLevels.sql @@ -0,0 +1,31 @@ +-- Reinterpret the existing FloorPlanFloors.SortOrder integer as user-facing floor Level. +-- This preserves current relative order for legacy 10-step SortOrder data without adding schema. + +IF OBJECT_ID(N'dbo.FloorPlanFloors', N'U') IS NOT NULL +BEGIN + ;WITH LegacyPlans AS + ( + SELECT FloorPlanID + FROM dbo.FloorPlanFloors + GROUP BY FloorPlanID + HAVING COUNT(*) > 0 + AND MIN(SortOrder) >= 10 + AND SUM(CASE WHEN SortOrder % 10 = 0 THEN 0 ELSE 1 END) = 0 + ), + OrderedFloors AS + ( + SELECT + fpf.FloorPlanFloorID, + ROW_NUMBER() OVER (PARTITION BY fpf.FloorPlanID ORDER BY fpf.SortOrder, fpf.Name, fpf.FloorPlanFloorID) - 1 AS FloorLevel + FROM dbo.FloorPlanFloors fpf + INNER JOIN LegacyPlans lp ON lp.FloorPlanID = fpf.FloorPlanID + ) + UPDATE fpf + SET + SortOrder = ordered.FloorLevel, + ModifiedDate = SYSUTCDATETIME() + FROM dbo.FloorPlanFloors fpf + INNER JOIN OrderedFloors ordered ON ordered.FloorPlanFloorID = fpf.FloorPlanFloorID + WHERE fpf.SortOrder <> ordered.FloorLevel; +END; +GO diff --git a/PlotLine/ViewModels/CoreViewModels.cs b/PlotLine/ViewModels/CoreViewModels.cs index 0a1de89..fe5964f 100644 --- a/PlotLine/ViewModels/CoreViewModels.cs +++ b/PlotLine/ViewModels/CoreViewModels.cs @@ -991,6 +991,8 @@ public sealed class TimelineMetricSettingOptionViewModel public int MetricTypeID { get; set; } public string MetricName { get; set; } = string.Empty; public string? Description { get; set; } + [Display(Name = "Level")] + [Range(-10, 50)] public int SortOrder { get; set; } public bool IsSelected { get; set; } } diff --git a/PlotLine/Views/FloorPlans/Edit.cshtml b/PlotLine/Views/FloorPlans/Edit.cshtml index 138b858..14873a3 100644 --- a/PlotLine/Views/FloorPlans/Edit.cshtml +++ b/PlotLine/Views/FloorPlans/Edit.cshtml @@ -113,12 +113,15 @@
Used to order floors and later to connect stairs up/down.
Location: @(string.IsNullOrWhiteSpace(floor.LocationPath) ? "A child Location will be created or linked on save." : floor.LocationPath)