feat(ui): make query-presets editable from the form view#15657
feat(ui): make query-presets editable from the form view#15657GermanJablo merged 15 commits intomainfrom
Conversation
📦 esbuild Bundle Analysis for payloadThis analysis was generated by esbuild-bundle-analyzer. 🤖
Largest pathsThese visualization shows top 20 largest paths in the bundle.Meta file: packages/next/meta_index.json, Out file: esbuild/index.js
Meta file: packages/payload/meta_index.json, Out file: esbuild/index.js
Meta file: packages/payload/meta_shared.json, Out file: esbuild/exports/shared.js
Meta file: packages/richtext-lexical/meta_client.json, Out file: esbuild/exports/client_optimized/index.js
Meta file: packages/ui/meta_client.json, Out file: esbuild/exports/client_optimized/index.js
Meta file: packages/ui/meta_shared.json, Out file: esbuild/exports/shared_optimized/index.js
DetailsNext to the size is how much the size has increased or decreased compared with the base branch of this PR.
|
|
|
||
| export type WhereBuilderProps = { | ||
| readonly collectionPluralLabel: SanitizedCollectionConfig['labels']['plural'] | ||
| readonly collectionPluralLabel?: SanitizedCollectionConfig['labels']['plural'] |
There was a problem hiding this comment.
Optional so the preset form can omit it; we derive it from getEntityConfig in form mode (see index.tsx).
| await expect(whereFieldContent).toBeVisible() | ||
| await expect(whereFieldContent).toContainText('No where query') | ||
| // Verify the Where field is visible (empty state: "Add Filter" or "No filters set") | ||
| const whereField = editModal.locator('.query-preset-where-field') |
There was a problem hiding this comment.
Assertions updated for editable WhereBuilder: we check for the builder and empty state instead of read-only ‘No where query’.
| // Verify the Columns field is visible and has 4 selected pills (same as default columns in list view) | ||
| const columnsField = editModal.locator('.query-preset-columns-field') | ||
| await expect(columnsField).toBeVisible() | ||
| await expect(columnsField.locator('.pill-selector__pill--selected')).toHaveCount(4) |
There was a problem hiding this comment.
A small UX improvement: now the columns that appear by default are the same as those that should appear by default in list view according to the Payload config.
| await expect(groupByField.locator('.group-by-builder')).toBeVisible() | ||
| await expect(groupByField).toContainText('Text') | ||
| await expect(groupByField).toContainText('ascending') | ||
| await expect(groupByField).toContainText(/ascending/i) |
There was a problem hiding this comment.
In the groupBy builder, "Ascending" is capitalized, hence the change
There was a problem hiding this comment.
Pull request overview
This PR enhances the query presets feature by making the preset document form fully editable. Previously, users could only create/edit presets from the list view by building a query and saving it as a preset. Now, the Where, Columns, and GroupBy fields in the preset form use interactive builders (WhereBuilder, PillSelector, GroupByBuilder) instead of read-only admin components, enabling direct creation and editing of presets from the document form.
Changes:
- Refactored WhereBuilder and GroupByBuilder to support dual-mode operation: list query state (original) and form-controlled mode (new)
- Replaced read-only display components in QueryPresets fields with interactive builders (WhereBuilder, GroupByBuilder, PillSelector)
- Updated e2e tests to reflect new UI elements and interaction patterns
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
packages/ui/src/elements/WhereBuilder/types.ts |
Added onChange and value props to make WhereBuilder controllable from forms |
packages/ui/src/elements/WhereBuilder/index.tsx |
Implemented dual-mode support: form-controlled via onChange/value or list query state |
packages/ui/src/elements/WhereBuilder/Condition/index.tsx |
Made filterOptions and RenderedFilter optional for form mode usage |
packages/ui/src/elements/WhereBuilder/Condition/Text/index.tsx |
Added null-safe access to field.hasMany property |
packages/ui/src/elements/WhereBuilder/Condition/DefaultFilter/index.tsx |
Added fallback empty object for optional filterOptions |
packages/ui/src/elements/QueryPresets/fields/WhereField/index.tsx |
Replaced custom read-only display with WhereBuilder component |
packages/ui/src/elements/GroupByBuilder/index.tsx |
Implemented dual-mode support and extracted form/list logic into separate handlers |
packages/ui/src/elements/QueryPresets/fields/GroupByField/index.tsx |
Replaced read-only Pill display with interactive GroupByBuilder |
packages/ui/src/elements/QueryPresets/fields/ColumnsField/index.tsx |
Replaced read-only Pill display with interactive PillSelector |
packages/ui/src/utilities/getColumns.ts |
Consolidated imports from payload/shared into single line |
test/query-presets/e2e.spec.ts |
Updated test selectors and expectations to match new interactive UI components |
test/group-by/e2e.spec.ts |
Updated test selectors to use .group-by-builder and adjusted case expectations |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const newColumns = currentColumns.map((col) => | ||
| col.accessor === pill.name ? { ...col, active: !col.active } : col, | ||
| ) | ||
| setValue(newColumns.length ? newColumns : undefined) |
There was a problem hiding this comment.
The condition newColumns.length ? newColumns : undefined will always be truthy as long as there are columns in the array, regardless of whether any are actually selected (active). This means you cannot clear all column selections. Consider checking if at least one column is active instead: newColumns.some(col => col.active) ? newColumns : undefined or simply always save newColumns without the conditional.
| setValue(newColumns.length ? newColumns : undefined) | |
| setValue(newColumns.some((col) => col.active) ? newColumns : undefined) |
|
🚀 This is included in version v3.78.0 |
Right now the only way to create/edit a preset is from the list view (build the query there, then “Save as preset”). The preset document form uses read-only admin components for where, columns, and groupBy. This PR replace those with a WhereBuilder (and similar for columns/groupBy) so presets can be created and edited directly in the document form, without depending on the list view.
Before
Screen.Recording.2026-02-18.at.11.48.04.mov
After
Screen.Recording.2026-02-17.at.18.15.34.mov