Skip to content

feat(apollo-wind): add ResourcePicker - #1244

Open
andreea-ene wants to merge 3 commits into
mainfrom
feat/resource-picker
Open

andreea-ene wants to merge 3 commits into
mainfrom
feat/resource-picker

Conversation

@andreea-ene

@andreea-ene andreea-ene commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Replaces #1210, which was opened from a fork so the required checks couldn't run.

Adds ResourcePicker, a field and popover for choosing one record from a grouped list.

The picker is generic over what it lists. A group is a heading with rows under it, and a row is an id, a label and an optional icon, so the same control serves Data Fabric entities, queues, storage buckets or anything else with that shape. The domain lives in the data a consumer passes, not in the component. Picking a person is the deliberate exception: people carry avatars and a resolved reference of their own, so they belong to a dedicated people picker.

Design decisions

Rows commit on click. One resource is one decision, so there is no Cancel and Select pair, which would add a second click to a choice that is already unambiguous. The footer's two slots hold the ways out of the picker instead, such as a link to create a new record. Passing them as slots keeps product routes out of the design system.

Selection is cyan, hover is neutral. The chosen row takes a tick, the brand tint (brand-subtle) and an accent label, and keeps them under the cursor. The neutral surface-overlay fill means cursor position and nothing else. surface-selected is not used for selection because it resolves to the same value as surface-hover in every theme, so the two states would be indistinguishable.

Ids must be non-empty and unique across groups, labels need not be. The same name can appear under two folders, so the id carries the path. An empty id is the picker's "no value", so a row with one is dropped, with a warning in development.

Structure

Built on Command and Popover, following VariablePicker, with the file layout FolderPicker uses: types.ts for the consumer-facing API and a components/ folder for the row, group header, footer and empty state. The empty state is its own component with its own test, since an empty picker and a search that matched nothing are different things and must not collapse into one message.

The search is Apollo's own CommandInput rather than a bespoke field.

Stories

Components/Core/Resource Picker: Default, WithDescriptions, CollapsedGroup, WithValue, NotClearable, Disabled, EmptyStates, ContentOnly.

Screenshots

Default, with footer links Rows with descriptions and a disabled row
Resource picker open on Data Fabric entities grouped by folder, with Add new entity and Open entities links in the footer Resource picker open on queues, each row showing a pending count, with Billing disputes disabled
Chosen row, with the hover clear control A group that opens collapsed, counts hidden
Resource picker with Aavi chosen on a cyan tint with a tick, and a clear control in the field Resource picker on storage buckets with the Archived group collapsed and no group counts

Selection in Future Light: the tint follows the theme's brand token.

Resource picker in the Future Light theme with Aavi chosen on a cyan tint and AviNew under the pointer on a neutral fill

Empty states: an empty picker and a search that matched nothing say different things.

Two panels: No entities yet for an empty list, and No results match zzz for a search with no match

Checks

Run locally:

Check Result
biome format pass, 382 files
biome check pass
tsc --noEmit pass
vitest run (resource-picker) 23 passed
npm run build pass

Note: src/components/forms/form-plugins.test.tsx fails 26 tests on main as well, unrelated to this branch.

🤖 Generated with Claude Code

Copilot AI balanced review requested due to automatic review settings September 30, 2026 13:02
@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Apollo Coded App preview deployments are ready.

Project Status Preview Updated (PT)
apollo-design Ready Preview · Logs Oct 15, 2026, 09:04:55 AM
apollo-docs Ready Preview · Logs Oct 15, 2026, 09:04:55 AM
apollo-landing Ready Preview · Logs Oct 15, 2026, 09:04:55 AM
apollo-vertex Ready Preview · Logs Oct 15, 2026, 09:04:55 AM

@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Dependency License Review

  • ✅ 1957 package(s) scanned
  • ✅ No license issues found
  • ⚠️ 2 package(s) excluded (see details below)
License distribution
License Packages
MIT 1721
ISC 91
Apache-2.0 57
BSD-3-Clause 28
BSD-2-Clause 23
BlueOak-1.0.0 8
MPL-2.0 4
CC0-1.0 4
MIT-0 3
MIT OR Apache-2.0 2
(MIT OR Apache-2.0) 2
Unlicense 2
LGPL-3.0-or-later 1
Python-2.0 1
CC-BY-4.0 1
(MPL-2.0 OR Apache-2.0) 1
Unknown 1
Artistic-2.0 1
(WTFPL OR MIT) 1
(BSD-2-Clause OR MIT OR Apache-2.0) 1
CC-BY-3.0 1
0BSD 1
(MIT OR CC0-1.0) 1
MIT AND ISC 1
Excluded packages
Package Version License Reason
@img/sharp-libvips-linux-x64 1.3.4 LGPL-3.0-or-later LGPL pre-built binary, not linked
khroma 2.1.0 Unknown MIT per GitHub repo, missing license field in package.json

