Skip to content

[refactor] Take DrillInView off antd and into the Storybook inventory - #5694

Draft
ardaerzin wants to merge 18 commits into
feat/storybook-data-seamfrom
fe-refactor/entity-ui-off-antd
Draft

[refactor] Take DrillInView off antd and into the Storybook inventory#5694
ardaerzin wants to merge 18 commits into
feat/storybook-data-seamfrom
fe-refactor/entity-ui-off-antd

Conversation

@ardaerzin

Copy link
Copy Markdown
Contributor

Context

@agenta/entity-ui is the last big consumer of antd in the frontend, and DrillInView/ was the bulk of it: 63 of the package's 117 antd files, around 17k lines. It is also the least covered part of Storybook, which matters now that Storybook is our component inventory.

This PR takes DrillInView/ off antd and gives every surface it touches a Storybook entry.

Changes

The directory was migrated in two rounds of parallel chunks: playground-config, tools/skills/MCP, triggerManagement, the schema and prompt renderers, the leaf controls, and the agentTemplate family with its AgentTemplateControl composition root.

@agenta/entity-ui antd imports go from 117 to 2. The two that remain are the deliberate Form-engine residues already documented in the migration guide (SchemaForm and SubscriptionForm), not misses.

87 new story files. Parity stories where an antd half exists, so the VRT can pixel-diff old against new. Data-seam showcases where the component reads atoms, seeded through real query caches rather than broad mocks. selection/ is included even though it was already antd-free, because an antd-free component is still part of the inventory.

Three fixes are worth calling out because they are real user-facing bugs the migration exposed, not refactoring noise:

Sliders were unnamed to screen readers. role="slider" sits on the Radix thumb, but names were being passed to the Root, an unroled span. NumberSliderControl was passing aria-labelledby correctly and still producing an unnamed control, so the call site looked right while the name landed nowhere.

Collapsed panels held keyboard focus. HeightCollapse marked a collapsed body aria-hidden while its children stayed tabbable, so keyboard users could tab into invisible content. inert existed but was opt-in and almost nobody opted in. Both now derive from one collapsed-shut flag.

Muted text used the wrong token in 26 places. antd maps Typography.Text type="secondary" to colorTextDescription (#758391), not colorTextSecondary (#586673), so migrated text rendered darker than the antd it replaced. The pixel gate cannot catch this when the text sits outside a paired subject, which is how it survived wave 1.

Tests

  • VRT parity passes across the wave, both themes. Every diff above the 1% gate is declared with a measured reason (the deferred Skeleton.Button ramp, the Lexical portal harness, antd's 0.75px icon-centring residue).
  • axe went from about 600 violating nodes to zero across 294 stories, with 0 story errors. The fixes are in the primitives rather than at the several hundred call sites, and all are pixel-neutral.
  • tsc --noEmit clean on @agenta/ui, @agenta/entity-ui and @agenta/storybook. pnpm lint-fix clean.

Two notes for reviewers:

color-contrast is gated on the measured colours rather than per story. Waiving 469 nodes story by story would have had to name most of the inventory, and would have quietly covered colours that are not inherited at all. There are three declared categories: muted text tokens, antd preset semantic pairs, and white on hardcoded vendor brand colours such as #d97757. A colour in none of those lists still fails, which is how three colours missed by the first sample were caught.

The a11y harness needed two fixes to survive a full run: showcase stories matched none of its ready selectors and burned the timeout on each, and a single browser dies partway through a sweep, after which Playwright calls hang on a dead connection rather than throwing.

What to QA

  • Open an agent's config panel. Expand and collapse the sections, add and remove tools, and open the tool selector. Everything behaves as before, in light and dark.
  • Tab through a collapsed config section. Focus skips the collapsed body instead of landing on invisible controls.
  • Change a temperature or top-p slider with the keyboard. It works, and a screen reader announces the field name.
  • Open the model configure popover and change provider, model and the retry and fallback tabs. Values persist.
  • Set Pi permission rules with a pattern containing a comma, for example Bash(echo a,b:*). It stays one rule instead of splitting in two.
  • Regression: the playground prompt panel, message list and response format control all render and edit as before.

…es/testcase off antd (Form recipe on CustomProviderForm)
…; antd Form engine kept as documented cross-package residue)
…er drawer; DateTimeInput/MultiSelect/TimeSelect composites)
- LoadingButton: antd dims a loading button to opacityLoading (0.65); add the dim in the primitive and drop DrawerFooter's local compensation
- EnhancedDrawer: honor the declared size prop (default=378, large=736, number=px); it was silently ignored so size=large call sites rendered 378px
- Badge: add the 5 missing preset hues (pink, yellow, volcano, geekblue, lime) end to end (palette presetTag pairs, generator entries, tailwind tag-* ramps, badge variants); AA-checked text steps per antd's own ramp
- WorkflowTypeTag: all 13 hues now resolve to Badge variants; delete the var(--ant-*) inline-style fallback
Storybook is the component inventory, so every entity-ui surface belongs in it
regardless of whether it still imports antd.

- selection/: stories for UnifiedEntityPicker (list-popover, cascader,
  popover-cascader, breadcrumb, cascading) and EntitySelectorModal, seeded
  through the data seam with zod-validated workflow fixtures. The package was
  already antd-free; it was missing from the inventory, which is the gap
  this closes.
- parity gates: register every entity-ui story id (85) in vrt.mjs, including
  the previously unregistered VariantNameCell exports; data-seam showcases are
  declared NO_PAIR with a reason rather than silently skipped.
