Dashboard: show 10 chapters titled Chapters; bump chapter mtime on beat changes

Beat create/update/delete/reorder/assign/move now touch the parent
chapter's UpdatedAt so the dashboard's recency sort reflects beat edits,
not just chapter-level prose/tag changes.
This commit is contained in:
James Wampler
2026-08-17 22:53:05 -07:00
parent 17facba3b9
commit bc85a36e18
3 changed files with 49 additions and 3 deletions
+21 -1
View File
@@ -116,6 +116,8 @@ public class BeatService(
beat.Tags = await tags.ResolveAsync(chapter.ProjectId, names, ct);
}
chapter.UpdatedAt = DateTimeOffset.UtcNow;
db.Beats.Add(beat);
await db.SaveChangesAsync(ct);
@@ -150,6 +152,7 @@ public class BeatService(
beat.WhatHappened = Patch.Apply(beat.WhatHappened, request.WhatHappened);
beat.WhatsNext = Patch.Apply(beat.WhatsNext, request.WhatsNext);
beat.UpdatedAt = DateTimeOffset.UtcNow;
chapter.UpdatedAt = beat.UpdatedAt;
if (request.CharacterIds is { } characterIds)
{
@@ -179,6 +182,12 @@ public class BeatService(
await RequireBeatAccessAsync(beat, ProjectPermission.DeleteContent, ct);
var chapter = await db.Chapters.FirstOrDefaultAsync(c => c.Id == beat.ChapterId, ct);
if (chapter is not null)
{
chapter.UpdatedAt = DateTimeOffset.UtcNow;
}
db.Beats.Remove(beat);
await db.SaveChangesAsync(ct);
return true;
@@ -215,6 +224,12 @@ public class BeatService(
beat.SortOrder = order++;
}
var chapter = await db.Chapters.FirstOrDefaultAsync(c => c.Id == chapterId, ct);
if (chapter is not null)
{
chapter.UpdatedAt = DateTimeOffset.UtcNow;
}
await db.SaveChangesAsync(ct);
return await ListAsync(chapterId, ct);
}
@@ -262,6 +277,7 @@ public class BeatService(
{
beat.Characters.Add(character);
beat.UpdatedAt = DateTimeOffset.UtcNow;
chapter.UpdatedAt = beat.UpdatedAt;
}
await db.SaveChangesAsync(ct);
@@ -312,14 +328,18 @@ public class BeatService(
}
var nextSortOrder = await NextSortOrderAsync(request.TargetChapterId, ct);
var now = DateTimeOffset.UtcNow;
foreach (var beatId in request.BeatIds)
{
var beat = beats.Single(b => b.Id == beatId);
beat.ChapterId = request.TargetChapterId;
beat.SortOrder = nextSortOrder++;
beat.UpdatedAt = DateTimeOffset.UtcNow;
beat.UpdatedAt = now;
}
chapter.UpdatedAt = now;
targetChapter.UpdatedAt = now;
await db.SaveChangesAsync(ct);
return beats;
}
+3 -2
View File
@@ -5,6 +5,7 @@ import { useAuth } from '../auth/AuthContext'
import { AutoField, EmptyState, ErrorNote, Spinner, StatusBadge } from '../components/ui'
const RECENT_COUNT = 5
const RECENT_CHAPTERS_COUNT = 10
export default function DashboardPage() {
const { projectId = '' } = useParams()
@@ -61,7 +62,7 @@ function OutliningDashboard({ projectId }: { projectId: string }) {
<div className="grid gap-6 lg:grid-cols-3">
<section className="card p-5 lg:col-span-2">
<div className="mb-4 flex items-center justify-between gap-4">
<h2 className="text-lg font-semibold">Outline</h2>
<h2 className="text-lg font-semibold">Chapters</h2>
<Link to="chapters" className="text-sm muted hover:underline">
View all
</Link>
@@ -74,7 +75,7 @@ function OutliningDashboard({ projectId }: { projectId: string }) {
<EmptyState title="No chapters yet" hint="Add the first chapter to start outlining." />
) : (
<ul className="grid grid-cols-1 gap-2">
{recentChapters.slice(0, RECENT_COUNT).map((chapter) => (
{recentChapters.slice(0, RECENT_CHAPTERS_COUNT).map((chapter) => (
<li key={chapter.id}>
<Link
to={`chapters/${chapter.id}`}