This comment was marked as outdated.

@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Storybook visual diff

⚠️ Visual changes detected: 16 added (of 28 compared, 12 unchanged). View report

Baseline is the deployed main Storybook, so changes merged to main after this branch was last updated can also appear here. Logs

Updated (PT): Oct 20, 2026, 02:43:19 AM

@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

📊 Coverage + size by package

Per-package coverage and bundle size on this PR. New-line coverage = of the source lines this PR adds or changes, the % hit by tests.

Package Coverage New-line coverage Packed (gzip) Unpacked vs main
@uipath/apollo-core — — 42.02 MB 50.17 MB ±0
@uipath/apollo-react 51.7% — 8.01 MB 31.60 MB +126 B
@uipath/apollo-ui-icons — — 2.86 MB 6.97 MB ±0
@uipath/apollo-vertex — — — — —
@uipath/apollo-wind 79.5% 98.9% (182/184) 803.0 KB 4.64 MB +15.4 KB
@uipath/ap-chat 85.8% — 40.37 MB 45.58 MB ±0

"Coverage" is each package's own coverage.include scope (e.g. apollo-core instruments only scripts/). "Packed"/"Unpacked" come from npm pack --dry-run and only cover built packages — "—" means not measured this run (package not affected / not built). "vs main" is the packed (gzipped) delta against the last successful main build (the package-sizes artifact from the Release workflow); "—" there means no main baseline was available this run. The baseline is main's latest build, not this PR's exact merge-base, so it includes any drift since the branch diverged. Packages with no vitest config are omitted.

Copilot AI balanced review requested due to automatic review settings October 1, 2026 12:43
@andreea-ene
andreea-ene force-pushed the feat/resource-picker branch from c0e0590 to 847ee0c Compare October 1, 2026 12:43

This comment was marked as outdated.

@andreea-ene
andreea-ene marked this pull request as draft October 5, 2026 09:05
Copilot AI balanced review requested due to automatic review settings October 5, 2026 11:58
@andreea-ene
andreea-ene force-pushed the feat/resource-picker branch from 4a1d8a3 to aa0695e Compare October 5, 2026 12:03

This comment was marked as outdated.

Copilot AI balanced review requested due to automatic review settings October 5, 2026 12:04

This comment was marked as outdated.

Copilot AI balanced review requested due to automatic review settings October 6, 2026 09:59
@andreea-ene
andreea-ene force-pushed the feat/resource-picker branch from aa0695e to 22d7212 Compare October 6, 2026 09:59

This comment was marked as outdated.

Copilot AI balanced review requested due to automatic review settings October 6, 2026 10:47
@andreea-ene
andreea-ene force-pushed the feat/resource-picker branch from 22d7212 to a041670 Compare October 6, 2026 10:47

This comment was marked as outdated.

Copilot AI balanced review requested due to automatic review settings October 7, 2026 10:08
@andreea-ene
andreea-ene force-pushed the feat/resource-picker branch from c50fc4a to 65a222a Compare October 7, 2026 10:08

This comment was marked as outdated.

This comment was marked as outdated.

This comment was marked as outdated.

This comment was marked as outdated.

This comment was marked as outdated.

This comment was marked as outdated.

This comment was marked as outdated.

This comment was marked as outdated.

This comment was marked as outdated.

Copilot AI 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.

🟡 Changes recommended

Closing can remount visible content during animation, and all-disabled groups lack a keyboard collapse path.

2 open findings

🧠 Review effort: Balanced

Comment thread packages/apollo-wind/src/components/ui/resource-picker/resource-picker.tsx Outdated
Comment thread packages/apollo-wind/src/components/ui/resource-picker/resource-picker.tsx Outdated

Copilot AI 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.

🔵 Needs a closer look

The custom cmdk/Radix cursor, keyboard, shadow-DOM, and ARIA interactions warrant final browser and assistive-technology validation.

0 open findings

2 resolved since last review

🧠 Review effort: Balanced

Copilot AI 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.

🔵 Needs a closer look

The extensive custom cmdk/Radix focus and accessibility state handling warrants final human validation.

0 open findings

🧠 Review effort: Balanced

Copilot AI 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.

🔵 Needs a closer look

The new public control has intricate cmdk/Radix focus and keyboard behavior that warrants final human browser validation.

0 open findings

🧠 Review effort: Balanced

Copilot AI 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.

🟡 Changes recommended

An unresolved accessibility issue prevents an unmatched controlled value from being announced without an external label.

1 open finding

🧠 Review effort: Balanced

Comment thread packages/apollo-wind/src/components/ui/resource-picker/resource-picker.tsx Outdated

Copilot AI 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.

🟡 Changes recommended

Null-character command values can break collapsed-group navigation after server rendering and hydration.

1 open finding
1 resolved since last review

🧠 Review effort: Balanced

Comment thread packages/apollo-wind/src/components/ui/resource-picker/resource-picker.tsx Outdated

Copilot AI 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.

🟡 Changes recommended

Closed pickers can still commit during exit animation, and empty resource IDs conflict with the no-selection sentinel.

3 open findings

🧠 Review effort: Balanced

Comment thread packages/apollo-wind/src/components/ui/resource-picker/types.ts Outdated

Copilot AI 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.

🔵 Needs a closer look

The custom cmdk cursor management and accessibility behavior warrant final human browser and assistive-technology verification.

2 open findings
1 resolved since last review

🧠 Review effort: Balanced

Copilot AI 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.

🔵 Needs a closer look

Custom cursor restoration, focus handling, and shadow-root interactions warrant browser-level human validation despite broad regression coverage.

2 open findings

🧠 Review effort: Balanced

Copilot AI 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.

🔵 Needs a closer look

Custom cursor restoration and popover focus interactions warrant human browser validation before approval.

2 open issues

Review effort: Balanced

Copilot AI 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.

🟡 Changes recommended

Footer keyboard handling blocks Tab propagation, bypassing the host’s focus-wrapping behavior.

3 open issues

Review effort: Balanced

Copilot AI 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.

🔵 Needs a closer look

Footer keyboard handling blocks Tab propagation needed for the hosting popover’s focus wrapping.

3 open issues
1 previously missed issue

In code that hasn't changed since last review

Medium severity Allow Tab to bubble for popover focus wrapping

packages/​apollo-wind/​src/​components/​ui/​resource-picker/​components/​resource-picker-footer.tsx:29

This also stops Tab from reaching the hosting Radix focus scope. Tabbing from the final footer action therefore bypasses the popover's focus wrap and can move focus outside and dismiss it instead of returning to the search. Allow Tab to bubble alongside Escape, while keeping the list-navigation and activation keys isolated. Add a regression test that tabs from the final footer action back to the search.

Review effort: Balanced

Copilot AI 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.

🟢 Approval recommended

The implementation and regression coverage address the reviewed behavior, with no unresolved blocking issues identified.

No open issues 🎉

3 resolved since last review

Review effort: Balanced

andreea-ene and others added 3 commits October 20, 2026 12:35
A field and popover for choosing one record from a grouped list. The
component is generic over what it lists: a group is a heading with rows
under it, and a row is an id, a label and an optional icon, so the same
control serves Data Fabric entities, queues, storage buckets or anything
else with that shape. The domain lives in the data a consumer passes.

Rows commit on click, so there is no Cancel and Select pair: one
resource is one decision. The footer's two slots hold the ways out of
the picker instead, which keeps product routes out of the component.

Built on Command and Popover, following VariablePicker, with the file
layout FolderPicker uses. Ids must be unique across groups; labels need
not be, since the same name can appear under two folders.

Selection is carried by a tick and a brand tint, kept apart from the
neutral fill that marks the cursor: `surface-selected` and
`surface-hover` resolve to the same value in every theme, so a selected
fill built on them would be indistinguishable from the row under the
pointer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ct empty row ids

Rows stay mounted while the popover animates out, so a click or Enter
could still commit after the picker was closed or disabled. Commits now
require the effective open state.

An empty id is the picker's "no value", so a row with one could never be
told apart from no selection. Such rows are dropped with a dev warning,
and an empty value no longer matches a row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The footer stopped every key but Escape, so Tab from its last action
never reached the popover's focus scope. Focus could leave the
non-modal popover and dismiss it instead of looping back to the
search. Tab now propagates alongside Escape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI 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.

🟡 Changes recommended

Empty-state detection counts discarded empty-ID rows, incorrectly reporting a search miss when no usable resources exist.

1 open issue

Review effort: Balanced

const filtering = query.trim().length > 0;
// With no rows at all, clearing the search could not reveal anything, so
// that is the empty state whatever the query, not a search miss.
const hasRows = groups.some((group) => group.items.length > 0);

This branch was successfully deployed

4 active deployments
preview/apollo-design — 1198f7ca Deployed Oct 20, 2026 by github-actions[bot]
preview/apollo-landing — 1198f7ca Deployed Oct 20, 2026 by github-actions[bot]
preview/apollo-vertex — 1198f7ca Deployed Oct 20, 2026 by github-actions[bot]
preview/apollo-docs — 1198f7ca Deployed Oct 20, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pkg:apollo-wind size:XXL 1,000+ changed lines.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants