diff --git a/src/components/Sidebar.test.tsx b/src/components/Sidebar.test.tsx index 6e9a733b..b1fbd067 100644 --- a/src/components/Sidebar.test.tsx +++ b/src/components/Sidebar.test.tsx @@ -914,6 +914,63 @@ describe('Sidebar', () => { }) }) + describe('Note type in sidebar', () => { + const noteEntries: VaultEntry[] = [ + ...mockEntries, + { + path: '/vault/note.md', filename: 'note.md', title: 'Note', isA: 'Type', + aliases: [], belongsTo: [], relatedTo: [], status: null, owner: null, cadence: null, + archived: false, trashed: false, trashedAt: null, modifiedAt: 1700000000, createdAt: null, + fileSize: 200, snippet: '', wordCount: 0, relationships: {}, + icon: null, color: null, order: null, sidebarLabel: null, template: null, sort: null, + outgoingLinks: [], properties: {}, + }, + { + path: '/vault/explicit-note.md', filename: 'explicit-note.md', title: 'Explicit Note', + isA: 'Note', aliases: [], belongsTo: [], relatedTo: [], status: null, owner: null, + cadence: null, archived: false, trashed: false, trashedAt: null, modifiedAt: 1700000000, + createdAt: null, fileSize: 300, snippet: '', wordCount: 0, relationships: {}, + icon: null, color: null, order: null, sidebarLabel: null, template: null, sort: null, + outgoingLinks: [], properties: {}, + }, + { + path: '/vault/untyped-note.md', filename: 'untyped-note.md', title: 'Untyped Note', + isA: null, aliases: [], belongsTo: [], relatedTo: [], status: null, owner: null, + cadence: null, archived: false, trashed: false, trashedAt: null, modifiedAt: 1700000000, + createdAt: null, fileSize: 150, snippet: '', wordCount: 0, relationships: {}, + icon: null, color: null, order: null, sidebarLabel: null, template: null, sort: null, + outgoingLinks: [], properties: {}, + }, + ] + + it('shows Notes section when Note entries exist', () => { + render( {}} />) + expect(screen.getByText('Notes')).toBeInTheDocument() + }) + + it('includes both explicit and untyped notes under Notes section', () => { + render( {}} />) + fireEvent.click(screen.getByLabelText('Expand Notes')) + expect(screen.getByText('Explicit Note')).toBeInTheDocument() + expect(screen.getByText('Untyped Note')).toBeInTheDocument() + }) + + it('shows Notes section for untyped entries even without explicit Note entries', () => { + const untypedOnly: VaultEntry[] = [ + { + path: '/vault/plain.md', filename: 'plain.md', title: 'Plain Note', + isA: null, aliases: [], belongsTo: [], relatedTo: [], status: null, owner: null, + cadence: null, archived: false, trashed: false, trashedAt: null, modifiedAt: 1700000000, + createdAt: null, fileSize: 100, snippet: '', wordCount: 0, relationships: {}, + icon: null, color: null, order: null, sidebarLabel: null, template: null, sort: null, + outgoingLinks: [], properties: {}, + }, + ] + render( {}} />) + expect(screen.getByText('Notes')).toBeInTheDocument() + }) + }) + it('renders exactly one section for a hyphenated custom type like Monday Ideas', () => { const entriesWithMondayIdeas: VaultEntry[] = [ ...mockEntries, diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 3dde792c..6c5bfc0e 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -115,7 +115,9 @@ function SortableSection({ group, sectionProps }: { & { entries: VaultEntry[]; collapsed: Record; onToggle: (type: string) => void; renamingType: string | null; renameInitialValue: string } }) { const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: group.type }) - const items = sectionProps.entries.filter((e) => e.isA === group.type && !e.archived && !e.trashed) + const items = sectionProps.entries.filter((e) => + !e.archived && !e.trashed && (group.type === 'Note' ? (e.isA === 'Note' || !e.isA) : e.isA === group.type), + ) const isCollapsed = sectionProps.collapsed[group.type] ?? true const isRenaming = sectionProps.renamingType === group.type diff --git a/src/utils/sidebarSections.ts b/src/utils/sidebarSections.ts index acd7d0aa..1ab3e8fe 100644 --- a/src/utils/sidebarSections.ts +++ b/src/utils/sidebarSections.ts @@ -26,11 +26,11 @@ const BUILT_IN_SECTION_GROUPS: SectionGroup[] = [ /** Metadata lookup for well-known types (icon/label only — NOT used to determine which sections to show) */ const BUILT_IN_TYPE_MAP = new Map(BUILT_IN_SECTION_GROUPS.map((sg) => [sg.type, sg])) -/** Collect unique isA values from active (non-trashed, non-archived) entries, excluding generic Note */ +/** Collect unique isA values from active (non-trashed, non-archived) entries. Untyped entries count as 'Note'. */ export function collectActiveTypes(entries: VaultEntry[]): Set { const types = new Set() for (const e of entries) { - if (e.isA && e.isA !== 'Note' && !e.trashed && !e.archived) types.add(e.isA) + if (!e.trashed && !e.archived) types.add(e.isA || 'Note') } return types }