The DynamicPropertiesPanel had a local countWords that used a regex
(/^---[\s\S]*?---/) which could match dashes inside frontmatter values,
leaving part of the frontmatter in the body and inflating the count.
Replace with the canonical countWords from utils/wikilinks.ts which uses
splitFrontmatter (line-based indexOf) and correctly finds the closing
delimiter on its own line.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two bugs caused stale dirty indicators after rename:
1. handleRenameTab didn't call loadModifiedFiles() after rename
2. handleSave (Cmd+S) skipped onAfterSave when nothing was pending
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The previous client_id pointed to a GitHub App that did not have
device authorization flow enabled, causing "failed to start login"
errors. Switch to the refactoringhq OAuth App (Ov23liwee215tDMs9u4L)
which supports device flow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tauri invoke errors are strings (not Error instances). The new test
verifies the frontend displays the actual backend error message.
Also tests that the login button is disabled during the OAuth flow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The GitHub App (Ov23liCuBz7Z5hKk6T8c) does not have Device
authorization flow enabled — GitHub returns 404. The error message
now includes specific setup steps so the user can fix the
configuration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The frontend was swallowing Tauri backend errors (which are strings,
not Error instances) and always showing generic "Failed to start login."
Now the actual error message is displayed. Also adds User-Agent header
to device flow requests, a clear error message for 404 responses, and
a test for the 404 case.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Drag cancel (dragEnd without drop) does not trigger reorder
- Drag from last tab toward first produces correct reorder
- Active tab path is preserved after reorder
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
handleDrop and handleDragOver closed over dragIndex/dropIndex state
values. When the last dragover and drop events fire in the same React
render cycle, the drop handler reads stale state (often null), causing
computeDropTarget to return null and skip the reorder.
Mirror dragIndex/dropIndex into refs that are updated synchronously
alongside setState. Event handlers now read from refs, ensuring they
always see the latest values regardless of React's batching schedule.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
window.prompt() doesn't work in Tauri WebView on macOS — silently returns null.
Removed handleCreateNewVault + create_vault_dir Tauri command entirely.
Open Local Folder is equivalent; Finder lets users create folders inline.
Also removes tauriCall helper (was only used by handleCreateNewVault).
573 frontend tests pass.
The save-regression cherry-pick (4b5812a) re-introduced the pre-refactor
vault.rs alongside vault/mod.rs, causing E0761 (ambiguous module) on CI.
vault/mod.rs (from PR #21 refactor-vault-rs) is the correct implementation
and already exports all needed functions (save_note_content, get_note_content,
purge_trash, etc.). Removing the duplicate vault.rs resolves the CI failure.
The tab-swap useEffect in Editor.tsx watched [activeTabPath, tabs, editor].
When save updated tabs via setTabs, the effect re-ran and re-applied stale
cached blocks from the initial tab load, visually reverting the editor.
Subsequent edits would then save old content, effectively losing changes.
Fix: skip the block swap when activeTabPath hasn't changed (only tab content
was updated). Also refresh the cache with current editor blocks so a later
tab switch doesn't revert to stale content.
Added regression tests for the save → update round-trip (JS + Rust).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The useImageDrop hook's handleDrop was uploading files and inserting
image blocks, but BlockNote already has a native dropFile ProseMirror
plugin that does the same via editor.uploadFile — causing duplicate
uploads and image block insertions on every drop.
Fix: handleDrop now only resets the visual overlay state. BlockNote's
native handler handles the actual upload (which calls uploadImageFile)
and block insertion with proper drop-position support.
Also fix build: exclude test files from tsconfig.app.json (test files
use vi.Mock types from vitest, not available in the app build config).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests cover: has_legacy_is_a, extract_is_a_value, migrate_file_is_a_to_type,
and migrate_is_a_to_type (public function). migration.rs was at 0% coverage.
E2E tests cover:
- Drag & drop image into editor inserts image block with data URL
- Drop zone overlay appears during image drag
- Non-image file drops are correctly ignored
Design file shows three states: idle, drag-over (dashed border +
overlay label), and after-drop (image block inserted inline).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract uploadImageFile to shared hook, add useImageDrop hook that
handles dragover/dragleave/drop events on the editor container.
Drops image files (jpg, png, gif, webp), uploads them via the existing
save_image flow, and inserts BlockNote image blocks at the drop position.
Visual feedback via drop overlay and dashed border.
Refactored Editor.tsx uploadFile to use the shared function.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shows all five type colors (red, yellow, green, purple, blue) with
matching dotted underlines — demonstrating the currentColor fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The underline was implemented via border-bottom with a hardcoded
var(--accent-blue), ignoring the per-type color set on the element.
Changed to currentColor so the underline inherits the dynamic color.
Also removed the no-op textDecorationColor inline style (text-decoration
is none; the visual underline comes from border-bottom).
Bonus: fixed pre-existing TS build error in useEditorSave.test.ts
(vi.Mock namespace → Mock type import).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Frames showing the fixed Commit & Push behavior:
- Button enabled state with correct badge count (3 files)
- Button with no changes (badge hidden)
- Commit dialog with correct file count after save+refresh
- Success toast after commit
- Error toast when commit fails
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: Two problems caused "0 files changed":
1. loadModifiedFiles() was only called on mount, never refreshed after saves
2. Pending editor content wasn't flushed to disk before git commit
Fix:
- useEditorSave: add savePending() to flush unsaved content, onAfterSave
callback to refresh git status after Cmd+S
- useCommitFlow: new hook managing save→commit→push flow with proper
sequencing (save pending → refresh files → show dialog → commit)
- App.tsx: wire onAfterSave to loadModifiedFiles, use useCommitFlow
- git.rs: include stdout in error when stderr is empty (fixes "nothing
to commit" message being swallowed)
- mock-tauri: track saved files so get_modified_files reflects edits
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Coverage was 83.83% (below 85% threshold). Added mockito-based HTTP mock
tests for all OAuth device flow functions, list/create repo, get user,
and send_chat. Coverage now at 90.26%.
- github.rs: 55.99% → 94.85% (added mock tests for all HTTP functions)
- ai_chat.rs: 63.27% → 95.70% (added mock tests for send_chat paths)
- Added mockito = "1" as dev-dependency
- Refactored HTTP functions to accept configurable base URLs for testability
Playwright tests verify:
- Connected state shows username and disconnect button
- Login with GitHub button appears after disconnecting
- No token input field is present
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract SettingsHeader, SettingsBody, SettingsFooter, GitHubConnectedRow,
GitHubWaitingView, GitHubLoginButton, and processPollResult helper.
Code health improved from 8.64 to 9.38 (target 9.0+).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copied from ui-design.pen — includes existing Settings Panel frame.
New OAuth states (login button, waiting, connected) are reflected in
the implementation. Pencil editor not available for adding new frames.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>