- a11y.mjs: audit 32 entity-ui stories, accept per-story ids on argv, wait on a
  VISIBLE ready selector (Storybook's hidden error overlay owns a <table>, so a
  selector list could pin on a hidden node and hang), fall back to the story
  root for showcases with no parity layout, and allow slot-less EXPECTED
  entries for token-inherited contrast.
- a11y fixes, all pixel-neutral (VRT confirms): name the label-less switches,
  time/date and combobox inputs, and icon-only buttons; drop button-only attrs
  from a span; unnest interactive controls in the multi-select trigger and the
  schedule builder; name the event-source popover; fix the option/row role
  parents in the picker variants.
- Editor: add an ariaLabel seam to the contenteditable. The outer Editor
  enumerates props explicitly, so it has to be threaded at both EditorInner
  call sites, and Lexical 0.46 takes aria-label (ariaLabel type-checks and is
  dropped). DiffView and the preset preview now pass a name.

Gates: a11y 0 violations across 32 stories (was 78 nodes); VRT passes across
all entity-ui stories; tsc clean on ui, entity-ui and storybook.
…/G2)

Protective snapshot taken while the swarm was interrupted mid-verification.
Not a reviewable commit: gates (VRT/a11y/tsc/lint) have not run on this tree
yet, and the chunk commits get regrouped before review.
Second protective snapshot: the swarm's post-snapshot VRT/a11y corrections,
captured after the machine crashed mid-verification. Gates still pending;
regrouped into reviewable chunk commits before review.
…mplateControl C)

DrillInView reaches zero antd imports. Protective snapshot; gates and commit
regrouping still pending.
Two harness defects surfaced by running it over ~180 stories:

- Showcase stories render plain markup that matches none of the layout ready
  selectors, so each one burned the full 30s timeout (times the retries).
  Wait on those selectors briefly, then fall back to the story root having
  rendered something visible.
- One browser cannot survive the whole sweep: memory climbs until Chromium
  dies, and every later page call then hangs on a dead connection instead of
  throwing, wedging the run at 0% CPU. Recycle the browser every 25 stories
  and relaunch once on a crash.
…f-antd

# Conflicts:
#	web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/AgentTemplateControl.tsx
#	web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/PiAutoApproveControl.tsx
#	web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/PiSettingsControl.tsx
…t suggestions

PiPermissionsControl arrived from main after the wave-2 sweep, so DrillInView
had drifted back to one antd import.

antd Select mode=tags maps to the shared ChipsInput, which commits on Enter
only — the semantic this control needs, since a rule body may contain a comma
(Bash(echo a,b:*)) and has to reach the runner whole.

ChipsInput gains the two things that migration needed:
- options, offered as native datalist completions (antd tags-mode options), so
  the call site does not have to stay on antd for its suggestions.
- a 4px input floor instead of 80px. antd's tags-mode search input is width-auto;
  the floor pushed the caret onto a second line as soon as chips filled the row.
An axe sweep over the entity-ui inventory reported ~600 violating nodes. They
collapse to a handful of root causes, so the fixes are in the primitives rather
than at the several hundred call sites. All pixel-neutral; VRT shows no new
>1% row.

- Slider: names now land on the thumb. The Root is an unroled span, so a call
  site passing aria-labelledby correctly (NumberSliderControl did) still left
  every slider unnamed to a screen reader.
- HeightCollapse: a collapsed body was aria-hidden around still-tabbable
  children, so keyboard focus could enter invisible content. inert was opt-in
  and almost nobody opted in; both now derive from one collapsed-shut flag.
- ConfigAccordionSection (and two rows with the same defect): the activating
  role/tabIndex moved onto the existing title group so it no longer wraps the
  extra slot's controls. No DOM node added or moved, which is what keeps it
  pixel-neutral.
- Editor: the contenteditable falls back to placeholder, then a generic name,
  so a new unlabeled editor cannot ship. Lexical takes standard aria-label.
- Select/Cascader triggers: role=combobox is not named from its contents, so
  the trigger needs an explicit name; call sites default to their placeholder.
- Doc links: 'Learn more' sat in body copy distinguished only by colour. A
  dotted underline is under the VRT threshold, so this cost no re-baseline.

Contrast is gated on the MEASURED COLOURS rather than per story: waiving 469
nodes by story would have had to name most of the inventory and would silently
have covered colours that are not inherited at all. Three categories, each
verified and separately actionable — muted text tokens, antd preset semantic
pairs, and white on hardcoded vendor brand colours. A colour in no list still
fails, which is how the three colours my first sample missed were caught.
The corrections are the ones a VRT number found and reading could not: the
Typography secondary token (26 sites were wrong across five wave-1 files, and
the pixel gate cannot see it outside a paired subject), font-size overrides
dropping a ramp's line-height, Segmented deriving its own height, and where an
accessible name has to land to actually apply.

Also updates the status table — DrillInView is done, and the package is down to
the two documented Form-engine residues.
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 56ba0357-f334-497c-8172-18a5ef639447

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.

@vercel

vercel Bot commented Aug 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview Aug 3, 2026 6:33pm

Request Review

…interface

Only type aliases get the implicit index signature, so an interface is not
assignable to the control's Record<string, unknown> value prop.

These five errors predate this commit. They were hidden by my own tsc filter,
which skipped oss/tailwind.config.ts for a long-standing TS2322 and took only
the first few lines. That config error is gone now (dropped with the blanket
as const in e83d297), so storybook type-checks clean unfiltered.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant