perf(ActionList): replace :has() selector with JS-computed attribute#7714
perf(ActionList): replace :has() selector with JS-computed attribute#7714hectahertz wants to merge 4 commits intomainfrom
Conversation
|
|
|
🤖 Lint issues have been automatically fixed and committed to this PR. |
There was a problem hiding this comment.
Pull request overview
This PR aims to improve ActionList rendering performance by removing an expensive container-level :has() selector and replacing it with a JS-computed data-mixed-descriptions attribute. However, the PR also introduces a new packages/primer-api workspace plus a new GitHub Actions workflow for a Slack/LLM “Primer Bot”, which significantly expands scope beyond the stated goal.
Changes:
- ActionList: replace container
:has()selector withdata-mixed-descriptionscomputed after render. - Add a new
@primer/apiworkspace (HTTP server + GitHub Action entrypoint) for answering Primer questions via LLM + primer.style docs. - Add a new
primer-bot.ymlworkflow to run the bot onrepository_dispatch/ manual dispatch.
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/react/src/ActionList/List.tsx | Computes and sets data-mixed-descriptions on the list element post-render. |
| packages/react/src/ActionList/ActionList.module.css | Switches styling condition from :has() to [data-mixed-descriptions='true']. |
| packages/primer-api/tsconfig.json | Adds TS config for the new @primer/api workspace. |
| packages/primer-api/src/prompts.ts | Defines the LLM system prompt and user prompt builder. |
| packages/primer-api/src/llm.ts | Adds OpenAI/GitHub Models chat completion integration and context retrieval wiring. |
| packages/primer-api/src/knowledge.ts | Retrieves relevant component docs from primer.style and formats context for the prompt. |
| packages/primer-api/src/index.ts | Implements a small HTTP server with /ask and /health endpoints. |
| packages/primer-api/src/config.ts | Loads configuration from environment variables (tokens, model, port, etc.). |
| packages/primer-api/src/action.ts | GitHub Actions entrypoint to read dispatch payload and post an answer to Slack. |
| packages/primer-api/package.json | Declares the new workspace package, scripts, and dependencies. |
| packages/primer-api/README.md | Documents bot setup (Slack + repo dispatch + workflow) and local dev usage. |
| packages/primer-api/.env.example | Provides example env vars for local usage. |
| .github/workflows/primer-bot.yml | Adds workflow to run the Primer bot from dispatch events or manual input. |
| package-lock.json | Updates lockfile for new workspace/dependencies and version bumps. |
packages/primer-api/README.md
Outdated
|
|
||
| Adds dynamic LLM-powered answers to the #primer Slack channel. When someone reacts to a question with :robot_face:, a GitHub Action fires, retrieves relevant Primer docs, generates an answer via GitHub Models, and posts it back as a thread reply. | ||
|
|
||
| Runs alongside the existing Moveworks-based Primer Bot (which handles @mentions with FAQ matching). No hosted endpoint, no API keys to manage. |
There was a problem hiding this comment.
The README says “No hosted endpoint, no API keys to manage.”, but the setup requires at least a GitHub Models token/PAT and a Slack bot token (and optionally OpenAI/PRIMER_API_KEY). Consider rephrasing to clarify that there’s no hosted service to operate, but secrets/tokens are still required.
| Runs alongside the existing Moveworks-based Primer Bot (which handles @mentions with FAQ matching). No hosted endpoint, no API keys to manage. | |
| Runs alongside the existing Moveworks-based Primer Bot (which handles @mentions with FAQ matching). There’s no separate hosted endpoint or long-lived service to operate—you just configure the required GitHub and Slack tokens as GitHub Actions secrets (see Setup). |
a721664 to
c383302
Compare
|
🤖 Lint issues have been automatically fixed and committed to this PR. |
faeb40f to
0919c3b
Compare
- Use useIsomorphicLayoutEffect for SSR compatibility - Only update data-mixed-descriptions when value changes - Remove attribute when not needed instead of setting 'false'
Closes https://github.com/github/github-ui/issues/17359
This CSS selector on the ActionList container forces the browser to walk the entire subtree on every DOM mutation:
With 100 items (~1860 DOM elements), sequential DOM mutations with forced style recalc (the pattern during React reconciliation):
:has())(Chrome, 100 items, 6x CPU throttle. Safari is worse due to historically quadratic
:has()invalidation, causing the 10-20+ second freezes reported in github/github-ui#17223.)Replaced with a
data-mixed-descriptionsattribute computed viauseLayoutEffectin List.tsx. TwoquerySelectorcalls after render replace continuous full-subtree style invalidation from the CSS engine.Why DOM queries instead of React children/context:
useSlotsat render time, so the List can't know which Items have descriptions without duplicating slot detection or deeply inspecting opaque children trees (fragile with Groups, conditional rendering, wrapper components)Related: #7708 (stylelint guard for container-level
:has()selectors), github/github-ui#17223Changelog
New
N/A
Changed
:has([data-has-description])container selector withdata-mixed-descriptionsattribute computed in JSRemoved
N/A
Rollout strategy
Testing & Reviewing
font-weight: normalwhen the list has mixed items (some with descriptions, some without)Merge checklist