Skip to content

Commit 22ed03f

Browse files
plop
1 parent fce5a07 commit 22ed03f

51 files changed

Lines changed: 2923 additions & 35 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎docs/Plugin-initialization.md‎

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -377,15 +377,18 @@ const config = {
377377

378378
The `InputComponent` wrapper accepts a settings object as its second argument:
379379

380-
| key | type | required | default | description |
381-
| ---------------- | ------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------- |
382-
| multiple | boolean | false | `false` | The input renders multiple values itself (e.g. a multi-select) instead of being repeated as an array of inputs. |
383-
| trim | boolean | false | `false` | Trim string values before they reach the model. |
384-
| emptyToUndefined | boolean | false | `false` | Replace an empty string with `undefined` (applied after `trim`). |
385-
| debounce | number | false | - | Debounce the value write to the model, in ms. A number (including `0`) defers the write; omitted = synchronous. |
380+
| key | type | required | default | description |
381+
| ---------------- | -------------------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------- |
382+
| multiple | boolean | false | `false` | The input renders multiple values itself (e.g. a multi-select) instead of being repeated as an array of inputs. |
383+
| trim | boolean | false | `false` | Trim string values before they reach the model. |
384+
| emptyToUndefined | boolean | false | `false` | Replace an empty string with `undefined` (applied after `trim`). |
385+
| debounce | number | false | - | Debounce the value write to the model, in ms. A number (including `0`) defers the write; omitted = synchronous. |
386+
| inline | false or Component | false | - | Behavior in the collection's [filter row](Usage#column-filters) (only effective there). Omitted: the registered component is used inline. A component: a compact variant rendered inline instead. `false`: the input is never rendered inline, the column is edited through its popover only. |
386387

387388
By default, when a filter is used with `in` or `not_in` operators, the input component is repeated once per value. With `multiple: true`, your component is rendered only once and is responsible for managing the array of values itself.
388389

390+
The `inline` setting follows the same resolution as the component itself (`propertyInputs` > `typeInputs` > built-in inputs). All built-in inputs stay inline-capable by default.
391+
389392
### Property inputs
390393

391394
| key | type | required |

‎docs/Query-filter-format.md‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,27 @@ A filter is removable by default but you can make it not removable by the user.
123123
}
124124
```
125125

126+
## Column marker
127+
When [column filters](Usage#column-filters) are enabled on the collection, each filtered column owns one dedicated node at the root of the root group, marked with `column: <fieldId>`:
128+
129+
- a plain column is a `group` holding its conditions;
130+
- a dotted column (e.g. `company.brand_name`) is a chain of `entity_condition` (`operator: 'has'`, plus `count_operator: '>=', count: 1` for relationship segments) with the marker on the outermost node and the group of conditions at the deepest point.
131+
132+
```js
133+
{
134+
type: 'group',
135+
operator: 'and',
136+
column: 'first_name', // managed by the first_name column editor
137+
filters: [
138+
{ type: 'condition', property: 'first_name', operator: 'ilike', value: 'ali' },
139+
],
140+
}
141+
```
142+
143+
The marker is internal bookkeeping: it survives the query builder round-trip but is stripped before the filter is sent to the server (like `key`, `editable` and `removable`). A tagged `entity_condition` whose group holds nothing effective is dropped entirely — a bare `has` is never sent because of a column filter.
144+
145+
If the marker is duplicated, the first node at the root wins. Children of a tagged group that the column editor did not create (scopes, sub-groups or conditions on other properties added through the query builder) are preserved and sent to the server, but the column editor neither displays nor counts them.
146+
126147
# Allowed operators
127148

128149
## Condition operators

‎docs/Types.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ Types used to type component props and models. See [Usage](Usage).
5252
- `ItemClickHandler`, `FieldClickHandler`, `PostRequestHandler`, `RequestErrorHandler`, `ExportHandler` — the callback signatures for the handler props (`onItemClick`, `onFieldClick`, `postRequest`, `onRequestError`, `onExport`).
5353
- `SortItemField`, `SortItemProperty` — a sort entry (`{ field, order }`), as used in `v-model:sort` and in request params.
5454
- `CollectionType` — `'infinite' | 'pagination'`.
55-
- `FieldsEditingLocation`, `SortEditingLocation`, `FilterEditingLocation`, `CollectionSortEditingLocation` — where each editor is mounted.
55+
- `FieldsEditingLocation`, `SortEditingLocation`, `FilterEditingLocation`, `CollectionSortEditingLocation`, `CollectionFilterEditingLocation` — where each editor is mounted. `CollectionFilterEditingLocation` (`'collection-column' | 'collection-row' | 'none'`) is the collection-side subset for [column filters](Usage#column-filters).
5656

5757
## Custom components
5858

‎docs/Usage.md‎

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,11 @@ Props marked with 🔗 support two-way binding via `v-model:<key>`.
139139
| sort | 🔗 | array | false | - | Sort order. Array of field ids (strings) or objects `{ field: string, order: 'asc'\|'desc' }`. |
140140
| page | 🔗 | number | false | `1` | Current page number. |
141141
| customFields | | object | false | - | Permit to customize collection headers and cells rendering. More information [here](Usage#custom-fields). |
142-
| filter | | object | false | - | The raw filter. The collection runs `computeFilter` on it before requesting the server. |
143-
| manual | | boolean | false | `false` | If true, prop changes to `filter`/`fields` do not auto-request; call the exposed `submit()` method to trigger the request. Direct interactions in the collection UI (header sort, fields editor, pagination) always request immediately. |
142+
| filter | 🔗 | object | false | `null` | The raw filter. The collection runs `computeFilter` on it before requesting the server. Two-way binding is only needed for [column filters](Usage#column-filters) (a one-way `:filter` binding keeps working: edits then live in the collection only). |
143+
| filterEditingLocation | | string | false | `'none'` | Where [column filters](Usage#column-filters) are edited: `'collection-column'` (funnel button + popover in each filterable header), `'collection-row'` (a filter row under the headers), or `'none'`. Prop-only: the global `filterEditingLocation` config applies to `QkitSearch` only. |
144+
| allowedOperators | | object | false | - | Restrict the operators offered by the column filter editors. Same format as the query builder prop ([here](Usage#allowed-operators)). |
145+
| aliasInsensitiveLabels | | boolean | false | `false` | Display case-insensitive operators with their case-sensitive label in the column filter editors. |
146+
| manual | | boolean | false | `false` | If true, prop changes to `filter`/`fields` do not auto-request; call the exposed `submit()` method to trigger the request. Direct interactions in the collection UI (header sort, fields editor, pagination) always request immediately. Column filter edits update the model but wait for the validate button of their popover. |
144147
| debounce | | number | false | `1000` | Time in ms to wait after a `filter`/`fields` change before requesting the server. `0` requests immediately. |
145148
| directQuery | | boolean | false | `true` | Request server and display results when component is mounted. |
146149
| limit | | number | false | `undefined` | The count limit of fetched items per page. |
@@ -210,6 +213,23 @@ const customFields = {
210213
};
211214
```
212215

