Skip to content

feat(gui): clamp long provider notes to two lines and open the full text in a popup - #4328

Merged
lidge-jun merged 4 commits into
devfrom
codex/provider-catalog-note-popup
Sep 12, 2026
Merged

feat(gui): clamp long provider notes to two lines and open the full text in a popup#4328
lidge-jun merged 4 commits into
devfrom
codex/provider-catalog-note-popup

Conversation

@lidge-jun

@lidge-jun lidge-jun commented Sep 12, 2026

Copy link
Copy Markdown
Owner

Summary

  • One catalog note is a paragraph. opencode-free runs ~1100 characters and meta-muse is longer still, so at the modal width a single row rendered 15-20 lines inside a 360px scroller and became the only row anyone could see. Notes now clamp to two lines, and a row with more to show grows a reveal strip along its bottom edge that opens the full text in a popup.
  • The reveal is a sibling of the row button inside a new .provider-catalog-row-wrap, never a child. .list-row is itself a <button>; a button nested in a button is invalid HTML that the parser may hoist out of the row, and stopPropagation cannot save a control that is no longer where it was written.
  • The popup is a native <dialog> opened with showModal() - the same shape as OAuthTosWarningModal - rendered as a fragment sibling of the add-provider overlay rather than inside it. Native showModal() is what restores focus to the reveal button on close. AddProviderModal owns the open state because its Escape listener is on window and does not read defaultPrevented, so every stacked overlay has to be named in that guard or Escape closes the whole modal out from under it. Escape now closes the note first and the add-provider modal second.
  • Every nonempty note has a full-text button because rendered clipping depends on width, adapter chips and badges; no character threshold can safely hide access. Popup cleanup closes the native dialog and restores focus to the triggering button.

One trap worth flagging for review: the reveal strip is qualified as .link-btn.provider-catalog-note-more, and that is not redundant. This stylesheet is @imported at the top of styles.css while .link-btn is declared far below at equal specificity, so the bare class lost its background, border and padding and rendered as a full-width underlined link floating between two rows. Vite HMR hid it by injecting the edited file last; a production bundle would not have. .list-row.provider-catalog-account-row--waiting already carries the same qualification for the same reason.

This is a gui change. Clamped rows with the reveal strip, and the popup:

Add provider catalog with provider notes clamped to two lines and a Show full description strip on the rows that need it

The full provider note open in a stacked popup dialog

Verification

  • bun x tsc --noEmit - passed.
  • cd gui && bun x tsc --noEmit -p tsconfig.json - passed (includes gui/tests).
  • bun run structure:check - passed.
  • Manual, in a dev build of this branch after a hard reload rather than HMR: rows clamp to two lines, the reveal strip renders inside the row box, clicking it opens the popup with the whole note, clicking the row body still selects the provider, and the first Escape closes only the popup while the second closes the add-provider modal.
  • New coverage: noteNeedsReveal coverage for empty and nonempty notes in tests/gui/provider-workspace-data.test.ts, and gui/tests/provider-catalog-note-popup.test.tsx for sibling placement, the reveal not selecting the provider, and the popup carrying the full note.
  • The test suite was NOT RUN locally by instruction. Remote CI on this PR's head is the test evidence.

Based on #4325. Retarget to dev once that lands.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

Integration review

The owner requested merging this chain into dev. Integrating as lidge-jun under MAINTAINERS.md after exact-head remote CI passes; no self-approval is claimed. Local tests remain NOT RUN.
Both Codex review findings are fixed: every nonempty note has a full-text action, and dialog cleanup closes the native dialog and restores the trigger focus. Manually verified using the NVIDIA NIM row and Escape. This layer includes its structure documentation.

Verification target for maintainer integration: 3627b7bcb256cc737de0c4468163f434675792a9. Cross-platform CI: https://github.com/lidge-jun/opencodex/actions/runs/34672266087. Merge is gated on that exact-head run succeeding. Review repairs were verified with a production GUI build and browser checks; the local suite remains NOT RUN.

@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner September 12, 2026 02:14
@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

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

🗂️ Base branches to auto review (2)
  • ^dev$
  • ^preview$

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: c79b7f74-6f53-49d7-a66c-3c72c693d0e2

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.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 12, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-12T02:17:45.983983Z 414ec2d PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the enhancement New feature or request label Sep 12, 2026
@lidge-jun

Copy link
Copy Markdown
Owner Author

리뷰 · 우선순위 50 / 80

설명

