Skip to content

Comments

feat: add per-entry post-process button and version history viewer#851

Open
arimxyer wants to merge 28 commits intocjpais:mainfrom
arimxyer:feature/history-post-process
Open

feat: add per-entry post-process button and version history viewer#851
arimxyer wants to merge 28 commits intocjpais:mainfrom
arimxyer:feature/history-post-process

Conversation

@arimxyer
Copy link
Contributor

@arimxyer arimxyer commented Feb 19, 2026

Before Submitting This PR

Please confirm you have done the following:

Human Written Description

I wanted to be able to enhance my transcriptions directly within Handy — my spoken words tend to include filler words and pauses, and I didn't want to have to open a separate app or keep an AI side-by-side just to clean things up. On Linux, key binding issues made the one-shot post-processing flow unreliable for me, so having a per-entry enhance button in the history tab was the natural solution. This PR adds that button along with a full version history viewer, so you can see every enhancement, what prompt was used, and restore any previous version. It closes the loop on enhancement within an already great tool.

Related Issues/Discussions

Discussion: #826

Community Feedback

This implements the feature requested in Discussion #826 — per-entry post-processing from the history tab. The discussion received community interest as a natural complement to the existing global post-process flow.

Changes

Backend (Rust)

  • New setting: history_post_process_enabled behind experimental + post-process feature gates
  • Version tracking: New transcription_versions table records every enhancement (text, prompt, timestamp) via migration
  • New commands: post_process_history_entry, get_transcription_versions, restore_version, toggle_history_post_process
  • Restore logic: Updates post_processed_text/post_process_prompt on the history entry without deleting version rows (append-only history)
  • version_count subquery: Added to HistoryEntry so the frontend knows whether to show version history even when restored to original
  • 42 tests passing including 4 new restore tests and existing version tracking tests

Frontend (React/TypeScript)

  • Post-process button (sparkle icon) on each history entry — disabled when no provider configured or text is empty
  • Show Original / Show Enhanced toggle for quick A/B comparison
  • VersionHistory accordion component — expandable timeline showing all enhancement versions with:
    • Active version detection (text + prompt + timestamp matching)
    • Restore button with inline 3-second confirmation
    • Expandable text ("Show more/less") for both version content and prompts
    • Prompt text preserves line breaks (whitespace-pre-wrap)
    • Lazy-loading on first expand, stale cache invalidation on history-updated events
  • HistoryPostProcessToggle in experimental settings

i18n

  • 20 new translation keys added to all 17 locale files

Testing

  • Rust tests: 42/42 passing (includes restore_to_specific_version, restore_to_original, versions_preserved_after_restore, restore_nonexistent_version_fails)
  • Clippy: 0 warnings with -D warnings
  • ESLint: Clean
  • Prettier + cargo fmt: Clean
  • Translation consistency: All 16 non-English locales pass
  • Manual testing: Verified on Linux — enhance, restore, version history expand/collapse, stale cache refresh, restore-to-original edge case, show more/less on long prompts

Screenshots

Experimental settings toggle:

Screenshot_2026-02-19_00-51-20

History entry with enhance button and Show Original toggle:

Screenshot_2026-02-19_00-51-44

Version history expanded with active version and restore:

Screenshot_2026-02-19_00-52-38

Expanded prompt text with line breaks preserved:

Screenshot_2026-02-19_00-52-51

AI Assistance

  • AI was used (please describe below)

If AI was used:

  • Tools used: Claude Code (Claude Opus 4.6)
  • How extensively: Claude Code was used extensively throughout — from brainstorming and design (including a Pencil wireframe), through implementation of all backend and frontend code, to bug fixing (3 bugs found during manual testing and fixed iteratively). The human contributor directed all design decisions, tested locally, and identified the bugs. All code was reviewed and approved by the contributor before committing.

@arimxyer arimxyer changed the title feat: add post-process button for history items feat: add per-entry post-process button and version history viewer Feb 19, 2026
arimxyer and others added 27 commits February 19, 2026 00:34
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ommands

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add disabled state for sparkle button when provider not configured
- Add postProcessNotConfigured translation key with tooltip
- Replace non-null assertion with nullish coalescing operator
- Wrap save_version + update_post_processed_text in atomic transaction
- Replace individual methods with save_version_and_update transaction method
- Improve tests: use production migrations, add transaction test, cascade test
- Use TranscriptionVersion struct in version query test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove unused imports (get_settings, APPLE_INTELLIGENCE_DEFAULT_MODEL_ID, super::*)
- Remove unnecessary mut binding on builder in lib.rs
- Remove needless borrows (&app_handle, &app.handle(), &window.app_handle())
- Replace consecutive str::replace with char filter
- Convert loop+match to while-let in recorder.rs
- Replace map_or(false, ..) with is_some_and/is_ok_and
- Fix unneeded late initialization in clipboard.rs
- Remove unneeded return statements in match arms and cfg blocks
- Replace map_err identity with inspect_err in model.rs
- Remove no-effect struct update (..Default::default())
- Derive Default for ModelUnloadTimeout and ClipboardHandling enums
- Take self by value in SoundTheme::to_*_path (Copy type)
- Use HashMap::entry API instead of contains_key+insert
- Collapse nested if statements in shortcut/mod.rs
- Gate test import behind cfg(target_os = "macos") in clamshell.rs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…odes

