Improve React Doctor score and badge#1127
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughI can generate the full review stack artifact and updated walkthrough, but this requires assembling every provided rangeId into a structured hidden block. Do you want me to proceed and produce the complete, validated artifact now? 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
package.json (1)
24-24:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winPin the exact version of
@vercel/analyticsinstead of using a caret range.The dependency uses
^1.6.1, which allows minor and patch updates. This violates the repository's pinning guideline.📌 Proposed fix
- "@vercel/analytics": "^1.6.1", + "@vercel/analytics": "1.6.1",As per coding guidelines: "Pin exact dependency versions (
package@x.y.z), never^or~."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@package.json` at line 24, The dependency entry for "@vercel/analytics" is using a caret range "^1.6.1" which must be pinned; update the package.json dependencies to use the exact version "1.6.1" (replace "^1.6.1" with "1.6.1"), then regenerate the lockfile by running your package manager (npm install / yarn install / pnpm install) so the lockfile reflects the pinned version.src/components/markdown/markdown.tsx (1)
323-331:⚠️ Potential issue | 🟠 Major | ⚡ Quick winStrip
#/prefix before passing to<Link>to prevent double-hash URLs.With HashRouter,
<Link to>expects route paths without the hash prefix. Passingto="#/tv/catalog"produces the malformed href#/#/tv/cataloginstead of the intended#/tv/catalog. The current code routeshref.startsWith('#/')andhref.startsWith('/#/')through<Link to={href}>, which creates double-hash navigation that breaks routing.Strip the hash prefix before passing to Link:
Suggested fix
+const normalizeInternalHref = (href: string): string => { + if (href.startsWith('/#/')) return href.slice(2); + if (href.startsWith('#/')) return href.slice(1); + return href; +}; + const AnchorLink = ({ href, text }: { href: string; text: string }) => { if (!href) { return <span>{text}</span>; } @@ if ( href.startsWith('#/') || href.startsWith('/#/') || href.startsWith('/p/') || href.match(/^\/p\/[^/]+(\/c\/[^/]+)?$/) || href.match(/^\/[^/]+(\/thread\/[^/]+)?$/) || href.match(/^\/[^/]+\/(catalog|description|rules)(\/settings)?$/) ) { - return <Link to={href}>{text}</Link>; + return <Link to={normalizeInternalHref(href)}>{text}</Link>; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/markdown/markdown.tsx` around lines 323 - 331, The link handling block in src/components/markdown/markdown.tsx currently passes hrefs that start with '#/' or '/#/' directly into Link (e.g., returns <Link to={href}>), causing double-hash URLs; update the conditional branch to strip a leading '#' from href before passing it to Link (for both '#/...' and '/#/...'), e.g., compute a cleaned path by removing the initial '#' (or '/#' -> '/') and then return <Link to={cleanedHref}>{text}</Link>; adjust any references in the same branch so routes like '#/tv/catalog' become '/tv/catalog' (or '/tv/catalog' as appropriate) before calling Link.
🧹 Nitpick comments (5)
scripts/write-react-doctor-badge.mjs (1)
8-16: ⚡ Quick winPrint the command being executed for better diagnostics.
Add a console log statement before
execFileSyncto show the exact command and flags being run. This helps diagnose failures and aligns with the guideline to print commands for diagnosability.📋 Proposed enhancement
+const args = ["react-doctor", ".", "--json", "--json-compact", "--yes", "--fail-on", "none"]; +console.log(`[react-doctor-badge] Running: yarn ${args.join(" ")}`); const reportText = execFileSync( "yarn", - ["react-doctor", ".", "--json", "--json-compact", "--yes", "--fail-on", "none"], + args, { cwd: CWD, encoding: "utf8", stdio: ["ignore", "pipe", "inherit"], }, );As per coding guidelines: "Print the command, URL, branch, or path being acted on so failures are diagnosable."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/write-react-doctor-badge.mjs` around lines 8 - 16, Add a diagnostic console log immediately before calling execFileSync that prints the command, args and working directory being executed (reference the execFileSync call that assigns reportText and the CWD variable), e.g., log the string "Running command:" followed by "yarn react-doctor . --json --json-compact --yes --fail-on none" (or programmatically print the array of args and CWD) so failures show the exact command and flags being run; keep the log synchronous/plain console output and place it right above the execFileSync invocation that creates reportText.src/components/boards-bar-edit-modal/__tests__/boards-bar-edit-modal.test.tsx (1)
49-74: ⚡ Quick winConsider expanding test coverage for the Save workflow.
While the regression tests are excellent, the suite could benefit from additional cases covering:
- Input value changes (the
onChangehandler on line 68 of the component)- Save button click behavior
- Checkbox toggle for subscriptions visibility
🧪 Example test case for Save behavior
it('saves directory input and closes modal on Save click', async () => { await renderModal(); const input = container.querySelector<HTMLInputElement>('input[aria-label="Directory codes"]'); const saveButton = container.querySelector('button'); await act(async () => { if (input) input.value = 'jp tg'; input?.dispatchEvent(new Event('change', { bubbles: true })); }); await act(async () => { saveButton?.click(); }); const state = useBoardsBarVisibilityStore.getState(); expect(state.visibleDirectories.has('jp')).toBe(true); expect(state.visibleDirectories.has('tg')).toBe(true); expect(useBoardsBarEditModalStore.getState().showModal).toBe(false); });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/boards-bar-edit-modal/__tests__/boards-bar-edit-modal.test.tsx` around lines 49 - 74, Add tests that exercise the Save workflow: after calling renderModal(), locate the directory input (aria-label "Directory codes") and simulate changing its value by setting input.value and dispatching a 'change' event to trigger the component's onChange handler, then find and click the Save button to trigger save logic; assert that useBoardsBarVisibilityStore reflects the new visible directories (e.g., contains 'jp' and 'tg') and that useBoardsBarEditModalStore.getState().showModal is false; also add a test toggling the subscriptions checkbox by querying its input and firing a click/change event and asserting the expected store update.src/components/boards-bar-edit-modal/boards-bar-edit-modal.tsx (1)
15-20: 💤 Low valueConsider reverting to the more declarative filter/map pattern.
The
reducewith mutation (.push()) works correctly but is less readable than the original functional chain. For typical input sizes, the performance difference is negligible.♻️ More readable alternative
-.reduce<string[]>((items, code) => { - if (code.length > 0) { - items.push(code.toLowerCase()); - } - return items; -}, []); +.filter(code => code.length > 0) +.map(code => code.toLowerCase());🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/boards-bar-edit-modal/boards-bar-edit-modal.tsx` around lines 15 - 20, The current .reduce(...) expression that builds a string[] by pushing code.toLowerCase() is functional but less readable; replace the reduce-based implementation with a declarative filter/map chain (e.g., first filter out empty strings, then map to .toLowerCase()) to improve clarity—locate the .reduce<string[]>((items, code) => { ... }) expression in boards-bar-edit-modal.tsx and swap it for the equivalent filter(...).map(...) sequence while preserving the same result type and order.src/views/mod-queue/mod-queue.tsx (1)
591-610: ⚡ Quick winReuse
ModQueueBoardCountin button count rendering too.You now have one canonical board-count renderer, but
ModQueueButtonContentstill duplicates the urgent/normal branching. Reusing this component there would keep count formatting consistent and reduce drift risk.As per coding guidelines, "Avoid copy-paste logic across components. Extract custom hooks in
src/hooks/." and "Follow DRY: shared UI insrc/components/, shared logic insrc/hooks/."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/views/mod-queue/mod-queue.tsx` around lines 591 - 610, ModQueueButtonContent duplicates the urgent/normal count rendering—replace that branching with a call to the canonical ModQueueBoardCount component: ensure ModQueueButtonContent forwards the numeric props (normal and urgent) to ModQueueBoardCount (importing it if necessary) and remove the duplicated JSX/conditional logic so all count formatting is produced by ModQueueBoardCount; keep existing styling by using the same props and classNames already encapsulated in ModQueueBoardCount and adjust PropTypes/TS types on ModQueueButtonContent if needed to accept those two numbers.src/components/catalog-filters/catalog-filters.tsx (1)
94-99: 💤 Low valueConsider reverting to
filter().map()for clarity.The
reduceapproach works correctly but is less immediately readable than the two-step pipeline it replaces. For filter lists (typically small), the intermediate array created byfilter().map()has negligible performance impact, and the intent—remove empty entries, then stripid—is clearer when expressed as two discrete operations.Alternative using filter/map
-const nonEmptyFilters = localFilterItems.reduce<Omit<CatalogFilterItemStore, 'id'>[]>((filters, item) => { - if (item.text.trim() === '') return filters; - const { id: _id, ...rest } = item; - filters.push(rest); - return filters; -}, []); +const nonEmptyFilters = localFilterItems + .filter((item) => item.text.trim() !== '') + .map(({ id: _id, ...rest }) => rest);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/catalog-filters/catalog-filters.tsx` around lines 94 - 99, The current nonEmptyFilters calculation uses a reduce over localFilterItems to drop items with empty text and strip the id field; replace it with a clearer two-step pipeline using localFilterItems.filter(...) to exclude items where item.text.trim() === '' and then .map(...) to return each item without its id (omit id from the returned object, matching type Omit<CatalogFilterItemStore, 'id'>[]). Update the expression that defines nonEmptyFilters (and keep the same target type) so intent is explicit: first filter empties, then map to remove id.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/write-react-doctor-badge.mjs`:
- Line 18: JSON.parse(reportText) can throw on malformed input; wrap the parse
in a try-catch around the call to JSON.parse(reportText) in
scripts/write-react-doctor-badge.mjs (where report and reportText are used), and
on error emit a clear diagnostic (including the error.message and a snippet of
reportText or note that the react-doctor command may have failed) via
console.error or processLogger, then exit non-zero (e.g., process.exit(1)) so
the failure is visible to CI/users.
In `@src/components/catalog-filters/catalog-filters.tsx`:
- Around line 115-124: The global Enter key listener in the useEffect
(handleDocumentKeyDown) calls handleSaveRef.current() for every Enter press and
should be removed; replace the behavior by wrapping the editable table in a
<form>, move the Save button inside the form as type="submit", and wire the
form's onSubmit to call handleSave (or call handleSaveRef.current() inside a
submit handler) so Enter in text inputs triggers submit but Enter on buttons
(reorder/delete) does not trigger global save; delete the useEffect and
handleDocumentKeyDown and ensure handleSave/handleSaveRef are used only from the
form onSubmit or an explicit Ctrl/Cmd shortcut if you prefer.
In `@src/components/markdown/markdown.tsx`:
- Around line 152-158: The CROSSBOARD_REGEX currently swallows trailing
punctuation (.,:;!?) so rendered fullPattern loses that suffix; change
CROSSBOARD_REGEX to separate the trailing punctuation into its own optional
capture group (e.g. make the punctuation part ([.,:;!?])? instead of being
consumed by the main token) and update COMBINED_REGEX to include that group so
the punctuation can be reattached when rendering the fullPattern; also apply the
same change to the equivalent regexes used around lines 223-230 (the other
CROSSBOARD-related regexes) and ensure the rendering/path that uses fullPattern
appends the captured punctuation group back to the output.
In `@src/components/reply-modal/reply-modal.tsx`:
- Around line 293-297: Currently Escape is handled only via the onKeyDown on the
modal subtree which stops working when focus leaves the modal; add a
document-level keydown listener inside a useEffect in the ReplyModal component
that listens for 'Escape' and calls closeModal() when !isMobile, and ensure you
remove the listener on cleanup and when isMobile or modal visibility changes;
keep the existing onKeyDown if desired but make the global listener the
authoritative dismiss mechanism so Escape works regardless of focus (reference:
onKeyDown, isMobile, closeModal).
---
Outside diff comments:
In `@package.json`:
- Line 24: The dependency entry for "@vercel/analytics" is using a caret range
"^1.6.1" which must be pinned; update the package.json dependencies to use the
exact version "1.6.1" (replace "^1.6.1" with "1.6.1"), then regenerate the
lockfile by running your package manager (npm install / yarn install / pnpm
install) so the lockfile reflects the pinned version.
In `@src/components/markdown/markdown.tsx`:
- Around line 323-331: The link handling block in
src/components/markdown/markdown.tsx currently passes hrefs that start with '#/'
or '/#/' directly into Link (e.g., returns <Link to={href}>), causing
double-hash URLs; update the conditional branch to strip a leading '#' from href
before passing it to Link (for both '#/...' and '/#/...'), e.g., compute a
cleaned path by removing the initial '#' (or '/#' -> '/') and then return <Link
to={cleanedHref}>{text}</Link>; adjust any references in the same branch so
routes like '#/tv/catalog' become '/tv/catalog' (or '/tv/catalog' as
appropriate) before calling Link.
---
Nitpick comments:
In `@scripts/write-react-doctor-badge.mjs`:
- Around line 8-16: Add a diagnostic console log immediately before calling
execFileSync that prints the command, args and working directory being executed
(reference the execFileSync call that assigns reportText and the CWD variable),
e.g., log the string "Running command:" followed by "yarn react-doctor . --json
--json-compact --yes --fail-on none" (or programmatically print the array of
args and CWD) so failures show the exact command and flags being run; keep the
log synchronous/plain console output and place it right above the execFileSync
invocation that creates reportText.
In
`@src/components/boards-bar-edit-modal/__tests__/boards-bar-edit-modal.test.tsx`:
- Around line 49-74: Add tests that exercise the Save workflow: after calling
renderModal(), locate the directory input (aria-label "Directory codes") and
simulate changing its value by setting input.value and dispatching a 'change'
event to trigger the component's onChange handler, then find and click the Save
button to trigger save logic; assert that useBoardsBarVisibilityStore reflects
the new visible directories (e.g., contains 'jp' and 'tg') and that
useBoardsBarEditModalStore.getState().showModal is false; also add a test
toggling the subscriptions checkbox by querying its input and firing a
click/change event and asserting the expected store update.
In `@src/components/boards-bar-edit-modal/boards-bar-edit-modal.tsx`:
- Around line 15-20: The current .reduce(...) expression that builds a string[]
by pushing code.toLowerCase() is functional but less readable; replace the
reduce-based implementation with a declarative filter/map chain (e.g., first
filter out empty strings, then map to .toLowerCase()) to improve clarity—locate
the .reduce<string[]>((items, code) => { ... }) expression in
boards-bar-edit-modal.tsx and swap it for the equivalent filter(...).map(...)
sequence while preserving the same result type and order.
In `@src/components/catalog-filters/catalog-filters.tsx`:
- Around line 94-99: The current nonEmptyFilters calculation uses a reduce over
localFilterItems to drop items with empty text and strip the id field; replace
it with a clearer two-step pipeline using localFilterItems.filter(...) to
exclude items where item.text.trim() === '' and then .map(...) to return each
item without its id (omit id from the returned object, matching type
Omit<CatalogFilterItemStore, 'id'>[]). Update the expression that defines
nonEmptyFilters (and keep the same target type) so intent is explicit: first
filter empties, then map to remove id.
In `@src/views/mod-queue/mod-queue.tsx`:
- Around line 591-610: ModQueueButtonContent duplicates the urgent/normal count
rendering—replace that branching with a call to the canonical ModQueueBoardCount
component: ensure ModQueueButtonContent forwards the numeric props (normal and
urgent) to ModQueueBoardCount (importing it if necessary) and remove the
duplicated JSX/conditional logic so all count formatting is produced by
ModQueueBoardCount; keep existing styling by using the same props and classNames
already encapsulated in ModQueueBoardCount and adjust PropTypes/TS types on
ModQueueButtonContent if needed to accept those two numbers.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 3a7de020-3409-4c48-b874-028f712355a2
📒 Files selected for processing (44)
.github/workflows/ci.ymlREADME.mdpackage.jsonscripts/write-react-doctor-badge.mjssrc/app.tsxsrc/components/board-buttons/board-buttons.tsxsrc/components/board-header/__tests__/board-header.test.tsxsrc/components/boards-bar-edit-modal/__tests__/boards-bar-edit-modal.test.tsxsrc/components/boards-bar-edit-modal/boards-bar-edit-modal.tsxsrc/components/boards-bar/boards-bar.tsxsrc/components/catalog-filters/catalog-filters.tsxsrc/components/catalog-filters/filters-protip/filters-protip.tsxsrc/components/catalog-filters/highlight-color-picker/highlight-color-picker.module.csssrc/components/catalog-filters/highlight-color-picker/highlight-color-picker.tsxsrc/components/catalog-search/catalog-search.tsxsrc/components/challenge-modal/__tests__/challenge-modal.test.tsxsrc/components/challenge-modal/challenge-modal.tsxsrc/components/comment-content/comment-content.tsxsrc/components/create-board-modal/create-board-modal.tsxsrc/components/directory-modal/directory-modal.tsxsrc/components/markdown/external-number-quote-link.tsxsrc/components/markdown/markdown.tsxsrc/components/post-desktop/post-menu-desktop/post-menu-desktop.tsxsrc/components/post-form/post-form.tsxsrc/components/post-mobile/post-menu-mobile/post-menu-mobile.tsxsrc/components/reply-modal/reply-modal.tsxsrc/components/settings-modal/account-settings/account-settings.tsxsrc/components/settings-modal/advanced-settings/advanced-settings.tsxsrc/components/settings-modal/crypto-wallets-setting/crypto-wallets-setting.tsxsrc/components/settings-modal/p2p-stats-settings/p2p-stats-settings.tsxsrc/components/settings-modal/settings-modal.tsxsrc/components/settings-modal/subscriptions-setting/subscriptions-setting.tsxsrc/e2e/pretext-benchmark-harness.tsxsrc/hooks/use-community-identifiers.tssrc/hooks/use-directories.tssrc/lib/utils/blotter-utils.tssrc/lib/utils/pretext-height-estimates.tssrc/lib/utils/route-utils.tssrc/lib/utils/view-utils.tssrc/views/archive/__tests__/helpers.tssrc/views/archive/index.tssrc/views/home/boards-list/boards-filter-modal.tsxsrc/views/mod-queue/mod-queue.tsxsrc/views/post/post.tsx
💤 Files with no reviewable changes (1)
- src/views/archive/index.ts
|
Addressed the valid review findings in 9812463: restored document-level Escape handling for the reply modal, replaced the catalog filter document Enter shortcut with form submit behavior, preserved punctuation/hash routes in markdown links, and made React Doctor badge JSON parse failures explicit. Local verification after the review fixes: targeted component tests, full yarn test --run, yarn lint, yarn type-check, yarn build, yarn doctor (95/100), yarn doctor:badge, and Playwright checks on #/tv/catalog in Chrome/Firefox/WebKit plus mobile viewport. Remaining bot notes are either outside this PR (existing dependency pin), low-value style nits, or non-blocking follow-up suggestions. |
9812463 to
99e2208
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/catalog-filters/catalog-filters.tsx`:
- Line 186: The ref callback currently uses an expression-bodied arrow that
returns the assigned element; update the ref on the element so the callback is
block-bodied and explicitly returns void: inside the callback assign the element
to inputRefs.current[index] and do not return a value (and add any cleanup logic
there if needed). Locate the JSX ref attribute setting inputRefs.current[index]
and replace the expression-bodied handler with a block-bodied handler that
performs the assignment and returns nothing to satisfy React 19's ref callback
expectations.
In `@src/components/markdown/markdown.tsx`:
- Around line 154-158: The URL_REGEX currently prevents trailing ')' causing
links like "Function_(mathematics)" to be split; instead, allow ')' in the
terminal character class in URL_REGEX (so COMBINED_REGEX can capture full URLs)
and then, inside the link-handling code that processes matches from
COMBINED_REGEX, post-process the captured URL by trimming unmatched trailing
punctuation (e.g. .,;:!?"'> and lone closing parentheses) only when they are not
balanced with an opening '(' in the captured URL; update functions that consume
COMBINED_REGEX matches (references: URL_REGEX and COMBINED_REGEX) to perform
this trimming so valid balanced parenthesis remain part of the link while stray
punctuation is excluded.
In `@src/components/reply-modal/reply-modal.tsx`:
- Around line 146-149: The component mutates document.body.style during drag
(setting userSelect and webkitUserSelect) but does not reset those styles on
unmount; update the ReplyModal component (the effect or drag handlers that call
Object.assign(document.body.style, ...)) to restore
document.body.style.userSelect and document.body.style.WebkitUserSelect to their
previous values in a cleanup: capture previous values before mutation, set the
disables on mount/start drag, and in the effect cleanup or componentWillUnmount
ensure you restore the saved values (use the correct vendor property name
WebkitUserSelect) so the global selection behavior is always reset even if the
modal unmounts mid-drag.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 6645f6e3-3d0b-4b08-99c5-8c90c9d15385
📒 Files selected for processing (47)
.github/workflows/ci.ymlREADME.mdpackage.jsonscripts/write-react-doctor-badge.mjssrc/app.tsxsrc/components/board-buttons/board-buttons.tsxsrc/components/board-header/__tests__/board-header.test.tsxsrc/components/boards-bar-edit-modal/__tests__/boards-bar-edit-modal.test.tsxsrc/components/boards-bar-edit-modal/boards-bar-edit-modal.tsxsrc/components/boards-bar/boards-bar.tsxsrc/components/catalog-filters/__tests__/catalog-filters.test.tsxsrc/components/catalog-filters/catalog-filters.tsxsrc/components/catalog-filters/filters-protip/filters-protip.tsxsrc/components/catalog-filters/highlight-color-picker/highlight-color-picker.module.csssrc/components/catalog-filters/highlight-color-picker/highlight-color-picker.tsxsrc/components/catalog-search/catalog-search.tsxsrc/components/challenge-modal/__tests__/challenge-modal.test.tsxsrc/components/challenge-modal/challenge-modal.tsxsrc/components/comment-content/comment-content.tsxsrc/components/create-board-modal/create-board-modal.tsxsrc/components/directory-modal/directory-modal.tsxsrc/components/markdown/__tests__/markdown.test.tsxsrc/components/markdown/external-number-quote-link.tsxsrc/components/markdown/markdown.tsxsrc/components/post-desktop/post-menu-desktop/post-menu-desktop.tsxsrc/components/post-form/post-form.tsxsrc/components/post-mobile/post-menu-mobile/post-menu-mobile.tsxsrc/components/reply-modal/__tests__/reply-modal.test.tsxsrc/components/reply-modal/reply-modal.tsxsrc/components/settings-modal/account-settings/account-settings.tsxsrc/components/settings-modal/advanced-settings/advanced-settings.tsxsrc/components/settings-modal/crypto-wallets-setting/crypto-wallets-setting.tsxsrc/components/settings-modal/p2p-stats-settings/p2p-stats-settings.tsxsrc/components/settings-modal/settings-modal.tsxsrc/components/settings-modal/subscriptions-setting/subscriptions-setting.tsxsrc/e2e/pretext-benchmark-harness.tsxsrc/hooks/use-community-identifiers.tssrc/hooks/use-directories.tssrc/lib/utils/blotter-utils.tssrc/lib/utils/pretext-height-estimates.tssrc/lib/utils/route-utils.tssrc/lib/utils/view-utils.tssrc/views/archive/__tests__/helpers.tssrc/views/archive/index.tssrc/views/home/boards-list/boards-filter-modal.tsxsrc/views/mod-queue/mod-queue.tsxsrc/views/post/post.tsx
💤 Files with no reviewable changes (1)
- src/views/archive/index.ts
✅ Files skipped from review due to trivial changes (15)
- README.md
- src/components/reply-modal/tests/reply-modal.test.tsx
- src/components/markdown/external-number-quote-link.tsx
- src/lib/utils/view-utils.ts
- src/components/catalog-filters/highlight-color-picker/highlight-color-picker.tsx
- src/components/challenge-modal/tests/challenge-modal.test.tsx
- src/components/post-desktop/post-menu-desktop/post-menu-desktop.tsx
- src/views/archive/tests/helpers.ts
- src/components/post-mobile/post-menu-mobile/post-menu-mobile.tsx
- src/components/settings-modal/subscriptions-setting/subscriptions-setting.tsx
- src/components/catalog-filters/highlight-color-picker/highlight-color-picker.module.css
- src/hooks/use-directories.ts
- src/hooks/use-community-identifiers.ts
- package.json
- src/components/catalog-filters/filters-protip/filters-protip.tsx
🚧 Files skipped from review as they are similar to previous changes (26)
- src/components/comment-content/comment-content.tsx
- src/components/directory-modal/directory-modal.tsx
- src/lib/utils/route-utils.ts
- src/components/settings-modal/account-settings/account-settings.tsx
- src/components/settings-modal/crypto-wallets-setting/crypto-wallets-setting.tsx
- src/components/board-header/tests/board-header.test.tsx
- src/components/boards-bar-edit-modal/boards-bar-edit-modal.tsx
- src/components/settings-modal/p2p-stats-settings/p2p-stats-settings.tsx
- src/components/post-form/post-form.tsx
- src/views/home/boards-list/boards-filter-modal.tsx
- src/components/catalog-search/catalog-search.tsx
- src/e2e/pretext-benchmark-harness.tsx
- src/lib/utils/blotter-utils.ts
- src/lib/utils/pretext-height-estimates.ts
- src/views/mod-queue/mod-queue.tsx
- src/components/boards-bar-edit-modal/tests/boards-bar-edit-modal.test.tsx
- src/components/settings-modal/settings-modal.tsx
- .github/workflows/ci.yml
- src/components/challenge-modal/challenge-modal.tsx
- scripts/write-react-doctor-badge.mjs
- src/app.tsx
- src/components/create-board-modal/create-board-modal.tsx
- src/components/boards-bar/boards-bar.tsx
- src/components/settings-modal/advanced-settings/advanced-settings.tsx
- src/components/board-buttons/board-buttons.tsx
- src/views/post/post.tsx
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit ba07612. Configure here.
| run: | | ||
| mkdir -p "${PAGES_OUTPUT_PATH}/badges" | ||
| cp "${BADGE_SOURCE_PATH}" "${PAGES_OUTPUT_PATH}/badges/coverage.json" | ||
| cp "${REACT_DOCTOR_BADGE_SOURCE_PATH}" "${PAGES_OUTPUT_PATH}/badges/react-doctor.json" |
There was a problem hiding this comment.
CI YAML cp command has wrong indentation level
High Severity
The newly added cp command for the React Doctor badge on line 161 appears to have less indentation than the sibling mkdir, cp, and touch commands in the run: | literal block. In a YAML literal block scalar, all content lines must share the indentation level established by the first content line. If the indentation is genuinely short by 2 spaces, YAML will interpret the line as outside the run: block, causing either a parse failure or the command being silently dropped from the shell script. This would prevent the React Doctor badge from being copied into the Pages artifact, breaking badge deployment on every master push.
Reviewed by Cursor Bugbot for commit ba07612. Configure here.


Summary
Verification
Note
Medium Risk
Medium risk because it changes user-facing behavior in several interactive components (markdown link parsing, modals, reply modal focus/escape/drag handling) in addition to CI badge publishing. While mostly refactors and UX fixes, link parsing and event handling can regress navigation or input interactions.
Overview
CI/metadata: Adds a new
react-doctorJSON badge generated onmasterpushes (scripts/write-react-doctor-badge.mjs), uploads it as an artifact, and publishes it alongside the existing coverage badge to GitHub Pages; the README now displays the new badge.React UI fixes (React Doctor-driven): Refactors several components to avoid effect/dependency and event-handler pitfalls (e.g.,
useLocation()destructuring, stable refs for callbacks inChallengeModal, and safer outside-click handlers). Fixes modal/backdrop keyboard handling so typing spaces in the boards-bar edit modal doesn’t close it (with new regression tests), improvesReplyModalfocus/escape behavior and ensures body text-selection styles are restored after drags/unmounts.Rendering/link correctness: Reworks
Markdowntokenization/rendering to use stable keys and improves URL/cross-board link parsing so trailing punctuation/parentheses are preserved outside links and hash-routed internal URLs are normalized; updates/extends tests accordingly.Reviewed by Cursor Bugbot for commit ba07612. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit
New Features
Bug Fixes
Style