216+
### Column filters
217+
With `filterEditingLocation` set to `'collection-column'` or `'collection-row'`, users filter directly from the columns. The conditions live in the main filter (`v-model:filter`), each column owning one dedicated node marked `column: <fieldId>` at the root of the filter — see [the column marker](Query-filter-format#column-marker). The filter is then edited in the columns **or** in the query builder, never both.
218+
219+
A column is filterable when the request schema allows it, mirroring column sortability: every segment of the field's path must be filtrable in its entity, and the leaf property must not be a `relationship`/`object`/`morph_to` and must have at least one operator. Open custom fields are never filterable. Non-filterable columns show no filter control.
220+
221+
For a dotted column (e.g. `company.brand_name`), the conditions are edited with the leaf entity's schema and sent as a `has` relationship condition chain.
222+
223+
The editor is a compact condition list: per condition, an operator select (same operators as the query builder for the property type) and the value input, plus a **+** button that adds a condition on the column's property only. The and/or selector of the group appears from two conditions on. Removing the last condition removes the column's node from the filter.
224+
225+
**`'collection-column'` mode** — each filterable header shows a funnel button with a counter of the column's effective conditions (a defined value, or `null`/`not_null`). Clicking it opens a popover anchored under the header (native Popover API + CSS anchor positioning): one popover open at a time, Esc and light-dismiss supported, focus moves to the first field on open and back to the button on close.
226+
227+
**`'collection-row'` mode** — a row of cells under the headers. A column is edited directly in its cell when three conditions hold: at most one condition, no array operator (`in`/`not_in`, `contains`/`not_contains`) on an input without `multiple` (a multi-capable input such as an enum select stays inline), and an input allowed inline (see the [`inline` input setting](Plugin-initialization#input-settings)). Otherwise the cell shows the funnel + counter and editing happens in the popover — opened automatically when the fold is caused by a gesture made in the row (adding a second condition, switching to an array operator).
228+
229+
**Requests** — in auto mode edits reload live (debounced); a condition without a value does not trigger anything since the computed filter does not change. In `manual` mode edits only update the model (counter included) and a validate button appears in the popover (Enter is equivalent), wired to the exposed `submit()`. Header-click sorting stays immediate even in manual mode.
230+
231+
**Reflow** — when the table reflows to cards the headers are hidden, so both modes fall back to a funnel button in the collection's actions bar (visible in reflow only) opening a modal that lists each displayed filterable column with its editor. Edits happen on a working copy: confirming writes the model **and** requests (even in `manual` mode — confirming counts as validation); closing without confirming discards everything.
232+
213233
# Search component
214234
The search component wires the query builder and the collection together into a ready-to-use search interface: what the user builds in the query builder drives what the collection queries and displays, with no glue code on your side.
215235

@@ -245,11 +265,11 @@ Props marked with 🔗 support two-way binding via `v-model:<key>`.
245265
| allowRedo | | boolean | false | `true` | Enable redo button. |
246266
| allowedProperties | | object | false | - | Restrict allowed properties. More information [here](Usage#allowed-properties). |
247267
| allowedScopes | | object | false | - | Restrict allowed scopes. More information [here](Usage#allowed-scopes). |
248-
| allowedOperators | | object | false | - | Restrict allowed operators. More information [here](Usage#allowed-operators). |
268+
| allowedOperators | | object | false | - | Restrict allowed operators, in the query builder and in the column filter editors. More information [here](Usage#allowed-operators). |
249269
| displayOperator | | boolean or object | false | `true` | Display operators. More information [here](Usage#display-operator). |
250270
| userTimezone | | string | false | `'UTC'` | Display time in given timezone. |
251271
| requestTimezone | | string | false | `'UTC'` | Timezone to use when requesting server. |
252-
| manual | | boolean | false | `false` | If true, filter changes request the server only when the user clicks the validate button. Direct interactions in the collection UI (header sort, fields editor, pagination) always request immediately. |
272+
| manual | | boolean | false | `false` | If true, filter changes request the server only when the user clicks a validate button (in the query builder, or in a column filter popover). Direct interactions in the collection UI (header sort, fields editor, pagination) always request immediately. |
253273
| directQuery | | boolean | false | `true` | Request server and display results when component is mounted. |
254274
| debounce | | number | false | `1000` | Time in ms to wait after a `filter`/`fields` change before requesting the server. `0` requests immediately. |
255275
| limit | | number | false | `undefined` | The count limit of fetched items per page. |
@@ -258,7 +278,7 @@ Props marked with 🔗 support two-way binding via `v-model:<key>`.
258278
| allowedCollectionTypes | | array | false | `['pagination']` | Display types: `'pagination'` and/or `'infinite'`. |
259279
| displayCount | | boolean | false | `true` | Display total items count. |
260280
| reflow | | boolean | false | `false` | When the collection's own width is narrow (≤576px), reflow the table into stacked cards instead of a horizontally-scrolling table (container-based, not the viewport). |
261-
| filterEditingLocation | | string | false | `'query-builder'` | Where the filter builder is shown: `'query-builder'` or `'none'`. The query builder is rendered only when at least one of `filterEditingLocation`/`fieldsEditingLocation`/`sortEditingLocation` is `'query-builder'`. Defaults come from the plugin config. |
281+
| filterEditingLocation | | string | false | `'query-builder'` | Where the filter is edited: `'query-builder'`, `'collection-column'` or `'collection-row'` ([column filters](Usage#column-filters)), or `'none'`. Exclusive: the filter is edited in the query builder OR in the columns, never both. The query builder is rendered only when at least one of `filterEditingLocation`/`fieldsEditingLocation`/`sortEditingLocation` is `'query-builder'`. Defaults come from the plugin config. |
262282
| fieldsEditingLocation | | string | false | `'none'` | Where users can add/remove/reorder fields: `'query-builder'` (inline in the query builder), `'collection'` (columns button in the collection header), or `'none'`. |
263283
| sortEditingLocation | | string | false | `'collection-column'` | Where sort can be edited: `'query-builder'` (inline sort builder, sorts by any sortable property), `'collection-modal'` (sort editor button in the collection header), `'collection-column'` (sortable column headers), or `'none'`. |
264284
| naturalSortWhenEmpty | | boolean | false | `false` | When `sort` is empty, send the entity's `natural_sort` to the server (request-only). No-op without `natural_sort`. |

0 commit comments

Comments
 (0)