Skip to content

feat: Add autocomplete, slider, collapsible, and spinner UI components#831

Merged
kingston merged 11 commits into
mainfrom
kingston/component-fixes
Mar 15, 2026
Merged

feat: Add autocomplete, slider, collapsible, and spinner UI components#831
kingston merged 11 commits into
mainfrom
kingston/component-fixes

Conversation

@kingston

@kingston kingston commented Mar 15, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features

    • Added Autocomplete, Collapsible, Slider, and Spinner UI components with Storybook examples and new public templates/re-exports.
    • Autocomplete exposes a full set of input, list, group, and status subcomponents and a filter hook.
  • Bug Fixes

    • Prevent duplicate insertion of codegen workaround.
    • Multi-select inputs hide placeholder when chips are present.
  • Chores

    • Added validator support for JSON fields and a new default "Type to search..." prompt.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Mar 15, 2026

Copy link
Copy Markdown

Deploying baseplate-storybook with  Cloudflare Pages  Cloudflare Pages

Latest commit: 719beac
Status: ✅  Deploy successful!
Preview URL: https://9b70334d.baseplate-storybook.pages.dev
Branch Preview URL: https://kingston-component-fixes.baseplate-storybook.pages.dev

View logs

@changeset-bot

changeset-bot Bot commented Mar 15, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b67d32e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 23 packages
Name Type
@baseplate-dev/react-generators Patch
@baseplate-dev/ui-components Patch
@baseplate-dev/project-builder-server Patch
@baseplate-dev/plugin-auth Patch
@baseplate-dev/plugin-email Patch
@baseplate-dev/plugin-observability Patch
@baseplate-dev/plugin-storage Patch
@baseplate-dev/project-builder-lib Patch
@baseplate-dev/project-builder-web Patch
@baseplate-dev/plugin-payments Patch
@baseplate-dev/plugin-queue Patch
@baseplate-dev/plugin-rate-limit Patch
@baseplate-dev/create-project Patch
@baseplate-dev/project-builder-cli Patch
@baseplate-dev/project-builder-common Patch
@baseplate-dev/project-builder-dev Patch
@baseplate-dev/project-builder-test Patch
@baseplate-dev/code-morph Patch
@baseplate-dev/core-generators Patch
@baseplate-dev/fastify-generators Patch
@baseplate-dev/sync Patch
@baseplate-dev/tools Patch
@baseplate-dev/utils Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Mar 15, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@kingston has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 13 minutes and 20 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e95013ef-a4b8-4a39-beea-1d141f31142d

📥 Commits

Reviewing files that changed from the base of the PR and between 719beac and b67d32e.

⛔ Files ignored due to path filters (3)
  • examples/blog-with-auth/apps/admin/baseplate/generated/src/components/ui/slider.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-better-auth/apps/admin/baseplate/generated/src/components/ui/slider.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-better-auth/apps/web/baseplate/generated/src/components/ui/slider.tsx is excluded by !**/generated/**, !**/generated/**
📒 Files selected for processing (4)
  • examples/blog-with-auth/apps/admin/src/components/ui/slider.tsx
  • examples/todo-with-better-auth/apps/admin/src/components/ui/slider.tsx
  • examples/todo-with-better-auth/apps/web/src/components/ui/slider.tsx
  • packages/react-generators/src/generators/core/react-components/templates/components/ui/slider.tsx
📝 Walkthrough

Walkthrough

Adds four new UI components (autocomplete, collapsible, slider, spinner) across generator templates, ui-components, and example apps; refactors async combobox state and pre-search messaging; makes codegen hooks idempotent to avoid duplicate TypeScript guards; updates an observability import mapping; adds a model 'json' validator and a changeset.

Changes

Cohort / File(s) Summary
Autocomplete (templates, package, ui, examples)
packages/react-generators/.../templates/components/ui/autocomplete.tsx, packages/react-generators/.../extractor.json, packages/ui-components/src/components/ui/autocomplete/autocomplete.tsx, packages/ui-components/src/components/ui/autocomplete/*.stories.tsx, examples/*/src/components/ui/autocomplete.tsx
Adds a comprehensive Autocomplete implementation with ~15 public exports (root, input, content, list, item, group, label, collection, empty, status, separator, trigger, clear, value, useFilter), storybook stories, and registers exports in extractor and example mappings.
Collapsible / Slider / Spinner (templates, package, ui, examples)
packages/react-generators/.../templates/components/ui/collapsible.tsx, .../slider.tsx, .../spinner.tsx, packages/ui-components/src/components/ui/{collapsible,slider,spinner}/*, examples/*/src/components/ui/{collapsible,slider,spinner}.tsx
Adds Collapsible wrappers (root/trigger/content), a Slider component (multi-thumb support, computed values), and a Spinner component; exports and registers these in generators, ui index, and examples.
Component registration & example mappings
packages/react-generators/.../extractor.json, examples/*/baseplate/file-id-map.json, examples/*/src/components/ui/.templates-info.json
Registers new components in extractor.json and adds file-id / template-info mappings for autocomplete, collapsible, slider, and spinner across example projects.
UI index & strings
packages/ui-components/src/components/ui/index.ts, packages/ui-components/src/constants/strings.ts
Re-exports autocomplete, slider, spinner from the UI index and adds comboboxTypeToSearch default string.
Async Combobox refactor
packages/ui-components/src/components/ui/async-combobox-field/async-combobox-field.tsx
Replaces separate useState hooks with a reducer (searchReducer); adds typeToSearchText prop and hasSearched tracking to show a pre-search message and centralizes search lifecycle actions.
Multi-Combobox placeholder UX
packages/ui-components/.../multi-combobox-field/*.tsx, examples/*/src/components/ui/multi-combobox-field.tsx
Hide placeholder in ComboboxChipsInput when values are selected (placeholder becomes empty string); storybook control updated.
Codegen idempotency fixes
packages/react-generators/.../templates/package/codegen.ts, examples/*/codegen.ts
Make afterAllFileWrite append of the _Unused / no-unused-locals workaround conditional (grep check) to avoid duplicate appends.
Model validator
packages/project-builder-lib/src/definition/model/model-field-utils.ts
Add support for modelField.type === 'json' returning a Zod validator unknown().
Observability import mapping
plugins/plugin-observability/.../apollo-sentry/extractor.json
Change packagePathSpecifier for reactSentryImportsProvider to point to plugin-observability path instead of react-generators.
Changeset
.changeset/add-autocomplete-slider-collapsible-spinner.md
Add changeset noting patch releases and added UI components.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.59% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding four new UI components (autocomplete, slider, collapsible, spinner) to the codebase.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch kingston/component-fixes
📝 Coding Plan
  • Generate coding plan for human review comments

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 and usage tips.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 17

🧹 Nitpick comments (5)
examples/todo-with-better-auth/apps/web/src/components/ui/collapsible.tsx (1)

14-28: Add JSDoc comments to exported functions.

Same as the admin counterpart: CollapsibleTrigger and CollapsibleContent are exported but lack JSDoc documentation.

📝 Proposed JSDoc additions
+/**
+ * A button that toggles the collapsible panel.
+ */
 function CollapsibleTrigger({
   ...props
 }: CollapsiblePrimitive.Trigger.Props): React.ReactElement {
   return (
     <CollapsiblePrimitive.Trigger data-slot="collapsible-trigger" {...props} />
   );
 }

+/**
+ * The content panel that expands/collapses.
+ */
 function CollapsibleContent({
   ...props
 }: CollapsiblePrimitive.Panel.Props): React.ReactElement {
   return (
     <CollapsiblePrimitive.Panel data-slot="collapsible-content" {...props} />
   );
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/todo-with-better-auth/apps/web/src/components/ui/collapsible.tsx`
around lines 14 - 28, Add JSDoc blocks above the exported functions
CollapsibleTrigger and CollapsibleContent describing their purpose (trigger and
panel wrappers for the Collapsible primitive), document the props parameter type
(CollapsiblePrimitive.Trigger.Props and CollapsiblePrimitive.Panel.Props
respectively), and document the return type (React.ReactElement). Keep the JSDoc
concise and include any data-slot details (data-slot="collapsible-trigger" and
data-slot="collapsible-content") so consumers know the rendered DOM attributes.
examples/todo-with-better-auth/apps/admin/src/components/ui/collapsible.tsx (1)

14-28: Add JSDoc comments to exported functions.

CollapsibleTrigger and CollapsibleContent are exported but lack JSDoc documentation. As per coding guidelines for this directory, all exported functions should have JSDoc comments.

📝 Proposed JSDoc additions
+/**
+ * A button that toggles the collapsible panel.
+ */
 function CollapsibleTrigger({
   ...props
 }: CollapsiblePrimitive.Trigger.Props): React.ReactElement {
   return (
     <CollapsiblePrimitive.Trigger data-slot="collapsible-trigger" {...props} />
   );
 }

+/**
+ * The content panel that expands/collapses.
+ */
 function CollapsibleContent({
   ...props
 }: CollapsiblePrimitive.Panel.Props): React.ReactElement {
   return (
     <CollapsiblePrimitive.Panel data-slot="collapsible-content" {...props} />
   );
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/todo-with-better-auth/apps/admin/src/components/ui/collapsible.tsx`
around lines 14 - 28, Add JSDoc comments for the exported React components
CollapsibleTrigger and CollapsibleContent: above each function
(CollapsibleTrigger and CollapsibleContent) include a brief description of the
component, document the props parameter (using `@param` props - describe that it
spreads CollapsiblePrimitive.Trigger.Props or CollapsiblePrimitive.Panel.Props
respectively), and add an `@returns` line describing the returned
React.ReactElement; keep the comments concise and follow existing JSDoc style in
the project.
examples/todo-with-better-auth/apps/web/src/components/ui/autocomplete.tsx (1)

29-289: Document the exported wrappers and hook.

AutocompleteValue, AutocompleteTrigger, AutocompleteClear, AutocompleteInput, AutocompleteContent, AutocompleteList, AutocompleteItem, AutocompleteGroup, AutocompleteLabel, AutocompleteCollection, AutocompleteEmpty, AutocompleteStatus, AutocompleteSeparator, and useAutocompleteFilter are exported public API, but only Autocomplete is documented right now.

As per coding guidelines "Add JSDoc comments to all exported functions, interfaces, and classes documenting the function/type, parameters, return value, and all fields"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/todo-with-better-auth/apps/web/src/components/ui/autocomplete.tsx`
around lines 29 - 289, Add JSDoc comments for each exported wrapper and hook
(AutocompleteValue, AutocompleteTrigger, AutocompleteClear, AutocompleteInput,
AutocompleteContent, AutocompleteList, AutocompleteItem, AutocompleteGroup,
AutocompleteLabel, AutocompleteCollection, AutocompleteEmpty,
AutocompleteStatus, AutocompleteSeparator, and useAutocompleteFilter) describing
what the component/hook does, its props/parameters (including optional props
like showTrigger/showClear/showSpinner for AutocompleteInput), and the return
value (React.ReactElement or the hook type); place the JSDoc immediately above
each function or exported constant, include param tags for props and a returns
tag, and ensure descriptions follow the project's JSDoc style so these exported
APIs are fully documented.
examples/todo-with-better-auth/apps/admin/src/components/ui/autocomplete.tsx (1)

29-289: Document the exported wrappers and hook.

AutocompleteValue, AutocompleteTrigger, AutocompleteClear, AutocompleteInput, AutocompleteContent, AutocompleteList, AutocompleteItem, AutocompleteGroup, AutocompleteLabel, AutocompleteCollection, AutocompleteEmpty, AutocompleteStatus, AutocompleteSeparator, and useAutocompleteFilter are exported public API, but only Autocomplete is documented right now.

As per coding guidelines "Add JSDoc comments to all exported functions, interfaces, and classes documenting the function/type, parameters, return value, and all fields"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/todo-with-better-auth/apps/admin/src/components/ui/autocomplete.tsx`
around lines 29 - 289, Add JSDoc comments for every exported wrapper and hook
(AutocompleteValue, AutocompleteTrigger, AutocompleteClear, AutocompleteInput,
AutocompleteContent, AutocompleteList, AutocompleteItem, AutocompleteGroup,
AutocompleteLabel, AutocompleteCollection, AutocompleteEmpty,
AutocompleteStatus, AutocompleteSeparator, and useAutocompleteFilter)
documenting purpose, parameters (props and any special props like
showTrigger/showClear/showSpinner for AutocompleteInput), and return value
(React.ReactElement or the hook type); place the JSDoc immediately above each
function or exported const, describe what the component does, detail important
props (including defaults like disabled, side/align/sideOffset for
AutocompleteContent), and for useAutocompleteFilter describe input and output
types and behavior.
examples/blog-with-auth/apps/admin/src/components/ui/autocomplete.tsx (1)

29-289: Document the exported wrappers and hook.

AutocompleteValue, AutocompleteTrigger, AutocompleteClear, AutocompleteInput, AutocompleteContent, AutocompleteList, AutocompleteItem, AutocompleteGroup, AutocompleteLabel, AutocompleteCollection, AutocompleteEmpty, AutocompleteStatus, AutocompleteSeparator, and useAutocompleteFilter are exported public API, but only Autocomplete is documented right now.

As per coding guidelines "Add JSDoc documentation to all exported functions, interfaces, and classes, documenting the entity, its parameters, return value, and all fields."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/blog-with-auth/apps/admin/src/components/ui/autocomplete.tsx` around
lines 29 - 289, Add JSDoc comments for each exported wrapper and hook
(AutocompleteValue, AutocompleteTrigger, AutocompleteClear, AutocompleteInput,
AutocompleteContent, AutocompleteList, AutocompleteItem, AutocompleteGroup,
AutocompleteLabel, AutocompleteCollection, AutocompleteEmpty,
AutocompleteStatus, AutocompleteSeparator, and useAutocompleteFilter) describing
the purpose, parameters (props and any special flags like
showTrigger/showClear/showSpinner in AutocompleteInput), return type
(React.ReactElement or appropriate type for the hook), and any noteworthy
behavior or slot/data attributes; place the JSDoc immediately above each
function or hook definition and follow the project's JSDoc style (include
`@param/`@returns and mention exported nature).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@examples/blog-with-auth/apps/admin/src/components/ui/autocomplete.tsx`:
- Around line 8-16: Update the import specifiers to include .js extensions so
they are ESM-safe: change imports of the utility and local components (symbols:
cn, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, Spinner) to
use '@src/utils/cn.js', './input-group.js', and './spinner.js' respectively;
keep the imported symbol names unchanged.

In `@examples/blog-with-auth/apps/admin/src/components/ui/collapsible.tsx`:
- Around line 14-28: Add JSDoc comments above the exported wrapper components
CollapsibleTrigger and CollapsibleContent describing their purpose as simple
wrappers around the underlying primitives, document the props parameter type
(CollapsiblePrimitive.Trigger.Props for CollapsibleTrigger and
CollapsiblePrimitive.Panel.Props for CollapsibleContent), list any notable
attributes (e.g. data-slot values "collapsible-trigger" and
"collapsible-content"), and state the return type (React.ReactElement). Mirror
the style and fields used in the existing Collapsible documentation so each
exported function has API docs covering description, `@param` props, and `@returns`.

In `@examples/blog-with-auth/apps/admin/src/components/ui/slider.tsx`:
- Line 6: Update the local alias import to include the .js extension: change the
import of the utility symbol `cn` from `@src/utils/cn` to `@src/utils/cn.js` in
the `slider.tsx` component so it follows the project's import-resolution
convention; ensure the import statement using `cn` (the named import in this
file) is updated accordingly.

In `@examples/blog-with-auth/apps/admin/src/components/ui/spinner.tsx`:
- Line 3: Update the internal alias import in spinner.tsx to include the
explicit .js extension: change the import that references '@src/utils/cn' so it
points to '@src/utils/cn.js' to comply with the repository rule that
examples/blog-with-auth/**/*.{ts,tsx,js,jsx} must use .js extensions in import
statements; locate the import at the top of the file (the line importing cn) and
modify only the module specifier to add the .js suffix.
- Around line 5-22: Add a JSDoc comment above the exported Spinner function
describing its purpose, the props it accepts, and any accessibility behavior;
specifically document the Spinner component (function Spinner) and its props
type React.ComponentProps<'div'>, mention that it returns a React.ReactElement,
and note the role="status" and aria-label="Loading" usage for screen readers.
Ensure the JSDoc is placed immediately above the Spinner declaration and uses
standard tags like `@param` and `@returns` so the linter for
examples/blog-with-auth/**/*.{ts,tsx} recognizes the exported function as
documented.

In
`@examples/todo-with-better-auth/apps/admin/src/components/ui/autocomplete.tsx`:
- Around line 8-16: The imports in this file use extensionless specifiers which
are not ESM-safe; update the internal imports to include the .js extension
(e.g., change imports for the cn utility and the components referenced as
InputGroup/InputGroupAddon/InputGroupButton/InputGroupInput and Spinner) so the
statements import from '@src/utils/cn.js', './input-group.js', and
'./spinner.js' respectively to match the app's ESM resolution rules.

In `@examples/todo-with-better-auth/apps/admin/src/components/ui/slider.tsx`:
- Line 6: Update the local alias import to include the .js extension: change the
import of the utility symbol "cn" from '@src/utils/cn' to '@src/utils/cn.js' in
the slider component so it follows the project's rule that examples use .js
extensions in import statements.

In `@examples/todo-with-better-auth/apps/admin/src/components/ui/spinner.tsx`:
- Around line 5-22: Add a JSDoc block above the exported Spinner component
describing what it renders and its intended use, documenting the props parameter
and return type; mention that it accepts standard div props
(React.ComponentProps<'div'>) and that it returns a React.ReactElement used to
indicate loading, include `@param` {React.ComponentProps<'div'>} props and
`@returns` {React.ReactElement} tags and a brief one-line description so the
exported Spinner symbol is properly documented.
- Line 3: Update the internal import in spinner.tsx to use the .js extension for
the cn utility import: locate the import statement referencing cn (import { cn }
from '@src/utils/cn') and change it to import from '@src/utils/cn.js' so it
follows the repository rule requiring .js extensions for internal imports in
examples.

In `@examples/todo-with-better-auth/apps/web/src/components/ui/autocomplete.tsx`:
- Around line 8-16: Update the three internal import specifiers to include the
.js extension so they are ESM-safe: change the import for cn (referenced as cn),
the import that provides InputGroup, InputGroupAddon, InputGroupButton,
InputGroupInput (referenced by those symbols), and the Spinner import
(referenced as Spinner) to use '@src/utils/cn.js', './input-group.js', and
'./spinner.js' respectively; keep the imported symbol names unchanged.

In `@examples/todo-with-better-auth/apps/web/src/components/ui/slider.tsx`:
- Around line 21-29: The _values computation in slider.tsx currently only
handles array cases and falls back to [min, max], causing two thumbs when value
or defaultValue are single numbers; update the React.useMemo for _values to
detect number (or non-array) single-value cases and return [value as number] or
[defaultValue as number] respectively (e.g. check Array.isArray(value) first,
then typeof value === 'number' (or !Array.isArray && value != null) to wrap into
a one-element array), otherwise fall back to [min, max]; adjust dependencies
remain [value, defaultValue, min, max].

In `@examples/todo-with-better-auth/apps/web/src/components/ui/spinner.tsx`:
- Around line 5-22: Exported component Spinner lacks JSDoc; add a JSDoc block
above the Spinner function describing its purpose (a simple loading spinner),
document parameters (props: React.ComponentProps<'div'> including className and
any spread props) and the return value (React.ReactElement), and mention any
accessibility attributes (role and aria-label) used; reference the Spinner
function name and the props signature so the comment is placed immediately above
function Spinner({ className, ...props }: React.ComponentProps<'div'>):
React.ReactElement.
- Line 3: Update the local alias import to include the .js extension for
consistency: change the import of the cn utility (the line importing cn from
'@src/utils/cn') to import from '@src/utils/cn.js' so the Spinner component
follows the app's rule of always using .js extensions in import statements.

In
`@packages/react-generators/src/generators/core/react-components/templates/components/ui/slider.tsx`:
- Around line 22-30: The _values memo currently treats only arrays as valid
inputs so when value or defaultValue is a single number it falls back to [min,
max] and renders two thumbs; update the logic in the React.useMemo that computes
_values to detect numeric scalars for value and defaultValue and wrap them into
a single-element array (e.g., treat typeof value === "number" and typeof
defaultValue === "number"), preserving existing behavior for arrays and the
[min, max] fallback so Slider renders one <Slider.Thumb> per numeric value.

In
`@packages/ui-components/src/components/ui/async-combobox-field/async-combobox-field.tsx`:
- Around line 294-299: When the popover closes in onOpenChangeComplete you
currently dispatch the 'reset' action but don't stop any pending debounce timers
or in-flight loads, so late searchStarted/searchSucceeded updates can repopulate
options; update the close branch of onOpenChangeComplete to also clear the
debounce timer (e.g. debounceTimerRef.current) and abort any in-flight request
(e.g. currentAbortControllerRef.current.abort()) or bump a search token
reference so stale results are ignored, and ensure the search flow
(loadOptions/searchStarted/searchSucceeded) checks that token or the abort state
before dispatching results so canceled searches cannot overwrite the reset
state.

In
`@packages/ui-components/src/components/ui/autocomplete/autocomplete.stories.tsx`:
- Around line 169-193: The handler in onValueChange leaves previous
searchResults visible until the new async search resolves; update the
onValueChange logic (the function that calls setSearchValue, creates controller,
uses abortControllerRef and startTransition) to immediately clear previous
results and reset error when a new non-empty query is issued — i.e., call
setSearchResults([]) and setError(null) right after creating/aborting the
AbortController and before starting the async startTransition/searchCities call
so the UI doesn't render stale results while the new request is pending.

In `@packages/ui-components/src/components/ui/autocomplete/autocomplete.tsx`:
- Around line 54-64: The Autocomplete components allow callers to override the
fixed render prop because {...props} is spread after the fixed render prop in
AutocompleteClear (AutocompletePrimitive.Clear) and the corresponding
AutocompleteInput (AutocompletePrimitive.Input); to fix, prevent render from
being overridden by either removing render from the exposed prop type or by
spreading {...props} before setting the fixed render prop so the component
always supplies the InputGroupButton (for AutocompleteClear) and InputGroupInput
(for AutocompleteInput); update AutocompleteClear, AutocompletePrimitive.Clear
usage and AutocompleteInput/AutocompletePrimitive.Input usage accordingly to
ensure render cannot be replaced.

---

Nitpick comments:
In `@examples/blog-with-auth/apps/admin/src/components/ui/autocomplete.tsx`:
- Around line 29-289: Add JSDoc comments for each exported wrapper and hook
(AutocompleteValue, AutocompleteTrigger, AutocompleteClear, AutocompleteInput,
AutocompleteContent, AutocompleteList, AutocompleteItem, AutocompleteGroup,
AutocompleteLabel, AutocompleteCollection, AutocompleteEmpty,
AutocompleteStatus, AutocompleteSeparator, and useAutocompleteFilter) describing
the purpose, parameters (props and any special flags like
showTrigger/showClear/showSpinner in AutocompleteInput), return type
(React.ReactElement or appropriate type for the hook), and any noteworthy
behavior or slot/data attributes; place the JSDoc immediately above each
function or hook definition and follow the project's JSDoc style (include
`@param/`@returns and mention exported nature).