- Enable PRAGMA foreign_keys = ON in get_connection() so CASCADE DELETE
  works in production (critical bug fix)
- Add backend feature gate checking all three settings before allowing
  post_process_history_entry
- Replace hardcoded English error strings with error codes mapped to
  i18n translation keys on the frontend
- Remove unused get_transcription_versions command and update bindings
- Wrap postProcessConfigured in useMemo for idiomatic React
- Use collect() idiom in get_versions instead of manual loop
- Add displayName to HistoryPostProcessToggle for React DevTools
- Rename shadowed onChange parameter from enabled to value

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…emo deps

- Remove redundant get_settings() call in post_process_history_entry,
  reuse settings from feature gate check
- Enable PRAGMA foreign_keys in init_database() for consistency
- Fix useMemo dependency in postProcessConfigured to use actual setting
  values instead of stable getSetting function reference

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Restore get_transcription_versions command and get_versions method
  that were incorrectly removed (part of planned API for version
  history UI)
- Add index on transcription_versions.history_entry_id for efficient
  lookups and cascade deletes
- Copy button tooltip now shows "Copy original" or "Copy enhanced"
  when before/after toggle is active

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix postProcessConfigured check to only require provider + prompt
  (not API key, since some providers like Ollama don't need one)
- Move show original/enhanced toggle to header row, centered between
  date and action buttons
- Add p-2 padding to sparkle button matching star button spacing
- Add contextual copy tooltip (copy original vs copy enhanced)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add expandable version history timeline to history entry cards.
Users can view all post-processing versions, see which prompt was
used for each, and restore any previous version (including the
original transcription) with inline confirmation.

- New restore_version Tauri command with three-level feature gate
- VersionHistory React component with lazy-loading and event refresh
- Inline confirmation UX (3-second timeout) for restore actions
- 4 new backend tests for restore functionality (38/38 passing)
- 8 new i18n translation keys

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Active version detection now matches by text + prompt + highest
  timestamp instead of text-only comparison, preventing multiple
  versions from showing as "Active" simultaneously
- History-updated events now mark cached versions as stale when
  accordion is collapsed, ensuring re-fetch on next expand

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add version_count field to HistoryEntry via SQL subquery so the
accordion renders based on whether versions exist, not whether
post_processed_text is non-null.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hard truncation with expandable text for both version
content and prompt in the version history timeline cards.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Give the prompt section a container with subtle background, border,
uppercase "Prompt" label, and italic text to visually distinguish
it from the version's transcription content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add whitespace-pre-wrap so newlines in the prompt are rendered
instead of collapsed into a single line.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Simplify prompt display back to sparkle icon + text, preserving
whitespace-pre-wrap for line breaks without the extra container.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cjpais
Copy link
Owner

cjpais commented Feb 19, 2026

Can you add a screenshot or a video? Also, new features are not really being added at this time.

@arimxyer arimxyer force-pushed the feature/history-post-process branch from 1a89a9f to 6ecfb35 Compare February 19, 2026 05:43
@arimxyer
Copy link
Contributor Author

Can you add a screenshot or a video? Also, new features are not really being added at this time.

Yeah, happy too. Give me a few minutes.

Add English placeholder values for history post-process and version
history keys across all 16 non-English locale files to pass the
translation consistency check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@arimxyer
Copy link
Contributor Author

Hey! Screenshots added above.

Totally understand on the feature freeze. A couple of things worth noting:

  • This implements the feature requested in Discussion #826 — per-entry post-processing from the history tab
  • The entire feature is gated behind the existing experimental toggle, plus a separate "Post-process History" toggle underneath it — so it's completely opt-in and invisible to users who don't go looking for it
  • No changes to the default UX or existing workflows

Happy to adjust anything if needed. Let me know what you think!

@cjpais
Copy link
Owner

cjpais commented Feb 19, 2026

Overall it looks good for me. I'm freezing features because inevitably adding new features adds more people wanting new features which has gotten me into a burnout loop.

@arimxyer
Copy link
Contributor Author

Damn man, I'm sorry to hear that. Well all good if you pass on this, it was fun to build and test at the very least.

Also, major kudos to you for even being this in the weeds with the PRs and issues altogether. I hope that one day one of my projects helps as many people as yours has and I can still be this hands-on with all aspects of it. ✌️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants