Skip to content

sync: port upstream web UI polish, prompt stash, appearance settings (#2109–#5004) - #193

Merged
aaditagrawal merged 35 commits into
mainfrom
sync/20260730-l4-web-polish
Aug 1, 2026
Merged

sync: port upstream web UI polish, prompt stash, appearance settings (#2109–#5004)#193
aaditagrawal merged 35 commits into
mainfrom
sync/20260730-l4-web-polish

Conversation

@aaditagrawal

Copy link
Copy Markdown
Owner

L4/7 of the 2026-07-30 upstream sync stack — the largest slice (35 commits). Stacked on #192.

What lands

Fork deviations preserved

  • ChatMarkdown.tsx: upstream's new code handler and the fork's older one merged as duplicate object keys with no textual conflict — the fork's later key silently won, which would have negated the ported commit. Kept upstream's implementation (its fileLinkChip wires openInPreferredEditor + preview, a superset of the fork's file-manager open) and removed the superseded duplicate.
  • ChatComposer.tsx: dropped upstream's module-level runtimeModeConfig; the fork uses provider-scoped getRuntimeModeConfig(provider) for its medium-access/Auto traits. Also dropped the now-unused IMAGE_SIZE_LIMIT_LABEL, which upstream removed along with its only usage.
  • useSettings.test.ts: kept the fork's provider-migration tests alongside upstream's new identification-mode tests.
  • CommandPalette.tsx: kept the fork's capture-phase keydown listener (so the shortcut survives xterm/contenteditable) with upstream's renamed handler and dep list.

Ordering note

#4809 (restore T3 Connect sign-in) depends on #4691 (waitlist removal), which I had originally slotted into L5 — moved into this PR so the stack builds in order. #4992 was deferred to L6 because it depends on #4903.

Verification

vp run typecheck and vp check pass; web suite green (193 files, 1724 tests).

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 57605ac1-365e-4a0b-bb5d-1c7b20610e81

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ effective changed lines (test files excluded in mixed PRs). labels Jul 31, 2026
@aaditagrawal

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 16e9018675

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

const restoreStashEntry = useCallback(
(entry: PromptStashEntry) => {
// Remove first so a double activation (click + Enter) can't restore twice.
const { entry: taken, durable } = takeStashEntry(entry.id);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Wait for pending images before restoring a stash

When a user restores an entry while pendingImageCount is nonzero, this removes the entry before its asynchronous image encoding finishes. The restore therefore contains no images, and finalizeEntryImages later finds that the entry is gone and discards the encoded attachments; the warning cannot recover an image that came from the clipboard. Disable restoration until encoding finishes, or coordinate restoration with the pending encoder instead of taking the entry immediately.

Useful? React with 👍 / 👎.

Comment on lines +264 to +265
const { durable } = persistEntries(nextEntries);
set(() => ({ entries: nextEntries }));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep rejected attachment payloads out of persisted stash state

When the second-phase write exceeds the browser's storage quota, persistEntries reports failure but the oversized nextEntries payload is still installed in memory. Every subsequent stash write includes that same rejected payload (plus the new entry), so it also fails until the user deletes the offending entry or reloads; deleting other entries can likewise disappear only in memory and resurrect after reload. Preserve a persistable representation after a failed attachment write, even if session-only images are tracked separately.

Useful? React with 👍 / 👎.

t3dotgg and others added 23 commits August 1, 2026 12:31
…queue (pingdotgg#4453)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 200fa82)
Co-authored-by: codex <codex@users.noreply.github.com>
(cherry picked from commit 7248877)
…tgg#4670)

Co-authored-by: codex <codex@users.noreply.github.com>
(cherry picked from commit e77f42c)
Co-authored-by: codex <codex@users.noreply.github.com>
(cherry picked from commit a2ffb12)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit c13a021)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 55dd016)
…4787)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit f2d2fb2)
Co-authored-by: codex <codex@users.noreply.github.com>
(cherry picked from commit 1ba3d01)
PixPMusic and others added 12 commits August 1, 2026 12:31
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 1b4830f)
…otgg#4853)

Co-authored-by: Simon Doba <simon.doba@orbit.de>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
(cherry picked from commit e698796)
…gdotgg#4905)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 2d9066e)
…gdotgg#4964)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit f0c6ba9)
…oring (pingdotgg#4967)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit cbe8052)
@aaditagrawal
aaditagrawal force-pushed the sync/20260730-l3-preview-scm branch from 3463451 to 05bf93b Compare August 1, 2026 07:11
@aaditagrawal
aaditagrawal force-pushed the sync/20260730-l4-web-polish branch from 16e9018 to fe91fe1 Compare August 1, 2026 07:11
@aaditagrawal

Copy link
Copy Markdown
Owner Author

Review triage

Every finding on this PR was checked against upstream/main by blob hash (not just diff). All are verbatim upstream code, carried in unmodified by this port — the files are byte-identical to upstream, so the flagged behavior affects upstream equally and is not introduced by the sync.

Deliberately not fixing them here: patching upstream bugs inside a 101-commit port would diverge the fork in exactly the files this stack exists to realign, and would make the next sync harder. They are better raised upstream or tracked as fork-local follow-ups on their own branch, where they can be reviewed on their merits.

Notably, the files where this PR did carry fork-specific conflict resolutions drew no findings.

@aaditagrawal
aaditagrawal changed the base branch from sync/20260730-l3-preview-scm to main August 1, 2026 07:18
@aaditagrawal
aaditagrawal merged commit 5062896 into main Aug 1, 2026
12 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

https://github.com/aaditagrawal/t3code/blob/fe91fe166596ca544be082981f07b87f6f541772/apps/web/src/imageCompression.ts#L185
P2 Badge Preserve animation during image recompression

For an animated GIF or WebP above the composer or stash size budget, drawing the ImageBitmap onto a canvas and encoding that canvas produces a single-frame WebP/JPEG. The attachment is accepted without warning but every frame after the decoded frame is silently discarded, even though the backend accepts GIF/WebP attachments. Detect animated inputs and reject/preserve them, or use animation-aware transcoding instead of this canvas path.


https://github.com/aaditagrawal/t3code/blob/fe91fe166596ca544be082981f07b87f6f541772/apps/web/src/components/FileBrowserPanel.tsx#L281-L289
P2 Badge Keep truncation visible in the file browser

When the project-entry response has truncated: true, this replacement header no longer renders the previous “partial” indicator anywhere. Because useFileTreeSearch searches only the returned tree paths, users of large repositories can now interpret an absent search result as a missing file even though it was merely omitted by the server-side entry limit. Retain a visible partial-results warning alongside the new search field.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// Terminal-context placeholders reference live sessions the stash can't
// round-trip, so they are stripped from the stashed prompt.
const prompt = promptRef.current.split(INLINE_TERMINAL_CONTEXT_PLACEHOLDER).join("").trim();
const images = [...composerImagesRef.current];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Wait for paste compression before stashing

When a large pasted image is still being compressed, it is only represented in pendingImageCompressionsRef and is absent from composerImagesRef.current. Pressing the stash shortcut during that window therefore saves and clears the prompt without the image; once compression finishes, the image is added back to the now-empty draft instead of the stash. Block or coordinate stashing just as submitComposer already does for pending image compression.

Useful? React with 👍 / 👎.

target.context.fillStyle = "#ffffff";
target.context.fillRect(0, 0, width, height);
}
target.context.drawImage(bitmap, 0, 0, width, height);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve animation during image recompression

For an animated GIF or WebP above the composer or stash size budget, drawing the ImageBitmap onto a canvas and encoding that canvas produces a single-frame WebP/JPEG. The attachment is accepted without warning but every frame after the decoded frame is silently discarded, even though the backend accepts GIF/WebP attachments. Detect animated inputs and reject/preserve them, or use animation-aware transcoding instead of this canvas path.

Useful? React with 👍 / 👎.

Comment on lines +281 to +289
<div className="surface-subheader gap-1 px-2" data-surface-subheader>
<RefreshFilesButton isPending={entriesQuery.isPending} onRefresh={entriesQuery.refresh} />
<FileSearchField
name="project-files-search"
ariaLabel={`Search ${projectName} files`}
value={search.value}
onValueChange={handleSearchValueChange}
onClose={search.close}
/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep truncation visible in the file browser

When the project-entry response has truncated: true, this replacement header no longer renders the previous “partial” indicator anywhere. Because useFileTreeSearch searches only the returned tree paths, users of large repositories can now interpret an absent search result as a missing file even though it was merely omitted by the server-side entry limit. Retain a visible partial-results warning alongside the new search field.

Useful? React with 👍 / 👎.

// Electron's updater owns the remaining quit/install/relaunch sequence.
// Cancelling the following app "before-quit" event breaks that sequence,
// most visibly on macOS where the native updater performs the relaunch.
updaterQuitAllowed = true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Shut down backends before updater-controlled quit

When before-quit-for-update sets this flag, the following before-quit event takes handleBeforeQuit's early-return path and never calls requestDesktopShutdownAndWait. DesktopApp is still blocked on shutdown.awaitRequest, so its backend-pool finalizer—the path that sends each backend its graceful stop—cannot run before Electron exits; installing an update can therefore hard-kill local/WSL backends and skip their persistence cleanup. Coordinate shutdown before invoking quitAndInstall rather than bypassing it.

AGENTS.md reference: AGENTS.md:L25-L25

Useful? React with 👍 / 👎.

Comment on lines +2230 to +2233
// Always claim the shortcut so the browser save dialog never opens,
// even when the composer is in a state that can't stash.
event.preventDefault();
event.stopPropagation();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Scope the stash shortcut to the composer

When focus is in the right-panel file editor or another editable control within the chat route, this window capture listener still resolves the default mod+s binding because it only excludes terminal focus. It then prevents the event before the focused editor can handle Save and may clear an unrelated composer prompt into the stash. Gate the shortcut on composer focus or ignore non-composer editable targets.

Useful? React with 👍 / 👎.

const stashCurrentPrompt = useCallback(async () => {
// Terminal-context placeholders reference live sessions the stash can't
// round-trip, so they are stripped from the stashed prompt.
const prompt = promptRef.current.split(INLINE_TERMINAL_CONTEXT_PLACEHOLDER).join("").trim();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve prompt whitespace in stash entries

When a prompt begins with indentation, such as an indented Markdown code block, or intentionally ends in newlines, this .trim() mutates it before persistence and the composer is then cleared. Restoring the entry therefore cannot reproduce the original prompt and can change its Markdown interpretation, whereas the normal send path preserves promptRef.current. Use trimming only for the emptiness check while storing the original placeholder-stripped text.

Useful? React with 👍 / 👎.

@aaditagrawal
aaditagrawal deleted the sync/20260730-l4-web-polish branch August 1, 2026 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ effective changed lines (test files excluded in mixed PRs). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants