Export buildNewEntry, slugify, entryMatchesTarget, buildNoteContent,
resolveNewNote, resolveNewType as public functions for direct unit testing.
Add coverage exclusions for untestable files: shadcn/ui primitives,
AI modules (useAIChat, useMcpBridge, ai-chat, AIChatPanel), and types.ts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove unused cn import from NoteList.tsx
- Fix SidebarSelection type narrowing in NoteList entity view
- Fix SortableSection onToggle type in Sidebar Omit type
- Fix TypeRow isA prop to accept null
- Align useEntryActions handleUpdateFrontmatter value type
- Add missing trashed/trashedAt/order to test mock VaultEntry objects
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Split Inspector.tsx (score 7.78) into:
- Inspector.tsx: slim shell with header, layout, prop wiring (score 9.6)
- InspectorPanels.tsx: DynamicRelationshipsPanel, BacklinksPanel,
GitHistoryPanel, LinkButton, RelationshipGroup (score 8.87)
Extracted LinkButton as reusable component for both relationship
refs and backlinks. Moved resolveRefProps to simplify RelationshipGroup.
Extracted AddRelationshipForm and extractRelationshipRefs as focused units.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Break up the monolithic useNoteActions hook (cc=37, 232 LoC, score 6.89) into:
- useTabManagement: owns tab state and all tab operations (score 9.53)
- mockFrontmatterHelpers: extracted and simplified YAML manipulation (score 9.09+)
- useNoteActions: now focused on note creation and frontmatter operations (score 9.22)
Key improvements:
- Extracted entryMatchesTarget() to reduce wikilink matching complexity
- Deduplicated replaceKeyInLines/removeKeyFromLines into processKeyInLines
- Converted buildNewEntry to use object param (was 5 positional args)
- Overall complexity reduced from cc=37 to cc=11 in useNoteActions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When pressing Enter in the inline tab rename input, handleSave was
called twice: once from the keydown handler and again from the blur
event triggered when React unmounted the input (editingPath → null).
The second rename call found the old path already deleted/moved,
producing empty content that overwrote the correctly renamed file
in MOCK_CONTENT — causing the editor to show a blank note.
Added a committedRef guard to InlineTabEdit so handleSave only
executes once per edit session.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
onClick={onCreateNote} passes the React MouseEvent as the first arg
to handleCreateNoteImmediate(type?), which treats it as a truthy type
string. generateUntitledName then calls .toLowerCase() on the event
object, throwing a TypeError and silently aborting note creation.
Wrap both NoteList and TabBar onClick handlers to call with no args.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When viewing a commit diff from git history, the GitBranch toggle in the
breadcrumb bar was disabled if the file had no unstaged changes, leaving
no way to return to the editor. Now the toggle stays active whenever
diffMode is true, and a visible "Back to editor" button appears at the
top of the diff view for better discoverability.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add get_file_diff_at_commit Rust command to show diff at a specific commit
- Make shortHash in GitHistoryPanel a clickable button that opens DiffView
- Show author name below commit message (small, muted)
- Remove disabled "View all revisions" button
- Wire onLoadDiffAtCommit through Editor → Inspector → App.tsx
- Add mock handler for get_file_diff_at_commit in browser mode
- Fix pre-existing missing `order` field on trashed mock entries
- Update Inspector tests for new behavior
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add trashed, trashedAt, and order properties that were missing from
test entry objects after those fields were added to the VaultEntry type.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the CreateNoteDialog flow with immediate creation. Clicking + or
pressing Cmd+N now instantly creates an "Untitled note" (type=Note) and
opens it as the active tab. Sidebar section + buttons create "Untitled
<type>" for that section's type. Editor auto-focuses after creation so
the user can start typing immediately.
Product decisions:
- Title naming: "Untitled note", "Untitled note 2", etc. for conflicts
- Sidebar section +: creates with that section's type directly
- Editor focus via custom event to avoid stealing focus on regular tab switches
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add `truncate` and `min-w-0` Tailwind classes to property value elements
in the properties panel so long text is shown on a single line with
ellipsis. The full value is visible via the title attribute on hover.
Affected elements:
- EditableValue display span (main property values)
- Status pill in DynamicPropertiesPanel
- Type button in DynamicPropertiesPanel
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add archive/unarchive toggle button to the BreadcrumbBar (Archive icon
for normal notes, ArrowUUpLeft icon for archived notes). Add cmd+e
keyboard shortcut to toggle archive state of the active note.
Refactored useAppKeyboard to use action map pattern (reduces cyclomatic
complexity) and extracted BreadcrumbActions from BreadcrumbBar to split
rendering complexity across two functions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Inspector aside element was missing flex-1, so it only grew to
its content height instead of filling the full height of its parent
flex-col container.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Changed the sidebar section header from a button-style "Customize sections"
label with inline icon to a clean "Sections" heading with the settings icon
pushed to the far right. The settings icon still toggles the customize
popover — no functionality change.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests verify:
- Trash button shows for non-trashed notes
- Restore button shows for trashed notes
- onClick callbacks fire correctly for both
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Added trash icon button in breadcrumb bar for non-trashed notes
- Added restore (arrow counter-clockwise) button for trashed notes
- Trash button sets trashed=true and trashed_at in frontmatter
- Restore button removes trashed/trashed_at from frontmatter
- Added Cmd+Delete keyboard shortcut to trash active note
- Wired handlers through Editor -> App with vault entry updates
- Toast notifications for trash/restore actions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix toggleSection to account for default collapsed state
(collapsed[type] ?? true, not just !prev[type])
- Update tests to expand sections before asserting item visibility
(sections start collapsed by default)
- Add tests for section ordering by Type entry order property
- Add test for drag handle rendering on section headers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Wrap sidebar section groups in @dnd-kit sortable context
- Add grip-vertical drag handle visible on hover of section headers
- Sort sections by `order` property from Type document entries
- On drag end, compute new sequential order values and persist to
each Type document's frontmatter via handleReorderSections
- Add onReorderSections callback from Sidebar → App.tsx → vault
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add `order: number | null` to VaultEntry (TS) and VaultEntry (Rust)
- Add order to Frontmatter struct and SKIP_KEYS in vault.rs
- Update all mock Type documents with order values (0-10)
- Add order: null to all non-Type mock entries and test fixtures
- Install @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests cover: rendering all tabs, draggable attribute, reorder on DnD,
no-op when dropping in same position, and tab switching on click.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- TabBar: HTML5 drag-and-drop on tab elements (grab/grabbing cursor,
0.5 opacity on dragged tab, 2px primary-color drop indicator)
- useNoteActions: handleReorderTabs splices tab array, saves order
to localStorage under "laputa-tab-order" key
- Tab order auto-persists on every change; restored on mount
- Wired through Editor → App props chain
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All MOCK_ENTRIES now have realistic createdAt timestamps (always before
modifiedAt). Stock Screener status changed to 'Paused' for sort-by-status
testing variety.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests for getSortComparator (6 tests):
- Sort by modified date descending
- Sort by created date descending (with fallback)
- Sort by title alphabetically
- Sort by status with priority ordering
- Status sort with modified-date tiebreaker
Tests for NoteList sort controls (6 tests):
- Sort button visible in flat list header
- Sort dropdown per relationship subsection
- Sort menu opens with all options
- Sort order changes on option selection
- Menu closes after selection
- Relationship subsection sorting works
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each relationship subsection header now has a sort dropdown control
(ArrowsDownUp icon + current sort label). Users can choose to sort by:
- Modified date (default, newest first)
- Created date (newest first)
- Title (alphabetical A-Z)
- Status (Active > Paused > Done > Finished)
The sort control also appears in the main note list header for flat
list views. Sort preferences are persisted per group in localStorage.
Also updates mock data with varied createdAt/status values for testing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add unit test verifying content blocks are applied via deferred microtask
(not synchronously in useEffect). Convert debug E2E test into a proper
regression test that checks editor content appears after clicking a note
and no flushSync errors are logged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Added filterEntries tests: trash excluded from all/section/topic/archived,
trash filter returns only trashed entries
- Added NoteList render tests: trash header, TRASHED badge, 30-day warning
banner, empty trash state
- Updated all test files with trashed/trashedAt fields on VaultEntry mocks
- Updated useNoteActions to include trashed/trashedAt on new entries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Sidebar: replaced disabled Trash placeholder with active filter showing
count badge and destructive color when selected
- Sidebar: trashed notes excluded from section groups and All Notes count
- NoteList: trash filter shows only trashed entries with TRASHED badge
- NoteList: 30-day warning banner when expired trash notes exist
- NoteList: per-note warning text for notes past 30-day retention
- Inspector: trash icon shown before name in relationship pills for
trashed entries, with (trashed) label and dimmed styling
- Inspector: backlinks show trash icon for trashed entries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Added trashed (boolean) and trashedAt (timestamp) to TypeScript VaultEntry
- Added 'trash' filter to SidebarSelection union type
- Added trashed/trashed_at fields to Rust VaultEntry struct and Frontmatter parser
- Added 3 trashed mock entries for visual testing (recently trashed,
30+ days old, and dropped experiment)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests cover:
- Customize button renders
- Popover opens with toggles for all sections
- Hiding a section removes it and its items from sidebar
- Re-showing a section restores it
- Persistence to/from localStorage
- Hidden sections don't affect top nav (All Notes, Favorites)
- Popover closes on outside click
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a "Customize sections" button above section groups in the sidebar.
Clicking it opens a popover with per-type toggle switches. Hidden sections
disappear from the sidebar entirely but notes remain accessible via
All Notes and search. Visibility state is persisted in localStorage.
- New useSectionVisibility hook: manages hidden sections set in localStorage
- Sidebar: "Customize sections" button + popover with toggle UI
- Outside-click closes the popover
- allSectionGroups (built-in + custom) filtered by visibility before render
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>