Skip to content

fix(ui): save log view preferences - #1015

Merged
benvinegar merged 2 commits into
mainfrom
fix/log-save-view-preferences
Sep 7, 2026
Merged

fix(ui): save log view preferences#1015
benvinegar merged 2 commits into
mainfrom
fix/log-save-view-preferences

Conversation

@benvinegar

Copy link
Copy Markdown
Member

Problem

Interactive hunk log owned a separate quit path from ordinary reviews. Theme changes were applied for the session, but history discarded the resolved preference baseline and config destination and quit without offering to save them.

Approach

  • carry the resolved view-preference baseline, prompt policy, and config path into the history runtime
  • reuse the shared view-preference quit controller and a shared confirmation dialog in both review and history surfaces
  • centralize the prompt keyboard mapping so save, discard, never-ask, and cancel stay identical
  • cancel pending commit-review preparation before opening the history quit prompt
  • add bootstrap, keyboard, lifecycle, and PTY regression coverage

Verification

  • bun run typecheck
  • bun run lint
  • bun run test (2,109 passed, 2 skipped)
  • bun test test/pty/log-integration.test.ts (8 passed)
  • bun run test:tty-smoke (9 passed)
  • real TTY smoke against the working-tree diff

bun run test:integration completed with 147 passing tests and 7 unrelated local-environment failures: the ignored checkout-local .hunk/config.toml forces theme = "dracula" and menu_bar = true, conflicting with chrome/pager tests that assume defaults. The targeted log PTY suite passes.

Visual evidence

Not captured; the prompt is the existing shared save-view-preferences dialog already used by hunk diff.

This PR description was generated by Pi using OpenAI GPT-5.6-sol

@vercel

vercel Bot commented Sep 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
hunk-web Ignored Ignored Preview Sep 7, 2026 3:39am UTC

Request Review

@greptile-apps

greptile-apps Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR extends the shared save-view-preferences quit workflow to interactive history sessions and adds regression coverage for configuration resolution, keyboard behavior, cancellation, and PTY persistence.

  • Carries resolved preference baselines, prompt policy, and config destination into the history runtime.
  • Shares the confirmation dialog and key dispatcher between review and history surfaces.
  • Cancels pending embedded-review preparation before opening the history quit prompt.
  • Contains a cancellation lifecycle race that can leave history stuck when another review is opened before cancellation settles.
  • Also requires a repository-mandated filename correction.

Confidence Score: 4/5

The PR is not yet safe to merge because reopening a review before cancelled preparation settles can permanently strand the history UI, and the explicit filename requirement must also be satisfied.

Cancellation exposes history before the host is ready to accept another review request; that request is dropped while LogApp retains its pending state. The delayed quit can also report the wrong exit status if another quit key overwrites its mutable ref.

Files Needing Attention: packages/hunk/src/ui/log/LogApp.tsx, packages/hunk/src/ui/session/HunkSessionHost.tsx, packages/hunk/src/ui/components/chrome/ViewPreferenceQuitDialog.tsx

Important Files Changed

Filename Overview
packages/hunk/src/ui/log/LogApp.tsx Adds history-owned preference prompting and preparation cancellation, but introduces a reopen lifecycle race and mutable delayed-exit status.
packages/hunk/src/ui/session/HunkSessionHost.tsx Invalidates and aborts pending review preparation, while silently rejecting new opens until non-cooperative preparation settles.
packages/hunk/src/app/historyBootstrap.ts Correctly carries the resolved preference baseline, prompt policy, and destination into the history runtime.
packages/hunk/src/ui/hooks/useViewPreferenceQuitController.ts Generalizes the existing preference quit controller for reuse without materially changing its established behavior.
packages/hunk/src/ui/components/chrome/ViewPreferenceQuitDialog.tsx Extracts the existing prompt UI faithfully, but its filename violates the repository’s dash-case rule.
packages/hunk/src/ui/lib/viewPreferenceQuitKeys.ts Centralizes the existing save, discard, never-ask, and cancel keyboard mapping with focused tests.
test/pty/log-integration.test.ts Adds end-to-end coverage proving that a changed history theme can be saved on quit.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[History session] --> B[Open commit]
    B --> C[Host prepares embedded review]
    C --> D[User requests quit]
    D --> E[Cancel preparation]
    D --> F{Preferences changed?}
    F -->|No| G[Quit]
    F -->|Yes| H[Save preferences prompt]
    H -->|Save / discard / never ask| G
    H -->|Escape| I[Return to history]
    I --> J[User opens another commit]
    J --> K{Earlier preparation settled?}
    K -->|Yes| B
    K -->|No| L[Host drops request while LogApp remains pending]
Loading
Prompt To Fix All With AI
### Issue 1
packages/hunk/src/ui/log/LogApp.tsx:179-182
**Reopening Can Strand History**

Cancelling a pending review clears `reviewPending` before the host’s preparation has settled. If the user closes the save-preferences prompt with Escape and immediately opens another commit, `LogApp` emits a new `open-review`, but `HunkSessionHost` silently rejects it while `preparingRef` remains true. `openSelected` then finishes without resetting `reviewPending`, leaving the history UI stuck on the opening-commit surface. Keep history blocked until cancellation settles, or make the host report the rejection so the local pending state is restored.

### Issue 2
packages/hunk/src/ui/log/LogApp.tsx:117-121
**Delayed Quit Changes Status**

After saving preferences, the prompt closes while the quit remains delayed for 120 ms. If the user presses Ctrl+C during that interval, `requestLogQuit(130)` overwrites `pendingExitCode` even though the controller rejects the second quit request. The original ordinary quit then reads the new value and exits with status 130 instead of 0. Capture the requested exit code when scheduling the delayed quit rather than reading this mutable ref later.

