Settings > Hardware: the Models list is now a bordered card row per
model with active/installed badges and a real progress bar for
downloads (was plain text links + a bare "downloading NN%" string),
using the app's existing lucide icon set.
Settings > Calendar: an Import range picker (30/90/180/365 days/all
time, persisted, applied to both a manual Import and the pst_auto_sync
startup re-import) and a Clean up section (delete all / older-than-N
threshold, confirm() gated, always reports how many events were kept
because they're linked to a meeting) -- fixes the 14,686-row bloat from
importing a mailbox's entire unbounded history.
Granola-style redesign: the live-recording view gains a Notes pane
(bound to recording.notesText) alongside the transcript, and each
transcript line is clickable to attach/edit a note for that moment
(recording.segmentNotes, badge on annotated lines).
Also, for both the live and finalized-meeting layouts: the
transcript/notes split is now drag-resizable and each side
independently collapsible (Splitter + layout store), and the
post-finalize Notes pane defaults to Preview (rendered) instead of raw
Editor mode, since the merged document is now properly sectioned rather
than a single-speaker blob.
Upload now and Save action items now use the existing .primary
solid-accent button style (with icons) instead of unstyled native
buttons; the AI provider dropdown gets real border/background/hover
states matching the app's other selects.
Left (meetings list) and right (summary) panes gain drag-to-resize via
Splitter and a collapse/expand toggle (thin rail + panel icon), sizes
and collapsed state persisted via the layout store.
Pane widths, collapsed flags, and the transcript/notes split ratio,
persisted to localStorage (pure client-side UI ephemera, not app data --
no Tauri settings round-trip needed).
Live notes (Granola-style redesign):
- update_live_notes/set_segment_note: live-session-only, mutate
RecordingSession.manual_notes and write-through to manual_notes.json.
- stop_recording, reprocess_transcript, and resume_transcription now call
MarkdownNotes::merge (loading manual_notes.json from disk for the
latter two, which have no live RecordingSession) instead of the old
transcript-only to_markdown, so re-transcription/crash-recovery never
silently drops what the user typed.
- refresh_notes_and_notify no longer re-renders/overwrites notes.md on a
post-finalize speaker rename/merge -- that used to clobber manual
edits; it still updates the speakers table and emits the live-refresh
event.
Calendar range/cleanup (14,686-row bloat fix):
- import_pst_core/import_pst take an optional range_days, converted to a
from timestamp for PstSource.
- New cleanup_calendar_events command wrapping the new store method.
- RecordingSession.manual_notes; register update_live_notes/set_segment_note.
- Register cleanup_calendar_events; pass pst_import_range_days through to
the pst_auto_sync startup re-import so it applies the same range as the
last manual import, not the full mailbox history.
CalendarCleanupResult + Store::cleanup_calendar_events(older_than_unix):
None deletes every unlinked event ("Delete all"), Some(cutoff) only those
starting before it. An event referenced by meetings.calendar_event_id is
always kept regardless of age or the "delete all" choice; participant
links cascade via the existing ON DELETE CASCADE FK.
PstSource used to silently ignore CalImport.from/to (only Graph honored
a range) -- a long-lived mailbox has no natural upper bound on history,
so importing "everything" meant every recurring series expanded across
its full lifetime (up to 500 occurrences each) plus every one-off entry
the file ever held (e.g. a decade of Outlook's auto-generated yearly
holidays). Filters parsed events by starts_at after readpst parsing,
after collect_events -- doesn't need to touch how readpst is invoked or
how recurrence expansion works.
Adds the Notes/Transcript-sectioned merge (freeform notes under ## Notes,
transcript dialogue under ## Transcript with per-moment annotations
placed as > note callouts right after the paragraph they anchor to,
unmatched anchors surfaced under "Other notes" rather than dropped) that
stop_recording now calls instead of the old transcript-only to_markdown.