Phase 6A Plot Lines
This commit is contained in:
parent
9de7f099cb
commit
fb5352ab8f
@ -381,6 +381,7 @@ public sealed class ImportRepository(ISqlConnectionFactory connectionFactory) :
|
||||
BookID = (int?)null,
|
||||
PlotLineName = Clean(DisplayName(plotLine.DisplayName, plotLine.Name)),
|
||||
PlotLineTypeID = ResolvePlotLineTypeId(lookupIds, plotLine.Type),
|
||||
PlotImportanceID = ResolvePlotImportanceId(lookupIds, plotLine),
|
||||
Description = CombineText(
|
||||
plotLine.Description,
|
||||
MetadataLine("Type", plotLine.Type),
|
||||
@ -388,9 +389,9 @@ public sealed class ImportRepository(ISqlConnectionFactory connectionFactory) :
|
||||
plotLine.Notes,
|
||||
ImportMarker),
|
||||
ParentPlotLineID = (int?)null,
|
||||
EmergesFromPlotLineID = (int?)null,
|
||||
SortOrder = (int?)null,
|
||||
Colour = "#2f6f63",
|
||||
IsMainPlot = string.Equals(plotLine.Type?.Trim(), "Main Plot", StringComparison.OrdinalIgnoreCase),
|
||||
IsVisibleOnTimeline = true
|
||||
},
|
||||
transaction,
|
||||
@ -685,6 +686,9 @@ public sealed class ImportRepository(ISqlConnectionFactory connectionFactory) :
|
||||
var plotLineTypes = (await connection.QueryAsync<ImportLookupRow>(
|
||||
"SELECT PlotLineTypeID AS LookupID, TypeName FROM dbo.PlotLineTypes WHERE IsActive = 1;",
|
||||
transaction: transaction)).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
||||
var plotImportance = (await connection.QueryAsync<ImportLookupRow>(
|
||||
"SELECT PlotImportanceID AS LookupID, ImportanceName AS TypeName FROM dbo.PlotImportance WHERE IsActive = 1;",
|
||||
transaction: transaction)).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
||||
var threadTypes = (await connection.QueryAsync<ImportLookupRow>(
|
||||
"SELECT ThreadTypeID AS LookupID, TypeName FROM dbo.ThreadTypes WHERE IsActive = 1;",
|
||||
transaction: transaction)).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
||||
@ -726,6 +730,7 @@ public sealed class ImportRepository(ISqlConnectionFactory connectionFactory) :
|
||||
roleTypes,
|
||||
presenceTypes,
|
||||
plotLineTypes,
|
||||
plotImportance,
|
||||
threadTypes,
|
||||
threadStatuses,
|
||||
threadEventTypes,
|
||||
@ -1111,6 +1116,19 @@ public sealed class ImportRepository(ISqlConnectionFactory connectionFactory) :
|
||||
: lookupIds.PlotLineTypeIds.Values.First();
|
||||
}
|
||||
|
||||
private static int ResolvePlotImportanceId(ImportLookupIds lookupIds, ImportPlotLineDto plotLine)
|
||||
{
|
||||
if (string.Equals(plotLine.Type?.Trim(), "Main Plot", StringComparison.OrdinalIgnoreCase)
|
||||
&& lookupIds.PlotImportanceIds.TryGetValue("Primary", out var primaryId))
|
||||
{
|
||||
return primaryId;
|
||||
}
|
||||
|
||||
return lookupIds.PlotImportanceIds.TryGetValue("Secondary", out var secondaryId)
|
||||
? secondaryId
|
||||
: lookupIds.PlotImportanceIds.Values.First();
|
||||
}
|
||||
|
||||
private static int ResolveThreadTypeId(ImportLookupIds lookupIds, string? type)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(type) && lookupIds.ThreadTypeIds.TryGetValue(type.Trim(), out var id))
|
||||
@ -1387,6 +1405,7 @@ public sealed class ImportRepository(ISqlConnectionFactory connectionFactory) :
|
||||
IReadOnlyDictionary<string, int> RoleTypeIds,
|
||||
IReadOnlyDictionary<string, int> PresenceTypeIds,
|
||||
IReadOnlyDictionary<string, int> PlotLineTypeIds,
|
||||
IReadOnlyDictionary<string, int> PlotImportanceIds,
|
||||
IReadOnlyDictionary<string, int> ThreadTypeIds,
|
||||
IReadOnlyDictionary<string, int> ThreadStatusIds,
|
||||
IReadOnlyDictionary<string, int> ThreadEventTypeIds,
|
||||
|
||||
@ -1850,9 +1850,11 @@ public sealed class PlotRepository(ISqlConnectionFactory connectionFactory) : IP
|
||||
return new PlotLookupData
|
||||
{
|
||||
PlotLineTypes = (await result.ReadAsync<PlotLineType>()).ToList(),
|
||||
PlotImportance = (await result.ReadAsync<PlotImportance>()).ToList(),
|
||||
ThreadTypes = (await result.ReadAsync<ThreadType>()).ToList(),
|
||||
ThreadStatuses = (await result.ReadAsync<ThreadStatus>()).ToList(),
|
||||
ThreadEventTypes = (await result.ReadAsync<ThreadEventType>()).ToList()
|
||||
ThreadEventTypes = (await result.ReadAsync<ThreadEventType>()).ToList(),
|
||||
PlotEventTypes = (await result.ReadAsync<PlotEventType>()).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
@ -1881,11 +1883,12 @@ public sealed class PlotRepository(ISqlConnectionFactory connectionFactory) : IP
|
||||
plotLine.BookID,
|
||||
plotLine.PlotLineName,
|
||||
plotLine.PlotLineTypeID,
|
||||
plotLine.PlotImportanceID,
|
||||
plotLine.Description,
|
||||
plotLine.ParentPlotLineID,
|
||||
plotLine.EmergesFromPlotLineID,
|
||||
plotLine.SortOrder,
|
||||
plotLine.Colour,
|
||||
plotLine.IsMainPlot,
|
||||
plotLine.IsVisibleOnTimeline
|
||||
},
|
||||
commandType: CommandType.StoredProcedure);
|
||||
@ -1969,6 +1972,8 @@ public sealed class PlotRepository(ISqlConnectionFactory connectionFactory) : IP
|
||||
threadEvent.PlotThreadID,
|
||||
threadEvent.SceneID,
|
||||
threadEvent.EventTypeID,
|
||||
threadEvent.PlotEventTypeID,
|
||||
threadEvent.TargetPlotLineID,
|
||||
threadEvent.EventTitle,
|
||||
threadEvent.EventDescription
|
||||
},
|
||||
|
||||
@ -361,6 +361,14 @@ public sealed class PlotLineType
|
||||
public bool IsActive { get; set; }
|
||||
}
|
||||
|
||||
public sealed class PlotImportance
|
||||
{
|
||||
public int PlotImportanceID { get; set; }
|
||||
public string ImportanceName { get; set; } = string.Empty;
|
||||
public int SortOrder { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
}
|
||||
|
||||
public sealed class PlotLineItem
|
||||
{
|
||||
public int PlotLineID { get; set; }
|
||||
@ -370,12 +378,15 @@ public sealed class PlotLineItem
|
||||
public string PlotLineName { get; set; } = string.Empty;
|
||||
public int PlotLineTypeID { get; set; }
|
||||
public string PlotLineTypeName { get; set; } = string.Empty;
|
||||
public int PlotImportanceID { get; set; } = 2;
|
||||
public string PlotImportanceName { get; set; } = "Secondary";
|
||||
public string? Description { get; set; }
|
||||
public int? ParentPlotLineID { get; set; }
|
||||
public string? ParentPlotLineName { get; set; }
|
||||
public int? EmergesFromPlotLineID { get; set; }
|
||||
public string? EmergesFromPlotLineName { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
public string Colour { get; set; } = "#2f6f63";
|
||||
public bool IsMainPlot { get; set; }
|
||||
public bool IsVisibleOnTimeline { get; set; } = true;
|
||||
public DateTime CreatedDate { get; set; }
|
||||
public DateTime UpdatedDate { get; set; }
|
||||
@ -434,6 +445,14 @@ public sealed class ThreadEventType
|
||||
public bool IsActive { get; set; }
|
||||
}
|
||||
|
||||
public sealed class PlotEventType
|
||||
{
|
||||
public int PlotEventTypeID { get; set; }
|
||||
public string TypeName { get; set; } = string.Empty;
|
||||
public int SortOrder { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
}
|
||||
|
||||
public sealed class ThreadEvent
|
||||
{
|
||||
public int ThreadEventID { get; set; }
|
||||
@ -446,12 +465,23 @@ public sealed class ThreadEvent
|
||||
public int EventTypeID { get; set; }
|
||||
public string EventTypeName { get; set; } = string.Empty;
|
||||
public string MarkerText { get; set; } = string.Empty;
|
||||
public int PlotEventTypeID { get; set; } = 2;
|
||||
public string PlotEventTypeName { get; set; } = "Progress";
|
||||
public int? TargetPlotLineID { get; set; }
|
||||
public string? TargetPlotLineName { get; set; }
|
||||
public string EventTitle { get; set; } = string.Empty;
|
||||
public string? EventDescription { get; set; }
|
||||
public DateTime CreatedDate { get; set; }
|
||||
public DateTime UpdatedDate { get; set; }
|
||||
}
|
||||
|
||||
public sealed class PlotEventTargetPlotLine
|
||||
{
|
||||
public int PlotEventID { get; set; }
|
||||
public int PlotLineID { get; set; }
|
||||
public DateTime CreatedDate { get; set; }
|
||||
}
|
||||
|
||||
public sealed class SceneOption
|
||||
{
|
||||
public int SceneID { get; set; }
|
||||
@ -465,9 +495,11 @@ public sealed class SceneOption
|
||||
public sealed class PlotLookupData
|
||||
{
|
||||
public IReadOnlyList<PlotLineType> PlotLineTypes { get; init; } = [];
|
||||
public IReadOnlyList<PlotImportance> PlotImportance { get; init; } = [];
|
||||
public IReadOnlyList<ThreadType> ThreadTypes { get; init; } = [];
|
||||
public IReadOnlyList<ThreadStatus> ThreadStatuses { get; init; } = [];
|
||||
public IReadOnlyList<ThreadEventType> ThreadEventTypes { get; init; } = [];
|
||||
public IReadOnlyList<PlotEventType> PlotEventTypes { get; init; } = [];
|
||||
}
|
||||
|
||||
public sealed class AssetKind
|
||||
|
||||
@ -2058,6 +2058,8 @@ public sealed class PlotService(IProjectRepository projects, IBookRepository boo
|
||||
SortOrder = (plotLines.Count + 1) * 10,
|
||||
Colour = "#2f6f63",
|
||||
IsVisibleOnTimeline = true,
|
||||
PlotImportanceID = lookupData.PlotImportance.FirstOrDefault(x => x.ImportanceName == "Secondary")?.PlotImportanceID
|
||||
?? lookupData.PlotImportance.First().PlotImportanceID,
|
||||
PlotLineTypeID = lookupData.PlotLineTypes.FirstOrDefault(x => x.TypeName == "Side Plot")?.PlotLineTypeID
|
||||
?? lookupData.PlotLineTypes.First().PlotLineTypeID
|
||||
}, lookupData, plotLines);
|
||||
@ -2086,11 +2088,12 @@ public sealed class PlotService(IProjectRepository projects, IBookRepository boo
|
||||
BookID = plotLine.BookID,
|
||||
PlotLineName = plotLine.PlotLineName,
|
||||
PlotLineTypeID = plotLine.PlotLineTypeID,
|
||||
PlotImportanceID = plotLine.PlotImportanceID,
|
||||
Description = plotLine.Description,
|
||||
ParentPlotLineID = plotLine.ParentPlotLineID,
|
||||
EmergesFromPlotLineID = plotLine.EmergesFromPlotLineID,
|
||||
SortOrder = plotLine.SortOrder,
|
||||
Colour = plotLine.Colour,
|
||||
IsMainPlot = plotLine.IsMainPlot,
|
||||
IsVisibleOnTimeline = plotLine.IsVisibleOnTimeline,
|
||||
Project = project
|
||||
}, lookupData, plotLines.Where(x => x.PlotLineID != plotLine.PlotLineID));
|
||||
@ -2106,11 +2109,12 @@ public sealed class PlotService(IProjectRepository projects, IBookRepository boo
|
||||
BookID = model.BookID,
|
||||
PlotLineName = model.PlotLineName,
|
||||
PlotLineTypeID = model.PlotLineTypeID,
|
||||
PlotImportanceID = model.PlotImportanceID,
|
||||
Description = model.Description,
|
||||
ParentPlotLineID = model.ParentPlotLineID,
|
||||
EmergesFromPlotLineID = model.EmergesFromPlotLineID,
|
||||
SortOrder = model.SortOrder,
|
||||
Colour = string.IsNullOrWhiteSpace(model.Colour) ? "#2f6f63" : model.Colour,
|
||||
IsMainPlot = model.IsMainPlot,
|
||||
IsVisibleOnTimeline = model.IsVisibleOnTimeline
|
||||
});
|
||||
await activity.RecordAsync(model.ProjectID, isNew ? "Created" : "Updated", "Plot Line", plotLineId, model.PlotLineName);
|
||||
@ -2264,6 +2268,7 @@ public sealed class PlotService(IProjectRepository projects, IBookRepository boo
|
||||
PlotThreadID = plotThreadId,
|
||||
SceneID = model.SceneID,
|
||||
EventTypeID = eventType.ThreadEventTypeID,
|
||||
PlotEventTypeID = lookupData.PlotEventTypes.FirstOrDefault(x => x.TypeName == "Progress")?.PlotEventTypeID ?? 2,
|
||||
EventTitle = title,
|
||||
EventDescription = model.EventDescription
|
||||
});
|
||||
@ -2297,6 +2302,7 @@ public sealed class PlotService(IProjectRepository projects, IBookRepository boo
|
||||
private async Task<PlotLineEditViewModel> PopulatePlotLineListsAsync(PlotLineEditViewModel model, PlotLookupData lookupData, IEnumerable<PlotLineItem> parentCandidates)
|
||||
{
|
||||
model.PlotLineTypes = ChapterService.ToSelectList(lookupData.PlotLineTypes, x => x.PlotLineTypeID, x => x.TypeName);
|
||||
model.PlotImportance = ChapterService.ToSelectList(lookupData.PlotImportance, x => x.PlotImportanceID, x => x.ImportanceName);
|
||||
model.BookOptions = (await books.ListByProjectAsync(model.ProjectID))
|
||||
.Select(x => new SelectListItem($"Book {x.BookNumber}: {x.BookTitle}", x.BookID.ToString()))
|
||||
.ToList();
|
||||
|
||||
1065
PlotLine/Sql/053_Phase6A_PlotLineDataModel.sql
Normal file
1065
PlotLine/Sql/053_Phase6A_PlotLineDataModel.sql
Normal file
File diff suppressed because it is too large
Load Diff
@ -704,26 +704,30 @@ public sealed class PlotLineEditViewModel
|
||||
[Display(Name = "Type")]
|
||||
public int PlotLineTypeID { get; set; }
|
||||
|
||||
[Display(Name = "Importance")]
|
||||
public int PlotImportanceID { get; set; } = 2;
|
||||
|
||||
public int? BookID { get; set; }
|
||||
public string? Description { get; set; }
|
||||
|
||||
[Display(Name = "Parent plot line")]
|
||||
public int? ParentPlotLineID { get; set; }
|
||||
|
||||
[Display(Name = "Emerges from plot line")]
|
||||
public int? EmergesFromPlotLineID { get; set; }
|
||||
|
||||
[Display(Name = "Sort order")]
|
||||
public int SortOrder { get; set; }
|
||||
|
||||
[Display(Name = "Colour")]
|
||||
public string Colour { get; set; } = "#2f6f63";
|
||||
|
||||
[Display(Name = "Main plot")]
|
||||
public bool IsMainPlot { get; set; }
|
||||
|
||||
[Display(Name = "Visible on timeline")]
|
||||
public bool IsVisibleOnTimeline { get; set; } = true;
|
||||
|
||||
public Project? Project { get; set; }
|
||||
public IReadOnlyList<SelectListItem> PlotLineTypes { get; set; } = [];
|
||||
public IReadOnlyList<SelectListItem> PlotImportance { get; set; } = [];
|
||||
public IReadOnlyList<SelectListItem> BookOptions { get; set; } = [];
|
||||
public IReadOnlyList<SelectListItem> ParentPlotLineOptions { get; set; } = [];
|
||||
}
|
||||
|
||||
@ -48,6 +48,10 @@
|
||||
<label asp-for="PlotLineTypeID" class="form-label">Type <help-icon key="plotLines.fields.type" mode="inline" /></label>
|
||||
<select asp-for="PlotLineTypeID" asp-items="Model.PlotLineTypes" class="form-select"></select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label asp-for="PlotImportanceID" class="form-label">Importance</label>
|
||||
<select asp-for="PlotImportanceID" asp-items="Model.PlotImportance" class="form-select"></select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label asp-for="BookID" class="form-label">Book / scope <help-icon key="plotLines.fields.scope" mode="inline" /></label>
|
||||
<select asp-for="BookID" asp-items="Model.BookOptions" class="form-select">
|
||||
@ -60,6 +64,12 @@
|
||||
<option value="">None</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label asp-for="EmergesFromPlotLineID" class="form-label">Emerges from plot line</label>
|
||||
<select asp-for="EmergesFromPlotLineID" asp-items="Model.ParentPlotLineOptions" class="form-select">
|
||||
<option value="">None</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label asp-for="SortOrder" class="form-label"></label>
|
||||
<input asp-for="SortOrder" class="form-control" />
|
||||
@ -72,12 +82,6 @@
|
||||
<label asp-for="Description" class="form-label"></label>
|
||||
<textarea asp-for="Description" class="form-control" rows="4"></textarea>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="purpose-check">
|
||||
<input asp-for="IsMainPlot" />
|
||||
<span>Main plot <help-icon key="plotLines.fields.mainPlot" mode="inline" /></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="purpose-check">
|
||||
<input asp-for="IsVisibleOnTimeline" />
|
||||
|
||||
@ -36,6 +36,7 @@
|
||||
<th>Colour</th>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Importance</th>
|
||||
<th>Book</th>
|
||||
<th>Timeline</th>
|
||||
<th></th>
|
||||
@ -48,6 +49,7 @@
|
||||
<td><span class="colour-swatch" style="background:@plotLine.Colour"></span></td>
|
||||
<td><a asp-action="Edit" asp-route-id="@plotLine.PlotLineID">@plotLine.PlotLineName</a></td>
|
||||
<td>@plotLine.PlotLineTypeName</td>
|
||||
<td>@plotLine.PlotImportanceName</td>
|
||||
<td>@(plotLine.BookTitle ?? "Project-wide")</td>
|
||||
<td>@(plotLine.IsVisibleOnTimeline ? "Visible" : "Hidden")</td>
|
||||
<td class="text-end">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user