In
`@examples/todo-with-better-auth/apps/admin/src/components/ui/autocomplete.tsx`:
- Around line 29-289: Add JSDoc comments for every exported wrapper and hook
(AutocompleteValue, AutocompleteTrigger, AutocompleteClear, AutocompleteInput,
AutocompleteContent, AutocompleteList, AutocompleteItem, AutocompleteGroup,
AutocompleteLabel, AutocompleteCollection, AutocompleteEmpty,
AutocompleteStatus, AutocompleteSeparator, and useAutocompleteFilter)
documenting purpose, parameters (props and any special props like
showTrigger/showClear/showSpinner for AutocompleteInput), and return value
(React.ReactElement or the hook type); place the JSDoc immediately above each
function or exported const, describe what the component does, detail important
props (including defaults like disabled, side/align/sideOffset for
AutocompleteContent), and for useAutocompleteFilter describe input and output
types and behavior.

In `@examples/todo-with-better-auth/apps/admin/src/components/ui/collapsible.tsx`:
- Around line 14-28: Add JSDoc comments for the exported React components
CollapsibleTrigger and CollapsibleContent: above each function
(CollapsibleTrigger and CollapsibleContent) include a brief description of the
component, document the props parameter (using `@param` props - describe that it
spreads CollapsiblePrimitive.Trigger.Props or CollapsiblePrimitive.Panel.Props
respectively), and add an `@returns` line describing the returned
React.ReactElement; keep the comments concise and follow existing JSDoc style in
the project.

