2026-04-08 09:03:02 +02:00
|
|
|
import { describe, expect, it } from 'vitest'
|
2026-04-18 11:53:06 +02:00
|
|
|
import { countAllByFilter, countAllNotesByFilter, countByFilter, filterEntries } from './noteListHelpers'
|
2026-04-08 09:03:02 +02:00
|
|
|
import { allSelection, makeEntry, mockEntries } from '../test-utils/noteListTestUtils'
|
2026-02-26 20:50:29 +01:00
|
|
|
|
2026-04-08 09:03:02 +02:00
|
|
|
describe('filterEntries', () => {
|
|
|
|
|
it('returns empty for entity selections because entity view uses grouped relationships', () => {
|
|
|
|
|
const result = filterEntries(mockEntries, { kind: 'entity', entry: mockEntries[4] })
|
|
|
|
|
expect(result).toHaveLength(0)
|
2026-02-26 20:50:29 +01:00
|
|
|
})
|
|
|
|
|
|
2026-04-08 09:03:02 +02:00
|
|
|
it('filters section groups by open sub-filter', () => {
|
|
|
|
|
const entries = [
|
|
|
|
|
makeEntry({ path: '/1.md', title: 'Active', isA: 'Project' }),
|
|
|
|
|
makeEntry({ path: '/2.md', title: 'Archived', isA: 'Project', archived: true }),
|
|
|
|
|
makeEntry({ path: '/4.md', title: 'Other', isA: 'Note' }),
|
2026-03-20 03:26:52 +01:00
|
|
|
]
|
2026-03-03 02:31:18 +01:00
|
|
|
|
2026-04-08 09:03:02 +02:00
|
|
|
const result = filterEntries(entries, { kind: 'sectionGroup', type: 'Project' }, 'open')
|
|
|
|
|
expect(result.map((entry) => entry.title)).toEqual(['Active'])
|
2026-03-03 02:31:18 +01:00
|
|
|
})
|
|
|
|
|
|
2026-04-08 09:03:02 +02:00
|
|
|
it('filters section groups by archived sub-filter', () => {
|
2026-03-03 02:31:18 +01:00
|
|
|
const entries = [
|
2026-04-08 09:03:02 +02:00
|
|
|
makeEntry({ path: '/1.md', title: 'Active', isA: 'Project' }),
|
|
|
|
|
makeEntry({ path: '/2.md', title: 'Archived', isA: 'Project', archived: true }),
|
|
|
|
|
makeEntry({ path: '/4.md', title: 'Other', isA: 'Note' }),
|
2026-03-03 02:31:18 +01:00
|
|
|
]
|
|
|
|
|
|
2026-04-08 09:03:02 +02:00
|
|
|
const result = filterEntries(entries, { kind: 'sectionGroup', type: 'Project' }, 'archived')
|
|
|
|
|
expect(result.map((entry) => entry.title)).toEqual(['Archived'])
|
2026-03-03 02:31:18 +01:00
|
|
|
})
|
|
|
|
|
|
2026-04-08 09:03:02 +02:00
|
|
|
it('defaults section groups to active notes when no sub-filter is provided', () => {
|
2026-03-03 02:31:18 +01:00
|
|
|
const entries = [
|
2026-04-08 09:03:02 +02:00
|
|
|
makeEntry({ path: '/1.md', title: 'Active', isA: 'Project' }),
|
|
|
|
|
makeEntry({ path: '/2.md', title: 'Archived', isA: 'Project', archived: true }),
|
|
|
|
|
makeEntry({ path: '/4.md', title: 'Other', isA: 'Note' }),
|
2026-03-03 02:31:18 +01:00
|
|
|
]
|
2026-03-03 11:22:04 +01:00
|
|
|
|
2026-04-08 09:03:02 +02:00
|
|
|
const result = filterEntries(entries, { kind: 'sectionGroup', type: 'Project' })
|
|
|
|
|
expect(result.map((entry) => entry.title)).toEqual(['Active'])
|
2026-03-03 11:22:04 +01:00
|
|
|
})
|
|
|
|
|
|
2026-04-08 09:03:02 +02:00
|
|
|
it('filters all notes by open sub-filter', () => {
|
|
|
|
|
const entries = [
|
|
|
|
|
makeEntry({ path: '/1.md', title: 'Active', isA: 'Project' }),
|
|
|
|
|
makeEntry({ path: '/2.md', title: 'Archived', isA: 'Project', archived: true }),
|
|
|
|
|
makeEntry({ path: '/4.md', title: 'Other', isA: 'Note' }),
|
2026-03-03 11:22:04 +01:00
|
|
|
]
|
2026-03-19 06:41:40 +01:00
|
|
|
|
2026-04-08 09:03:02 +02:00
|
|
|
const result = filterEntries(entries, allSelection, 'open')
|
|
|
|
|
expect(result.map((entry) => entry.title)).toEqual(['Active', 'Other'])
|
2026-03-19 06:41:40 +01:00
|
|
|
})
|
|
|
|
|
|
2026-04-08 09:03:02 +02:00
|
|
|
it('filters all notes by archived sub-filter', () => {
|
|
|
|
|
const entries = [
|
|
|
|
|
makeEntry({ path: '/1.md', title: 'Active', isA: 'Project' }),
|
|
|
|
|
makeEntry({ path: '/2.md', title: 'Archived', isA: 'Project', archived: true }),
|
|
|
|
|
makeEntry({ path: '/4.md', title: 'Other', isA: 'Note' }),
|
|
|
|
|
]
|
2026-03-19 06:41:40 +01:00
|
|
|
|
2026-04-08 09:03:02 +02:00
|
|
|
const result = filterEntries(entries, allSelection, 'archived')
|
|
|
|
|
expect(result.map((entry) => entry.title)).toEqual(['Archived'])
|
2026-03-19 06:41:40 +01:00
|
|
|
})
|
2026-04-18 11:53:06 +02:00
|
|
|
|
|
|
|
|
it('excludes attachments-folder markdown from the All Notes view', () => {
|
|
|
|
|
const entries = [
|
|
|
|
|
makeEntry({ path: '/vault/note/real-note.md', title: 'Real Note', isA: 'Note' }),
|
|
|
|
|
makeEntry({ path: '/vault/attachments/reference.md', title: 'Attachment Markdown', isA: 'Note' }),
|
|
|
|
|
makeEntry({ path: '/vault/attachments/nested/diagram.md', title: 'Nested Attachment Markdown', isA: 'Note' }),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const result = filterEntries(entries, allSelection, 'open')
|
|
|
|
|
expect(result.map((entry) => entry.title)).toEqual(['Real Note'])
|
|
|
|
|
})
|
2026-03-19 06:41:40 +01:00
|
|
|
})
|
|
|
|
|
|
2026-04-08 09:03:02 +02:00
|
|
|
describe('countByFilter', () => {
|
|
|
|
|
it('counts open and archived entries for a type', () => {
|
|
|
|
|
const entries = [
|
|
|
|
|
makeEntry({ path: '/1.md', isA: 'Project' }),
|
|
|
|
|
makeEntry({ path: '/2.md', isA: 'Project', archived: true }),
|
|
|
|
|
makeEntry({ path: '/3.md', isA: 'Project' }),
|
|
|
|
|
makeEntry({ path: '/4.md', isA: 'Note' }),
|
2026-03-19 06:41:40 +01:00
|
|
|
]
|
2026-03-31 11:19:31 +02:00
|
|
|
|
2026-04-08 09:03:02 +02:00
|
|
|
expect(countByFilter(entries, 'Project')).toEqual({ open: 2, archived: 1 })
|
2026-03-31 11:19:31 +02:00
|
|
|
})
|
|
|
|
|
|
2026-04-08 09:03:02 +02:00
|
|
|
it('returns zeros when a type has no matching entries', () => {
|
|
|
|
|
expect(countByFilter([], 'Project')).toEqual({ open: 0, archived: 0 })
|
2026-03-31 11:19:31 +02:00
|
|
|
})
|
|
|
|
|
})
|
feat: show all files in folder view, open text files in raw editor, gray out binary
Vault scanner now includes all files (not just .md). Each VaultEntry has a
fileKind field ("markdown", "text", or "binary") that controls how the
frontend handles it:
- Folder view shows all file kinds; other views (All Notes, type sections)
continue to show only markdown files
- Text files (.yml, .json, .txt, .py, etc.) open in the raw CodeMirror editor
- Binary files (.png, .jpg, .pdf, etc.) appear grayed out and are not clickable
- Non-markdown files use filename as title, skip frontmatter parsing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 17:38:09 +02:00
|
|
|
|
2026-04-08 09:03:02 +02:00
|
|
|
describe('countAllByFilter', () => {
|
|
|
|
|
it('counts all entries by archive status', () => {
|
|
|
|
|
const entries = [
|
|
|
|
|
makeEntry({ path: '/1.md', isA: 'Project' }),
|
|
|
|
|
makeEntry({ path: '/2.md', isA: 'Note' }),
|
|
|
|
|
makeEntry({ path: '/3.md', isA: 'Project', archived: true }),
|
feat: show all files in folder view, open text files in raw editor, gray out binary
Vault scanner now includes all files (not just .md). Each VaultEntry has a
fileKind field ("markdown", "text", or "binary") that controls how the
frontend handles it:
- Folder view shows all file kinds; other views (All Notes, type sections)
continue to show only markdown files
- Text files (.yml, .json, .txt, .py, etc.) open in the raw CodeMirror editor
- Binary files (.png, .jpg, .pdf, etc.) appear grayed out and are not clickable
- Non-markdown files use filename as title, skip frontmatter parsing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 17:38:09 +02:00
|
|
|
]
|
2026-04-08 09:03:02 +02:00
|
|
|
|
|
|
|
|
expect(countAllByFilter(entries)).toEqual({ open: 2, archived: 1 })
|
feat: show all files in folder view, open text files in raw editor, gray out binary
Vault scanner now includes all files (not just .md). Each VaultEntry has a
fileKind field ("markdown", "text", or "binary") that controls how the
frontend handles it:
- Folder view shows all file kinds; other views (All Notes, type sections)
continue to show only markdown files
- Text files (.yml, .json, .txt, .py, etc.) open in the raw CodeMirror editor
- Binary files (.png, .jpg, .pdf, etc.) appear grayed out and are not clickable
- Non-markdown files use filename as title, skip frontmatter parsing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 17:38:09 +02:00
|
|
|
})
|
2026-04-05 04:53:52 +02:00
|
|
|
|
2026-04-08 09:03:02 +02:00
|
|
|
it('excludes non-markdown files from counts', () => {
|
2026-04-05 04:53:52 +02:00
|
|
|
const entries = [
|
2026-04-08 09:03:02 +02:00
|
|
|
makeEntry({ path: '/1.md', isA: 'Note', fileKind: 'markdown' }),
|
|
|
|
|
makeEntry({ path: '/2.yml', isA: undefined, fileKind: 'text' }),
|
|
|
|
|
makeEntry({ path: '/3.png', isA: undefined, fileKind: 'binary' }),
|
2026-04-05 04:53:52 +02:00
|
|
|
]
|
2026-04-08 09:03:02 +02:00
|
|
|
|
|
|
|
|
expect(countAllByFilter(entries)).toEqual({ open: 1, archived: 0 })
|
2026-04-05 04:53:52 +02:00
|
|
|
})
|
|
|
|
|
})
|
2026-04-18 11:53:06 +02:00
|
|
|
|
|
|
|
|
describe('countAllNotesByFilter', () => {
|
|
|
|
|
it('excludes attachments-folder files from All Notes totals', () => {
|
|
|
|
|
const entries = [
|
|
|
|
|
makeEntry({ path: '/vault/note/real-note.md', isA: 'Note' }),
|
|
|
|
|
makeEntry({ path: '/vault/attachments/reference.md', isA: 'Note' }),
|
|
|
|
|
makeEntry({ path: '/vault/attachments/archive.md', isA: 'Note', archived: true }),
|
|
|
|
|
makeEntry({ path: '/vault/attachments/image.png', fileKind: 'binary' }),
|
|
|
|
|
makeEntry({ path: '/vault/archive/real-archive.md', isA: 'Note', archived: true }),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
expect(countAllNotesByFilter(entries)).toEqual({ open: 1, archived: 1 })
|
|
|
|
|
})
|
|
|
|
|
})
|