### Issue 3
packages/hunk/src/ui/components/chrome/ViewPreferenceQuitDialog.tsx:1
**Filename Violates Dash-Case Rule**

The new `ViewPreferenceQuitDialog.tsx` file violates the repository directive requiring dash-case names for `.ts` and `.tsx` files. This repository requirement must be satisfied before merging: rename the file to `view-preference-quit-dialog.tsx` and update its imports.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "fix(ui): save log view preferences" | Re-trigger Greptile

Comment thread packages/hunk/src/ui/log/LogApp.tsx Outdated
Comment on lines +179 to +182
reviewPending.current = false;
reviewQuitEnabled.current = false;
setOpeningCommit(null);
void onOutcome({ kind: "cancel-open-review" });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Reopening Can Strand History

Cancelling a pending review clears reviewPending before the host’s preparation has settled. If the user closes the save-preferences prompt with Escape and immediately opens another commit, LogApp emits a new open-review, but HunkSessionHost silently rejects it while preparingRef remains true. openSelected then finishes without resetting reviewPending, leaving the history UI stuck on the opening-commit surface. Keep history blocked until cancellation settles, or make the host report the rejection so the local pending state is restored.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/hunk/src/ui/log/LogApp.tsx
Line: 179-182

Comment:
**Reopening Can Strand History**

Cancelling a pending review clears `reviewPending` before the host’s preparation has settled. If the user closes the save-preferences prompt with Escape and immediately opens another commit, `LogApp` emits a new `open-review`, but `HunkSessionHost` silently rejects it while `preparingRef` remains true. `openSelected` then finishes without resetting `reviewPending`, leaving the history UI stuck on the opening-commit surface. Keep history blocked until cancellation settles, or make the host report the rejection so the local pending state is restored.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 9dd6522. History now keeps its local review-open lock until the host’s cancellation settlement resolves. Closing the preference prompt and immediately pressing Enter is swallowed until the prior preparation has fully settled, with regression coverage for the race.

Responded by Pi using openai-codex/gpt-5.6-sol.

This comment was generated by Pi using GPT-5.6 Sol

Comment on lines +117 to +121
onQuit: () => {
const exitCode = pendingExitCode.current;
pendingExitCode.current = undefined;
void onOutcome({ kind: "quit", ...(exitCode === undefined ? {} : { exitCode }) });
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Delayed Quit Changes Status

After saving preferences, the prompt closes while the quit remains delayed for 120 ms. If the user presses Ctrl+C during that interval, requestLogQuit(130) overwrites pendingExitCode even though the controller rejects the second quit request. The original ordinary quit then reads the new value and exits with status 130 instead of 0. Capture the requested exit code when scheduling the delayed quit rather than reading this mutable ref later.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/hunk/src/ui/log/LogApp.tsx
Line: 117-121

Comment:
**Delayed Quit Changes Status**

After saving preferences, the prompt closes while the quit remains delayed for 120 ms. If the user presses Ctrl+C during that interval, `requestLogQuit(130)` overwrites `pendingExitCode` even though the controller rejects the second quit request. The original ordinary quit then reads the new value and exits with status 130 instead of 0. Capture the requested exit code when scheduling the delayed quit rather than reading this mutable ref later.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 9dd6522. The first quit request now captures its exit status until the decision completes or is cancelled, so Ctrl-C during the delayed post-save quit cannot replace an ordinary exit with status 130. Added regression coverage with an injected quit scheduler.

Responded by Pi using openai-codex/gpt-5.6-sol.

This comment was generated by Pi using GPT-5.6 Sol

@@ -0,0 +1,65 @@
import type { ViewPreferenceQuitController } from "../../hooks/useViewPreferenceQuitController";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Filename Violates Dash-Case Rule

The new ViewPreferenceQuitDialog.tsx file violates the repository directive requiring dash-case names for .ts and .tsx files. This repository requirement must be satisfied before merging: rename the file to view-preference-quit-dialog.tsx and update its imports.

Context Used: guidelines.mdc Cursor rule (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/hunk/src/ui/components/chrome/ViewPreferenceQuitDialog.tsx
Line: 1

Comment:
**Filename Violates Dash-Case Rule**

The new `ViewPreferenceQuitDialog.tsx` file violates the repository directive requiring dash-case names for `.ts` and `.tsx` files. This repository requirement must be satisfied before merging: rename the file to `view-preference-quit-dialog.tsx` and update its imports.

**Context Used:** guidelines.mdc Cursor rule ([source](https://github.com/modem-dev/modem/blob/main/.cursor/rules/guidelines.mdc))

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not changing this. Hunk’s React component files conventionally use PascalCase in this directory (ConfirmDialog.tsx, ThemeSelectorDialog.tsx, HelpDialog.tsx, etc.), and the cited dash-case rule is from a different repository rather than Hunk’s checked-in contributor guidance. ViewPreferenceQuitDialog.tsx follows the local convention.

Responded by Pi using openai-codex/gpt-5.6-sol.

This comment was generated by Pi using GPT-5.6 Sol

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. The surrounding chrome components use PascalCase filenames (ConfirmDialog.tsx, ThemeSelectorDialog.tsx, HelpDialog.tsx), and the checked-in Hunk guidance does not establish a dash-case requirement here. ViewPreferenceQuitDialog.tsx follows the local convention, so I’m withdrawing this finding; no rename is needed.

@benvinegar
benvinegar merged commit cbf77de into main Sep 7, 2026
12 checks passed
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.

1 participant