In `@examples/todo-with-better-auth/apps/web/src/components/ui/autocomplete.tsx`:
- Around line 29-289: Add JSDoc comments for each exported wrapper and hook
(AutocompleteValue, AutocompleteTrigger, AutocompleteClear, AutocompleteInput,
AutocompleteContent, AutocompleteList, AutocompleteItem, AutocompleteGroup,
AutocompleteLabel, AutocompleteCollection, AutocompleteEmpty,
AutocompleteStatus, AutocompleteSeparator, and useAutocompleteFilter) describing
what the component/hook does, its props/parameters (including optional props
like showTrigger/showClear/showSpinner for AutocompleteInput), and the return
value (React.ReactElement or the hook type); place the JSDoc immediately above
each function or exported constant, include param tags for props and a returns
tag, and ensure descriptions follow the project's JSDoc style so these exported
APIs are fully documented.

In `@examples/todo-with-better-auth/apps/web/src/components/ui/collapsible.tsx`:
- Around line 14-28: Add JSDoc blocks above the exported functions
CollapsibleTrigger and CollapsibleContent describing their purpose (trigger and
panel wrappers for the Collapsible primitive), document the props parameter type
(CollapsiblePrimitive.Trigger.Props and CollapsiblePrimitive.Panel.Props
respectively), and document the return type (React.ReactElement). Keep the JSDoc
concise and include any data-slot details (data-slot="collapsible-trigger" and
data-slot="collapsible-content") so consumers know the rendered DOM attributes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f1b7ecf9-e879-4e75-b038-e8f7a71df3e0

📥 Commits

Reviewing files that changed from the base of the PR and between c175429 and 644ce86.

