@pythia-software/query-table-ui 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +382 -8
- package/dist/FormulaEditor-NZWSPFJQ.js +7 -0
- package/dist/FormulaEditor-NZWSPFJQ.js.map +1 -0
- package/dist/chunk-TC5KDYUF.js +778 -0
- package/dist/chunk-TC5KDYUF.js.map +1 -0
- package/dist/index.d.ts +527 -14
- package/dist/index.js +13697 -3353
- package/dist/index.js.map +1 -1
- package/dist/theme.css +4557 -415
- package/dist/theme.css.map +1 -1
- package/package.json +6 -11
- package/dist/FormulaEditor-YCPICDIH.js +0 -251
- package/dist/FormulaEditor-YCPICDIH.js.map +0 -1
- package/dist/theme.d.ts +0 -2
package/README.md
CHANGED
|
@@ -1,15 +1,239 @@
|
|
|
1
1
|
# @pythia-software/query-table-ui
|
|
2
2
|
|
|
3
|
+
`ObjectInspector`, `ObjectProperties`, `PropertyViewControls`, and
|
|
4
|
+
`PropertyViewEditor` provide customizable read-only object details. See
|
|
5
|
+
[object property views](../../docs/object-properties.md) for setup and composition.
|
|
6
|
+
|
|
7
|
+
`ObjectInspector` supplies a compact card with a saved-view toolbar, property/value
|
|
8
|
+
rows, and a read-only footer. The host owns visible identity. Its property editor
|
|
9
|
+
opens a modal workbench with an ordered list, display settings and a live preview.
|
|
10
|
+
|
|
11
|
+
Enable `useQueryTable({ schema, itemDetails: true })` and pass
|
|
12
|
+
`itemDetails={api.itemDetails}` to `DataTable` for click popovers, resizable item modals
|
|
13
|
+
and row expansion. Detail is a regular draggable/resizable column, defaulting to Modal. Page links
|
|
14
|
+
support URL templates and same-tab/new-tab navigation. Item toolbars include Share. Each
|
|
15
|
+
modality has independent saved property views; shared links carry the query,
|
|
16
|
+
typed item ID, modality and layouts. Property label widths are saved with the
|
|
17
|
+
view; values support double click or focused Enter to copy raw data.
|
|
18
|
+
The Detail chip's right caret opens its settings in the column selector.
|
|
19
|
+
Popovers use compact icon controls and scroll properties within the card;
|
|
20
|
+
expanded rows keep Collapse in the card toolbar. Mode labels appear only in
|
|
21
|
+
the properties editor's context strip.
|
|
3
22
|
Opinionated, themeable React components for query-table, including the data
|
|
4
23
|
table, query builder, field picker, metrics panel, saved queries, cell menus,
|
|
5
24
|
and selection toolbar.
|
|
6
25
|
|
|
26
|
+
## Grouped rows
|
|
27
|
+
|
|
28
|
+
`useQueryTable({ schema, clientRows })` enables one row-producing grouping stage
|
|
29
|
+
for complete local datasets. The standard query builder supplies GROUP BY,
|
|
30
|
+
HAVING, aggregate column editing and representative-row ordering. Use
|
|
31
|
+
`api.schema`, `api.visibleFields` and `api.rowId` for the active result shape;
|
|
32
|
+
set `grouping: false` to opt out. Backend transports currently reject grouped
|
|
33
|
+
row queries. See [grouping integration](../../docs/grouping.md) for the query
|
|
34
|
+
shape, source-stage controls, saved state and execution boundaries.
|
|
35
|
+
|
|
7
36
|
## Install
|
|
8
37
|
|
|
9
38
|
```bash
|
|
10
39
|
npm install @pythia-software/query-table-core @pythia-software/query-table-react @pythia-software/query-table-ui react react-dom
|
|
11
40
|
```
|
|
12
41
|
|
|
42
|
+
## Client palettes and column roles
|
|
43
|
+
|
|
44
|
+
Import `theme.css` and override `--qt-*` properties on a wrapper around your
|
|
45
|
+
query table. Each instance can have its own palette; the library does not choose
|
|
46
|
+
one from the OS appearance. `color-scheme` can match the host's native controls,
|
|
47
|
+
but surfaces and role colors come from explicit tokens. Scoped tokens and
|
|
48
|
+
typography also follow pickers and dialogs into mobile portals, including live
|
|
49
|
+
changes to the wrapper's `class`, `style`, or `data-theme`.
|
|
50
|
+
|
|
51
|
+
The general palette uses `--qt-bg`, `--qt-text`, `--qt-muted`, `--qt-header-bg`,
|
|
52
|
+
`--qt-border`, and `--qt-border-subtle`. Actions use `--qt-accent` and
|
|
53
|
+
`--qt-accent-bg`; filled buttons additionally accept `--qt-accent-fg` (default
|
|
54
|
+
white) and `--qt-accent-hover` (default a darker accent).
|
|
55
|
+
|
|
56
|
+
Grouping roles have their own tokens, independent of actions and metric/chart
|
|
57
|
+
category colors:
|
|
58
|
+
|
|
59
|
+
| Prefix | Meaning | Default text color |
|
|
60
|
+
| --- | --- | --- |
|
|
61
|
+
| `--qt-column-key` | GROUP BY key | `#956000` |
|
|
62
|
+
| `--qt-column-aggregate` | Aggregated value, including custom formulas | `#7942a8` |
|
|
63
|
+
| `--qt-column-row` | Value from the group's representative row | `#08786d` |
|
|
64
|
+
|
|
65
|
+
Each prefix supports these suffixes:
|
|
66
|
+
|
|
67
|
+
| Suffix | Controls | Default |
|
|
68
|
+
| --- | --- | --- |
|
|
69
|
+
| `-color` | Role text, label, and badge | Color above |
|
|
70
|
+
| `-bg` | Badge and compact option background | 9% role color over `--qt-bg` |
|
|
71
|
+
| `-border` | Role selection border | 45% role color over `--qt-border` |
|
|
72
|
+
| `-hover-bg` | Hovered role option/control | 15% role color over `--qt-bg` |
|
|
73
|
+
| `-selected-bg` | Selected role option/column | Role `-bg` |
|
|
74
|
+
|
|
75
|
+
For example, a host adapter can map its own palette directly:
|
|
76
|
+
|
|
77
|
+
```css
|
|
78
|
+
.client-query-table {
|
|
79
|
+
--qt-bg: var(--client-panel);
|
|
80
|
+
--qt-text: var(--client-ink);
|
|
81
|
+
--qt-accent: var(--client-accent);
|
|
82
|
+
--qt-accent-fg: var(--client-panel);
|
|
83
|
+
--qt-column-key-color: var(--client-key-label);
|
|
84
|
+
--qt-column-aggregate-color: var(--client-aggregate-label);
|
|
85
|
+
--qt-column-row-color: var(--client-row-label);
|
|
86
|
+
/* Optional: choose a badge surface rather than deriving a tint. */
|
|
87
|
+
--qt-column-key-bg: var(--client-key-surface);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`ColumnRoleBadge` accepts presentation metadata
|
|
92
|
+
`{ kind: "key" | "aggregate" | "row", badge: string, title: string }` and an
|
|
93
|
+
optional `className`. Use it with `DataTable.headerAdornment` and
|
|
94
|
+
`QueryBuilder.selectPresentation.renderChip`; a `.qt-column-label` wrapper
|
|
95
|
+
with the same `data-column-role` colors the field label too. Pass `undefined`
|
|
96
|
+
for ordinary ungrouped fields to omit the badge. The host determines provenance;
|
|
97
|
+
the component does not infer a role from a field's name or type. Role tokens
|
|
98
|
+
also style the grouped column options and column workbench.
|
|
99
|
+
|
|
100
|
+
The role text remains visible alongside color. Choose readable foregrounds
|
|
101
|
+
against your surfaces; you can use neutral colors without losing the KEY,
|
|
102
|
+
ROW, and aggregate labels. These presentation settings do not enter saved
|
|
103
|
+
queries. Metric category assignments remain in the separate `MetricTheme` API.
|
|
104
|
+
The `/grouping` demo includes adapters for Pharos' cream and forest palettes.
|
|
105
|
+
|
|
106
|
+
## Column widths
|
|
107
|
+
|
|
108
|
+
Drag a header edge to resize one column (arrow keys nudge, Enter auto-fits).
|
|
109
|
+
Click anywhere in a column header to open its actions menu, including padding
|
|
110
|
+
and blank space. Resize handles remain dedicated to resizing.
|
|
111
|
+
Open **Column Widths** to resize in one step:
|
|
112
|
+
|
|
113
|
+
- **Fit This Column** sizes the clicked column to its widest rendered value.
|
|
114
|
+
- **Fit All to Content** does the same for every column.
|
|
115
|
+
- **Fit All to Screen** fills the viewport; when content overflows, narrow
|
|
116
|
+
columns keep their content width and only the widest ones are trimmed. It
|
|
117
|
+
sets `query.fitToScreen`, so shared links and saved queries fit each viewer's
|
|
118
|
+
available table area after loading and when that area changes.
|
|
119
|
+
- **Equal Widths** splits the viewport evenly.
|
|
120
|
+
- **Reset Widths** drops explicit widths back to schema defaults.
|
|
121
|
+
|
|
122
|
+
Widths live in `query.select`, so presets are shareable and undoable.
|
|
123
|
+
The fit-to-screen preference travels in the existing encoded `?q=` parameter
|
|
124
|
+
(`fs: true` in its compact payload). Manual column resizing, fitting a single
|
|
125
|
+
column, another width preset, or resetting widths clears it. Set
|
|
126
|
+
`fitToScreen: true` on an initial query to enable the same behavior directly.
|
|
127
|
+
|
|
128
|
+
## Cell quick filters
|
|
129
|
+
|
|
130
|
+
Click a text cell to open paired keep/exclude filters. Length comparisons use
|
|
131
|
+
`length > / ≤`, `length < / ≥`, and `length = / ≠`, prefilled with the clicked
|
|
132
|
+
value's Unicode code-point count.
|
|
133
|
+
|
|
134
|
+
## Reusable menus
|
|
135
|
+
|
|
136
|
+
`Menu`, `MenuButton`, `MenuGroup`, `MenuItem`, `MenuSubmenu`, and `MenuSeparator`
|
|
137
|
+
serve table header/cell actions, condition choices, and metric actions. They also
|
|
138
|
+
work independently of a table.
|
|
139
|
+
Mount a `Menu` while open, place it beneath your theme provider, and supply a
|
|
140
|
+
trigger element or viewport `{ x, y }` coordinates as its `anchor`:
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
import { useState } from "react";
|
|
144
|
+
import { Menu, MenuItem, MenuSubmenu, MenuSeparator } from "@pythia-software/query-table-ui";
|
|
145
|
+
|
|
146
|
+
function ViewActions() {
|
|
147
|
+
const [anchor, setAnchor] = useState<HTMLButtonElement | null>(null);
|
|
148
|
+
return <>
|
|
149
|
+
<button aria-haspopup="menu" aria-expanded={!!anchor}
|
|
150
|
+
onClick={event => { const trigger = event.currentTarget; setAnchor(previous => previous ? null : trigger); }}>
|
|
151
|
+
Actions
|
|
152
|
+
</button>
|
|
153
|
+
{anchor && <Menu label="View actions" anchor={anchor} onClose={() => setAnchor(null)}>
|
|
154
|
+
<MenuItem onSelect={() => copyView()}>Copy view</MenuItem>
|
|
155
|
+
<MenuSubmenu label="Export">
|
|
156
|
+
<MenuItem onSelect={() => exportCsv()}>CSV</MenuItem>
|
|
157
|
+
<MenuItem disabled>Image</MenuItem>
|
|
158
|
+
</MenuSubmenu>
|
|
159
|
+
<MenuSeparator />
|
|
160
|
+
<MenuItem tone="danger" onSelect={() => removeView()}>Remove view</MenuItem>
|
|
161
|
+
</Menu>}
|
|
162
|
+
</>;
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
For a button trigger, `MenuButton` owns open/close state, click toggling, and
|
|
167
|
+
ArrowDown/ArrowUp opening at the first/last enabled action:
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
<MenuButton label="Metric actions" trigger="⋯" width={200}
|
|
171
|
+
buttonProps={{ className: "my-trigger" }}>
|
|
172
|
+
<MenuItem onSelect={duplicate}>Duplicate</MenuItem>
|
|
173
|
+
<MenuItem disabled={!canMove} onSelect={move}>Move up</MenuItem>
|
|
174
|
+
<MenuSeparator />
|
|
175
|
+
<MenuItem tone="danger" onSelect={remove}>Remove</MenuItem>
|
|
176
|
+
</MenuButton>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
`MenuGroup` adds a labeled group. Set `columns={2}` for paired actions: horizontal
|
|
180
|
+
arrows move within a row, vertical arrows follow a column, disabled cells are
|
|
181
|
+
skipped, and vertical boundaries continue to adjacent actions. Direct action
|
|
182
|
+
children should follow visual row order. Set `checked` with
|
|
183
|
+
`selectionType="radio"` for exclusive choices; the consumer owns selected state.
|
|
184
|
+
|
|
185
|
+
Items accept `icon`, `shortcut`, `disabled`, and `textValue` for rich-content
|
|
186
|
+
typeahead labels. Set `checked` for checkbox semantics and `closeOnSelect={false}`
|
|
187
|
+
for toggles that should keep the menu open. Submenus can nest and accept `width`.
|
|
188
|
+
Actions close the whole tree; Escape and the back arrow close one level. Up/Down,
|
|
189
|
+
Home/End, typeahead, and direction-aware submenu arrows handle keyboard navigation.
|
|
190
|
+
Desktop Tab closes the menu and continues from its trigger. `returnFocus` supplies
|
|
191
|
+
a destination for coordinate menus; outside interactions keep their own focus.
|
|
192
|
+
|
|
193
|
+
Desktop menus follow element anchors, flip/shift at viewport edges, scroll when
|
|
194
|
+
long, and portal outside clipping containers. Within a dialog, they remain inside
|
|
195
|
+
its focus trap. Coordinate menus dismiss on external scrolling. Mouse travel across
|
|
196
|
+
submenu gaps uses a safe corridor; only one child submenu opens at each level.
|
|
197
|
+
Phones use the shared focus-trapping sheet with expandable inline submenus.
|
|
198
|
+
|
|
199
|
+
Scoped `--qt-*` variables, font family, color scheme, and text direction propagate
|
|
200
|
+
through portals, including theme changes while open. Optional tokens are
|
|
201
|
+
`--qt-menu-bg`, `--qt-menu-border`, `--qt-menu-radius`, `--qt-menu-shadow`, and
|
|
202
|
+
`--qt-menu-hover`; defaults use the existing palette. `classNames` supports
|
|
203
|
+
`popover`, `submenu`, `item`, and `separator`; existing `qt-cm-*` CSS hooks remain.
|
|
204
|
+
Import `theme.css` for the standard visual and responsive behavior.
|
|
205
|
+
|
|
206
|
+
Visit the demo's `/menus` playground for nested, themed, RTL, clipped, long, and
|
|
207
|
+
dialog examples. With the demo running, `npm run test:menus` checks those behaviors
|
|
208
|
+
in Chromium and WebKit (`QT_DEMO_URL` can point to a different server).
|
|
209
|
+
|
|
210
|
+
### Forms and searchable pickers
|
|
211
|
+
|
|
212
|
+
Use `Popover` for inputs and settings. It shares menu positioning, theme,
|
|
213
|
+
dismissal, portals, and mobile sheets, with regular form Tab behavior and dialog
|
|
214
|
+
semantics. Desktop focus starts at the first enabled control; `initialFocus` can
|
|
215
|
+
supply a selector scoped to the surface. Escape restores the trigger, leaving
|
|
216
|
+
focus dismisses the popover, and outside clicks retain the clicked destination.
|
|
217
|
+
It accepts `anchor`, `label`, `onClose`, `returnFocus`, `width`, `placement`,
|
|
218
|
+
`className`, and arbitrary children. Mount it only while open:
|
|
219
|
+
|
|
220
|
+
```tsx
|
|
221
|
+
{open && trigger.current && <Popover label="View settings" anchor={trigger.current}
|
|
222
|
+
placement="bottom-end" width={280} onClose={() => setOpen(false)}>
|
|
223
|
+
<label>Name <input value={name} onChange={event => setName(event.target.value)} /></label>
|
|
224
|
+
<button onClick={() => { save(name); setOpen(false); }}>Save</button>
|
|
225
|
+
</Popover>}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Add column/filter/sort field pickers, rich filter-value pickers, and auto-refresh
|
|
229
|
+
settings use this surface. `FieldPicker` accepts an optional `anchor` (or
|
|
230
|
+
`PickerAnchor` wrapper) for floating desktop use; otherwise it stays inline on
|
|
231
|
+
desktop. With `onClose`, it becomes a dismissible sheet on mobile. Omit `onClose`
|
|
232
|
+
to keep a standalone picker inline on all screen sizes. Tag multi-select editors and
|
|
233
|
+
full workbenches use the shared modal/sheet foundation with Apply/Cancel and focus
|
|
234
|
+
containment. Native selects, expandable sections, and formula autocomplete keep
|
|
235
|
+
their respective form, disclosure, and combobox interactions.
|
|
236
|
+
|
|
13
237
|
## Tag/set filters
|
|
14
238
|
|
|
15
239
|
Set `filter.editor: "set"` on a `textarray` field to use the native WHERE
|
|
@@ -68,6 +292,14 @@ export function OrdersTable({ table, schema }) {
|
|
|
68
292
|
}
|
|
69
293
|
```
|
|
70
294
|
|
|
295
|
+
`QueryBuilder` has an inline **Query** label and chevron in its toolbar to fold
|
|
296
|
+
the editor. Set `defaultCollapsed` for its initial state, or use `collapsed` and
|
|
297
|
+
`onCollapsedChange` to control it from a parent. Folding keeps the current query,
|
|
298
|
+
its summary, saved-query controls, history, and run actions available; pass
|
|
299
|
+
`summary` to replace the default folded summary. The demo's Metrics and Table
|
|
300
|
+
sections fold independently through their inline labels, with metric and row
|
|
301
|
+
counts visible in their headers and 44px touch targets on small screens.
|
|
302
|
+
|
|
71
303
|
`DataTable` virtualizes body rows and uses a 600px maximum-height scroll
|
|
72
304
|
viewport by default. Set `maxHeight` to match the surrounding layout;
|
|
73
305
|
`estimateRowHeight` (37px by default) and `overscan` (8 rows) are available for
|
|
@@ -78,11 +310,34 @@ The bundled `link` renderer allows only HTTP(S), email, telephone, relative,
|
|
|
78
310
|
and fragment URLs. Applications remain responsible for validating URLs emitted
|
|
79
311
|
by custom renderers.
|
|
80
312
|
|
|
313
|
+
Pass `savedQueryControls` to `QueryBuilder` to replace its built-in saved-query
|
|
314
|
+
name/star, Update action, and Saved menu with host-owned React controls; omitting
|
|
315
|
+
the prop keeps the default interface. Use `api.saved` for persistence and loading,
|
|
316
|
+
and handle selection, save feedback, and unsaved-edit protection in your controls.
|
|
317
|
+
Share and query history remain available. The demo's `/saved-queries` route shows
|
|
318
|
+
an integrated prototype of this slot.
|
|
319
|
+
|
|
81
320
|
The query builder's **Share** button copies a URL containing the complete
|
|
82
321
|
current query, including a saved default query. Configure `useQueryTable` with
|
|
83
322
|
`syncUrl: true` so recipients load shared query URLs. Query tokens are encoded,
|
|
84
323
|
not encrypted, and may contain raw filter values.
|
|
85
324
|
|
|
325
|
+
Pass `selection={table.selection}` to enable row checkboxes with editable ranges:
|
|
326
|
+
|
|
327
|
+
- Click a checkbox to toggle it and start a new range, preserving prior checks.
|
|
328
|
+
- Shift-click to grow or shrink the range from its fixed starting row. Starting
|
|
329
|
+
by unchecking a row makes Shift-click uncheck the range instead.
|
|
330
|
+
- Ctrl/Cmd-click toggles one checkbox; Ctrl/Cmd+Shift-click adds the span while
|
|
331
|
+
preserving every existing check.
|
|
332
|
+
- Space toggles the focused checkbox; Shift+Space adjusts the range, with
|
|
333
|
+
Ctrl/Cmd+Shift+Space available for an additive span.
|
|
334
|
+
|
|
335
|
+
For example, click 2, Shift-click 4, click 8, Shift-click 12, then Shift-click 10
|
|
336
|
+
to select rows 2–4 and 8–10. Shrinking an overlapping range preserves checks that
|
|
337
|
+
existed before it began. Ranges follow the current page's displayed order,
|
|
338
|
+
including virtualized rows, and reset when that order changes. The header
|
|
339
|
+
checkbox selects or clears the current page and starts a fresh range context.
|
|
340
|
+
|
|
86
341
|
`SelectionToolbar` action callbacks receive `(selectedIds, selection)`, so
|
|
87
342
|
consumer-owned bulk actions can call `selection.replace(ids)` or
|
|
88
343
|
`selection.retain(ids)` atomically. Existing callbacks that use only the first
|
|
@@ -90,6 +345,9 @@ argument remain compatible.
|
|
|
90
345
|
|
|
91
346
|
## Icons
|
|
92
347
|
|
|
348
|
+
The bundled theme aligns table-header sort arrows and priority indicators with
|
|
349
|
+
their labels for both single-column and multi-column sorts.
|
|
350
|
+
|
|
93
351
|
`Icon` is the shared, hand-drawn SVG set used throughout the UI and demo. Its
|
|
94
352
|
24px grid, rounded 1.8px strokes, and `currentColor` styling keep controls
|
|
95
353
|
cohesive without forcing every shape into the same silhouette. Drag handles
|
|
@@ -116,8 +374,9 @@ touch-based landscape viewports use a mobile interaction model:
|
|
|
116
374
|
- **Tap to edit or delete:** filters, sorts, and metrics become readable summaries
|
|
117
375
|
with pencil buttons. Remove actions live inside the editor, including removal
|
|
118
376
|
of an entire OR group, and support Undo. There are no inline trash buttons.
|
|
119
|
-
Adding a filter
|
|
120
|
-
|
|
377
|
+
Adding a filter or metric opens its editor. Add sort lets you choose a field,
|
|
378
|
+
then ascending or descending before committing; Back returns to the same field search.
|
|
379
|
+
Filters can be combined with OR without relying on drag-and-drop.
|
|
121
380
|
- **Direct ordering:** columns, sorts, and metrics have leading drag handles
|
|
122
381
|
directly in the query builder, with no Order buttons. Column chips stay
|
|
123
382
|
wrapped and can move horizontally or between rows. Keyboard arrow keys reorder
|
|
@@ -138,20 +397,20 @@ touch-based landscape viewports use a mobile interaction model:
|
|
|
138
397
|
padding and redundant headings. Query chips, their buttons, and inline handles
|
|
139
398
|
use a 32px minimum height with zero vertical padding; long summaries can wrap.
|
|
140
399
|
Filter, sort, and metric inputs use 36px controls. Keyword sections have extra breathing room
|
|
141
|
-
|
|
400
|
+
without divider lines between clauses on desktop and mobile.
|
|
142
401
|
- **Dense query setup:** filter, sort, and metric actions share a section header.
|
|
143
402
|
Summaries use one line when space allows and wrap without truncating values.
|
|
144
403
|
Labeled condition/value and function/measure pairs replace wrapping desktop
|
|
145
404
|
chips. Sort direction and null-value placement use native selects; regex
|
|
146
|
-
extraction stays optional. Its configuration opens a dialog (a bottom sheet on small screens) with a live, worker-isolated preview of up to 100 matching rows. The preview shows original values, extracted sort values, and no-match/null states; Apply commits any syntactically valid pattern even when the preview is unavailable or still loading, while Cancel leaves the sort unchanged. Grouping uses removable tags and a field picker.
|
|
405
|
+
extraction stays optional. It is available from Add sort's field options or its detailed-sort caret, with direction configurable in the dialog. Plain desktop sort chips omit the extraction action; configured extractions remain editable. Its configuration opens a dialog (a bottom sheet on small screens) with a live, worker-isolated preview of up to 100 matching rows. The preview shows original values, extracted sort values, and no-match/null states; Apply commits any syntactically valid pattern even when the preview is unavailable or still loading, while Cancel leaves the sort unchanged. Grouping uses removable tags and a field picker.
|
|
147
406
|
Simple metric results share two-column rows; grouped results use the full width.
|
|
148
407
|
- **Touch-first controls:** dedicated drag handles, 16px text inputs,
|
|
149
408
|
sticky bulk actions, a horizontal table scroll cue, and the device's native
|
|
150
409
|
share sheet when available (clipboard fallback otherwise).
|
|
151
410
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
411
|
+
Filter and sort edits update the query immediately; **Done** dismisses the sheet. The column and metric workbenches retain explicit **Apply** draft workflows. Desktop chips, popovers, and drag-and-drop remain available.
|
|
412
|
+
|
|
413
|
+
In compact mode, **Add offset** reveals and focuses the inline offset input without changing the query. Enter or blur commits the value; the clear action returns to **Add offset**.
|
|
155
414
|
|
|
156
415
|
Keep the standard viewport meta tag in the host page:
|
|
157
416
|
|
|
@@ -173,7 +432,37 @@ for customization and backend integration details.
|
|
|
173
432
|
|
|
174
433
|
## SELECT editor
|
|
175
434
|
|
|
176
|
-
`QueryBuilder` includes a split **Add** button and **Reset** action for Columns: Add opens the field picker, while its caret opens the column customizer. Actions follow the selected chips on desktop and sit in the section header on small screens. The exported `SelectColumnEditor` also accepts `{ api, onClose }` for standalone use. It supports draft column ordering, a searchable catalogue, sampled value frequencies, and a lazy-loaded
|
|
435
|
+
`QueryBuilder` includes a split **Add** button and **Reset** action for Columns: Add opens the field picker, while its caret opens the column customizer. Actions follow the selected chips on desktop and sit in the section header on small screens. The exported `SelectColumnEditor` also accepts `{ api, onClose }` for standalone use. It supports draft column ordering, a searchable catalogue, sampled value frequencies, and a lazy-loaded, dependency-free textarea formula editor with field/function suggestions, signature help, and compiler diagnostics with grouped live previews and regex inspection. A Function library beside the editor supports search by name or intent, browsing by concept and return type, and insertion at the cursor or around selected text; it stacks below the editor on narrow screens. Shared-definition saves and query-layout application are separate actions.
|
|
436
|
+
|
|
437
|
+
### Shared editor components
|
|
438
|
+
|
|
439
|
+
`EditorModal`, `useEditorWorkbench`, `EditorPanelToggle`, and
|
|
440
|
+
`EditorPanelSeparator` provide the shared shell and panel geometry used by the
|
|
441
|
+
metric editor and the grouped column editor. The hook accepts a
|
|
442
|
+
fixed list of `{ width, minWidth, defaultVisible? }` panel sizes in pixels. Attach `root` to the
|
|
443
|
+
workspace, build its grid from `visibleIndices` and `widths` with 6px separators,
|
|
444
|
+
and hide panels with `visiblePanes`. The modal wires the header and Reset layout;
|
|
445
|
+
its `panelControls` slot places panel toggles beside Reset layout. Pass the same
|
|
446
|
+
workbench to panel toggles and separators. Reset restores dialog/pane sizes and
|
|
447
|
+
each panel's current `defaultVisible` setting (true when omitted). Defaults can
|
|
448
|
+
follow the selected column; changing them alone does not override manual toggles.
|
|
449
|
+
Separators support
|
|
450
|
+
pointer drag, arrow keys (Shift for larger steps), Home/double-click reset, and
|
|
451
|
+
Escape to cancel a drag. Toggles keep at least one panel open. Geometry stays
|
|
452
|
+
separate from query drafts; the consumer owns draft validation, Apply/Cancel,
|
|
453
|
+
panel contents, and responsive section navigation.
|
|
454
|
+
|
|
455
|
+
`FormulaEditor` is also exported for reuse. Supply `value`, `onChange`, `fields`,
|
|
456
|
+
and `compile`; an optional `functions` catalogue drives completions, signature
|
|
457
|
+
help, and the Function library. Row formulas use `FORMULA_FUNCTIONS` by default.
|
|
458
|
+
Aggregate editors can combine core's `METRIC_FUNCTIONS` and `FORMULA_FUNCTIONS`
|
|
459
|
+
with `compileMetric`, including `MEDIAN`. A catalogue describes available
|
|
460
|
+
functions; the supplied compiler determines which expressions are valid.
|
|
461
|
+
For a separate function panel, set `showLibrary={false}` and connect the exported
|
|
462
|
+
`FormulaFunctionBrowser` with `variant="panel"` to the editor's
|
|
463
|
+
`actionsRef.current.insertFunction(name)`. This preserves cursor/selection and
|
|
464
|
+
native text undo. Omitting the browser's `onInsert` makes it a reference-only
|
|
465
|
+
library when no formula is selected.
|
|
177
466
|
|
|
178
467
|
### Filter value presentation
|
|
179
468
|
|
|
@@ -196,3 +485,88 @@ The searchable static picker matches both labels and keys. Selection emits the
|
|
|
196
485
|
canonical `value` only; presentation is never serialized into queries. A resolver
|
|
197
486
|
can present a current value even when it is absent from the options. Strings without
|
|
198
487
|
a presentation provider retain the existing select control.
|
|
488
|
+
|
|
489
|
+
## Metric workbench and dashboards
|
|
490
|
+
|
|
491
|
+
QueryBuilder offers **Add metric** while the query has no metrics. Once metrics exist, editing moves to the always-visible **Edit** button in `MetricsPanel`, which opens the resizable four-pane `MetricsEditor`. Apply commits drafts together; Cancel discards them. Dashboard layout provides draggable canvas widths, whole-rem card sizing through corner handles or inputs, canvas presets, pointer/keyboard reordering, and inline names. Metrics use their own workbench on desktop and compact viewports; their changes commit on Apply.
|
|
492
|
+
|
|
493
|
+
Use the icon buttons beside **Panels** in the modal header to show or hide the metric list, definition, references, and preview. At least one panel stays visible; the metric picker and Previous/Next controls remain available when the list is hidden. **See in dashboard** reveals the selected card in the same draft; **Back to metric**, the card’s pencil action, or a double-click returns to editing. Open settings and panel preferences survive these transitions.
|
|
494
|
+
|
|
495
|
+
Drag the dashboard canvas’s right edge to test responsive wrapping. Card corner handles adjust preferred width and height in whole rems; arrow keys resize and Shift increases the step. Escape or a cancelled pointer gesture restores the dimensions at drag start. Canvas and panel geometry are temporary preferences; card geometry commits on Apply. Removal offers **Undo remove**, and **Review issues** opens the metric needing attention while valid metrics continue to preview.
|
|
496
|
+
|
|
497
|
+
Use **Dialog size** for keyboard-editable pixel width/height controls; the native resize corner remains available. **Reset layout** restores the modal and all pane widths without changing metric drafts. Card minimum widths apply equally in the layout canvas and saved dashboard; narrower containers scroll horizontally.
|
|
498
|
+
|
|
499
|
+
**Value** requires no grouping. Incompatible drafts show an actionable diagnostic and block Apply; standalone `MetricCard` also rejects grouped or multiple scalar buckets. Lists suppress magnitude bars for signed results. Charts visibly disclose missing/error points and drawing limits while keeping ordinary captions compact. Malformed remote box/histogram summaries produce a card-local diagnostic instead of throwing during rendering.
|
|
500
|
+
|
|
501
|
+
`MetricsPanel` renders values, lists, pivots/flat tables, bars, lines, pie/ring, scatter, box, and histogram cards through native SVG and accessible data tables/tooltips. Pass a `MetricTheme` as `metricTheme` to QueryBuilder and `theme` to MetricsPanel for consistent typed-category palette assignments. Labels, temporal units/patterns, legends, list styling, axis labels, and card dimensions are query-local. `MetricCard` and `MetricsEditor` are also exported for standalone integration.
|
|
502
|
+
|
|
503
|
+
See [the production metrics guide](../../docs/metrics.md). Run `npm run test:metrics` against the demo for authoring/layout/persistence and chart interactions.
|
|
504
|
+
|
|
505
|
+
## Cell displays
|
|
506
|
+
|
|
507
|
+
Set `FieldDef.display` for built-in JSON, date/time, duration, number/percent,
|
|
508
|
+
text, and chip presentation. JSON cells open a searchable tree with nested paths
|
|
509
|
+
and original/decoded copying; objects, JSON strings and escaped strings share
|
|
510
|
+
the same inspector. Custom `render` functions and registered keys take precedence.
|
|
511
|
+
Detail properties inherit these displays and embed initially collapsed JSON
|
|
512
|
+
trees in popovers, modals, and expanded rows. A button beside the property label
|
|
513
|
+
opens the full viewer with filter/highlight search, match navigation, and copy
|
|
514
|
+
controls. JSON property options can be edited, saved, and shared through the
|
|
515
|
+
existing property-view controls.
|
|
516
|
+
See the [cell display guide](../../docs/cell-displays.md) for typed configuration,
|
|
517
|
+
units, examples, and inspection limits. `JsonCell` and the embedded `JsonValueView`
|
|
518
|
+
are also exported for standalone use.
|
|
519
|
+
|
|
520
|
+
## Compact metric covers
|
|
521
|
+
|
|
522
|
+
`<MetricCard compact clause={clause} result={result} fields={fields} />` uses
|
|
523
|
+
sparse round numeric ticks and short unit labels for a small chart. Calendar
|
|
524
|
+
charts keep the computation timezone and use sparse local calendar boundaries;
|
|
525
|
+
bar timelines render chronologically. This is a rendering option, so saved query
|
|
526
|
+
formats and full data values are unchanged. Explicit axis bounds are respected.
|
|
527
|
+
|
|
528
|
+
Compact Cartesian charts put both axis titles below the plot on one line,
|
|
529
|
+
with ↑ for the vertical axis and → for the horizontal axis. The compact plot
|
|
530
|
+
reserves only the tick gutter, allowing more width for data. Full charts retain
|
|
531
|
+
their usual title placement. Metric loading uses an accessible spinner and
|
|
532
|
+
respects reduced-motion preferences.
|
|
533
|
+
|
|
534
|
+
Compact box plots label each row above its glyph and show its median. Each row
|
|
535
|
+
uses an independent linear scale focused on its whiskers, omitting outlier
|
|
536
|
+
markers. A visible guide explains that the box spans the middle 50%, the line
|
|
537
|
+
marks the median, and scales differ between rows. Full statistics and outlier
|
|
538
|
+
counts remain in accessible mark descriptions and the data table. Allow at least
|
|
539
|
+
52px per plotted row plus the guide; constrain the supplied bucket count when
|
|
540
|
+
using a fixed-height cover. The default full chart retains its shared scale.
|
|
541
|
+
|
|
542
|
+
### Underline list bars
|
|
543
|
+
|
|
544
|
+
Use `display: { kind: "list", list: { barPosition: "below" } }` to put a thin
|
|
545
|
+
bar under each label and value. Labels wrap across the available row instead of
|
|
546
|
+
being ellipsized in a narrow column. The default `"inline"` layout keeps the bar
|
|
547
|
+
beside the label. The metric editor exposes both under **Bar placement**. This
|
|
548
|
+
setting survives query links and saved views; it does not change computation,
|
|
549
|
+
sort order, values, or the `showBars` / `showValues` switches.
|
|
550
|
+
|
|
551
|
+
Set `display.list.maxLabelLines` to a positive integer to cap the wrapped label
|
|
552
|
+
height when `barPosition` is `"below"`, for example
|
|
553
|
+
`list: { barPosition: "below", maxLabelLines: 2 }`. Omit it for unlimited lines;
|
|
554
|
+
the editor's **Maximum label lines** input accepts a blank value for unlimited.
|
|
555
|
+
The limit has no effect on inline bars. Truncated labels keep their full text in
|
|
556
|
+
the tooltip, and the limit survives query links and saved views.
|
|
557
|
+
|
|
558
|
+
### Visible groups and remainder
|
|
559
|
+
|
|
560
|
+
`display.maxGroups` caps displayed groups in result order without changing the
|
|
561
|
+
metric computation or its server `groupLimit`. It is a positive integer, and
|
|
562
|
+
the editor exposes it as **Maximum displayed groups**. Omission retains the
|
|
563
|
+
automatic layout limits (for example eight pie slices and six histogram series).
|
|
564
|
+
|
|
565
|
+
`display.showOther` controls the synthetic remainder in pie/donut charts
|
|
566
|
+
(default true) and lists (default false). Lists combine only exact additive
|
|
567
|
+
counts or sums, with complete results or an exact server remainder. Averages,
|
|
568
|
+
rates, missing values, and partial results never produce an invented remainder.
|
|
569
|
+
Hiding a pie remainder retains the full denominator and leaves its angular
|
|
570
|
+
share empty; it does not rescale the selected groups to 100%. A real group named
|
|
571
|
+
Other remains visible. Both settings survive query links and saved views.
|
|
572
|
+
Use `display.legendPosition: "none"` to hide the chart key.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|