From 350b8ba9abd183b7ca94fdee99d90bbc288ada53 Mon Sep 17 00:00:00 2001 From: Nick Beckley Date: Mon, 22 Jun 2026 16:58:20 +0100 Subject: [PATCH] Implemented the focused Floor Plans performance pass. Measured findings: Authenticated Calendar House editor load measured around 600 ms locally. SQL calls were generally around 50-65 ms after warm-up. The main recent bloat was the Help UI wiring: the editor had 615 help icons and about 1.5 MB of HTML. Optimisations made: Reduced repeated hidden help icons in [Edit.cshtml (line 409)](C:/Source/PlotLine/PlotLine/Views/FloorPlans/Edit.cshtml:409), especially per-block editors and repeated transition edit modals. Help icons now measure at 107, with HTML reduced to about 1.26 MB. Optimised occupancy warning calculation in [CoreServices.cs (line 7883)](C:/Source/PlotLine/PlotLine/Services/CoreServices.cs:7883) by grouping occupancy rows once instead of repeatedly scanning them per scene. Added new index migration [083_FloorPlanEditorOccupancyIndexes.sql](C:/Source/PlotLine/PlotLine/Sql/083_FloorPlanEditorOccupancyIndexes.sql) for Floor Plan scene/occupancy lookups. Applied locally. Verified: Structure/Occupancy mode still works. Previous/Next scene changes the selected scene. Tokens and transitions still render. Help icons still resolve to articles. dotnet build PlotLine.slnx passes with 0 warnings and 0 errors. No Floor Plans behaviour, transition logic, occupancy data model, or feature architecture changes. --- PlotLine/Services/CoreServices.cs | 3 +- .../083_FloorPlanEditorOccupancyIndexes.sql | 36 +++++++++++++++++ PlotLine/Views/FloorPlans/Edit.cshtml | 40 ++++++++++++------- 3 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 PlotLine/Sql/083_FloorPlanEditorOccupancyIndexes.sql diff --git a/PlotLine/Services/CoreServices.cs b/PlotLine/Services/CoreServices.cs index eb4bea2..ee1e980 100644 --- a/PlotLine/Services/CoreServices.cs +++ b/PlotLine/Services/CoreServices.cs @@ -7880,6 +7880,7 @@ public sealed class FloorPlanService( var warnings = new List(); var blocksByLocation = blocks.GroupBy(x => x.LocationID).ToDictionary(x => x.Key, x => x.ToList()); var floors = blocks.Select(x => x.FloorPlanFloorID).Distinct().ToList(); + var occupancyRowsByScene = occupancyRows.GroupBy(x => x.SceneID).ToDictionary(x => x.Key, x => x.ToList()); var visibleEntranceLocationIds = transitions .Where(x => IsVisibleEntranceTransition(x.TransitionType)) .SelectMany(x => new[] { x.FromLocationID, x.ToLocationID }) @@ -7888,7 +7889,7 @@ public sealed class FloorPlanService( foreach (var sceneGroup in participants.GroupBy(x => x.SceneID)) { var sceneId = sceneGroup.Key; - var sceneRows = occupancyRows.Where(x => x.SceneID == sceneId).ToList(); + var sceneRows = occupancyRowsByScene.GetValueOrDefault(sceneId) ?? []; var occupiedCharacterIds = sceneRows.Where(x => x.CharacterID.HasValue).Select(x => x.CharacterID!.Value).ToHashSet(); var occupiedAssetIds = sceneRows.Where(x => x.StoryAssetID.HasValue).Select(x => x.StoryAssetID!.Value).ToHashSet(); diff --git a/PlotLine/Sql/083_FloorPlanEditorOccupancyIndexes.sql b/PlotLine/Sql/083_FloorPlanEditorOccupancyIndexes.sql new file mode 100644 index 0000000..7ee8b0f --- /dev/null +++ b/PlotLine/Sql/083_FloorPlanEditorOccupancyIndexes.sql @@ -0,0 +1,36 @@ +SET ANSI_NULLS ON; +GO +SET QUOTED_IDENTIFIER ON; +GO + +IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_Scenes_FloorPlanID' AND object_id = OBJECT_ID(N'dbo.Scenes')) + CREATE INDEX IX_Scenes_FloorPlanID ON dbo.Scenes(FloorPlanID, IsArchived, ChapterID, SceneNumber, SortOrder) + INCLUDE (SceneTitle, InitialFloorPlanFloorID); +GO + +IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_Scenes_InitialFloorPlanFloorID' AND object_id = OBJECT_ID(N'dbo.Scenes')) + CREATE INDEX IX_Scenes_InitialFloorPlanFloorID ON dbo.Scenes(InitialFloorPlanFloorID) + WHERE InitialFloorPlanFloorID IS NOT NULL; +GO + +IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_SceneFloorPlanOccupancy_FloorPlanID' AND object_id = OBJECT_ID(N'dbo.SceneFloorPlanOccupancy')) + CREATE INDEX IX_SceneFloorPlanOccupancy_FloorPlanID ON dbo.SceneFloorPlanOccupancy(FloorPlanID, SceneID, LocationID) + INCLUDE (FloorPlanFloorID, CharacterID, StoryAssetID); +GO + +IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_SceneFloorPlanOccupancy_LocationID' AND object_id = OBJECT_ID(N'dbo.SceneFloorPlanOccupancy')) + CREATE INDEX IX_SceneFloorPlanOccupancy_LocationID ON dbo.SceneFloorPlanOccupancy(LocationID) + INCLUDE (SceneID, FloorPlanID, FloorPlanFloorID, CharacterID, StoryAssetID); +GO + +IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_SceneFloorPlanOccupancy_CharacterID' AND object_id = OBJECT_ID(N'dbo.SceneFloorPlanOccupancy')) + CREATE INDEX IX_SceneFloorPlanOccupancy_CharacterID ON dbo.SceneFloorPlanOccupancy(CharacterID) + INCLUDE (SceneID, FloorPlanID, LocationID) + WHERE CharacterID IS NOT NULL; +GO + +IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_SceneFloorPlanOccupancy_StoryAssetID' AND object_id = OBJECT_ID(N'dbo.SceneFloorPlanOccupancy')) + CREATE INDEX IX_SceneFloorPlanOccupancy_StoryAssetID ON dbo.SceneFloorPlanOccupancy(StoryAssetID) + INCLUDE (SceneID, FloorPlanID, LocationID) + WHERE StoryAssetID IS NOT NULL; +GO diff --git a/PlotLine/Views/FloorPlans/Edit.cshtml b/PlotLine/Views/FloorPlans/Edit.cshtml index 87cf598..9e9994f 100644 --- a/PlotLine/Views/FloorPlans/Edit.cshtml +++ b/PlotLine/Views/FloorPlans/Edit.cshtml @@ -407,6 +407,17 @@