⛔ Files ignored due to path filters (20)
  • examples/blog-with-auth/apps/admin/baseplate/generated/codegen.ts is excluded by !**/generated/**, !**/generated/**
  • examples/blog-with-auth/apps/admin/baseplate/generated/src/components/ui/autocomplete.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/blog-with-auth/apps/admin/baseplate/generated/src/components/ui/collapsible.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/blog-with-auth/apps/admin/baseplate/generated/src/components/ui/slider.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/blog-with-auth/apps/admin/baseplate/generated/src/components/ui/spinner.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-better-auth/apps/admin/baseplate/generated/codegen.ts is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-better-auth/apps/admin/baseplate/generated/src/components/ui/autocomplete.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-better-auth/apps/admin/baseplate/generated/src/components/ui/collapsible.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-better-auth/apps/admin/baseplate/generated/src/components/ui/slider.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-better-auth/apps/admin/baseplate/generated/src/components/ui/spinner.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-better-auth/apps/web/baseplate/generated/codegen.ts is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-better-auth/apps/web/baseplate/generated/src/components/ui/autocomplete.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-better-auth/apps/web/baseplate/generated/src/components/ui/collapsible.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-better-auth/apps/web/baseplate/generated/src/components/ui/slider.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-better-auth/apps/web/baseplate/generated/src/components/ui/spinner.tsx is excluded by !**/generated/**, !**/generated/**
  • packages/react-generators/src/generators/core/react-components/generated/template-paths.ts is excluded by !**/generated/**, !**/generated/**
  • packages/react-generators/src/generators/core/react-components/generated/ts-import-providers.ts is excluded by !**/generated/**, !**/generated/**
  • packages/react-generators/src/generators/core/react-components/generated/typed-templates.ts is excluded by !**/generated/**, !**/generated/**
  • plugins/plugin-observability/src/sentry/core/generators/apollo-sentry/generated/template-renderers.ts is excluded by !**/generated/**, !**/generated/**
  • plugins/plugin-observability/src/sentry/core/generators/apollo-sentry/generated/typed-templates.ts is excluded by !**/generated/**, !**/generated/**
📒 Files selected for processing (41)
  • .changeset/add-autocomplete-slider-collapsible-spinner.md
  • examples/blog-with-auth/apps/admin/baseplate/file-id-map.json
  • examples/blog-with-auth/apps/admin/codegen.ts
  • examples/blog-with-auth/apps/admin/src/components/ui/.templates-info.json
  • examples/blog-with-auth/apps/admin/src/components/ui/autocomplete.tsx
  • examples/blog-with-auth/apps/admin/src/components/ui/collapsible.tsx
  • examples/blog-with-auth/apps/admin/src/components/ui/slider.tsx
  • examples/blog-with-auth/apps/admin/src/components/ui/spinner.tsx
  • examples/todo-with-better-auth/apps/admin/baseplate/file-id-map.json
  • examples/todo-with-better-auth/apps/admin/codegen.ts
  • examples/todo-with-better-auth/apps/admin/src/components/ui/.templates-info.json
  • examples/todo-with-better-auth/apps/admin/src/components/ui/autocomplete.tsx
  • examples/todo-with-better-auth/apps/admin/src/components/ui/collapsible.tsx
  • examples/todo-with-better-auth/apps/admin/src/components/ui/slider.tsx
  • examples/todo-with-better-auth/apps/admin/src/components/ui/spinner.tsx
  • examples/todo-with-better-auth/apps/web/baseplate/file-id-map.json
  • examples/todo-with-better-auth/apps/web/codegen.ts
  • examples/todo-with-better-auth/apps/web/src/components/ui/.templates-info.json
  • examples/todo-with-better-auth/apps/web/src/components/ui/autocomplete.tsx
  • examples/todo-with-better-auth/apps/web/src/components/ui/collapsible.tsx
  • examples/todo-with-better-auth/apps/web/src/components/ui/slider.tsx
  • examples/todo-with-better-auth/apps/web/src/components/ui/spinner.tsx
  • packages/project-builder-lib/src/definition/model/model-field-utils.ts
  • packages/react-generators/src/generators/apollo/react-apollo/templates/package/codegen.ts
  • packages/react-generators/src/generators/core/react-components/extractor.json
  • packages/react-generators/src/generators/core/react-components/templates/components/ui/autocomplete.tsx
  • packages/react-generators/src/generators/core/react-components/templates/components/ui/collapsible.tsx
  • packages/react-generators/src/generators/core/react-components/templates/components/ui/multi-combobox-field.tsx
  • packages/react-generators/src/generators/core/react-components/templates/components/ui/slider.tsx
  • packages/react-generators/src/generators/core/react-components/templates/components/ui/spinner.tsx
  • packages/ui-components/src/components/ui/async-combobox-field/async-combobox-field.tsx
  • packages/ui-components/src/components/ui/autocomplete/autocomplete.stories.tsx
  • packages/ui-components/src/components/ui/autocomplete/autocomplete.tsx
  • packages/ui-components/src/components/ui/index.ts
  • packages/ui-components/src/components/ui/multi-combobox-field/multi-combobox-field.stories.tsx
  • packages/ui-components/src/components/ui/multi-combobox-field/multi-combobox-field.tsx
  • packages/ui-components/src/components/ui/slider/slider.tsx
  • packages/ui-components/src/components/ui/spinner/spinner.stories.tsx
  • packages/ui-components/src/components/ui/spinner/spinner.tsx
  • packages/ui-components/src/constants/strings.ts
  • plugins/plugin-observability/src/sentry/core/generators/apollo-sentry/extractor.json

Comment on lines +8 to +16
import { cn } from '@src/utils/cn';

import {
InputGroup,
InputGroupAddon,
InputGroupButton,
InputGroupInput,
} from './input-group';
import { Spinner } from './spinner';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add .js suffixes to the internal imports.

This example app expects ESM-safe specifiers. Leaving @src/utils/cn, ./input-group, and ./spinner extensionless here makes this file inconsistent with the rest of the app and can break resolution after emit.

🔧 Suggested change
-import { cn } from '@src/utils/cn';
+import { cn } from '@src/utils/cn.js';
 
 import {
   InputGroup,
   InputGroupAddon,
   InputGroupButton,
   InputGroupInput,
-} from './input-group';
-import { Spinner } from './spinner';
+} from './input-group.js';
+import { Spinner } from './spinner.js';
As per coding guidelines "Always use .js extensions in import statements, even for TypeScript files. Example: `import { getSystemInfo } from '@src/system-info.js';`"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/blog-with-auth/apps/admin/src/components/ui/autocomplete.tsx` around
lines 8 - 16, Update the import specifiers to include .js extensions so they are
ESM-safe: change imports of the utility and local components (symbols: cn,
InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, Spinner) to use
'@src/utils/cn.js', './input-group.js', and './spinner.js' respectively; keep
the imported symbol names unchanged.

Comment on lines +14 to +28
function CollapsibleTrigger({
...props
}: CollapsiblePrimitive.Trigger.Props): React.ReactElement {
return (
<CollapsiblePrimitive.Trigger data-slot="collapsible-trigger" {...props} />
);
}

function CollapsibleContent({
...props
}: CollapsiblePrimitive.Panel.Props): React.ReactElement {
return (
<CollapsiblePrimitive.Panel data-slot="collapsible-content" {...props} />
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Document exported wrapper functions with JSDoc.

CollapsibleTrigger and CollapsibleContent are exported without JSDoc. Please add API docs similar to Collapsible.

Suggested fix
+/**
+ * Toggles the collapsible panel open/closed.
+ *
+ * `@param` props - Trigger props forwarded to the primitive trigger.
+ * `@returns` The collapsible trigger element.
+ */
 function CollapsibleTrigger({
   ...props
 }: CollapsiblePrimitive.Trigger.Props): React.ReactElement {
@@
+/**
+ * Renders collapsible panel content.
+ *
+ * `@param` props - Panel props forwarded to the primitive panel.
+ * `@returns` The collapsible content element.
+ */
 function CollapsibleContent({
   ...props
 }: CollapsiblePrimitive.Panel.Props): React.ReactElement {

As per coding guidelines: examples/blog-with-auth/**/*.{ts,tsx}: Add JSDoc documentation to all exported functions, interfaces, and classes, documenting the entity, its parameters, return value, and all fields.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function CollapsibleTrigger({
...props
}: CollapsiblePrimitive.Trigger.Props): React.ReactElement {
return (
<CollapsiblePrimitive.Trigger data-slot="collapsible-trigger" {...props} />
);
}
function CollapsibleContent({
...props
}: CollapsiblePrimitive.Panel.Props): React.ReactElement {
return (
<CollapsiblePrimitive.Panel data-slot="collapsible-content" {...props} />
);
}
/**
* Toggles the collapsible panel open/closed.
*
* `@param` props - Trigger props forwarded to the primitive trigger.
* `@returns` The collapsible trigger element.
*/
function CollapsibleTrigger({
...props
}: CollapsiblePrimitive.Trigger.Props): React.ReactElement {
return (
<CollapsiblePrimitive.Trigger data-slot="collapsible-trigger" {...props} />
);
}
/**
* Renders collapsible panel content.
*
* `@param` props - Panel props forwarded to the primitive panel.
* `@returns` The collapsible content element.
*/
function CollapsibleContent({
...props
}: CollapsiblePrimitive.Panel.Props): React.ReactElement {
return (
<CollapsiblePrimitive.Panel data-slot="collapsible-content" {...props} />
);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/blog-with-auth/apps/admin/src/components/ui/collapsible.tsx` around
lines 14 - 28, Add JSDoc comments above the exported wrapper components
CollapsibleTrigger and CollapsibleContent describing their purpose as simple
wrappers around the underlying primitives, document the props parameter type
(CollapsiblePrimitive.Trigger.Props for CollapsibleTrigger and
CollapsiblePrimitive.Panel.Props for CollapsibleContent), list any notable
attributes (e.g. data-slot values "collapsible-trigger" and
"collapsible-content"), and state the return type (React.ReactElement). Mirror
the style and fields used in the existing Collapsible documentation so each
exported function has API docs covering description, `@param` props, and `@returns`.

import { Slider as SliderPrimitive } from '@base-ui/react/slider';
import * as React from 'react';

import { cn } from '@src/utils/cn';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use .js extension for the local alias import.

Line 6 should include the .js suffix to match this app’s import-resolution convention.

Suggested fix
-import { cn } from '@src/utils/cn';
+import { cn } from '@src/utils/cn.js';

As per coding guidelines: examples/blog-with-auth/**/*.{ts,tsx,js,jsx}: Always use .js extensions in import statements, even for TypeScript files.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { cn } from '@src/utils/cn';
import { cn } from '@src/utils/cn.js';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/blog-with-auth/apps/admin/src/components/ui/slider.tsx` at line 6,
Update the local alias import to include the .js extension: change the import of
the utility symbol `cn` from `@src/utils/cn` to `@src/utils/cn.js` in the
`slider.tsx` component so it follows the project's import-resolution convention;
ensure the import statement using `cn` (the named import in this file) is
updated accordingly.

@@ -0,0 +1,22 @@
import type React from 'react';

import { cn } from '@src/utils/cn';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add .js extension to the internal alias import.

This import should include the explicit .js suffix to match project rules.

Suggested change
-import { cn } from '@src/utils/cn';
+import { cn } from '@src/utils/cn.js';

As per coding guidelines, examples/blog-with-auth/**/*.{ts,tsx,js,jsx} must use .js extensions in import statements.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { cn } from '@src/utils/cn';
import { cn } from '@src/utils/cn.js';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/blog-with-auth/apps/admin/src/components/ui/spinner.tsx` at line 3,
Update the internal alias import in spinner.tsx to include the explicit .js
extension: change the import that references '@src/utils/cn' so it points to
'@src/utils/cn.js' to comply with the repository rule that
examples/blog-with-auth/**/*.{ts,tsx,js,jsx} must use .js extensions in import
statements; locate the import at the top of the file (the line importing cn) and
modify only the module specifier to add the .js suffix.

Comment on lines +5 to +22
function Spinner({
className,
...props
}: React.ComponentProps<'div'>): React.ReactElement {
return (
<div
role="status"
aria-label="Loading"
className={cn(
'size-4 animate-spin rounded-full border-2 border-current border-t-transparent',
className,
)}
{...props}
/>
);
}

export { Spinner };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add JSDoc for the exported Spinner component.

The exported function is missing required documentation.

Suggested change
+/**
+ * Spinner indicator component.
+ *
+ * `@param` props - Standard div props.
+ * `@param` props.className - Optional class names merged into the spinner.
+ * `@returns` Spinner element.
+ */
 function Spinner({
   className,
   ...props
 }: React.ComponentProps<'div'>): React.ReactElement {

As per coding guidelines, examples/blog-with-auth/**/*.{ts,tsx} requires JSDoc on exported functions, interfaces, and classes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/blog-with-auth/apps/admin/src/components/ui/spinner.tsx` around
lines 5 - 22, Add a JSDoc comment above the exported Spinner function describing
its purpose, the props it accepts, and any accessibility behavior; specifically
document the Spinner component (function Spinner) and its props type
React.ComponentProps<'div'>, mention that it returns a React.ReactElement, and
note the role="status" and aria-label="Loading" usage for screen readers. Ensure
the JSDoc is placed immediately above the Spinner declaration and uses standard
tags like `@param` and `@returns` so the linter for
examples/blog-with-auth/**/*.{ts,tsx} recognizes the exported function as
documented.

Comment on lines +5 to +22
function Spinner({
className,
...props
}: React.ComponentProps<'div'>): React.ReactElement {
return (
<div
role="status"
aria-label="Loading"
className={cn(
'size-4 animate-spin rounded-full border-2 border-current border-t-transparent',
className,
)}
{...props}
/>
);
}

export { Spinner };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add JSDoc for exported Spinner.

Spinner is exported but undocumented. Please add JSDoc documenting purpose, params, and return value.

Suggested fix
+/**
+ * Displays a small loading indicator.
+ *
+ * `@param` props - Spinner container props.
+ * `@param` props.className - Additional classes merged into the spinner.
+ * `@returns` A status-role spinner element.
+ */
 function Spinner({
   className,
   ...props
 }: React.ComponentProps<'div'>): React.ReactElement {

As per coding guidelines: examples/todo-with-better-auth/**/*.{ts,tsx,js,jsx}: Add JSDoc comments to all exported functions, interfaces, and classes documenting the function/type, parameters, return value, and all fields.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function Spinner({
className,
...props
}: React.ComponentProps<'div'>): React.ReactElement {
return (
<div
role="status"
aria-label="Loading"
className={cn(
'size-4 animate-spin rounded-full border-2 border-current border-t-transparent',
className,
)}
{...props}
/>
);
}
export { Spinner };
/**
* Displays a small loading indicator.
*
* `@param` props - Spinner container props.
* `@param` props.className - Additional classes merged into the spinner.
* `@returns` A status-role spinner element.
*/
function Spinner({
className,
...props
}: React.ComponentProps<'div'>): React.ReactElement {
return (
<div
role="status"
aria-label="Loading"
className={cn(
'size-4 animate-spin rounded-full border-2 border-current border-t-transparent',
className,
)}
{...props}
/>
);
}
export { Spinner };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/todo-with-better-auth/apps/web/src/components/ui/spinner.tsx` around
lines 5 - 22, Exported component Spinner lacks JSDoc; add a JSDoc block above
the Spinner function describing its purpose (a simple loading spinner), document
parameters (props: React.ComponentProps<'div'> including className and any
spread props) and the return value (React.ReactElement), and mention any
accessibility attributes (role and aria-label) used; reference the Spinner
function name and the props signature so the comment is placed immediately above
function Spinner({ className, ...props }: React.ComponentProps<'div'>):
React.ReactElement.

Comment on lines +169 to +193
onValueChange={(nextValue) => {
setSearchValue(nextValue);

const controller = new AbortController();
abortControllerRef.current?.abort();
abortControllerRef.current = controller;

if (nextValue === '') {
setSearchResults([]);
setError(null);
return;
}

startTransition(async () => {
setError(null);
const result = await searchCities(nextValue, contains);
if (controller.signal.aborted) {
return;
}
startTransition(() => {
setSearchResults(result.cities);
setError(result.error);
});
});
}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Clear the previous results before firing the next request.

Line 182 starts a new search but leaves the last searchResults in place until the promise resolves. Because open stays true when those old results are non-empty, the async story renders the previous query's list while the new query is pending.

Suggested fix
           if (nextValue === '') {
             setSearchResults([]);
             setError(null);
             return;
           }
 
+          setSearchResults([]);
+          setError(null);
           startTransition(async () => {
-            setError(null);
             const result = await searchCities(nextValue, contains);
             if (controller.signal.aborted) {
               return;
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/ui-components/src/components/ui/autocomplete/autocomplete.stories.tsx`
around lines 169 - 193, The handler in onValueChange leaves previous
searchResults visible until the new async search resolves; update the
onValueChange logic (the function that calls setSearchValue, creates controller,
uses abortControllerRef and startTransition) to immediately clear previous
results and reset error when a new non-empty query is issued — i.e., call
setSearchResults([]) and setError(null) right after creating/aborting the
AbortController and before starting the async startTransition/searchCities call
so the UI doesn't render stale results while the new request is pending.

Comment on lines +54 to +64
function AutocompleteClear({
className,
...props
}: AutocompletePrimitive.Clear.Props): React.ReactElement {
return (
<AutocompletePrimitive.Clear
data-slot="autocomplete-clear"
render={<InputGroupButton variant="ghost" size="icon-xs" />}
className={cn(className)}
{...props}
>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, locate the file and check its size
wc -l packages/ui-components/src/components/ui/autocomplete/autocomplete.tsx

Repository: halfdomelabs/baseplate

Length of output: 140


🏁 Script executed:

# Read the relevant sections of the file (lines 50-95 to capture both components)
sed -n '50,95p' packages/ui-components/src/components/ui/autocomplete/autocomplete.tsx

Repository: halfdomelabs/baseplate

Length of output: 1241


🏁 Script executed:

# Check for UI guidelines files mentioned in the coding guidelines
find . -name "ui-rules.md" -o -name "ui-components.md" -o -name "code-style.md" | head -20

Repository: halfdomelabs/baseplate

Length of output: 138


🏁 Script executed:

# Search for example implementations mentioned in the scratchpad
find . -path "*/autocomplete/*example*" -o -path "*/autocomplete/*demo*" | grep -E "\.(tsx?|jsx?)$"

Repository: halfdomelabs/baseplate

Length of output: 48


🏁 Script executed:

# Check the UI rules and UI components guidelines
cat .agents/ui-rules.md

Repository: halfdomelabs/baseplate

Length of output: 864


🏁 Script executed:

# Also check code-style guidelines
cat .agents/code-style.md

Repository: halfdomelabs/baseplate

Length of output: 3762


🏁 Script executed:

# Search for other component examples using similar render patterns
rg "render=" packages/ui-components/src/components/ -A 2 -B 2 | head -50

Repository: halfdomelabs/baseplate

Length of output: 4463


🏁 Script executed:

# Check the `@base-ui/react/autocomplete` types to understand the render prop
rg "export.*Clear" node_modules/@base-ui/react/ 2>/dev/null | head -10

Repository: halfdomelabs/baseplate

Length of output: 48


🏁 Script executed:

# Search for autocomplete example or story files
find packages/ui-components -path "*autocomplete*" -type f | grep -E "\.(tsx?|jsx?)$"

Repository: halfdomelabs/baseplate

Length of output: 215


🏁 Script executed:

# Check if there's an autocomplete.stories.tsx file
find . -name "*autocomplete*.stories.tsx"

Repository: halfdomelabs/baseplate

Length of output: 146


🏁 Script executed:

# Let's also verify the exact JSX prop evaluation order - check how props are spread in other wrapper components
rg "render=\{" packages/ui-components/src/components/ui/ -A 1 -B 1 | head -40

Repository: halfdomelabs/baseplate

Length of output: 3323


🏁 Script executed:

# Check the autocomplete.stories.tsx file to see if examples mirror the issue
cat packages/ui-components/src/components/ui/autocomplete/autocomplete.stories.tsx

Repository: halfdomelabs/baseplate

Length of output: 7648


🏁 Script executed:

# Now let's check the full context of AutocompleteInput to see the current state (lines 70-88)
sed -n '70,95p' packages/ui-components/src/components/ui/autocomplete/autocomplete.tsx

Repository: halfdomelabs/baseplate

Length of output: 787


🏁 Script executed:

# Let's verify prop spreading order in React/JSX - test if later props override earlier ones
python3 << 'EOF'
# In JSX/React, when you have:
# <Component prop1={value1} prop2={value2} />
# Later props override earlier props only if they are the same prop name
# So if we have:
# <Component render={<Button />} {...props} />
# And props contains render={<CustomButton />}
# Then render={<CustomButton />} from props will override the fixed render

# Let's verify this with a simple example
test_code = """
// Example of how React/JSX handles duplicate props
<Element 
  render={<InputGroupButton />}  // Defined first
  {...props}                      // Contains render={<CustomButton />}
  />
// Result: render={<CustomButton />} wins because it comes in props
"""

print("JSX Prop Resolution Order:")
print("When the same prop appears multiple times, the LAST one in left-to-right order wins.")
print("\nIn the current code:")
print("  render={<InputGroupButton />}  // First")
print("  {...props}                      // props.render comes after")
print("\nResult: props.render WILL override the intended InputGroupButton")
print("\nSuggested fix option 1: Omit render from props type")
print("Suggested fix option 2: Spread {...props} BEFORE render prop")
EOF

Repository: halfdomelabs/baseplate

Length of output: 483


🏁 Script executed:

# Check the entire AutocompleteClear and AutocompleteInput functions with broader context
sed -n '53,105p' packages/ui-components/src/components/ui/autocomplete/autocomplete.tsx

Repository: halfdomelabs/baseplate

Length of output: 1602


🏁 Script executed:

# Final check: verify the specific line numbers match the original review comment
sed -n '54,65p' packages/ui-components/src/components/ui/autocomplete/autocomplete.tsx | cat -n

Repository: halfdomelabs/baseplate

Length of output: 515


🏁 Script executed:

# Confirm that the issue description matches - props order vulnerability
echo "Checking if props.render can override fixed render prop..."
python3 << 'EOF'
# In JSX, when you have:
# <Component prop={value1} {...obj} />
# If obj.prop exists, obj.prop WINS (spreads come after explicit props)

# Review comment claims the opposite direction, let me verify
# Current actual code:
# <AutocompletePrimitive.Clear
#   render={<InputGroupButton ... />}   [1st]
#   {...props}                           [2nd - can contain render]
# />

# So if props = { render: <CustomButton /> }
# The spread {...props} comes AFTER the fixed render
# In JSX, spreads that come AFTER explicit props DON'T override them
# Wait - I need to check the JSX prop order semantics carefully

# Actually in React/JSX:
# <Component a={1} b={2} {...obj} />
# becomes: {...obj} is processed AFTER a and b
# So obj.a and obj.b WILL override the explicit values if they exist

print("CORRECTION:")
print("JSX processes attributes left-to-right")
print("So {...props} AFTER render= WILL override if props.render exists")
print("Current code: render={...} THEN {...props}")
print("Result: props.render WILL override the fixed render")
print("\nThis matches the review comment's claim ✓")
EOF

Repository: halfdomelabs/baseplate

Length of output: 378


Prevent callers from overriding the fixed render props.

Lines 61 and 86 set fixed render elements, but the later ...props spread allows a caller to pass render and replace the InputGroupButton/InputGroupInput wrappers. This breaks the component's intended API contract. Omit render from the exposed prop types, or spread ...props before the fixed render prop so the wrapper's intent cannot be overridden. The same pattern applies to the combobox component.

🔧 Suggested change
+type AutocompleteClearProps = Omit<AutocompletePrimitive.Clear.Props, 'render'>;
+
 function AutocompleteClear({
   className,
   ...props
-}: AutocompletePrimitive.Clear.Props): React.ReactElement {
+}: AutocompleteClearProps): React.ReactElement {
   return (
     <AutocompletePrimitive.Clear
+      {...props}
       data-slot="autocomplete-clear"
       render={<InputGroupButton variant="ghost" size="icon-xs" />}
       className={cn(className)}
-      {...props}
     >
       <MdClose className="pointer-events-none" />
     </AutocompletePrimitive.Clear>
   );
 }
 
+type AutocompleteInputProps = Omit<AutocompletePrimitive.Input.Props, 'render'> & {
+  showTrigger?: boolean;
+  showClear?: boolean;
+  showSpinner?: boolean;
+};
+
 function AutocompleteInput({
   className,
   children,
   disabled = false,
   showTrigger = false,
   showClear = false,
   showSpinner = false,
   ...props
-}: AutocompletePrimitive.Input.Props & {
-  showTrigger?: boolean;
-  showClear?: boolean;
-  showSpinner?: boolean;
-}): React.ReactElement {
+}: AutocompleteInputProps): React.ReactElement {
   return (
     <InputGroup className={cn('w-auto', className)}>
       <AutocompletePrimitive.Input
+        {...props}
         render={<InputGroupInput disabled={disabled} />}
-        {...props}
       />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ui-components/src/components/ui/autocomplete/autocomplete.tsx`
around lines 54 - 64, The Autocomplete components allow callers to override the
fixed render prop because {...props} is spread after the fixed render prop in
AutocompleteClear (AutocompletePrimitive.Clear) and the corresponding
AutocompleteInput (AutocompletePrimitive.Input); to fix, prevent render from
being overridden by either removing render from the exposed prop type or by
spreading {...props} before setting the fixed render prop so the component
always supplies the InputGroupButton (for AutocompleteClear) and InputGroupInput
(for AutocompleteInput); update AutocompleteClear, AutocompletePrimitive.Clear
usage and AutocompleteInput/AutocompletePrimitive.Input usage accordingly to
ensure render cannot be replaced.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

♻️ Duplicate comments (2)
examples/blog-with-auth/apps/admin/src/components/ui/slider.tsx (1)

6-6: ⚠️ Potential issue | 🟠 Major

Add .js extension to local alias import.

Line 6 should use the .js suffix to match this app’s import convention.

Proposed fix
-import { cn } from '@src/utils/cn';
+import { cn } from '@src/utils/cn.js';

As per coding guidelines: examples/blog-with-auth/**/*.{ts,tsx,js,jsx}: Always use .js extensions in import statements, even for TypeScript files.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/blog-with-auth/apps/admin/src/components/ui/slider.tsx` at line 6,
Update the local alias import to include the .js extension: change the import
that brings in the utility symbol "cn" from '@src/utils/cn' to use the .js
suffix (i.e., import "cn" from '@src/utils/cn.js') so the file follows the
project's import convention enforced for examples/blog-with-auth; ensure the
same change is applied wherever the '@src/utils/cn' alias is used in this
component.
examples/todo-with-better-auth/apps/admin/src/components/ui/slider.tsx (1)

6-6: ⚠️ Potential issue | 🟠 Major

Import path should include .js extension.

Line 6 should use .js per this example app’s import convention.

Proposed fix
-import { cn } from '@src/utils/cn';
+import { cn } from '@src/utils/cn.js';

As per coding guidelines: examples/todo-with-better-auth/**/*.{ts,tsx,js,jsx}: Always use .js extensions in import statements, even for TypeScript files.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/todo-with-better-auth/apps/admin/src/components/ui/slider.tsx` at
line 6, Update the import for the utility symbol `cn` so it uses a .js
extension: change the module specifier from "@src/utils/cn" to
"@src/utils/cn.js" where `cn` is imported in the slider component; ensure the
import statement that brings in `cn` is the only edit so it follows the
project's rule of always using .js extensions in import paths for examples.
🧹 Nitpick comments (1)
packages/ui-components/src/components/ui/async-combobox-field/async-combobox-field.tsx (1)

64-68: Collapse duplicate reducer actions (reset and cleared).

These two actions currently produce identical state, which adds unnecessary branching and maintenance overhead.

Refactor suggestion
 type SearchAction<OptionType> =
   | { type: 'reset'; initialOptions: OptionType[] }
   | { type: 'searchStarted' }
   | { type: 'searchSucceeded'; options: OptionType[] }
-  | { type: 'searchFailed'; error: string }
-  | { type: 'cleared'; initialOptions: OptionType[] };
+  | { type: 'searchFailed'; error: string };

 function searchReducer<OptionType>(
   state: SearchState<OptionType>,
   action: SearchAction<OptionType>,
 ): SearchState<OptionType> {
   switch (action.type) {
     case 'reset': {
       return {
         options: action.initialOptions,
         isLoading: false,
         loadError: null,
         hasSearched: false,
       };
     }
@@
-    case 'cleared': {
-      return {
-        options: action.initialOptions,
-        isLoading: false,
-        loadError: null,
-        hasSearched: false,
-      };
-    }
   }
 }
-        dispatch({
-          type: 'cleared',
-          initialOptions: initialOptionsRef.current,
-        });
+        dispatch({ type: 'reset', initialOptions: initialOptionsRef.current });

Also applies to: 75-82, 97-104

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/ui-components/src/components/ui/async-combobox-field/async-combobox-field.tsx`
around lines 64 - 68, The reducer defines two identical actions `{ type:
'reset'; initialOptions: OptionType[] }` and `{ type: 'cleared'; initialOptions:
OptionType[] }` causing duplicate branches; collapse them into a single action
(choose one name, e.g., 'reset') by removing the other from the action union and
updating the reducer switch branches that handle 'cleared' (and any other
duplicate handling at the other occurrences) to handle only 'reset', and update
all dispatch sites that currently dispatch `{ type: 'cleared' }` to dispatch `{
type: 'reset', initialOptions }` (or vice versa) so only one action and branch
remain in the reducer and action union.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@examples/blog-with-auth/apps/admin/src/components/ui/slider.tsx`:
- Around line 8-16: Add a complete JSDoc block to the exported Slider function:
describe what the component does, document the single parameter (props) and each
prop used by Slider (e.g., value, min, max, step, onChange, disabled or any
other props defined on the function's parameter object) with `@param` tags and
types/brief descriptions, and add an `@returns` tag indicating it returns a
JSX.Element/React.ReactNode; ensure the JSDoc uses the exact exported function
name Slider so the linter recognizes the documentation.

In `@examples/todo-with-better-auth/apps/admin/src/components/ui/slider.tsx`:
- Around line 8-16: Update the JSDoc for the exported Slider component to
document the function, its props, and return value: add a summary line for
Slider, an `@param` block describing the props object and each prop (e.g., value,
onChange, min, max, step, and any other fields defined on the Slider props type
or interface used by the Slider function), and an `@returns` line describing the
React element returned (e.g., JSX.Element). Ensure the doc mentions types and
behavior for optional vs required props and any default values used by the
Slider function so tooling and readers can understand usage.

In `@examples/todo-with-better-auth/apps/web/src/components/ui/slider.tsx`:
- Around line 8-16: The exported function Slider is missing JSDoc tags for its
parameters and return value; update the existing block above the Slider
declaration to include an `@param` describing the props argument (list key props
like value, onChange, min, max, step, disabled, etc., matching the
SliderProps/interface used) and an `@returns` describing the rendered
React.ReactElement (or JSX.Element), and document any side effects; ensure the
doc block references the exported Slider function and uses the same prop
names/types as defined in the component so tooling and consumers have complete
API docs.

---

Duplicate comments:
In `@examples/blog-with-auth/apps/admin/src/components/ui/slider.tsx`:
- Line 6: Update the local alias import to include the .js extension: change the
import that brings in the utility symbol "cn" from '@src/utils/cn' to use the
.js suffix (i.e., import "cn" from '@src/utils/cn.js') so the file follows the
project's import convention enforced for examples/blog-with-auth; ensure the
same change is applied wherever the '@src/utils/cn' alias is used in this
component.

In `@examples/todo-with-better-auth/apps/admin/src/components/ui/slider.tsx`:
- Line 6: Update the import for the utility symbol `cn` so it uses a .js
extension: change the module specifier from "@src/utils/cn" to
"@src/utils/cn.js" where `cn` is imported in the slider component; ensure the
import statement that brings in `cn` is the only edit so it follows the
project's rule of always using .js extensions in import paths for examples.

---

Nitpick comments:
In
`@packages/ui-components/src/components/ui/async-combobox-field/async-combobox-field.tsx`:
- Around line 64-68: The reducer defines two identical actions `{ type: 'reset';
initialOptions: OptionType[] }` and `{ type: 'cleared'; initialOptions:
OptionType[] }` causing duplicate branches; collapse them into a single action
(choose one name, e.g., 'reset') by removing the other from the action union and
updating the reducer switch branches that handle 'cleared' (and any other
duplicate handling at the other occurrences) to handle only 'reset', and update
all dispatch sites that currently dispatch `{ type: 'cleared' }` to dispatch `{
type: 'reset', initialOptions }` (or vice versa) so only one action and branch
remain in the reducer and action union.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d3124663-bcc6-4a58-8337-0787614b10ef

📥 Commits

Reviewing files that changed from the base of the PR and between c1cdecb and 719beac.

⛔ Files ignored due to path filters (6)
  • examples/blog-with-auth/apps/admin/baseplate/generated/src/components/ui/slider.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/blog-with-auth/apps/admin/baseplate/generated/src/components/ui/spinner.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-better-auth/apps/admin/baseplate/generated/src/components/ui/slider.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-better-auth/apps/admin/baseplate/generated/src/components/ui/spinner.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-better-auth/apps/web/baseplate/generated/src/components/ui/slider.tsx is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-better-auth/apps/web/baseplate/generated/src/components/ui/spinner.tsx is excluded by !**/generated/**, !**/generated/**
📒 Files selected for processing (13)
  • examples/blog-with-auth/CLAUDE.md
  • examples/blog-with-auth/apps/admin/src/components/ui/slider.tsx
  • examples/blog-with-auth/apps/admin/src/components/ui/spinner.tsx
  • examples/todo-with-better-auth/CLAUDE.md
  • examples/todo-with-better-auth/apps/admin/src/components/ui/slider.tsx
  • examples/todo-with-better-auth/apps/admin/src/components/ui/spinner.tsx
  • examples/todo-with-better-auth/apps/web/src/components/ui/slider.tsx
  • examples/todo-with-better-auth/apps/web/src/components/ui/spinner.tsx
  • packages/react-generators/src/generators/core/react-components/templates/components/ui/slider.tsx
  • packages/react-generators/src/generators/core/react-components/templates/components/ui/spinner.tsx
  • packages/ui-components/src/components/ui/async-combobox-field/async-combobox-field.tsx
  • packages/ui-components/src/components/ui/slider/slider.tsx
  • packages/ui-components/src/components/ui/spinner/spinner.tsx
💤 Files with no reviewable changes (2)
  • examples/blog-with-auth/CLAUDE.md
  • examples/todo-with-better-auth/CLAUDE.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • examples/todo-with-better-auth/apps/admin/src/components/ui/spinner.tsx
  • packages/react-generators/src/generators/core/react-components/templates/components/ui/spinner.tsx
  • packages/ui-components/src/components/ui/spinner/spinner.tsx

Comment on lines +8 to +16
/**
* An input where the user selects a value from within a given range.
*
* - Fixed single value support
*
* https://ui.shadcn.com/docs/components/base/slider
*
*/
function Slider({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Complete exported function JSDoc with params and return value.

The JSDoc for exported Slider lacks parameter/return annotations required by project rules.

As per coding guidelines: examples/blog-with-auth/**/*.{ts,tsx}: Add JSDoc documentation to all exported functions, interfaces, and classes, documenting the entity, its parameters, return value, and all fields.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/blog-with-auth/apps/admin/src/components/ui/slider.tsx` around lines
8 - 16, Add a complete JSDoc block to the exported Slider function: describe
what the component does, document the single parameter (props) and each prop
used by Slider (e.g., value, min, max, step, onChange, disabled or any other
props defined on the function's parameter object) with `@param` tags and
types/brief descriptions, and add an `@returns` tag indicating it returns a
JSX.Element/React.ReactNode; ensure the JSDoc uses the exact exported function
name Slider so the linter recognizes the documentation.

Comment on lines +8 to +16
/**
* An input where the user selects a value from within a given range.
*
* - Fixed single value support
*
* https://ui.shadcn.com/docs/components/base/slider
*
*/
function Slider({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Expand JSDoc for exported Slider with params/returns.

The exported function docs should include parameter and return details.

As per coding guidelines: examples/todo-with-better-auth/**/*.{ts,tsx,js,jsx}: Add JSDoc comments to all exported functions, interfaces, and classes documenting the function/type, parameters, return value, and all fields.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/todo-with-better-auth/apps/admin/src/components/ui/slider.tsx`
around lines 8 - 16, Update the JSDoc for the exported Slider component to
document the function, its props, and return value: add a summary line for
Slider, an `@param` block describing the props object and each prop (e.g., value,
onChange, min, max, step, and any other fields defined on the Slider props type
or interface used by the Slider function), and an `@returns` line describing the
React element returned (e.g., JSX.Element). Ensure the doc mentions types and
behavior for optional vs required props and any default values used by the
Slider function so tooling and readers can understand usage.

Comment on lines +8 to +16
/**
* An input where the user selects a value from within a given range.
*
* - Fixed single value support
*
* https://ui.shadcn.com/docs/components/base/slider
*
*/
function Slider({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

JSDoc for exported Slider should include params and return docs.

Current JSDoc is descriptive but incomplete against the project requirement for exported APIs.

As per coding guidelines: examples/todo-with-better-auth/**/*.{ts,tsx,js,jsx}: Add JSDoc comments to all exported functions, interfaces, and classes documenting the function/type, parameters, return value, and all fields.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/todo-with-better-auth/apps/web/src/components/ui/slider.tsx` around
lines 8 - 16, The exported function Slider is missing JSDoc tags for its
parameters and return value; update the existing block above the Slider
declaration to include an `@param` describing the props argument (list key props
like value, onChange, min, max, step, disabled, etc., matching the
SliderProps/interface used) and an `@returns` describing the rendered
React.ReactElement (or JSX.Element), and document any side effects; ensure the
doc block references the exported Slider function and uses the same prop
names/types as defined in the component so tooling and consumers have complete
API docs.

@kingston kingston merged commit 1115ba0 into main Mar 15, 2026
12 checks passed
@kingston kingston deleted the kingston/component-fixes branch March 15, 2026 09:51
@github-actions github-actions Bot mentioned this pull request Mar 14, 2026
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