이 PR은 Providers 대시보드의 프로바이더 추가 모달에서, 카탈로그 행에 붙은 긴 note를 두 줄로 줄이고 나머지는 팝업으로 읽는 R2(note clamp) 구현이다. 지금 dev HEAD는 a0676af29이고 Devin 라벨/컨텍스트 창 정확도(#4326/#4323) 쪽을 다듬는 중이라, 이 스택(#4324 계획 → #4325 Local 탭 → 이 #4328)은 아직 dev에 없다. 베이스도 dev가 아니라 codex/provider-catalog-local-tab(#4325)이다. 본문에 적힌 대로 #4325가 먼저 들어간 뒤 dev로 다시 겨냥하면 된다.

왜 필요한지부터 말하면, opencode-free note는 대략 1100자, meta-muse는 더 길다. 모달 폭에서 한 행이 15~20줄이 되면 360px 스크롤 안에서 그 행만 보이게 된다. 그래서 CSS로 .sub를 두 줄 line-clamp 하고, 잘린 행에만 하단 reveal 스트립을 붙인 뒤 전체 글을 팝업으로 연다.

중요한 설계 선택은 세 가지다. 첫째, reveal는 행 버튼의자식이 아니라 .provider-catalog-row-wrap 안의 형제다. .list-row 자체가 <button>이라 버튼을 안에 넣으면 HTML이 깨지고 파서가 밖으로 빼 버릴 수 있다. 그때는 stopPropagation도 소용없다. 둘째, 팝업은 OAuthTosWarningModal과 같은 네이티브 <dialog> + showModal()이고, 추가 모달 오버레이 안이 아니라 형제로 렌더한다. 셋째, Escape 가드는 AddProviderModal의 window 리스너가 defaultPrevented를 안 읽기 때문에 notePreset이 열려 있으면 추가 모달을 닫지 않게 이름을 넣어 두었다. 감사 문서 016_audit_corrections.md가 지적한 nested button / Escape / Accounts 클램프 금지 방향을 코드가 대체로 따라간다. Accounts 행은 tier !== "accounts" 분기로 wrap/reveal 자체가 없다.

검증 쪽은 noteNeedsReveal 경계 테스트와 gui/tests/provider-catalog-note-popup.test.tsx(형제 배치, reveal가 선택하지 않음, 전체 note 표시)가 추가됐다. 로케일 9개(en/de/fr/ja/ko/ru/tr/zh/zh-TW)에 modal.noteMore가 들어갔다. CSS cascade 함정도 본문에 잘 적혀 있다. provider-catalog.cssstyles.css 맨 위에서 import되고 .link-btn은 아래에 있어서, 한정자 없이 쓰면 배경/테두리가 날아가 행 사이에 밑줄 링크로 뜬다. .link-btn.provider-catalog-note-more로 맞춘 것은 맞고, Accounts waiting 행과 같은 패턴이다.

gui/src/components/provider-catalog/provider-presets.ts (NOTE_CLAMP_CHARS JSDoc) - 주석이 "Erring slightly long only costs a reveal"라고 쓰여 있는데, 실제 임계값 90은 짧게 잡아 reveal를 더 자주 띄우는 쪽이다. 030_r2_note_clamp.md의 supersede 문장(짧게 잡아야 잘린 채 읽을 수 없는 상태를 피한다)과 방향이 반대라, 나중에 숫자만 보고 120으로 되돌릴 위험이 있다.

gui/src/components/provider-catalog/ProviderCatalog.tsx (onShowNote?) - onShowNote가 선택(optional)인데 CSS 클램프는 wrap이 있으면 항상 적용된다. 호출부가 빼먹으면 긴 note는 잘리기만 하고 읽는 길이 사라진다. 지금 AddProviderModal은 넘기므로 당장 깨지진 않지만, 타입을 필수로 두거나 reveal 조건을 onShowNote 유무와 묶는 편이 안전하다.

gui/tests/provider-catalog-note-popup.test.tsx - Escape로 note만 닫히고 추가 모달은 남는 스택, 그리고 Accounts 행에 reveal가 안 붙는지는 테스트가 없다. 감사에서 막으라고 한 두 축이라 CI 통과만으로 그 계약을 고정하기 어렵다.

devlog/_plan/.../030_r2_note_clamp.md - 본문 일부는 여전히 role="dialog" 카드 표현이 남아 있고, 구현은 네이티브 <dialog>다. supersede 문단이 옆에 있어서 큰 혼란은 아니지만, 후속 PR이 옛 문장만 읽으면 다시 div dialog로 돌아갈 수 있다.

메인테이너의 판단이 필요한 지점

너의 추천

CI(특히 gui 테스트 잡)가 초록이 되면, #4324와 #4325가 dev에 들어간 뒤에 이 PR을 dev로 다시 겨냥해 합쳐라. 합치기 전에 JSDoc의 "erring long" 문장만 "erring short"로 고치고, 가능하면 Escape 스택 테스트 한 줄을 추가하라. 지금은 #4325 대기 + CI 확인이 다음 단계다.

이 댓글은 grok-bot이 작성했습니다

@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: 414ec2dffe

ℹ️ 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".

Comment on lines +132 to +133
export function noteNeedsReveal(note: string | undefined): boolean {
return (note?.trim().length ?? 0) > NOTE_CLAMP_CHARS;

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 Determine the reveal from actual rendered overflow

At the normal catalog width, character count does not correspond to the two-line clamp because the same line also contains the adapter chip and the badges reduce the available width. The committed screenshot already demonstrates this for NVIDIA NIM: its 86-character note is visibly cut off after “API...” while this predicate returns false, so the user gets no way to read the remaining key instructions. Detect rendered overflow (or conservatively provide the reveal for every nonempty clamped note) instead of using the note-only length.

Useful? React with 👍 / 👎.

Comment on lines +38 to +41
useEffect(() => {
const dialog = dialogRef.current;
if (dialog && !dialog.open) dialog.showModal();
}, []);

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 Restore focus after closing the note dialog

When the popup is dismissed via Escape, the backdrop, or either Close button, onClose immediately unmounts the still-open native dialog; no path calls dialog.close() and the parent retains no reference to the reveal button. Because the focused control is removed with the dialog, keyboard focus falls back to the document instead of returning to “Show full description,” so keyboard users lose their place in the catalog. Close the dialog during teardown and explicitly restore focus to the triggering reveal after the popup state clears.

AGENTS.md reference: gui/AGENTS.md:L31-L34

Useful? React with 👍 / 👎.

…ext in a popup

One catalog note is a paragraph. The opencode-free note runs ~1100 characters and meta-muse is longer still, so at the modal width a single row rendered 15-20 lines inside a 360px scroller and became the only row anyone could see. Notes now clamp to two lines and rows with more to show grow a reveal strip along their bottom edge.

The reveal is a SIBLING of the row button inside a new .provider-catalog-row-wrap, never a child: .list-row is itself a <button>, a button nested in a button is invalid HTML the parser may hoist out of the row, and stopPropagation cannot save a control that is no longer where it was written.

The popup is a native <dialog> opened with showModal(), the same shape as OAuthTosWarningModal, rendered as a fragment sibling of the add-provider overlay rather than inside it. Native showModal is what restores focus to the reveal button on close. AddProviderModal owns the open state because its Escape listener is on window and does not read defaultPrevented, so every stacked overlay has to be named in that guard or Escape closes the whole modal out from under it. Escape now closes the note first and the add-provider modal second.

The reveal strip is qualified as .link-btn.provider-catalog-note-more, and that is not redundant: this stylesheet is @imported at the top of styles.css while .link-btn is declared far below at equal specificity, so the bare class lost its background, border and padding and rendered as a full-width underlined link floating between rows. Vite HMR hid it; a production bundle would not have.
@lidge-jun
lidge-jun force-pushed the codex/provider-catalog-note-popup branch from 414ec2d to e3fdf8f Compare September 12, 2026 02:48
lidge-jun added a commit that referenced this pull request Sep 12, 2026
…vidence

Four dependent PRs with their exact heads and live CI run ids, plus the two traps that make a green head look red: a cancelled duplicate run leaves a FAILURE ci row attached to the same SHA as the live green run, and a cancelled required check is not a passing one - all three enforce-target attempts on #4328 were cancelled by concurrency, which left the PR UNSTABLE until one was re-run.
Base automatically changed from codex/provider-catalog-local-tab to dev September 12, 2026 04:15
@lidge-jun
lidge-jun changed the base branch from codex/provider-catalog-local-tab to dev September 12, 2026 04:15
@lidge-jun
lidge-jun merged commit d8df1b1 into dev Sep 12, 2026
35 of 37 checks passed
@lidge-jun
lidge-jun deleted the codex/provider-catalog-note-popup branch September 12, 2026 04:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant