fix(web): keep the provider settings editor from jumping - #130

Merged
rynfar merged 1 commit into
pylonfrom
upstream/2026-08-28-provider-editor-layout
Aug 29, 2026
Merged

fix(web): keep the provider settings editor from jumping#130
rynfar merged 1 commit into
pylonfrom
upstream/2026-08-28-provider-editor-layout

Conversation

@rynfar

@rynfarrynfar commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Selecting a different provider account resized the whole settings panel. The
master-detail grid had no height of its own, so the editor pane grew to fit
whichever account was open and the surrounding page reflowed. The models list
was separately capped at a max-h-40 scroll box no matter how much room the
editor had.

Gives the grid a fixed height (lg:h-[min(38rem,calc(100dvh-16rem))] with a
30rem floor), makes the list and editor panes scroll independently, pins the
headers and tab strip with shrink-0, and lets the models list grow to fill the
editor.

Adopted from T3 Code f276e632c5a7952655e2455aef3b86c08164b988
(pingdotgg/t3code#8472) — the follow-up to the provider settings split Pylon
adopted in #125.

Adaptation

Upstream #8472 also re-added the account email as a labelled Account email
field in the Configuration tab. Pylon already shows it in the editor header, so
that half is deliberately not adopted: taking both would render the same
redacted address twice in one panel.

Four conflicts, all resolved Pylon-first, preserving:

  • the richer ProviderAuthEmail (prefix/separator variant used by the header);
  • the widened showEditorStatus (also true when disabled, when an email exists,
    or when sign-in is offered);
  • the disabled-account detail message;
  • the Provider usage block and its ProviderUsageRows.

Upstream's test for the Configuration placement is retargeted at Pylon's header
placement, keeps its security assertion, and gains a guard that the Configuration
field stays absent. It also needed Pylon's required timestampFormat prop, which
upstream's card does not have — that surfaced as a typecheck error, not a test
failure, since React tolerates the missing prop at runtime.

Verification

  • vp test run ProviderInstanceCard.test.ts ProviderSettingsPanel.environment.test.tsx — 9 passed
  • vp run -F @t3tools/web typecheck — clean
  • vp lint + vp fmt on the four changed files — clean
  • Mutation probes on the adapted test, both directions:
    • removing the redacted email from the editor header fails it
      (expected … to contain 'aria-label="Toggle account email visibility"');
    • re-adding upstream's Configuration field fails it
      (expected … not to contain 'Account email').
      The second probe initially passed for the wrong reason — my first injection
      landed somewhere unrendered — so the guard was re-verified against a checked
      insertion point rather than assumed non-vacuous.

Before/after images are pending; this is one of several web changes in the
current upstream batch and they will get one consolidated real-client pass
rather than five separate dev-server runs.

Claude Opus 5 via Claude Code.


View with [code]smithAutofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Aug 28, 2026
@github-actions

github-actionsBot commented Aug 28, 2026

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.3 KiB13.2 KiB−106 B (−0.8%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−5 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.4 KiB6.3 KiB−101 B (−1.5%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB54.7 KiB−822 B (−1.4%)66.4 KiB
CodexLive turn messages990 (0.0%)21
ClaudeTotal thread wire13.3 KiB13.3 KiB−2 B (−0.0%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+16 B (+0.2%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.4 KiB−18 B (−0.3%)7.8 KiB
ClaudeLive turn WebSocket decoded56.4 KiB56.4 KiB−44 B (−0.1%)66.4 KiB
ClaudeLive turn messages1110−1 (−9.1%)21

Baseline: 3d6035f · PR result: c7eaf6a · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Review note — inherited limitation, deliberately not fixed here.

The Configuration tab's new lg:overflow-y-auto scroller sits inside the wrapper
carrying inert={readOnly}. On a view-only environment at lg width with config
content taller than the pane, the scroller is not focusable and its contents are
inert, so the bottom of the read-only configuration may be unreachable — the page
scroller used to handle that.

Upstream has the identical structure (readOnly came from #8380, the scroller
from #8472), so this is not a Pylon regression and not something this adoption
introduces. Fixing it means moving inert off the scrolling element onto an inner
wrapper, which is a structural divergence from upstream and a separate concern
from the layout fix. Flagging it here so it is on the record rather than silently
carried.

Also cosmetic and identical upstream: at lg width but short height (e.g.
1280x600) the lg:min-h-[30rem] floor can produce nested page-then-pane
scrolling.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Before / after

Captured against the seeded database at 1280x860, same provider (Codex), same
Configuration tab, toasts dismissed.

Before — the panel has no height of its own, so the editor runs past the
viewport and the whole page scrolls. Advanced is off-screen entirely.

Before: provider settings editor runs past the viewport

After — the grid is height-bounded, the editor pane scrolls internally (note
"Path to the Codex binary…" clipped at the pane edge rather than the page edge),
the list pane keeps its own footer, and Advanced is now visible below the
panel instead of being pushed off-screen.

After: panel is height-bounded and panes scroll independently

Verification note: the first capture attempt produced an identical-looking
"after" because Vite was still serving the pre-switch module — confirmed by
curling /src/components/settings/ProviderSettingsPanel.tsx and finding zero
occurrences of the new min(38rem…) class. The dev server was restarted and the
class confirmed served before recapturing, so these two images really do differ
by this branch.

The account email stays in the editor header in both, which is the placement this
PR deliberately keeps rather than adopting upstream's Configuration-tab field.

Selecting a different provider account resized the whole settings panel,
because the master-detail grid had no height of its own and the editor pane
grew to fit whichever account was open. The models list was also capped at a
40-unit scroll box regardless of available space.
Gives the grid a fixed height, lets the list and editor panes scroll
independently, and lets the models list grow to fill the editor instead of
scrolling inside a stub.
Adopted from T3 Code f276e632c5a7952655e2455aef3b86c08164b988
(pingdotgg/t3code#8472), the follow-up to the provider settings split Pylon
took in #125.
Adaptation: upstream also re-added the account email as a labelled
"Account email" field in the Configuration tab. Pylon already shows it in the
editor header, so that half is deliberately not adopted — taking both would
render the same redacted address twice in one panel. Upstream's test for the
Configuration placement is retargeted at Pylon's header placement and gains a
guard asserting the Configuration field stays absent; it also needed Pylon's
required timestampFormat prop, which upstream's card does not have. Four
conflicts resolved Pylon-first, preserving the richer ProviderAuthEmail, the
widened showEditorStatus, the disabled-account detail message, and the
Provider usage block.
@rynfar
rynfarforce-pushed the upstream/2026-08-28-provider-editor-layout branch from 919a496 to c7eaf6aCompareAugust 29, 2026 02:55
@rynfar
rynfar merged commit 7733645 into pylonAug 29, 2026
15 checks passed
@rynfar
rynfar deleted the upstream/2026-08-28-provider-editor-layout branch August 29, 2026 03:04
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:Mvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@rynfar
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(web): keep the provider settings editor from jumping - #130

Merged
rynfar merged 1 commit into
pylonfrom
upstream/2026-08-28-provider-editor-layout
Aug 29, 2026
Merged

fix(web): keep the provider settings editor from jumping#130
rynfar merged 1 commit into
pylonfrom
upstream/2026-08-28-provider-editor-layout

Conversation

@rynfar

@rynfarrynfar commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Selecting a different provider account resized the whole settings panel. The
master-detail grid had no height of its own, so the editor pane grew to fit
whichever account was open and the surrounding page reflowed. The models list
was separately capped at a max-h-40 scroll box no matter how much room the
editor had.

Gives the grid a fixed height (lg:h-[min(38rem,calc(100dvh-16rem))] with a
30rem floor), makes the list and editor panes scroll independently, pins the
headers and tab strip with shrink-0, and lets the models list grow to fill the
editor.

Adopted from T3 Code f276e632c5a7952655e2455aef3b86c08164b988
(pingdotgg/t3code#8472) — the follow-up to the provider settings split Pylon
adopted in #125.

Adaptation

Upstream #8472 also re-added the account email as a labelled Account email
field in the Configuration tab. Pylon already shows it in the editor header, so
that half is deliberately not adopted: taking both would render the same
redacted address twice in one panel.

Four conflicts, all resolved Pylon-first, preserving:

  • the richer ProviderAuthEmail (prefix/separator variant used by the header);
  • the widened showEditorStatus (also true when disabled, when an email exists,
    or when sign-in is offered);
  • the disabled-account detail message;
  • the Provider usage block and its ProviderUsageRows.

Upstream's test for the Configuration placement is retargeted at Pylon's header
placement, keeps its security assertion, and gains a guard that the Configuration
field stays absent. It also needed Pylon's required timestampFormat prop, which
upstream's card does not have — that surfaced as a typecheck error, not a test
failure, since React tolerates the missing prop at runtime.

Verification

  • vp test run ProviderInstanceCard.test.ts ProviderSettingsPanel.environment.test.tsx — 9 passed
  • vp run -F @t3tools/web typecheck — clean
  • vp lint + vp fmt on the four changed files — clean
  • Mutation probes on the adapted test, both directions:
    • removing the redacted email from the editor header fails it
      (expected … to contain 'aria-label="Toggle account email visibility"');
    • re-adding upstream's Configuration field fails it
      (expected … not to contain 'Account email').
      The second probe initially passed for the wrong reason — my first injection
      landed somewhere unrendered — so the guard was re-verified against a checked
      insertion point rather than assumed non-vacuous.

Before/after images are pending; this is one of several web changes in the
current upstream batch and they will get one consolidated real-client pass
rather than five separate dev-server runs.

Claude Opus 5 via Claude Code.


View with [code]smithAutofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Aug 28, 2026
@github-actions

github-actionsBot commented Aug 28, 2026

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.3 KiB13.2 KiB−106 B (−0.8%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−5 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.4 KiB6.3 KiB−101 B (−1.5%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB54.7 KiB−822 B (−1.4%)66.4 KiB
CodexLive turn messages990 (0.0%)21
ClaudeTotal thread wire13.3 KiB13.3 KiB−2 B (−0.0%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+16 B (+0.2%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.4 KiB−18 B (−0.3%)7.8 KiB
ClaudeLive turn WebSocket decoded56.4 KiB56.4 KiB−44 B (−0.1%)66.4 KiB
ClaudeLive turn messages1110−1 (−9.1%)21

Baseline: 3d6035f · PR result: c7eaf6a · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Review note — inherited limitation, deliberately not fixed here.

The Configuration tab's new lg:overflow-y-auto scroller sits inside the wrapper
carrying inert={readOnly}. On a view-only environment at lg width with config
content taller than the pane, the scroller is not focusable and its contents are
inert, so the bottom of the read-only configuration may be unreachable — the page
scroller used to handle that.

Upstream has the identical structure (readOnly came from #8380, the scroller
from #8472), so this is not a Pylon regression and not something this adoption
introduces. Fixing it means moving inert off the scrolling element onto an inner
wrapper, which is a structural divergence from upstream and a separate concern
from the layout fix. Flagging it here so it is on the record rather than silently
carried.

Also cosmetic and identical upstream: at lg width but short height (e.g.
1280x600) the lg:min-h-[30rem] floor can produce nested page-then-pane
scrolling.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Before / after

Captured against the seeded database at 1280x860, same provider (Codex), same
Configuration tab, toasts dismissed.

Before — the panel has no height of its own, so the editor runs past the
viewport and the whole page scrolls. Advanced is off-screen entirely.

Before: provider settings editor runs past the viewport

After — the grid is height-bounded, the editor pane scrolls internally (note
"Path to the Codex binary…" clipped at the pane edge rather than the page edge),
the list pane keeps its own footer, and Advanced is now visible below the
panel instead of being pushed off-screen.

After: panel is height-bounded and panes scroll independently

Verification note: the first capture attempt produced an identical-looking
"after" because Vite was still serving the pre-switch module — confirmed by
curling /src/components/settings/ProviderSettingsPanel.tsx and finding zero
occurrences of the new min(38rem…) class. The dev server was restarted and the
class confirmed served before recapturing, so these two images really do differ
by this branch.

The account email stays in the editor header in both, which is the placement this
PR deliberately keeps rather than adopting upstream's Configuration-tab field.

Selecting a different provider account resized the whole settings panel,
because the master-detail grid had no height of its own and the editor pane
grew to fit whichever account was open. The models list was also capped at a
40-unit scroll box regardless of available space.
Gives the grid a fixed height, lets the list and editor panes scroll
independently, and lets the models list grow to fill the editor instead of
scrolling inside a stub.
Adopted from T3 Code f276e632c5a7952655e2455aef3b86c08164b988
(pingdotgg/t3code#8472), the follow-up to the provider settings split Pylon
took in #125.
Adaptation: upstream also re-added the account email as a labelled
"Account email" field in the Configuration tab. Pylon already shows it in the
editor header, so that half is deliberately not adopted — taking both would
render the same redacted address twice in one panel. Upstream's test for the
Configuration placement is retargeted at Pylon's header placement and gains a
guard asserting the Configuration field stays absent; it also needed Pylon's
required timestampFormat prop, which upstream's card does not have. Four
conflicts resolved Pylon-first, preserving the richer ProviderAuthEmail, the
widened showEditorStatus, the disabled-account detail message, and the
Provider usage block.
@rynfar
rynfarforce-pushed the upstream/2026-08-28-provider-editor-layout branch from 919a496 to c7eaf6aCompareAugust 29, 2026 02:55
@rynfar
rynfar merged commit 7733645 into pylonAug 29, 2026
15 checks passed
@rynfar
rynfar deleted the upstream/2026-08-28-provider-editor-layout branch August 29, 2026 03:04
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:Mvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@rynfar
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(web): keep the provider settings editor from jumping - #130

Merged
rynfar merged 1 commit into
pylonfrom
upstream/2026-08-28-provider-editor-layout
Aug 29, 2026
Merged

fix(web): keep the provider settings editor from jumping#130
rynfar merged 1 commit into
pylonfrom
upstream/2026-08-28-provider-editor-layout

Conversation

@rynfar

@rynfarrynfar commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Selecting a different provider account resized the whole settings panel. The
master-detail grid had no height of its own, so the editor pane grew to fit
whichever account was open and the surrounding page reflowed. The models list
was separately capped at a max-h-40 scroll box no matter how much room the
editor had.

Gives the grid a fixed height (lg:h-[min(38rem,calc(100dvh-16rem))] with a
30rem floor), makes the list and editor panes scroll independently, pins the
headers and tab strip with shrink-0, and lets the models list grow to fill the
editor.

Adopted from T3 Code f276e632c5a7952655e2455aef3b86c08164b988
(pingdotgg/t3code#8472) — the follow-up to the provider settings split Pylon
adopted in #125.

Adaptation

Upstream #8472 also re-added the account email as a labelled Account email
field in the Configuration tab. Pylon already shows it in the editor header, so
that half is deliberately not adopted: taking both would render the same
redacted address twice in one panel.

Four conflicts, all resolved Pylon-first, preserving:

  • the richer ProviderAuthEmail (prefix/separator variant used by the header);
  • the widened showEditorStatus (also true when disabled, when an email exists,
    or when sign-in is offered);
  • the disabled-account detail message;
  • the Provider usage block and its ProviderUsageRows.

Upstream's test for the Configuration placement is retargeted at Pylon's header
placement, keeps its security assertion, and gains a guard that the Configuration
field stays absent. It also needed Pylon's required timestampFormat prop, which
upstream's card does not have — that surfaced as a typecheck error, not a test
failure, since React tolerates the missing prop at runtime.

Verification

  • vp test run ProviderInstanceCard.test.ts ProviderSettingsPanel.environment.test.tsx — 9 passed
  • vp run -F @t3tools/web typecheck — clean
  • vp lint + vp fmt on the four changed files — clean
  • Mutation probes on the adapted test, both directions:
    • removing the redacted email from the editor header fails it
      (expected … to contain 'aria-label="Toggle account email visibility"');
    • re-adding upstream's Configuration field fails it
      (expected … not to contain 'Account email').
      The second probe initially passed for the wrong reason — my first injection
      landed somewhere unrendered — so the guard was re-verified against a checked
      insertion point rather than assumed non-vacuous.

Before/after images are pending; this is one of several web changes in the
current upstream batch and they will get one consolidated real-client pass
rather than five separate dev-server runs.

Claude Opus 5 via Claude Code.


View with [code]smithAutofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Aug 28, 2026
@github-actions

github-actionsBot commented Aug 28, 2026

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.3 KiB13.2 KiB−106 B (−0.8%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−5 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.4 KiB6.3 KiB−101 B (−1.5%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB54.7 KiB−822 B (−1.4%)66.4 KiB
CodexLive turn messages990 (0.0%)21
ClaudeTotal thread wire13.3 KiB13.3 KiB−2 B (−0.0%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+16 B (+0.2%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.4 KiB−18 B (−0.3%)7.8 KiB
ClaudeLive turn WebSocket decoded56.4 KiB56.4 KiB−44 B (−0.1%)66.4 KiB
ClaudeLive turn messages1110−1 (−9.1%)21

Baseline: 3d6035f · PR result: c7eaf6a · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Review note — inherited limitation, deliberately not fixed here.

The Configuration tab's new lg:overflow-y-auto scroller sits inside the wrapper
carrying inert={readOnly}. On a view-only environment at lg width with config
content taller than the pane, the scroller is not focusable and its contents are
inert, so the bottom of the read-only configuration may be unreachable — the page
scroller used to handle that.

Upstream has the identical structure (readOnly came from #8380, the scroller
from #8472), so this is not a Pylon regression and not something this adoption
introduces. Fixing it means moving inert off the scrolling element onto an inner
wrapper, which is a structural divergence from upstream and a separate concern
from the layout fix. Flagging it here so it is on the record rather than silently
carried.

Also cosmetic and identical upstream: at lg width but short height (e.g.
1280x600) the lg:min-h-[30rem] floor can produce nested page-then-pane
scrolling.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Before / after

Captured against the seeded database at 1280x860, same provider (Codex), same
Configuration tab, toasts dismissed.

Before — the panel has no height of its own, so the editor runs past the
viewport and the whole page scrolls. Advanced is off-screen entirely.

Before: provider settings editor runs past the viewport

After — the grid is height-bounded, the editor pane scrolls internally (note
"Path to the Codex binary…" clipped at the pane edge rather than the page edge),
the list pane keeps its own footer, and Advanced is now visible below the
panel instead of being pushed off-screen.

After: panel is height-bounded and panes scroll independently

Verification note: the first capture attempt produced an identical-looking
"after" because Vite was still serving the pre-switch module — confirmed by
curling /src/components/settings/ProviderSettingsPanel.tsx and finding zero
occurrences of the new min(38rem…) class. The dev server was restarted and the
class confirmed served before recapturing, so these two images really do differ
by this branch.

The account email stays in the editor header in both, which is the placement this
PR deliberately keeps rather than adopting upstream's Configuration-tab field.

Selecting a different provider account resized the whole settings panel,
because the master-detail grid had no height of its own and the editor pane
grew to fit whichever account was open. The models list was also capped at a
40-unit scroll box regardless of available space.
Gives the grid a fixed height, lets the list and editor panes scroll
independently, and lets the models list grow to fill the editor instead of
scrolling inside a stub.
Adopted from T3 Code f276e632c5a7952655e2455aef3b86c08164b988
(pingdotgg/t3code#8472), the follow-up to the provider settings split Pylon
took in #125.
Adaptation: upstream also re-added the account email as a labelled
"Account email" field in the Configuration tab. Pylon already shows it in the
editor header, so that half is deliberately not adopted — taking both would
render the same redacted address twice in one panel. Upstream's test for the
Configuration placement is retargeted at Pylon's header placement and gains a
guard asserting the Configuration field stays absent; it also needed Pylon's
required timestampFormat prop, which upstream's card does not have. Four
conflicts resolved Pylon-first, preserving the richer ProviderAuthEmail, the
widened showEditorStatus, the disabled-account detail message, and the
Provider usage block.
@rynfar
rynfarforce-pushed the upstream/2026-08-28-provider-editor-layout branch from 919a496 to c7eaf6aCompareAugust 29, 2026 02:55
@rynfar
rynfar merged commit 7733645 into pylonAug 29, 2026
15 checks passed
@rynfar
rynfar deleted the upstream/2026-08-28-provider-editor-layout branch August 29, 2026 03:04
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:Mvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@rynfar
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(web): keep the provider settings editor from jumping - #130

Merged
rynfar merged 1 commit into
pylonfrom
upstream/2026-08-28-provider-editor-layout
Aug 29, 2026
Merged

fix(web): keep the provider settings editor from jumping#130
rynfar merged 1 commit into
pylonfrom
upstream/2026-08-28-provider-editor-layout

Conversation

@rynfar

@rynfarrynfar commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Selecting a different provider account resized the whole settings panel. The
master-detail grid had no height of its own, so the editor pane grew to fit
whichever account was open and the surrounding page reflowed. The models list
was separately capped at a max-h-40 scroll box no matter how much room the
editor had.

Gives the grid a fixed height (lg:h-[min(38rem,calc(100dvh-16rem))] with a
30rem floor), makes the list and editor panes scroll independently, pins the
headers and tab strip with shrink-0, and lets the models list grow to fill the
editor.

Adopted from T3 Code f276e632c5a7952655e2455aef3b86c08164b988
(pingdotgg/t3code#8472) — the follow-up to the provider settings split Pylon
adopted in #125.

Adaptation

Upstream #8472 also re-added the account email as a labelled Account email
field in the Configuration tab. Pylon already shows it in the editor header, so
that half is deliberately not adopted: taking both would render the same
redacted address twice in one panel.

Four conflicts, all resolved Pylon-first, preserving:

  • the richer ProviderAuthEmail (prefix/separator variant used by the header);
  • the widened showEditorStatus (also true when disabled, when an email exists,
    or when sign-in is offered);
  • the disabled-account detail message;
  • the Provider usage block and its ProviderUsageRows.

Upstream's test for the Configuration placement is retargeted at Pylon's header
placement, keeps its security assertion, and gains a guard that the Configuration
field stays absent. It also needed Pylon's required timestampFormat prop, which
upstream's card does not have — that surfaced as a typecheck error, not a test
failure, since React tolerates the missing prop at runtime.

Verification

  • vp test run ProviderInstanceCard.test.ts ProviderSettingsPanel.environment.test.tsx — 9 passed
  • vp run -F @t3tools/web typecheck — clean
  • vp lint + vp fmt on the four changed files — clean
  • Mutation probes on the adapted test, both directions:
    • removing the redacted email from the editor header fails it
      (expected … to contain 'aria-label="Toggle account email visibility"');
    • re-adding upstream's Configuration field fails it
      (expected … not to contain 'Account email').
      The second probe initially passed for the wrong reason — my first injection
      landed somewhere unrendered — so the guard was re-verified against a checked
      insertion point rather than assumed non-vacuous.

Before/after images are pending; this is one of several web changes in the
current upstream batch and they will get one consolidated real-client pass
rather than five separate dev-server runs.

Claude Opus 5 via Claude Code.


View with [code]smithAutofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Aug 28, 2026
@github-actions

github-actionsBot commented Aug 28, 2026

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.3 KiB13.2 KiB−106 B (−0.8%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−5 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.4 KiB6.3 KiB−101 B (−1.5%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB54.7 KiB−822 B (−1.4%)66.4 KiB
CodexLive turn messages990 (0.0%)21
ClaudeTotal thread wire13.3 KiB13.3 KiB−2 B (−0.0%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+16 B (+0.2%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.4 KiB−18 B (−0.3%)7.8 KiB
ClaudeLive turn WebSocket decoded56.4 KiB56.4 KiB−44 B (−0.1%)66.4 KiB
ClaudeLive turn messages1110−1 (−9.1%)21

Baseline: 3d6035f · PR result: c7eaf6a · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Review note — inherited limitation, deliberately not fixed here.

The Configuration tab's new lg:overflow-y-auto scroller sits inside the wrapper
carrying inert={readOnly}. On a view-only environment at lg width with config
content taller than the pane, the scroller is not focusable and its contents are
inert, so the bottom of the read-only configuration may be unreachable — the page
scroller used to handle that.

Upstream has the identical structure (readOnly came from #8380, the scroller
from #8472), so this is not a Pylon regression and not something this adoption
introduces. Fixing it means moving inert off the scrolling element onto an inner
wrapper, which is a structural divergence from upstream and a separate concern
from the layout fix. Flagging it here so it is on the record rather than silently
carried.

Also cosmetic and identical upstream: at lg width but short height (e.g.
1280x600) the lg:min-h-[30rem] floor can produce nested page-then-pane
scrolling.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Before / after

Captured against the seeded database at 1280x860, same provider (Codex), same
Configuration tab, toasts dismissed.

Before — the panel has no height of its own, so the editor runs past the
viewport and the whole page scrolls. Advanced is off-screen entirely.

Before: provider settings editor runs past the viewport

After — the grid is height-bounded, the editor pane scrolls internally (note
"Path to the Codex binary…" clipped at the pane edge rather than the page edge),
the list pane keeps its own footer, and Advanced is now visible below the
panel instead of being pushed off-screen.

After: panel is height-bounded and panes scroll independently

Verification note: the first capture attempt produced an identical-looking
"after" because Vite was still serving the pre-switch module — confirmed by
curling /src/components/settings/ProviderSettingsPanel.tsx and finding zero
occurrences of the new min(38rem…) class. The dev server was restarted and the
class confirmed served before recapturing, so these two images really do differ
by this branch.

The account email stays in the editor header in both, which is the placement this
PR deliberately keeps rather than adopting upstream's Configuration-tab field.

Selecting a different provider account resized the whole settings panel,
because the master-detail grid had no height of its own and the editor pane
grew to fit whichever account was open. The models list was also capped at a
40-unit scroll box regardless of available space.
Gives the grid a fixed height, lets the list and editor panes scroll
independently, and lets the models list grow to fill the editor instead of
scrolling inside a stub.
Adopted from T3 Code f276e632c5a7952655e2455aef3b86c08164b988
(pingdotgg/t3code#8472), the follow-up to the provider settings split Pylon
took in #125.
Adaptation: upstream also re-added the account email as a labelled
"Account email" field in the Configuration tab. Pylon already shows it in the
editor header, so that half is deliberately not adopted — taking both would
render the same redacted address twice in one panel. Upstream's test for the
Configuration placement is retargeted at Pylon's header placement and gains a
guard asserting the Configuration field stays absent; it also needed Pylon's
required timestampFormat prop, which upstream's card does not have. Four
conflicts resolved Pylon-first, preserving the richer ProviderAuthEmail, the
widened showEditorStatus, the disabled-account detail message, and the
Provider usage block.
@rynfar
rynfarforce-pushed the upstream/2026-08-28-provider-editor-layout branch from 919a496 to c7eaf6aCompareAugust 29, 2026 02:55
@rynfar
rynfar merged commit 7733645 into pylonAug 29, 2026
15 checks passed
@rynfar
rynfar deleted the upstream/2026-08-28-provider-editor-layout branch August 29, 2026 03:04
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:Mvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@rynfar
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(web): keep the provider settings editor from jumping - #130

Merged
rynfar merged 1 commit into
pylonfrom
upstream/2026-08-28-provider-editor-layout
Aug 29, 2026
Merged

fix(web): keep the provider settings editor from jumping#130
rynfar merged 1 commit into
pylonfrom
upstream/2026-08-28-provider-editor-layout

Conversation

@rynfar

@rynfarrynfar commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Selecting a different provider account resized the whole settings panel. The
master-detail grid had no height of its own, so the editor pane grew to fit
whichever account was open and the surrounding page reflowed. The models list
was separately capped at a max-h-40 scroll box no matter how much room the
editor had.

Gives the grid a fixed height (lg:h-[min(38rem,calc(100dvh-16rem))] with a
30rem floor), makes the list and editor panes scroll independently, pins the
headers and tab strip with shrink-0, and lets the models list grow to fill the
editor.

Adopted from T3 Code f276e632c5a7952655e2455aef3b86c08164b988
(pingdotgg/t3code#8472) — the follow-up to the provider settings split Pylon
adopted in #125.

Adaptation

Upstream #8472 also re-added the account email as a labelled Account email
field in the Configuration tab. Pylon already shows it in the editor header, so
that half is deliberately not adopted: taking both would render the same
redacted address twice in one panel.

Four conflicts, all resolved Pylon-first, preserving:

  • the richer ProviderAuthEmail (prefix/separator variant used by the header);
  • the widened showEditorStatus (also true when disabled, when an email exists,
    or when sign-in is offered);
  • the disabled-account detail message;
  • the Provider usage block and its ProviderUsageRows.

Upstream's test for the Configuration placement is retargeted at Pylon's header
placement, keeps its security assertion, and gains a guard that the Configuration
field stays absent. It also needed Pylon's required timestampFormat prop, which
upstream's card does not have — that surfaced as a typecheck error, not a test
failure, since React tolerates the missing prop at runtime.

Verification

  • vp test run ProviderInstanceCard.test.ts ProviderSettingsPanel.environment.test.tsx — 9 passed
  • vp run -F @t3tools/web typecheck — clean
  • vp lint + vp fmt on the four changed files — clean
  • Mutation probes on the adapted test, both directions:
    • removing the redacted email from the editor header fails it
      (expected … to contain 'aria-label="Toggle account email visibility"');
    • re-adding upstream's Configuration field fails it
      (expected … not to contain 'Account email').
      The second probe initially passed for the wrong reason — my first injection
      landed somewhere unrendered — so the guard was re-verified against a checked
      insertion point rather than assumed non-vacuous.

Before/after images are pending; this is one of several web changes in the
current upstream batch and they will get one consolidated real-client pass
rather than five separate dev-server runs.

Claude Opus 5 via Claude Code.


View with [code]smithAutofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Aug 28, 2026
@github-actions

github-actionsBot commented Aug 28, 2026

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.3 KiB13.2 KiB−106 B (−0.8%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−5 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.4 KiB6.3 KiB−101 B (−1.5%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB54.7 KiB−822 B (−1.4%)66.4 KiB
CodexLive turn messages990 (0.0%)21
ClaudeTotal thread wire13.3 KiB13.3 KiB−2 B (−0.0%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+16 B (+0.2%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.4 KiB−18 B (−0.3%)7.8 KiB
ClaudeLive turn WebSocket decoded56.4 KiB56.4 KiB−44 B (−0.1%)66.4 KiB
ClaudeLive turn messages1110−1 (−9.1%)21

Baseline: 3d6035f · PR result: c7eaf6a · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Review note — inherited limitation, deliberately not fixed here.

The Configuration tab's new lg:overflow-y-auto scroller sits inside the wrapper
carrying inert={readOnly}. On a view-only environment at lg width with config
content taller than the pane, the scroller is not focusable and its contents are
inert, so the bottom of the read-only configuration may be unreachable — the page
scroller used to handle that.

Upstream has the identical structure (readOnly came from #8380, the scroller
from #8472), so this is not a Pylon regression and not something this adoption
introduces. Fixing it means moving inert off the scrolling element onto an inner
wrapper, which is a structural divergence from upstream and a separate concern
from the layout fix. Flagging it here so it is on the record rather than silently
carried.

Also cosmetic and identical upstream: at lg width but short height (e.g.
1280x600) the lg:min-h-[30rem] floor can produce nested page-then-pane
scrolling.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Before / after

Captured against the seeded database at 1280x860, same provider (Codex), same
Configuration tab, toasts dismissed.

Before — the panel has no height of its own, so the editor runs past the
viewport and the whole page scrolls. Advanced is off-screen entirely.

Before: provider settings editor runs past the viewport

After — the grid is height-bounded, the editor pane scrolls internally (note
"Path to the Codex binary…" clipped at the pane edge rather than the page edge),
the list pane keeps its own footer, and Advanced is now visible below the
panel instead of being pushed off-screen.

After: panel is height-bounded and panes scroll independently

Verification note: the first capture attempt produced an identical-looking
"after" because Vite was still serving the pre-switch module — confirmed by
curling /src/components/settings/ProviderSettingsPanel.tsx and finding zero
occurrences of the new min(38rem…) class. The dev server was restarted and the
class confirmed served before recapturing, so these two images really do differ
by this branch.

The account email stays in the editor header in both, which is the placement this
PR deliberately keeps rather than adopting upstream's Configuration-tab field.

Selecting a different provider account resized the whole settings panel,
because the master-detail grid had no height of its own and the editor pane
grew to fit whichever account was open. The models list was also capped at a
40-unit scroll box regardless of available space.
Gives the grid a fixed height, lets the list and editor panes scroll
independently, and lets the models list grow to fill the editor instead of
scrolling inside a stub.
Adopted from T3 Code f276e632c5a7952655e2455aef3b86c08164b988
(pingdotgg/t3code#8472), the follow-up to the provider settings split Pylon
took in #125.
Adaptation: upstream also re-added the account email as a labelled
"Account email" field in the Configuration tab. Pylon already shows it in the
editor header, so that half is deliberately not adopted — taking both would
render the same redacted address twice in one panel. Upstream's test for the
Configuration placement is retargeted at Pylon's header placement and gains a
guard asserting the Configuration field stays absent; it also needed Pylon's
required timestampFormat prop, which upstream's card does not have. Four
conflicts resolved Pylon-first, preserving the richer ProviderAuthEmail, the
widened showEditorStatus, the disabled-account detail message, and the
Provider usage block.
@rynfar
rynfarforce-pushed the upstream/2026-08-28-provider-editor-layout branch from 919a496 to c7eaf6aCompareAugust 29, 2026 02:55
@rynfar
rynfar merged commit 7733645 into pylonAug 29, 2026
15 checks passed
@rynfar
rynfar deleted the upstream/2026-08-28-provider-editor-layout branch August 29, 2026 03:04
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:Mvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@rynfar
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(web): keep the provider settings editor from jumping - #130

Merged
rynfar merged 1 commit into
pylonfrom
upstream/2026-08-28-provider-editor-layout
Aug 29, 2026
Merged

fix(web): keep the provider settings editor from jumping#130
rynfar merged 1 commit into
pylonfrom
upstream/2026-08-28-provider-editor-layout

Conversation

@rynfar

@rynfarrynfar commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Selecting a different provider account resized the whole settings panel. The
master-detail grid had no height of its own, so the editor pane grew to fit
whichever account was open and the surrounding page reflowed. The models list
was separately capped at a max-h-40 scroll box no matter how much room the
editor had.

Gives the grid a fixed height (lg:h-[min(38rem,calc(100dvh-16rem))] with a
30rem floor), makes the list and editor panes scroll independently, pins the
headers and tab strip with shrink-0, and lets the models list grow to fill the
editor.

Adopted from T3 Code f276e632c5a7952655e2455aef3b86c08164b988
(pingdotgg/t3code#8472) — the follow-up to the provider settings split Pylon
adopted in #125.

Adaptation

Upstream #8472 also re-added the account email as a labelled Account email
field in the Configuration tab. Pylon already shows it in the editor header, so
that half is deliberately not adopted: taking both would render the same
redacted address twice in one panel.

Four conflicts, all resolved Pylon-first, preserving:

  • the richer ProviderAuthEmail (prefix/separator variant used by the header);
  • the widened showEditorStatus (also true when disabled, when an email exists,
    or when sign-in is offered);
  • the disabled-account detail message;
  • the Provider usage block and its ProviderUsageRows.

Upstream's test for the Configuration placement is retargeted at Pylon's header
placement, keeps its security assertion, and gains a guard that the Configuration
field stays absent. It also needed Pylon's required timestampFormat prop, which
upstream's card does not have — that surfaced as a typecheck error, not a test
failure, since React tolerates the missing prop at runtime.

Verification

  • vp test run ProviderInstanceCard.test.ts ProviderSettingsPanel.environment.test.tsx — 9 passed
  • vp run -F @t3tools/web typecheck — clean
  • vp lint + vp fmt on the four changed files — clean
  • Mutation probes on the adapted test, both directions:
    • removing the redacted email from the editor header fails it
      (expected … to contain 'aria-label="Toggle account email visibility"');
    • re-adding upstream's Configuration field fails it
      (expected … not to contain 'Account email').
      The second probe initially passed for the wrong reason — my first injection
      landed somewhere unrendered — so the guard was re-verified against a checked
      insertion point rather than assumed non-vacuous.

Before/after images are pending; this is one of several web changes in the
current upstream batch and they will get one consolidated real-client pass
rather than five separate dev-server runs.

Claude Opus 5 via Claude Code.


View with [code]smithAutofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Aug 28, 2026
@github-actions

github-actionsBot commented Aug 28, 2026

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.3 KiB13.2 KiB−106 B (−0.8%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−5 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.4 KiB6.3 KiB−101 B (−1.5%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB54.7 KiB−822 B (−1.4%)66.4 KiB
CodexLive turn messages990 (0.0%)21
ClaudeTotal thread wire13.3 KiB13.3 KiB−2 B (−0.0%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+16 B (+0.2%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.4 KiB−18 B (−0.3%)7.8 KiB
ClaudeLive turn WebSocket decoded56.4 KiB56.4 KiB−44 B (−0.1%)66.4 KiB
ClaudeLive turn messages1110−1 (−9.1%)21

Baseline: 3d6035f · PR result: c7eaf6a · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Review note — inherited limitation, deliberately not fixed here.

The Configuration tab's new lg:overflow-y-auto scroller sits inside the wrapper
carrying inert={readOnly}. On a view-only environment at lg width with config
content taller than the pane, the scroller is not focusable and its contents are
inert, so the bottom of the read-only configuration may be unreachable — the page
scroller used to handle that.

Upstream has the identical structure (readOnly came from #8380, the scroller
from #8472), so this is not a Pylon regression and not something this adoption
introduces. Fixing it means moving inert off the scrolling element onto an inner
wrapper, which is a structural divergence from upstream and a separate concern
from the layout fix. Flagging it here so it is on the record rather than silently
carried.

Also cosmetic and identical upstream: at lg width but short height (e.g.
1280x600) the lg:min-h-[30rem] floor can produce nested page-then-pane
scrolling.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Before / after

Captured against the seeded database at 1280x860, same provider (Codex), same
Configuration tab, toasts dismissed.

Before — the panel has no height of its own, so the editor runs past the
viewport and the whole page scrolls. Advanced is off-screen entirely.

Before: provider settings editor runs past the viewport

After — the grid is height-bounded, the editor pane scrolls internally (note
"Path to the Codex binary…" clipped at the pane edge rather than the page edge),
the list pane keeps its own footer, and Advanced is now visible below the
panel instead of being pushed off-screen.

After: panel is height-bounded and panes scroll independently

Verification note: the first capture attempt produced an identical-looking
"after" because Vite was still serving the pre-switch module — confirmed by
curling /src/components/settings/ProviderSettingsPanel.tsx and finding zero
occurrences of the new min(38rem…) class. The dev server was restarted and the
class confirmed served before recapturing, so these two images really do differ
by this branch.

The account email stays in the editor header in both, which is the placement this
PR deliberately keeps rather than adopting upstream's Configuration-tab field.

Selecting a different provider account resized the whole settings panel,
because the master-detail grid had no height of its own and the editor pane
grew to fit whichever account was open. The models list was also capped at a
40-unit scroll box regardless of available space.
Gives the grid a fixed height, lets the list and editor panes scroll
independently, and lets the models list grow to fill the editor instead of
scrolling inside a stub.
Adopted from T3 Code f276e632c5a7952655e2455aef3b86c08164b988
(pingdotgg/t3code#8472), the follow-up to the provider settings split Pylon
took in #125.
Adaptation: upstream also re-added the account email as a labelled
"Account email" field in the Configuration tab. Pylon already shows it in the
editor header, so that half is deliberately not adopted — taking both would
render the same redacted address twice in one panel. Upstream's test for the
Configuration placement is retargeted at Pylon's header placement and gains a
guard asserting the Configuration field stays absent; it also needed Pylon's
required timestampFormat prop, which upstream's card does not have. Four
conflicts resolved Pylon-first, preserving the richer ProviderAuthEmail, the
widened showEditorStatus, the disabled-account detail message, and the
Provider usage block.
@rynfar
rynfarforce-pushed the upstream/2026-08-28-provider-editor-layout branch from 919a496 to c7eaf6aCompareAugust 29, 2026 02:55
@rynfar
rynfar merged commit 7733645 into pylonAug 29, 2026
15 checks passed
@rynfar
rynfar deleted the upstream/2026-08-28-provider-editor-layout branch August 29, 2026 03:04
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:Mvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@rynfar
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(web): keep the provider settings editor from jumping - #130

Merged
rynfar merged 1 commit into
pylonfrom
upstream/2026-08-28-provider-editor-layout
Aug 29, 2026
Merged

fix(web): keep the provider settings editor from jumping#130
rynfar merged 1 commit into
pylonfrom
upstream/2026-08-28-provider-editor-layout

Conversation

@rynfar

@rynfarrynfar commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Selecting a different provider account resized the whole settings panel. The
master-detail grid had no height of its own, so the editor pane grew to fit
whichever account was open and the surrounding page reflowed. The models list
was separately capped at a max-h-40 scroll box no matter how much room the
editor had.

Gives the grid a fixed height (lg:h-[min(38rem,calc(100dvh-16rem))] with a
30rem floor), makes the list and editor panes scroll independently, pins the
headers and tab strip with shrink-0, and lets the models list grow to fill the
editor.

Adopted from T3 Code f276e632c5a7952655e2455aef3b86c08164b988
(pingdotgg/t3code#8472) — the follow-up to the provider settings split Pylon
adopted in #125.

Adaptation

Upstream #8472 also re-added the account email as a labelled Account email
field in the Configuration tab. Pylon already shows it in the editor header, so
that half is deliberately not adopted: taking both would render the same
redacted address twice in one panel.

Four conflicts, all resolved Pylon-first, preserving:

  • the richer ProviderAuthEmail (prefix/separator variant used by the header);
  • the widened showEditorStatus (also true when disabled, when an email exists,
    or when sign-in is offered);
  • the disabled-account detail message;
  • the Provider usage block and its ProviderUsageRows.

Upstream's test for the Configuration placement is retargeted at Pylon's header
placement, keeps its security assertion, and gains a guard that the Configuration
field stays absent. It also needed Pylon's required timestampFormat prop, which
upstream's card does not have — that surfaced as a typecheck error, not a test
failure, since React tolerates the missing prop at runtime.

Verification

  • vp test run ProviderInstanceCard.test.ts ProviderSettingsPanel.environment.test.tsx — 9 passed
  • vp run -F @t3tools/web typecheck — clean
  • vp lint + vp fmt on the four changed files — clean
  • Mutation probes on the adapted test, both directions:
    • removing the redacted email from the editor header fails it
      (expected … to contain 'aria-label="Toggle account email visibility"');
    • re-adding upstream's Configuration field fails it
      (expected … not to contain 'Account email').
      The second probe initially passed for the wrong reason — my first injection
      landed somewhere unrendered — so the guard was re-verified against a checked
      insertion point rather than assumed non-vacuous.

Before/after images are pending; this is one of several web changes in the
current upstream batch and they will get one consolidated real-client pass
rather than five separate dev-server runs.

Claude Opus 5 via Claude Code.


View with [code]smithAutofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Aug 28, 2026
@github-actions

github-actionsBot commented Aug 28, 2026

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.3 KiB13.2 KiB−106 B (−0.8%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−5 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.4 KiB6.3 KiB−101 B (−1.5%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB54.7 KiB−822 B (−1.4%)66.4 KiB
CodexLive turn messages990 (0.0%)21
ClaudeTotal thread wire13.3 KiB13.3 KiB−2 B (−0.0%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+16 B (+0.2%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.4 KiB−18 B (−0.3%)7.8 KiB
ClaudeLive turn WebSocket decoded56.4 KiB56.4 KiB−44 B (−0.1%)66.4 KiB
ClaudeLive turn messages1110−1 (−9.1%)21

Baseline: 3d6035f · PR result: c7eaf6a · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Review note — inherited limitation, deliberately not fixed here.

The Configuration tab's new lg:overflow-y-auto scroller sits inside the wrapper
carrying inert={readOnly}. On a view-only environment at lg width with config
content taller than the pane, the scroller is not focusable and its contents are
inert, so the bottom of the read-only configuration may be unreachable — the page
scroller used to handle that.

Upstream has the identical structure (readOnly came from #8380, the scroller
from #8472), so this is not a Pylon regression and not something this adoption
introduces. Fixing it means moving inert off the scrolling element onto an inner
wrapper, which is a structural divergence from upstream and a separate concern
from the layout fix. Flagging it here so it is on the record rather than silently
carried.

Also cosmetic and identical upstream: at lg width but short height (e.g.
1280x600) the lg:min-h-[30rem] floor can produce nested page-then-pane
scrolling.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Before / after

Captured against the seeded database at 1280x860, same provider (Codex), same
Configuration tab, toasts dismissed.

Before — the panel has no height of its own, so the editor runs past the
viewport and the whole page scrolls. Advanced is off-screen entirely.

Before: provider settings editor runs past the viewport

After — the grid is height-bounded, the editor pane scrolls internally (note
"Path to the Codex binary…" clipped at the pane edge rather than the page edge),
the list pane keeps its own footer, and Advanced is now visible below the
panel instead of being pushed off-screen.

After: panel is height-bounded and panes scroll independently

Verification note: the first capture attempt produced an identical-looking
"after" because Vite was still serving the pre-switch module — confirmed by
curling /src/components/settings/ProviderSettingsPanel.tsx and finding zero
occurrences of the new min(38rem…) class. The dev server was restarted and the
class confirmed served before recapturing, so these two images really do differ
by this branch.

The account email stays in the editor header in both, which is the placement this
PR deliberately keeps rather than adopting upstream's Configuration-tab field.

Selecting a different provider account resized the whole settings panel,
because the master-detail grid had no height of its own and the editor pane
grew to fit whichever account was open. The models list was also capped at a
40-unit scroll box regardless of available space.
Gives the grid a fixed height, lets the list and editor panes scroll
independently, and lets the models list grow to fill the editor instead of
scrolling inside a stub.
Adopted from T3 Code f276e632c5a7952655e2455aef3b86c08164b988
(pingdotgg/t3code#8472), the follow-up to the provider settings split Pylon
took in #125.
Adaptation: upstream also re-added the account email as a labelled
"Account email" field in the Configuration tab. Pylon already shows it in the
editor header, so that half is deliberately not adopted — taking both would
render the same redacted address twice in one panel. Upstream's test for the
Configuration placement is retargeted at Pylon's header placement and gains a
guard asserting the Configuration field stays absent; it also needed Pylon's
required timestampFormat prop, which upstream's card does not have. Four
conflicts resolved Pylon-first, preserving the richer ProviderAuthEmail, the
widened showEditorStatus, the disabled-account detail message, and the
Provider usage block.
@rynfar
rynfarforce-pushed the upstream/2026-08-28-provider-editor-layout branch from 919a496 to c7eaf6aCompareAugust 29, 2026 02:55
@rynfar
rynfar merged commit 7733645 into pylonAug 29, 2026
15 checks passed
@rynfar
rynfar deleted the upstream/2026-08-28-provider-editor-layout branch August 29, 2026 03:04
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:Mvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@rynfar
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(web): keep the provider settings editor from jumping - #130

Merged
rynfar merged 1 commit into
pylonfrom
upstream/2026-08-28-provider-editor-layout
Aug 29, 2026
Merged

fix(web): keep the provider settings editor from jumping#130
rynfar merged 1 commit into
pylonfrom
upstream/2026-08-28-provider-editor-layout

Conversation

@rynfar

@rynfarrynfar commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Selecting a different provider account resized the whole settings panel. The
master-detail grid had no height of its own, so the editor pane grew to fit
whichever account was open and the surrounding page reflowed. The models list
was separately capped at a max-h-40 scroll box no matter how much room the
editor had.

Gives the grid a fixed height (lg:h-[min(38rem,calc(100dvh-16rem))] with a
30rem floor), makes the list and editor panes scroll independently, pins the
headers and tab strip with shrink-0, and lets the models list grow to fill the
editor.

Adopted from T3 Code f276e632c5a7952655e2455aef3b86c08164b988
(pingdotgg/t3code#8472) — the follow-up to the provider settings split Pylon
adopted in #125.

Adaptation

Upstream #8472 also re-added the account email as a labelled Account email
field in the Configuration tab. Pylon already shows it in the editor header, so
that half is deliberately not adopted: taking both would render the same
redacted address twice in one panel.

Four conflicts, all resolved Pylon-first, preserving:

  • the richer ProviderAuthEmail (prefix/separator variant used by the header);
  • the widened showEditorStatus (also true when disabled, when an email exists,
    or when sign-in is offered);
  • the disabled-account detail message;
  • the Provider usage block and its ProviderUsageRows.

Upstream's test for the Configuration placement is retargeted at Pylon's header
placement, keeps its security assertion, and gains a guard that the Configuration
field stays absent. It also needed Pylon's required timestampFormat prop, which
upstream's card does not have — that surfaced as a typecheck error, not a test
failure, since React tolerates the missing prop at runtime.

Verification

  • vp test run ProviderInstanceCard.test.ts ProviderSettingsPanel.environment.test.tsx — 9 passed
  • vp run -F @t3tools/web typecheck — clean
  • vp lint + vp fmt on the four changed files — clean
  • Mutation probes on the adapted test, both directions:
    • removing the redacted email from the editor header fails it
      (expected … to contain 'aria-label="Toggle account email visibility"');
    • re-adding upstream's Configuration field fails it
      (expected … not to contain 'Account email').
      The second probe initially passed for the wrong reason — my first injection
      landed somewhere unrendered — so the guard was re-verified against a checked
      insertion point rather than assumed non-vacuous.

Before/after images are pending; this is one of several web changes in the
current upstream batch and they will get one consolidated real-client pass
rather than five separate dev-server runs.

Claude Opus 5 via Claude Code.


View with [code]smithAutofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Aug 28, 2026
@github-actions

github-actionsBot commented Aug 28, 2026

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.3 KiB13.2 KiB−106 B (−0.8%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−5 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.4 KiB6.3 KiB−101 B (−1.5%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB54.7 KiB−822 B (−1.4%)66.4 KiB
CodexLive turn messages990 (0.0%)21
ClaudeTotal thread wire13.3 KiB13.3 KiB−2 B (−0.0%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+16 B (+0.2%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.4 KiB−18 B (−0.3%)7.8 KiB
ClaudeLive turn WebSocket decoded56.4 KiB56.4 KiB−44 B (−0.1%)66.4 KiB
ClaudeLive turn messages1110−1 (−9.1%)21

Baseline: 3d6035f · PR result: c7eaf6a · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Review note — inherited limitation, deliberately not fixed here.

The Configuration tab's new lg:overflow-y-auto scroller sits inside the wrapper
carrying inert={readOnly}. On a view-only environment at lg width with config
content taller than the pane, the scroller is not focusable and its contents are
inert, so the bottom of the read-only configuration may be unreachable — the page
scroller used to handle that.

Upstream has the identical structure (readOnly came from #8380, the scroller
from #8472), so this is not a Pylon regression and not something this adoption
introduces. Fixing it means moving inert off the scrolling element onto an inner
wrapper, which is a structural divergence from upstream and a separate concern
from the layout fix. Flagging it here so it is on the record rather than silently
carried.

Also cosmetic and identical upstream: at lg width but short height (e.g.
1280x600) the lg:min-h-[30rem] floor can produce nested page-then-pane
scrolling.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Before / after

Captured against the seeded database at 1280x860, same provider (Codex), same
Configuration tab, toasts dismissed.

Before — the panel has no height of its own, so the editor runs past the
viewport and the whole page scrolls. Advanced is off-screen entirely.

Before: provider settings editor runs past the viewport

After — the grid is height-bounded, the editor pane scrolls internally (note
"Path to the Codex binary…" clipped at the pane edge rather than the page edge),
the list pane keeps its own footer, and Advanced is now visible below the
panel instead of being pushed off-screen.

After: panel is height-bounded and panes scroll independently

Verification note: the first capture attempt produced an identical-looking
"after" because Vite was still serving the pre-switch module — confirmed by
curling /src/components/settings/ProviderSettingsPanel.tsx and finding zero
occurrences of the new min(38rem…) class. The dev server was restarted and the
class confirmed served before recapturing, so these two images really do differ
by this branch.

The account email stays in the editor header in both, which is the placement this
PR deliberately keeps rather than adopting upstream's Configuration-tab field.

Selecting a different provider account resized the whole settings panel,
because the master-detail grid had no height of its own and the editor pane
grew to fit whichever account was open. The models list was also capped at a
40-unit scroll box regardless of available space.
Gives the grid a fixed height, lets the list and editor panes scroll
independently, and lets the models list grow to fill the editor instead of
scrolling inside a stub.
Adopted from T3 Code f276e632c5a7952655e2455aef3b86c08164b988
(pingdotgg/t3code#8472), the follow-up to the provider settings split Pylon
took in #125.
Adaptation: upstream also re-added the account email as a labelled
"Account email" field in the Configuration tab. Pylon already shows it in the
editor header, so that half is deliberately not adopted — taking both would
render the same redacted address twice in one panel. Upstream's test for the
Configuration placement is retargeted at Pylon's header placement and gains a
guard asserting the Configuration field stays absent; it also needed Pylon's
required timestampFormat prop, which upstream's card does not have. Four
conflicts resolved Pylon-first, preserving the richer ProviderAuthEmail, the
widened showEditorStatus, the disabled-account detail message, and the
Provider usage block.
@rynfar
rynfarforce-pushed the upstream/2026-08-28-provider-editor-layout branch from 919a496 to c7eaf6aCompareAugust 29, 2026 02:55
@rynfar
rynfar merged commit 7733645 into pylonAug 29, 2026
15 checks passed
@rynfar
rynfar deleted the upstream/2026-08-28-provider-editor-layout branch August 29, 2026 03:04
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:Mvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@rynfar