feat: add persistent document handling and protect note drafts
Add HTTP PaddleOCR-VL settings and shared document previews for chat and knowledge imports. Preserve attachment originals and parsed assets across drafts, messages and queues; support explicit image OCR, selecting document images into a conversation draft, and restoring queued input for editing. Protect unsaved note bodies and titles during navigation and asynchronous updates. Match canvas analysis to source revisions, invalidate affected comments, preserve annotations during pagination, and provide a resizable record index with saved width preferences. Existing OCR settings retain local behavior. Historical attachments without saved originals are not reconstructed. Advanced OCR options depend on the configured service; image sending depends on the effective model and Runtime. Validation: full typecheck and lint passed; 477 focused tests passed across 12 files; staged whitespace checks passed. The full repository suite was not rerun for this commit. Release note: Keep note drafts safe while switching workspaces, resize the record index, and revisit saved document attachments with OCR previews and selected images in chat.
This commit is contained in:
@@ -8,6 +8,12 @@ clearing a composer, flushing content or invoking the draft-switch guard. Openin
|
||||
a note shows a blank composer below the title and above the stream, without a New
|
||||
record button. Editing another entry or
|
||||
leaving the note still checks unsaved content after flushing canvas changes.
|
||||
`MagicNotesWorkspace.onBeforeLeave` registers this same check with the App navigation
|
||||
gate, including sidebar, application launcher and conversation jumps. The gate waits
|
||||
for canvas flush, then offers Continue editing or Discard draft and switch for dirty
|
||||
body or title content. Workspace cache eviction does not serve as draft protection.
|
||||
Non-title detail responses retain a dirty title. A title-save response acknowledges
|
||||
only the submitted input; text entered while that request runs remains a draft.
|
||||
The shared store returns `MagicNoteEntryCreateResult`, the existing detail shape
|
||||
plus a required `createdEntryId`. Production IPC and preload preserve that ID.
|
||||
Creating an entry selects this exact ID and resets the composer through its key;
|
||||
@@ -43,13 +49,19 @@ content and streamed draft comments through the shared draft-analysis cleanup.
|
||||
The context counter rejects late results and prevents dispatch after abandoned
|
||||
settings preparation. This cleanup does not clear the new-entry composer's content.
|
||||
|
||||
The left index is 168px wide. Its toggle stays in the detail header immediately
|
||||
The left index defaults to 168px and resizes from its right edge between 140px
|
||||
and 320px. It shares the AI pane's pointer-capture handlers, separator styling
|
||||
and keyboard semantics (16px arrow steps, Home/End limits). Both widths are
|
||||
stored in `goodbuddy.magic-notes-layout.v1`; missing index width defaults to
|
||||
168px. Displayed widths clamp together to reserve at least 300px for the stream,
|
||||
without overwriting saved widths when the window shrinks. The index toggle stays in the detail header immediately
|
||||
before the title; collapsing hides the entire index and removes its grid column,
|
||||
border and occupied width. AI has a separate
|
||||
border, resize separator and occupied width. AI has a separate
|
||||
right pane with its existing resize separator and header toggle. Both panes scroll
|
||||
independently and persist independent desktop visibility. At container widths of
|
||||
800px or less, the index defaults to hidden and the same header toggle opens or
|
||||
closes a 168px drawer below the header, without reserving a rail; choosing
|
||||
closes a fixed 168px drawer below the header, without reserving a rail or showing
|
||||
an index resize separator; choosing
|
||||
an item or pressing Escape closes it. AI moves below the stream, limited to 40%
|
||||
of layout height and 280px. Overview search, scroll, task selection and return
|
||||
focus stay mounted.
|
||||
@@ -233,6 +245,15 @@ Todo analysis includes its title and instructions plus the source canvas context
|
||||
and uses the same capability and capture rules. Non-canvas content keeps the text
|
||||
analysis path. All analysis remains read-only with no tool calls.
|
||||
|
||||
Saved-entry requests accept `expectedRevision`; todo requests accept
|
||||
`sourceEntryRevision`. Nonempty `canvasImages` requires the corresponding revision,
|
||||
even when the resolved model uses text fallback. Main loads the source after
|
||||
resolving settings and checks the supplied revision before model invocation.
|
||||
Existing rich-text callers may omit these fields. Entry writeback retains its
|
||||
revision check; canvas todo writeback also requires the source entry revision,
|
||||
including when no comments existed at request time. No additional stored snapshot
|
||||
or schema migration is needed.
|
||||
|
||||
Canvas `immediate` mode provides an Analyze canvas draft action without a persistent
|
||||
instruction banner; pen strokes do not trigger automatic requests. `after-save-auto`
|
||||
prepares analysis input and then saves manually submitted content. Settings or
|
||||
@@ -242,14 +263,25 @@ does not roll back the save. Failure to flush the document itself still prevents
|
||||
saving incomplete content.
|
||||
|
||||
For v2-to-v2 entry updates, identical content retains saved comments. If all
|
||||
comments have `text` or `text-fallback` input mode, equal extracted `plainText`
|
||||
comments have `text` or `text-fallback` input mode, equal analysis text from shared
|
||||
`magicNoteCanvasAnalysisText(content)` (including page numbers)
|
||||
also retains comments across layout-only changes. Other changed canvas content,
|
||||
including layout changes with `canvas-images` comments, clears saved entry
|
||||
comments and `analyzed_at`. In `after-save-auto`, visual comments trigger renewed
|
||||
comments and `analyzed_at`. Source canvas changes apply the same rule to saved
|
||||
todo comments and increment the affected todo revision without replacing its ID.
|
||||
In `after-save-auto`, visual comments trigger renewed
|
||||
analysis when content changes, while existing text-only comments trigger it when
|
||||
extracted text changes. A changed draft clears its prior canvas draft analysis.
|
||||
analysis text changes. A changed draft clears its prior canvas draft analysis.
|
||||
The UI labels the actual input mode so a text fallback is visible to the user.
|
||||
|
||||
Workspace captures the saved entry and its revision before awaiting image capture;
|
||||
an external refresh cannot pair an old capture with a newer revision. Automatic
|
||||
post-save analysis takes the revision from the save response using `createdEntryId`
|
||||
or the edited entry ID. Todo capture uses the selected source entry's actual page
|
||||
IDs and revision. Renderer text-only change detection uses the same shared
|
||||
analysis-text helper as persistence, so inserting a blank page before text triggers
|
||||
renewed analysis when its cited page number changes. Draft analysis remains unversioned.
|
||||
|
||||
## Change Notifications
|
||||
|
||||
`AssistantDatabase` accepts `onMagicNotesChanged: () => void`. Every successful
|
||||
|
||||
Reference in New Issue
Block a user