Support preselected examples in create listing modal#4283
Conversation
|
@codex review |
Preview deployments |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 888f041ed7
ℹ️ 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".
| display: inline-flex; | ||
| align-items: center; | ||
| } | ||
| .selected-example-atom :deep([data-test-card-format='atom']) { |
There was a problem hiding this comment.
Replace test-only selector in runtime CSS
The new style rule uses data-test-* as a runtime selector, but AGENTS.md explicitly says these attributes are stripped from production builds and must not be used for app behavior/styling. In production this selector will never match, so the selected-example atom layout can regress (for example, chips not shrinking as intended). Please switch this to a production-safe hook (class or non-test data-*) instead.
Useful? React with 👍 / 👎.
Host Test Results 1 files ± 0 1 suites ±0 4h 24m 1s ⏱️ + 2h 12m 2s For more details on these errors, see this check. Results for commit b873a46. ± Comparison against base commit bbc3db5. This pull request removes 2 and adds 4 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e9bf82d81c
ℹ️ 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".
| .filter((ref) => !ref.negated) | ||
| .map((ref) => ref.ref) | ||
| .filter(isResolvedCodeRef) | ||
| .map((ref) => ref.name), |
There was a problem hiding this comment.
Use display-name keys for default type preselection
defaultSelectedTypeNames is populated from ref.name (the exported class name), but the picker options are keyed by card type display labels (card.cardType / cardTypeDisplayName). When those differ (for example BlogPost vs Blog Post), the new preselection logic never matches, so the chooser opens on “Any Type” instead of the base filter’s type and shows unrelated results.
Useful? React with 👍 / 👎.
| let instances = await this.store.search( | ||
| { filter: { type: codeRef } }, | ||
| targetRealms, | ||
| ); |
There was a problem hiding this comment.
Handle preselection search errors gracefully
This newly added store.search runs before opening the modal, and it is awaited without error handling. store.search throws on failed search responses, so if the selected declaration type is not indexed yet (for example newly edited/unsaved modules or stale index state), the action rejects and the Create Listing modal never opens. We should catch this lookup failure and continue with empty openCardIds so listing creation still works.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: aeeddfe7de
ℹ️ 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".
There was a problem hiding this comment.
Pull request overview
Adds support for preselecting and managing example cards when opening the “Create Listing” modal, including multi-select preselection and hiding examples for field definitions.
Changes:
- Extended the card chooser API/state to support preselecting multiple cards and optionally preselecting the consuming realm.
- Reworked the Create Listing modal examples UI to render selected examples as prerendered atom templates with remove controls and an “Add Examples” flow.
- Added logic to classify declarations as
cardvsfieldto conditionally hide the examples row.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/runtime-common/index.ts | Extends chooseCard option types to support preselected URLs and consuming-realm preselection. |
| packages/host/app/components/card-catalog/modal.gts | Implements multi-card preselection and passes consuming-realm preselection through to search UI. |
| packages/host/app/components/card-search/panel.gts | Adds consuming realm inputs; initializes realm selection + focused section for search results. |
| packages/host/app/components/card-search/search-content.gts | Allows initial focused section to be set from the parent panel. |
| packages/host/app/components/operator-mode/create-listing-modal.gts | Replaces instance picker with prerendered selected-example atoms + remove + “Add Examples” chooser. |
| packages/host/app/components/operator-mode/detail-panel.gts | Adds a fallback search to preselect an instance when launching listing creation from a module. |
| packages/host/app/commands/open-create-listing-modal.ts | Determines declarationKind (card vs field) to control examples UI visibility. |
| packages/host/app/services/operator-mode-state-service.ts | Extends modal payload with declarationKind. |
| packages/host/tests/integration/components/create-listing-modal-test.gts | Updates integration tests for the new examples UI and field-definition behavior. |
| packages/host/tests/integration/commands/open-create-listing-modal-test.gts | Adds coverage for declarationKind classification in modal payload. |
| packages/host/tests/acceptance/code-submode/inspector-test.ts | Updates acceptance assertions to match atom-based selected example rendering. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let consumingRealm = this.args.consumingRealm; | ||
| if (!this.shouldPreselectConsumingRealm || !consumingRealm) { | ||
| return []; | ||
| } | ||
| let realmURL = consumingRealm.href; | ||
| let info = this.realm.info(realmURL); | ||
| let label = info?.name ?? realmURL; | ||
| let icon = info?.iconURL ?? undefined; | ||
| return [{ id: realmURL, icon, label, type: 'option' }]; |
There was a problem hiding this comment.
selectedRealms is initialized with a newly constructed PickerOption when preselectConsumingRealm is enabled. The Boxel Picker (used by RealmPicker) determines selection via object identity (includes(selected, option)), so this preselected option will not match the options instances created inside RealmPicker. This can cause the consuming realm to not appear selected in the dropdown and can lead to toggle/deselect issues (duplicates) when interacting with the picker. Consider preselecting by realm URL and mapping to the actual option objects used by the picker (or providing an id-based matcher) so selected references come from the current @options array.
| let consumingRealm = this.args.consumingRealm; | |
| if (!this.shouldPreselectConsumingRealm || !consumingRealm) { | |
| return []; | |
| } | |
| let realmURL = consumingRealm.href; | |
| let info = this.realm.info(realmURL); | |
| let label = info?.name ?? realmURL; | |
| let icon = info?.iconURL ?? undefined; | |
| return [{ id: realmURL, icon, label, type: 'option' }]; | |
| // Do not construct a new PickerOption instance here, since the Boxel Picker | |
| // determines selection by object identity. The Picker should own the | |
| // selection instances based on its own @options array. | |
| return []; |
| .selected-example-atom | ||
| :deep(.field-component-card.atom-format.display-container-true) { | ||
| min-width: 0; | ||
| } | ||
| .selected-example-atom | ||
| :deep(.field-component-card.atom-format.display-container-true) { | ||
| padding-right: calc( | ||
| var(--boxel-sp-xs) + var(--boxel-icon-sm) + var(--boxel-sp-6xs) | ||
| ); | ||
| } |
There was a problem hiding this comment.
The .selected-example-atom :deep(.field-component-card.atom-format.display-container-true) selector is duplicated in two consecutive blocks; this can be consolidated into a single rule to avoid drift and make future styling changes easier.
| if (!openCardIds.length) { | ||
| let targetRealms = [targetRealm]; | ||
| let firstInstanceId: string | undefined; | ||
| try { | ||
| let instances = await this.store.search( | ||
| { filter: { type: codeRef } }, | ||
| targetRealms, | ||
| ); | ||
| firstInstanceId = instances.find((c) => c.id)?.id; | ||
| } catch (error) { | ||
| console.warn( | ||
| 'Failed to prefetch instances for create listing modal', | ||
| error, | ||
| ); | ||
| } | ||
| openCardIds = firstInstanceId ? [firstInstanceId] : []; | ||
| } |
There was a problem hiding this comment.
This new fallback prefetch (await this.store.search(...)) runs before OpenCreateListingModalCommand.execute(), which means opening the Create Listing modal from a module definition now blocks on a network/search request. That’s a user-visible latency regression compared to opening the modal immediately and loading examples asynchronously. Consider opening the modal right away (with no or existing openCardIds) and then populating a default example in the modal once the search resolves, or otherwise running the prefetch in the background so the modal doesn’t wait on it.
linear: https://linear.app/cardstack/issue/CS-10547/support-preselected-examples-in-create-listing-modal
Summary:
Add support for pre-selecting example cards when opening the create listing modal using ModalCardChooser. Display the atom template of selected example instances, preselect the realm and type pickers based on the consuming realm and card type filter, and show only target realm prerendered data.
Key changes:
Demo:
Screen.Recording.2026-03-31.at.4.15.42.PM.mov