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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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}`}
|
||||
|
||||
Reference in New Issue
Block a user