Skip to content

Commit c5593e4

Browse files
committed
Prioritize changed subtitles in memory review
1 parent 75dd563 commit c5593e4

File tree

1 file changed

+70
-16
lines changed

1 file changed

+70
-16
lines changed

packages/web/src/pages/MemoryReviewPage.tsx

Lines changed: 70 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ interface MemoryTreeNode {
7171
children?: MemoryTreeNode[]
7272
}
7373

74+
interface RankedSection {
75+
id: string
76+
title: string
77+
changed: boolean
78+
}
79+
7480
function formatBytes(size: number): string {
7581
if (size < 1024) return `${size} B`
7682
if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`
@@ -393,6 +399,22 @@ function buildCatalogQuery(extraMarkdownDirs: string[], extraFilePaths: string[]
393399
return qs ? `?${qs}` : ''
394400
}
395401

402+
function rankSections(file: MemoryFile, modification?: MemoryModification | null): RankedSection[] {
403+
const haystack = `${modification?.oldContent ?? ''}\n${modification?.newContent ?? ''}\n${modification?.generatedContent ?? ''}`.toLowerCase()
404+
const ranked = file.sections.map(section => ({
405+
...section,
406+
changed: section.title.trim().length > 0 && haystack.includes(section.title.toLowerCase()),
407+
}))
408+
ranked.sort((a, b) => {
409+
if (a.changed !== b.changed) return a.changed ? -1 : 1
410+
return a.title.localeCompare(b.title)
411+
})
412+
if (!ranked.some(section => section.changed) && modification && ranked.length > 0) {
413+
ranked[0] = { ...ranked[0], changed: true }
414+
}
415+
return ranked
416+
}
417+
396418
export default function MemoryReviewPage() {
397419
const { id } = useParams<{ id: string }>()
398420
const navigate = useNavigate()
@@ -521,6 +543,14 @@ export default function MemoryReviewPage() {
521543
return payload.modifications.find(mod => mod.fileId === selectedFileId) ?? null
522544
}, [payload, selectedFileId])
523545

546+
const modificationByFileId = useMemo(() => {
547+
const map = new Map<string, MemoryModification>()
548+
for (const modification of payload?.modifications ?? []) {
549+
map.set(modification.fileId, modification)
550+
}
551+
return map
552+
}, [payload])
553+
524554
const diffLines = useMemo(() => {
525555
if (!selectedModification) return []
526556
return computeSimpleDiff(selectedModification.oldContent, selectedModification.newContent)
@@ -900,22 +930,46 @@ export default function MemoryReviewPage() {
900930
<span key={cat} className="text-[10px] px-1.5 py-0.5 rounded bg-zinc-100 dark:bg-zinc-800 text-zinc-500 dark:text-slate-400">{cat}</span>
901931
))}
902932
</div>
903-
{file.sections.slice(0, 8).map(sec => (
904-
<button
905-
key={sec.id}
906-
onClick={() => {
907-
setSelectedFileId(file.id)
908-
setFocusedSectionTitle(sec.title)
909-
}}
910-
className={`block w-full text-left text-[11px] truncate ${
911-
changedFileIds.has(file.id)
912-
? 'text-amber-600 dark:text-amber-300 hover:text-amber-700 dark:hover:text-amber-200'
913-
: 'text-zinc-500 dark:text-slate-400 hover:text-zinc-700 dark:hover:text-slate-200'
914-
}`}
915-
>
916-
# {sec.title}
917-
</button>
918-
))}
933+
{(() => {
934+
const rankedSections = rankSections(file, modificationByFileId.get(file.id))
935+
const previewToggleId = `${fileNodeId}:subtitle-preview`
936+
const previewExpanded = collapsedIds.has(previewToggleId)
937+
const changedSections = rankedSections.filter(section => section.changed)
938+
const unchangedSections = rankedSections.filter(section => !section.changed)
939+
const visibleSections = previewExpanded
940+
? rankedSections.slice(0, 8)
941+
: [...changedSections.slice(0, 4), ...(changedSections.length === 0 ? unchangedSections.slice(0, 1) : [])]
942+
const hiddenCount = Math.max(0, Math.min(rankedSections.length, 8) - visibleSections.length)
943+
return (
944+
<>
945+
{visibleSections.map(sec => (
946+
<button
947+
key={sec.id}
948+
onClick={() => {
949+
setSelectedFileId(file.id)
950+
setFocusedSectionTitle(sec.title)
951+
}}
952+
className={`block w-full text-left text-[11px] truncate ${
953+
sec.changed
954+
? 'text-amber-600 dark:text-amber-300 hover:text-amber-700 dark:hover:text-amber-200 font-medium'
955+
: 'text-zinc-500 dark:text-slate-400 hover:text-zinc-700 dark:hover:text-slate-200'
956+
}`}
957+
>
958+
{sec.changed ? '# ' : '... '}
959+
{sec.title}
960+
</button>
961+
))}
962+
{hiddenCount > 0 && (
963+
<button
964+
onClick={() => toggleCollapse(previewToggleId)}
965+
className="block w-full text-left text-[11px] text-zinc-400 dark:text-slate-500 hover:text-zinc-700 dark:hover:text-slate-200"
966+
>
967+
{previewExpanded ? 'Fold subtitle preview' : `... unfold ${hiddenCount} more subtitle${hiddenCount > 1 ? 's' : ''}`}
968+
</button>
969+
)}
970+
</>
971+
)
972+
})()}
919973
</div>
920974
)}
921975
</div>

0 commit comments

Comments
 (0)