@pythia-software/query-table-ui 0.3.0 → 0.4.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/dist/index.js CHANGED
@@ -138,15 +138,69 @@ function formatRelative(iso) {
138
138
 
139
139
  // src/DataTable.tsx
140
140
  import { isComputedCellError } from "@pythia-software/query-table-core";
141
- import { useCallback, useEffect as useEffect2, useMemo, useRef, useState as useState2 } from "react";
141
+ import { useCallback, useEffect as useEffect2, useMemo, useRef, useState as useState3 } from "react";
142
142
  import { useVirtualizer } from "@tanstack/react-virtual";
143
143
  import { isSortable, readFieldValue } from "@pythia-software/query-table-core";
144
144
  import { useColumnDrag } from "@pythia-software/query-table-react";
145
145
 
146
+ // src/FilterValuePresentation.tsx
147
+ import { createContext, useContext, useState } from "react";
148
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
149
+ var Context = createContext({});
150
+ var FilterValueProvider = Context.Provider;
151
+ function useFilterValuePresentation() {
152
+ return useContext(Context);
153
+ }
154
+ function PresentedFilterValue({ field, value }) {
155
+ const presentation = useContext(Context);
156
+ return /* @__PURE__ */ jsx(Fragment, { children: presentation.render?.(field, value) ?? presentation.label?.(field, value) ?? value });
157
+ }
158
+ function PresentedValueInput({ field, value, options, onChange }) {
159
+ const presentation = useContext(Context);
160
+ const [open, setOpen] = useState(false), [search, setSearch] = useState("");
161
+ const choices = options.map((option) => typeof option === "string" ? { value: option, label: presentation.label?.(field, option) ?? option } : option);
162
+ const visible = choices.filter((option) => `${option.value} ${option.label}`.toLowerCase().includes(search.toLowerCase()));
163
+ return /* @__PURE__ */ jsxs("span", { style: { position: "relative" }, children: [
164
+ /* @__PURE__ */ jsxs("button", { type: "button", "aria-label": `Edit ${field} filter value`, "aria-expanded": open, onClick: () => setOpen(!open), children: [
165
+ /* @__PURE__ */ jsx(PresentedFilterValue, { field, value }),
166
+ !value && "Choose value"
167
+ ] }),
168
+ open && /* @__PURE__ */ jsxs("span", { style: { position: "absolute", top: "100%", left: 0, zIndex: 30, background: "var(--qt-bg, #fff)", padding: 8, minWidth: 220, maxHeight: 300, overflowY: "auto" }, onKeyDown: (e) => {
169
+ if (e.key === "Escape") setOpen(false);
170
+ }, children: [
171
+ /* @__PURE__ */ jsx("input", { autoFocus: true, "aria-label": `Search ${field} values`, value: search, onChange: (e) => setSearch(e.target.value), onKeyDown: (e) => {
172
+ if (e.key === "Enter" && search) {
173
+ e.preventDefault();
174
+ onChange(search);
175
+ setOpen(false);
176
+ }
177
+ } }),
178
+ visible.map((option) => /* @__PURE__ */ jsxs("button", { type: "button", style: { display: "block" }, onClick: () => {
179
+ onChange(option.value);
180
+ setOpen(false);
181
+ }, children: [
182
+ /* @__PURE__ */ jsx(PresentedFilterValue, { field, value: option.value }),
183
+ option.label !== option.value && /* @__PURE__ */ jsxs("small", { children: [
184
+ " ",
185
+ option.value
186
+ ] })
187
+ ] }, option.value)),
188
+ search && !choices.some((option) => option.value === search) && /* @__PURE__ */ jsxs("button", { type: "button", onClick: () => {
189
+ onChange(search);
190
+ setOpen(false);
191
+ }, children: [
192
+ "Use \u201C",
193
+ search,
194
+ "\u201D"
195
+ ] })
196
+ ] })
197
+ ] });
198
+ }
199
+
146
200
  // src/CellMenu.tsx
147
201
  import { useEffect } from "react";
148
202
  import { NULLARY_OPS, negateClause, opsForField, opPairsForField, isFilterable } from "@pythia-software/query-table-core";
149
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
203
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
150
204
  var cx = (...parts) => parts.filter(Boolean).join(" ");
151
205
  var MENU_WIDTH = 320;
152
206
  var ROW_HEIGHT = 32;
@@ -196,7 +250,7 @@ function CellMenu({ field, value, x, y, onAddFilter, onClose, classNames }) {
196
250
  const approxRows = 3 + rows.length;
197
251
  const left = Math.max(8, Math.min(x + POINTER_OFFSET, vw - MENU_WIDTH - 8));
198
252
  const top = Math.max(8, Math.min(y + POINTER_OFFSET, vh - ROW_HEIGHT * approxRows - 8));
199
- return /* @__PURE__ */ jsxs(
253
+ return /* @__PURE__ */ jsxs2(
200
254
  "div",
201
255
  {
202
256
  className: cx("qt-cell-menu", classNames?.popover),
@@ -205,11 +259,11 @@ function CellMenu({ field, value, x, y, onAddFilter, onClose, classNames }) {
205
259
  onContextMenu: (e) => e.preventDefault(),
206
260
  role: "menu",
207
261
  children: [
208
- /* @__PURE__ */ jsxs("div", { className: "qt-cm-header", children: [
209
- /* @__PURE__ */ jsx("span", { className: "qt-cm-field", children: field.label }),
210
- /* @__PURE__ */ jsx("span", { className: "qt-cm-value", children: previewValue(value) })
262
+ /* @__PURE__ */ jsxs2("div", { className: "qt-cm-header", children: [
263
+ /* @__PURE__ */ jsx2("span", { className: "qt-cm-field", children: field.label }),
264
+ /* @__PURE__ */ jsx2("span", { className: "qt-cm-value", children: Array.isArray(value) ? value.map((v) => /* @__PURE__ */ jsx2(PresentedFilterValue, { field: field.name, value: String(v) }, String(v))) : /* @__PURE__ */ jsx2(PresentedFilterValue, { field: field.name, value: String(value ?? "") }) })
211
265
  ] }),
212
- /* @__PURE__ */ jsx(
266
+ /* @__PURE__ */ jsx2(
213
267
  MenuItem,
214
268
  {
215
269
  classNames,
@@ -223,11 +277,11 @@ function CellMenu({ field, value, x, y, onAddFilter, onClose, classNames }) {
223
277
  children: "copy value"
224
278
  }
225
279
  ),
226
- /* @__PURE__ */ jsx("div", { className: cx("qt-cm-sep", classNames?.separator) }),
227
- rows.length > 0 && /* @__PURE__ */ jsxs("div", { className: "qt-cm-filter-grid", role: "group", "aria-label": "Filter by this cell", children: [
228
- /* @__PURE__ */ jsx("span", { className: "qt-cm-col-head", children: "keep" }),
229
- /* @__PURE__ */ jsx("span", { className: "qt-cm-col-head qt-cm-col-head--neg", children: "exclude" }),
230
- rows.map((row, i) => /* @__PURE__ */ jsx(FilterPairRow, { row, value, classNames, onApply: applyClause }, i))
280
+ /* @__PURE__ */ jsx2("div", { className: cx("qt-cm-sep", classNames?.separator) }),
281
+ rows.length > 0 && /* @__PURE__ */ jsxs2("div", { className: "qt-cm-filter-grid", role: "group", "aria-label": "Filter by this cell", children: [
282
+ /* @__PURE__ */ jsx2("span", { className: "qt-cm-col-head", children: "keep" }),
283
+ /* @__PURE__ */ jsx2("span", { className: "qt-cm-col-head qt-cm-col-head--neg", children: "exclude" }),
284
+ rows.map((row, i) => /* @__PURE__ */ jsx2(FilterPairRow, { row, value, classNames, onApply: applyClause }, i))
231
285
  ] })
232
286
  ]
233
287
  }
@@ -239,9 +293,9 @@ function FilterPairRow({
239
293
  classNames,
240
294
  onApply
241
295
  }) {
242
- return /* @__PURE__ */ jsxs(Fragment, { children: [
243
- /* @__PURE__ */ jsx(FilterButton, { clause: row.positive, value, classNames, onApply }),
244
- /* @__PURE__ */ jsx(FilterButton, { clause: row.negative, value, negative: true, classNames, onApply })
296
+ return /* @__PURE__ */ jsxs2(Fragment2, { children: [
297
+ /* @__PURE__ */ jsx2(FilterButton, { clause: row.positive, value, classNames, onApply }),
298
+ /* @__PURE__ */ jsx2(FilterButton, { clause: row.negative, value, negative: true, classNames, onApply })
245
299
  ] });
246
300
  }
247
301
  function FilterButton({
@@ -251,9 +305,9 @@ function FilterButton({
251
305
  classNames,
252
306
  onApply
253
307
  }) {
254
- if (!clause) return /* @__PURE__ */ jsx("span", { className: "qt-cm-filter-empty", "aria-hidden": true });
308
+ if (!clause) return /* @__PURE__ */ jsx2("span", { className: "qt-cm-filter-empty", "aria-hidden": true });
255
309
  const nullary = NULLARY_OPS.has(clause.op);
256
- return /* @__PURE__ */ jsxs(
310
+ return /* @__PURE__ */ jsxs2(
257
311
  "button",
258
312
  {
259
313
  type: "button",
@@ -261,10 +315,10 @@ function FilterButton({
261
315
  onClick: () => onApply(clause),
262
316
  role: "menuitem",
263
317
  children: [
264
- /* @__PURE__ */ jsx("span", { className: "qt-cm-op", children: predicateSymbol(clause) }),
265
- !nullary ? /* @__PURE__ */ jsxs(Fragment, { children: [
318
+ /* @__PURE__ */ jsx2("span", { className: "qt-cm-op", children: predicateSymbol(clause) }),
319
+ !nullary ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
266
320
  " ",
267
- /* @__PURE__ */ jsx("code", { children: previewValue(value) })
321
+ /* @__PURE__ */ jsx2("code", { children: /* @__PURE__ */ jsx2(PresentedFilterValue, { field: clause.field, value: clause.value }) })
268
322
  ] }) : null
269
323
  ]
270
324
  }
@@ -275,7 +329,7 @@ function MenuItem({
275
329
  onClick,
276
330
  classNames
277
331
  }) {
278
- return /* @__PURE__ */ jsx("button", { type: "button", className: cx("qt-cm-item", classNames?.item), onClick, role: "menuitem", children });
332
+ return /* @__PURE__ */ jsx2("button", { type: "button", className: cx("qt-cm-item", classNames?.item), onClick, role: "menuitem", children });
279
333
  }
280
334
  function predicateSymbol(clause) {
281
335
  const base = opSymbol(clause.op);
@@ -310,17 +364,9 @@ function valueToString(v) {
310
364
  if (Array.isArray(v)) return v.join(", ");
311
365
  return String(v);
312
366
  }
313
- function previewValue(v) {
314
- if (v == null || v === "") return "(empty)";
315
- if (Array.isArray(v)) {
316
- return v.length === 0 ? "(empty)" : `[${v.length}] ${v.slice(0, 2).join(", ")}${v.length > 2 ? "\u2026" : ""}`;
317
- }
318
- const s = String(v);
319
- return s.length > 50 ? s.slice(0, 50) + "\u2026" : s;
320
- }
321
367
 
322
368
  // src/DataTable.tsx
323
- import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
369
+ import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
324
370
  var cx2 = (...parts) => parts.filter((p) => Boolean(p)).join(" ");
325
371
  var MIN_WIDTH = 1;
326
372
  var MIN_SELECTION_WIDTH = 1;
@@ -354,12 +400,12 @@ function DataTable(props) {
354
400
  overscan = DEFAULT_OVERSCAN,
355
401
  classNames
356
402
  } = props;
357
- const [menu, setMenu] = useState2(null);
358
- const [selectionColumnWidth, setSelectionColumnWidth] = useState2(DEFAULT_SELECTION_WIDTH);
359
- const [tableColumnOrder, setTableColumnOrder] = useState2([]);
360
- const [copiedCellKey, setCopiedCellKey] = useState2(null);
361
- const [headerHeight, setHeaderHeight] = useState2(0);
362
- const [showHorizontalCue, setShowHorizontalCue] = useState2(false);
403
+ const [menu, setMenu] = useState3(null);
404
+ const [selectionColumnWidth, setSelectionColumnWidth] = useState3(DEFAULT_SELECTION_WIDTH);
405
+ const [tableColumnOrder, setTableColumnOrder] = useState3([]);
406
+ const [copiedCellKey, setCopiedCellKey] = useState3(null);
407
+ const [headerHeight, setHeaderHeight] = useState3(0);
408
+ const [showHorizontalCue, setShowHorizontalCue] = useState3(false);
363
409
  const tableWrapRef = useRef(null);
364
410
  const tableHeadRef = useRef(null);
365
411
  const tableRef = useRef(null);
@@ -687,7 +733,7 @@ function DataTable(props) {
687
733
  }
688
734
  }
689
735
  function resizeHandle(name, label, width) {
690
- return /* @__PURE__ */ jsx2(
736
+ return /* @__PURE__ */ jsx3(
691
737
  "span",
692
738
  {
693
739
  className: cx2("qt-resize-handle", classNames?.resizeHandle),
@@ -735,12 +781,12 @@ function DataTable(props) {
735
781
  const lastVirtualRow = virtualRows[virtualRows.length - 1];
736
782
  const paddingTop = firstVirtualRow ? Math.max(0, firstVirtualRow.start - headerHeight) : 0;
737
783
  const paddingBottom = lastVirtualRow ? Math.max(0, rowVirtualizer.getTotalSize() - (lastVirtualRow.end - headerHeight)) : 0;
738
- return /* @__PURE__ */ jsxs2(Fragment2, { children: [
739
- showHorizontalCue ? /* @__PURE__ */ jsxs2("div", { className: "qt-table-scroll-cue", "aria-hidden": "true", children: [
784
+ return /* @__PURE__ */ jsxs3(Fragment3, { children: [
785
+ showHorizontalCue ? /* @__PURE__ */ jsxs3("div", { className: "qt-table-scroll-cue", "aria-hidden": "true", children: [
740
786
  "Swipe to see more ",
741
- /* @__PURE__ */ jsx2("span", { children: "\u2192" })
787
+ /* @__PURE__ */ jsx3("span", { children: "\u2192" })
742
788
  ] }) : null,
743
- /* @__PURE__ */ jsxs2(
789
+ /* @__PURE__ */ jsxs3(
744
790
  "div",
745
791
  {
746
792
  ref: tableWrapRef,
@@ -760,8 +806,8 @@ function DataTable(props) {
760
806
  "aria-label": "Scrollable data table",
761
807
  tabIndex: 0,
762
808
  children: [
763
- loading && /* @__PURE__ */ jsx2("div", { className: cx2("qt-loading-bar", classNames?.loadingBar), role: "progressbar", "aria-label": "loading" }),
764
- /* @__PURE__ */ jsx2(
809
+ loading && /* @__PURE__ */ jsx3("div", { className: cx2("qt-loading-bar", classNames?.loadingBar), role: "progressbar", "aria-label": "loading" }),
810
+ /* @__PURE__ */ jsx3(
765
811
  "div",
766
812
  {
767
813
  ref: resizeGuideRef,
@@ -769,21 +815,21 @@ function DataTable(props) {
769
815
  "aria-hidden": "true"
770
816
  }
771
817
  ),
772
- /* @__PURE__ */ jsxs2("table", { ref: tableRef, className: cx2("qt-table", classNames?.table), style: { minWidth: tableWidth }, children: [
773
- /* @__PURE__ */ jsxs2("colgroup", { children: [
818
+ /* @__PURE__ */ jsxs3("table", { ref: tableRef, className: cx2("qt-table", classNames?.table), style: { minWidth: tableWidth }, children: [
819
+ /* @__PURE__ */ jsxs3("colgroup", { children: [
774
820
  renderedColumnNames.map((name) => {
775
821
  const f = fieldByName.get(name);
776
822
  const w = displayColumnWidthFor(name, f);
777
- if (name === SELECTION_COLUMN) return /* @__PURE__ */ jsx2("col", { "data-qt-column": name, style: { width: w } }, name);
823
+ if (name === SELECTION_COLUMN) return /* @__PURE__ */ jsx3("col", { "data-qt-column": name, style: { width: w } }, name);
778
824
  if (!f) return null;
779
- return /* @__PURE__ */ jsx2("col", { "data-qt-column": f.name, style: { width: w } }, f.name);
825
+ return /* @__PURE__ */ jsx3("col", { "data-qt-column": f.name, style: { width: w } }, f.name);
780
826
  }),
781
- trailing && /* @__PURE__ */ jsx2("col", { style: { width: 40 } })
827
+ trailing && /* @__PURE__ */ jsx3("col", { style: { width: 40 } })
782
828
  ] }),
783
- /* @__PURE__ */ jsx2("thead", { ref: tableHeadRef, className: classNames?.thead, children: /* @__PURE__ */ jsxs2("tr", { className: classNames?.headerRow, children: [
829
+ /* @__PURE__ */ jsx3("thead", { ref: tableHeadRef, className: classNames?.thead, children: /* @__PURE__ */ jsxs3("tr", { className: classNames?.headerRow, children: [
784
830
  renderedColumnNames.map((name) => {
785
831
  if (name === SELECTION_COLUMN) {
786
- return /* @__PURE__ */ jsxs2(
832
+ return /* @__PURE__ */ jsxs3(
787
833
  "th",
788
834
  {
789
835
  "data-qt-field": name,
@@ -827,7 +873,7 @@ function DataTable(props) {
827
873
  },
828
874
  onDragEnd: () => columnDrag.end(),
829
875
  children: [
830
- /* @__PURE__ */ jsx2(
876
+ /* @__PURE__ */ jsx3(
831
877
  "input",
832
878
  {
833
879
  type: "checkbox",
@@ -849,7 +895,7 @@ function DataTable(props) {
849
895
  if (!f) return null;
850
896
  const info = sortInfo(f);
851
897
  const sortable = isSortable(f);
852
- return /* @__PURE__ */ jsxs2(
898
+ return /* @__PURE__ */ jsxs3(
853
899
  "th",
854
900
  {
855
901
  "data-qt-field": f.name,
@@ -893,7 +939,7 @@ function DataTable(props) {
893
939
  },
894
940
  onDragEnd: () => columnDrag.end(),
895
941
  children: [
896
- /* @__PURE__ */ jsxs2(
942
+ /* @__PURE__ */ jsxs3(
897
943
  "span",
898
944
  {
899
945
  className: "qt-th-label",
@@ -902,9 +948,9 @@ function DataTable(props) {
902
948
  title: "Click to open column actions",
903
949
  children: [
904
950
  f.label,
905
- info && /* @__PURE__ */ jsxs2("span", { className: "qt-sort-indicator", children: [
951
+ info && /* @__PURE__ */ jsxs3("span", { className: "qt-sort-indicator", children: [
906
952
  info.dir === "asc" ? " \u2191" : " \u2193",
907
- info.priority != null && /* @__PURE__ */ jsx2("sup", { className: "qt-sort-priority", children: info.priority })
953
+ info.priority != null && /* @__PURE__ */ jsx3("sup", { className: "qt-sort-priority", children: info.priority })
908
954
  ] })
909
955
  ]
910
956
  }
@@ -915,17 +961,17 @@ function DataTable(props) {
915
961
  f.name
916
962
  );
917
963
  }),
918
- trailing && /* @__PURE__ */ jsx2("th", { className: cx2("qt-th", classNames?.th), children: trailingLabel ?? "" })
964
+ trailing && /* @__PURE__ */ jsx3("th", { className: cx2("qt-th", classNames?.th), children: trailingLabel ?? "" })
919
965
  ] }) }),
920
- /* @__PURE__ */ jsxs2("tbody", { className: classNames?.tbody, children: [
921
- rows.length === 0 && /* @__PURE__ */ jsx2("tr", { children: /* @__PURE__ */ jsx2("td", { colSpan: totalCols, className: cx2("qt-cell", "qt-empty", classNames?.empty), children: emptyMessage ?? "No rows." }) }),
922
- paddingTop > 0 && /* @__PURE__ */ jsx2("tr", { className: "qt-virtual-spacer", "aria-hidden": "true", children: /* @__PURE__ */ jsx2("td", { colSpan: totalCols, style: { height: paddingTop, padding: 0, border: 0 } }) }),
966
+ /* @__PURE__ */ jsxs3("tbody", { className: classNames?.tbody, children: [
967
+ rows.length === 0 && /* @__PURE__ */ jsx3("tr", { children: /* @__PURE__ */ jsx3("td", { colSpan: totalCols, className: cx2("qt-cell", "qt-empty", classNames?.empty), children: emptyMessage ?? "No rows." }) }),
968
+ paddingTop > 0 && /* @__PURE__ */ jsx3("tr", { className: "qt-virtual-spacer", "aria-hidden": "true", children: /* @__PURE__ */ jsx3("td", { colSpan: totalCols, style: { height: paddingTop, padding: 0, border: 0 } }) }),
923
969
  virtualRows.map((virtualRow) => {
924
970
  const i = virtualRow.index;
925
971
  const row = rows[i];
926
972
  const id = rowIds[i] ?? null;
927
973
  const selected = id != null && selection ? selection.isSelected(id) : false;
928
- return /* @__PURE__ */ jsxs2(
974
+ return /* @__PURE__ */ jsxs3(
929
975
  "tr",
930
976
  {
931
977
  "data-index": i,
@@ -934,7 +980,7 @@ function DataTable(props) {
934
980
  children: [
935
981
  renderedColumnNames.map((name) => {
936
982
  if (name === SELECTION_COLUMN) {
937
- return /* @__PURE__ */ jsx2(
983
+ return /* @__PURE__ */ jsx3(
938
984
  "td",
939
985
  {
940
986
  "data-qt-field": name,
@@ -945,7 +991,7 @@ function DataTable(props) {
945
991
  classNames?.cell,
946
992
  classNames?.checkboxCell
947
993
  ),
948
- children: id != null && /* @__PURE__ */ jsx2(
994
+ children: id != null && /* @__PURE__ */ jsx3(
949
995
  "input",
950
996
  {
951
997
  type: "checkbox",
@@ -965,7 +1011,7 @@ function DataTable(props) {
965
1011
  const render = resolveRenderer(f, renderers);
966
1012
  const value = readFieldValue(f, row);
967
1013
  const key = cellKey(id, i, f.name);
968
- return /* @__PURE__ */ jsx2(
1014
+ return /* @__PURE__ */ jsx3(
969
1015
  "td",
970
1016
  {
971
1017
  "data-qt-field": f.name,
@@ -974,21 +1020,21 @@ function DataTable(props) {
974
1020
  onClick: (e) => openMenu(e, f, row),
975
1021
  onContextMenu: (e) => openMenu(e, f, row),
976
1022
  onDoubleClick: (e) => copyCellToClipboard(e, f, id, i, value),
977
- children: copiedCellKey === key ? /* @__PURE__ */ jsx2("span", { className: "qt-cell-copy-chip", children: "\u2713 copied" }) : isComputedCellError(value) ? /* @__PURE__ */ jsx2("span", { className: "qt-formula-error", title: value.computedError, children: value.computedError === "Calculating\u2026" ? "Calculating\u2026" : "Error" }) : render({ value, row, field: f, query })
1023
+ children: copiedCellKey === key ? /* @__PURE__ */ jsx3("span", { className: "qt-cell-copy-chip", children: "\u2713 copied" }) : isComputedCellError(value) ? /* @__PURE__ */ jsx3("span", { className: "qt-formula-error", title: value.computedError, children: value.computedError === "Calculating\u2026" ? "Calculating\u2026" : "Error" }) : render({ value, row, field: f, query })
978
1024
  },
979
1025
  f.name
980
1026
  );
981
1027
  }),
982
- trailing && /* @__PURE__ */ jsx2("td", { className: cx2("qt-cell", "qt-trailing-cell", classNames?.cell), children: trailing(row) })
1028
+ trailing && /* @__PURE__ */ jsx3("td", { className: cx2("qt-cell", "qt-trailing-cell", classNames?.cell), children: trailing(row) })
983
1029
  ]
984
1030
  },
985
1031
  virtualRow.key
986
1032
  );
987
1033
  }),
988
- paddingBottom > 0 && /* @__PURE__ */ jsx2("tr", { className: "qt-virtual-spacer", "aria-hidden": "true", children: /* @__PURE__ */ jsx2("td", { colSpan: totalCols, style: { height: paddingBottom, padding: 0, border: 0 } }) })
1034
+ paddingBottom > 0 && /* @__PURE__ */ jsx3("tr", { className: "qt-virtual-spacer", "aria-hidden": "true", children: /* @__PURE__ */ jsx3("td", { colSpan: totalCols, style: { height: paddingBottom, padding: 0, border: 0 } }) })
989
1035
  ] }),
990
- /* @__PURE__ */ jsx2("tfoot", { children: /* @__PURE__ */ jsx2("tr", { className: cx2("qt-table-summary-row", classNames?.summaryRow), children: /* @__PURE__ */ jsx2("td", { colSpan: totalCols, className: cx2("qt-cell", "qt-table-summary-cell", classNames?.summaryCell), children: /* @__PURE__ */ jsxs2("div", { className: cx2("qt-table-summary", classNames?.summaryControls), children: [
991
- /* @__PURE__ */ jsx2(
1036
+ /* @__PURE__ */ jsx3("tfoot", { children: /* @__PURE__ */ jsx3("tr", { className: cx2("qt-table-summary-row", classNames?.summaryRow), children: /* @__PURE__ */ jsx3("td", { colSpan: totalCols, className: cx2("qt-cell", "qt-table-summary-cell", classNames?.summaryCell), children: /* @__PURE__ */ jsxs3("div", { className: cx2("qt-table-summary", classNames?.summaryControls), children: [
1037
+ /* @__PURE__ */ jsx3(
992
1038
  "button",
993
1039
  {
994
1040
  type: "button",
@@ -998,8 +1044,8 @@ function DataTable(props) {
998
1044
  children: "\u2190 prev"
999
1045
  }
1000
1046
  ),
1001
- /* @__PURE__ */ jsx2("span", { className: cx2("qt-table-summary-hint", classNames?.summaryHint), children: summaryText }),
1002
- /* @__PURE__ */ jsx2(
1047
+ /* @__PURE__ */ jsx3("span", { className: cx2("qt-table-summary-hint", classNames?.summaryHint), children: summaryText }),
1048
+ /* @__PURE__ */ jsx3(
1003
1049
  "button",
1004
1050
  {
1005
1051
  type: "button",
@@ -1014,7 +1060,7 @@ function DataTable(props) {
1014
1060
  ]
1015
1061
  }
1016
1062
  ),
1017
- menu && (menu.kind === "cell" ? /* @__PURE__ */ jsx2(
1063
+ menu && (menu.kind === "cell" ? /* @__PURE__ */ jsx3(
1018
1064
  CellMenu,
1019
1065
  {
1020
1066
  field: menu.field,
@@ -1024,7 +1070,7 @@ function DataTable(props) {
1024
1070
  onAddFilter: (clause) => onQueryChange((prev) => ({ ...prev, offset: 0, where: [...prev.where, clause] })),
1025
1071
  onClose: () => setMenu(null)
1026
1072
  }
1027
- ) : /* @__PURE__ */ jsx2(
1073
+ ) : /* @__PURE__ */ jsx3(
1028
1074
  HeaderMenu,
1029
1075
  {
1030
1076
  field: menu.field,
@@ -1066,7 +1112,7 @@ function HeaderMenu({
1066
1112
  }, [onClose]);
1067
1113
  const items = [];
1068
1114
  const addSortItem = (placement, dir, label) => items.push(
1069
- /* @__PURE__ */ jsx2(MenuItem2, { disabled: !sortable, onClick: () => onSetSort(placement, dir), children: label }, `${placement}-${dir}`)
1115
+ /* @__PURE__ */ jsx3(MenuItem2, { disabled: !sortable, onClick: () => onSetSort(placement, dir), children: label }, `${placement}-${dir}`)
1070
1116
  );
1071
1117
  addSortItem("set", "asc", "Set Sort (Asc)");
1072
1118
  addSortItem("set", "desc", "Set Sort (Desc)");
@@ -1074,15 +1120,15 @@ function HeaderMenu({
1074
1120
  addSortItem("append", "desc", "Append Sort (Desc)");
1075
1121
  addSortItem("prepend", "asc", "Prepend Sort (Asc)");
1076
1122
  addSortItem("prepend", "desc", "Prepend Sort (Desc)");
1077
- items.push(/* @__PURE__ */ jsx2("div", { className: "qt-cm-sep" }, "sep"));
1123
+ items.push(/* @__PURE__ */ jsx3("div", { className: "qt-cm-sep" }, "sep"));
1078
1124
  items.push(
1079
- /* @__PURE__ */ jsx2(MenuItem2, { disabled: !canRemoveColumn, onClick: onRemove, children: "Remove Column" }, "remove")
1125
+ /* @__PURE__ */ jsx3(MenuItem2, { disabled: !canRemoveColumn, onClick: onRemove, children: "Remove Column" }, "remove")
1080
1126
  );
1081
1127
  const vw = typeof window !== "undefined" ? window.innerWidth : 9999;
1082
1128
  const vh = typeof window !== "undefined" ? window.innerHeight : 9999;
1083
1129
  const left = Math.max(8, Math.min(x, vw - MENU_WIDTH2 - 8));
1084
1130
  const top = Math.max(8, Math.min(y, vh - MENU_ROW_HEIGHT * items.length - 8));
1085
- return /* @__PURE__ */ jsxs2(
1131
+ return /* @__PURE__ */ jsxs3(
1086
1132
  "div",
1087
1133
  {
1088
1134
  className: "qt-cell-menu",
@@ -1091,7 +1137,7 @@ function HeaderMenu({
1091
1137
  onContextMenu: (e) => e.preventDefault(),
1092
1138
  role: "menu",
1093
1139
  children: [
1094
- /* @__PURE__ */ jsx2("div", { className: "qt-cm-header", children: /* @__PURE__ */ jsx2("span", { className: "qt-cm-field", children: field.label }) }),
1140
+ /* @__PURE__ */ jsx3("div", { className: "qt-cm-header", children: /* @__PURE__ */ jsx3("span", { className: "qt-cm-field", children: field.label }) }),
1095
1141
  items
1096
1142
  ]
1097
1143
  }
@@ -1102,7 +1148,7 @@ function MenuItem2({
1102
1148
  onClick,
1103
1149
  disabled
1104
1150
  }) {
1105
- return /* @__PURE__ */ jsx2(
1151
+ return /* @__PURE__ */ jsx3(
1106
1152
  "button",
1107
1153
  {
1108
1154
  type: "button",
@@ -1160,7 +1206,7 @@ import {
1160
1206
  useId,
1161
1207
  useMemo as useMemo2,
1162
1208
  useRef as useRef2,
1163
- useState as useState3
1209
+ useState as useState4
1164
1210
  } from "react";
1165
1211
  import {
1166
1212
  computedFieldName,
@@ -1215,7 +1261,7 @@ function orderPreviewGroups(groups, sort) {
1215
1261
  }
1216
1262
 
1217
1263
  // src/SelectColumnEditor.tsx
1218
- import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1264
+ import { Fragment as Fragment4, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1219
1265
  var FormulaEditor = lazy(() => import("./FormulaEditor-YCPICDIH.js"));
1220
1266
  var fieldExpression = (name) => `[${name.replace(/\]/g, "]]")}]`;
1221
1267
  var display = (v) => v === null ? "NULL" : typeof v === "string" ? v === "" ? '""' : v : JSON.stringify(v);
@@ -1226,18 +1272,19 @@ function SelectColumnEditor({
1226
1272
  const titleId = useId(), dialog = useRef2(null);
1227
1273
  const closeRef = useRef2(onClose);
1228
1274
  closeRef.current = onClose;
1229
- const [columns, setColumns] = useState3(
1275
+ const [columns, setColumns] = useState4(
1230
1276
  () => api.select.visible.map((c) => ({ ...c }))
1231
1277
  );
1232
- const [search, setSearch] = useState3(""), [active, setActive] = useState3(api.select.visible[0]?.field ?? "");
1233
- const [editing, setEditing] = useState3(false), [id, setId] = useState3(""), [revision, setRevision] = useState3(null);
1234
- const [label, setLabel] = useState3(""), [source, setSource] = useState3("");
1235
- const [count, setCount] = useState3(1e3), [preview, setPreview] = useState3(null), [loading, setLoading] = useState3(false);
1236
- const [error, setError] = useState3(null), [notice, setNotice] = useState3(""), [saving, setSaving] = useState3(false);
1237
- const [filter, setFilter] = useState3("all"), [page, setPage] = useState3(0), [retry, setRetry] = useState3(0), [functionSearch, setFunctionSearch] = useState3("");
1238
- const [previewSort, setPreviewSort] = useState3(null);
1278
+ const [search, setSearch] = useState4(""), [active, setActive] = useState4(api.select.visible[0]?.field ?? "");
1279
+ const [editing, setEditing] = useState4(false), [id, setId] = useState4(""), [revision, setRevision] = useState4(null);
1280
+ const [label, setLabel] = useState4(""), [source, setSource] = useState4("");
1281
+ const [count, setCount] = useState4(1e3), [preview, setPreview] = useState4(null), [loading, setLoading] = useState4(false);
1282
+ const [error, setError] = useState4(null), [notice, setNotice] = useState4(""), [saving, setSaving] = useState4(false);
1283
+ const [filter, setFilter] = useState4("all"), [page, setPage] = useState4(0), [retry, setRetry] = useState4(0), [functionSearch, setFunctionSearch] = useState4("");
1284
+ const [previewSort, setPreviewSort] = useState4(null);
1285
+ const [fieldStats, setFieldStats] = useState4({});
1239
1286
  const drag = useRef2(null);
1240
- const [inspection, setInspection] = useState3(null);
1287
+ const [inspection, setInspection] = useState4(null);
1241
1288
  const catalogue = api.computed.catalogue.filter(isSelectable);
1242
1289
  const chosen = catalogue.find((f) => f.name === active);
1243
1290
  const expression = editing ? source : active ? fieldExpression(active) : "";
@@ -1252,6 +1299,12 @@ function SelectColumnEditor({
1252
1299
  return { error: e instanceof Error ? e.message : String(e) };
1253
1300
  }
1254
1301
  }, [expression, editing, id, api.computed.compile]);
1302
+ const previewPlanKey = validation.error ? `error:${validation.error}` : `plan:${JSON.stringify(validation.plan)}`;
1303
+ const previewRequest = useRef2(api.computed.preview);
1304
+ previewRequest.current = api.computed.preview;
1305
+ const fieldStatsRequest = useRef2(api.fieldStats);
1306
+ fieldStatsRequest.current = api.fieldStats;
1307
+ const catalogueKey = JSON.stringify(catalogue.map((field) => field.name));
1255
1308
  useEffect3(() => {
1256
1309
  const previous = document.activeElement;
1257
1310
  dialog.current?.focus();
@@ -1285,6 +1338,17 @@ function SelectColumnEditor({
1285
1338
  previous?.focus();
1286
1339
  };
1287
1340
  }, []);
1341
+ useEffect3(() => {
1342
+ const ac = new AbortController();
1343
+ void fieldStatsRequest.current(
1344
+ catalogue.map((field) => field.name),
1345
+ ac.signal
1346
+ ).then((result) => {
1347
+ if (!ac.signal.aborted) setFieldStats(result);
1348
+ }).catch(() => {
1349
+ });
1350
+ return () => ac.abort();
1351
+ }, [catalogueKey]);
1288
1352
  useEffect3(() => {
1289
1353
  const ac = new AbortController();
1290
1354
  setPreview(null);
@@ -1297,7 +1361,8 @@ function SelectColumnEditor({
1297
1361
  }
1298
1362
  setLoading(true);
1299
1363
  const timer = setTimeout(() => {
1300
- void api.computed.preview(
1364
+ const request = previewRequest.current;
1365
+ void request(
1301
1366
  expression,
1302
1367
  count,
1303
1368
  ac.signal,
@@ -1316,7 +1381,7 @@ function SelectColumnEditor({
1316
1381
  ac.abort();
1317
1382
  clearTimeout(timer);
1318
1383
  };
1319
- }, [expression, count, editing, id, validation, api.computed.preview, retry]);
1384
+ }, [expression, count, editing, id, previewPlanKey, retry]);
1320
1385
  const move = (field, index) => setColumns((cols) => {
1321
1386
  const next = cols.filter((c) => c.field !== field), item = cols.find((c) => c.field === field);
1322
1387
  if (item) next.splice(Math.max(0, Math.min(index, next.length)), 0, item);
@@ -1377,6 +1442,16 @@ function SelectColumnEditor({
1377
1442
  ),
1378
1443
  [preview, filter, previewSort]
1379
1444
  );
1445
+ const catalogueResults = useMemo2(
1446
+ () => catalogue.filter(
1447
+ (f) => `${f.label} ${f.name} ${f.type} ${f.group ?? ""}`.toLowerCase().includes(search.toLowerCase())
1448
+ ).map((field, index) => ({ field, index })).sort((a, b) => {
1449
+ const aLow = (fieldStats[a.field.name]?.distinct ?? 2) <= 1;
1450
+ const bLow = (fieldStats[b.field.name]?.distinct ?? 2) <= 1;
1451
+ return Number(aLow) - Number(bLow) || a.index - b.index;
1452
+ }).map(({ field }) => field),
1453
+ [catalogue, search, fieldStats]
1454
+ );
1380
1455
  const shown = groups.slice(page * 50, (page + 1) * 50);
1381
1456
  const samePreviewSortKey = (a, b) => {
1382
1457
  if (a.kind !== b.kind) return false;
@@ -1398,7 +1473,7 @@ function SelectColumnEditor({
1398
1473
  };
1399
1474
  const previewSortHeader = (label2, key, direction = "asc") => {
1400
1475
  const currentDirection = previewSortDirection(key);
1401
- return /* @__PURE__ */ jsxs3(
1476
+ return /* @__PURE__ */ jsxs4(
1402
1477
  "button",
1403
1478
  {
1404
1479
  type: "button",
@@ -1412,7 +1487,7 @@ function SelectColumnEditor({
1412
1487
  }
1413
1488
  );
1414
1489
  };
1415
- return /* @__PURE__ */ jsx3("div", { className: "qt-modal-backdrop qt-select-editor-backdrop", children: /* @__PURE__ */ jsxs3(
1490
+ return /* @__PURE__ */ jsx4("div", { className: "qt-modal-backdrop qt-select-editor-backdrop", children: /* @__PURE__ */ jsxs4(
1416
1491
  "div",
1417
1492
  {
1418
1493
  className: "qt-select-editor",
@@ -1422,12 +1497,12 @@ function SelectColumnEditor({
1422
1497
  ref: dialog,
1423
1498
  tabIndex: -1,
1424
1499
  children: [
1425
- /* @__PURE__ */ jsxs3("header", { className: "qt-select-editor-header", children: [
1426
- /* @__PURE__ */ jsxs3("div", { children: [
1427
- /* @__PURE__ */ jsx3("h2", { id: titleId, children: "Select columns" }),
1428
- /* @__PURE__ */ jsx3("p", { children: "Arrange your view, explore values, and create reusable computed columns." })
1500
+ /* @__PURE__ */ jsxs4("header", { className: "qt-select-editor-header", children: [
1501
+ /* @__PURE__ */ jsxs4("div", { children: [
1502
+ /* @__PURE__ */ jsx4("h2", { id: titleId, children: "Select columns" }),
1503
+ /* @__PURE__ */ jsx4("p", { children: "Arrange your view, explore values, and create reusable computed columns." })
1429
1504
  ] }),
1430
- /* @__PURE__ */ jsx3(
1505
+ /* @__PURE__ */ jsx4(
1431
1506
  "button",
1432
1507
  {
1433
1508
  type: "button",
@@ -1438,16 +1513,16 @@ function SelectColumnEditor({
1438
1513
  }
1439
1514
  )
1440
1515
  ] }),
1441
- /* @__PURE__ */ jsxs3("div", { className: "qt-select-editor-body", children: [
1442
- /* @__PURE__ */ jsxs3("aside", { className: "qt-selected-panel", children: [
1443
- /* @__PURE__ */ jsxs3("h3", { children: [
1516
+ /* @__PURE__ */ jsxs4("div", { className: "qt-select-editor-body", children: [
1517
+ /* @__PURE__ */ jsxs4("aside", { className: "qt-selected-panel", children: [
1518
+ /* @__PURE__ */ jsxs4("h3", { children: [
1444
1519
  "Selected ",
1445
- /* @__PURE__ */ jsx3("span", { className: "qt-muted", children: columns.length })
1520
+ /* @__PURE__ */ jsx4("span", { className: "qt-muted", children: columns.length })
1446
1521
  ] }),
1447
- /* @__PURE__ */ jsx3("p", { className: "qt-muted", children: "Drag to reorder, or use the arrow buttons." }),
1448
- /* @__PURE__ */ jsx3("ol", { className: "qt-editor-columns", children: columns.map((c, i) => {
1522
+ /* @__PURE__ */ jsx4("p", { className: "qt-muted", children: "Drag to reorder, or use the arrow buttons." }),
1523
+ /* @__PURE__ */ jsx4("ol", { className: "qt-editor-columns", children: columns.map((c, i) => {
1449
1524
  const f = catalogue.find((f2) => f2.name === c.field);
1450
- return /* @__PURE__ */ jsxs3(
1525
+ return /* @__PURE__ */ jsxs4(
1451
1526
  "li",
1452
1527
  {
1453
1528
  draggable: true,
@@ -1465,8 +1540,8 @@ function SelectColumnEditor({
1465
1540
  drag.current = null;
1466
1541
  },
1467
1542
  children: [
1468
- /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: "\u283F" }),
1469
- /* @__PURE__ */ jsx3(
1543
+ /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: "\u283F" }),
1544
+ /* @__PURE__ */ jsx4(
1470
1545
  "button",
1471
1546
  {
1472
1547
  type: "button",
@@ -1475,7 +1550,7 @@ function SelectColumnEditor({
1475
1550
  children: f?.label ?? c.field
1476
1551
  }
1477
1552
  ),
1478
- /* @__PURE__ */ jsx3(
1553
+ /* @__PURE__ */ jsx4(
1479
1554
  "button",
1480
1555
  {
1481
1556
  type: "button",
@@ -1486,7 +1561,7 @@ function SelectColumnEditor({
1486
1561
  children: "\u2191"
1487
1562
  }
1488
1563
  ),
1489
- /* @__PURE__ */ jsx3(
1564
+ /* @__PURE__ */ jsx4(
1490
1565
  "button",
1491
1566
  {
1492
1567
  type: "button",
@@ -1497,7 +1572,7 @@ function SelectColumnEditor({
1497
1572
  children: "\u2193"
1498
1573
  }
1499
1574
  ),
1500
- /* @__PURE__ */ jsx3(
1575
+ /* @__PURE__ */ jsx4(
1501
1576
  "button",
1502
1577
  {
1503
1578
  type: "button",
@@ -1512,7 +1587,7 @@ function SelectColumnEditor({
1512
1587
  c.field
1513
1588
  );
1514
1589
  }) }),
1515
- /* @__PURE__ */ jsx3(
1590
+ /* @__PURE__ */ jsx4(
1516
1591
  "button",
1517
1592
  {
1518
1593
  type: "button",
@@ -1524,9 +1599,9 @@ function SelectColumnEditor({
1524
1599
  }
1525
1600
  )
1526
1601
  ] }),
1527
- /* @__PURE__ */ jsxs3("aside", { className: "qt-catalogue-panel", children: [
1528
- /* @__PURE__ */ jsx3("h3", { children: "Column catalogue" }),
1529
- /* @__PURE__ */ jsx3(
1602
+ /* @__PURE__ */ jsxs4("aside", { className: "qt-catalogue-panel", children: [
1603
+ /* @__PURE__ */ jsx4("h3", { children: "Column catalogue" }),
1604
+ /* @__PURE__ */ jsx4(
1530
1605
  "input",
1531
1606
  {
1532
1607
  className: "qt-input",
@@ -1536,7 +1611,7 @@ function SelectColumnEditor({
1536
1611
  onChange: (e) => setSearch(e.target.value)
1537
1612
  }
1538
1613
  ),
1539
- /* @__PURE__ */ jsx3(
1614
+ /* @__PURE__ */ jsx4(
1540
1615
  "button",
1541
1616
  {
1542
1617
  type: "button",
@@ -1545,38 +1620,40 @@ function SelectColumnEditor({
1545
1620
  children: "\uFF0B Computed column"
1546
1621
  }
1547
1622
  ),
1548
- api.computed.loading && /* @__PURE__ */ jsx3("p", { role: "status", children: "Loading definitions\u2026" }),
1549
- api.computed.error && /* @__PURE__ */ jsx3("p", { role: "alert", children: api.computed.error }),
1550
- /* @__PURE__ */ jsx3("div", { className: "qt-catalogue-list", children: catalogue.filter(
1551
- (f) => `${f.label} ${f.name} ${f.type} ${f.group ?? ""}`.toLowerCase().includes(search.toLowerCase())
1552
- ).map((f) => /* @__PURE__ */ jsxs3(
1553
- "div",
1554
- {
1555
- className: `qt-catalogue-item ${active === f.name && !editing ? "is-active" : ""}`,
1556
- children: [
1557
- /* @__PURE__ */ jsx3(
1558
- "input",
1559
- {
1560
- type: "checkbox",
1561
- "aria-label": `Include ${f.label}`,
1562
- checked: columns.some((c) => c.field === f.name),
1563
- onChange: () => toggle(f.name)
1564
- }
1565
- ),
1566
- /* @__PURE__ */ jsxs3("button", { type: "button", onClick: () => browse(f.name), children: [
1567
- /* @__PURE__ */ jsx3("strong", { children: f.label }),
1568
- /* @__PURE__ */ jsxs3("small", { children: [
1569
- isComputedField(f.name) ? "\u0192 \xB7 " : "",
1570
- f.type,
1571
- " \xB7 ",
1572
- f.group ?? f.name
1623
+ api.computed.loading && /* @__PURE__ */ jsx4("p", { role: "status", children: "Loading definitions\u2026" }),
1624
+ api.computed.error && /* @__PURE__ */ jsx4("p", { role: "alert", children: api.computed.error }),
1625
+ /* @__PURE__ */ jsx4("div", { className: "qt-catalogue-list", children: catalogueResults.map((f) => {
1626
+ const distinct = fieldStats[f.name]?.distinct;
1627
+ return /* @__PURE__ */ jsxs4(
1628
+ "div",
1629
+ {
1630
+ className: `qt-catalogue-item ${active === f.name && !editing ? "is-active" : ""} ${distinct != null && distinct <= 1 ? "is-low-cardinality" : ""}`,
1631
+ children: [
1632
+ /* @__PURE__ */ jsx4(
1633
+ "input",
1634
+ {
1635
+ type: "checkbox",
1636
+ "aria-label": `Include ${f.label}`,
1637
+ checked: columns.some((c) => c.field === f.name),
1638
+ onChange: () => toggle(f.name)
1639
+ }
1640
+ ),
1641
+ /* @__PURE__ */ jsxs4("button", { type: "button", onClick: () => browse(f.name), children: [
1642
+ /* @__PURE__ */ jsx4("strong", { children: f.label }),
1643
+ /* @__PURE__ */ jsxs4("small", { children: [
1644
+ isComputedField(f.name) ? "\u0192 \xB7 " : "",
1645
+ f.type,
1646
+ " \xB7 ",
1647
+ f.group ?? f.name,
1648
+ distinct != null && ` \xB7 ${distinct.toLocaleString()} distinct`
1649
+ ] })
1573
1650
  ] })
1574
- ] })
1575
- ]
1576
- },
1577
- f.name
1578
- )) }),
1579
- /* @__PURE__ */ jsx3(
1651
+ ]
1652
+ },
1653
+ f.name
1654
+ );
1655
+ }) }),
1656
+ /* @__PURE__ */ jsx4(
1580
1657
  "button",
1581
1658
  {
1582
1659
  type: "button",
@@ -1586,15 +1663,15 @@ function SelectColumnEditor({
1586
1663
  }
1587
1664
  )
1588
1665
  ] }),
1589
- /* @__PURE__ */ jsxs3("section", { className: "qt-column-workbench", children: [
1590
- editing ? /* @__PURE__ */ jsxs3(Fragment3, { children: [
1591
- /* @__PURE__ */ jsxs3("div", { className: "qt-editor-title", children: [
1592
- /* @__PURE__ */ jsx3("h3", { children: revision ? "Edit shared computed column" : "New computed column" }),
1593
- /* @__PURE__ */ jsx3("span", { className: "qt-type-badge", children: validation.plan?.type ?? "Check formula" })
1666
+ /* @__PURE__ */ jsxs4("section", { className: "qt-column-workbench", children: [
1667
+ editing ? /* @__PURE__ */ jsxs4(Fragment4, { children: [
1668
+ /* @__PURE__ */ jsxs4("div", { className: "qt-editor-title", children: [
1669
+ /* @__PURE__ */ jsx4("h3", { children: revision ? "Edit shared computed column" : "New computed column" }),
1670
+ /* @__PURE__ */ jsx4("span", { className: "qt-type-badge", children: validation.plan?.type ?? "Check formula" })
1594
1671
  ] }),
1595
- /* @__PURE__ */ jsxs3("label", { className: "qt-editor-label", children: [
1672
+ /* @__PURE__ */ jsxs4("label", { className: "qt-editor-label", children: [
1596
1673
  "Column name",
1597
- /* @__PURE__ */ jsx3(
1674
+ /* @__PURE__ */ jsx4(
1598
1675
  "input",
1599
1676
  {
1600
1677
  className: "qt-input",
@@ -1605,10 +1682,10 @@ function SelectColumnEditor({
1605
1682
  }
1606
1683
  )
1607
1684
  ] }),
1608
- /* @__PURE__ */ jsx3(
1685
+ /* @__PURE__ */ jsx4(
1609
1686
  Suspense,
1610
1687
  {
1611
- fallback: /* @__PURE__ */ jsx3(
1688
+ fallback: /* @__PURE__ */ jsx4(
1612
1689
  "textarea",
1613
1690
  {
1614
1691
  "aria-label": "Computed column formula",
@@ -1616,7 +1693,7 @@ function SelectColumnEditor({
1616
1693
  onChange: (e) => setSource(e.target.value)
1617
1694
  }
1618
1695
  ),
1619
- children: /* @__PURE__ */ jsx3(
1696
+ children: /* @__PURE__ */ jsx4(
1620
1697
  FormulaEditor,
1621
1698
  {
1622
1699
  value: source,
@@ -1629,9 +1706,9 @@ function SelectColumnEditor({
1629
1706
  )
1630
1707
  }
1631
1708
  ),
1632
- /* @__PURE__ */ jsxs3("details", { className: "qt-function-library", children: [
1633
- /* @__PURE__ */ jsx3("summary", { children: "Functions & examples" }),
1634
- /* @__PURE__ */ jsx3(
1709
+ /* @__PURE__ */ jsxs4("details", { className: "qt-function-library", children: [
1710
+ /* @__PURE__ */ jsx4("summary", { children: "Functions & examples" }),
1711
+ /* @__PURE__ */ jsx4(
1635
1712
  "input",
1636
1713
  {
1637
1714
  className: "qt-input",
@@ -1641,34 +1718,34 @@ function SelectColumnEditor({
1641
1718
  onChange: (e) => setFunctionSearch(e.target.value)
1642
1719
  }
1643
1720
  ),
1644
- /* @__PURE__ */ jsx3("div", { className: "qt-function-list", children: FORMULA_FUNCTIONS.filter(
1721
+ /* @__PURE__ */ jsx4("div", { className: "qt-function-list", children: FORMULA_FUNCTIONS.filter(
1645
1722
  (f) => `${f.name} ${f.description}`.toLowerCase().includes(functionSearch.toLowerCase())
1646
- ).map((f) => /* @__PURE__ */ jsxs3(
1723
+ ).map((f) => /* @__PURE__ */ jsxs4(
1647
1724
  "button",
1648
1725
  {
1649
1726
  type: "button",
1650
1727
  title: f.description,
1651
1728
  onClick: () => setSource(`${f.name}(${source})`),
1652
1729
  children: [
1653
- /* @__PURE__ */ jsx3("code", { children: f.signature }),
1654
- /* @__PURE__ */ jsx3("small", { children: f.description })
1730
+ /* @__PURE__ */ jsx4("code", { children: f.signature }),
1731
+ /* @__PURE__ */ jsx4("small", { children: f.description })
1655
1732
  ]
1656
1733
  },
1657
1734
  f.name
1658
1735
  )) }),
1659
- /* @__PURE__ */ jsxs3("p", { children: [
1736
+ /* @__PURE__ */ jsxs4("p", { children: [
1660
1737
  "Examples: ",
1661
- /* @__PURE__ */ jsx3("code", { children: "LEFT([name], 3)" }),
1738
+ /* @__PURE__ */ jsx4("code", { children: "LEFT([name], 3)" }),
1662
1739
  " \xB7",
1663
1740
  " ",
1664
- /* @__PURE__ */ jsx3("code", { children: 'IF([amount] > 100, "High", "Low")' }),
1741
+ /* @__PURE__ */ jsx4("code", { children: 'IF([amount] > 100, "High", "Low")' }),
1665
1742
  " \xB7",
1666
1743
  " ",
1667
- /* @__PURE__ */ jsx3("code", { children: 'REGEX_EXTRACT([email], "@(.+)$", 1)' })
1744
+ /* @__PURE__ */ jsx4("code", { children: 'REGEX_EXTRACT([email], "@(.+)$", 1)' })
1668
1745
  ] })
1669
1746
  ] }),
1670
- /* @__PURE__ */ jsxs3("div", { className: "qt-definition-actions", children: [
1671
- /* @__PURE__ */ jsx3(
1747
+ /* @__PURE__ */ jsxs4("div", { className: "qt-definition-actions", children: [
1748
+ /* @__PURE__ */ jsx4(
1672
1749
  "button",
1673
1750
  {
1674
1751
  type: "button",
@@ -1678,7 +1755,7 @@ function SelectColumnEditor({
1678
1755
  children: saving ? "Saving\u2026" : revision ? "Save shared definition" : "Save definition & add column"
1679
1756
  }
1680
1757
  ),
1681
- revision && /* @__PURE__ */ jsx3(
1758
+ revision && /* @__PURE__ */ jsx4(
1682
1759
  "button",
1683
1760
  {
1684
1761
  type: "button",
@@ -1688,18 +1765,18 @@ function SelectColumnEditor({
1688
1765
  }
1689
1766
  )
1690
1767
  ] }),
1691
- /* @__PURE__ */ jsx3("p", { className: "qt-muted", children: "Saving changes this definition across all queries. Cancel below only discards column layout changes." })
1692
- ] }) : /* @__PURE__ */ jsxs3("div", { className: "qt-editor-title", children: [
1693
- /* @__PURE__ */ jsxs3("div", { children: [
1694
- /* @__PURE__ */ jsx3("h3", { children: chosen?.label ?? "Explore a column" }),
1695
- /* @__PURE__ */ jsxs3("p", { className: "qt-muted", children: [
1768
+ /* @__PURE__ */ jsx4("p", { className: "qt-muted", children: "Saving changes this definition across all queries. Cancel below only discards column layout changes." })
1769
+ ] }) : /* @__PURE__ */ jsxs4("div", { className: "qt-editor-title", children: [
1770
+ /* @__PURE__ */ jsxs4("div", { children: [
1771
+ /* @__PURE__ */ jsx4("h3", { children: chosen?.label ?? "Explore a column" }),
1772
+ /* @__PURE__ */ jsxs4("p", { className: "qt-muted", children: [
1696
1773
  chosen?.name,
1697
1774
  " ",
1698
1775
  chosen ? `\xB7 ${chosen.type}` : ""
1699
1776
  ] })
1700
1777
  ] }),
1701
- chosen && isComputedField(chosen.name) && /* @__PURE__ */ jsxs3(Fragment3, { children: [
1702
- /* @__PURE__ */ jsx3(
1778
+ chosen && isComputedField(chosen.name) && /* @__PURE__ */ jsxs4(Fragment4, { children: [
1779
+ /* @__PURE__ */ jsx4(
1703
1780
  "button",
1704
1781
  {
1705
1782
  type: "button",
@@ -1708,7 +1785,7 @@ function SelectColumnEditor({
1708
1785
  children: "Edit definition"
1709
1786
  }
1710
1787
  ),
1711
- /* @__PURE__ */ jsx3(
1788
+ /* @__PURE__ */ jsx4(
1712
1789
  "button",
1713
1790
  {
1714
1791
  type: "button",
@@ -1728,11 +1805,11 @@ function SelectColumnEditor({
1728
1805
  )
1729
1806
  ] })
1730
1807
  ] }),
1731
- /* @__PURE__ */ jsxs3("div", { className: "qt-preview-controls", children: [
1732
- /* @__PURE__ */ jsxs3("label", { children: [
1808
+ /* @__PURE__ */ jsxs4("div", { className: "qt-preview-controls", children: [
1809
+ /* @__PURE__ */ jsxs4("label", { children: [
1733
1810
  "Rows to process",
1734
1811
  " ",
1735
- /* @__PURE__ */ jsx3(
1812
+ /* @__PURE__ */ jsx4(
1736
1813
  "input",
1737
1814
  {
1738
1815
  className: "qt-input",
@@ -1745,7 +1822,7 @@ function SelectColumnEditor({
1745
1822
  }
1746
1823
  )
1747
1824
  ] }),
1748
- /* @__PURE__ */ jsx3(
1825
+ /* @__PURE__ */ jsx4(
1749
1826
  "button",
1750
1827
  {
1751
1828
  type: "button",
@@ -1754,10 +1831,10 @@ function SelectColumnEditor({
1754
1831
  children: "Refresh preview"
1755
1832
  }
1756
1833
  ),
1757
- /* @__PURE__ */ jsxs3("label", { children: [
1834
+ /* @__PURE__ */ jsxs4("label", { children: [
1758
1835
  "Show",
1759
1836
  " ",
1760
- /* @__PURE__ */ jsxs3(
1837
+ /* @__PURE__ */ jsxs4(
1761
1838
  "select",
1762
1839
  {
1763
1840
  value: filter,
@@ -1766,29 +1843,29 @@ function SelectColumnEditor({
1766
1843
  setPage(0);
1767
1844
  },
1768
1845
  children: [
1769
- /* @__PURE__ */ jsx3("option", { value: "all", children: "All results" }),
1770
- /* @__PURE__ */ jsx3("option", { value: "nulls", children: "Null results" }),
1771
- /* @__PURE__ */ jsx3("option", { value: "errors", children: "Errors" })
1846
+ /* @__PURE__ */ jsx4("option", { value: "all", children: "All results" }),
1847
+ /* @__PURE__ */ jsx4("option", { value: "nulls", children: "Null results" }),
1848
+ /* @__PURE__ */ jsx4("option", { value: "errors", children: "Errors" })
1772
1849
  ]
1773
1850
  }
1774
1851
  )
1775
1852
  ] })
1776
1853
  ] }),
1777
- /* @__PURE__ */ jsx3("p", { className: "qt-muted", children: "First matching rows in current sort order, starting at row 1. Counts describe the processed sample. Maximum 10,000 rows." }),
1778
- (!Number.isInteger(count) || count < 1 || count > 1e4) && /* @__PURE__ */ jsx3("p", { role: "alert", children: "Choose a whole number between 1 and 10,000." }),
1779
- validation.error && /* @__PURE__ */ jsx3("p", { className: "qt-formula-error", role: "alert", children: validation.error }),
1780
- error && /* @__PURE__ */ jsx3("p", { className: "qt-formula-error", role: "alert", children: error }),
1781
- notice && /* @__PURE__ */ jsx3("p", { className: "qt-editor-notice", role: "status", children: notice }),
1782
- loading && /* @__PURE__ */ jsx3("p", { role: "status", children: "Processing preview\u2026" }),
1783
- preview && /* @__PURE__ */ jsxs3(Fragment3, { children: [
1784
- /* @__PURE__ */ jsxs3("p", { className: "qt-preview-summary", role: "status", children: [
1785
- /* @__PURE__ */ jsx3("strong", { children: preview.processed.toLocaleString() }),
1854
+ /* @__PURE__ */ jsx4("p", { className: "qt-muted", children: "First matching rows in current sort order, starting at row 1. Counts describe the processed sample. Maximum 10,000 rows." }),
1855
+ (!Number.isInteger(count) || count < 1 || count > 1e4) && /* @__PURE__ */ jsx4("p", { role: "alert", children: "Choose a whole number between 1 and 10,000." }),
1856
+ validation.error && /* @__PURE__ */ jsx4("p", { className: "qt-formula-error", role: "alert", children: validation.error }),
1857
+ error && /* @__PURE__ */ jsx4("p", { className: "qt-formula-error", role: "alert", children: error }),
1858
+ notice && /* @__PURE__ */ jsx4("p", { className: "qt-editor-notice", role: "status", children: notice }),
1859
+ loading && /* @__PURE__ */ jsx4("p", { role: "status", children: "Processing preview\u2026" }),
1860
+ preview && /* @__PURE__ */ jsxs4(Fragment4, { children: [
1861
+ /* @__PURE__ */ jsxs4("p", { className: "qt-preview-summary", role: "status", children: [
1862
+ /* @__PURE__ */ jsx4("strong", { children: preview.processed.toLocaleString() }),
1786
1863
  " of",
1787
1864
  " ",
1788
1865
  preview.total.toLocaleString(),
1789
1866
  " matching rows \xB7",
1790
1867
  " ",
1791
- /* @__PURE__ */ jsx3("strong", { children: preview.groups.length.toLocaleString() }),
1868
+ /* @__PURE__ */ jsx4("strong", { children: preview.groups.length.toLocaleString() }),
1792
1869
  " ",
1793
1870
  "distinct combinations \xB7 ",
1794
1871
  preview.nulls.toLocaleString(),
@@ -1797,9 +1874,9 @@ function SelectColumnEditor({
1797
1874
  " errors",
1798
1875
  preview.processed === preview.total ? " \xB7 complete filtered set" : " \xB7 sample"
1799
1876
  ] }),
1800
- /* @__PURE__ */ jsx3("div", { className: "qt-preview-table-wrap", children: /* @__PURE__ */ jsxs3("table", { className: "qt-preview-table", children: [
1801
- /* @__PURE__ */ jsx3("thead", { children: /* @__PURE__ */ jsxs3("tr", { children: [
1802
- editing && preview.dependencies.map((name, index) => /* @__PURE__ */ jsx3(
1877
+ /* @__PURE__ */ jsx4("div", { className: "qt-preview-table-wrap", children: /* @__PURE__ */ jsxs4("table", { className: "qt-preview-table", children: [
1878
+ /* @__PURE__ */ jsx4("thead", { children: /* @__PURE__ */ jsxs4("tr", { children: [
1879
+ editing && preview.dependencies.map((name, index) => /* @__PURE__ */ jsx4(
1803
1880
  "th",
1804
1881
  {
1805
1882
  "aria-sort": previewAriaSort({
@@ -1815,22 +1892,22 @@ function SelectColumnEditor({
1815
1892
  },
1816
1893
  name
1817
1894
  )),
1818
- /* @__PURE__ */ jsx3("th", { "aria-sort": previewAriaSort({ kind: "result" }), children: previewSortHeader(editing ? "Result" : "Value", {
1895
+ /* @__PURE__ */ jsx4("th", { "aria-sort": previewAriaSort({ kind: "result" }), children: previewSortHeader(editing ? "Result" : "Value", {
1819
1896
  kind: "result"
1820
1897
  }) }),
1821
- /* @__PURE__ */ jsx3("th", { "aria-sort": previewAriaSort({ kind: "count" }), children: previewSortHeader("Count", { kind: "count" }, "desc") }),
1822
- /* @__PURE__ */ jsx3("th", { "aria-sort": previewAriaSort({ kind: "percentage" }), children: previewSortHeader("%", { kind: "percentage" }, "desc") })
1898
+ /* @__PURE__ */ jsx4("th", { "aria-sort": previewAriaSort({ kind: "count" }), children: previewSortHeader("Count", { kind: "count" }, "desc") }),
1899
+ /* @__PURE__ */ jsx4("th", { "aria-sort": previewAriaSort({ kind: "percentage" }), children: previewSortHeader("%", { kind: "percentage" }, "desc") })
1823
1900
  ] }) }),
1824
- /* @__PURE__ */ jsx3("tbody", { children: shown.map((group, i) => /* @__PURE__ */ jsxs3("tr", { children: [
1825
- editing && group.inputs.map((value, j) => /* @__PURE__ */ jsx3("td", { title: display(value), children: display(value) }, j)),
1826
- /* @__PURE__ */ jsxs3(
1901
+ /* @__PURE__ */ jsx4("tbody", { children: shown.map((group, i) => /* @__PURE__ */ jsxs4("tr", { children: [
1902
+ editing && group.inputs.map((value, j) => /* @__PURE__ */ jsx4("td", { title: display(value), children: display(value) }, j)),
1903
+ /* @__PURE__ */ jsxs4(
1827
1904
  "td",
1828
1905
  {
1829
1906
  className: group.result.error ? "qt-formula-error" : "",
1830
1907
  title: group.result.error ?? display(group.result.value),
1831
1908
  children: [
1832
1909
  group.result.error ?? display(group.result.value),
1833
- group.result.regex && /* @__PURE__ */ jsx3(
1910
+ group.result.regex && /* @__PURE__ */ jsx4(
1834
1911
  "button",
1835
1912
  {
1836
1913
  type: "button",
@@ -1842,8 +1919,8 @@ function SelectColumnEditor({
1842
1919
  ]
1843
1920
  }
1844
1921
  ),
1845
- /* @__PURE__ */ jsx3("td", { children: group.count.toLocaleString() }),
1846
- /* @__PURE__ */ jsxs3("td", { children: [
1922
+ /* @__PURE__ */ jsx4("td", { children: group.count.toLocaleString() }),
1923
+ /* @__PURE__ */ jsxs4("td", { children: [
1847
1924
  (100 * group.count / preview.processed).toFixed(
1848
1925
  1
1849
1926
  ),
@@ -1851,28 +1928,28 @@ function SelectColumnEditor({
1851
1928
  ] })
1852
1929
  ] }, i)) })
1853
1930
  ] }) }),
1854
- inspection && /* @__PURE__ */ jsxs3("div", { className: "qt-regex-inspector", children: [
1855
- /* @__PURE__ */ jsx3("h4", { children: "Regex match" }),
1856
- /* @__PURE__ */ jsxs3("pre", { children: [
1931
+ inspection && /* @__PURE__ */ jsxs4("div", { className: "qt-regex-inspector", children: [
1932
+ /* @__PURE__ */ jsx4("h4", { children: "Regex match" }),
1933
+ /* @__PURE__ */ jsxs4("pre", { children: [
1857
1934
  inspection.input.slice(0, inspection.start),
1858
- /* @__PURE__ */ jsx3("mark", { children: inspection.input.slice(
1935
+ /* @__PURE__ */ jsx4("mark", { children: inspection.input.slice(
1859
1936
  inspection.start,
1860
1937
  inspection.end
1861
1938
  ) }),
1862
1939
  inspection.input.slice(inspection.end)
1863
1940
  ] }),
1864
- /* @__PURE__ */ jsx3("dl", { children: inspection.groups.map((value, i) => /* @__PURE__ */ jsxs3("div", { children: [
1865
- /* @__PURE__ */ jsxs3("dt", { children: [
1941
+ /* @__PURE__ */ jsx4("dl", { children: inspection.groups.map((value, i) => /* @__PURE__ */ jsxs4("div", { children: [
1942
+ /* @__PURE__ */ jsxs4("dt", { children: [
1866
1943
  "Group ",
1867
1944
  i,
1868
1945
  i === 0 ? " (whole match)" : ""
1869
1946
  ] }),
1870
- /* @__PURE__ */ jsx3("dd", { children: display(value) })
1947
+ /* @__PURE__ */ jsx4("dd", { children: display(value) })
1871
1948
  ] }, i)) })
1872
1949
  ] }),
1873
- !groups.length && /* @__PURE__ */ jsx3("p", { children: "No matching results in this sample." }),
1874
- groups.length > 50 && /* @__PURE__ */ jsxs3("div", { className: "qt-preview-pages", children: [
1875
- /* @__PURE__ */ jsx3(
1950
+ !groups.length && /* @__PURE__ */ jsx4("p", { children: "No matching results in this sample." }),
1951
+ groups.length > 50 && /* @__PURE__ */ jsxs4("div", { className: "qt-preview-pages", children: [
1952
+ /* @__PURE__ */ jsx4(
1876
1953
  "button",
1877
1954
  {
1878
1955
  type: "button",
@@ -1882,7 +1959,7 @@ function SelectColumnEditor({
1882
1959
  children: "Previous"
1883
1960
  }
1884
1961
  ),
1885
- /* @__PURE__ */ jsxs3("span", { children: [
1962
+ /* @__PURE__ */ jsxs4("span", { children: [
1886
1963
  "Combinations ",
1887
1964
  page * 50 + 1,
1888
1965
  "\u2013",
@@ -1891,7 +1968,7 @@ function SelectColumnEditor({
1891
1968
  " ",
1892
1969
  groups.length
1893
1970
  ] }),
1894
- /* @__PURE__ */ jsx3(
1971
+ /* @__PURE__ */ jsx4(
1895
1972
  "button",
1896
1973
  {
1897
1974
  type: "button",
@@ -1905,10 +1982,10 @@ function SelectColumnEditor({
1905
1982
  ] })
1906
1983
  ] })
1907
1984
  ] }),
1908
- /* @__PURE__ */ jsxs3("footer", { className: "qt-select-editor-footer", children: [
1909
- /* @__PURE__ */ jsx3("span", { className: "qt-muted", children: "Computed columns are display-only. Select at least one column." }),
1910
- /* @__PURE__ */ jsx3("button", { type: "button", className: "qt-btn", onClick: onClose, children: "Cancel layout changes" }),
1911
- /* @__PURE__ */ jsx3(
1985
+ /* @__PURE__ */ jsxs4("footer", { className: "qt-select-editor-footer", children: [
1986
+ /* @__PURE__ */ jsx4("span", { className: "qt-muted", children: "Computed columns are display-only. Select at least one column." }),
1987
+ /* @__PURE__ */ jsx4("button", { type: "button", className: "qt-btn", onClick: onClose, children: "Cancel layout changes" }),
1988
+ /* @__PURE__ */ jsx4(
1912
1989
  "button",
1913
1990
  {
1914
1991
  type: "button",
@@ -1928,7 +2005,7 @@ function SelectColumnEditor({
1928
2005
  }
1929
2006
 
1930
2007
  // src/QueryBuilder.tsx
1931
- import { Fragment as Fragment5, useEffect as useEffect5, useId as useId2, useMemo as useMemo4, useRef as useRef3, useState as useState5 } from "react";
2008
+ import { Fragment as Fragment6, useEffect as useEffect5, useId as useId2, useMemo as useMemo4, useRef as useRef3, useState as useState6 } from "react";
1932
2009
  import {
1933
2010
  NULLARY_OPS as NULLARY_OPS2,
1934
2011
  aggOpNeedsField,
@@ -1948,8 +2025,8 @@ import {
1948
2025
  } from "@pythia-software/query-table-core";
1949
2026
 
1950
2027
  // src/FieldPicker.tsx
1951
- import { useMemo as useMemo3, useState as useState4 } from "react";
1952
- import { Fragment as Fragment4, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
2028
+ import { useMemo as useMemo3, useState as useState5 } from "react";
2029
+ import { Fragment as Fragment5, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1953
2030
  var UNGROUPED = "other";
1954
2031
  function FieldPicker({
1955
2032
  fields,
@@ -1959,7 +2036,7 @@ function FieldPicker({
1959
2036
  onPick,
1960
2037
  onClose
1961
2038
  }) {
1962
- const [search, setSearch] = useState4("");
2039
+ const [search, setSearch] = useState5("");
1963
2040
  const needle = search.trim().toLowerCase();
1964
2041
  const excludedSet = useMemo3(() => new Set(excluded ?? []), [excluded]);
1965
2042
  const matched = useMemo3(
@@ -1972,8 +2049,8 @@ function FieldPicker({
1972
2049
  );
1973
2050
  const grouped = useMemo3(() => groupByGroup(matched), [matched]);
1974
2051
  const firstEnabled = matched.find((f) => isEnabled(f, stats, gateOnDistinct));
1975
- return /* @__PURE__ */ jsxs4("div", { className: "qt-picker", children: [
1976
- /* @__PURE__ */ jsx4(
2052
+ return /* @__PURE__ */ jsxs5("div", { className: "qt-picker", children: [
2053
+ /* @__PURE__ */ jsx5(
1977
2054
  "input",
1978
2055
  {
1979
2056
  autoFocus: true,
@@ -1992,13 +2069,13 @@ function FieldPicker({
1992
2069
  onBlur: () => setTimeout(() => onClose?.(), 150)
1993
2070
  }
1994
2071
  ),
1995
- /* @__PURE__ */ jsx4("div", { className: "qt-picker-list", children: matched.length === 0 ? /* @__PURE__ */ jsx4("div", { className: "qt-picker-empty", children: "no matches" }) : grouped.map(([group, fs]) => /* @__PURE__ */ jsxs4("div", { className: "qt-picker-group", children: [
1996
- /* @__PURE__ */ jsx4("div", { className: "qt-picker-group-label", children: group }),
2072
+ /* @__PURE__ */ jsx5("div", { className: "qt-picker-list", children: matched.length === 0 ? /* @__PURE__ */ jsx5("div", { className: "qt-picker-empty", children: "no matches" }) : grouped.map(([group, fs]) => /* @__PURE__ */ jsxs5("div", { className: "qt-picker-group", children: [
2073
+ /* @__PURE__ */ jsx5("div", { className: "qt-picker-group-label", children: group }),
1997
2074
  fs.map((f) => {
1998
2075
  const enabled = isEnabled(f, stats, gateOnDistinct);
1999
2076
  const s = stats?.[f.name];
2000
2077
  const aliasHit = aliasMatch(f, needle);
2001
- return /* @__PURE__ */ jsxs4(
2078
+ return /* @__PURE__ */ jsxs5(
2002
2079
  "button",
2003
2080
  {
2004
2081
  type: "button",
@@ -2012,20 +2089,20 @@ function FieldPicker({
2012
2089
  setSearch("");
2013
2090
  },
2014
2091
  children: [
2015
- /* @__PURE__ */ jsxs4("span", { className: "qt-picker-row", children: [
2016
- /* @__PURE__ */ jsx4("span", { className: "qt-picker-label", children: f.label }),
2017
- /* @__PURE__ */ jsx4("span", { className: "qt-picker-name", children: f.name })
2092
+ /* @__PURE__ */ jsxs5("span", { className: "qt-picker-row", children: [
2093
+ /* @__PURE__ */ jsx5("span", { className: "qt-picker-label", children: f.label }),
2094
+ /* @__PURE__ */ jsx5("span", { className: "qt-picker-name", children: f.name })
2018
2095
  ] }),
2019
- aliasHit && /* @__PURE__ */ jsxs4("span", { className: "qt-picker-alias", children: [
2096
+ aliasHit && /* @__PURE__ */ jsxs5("span", { className: "qt-picker-alias", children: [
2020
2097
  "matches: ",
2021
2098
  aliasHit
2022
2099
  ] }),
2023
- s && /* @__PURE__ */ jsxs4("span", { className: "qt-picker-stats", children: [
2024
- s.distinct != null && /* @__PURE__ */ jsxs4(Fragment4, { children: [
2100
+ s && /* @__PURE__ */ jsxs5("span", { className: "qt-picker-stats", children: [
2101
+ s.distinct != null && /* @__PURE__ */ jsxs5(Fragment5, { children: [
2025
2102
  s.distinct,
2026
2103
  " distinct"
2027
2104
  ] }),
2028
- s.min != null && s.max != null && /* @__PURE__ */ jsxs4(Fragment4, { children: [
2105
+ s.min != null && s.max != null && /* @__PURE__ */ jsxs5(Fragment5, { children: [
2029
2106
  " ",
2030
2107
  "\xB7 ",
2031
2108
  fmtStat(s.min),
@@ -2080,7 +2157,7 @@ function fmtStat(v) {
2080
2157
 
2081
2158
  // src/SavedQueriesModal.tsx
2082
2159
  import { useEffect as useEffect4 } from "react";
2083
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
2160
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2084
2161
  function SavedQueriesModal({ saved, onClose, onLoad }) {
2085
2162
  useEffect4(() => {
2086
2163
  function onKey(e) {
@@ -2089,7 +2166,7 @@ function SavedQueriesModal({ saved, onClose, onLoad }) {
2089
2166
  window.addEventListener("keydown", onKey);
2090
2167
  return () => window.removeEventListener("keydown", onKey);
2091
2168
  }, [onClose]);
2092
- return /* @__PURE__ */ jsx5("div", { className: "qt-modal-backdrop", onClick: onClose, children: /* @__PURE__ */ jsxs5(
2169
+ return /* @__PURE__ */ jsx6("div", { className: "qt-modal-backdrop", onClick: onClose, children: /* @__PURE__ */ jsxs6(
2093
2170
  "div",
2094
2171
  {
2095
2172
  className: "qt-modal",
@@ -2098,12 +2175,12 @@ function SavedQueriesModal({ saved, onClose, onLoad }) {
2098
2175
  "aria-modal": "true",
2099
2176
  "aria-label": "Saved queries",
2100
2177
  children: [
2101
- /* @__PURE__ */ jsx5("h3", { className: "qt-modal-title", children: "Saved queries" }),
2102
- saved.loading ? /* @__PURE__ */ jsx5("p", { className: "qt-muted", children: "Loading\u2026" }) : saved.items.length === 0 ? /* @__PURE__ */ jsx5("p", { className: "qt-muted", children: "None saved yet. Save the current query from the toolbar." }) : /* @__PURE__ */ jsx5("ul", { className: "qt-saved-list", children: saved.items.map((s) => {
2178
+ /* @__PURE__ */ jsx6("h3", { className: "qt-modal-title", children: "Saved queries" }),
2179
+ saved.loading ? /* @__PURE__ */ jsx6("p", { className: "qt-muted", children: "Loading\u2026" }) : saved.items.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "qt-muted", children: "None saved yet. Save the current query from the toolbar." }) : /* @__PURE__ */ jsx6("ul", { className: "qt-saved-list", children: saved.items.map((s) => {
2103
2180
  const filters = s.query.where.length;
2104
2181
  const isDefault = saved.defaultId === s.id;
2105
- return /* @__PURE__ */ jsxs5("li", { className: "qt-saved-item", children: [
2106
- /* @__PURE__ */ jsxs5(
2182
+ return /* @__PURE__ */ jsxs6("li", { className: "qt-saved-item", children: [
2183
+ /* @__PURE__ */ jsxs6(
2107
2184
  "button",
2108
2185
  {
2109
2186
  type: "button",
@@ -2114,8 +2191,8 @@ function SavedQueriesModal({ saved, onClose, onLoad }) {
2114
2191
  onClose();
2115
2192
  },
2116
2193
  children: [
2117
- /* @__PURE__ */ jsx5("span", { className: "qt-saved-name", children: s.name }),
2118
- /* @__PURE__ */ jsxs5("span", { className: "qt-saved-meta qt-muted", children: [
2194
+ /* @__PURE__ */ jsx6("span", { className: "qt-saved-name", children: s.name }),
2195
+ /* @__PURE__ */ jsxs6("span", { className: "qt-saved-meta qt-muted", children: [
2119
2196
  isDefault ? "Default view \xB7 " : "",
2120
2197
  new Date(s.savedAt).toLocaleString(),
2121
2198
  " \xB7 ",
@@ -2126,7 +2203,7 @@ function SavedQueriesModal({ saved, onClose, onLoad }) {
2126
2203
  ]
2127
2204
  }
2128
2205
  ),
2129
- isDefault ? /* @__PURE__ */ jsx5(
2206
+ isDefault ? /* @__PURE__ */ jsx6(
2130
2207
  "button",
2131
2208
  {
2132
2209
  type: "button",
@@ -2135,7 +2212,7 @@ function SavedQueriesModal({ saved, onClose, onLoad }) {
2135
2212
  onClick: () => void saved.clearDefault(),
2136
2213
  children: "default"
2137
2214
  }
2138
- ) : /* @__PURE__ */ jsx5(
2215
+ ) : /* @__PURE__ */ jsx6(
2139
2216
  "button",
2140
2217
  {
2141
2218
  type: "button",
@@ -2145,7 +2222,7 @@ function SavedQueriesModal({ saved, onClose, onLoad }) {
2145
2222
  children: "make default"
2146
2223
  }
2147
2224
  ),
2148
- /* @__PURE__ */ jsx5(
2225
+ /* @__PURE__ */ jsx6(
2149
2226
  "button",
2150
2227
  {
2151
2228
  type: "button",
@@ -2157,14 +2234,14 @@ function SavedQueriesModal({ saved, onClose, onLoad }) {
2157
2234
  )
2158
2235
  ] }, s.id);
2159
2236
  }) }),
2160
- /* @__PURE__ */ jsx5("div", { className: "qt-modal-footer", children: /* @__PURE__ */ jsx5("button", { type: "button", className: "qt-btn", onClick: onClose, children: "close" }) })
2237
+ /* @__PURE__ */ jsx6("div", { className: "qt-modal-footer", children: /* @__PURE__ */ jsx6("button", { type: "button", className: "qt-btn", onClick: onClose, children: "close" }) })
2161
2238
  ]
2162
2239
  }
2163
2240
  ) });
2164
2241
  }
2165
2242
 
2166
2243
  // src/QueryBuilder.tsx
2167
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2244
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
2168
2245
  var cx3 = (...parts) => parts.filter((p) => Boolean(p)).join(" ");
2169
2246
  var MAX_AUTO_REFRESH_POLLS = 1e3;
2170
2247
  var DEFAULT_AUTO_REFRESH_FREQUENCY_MS = 2e4;
@@ -2208,7 +2285,7 @@ function formatStatusTime(ms) {
2208
2285
  return new Date(ms).toLocaleTimeString([], { hour: "numeric", minute: "2-digit", second: "2-digit" });
2209
2286
  }
2210
2287
  function useFieldHasNull(api, fieldName) {
2211
- const [hasNull, setHasNull] = useState5(void 0);
2288
+ const [hasNull, setHasNull] = useState6(void 0);
2212
2289
  useEffect5(() => {
2213
2290
  if (!fieldName) return;
2214
2291
  let cancelled = false;
@@ -2234,7 +2311,9 @@ function predicateAsText(clause, byName) {
2234
2311
  const op = clause.op.replace(/_/g, " ");
2235
2312
  const not = clause.negated ? "not " : "";
2236
2313
  if (NULLARY_OPS2.has(clause.op)) return `${field} ${not}${op}`;
2237
- const value = clause.value === "" ? "''" : clause.value;
2314
+ const strategy = byName.get(clause.field)?.filter?.values;
2315
+ const option = strategy?.source === "static" ? strategy.options.find((o) => typeof o !== "string" && o.value === clause.value) : void 0;
2316
+ const value = clause.value === "" ? "''" : typeof option === "object" ? option.label : clause.value;
2238
2317
  return `${field} ${not}${op} ${value}`;
2239
2318
  }
2240
2319
  function whereTermAsText(term, byName) {
@@ -2254,9 +2333,6 @@ function chipFieldWidthForInput(text, fieldType, fallback = 5, padding = 0) {
2254
2333
  const cap = fieldType === "number" ? 10 : 30;
2255
2334
  return chipFieldWidthChars(text, fallback, cap) + padding;
2256
2335
  }
2257
- function chipFieldWidthForSelect(text, fallback = 3, max = 30) {
2258
- return chipFieldWidthChars(text, fallback, max) + 2;
2259
- }
2260
2336
  function buildCollapsedSummary(where, orderBy, byName) {
2261
2337
  const whereText = whereClauseSummaryText(where, byName);
2262
2338
  const orderText = orderBy.length === 0 ? "(default)" : orderBy.map((term) => orderByAsText(term, byName)).join(", ");
@@ -2279,15 +2355,15 @@ function QueryBuilder({
2279
2355
  defaultCollapsed = false
2280
2356
  }) {
2281
2357
  const UNSAVED_QUERY_EDIT_ID = "__qt-unsaved-query__";
2282
- const [showSaved, setShowSaved] = useState5(false);
2283
- const [shareCopied, setShareCopied] = useState5(false);
2284
- const [showAutoRefresh, setShowAutoRefresh] = useState5(false);
2285
- const [autoRefreshFrequencyMs, setAutoRefreshFrequencyMs] = useState5(DEFAULT_AUTO_REFRESH_FREQUENCY_MS);
2286
- const [autoRefreshTurnOffAfterMs, setAutoRefreshTurnOffAfterMs] = useState5(DEFAULT_AUTO_REFRESH_TURN_OFF_AFTER_MS);
2287
- const [editingSavedId, setEditingSavedId] = useState5(null);
2288
- const [editingSavedName, setEditingSavedName] = useState5("");
2289
- const [lastSavedId, setLastSavedId] = useState5(null);
2290
- const [collapsedFallback, setCollapsedFallback] = useState5(defaultCollapsed);
2358
+ const [showSaved, setShowSaved] = useState6(false);
2359
+ const [shareCopied, setShareCopied] = useState6(false);
2360
+ const [showAutoRefresh, setShowAutoRefresh] = useState6(false);
2361
+ const [autoRefreshFrequencyMs, setAutoRefreshFrequencyMs] = useState6(DEFAULT_AUTO_REFRESH_FREQUENCY_MS);
2362
+ const [autoRefreshTurnOffAfterMs, setAutoRefreshTurnOffAfterMs] = useState6(DEFAULT_AUTO_REFRESH_TURN_OFF_AFTER_MS);
2363
+ const [editingSavedId, setEditingSavedId] = useState6(null);
2364
+ const [editingSavedName, setEditingSavedName] = useState6("");
2365
+ const [lastSavedId, setLastSavedId] = useState6(null);
2366
+ const [collapsedFallback, setCollapsedFallback] = useState6(defaultCollapsed);
2291
2367
  const collapsedControlled = typeof collapsed !== "undefined";
2292
2368
  const isCollapsed = collapsedControlled ? collapsed : collapsedFallback;
2293
2369
  const setCollapsed = (next) => {
@@ -2297,8 +2373,8 @@ function QueryBuilder({
2297
2373
  }
2298
2374
  setCollapsedFallback(next);
2299
2375
  };
2300
- const [lastUpdatedAt, setLastUpdatedAt] = useState5(null);
2301
- const [lastFailureAt, setLastFailureAt] = useState5(null);
2376
+ const [lastUpdatedAt, setLastUpdatedAt] = useState6(null);
2377
+ const [lastFailureAt, setLastFailureAt] = useState6(null);
2302
2378
  const byName = useMemo4(() => new Map(fields.map((f) => [f.name, f])), [fields]);
2303
2379
  const activeSavedQuery = useMemo4(
2304
2380
  () => api.saved.items.find((item) => queriesEqual(item.query, api.query)),
@@ -2338,7 +2414,7 @@ function QueryBuilder({
2338
2414
  const previousLoadingRef = useRef3(api.loading);
2339
2415
  const autoRefreshRef = useRef3(null);
2340
2416
  const autoRefreshPopoverRef = useRef3(null);
2341
- const [autoRefreshPopoverAlignRight, setAutoRefreshPopoverAlignRight] = useState5(false);
2417
+ const [autoRefreshPopoverAlignRight, setAutoRefreshPopoverAlignRight] = useState6(false);
2342
2418
  const shareFeedbackTimerRef = useRef3(null);
2343
2419
  useEffect5(
2344
2420
  () => () => {
@@ -2533,11 +2609,11 @@ function QueryBuilder({
2533
2609
  window.prompt("Copy this query URL", url.toString());
2534
2610
  }
2535
2611
  }
2536
- return /* @__PURE__ */ jsxs6("div", { className: cx3("qt-qb", classNames?.root), children: [
2537
- /* @__PURE__ */ jsxs6("div", { className: "qt-qb-bar qt-qb-state-bar qt-qb-row", children: [
2538
- /* @__PURE__ */ jsxs6("span", { className: "qt-qb-state-main", children: [
2539
- /* @__PURE__ */ jsxs6("span", { className: "qt-qb-saved", children: [
2540
- /* @__PURE__ */ jsx6(
2612
+ return /* @__PURE__ */ jsxs7("div", { className: cx3("qt-qb", classNames?.root), children: [
2613
+ /* @__PURE__ */ jsxs7("div", { className: "qt-qb-bar qt-qb-state-bar qt-qb-row", children: [
2614
+ /* @__PURE__ */ jsxs7("span", { className: "qt-qb-state-main", children: [
2615
+ /* @__PURE__ */ jsxs7("span", { className: "qt-qb-saved", children: [
2616
+ /* @__PURE__ */ jsx7(
2541
2617
  "button",
2542
2618
  {
2543
2619
  type: "button",
@@ -2548,8 +2624,8 @@ function QueryBuilder({
2548
2624
  children: isSavedQuery ? "\u2605" : "\u2606"
2549
2625
  }
2550
2626
  ),
2551
- isEditingSaved || isEditingUnsaved ? /* @__PURE__ */ jsxs6("span", { className: "qt-qb-saved-input-wrap", children: [
2552
- /* @__PURE__ */ jsx6(
2627
+ isEditingSaved || isEditingUnsaved ? /* @__PURE__ */ jsxs7("span", { className: "qt-qb-saved-input-wrap", children: [
2628
+ /* @__PURE__ */ jsx7(
2553
2629
  "input",
2554
2630
  {
2555
2631
  type: "text",
@@ -2572,7 +2648,7 @@ function QueryBuilder({
2572
2648
  onClick: (e) => e.stopPropagation()
2573
2649
  }
2574
2650
  ),
2575
- /* @__PURE__ */ jsx6(
2651
+ /* @__PURE__ */ jsx7(
2576
2652
  "button",
2577
2653
  {
2578
2654
  type: "button",
@@ -2586,7 +2662,7 @@ function QueryBuilder({
2586
2662
  children: "\u2715"
2587
2663
  }
2588
2664
  )
2589
- ] }) : /* @__PURE__ */ jsx6(
2665
+ ] }) : /* @__PURE__ */ jsx7(
2590
2666
  "button",
2591
2667
  {
2592
2668
  type: "button",
@@ -2596,17 +2672,17 @@ function QueryBuilder({
2596
2672
  }
2597
2673
  )
2598
2674
  ] }),
2599
- isCollapsed ? /* @__PURE__ */ jsxs6("span", { className: "qt-qb-summary qt-truncate", title: collapsedSummary, children: [
2600
- /* @__PURE__ */ jsx6("span", { className: "qt-qb-summary-kw", children: "WHERE" }),
2675
+ isCollapsed ? /* @__PURE__ */ jsxs7("span", { className: "qt-qb-summary qt-truncate", title: collapsedSummary, children: [
2676
+ /* @__PURE__ */ jsx7("span", { className: "qt-qb-summary-kw", children: "WHERE" }),
2601
2677
  " ",
2602
- /* @__PURE__ */ jsx6("strong", { children: collapsedWhereText }),
2678
+ /* @__PURE__ */ jsx7("strong", { children: collapsedWhereText }),
2603
2679
  " ",
2604
- /* @__PURE__ */ jsx6("span", { className: "qt-qb-summary-kw", children: "ORDER BY" }),
2680
+ /* @__PURE__ */ jsx7("span", { className: "qt-qb-summary-kw", children: "ORDER BY" }),
2605
2681
  " ",
2606
- /* @__PURE__ */ jsx6("strong", { children: collapsedOrderText })
2682
+ /* @__PURE__ */ jsx7("strong", { children: collapsedOrderText })
2607
2683
  ] }) : null
2608
2684
  ] }),
2609
- showUpdateButton ? /* @__PURE__ */ jsx6(
2685
+ showUpdateButton ? /* @__PURE__ */ jsx7(
2610
2686
  "button",
2611
2687
  {
2612
2688
  type: "button",
@@ -2616,7 +2692,7 @@ function QueryBuilder({
2616
2692
  children: `Update Query '${lastSavedQuery?.name ?? "query"}'`
2617
2693
  }
2618
2694
  ) : null,
2619
- /* @__PURE__ */ jsx6(
2695
+ /* @__PURE__ */ jsx7(
2620
2696
  "button",
2621
2697
  {
2622
2698
  type: "button",
@@ -2627,11 +2703,11 @@ function QueryBuilder({
2627
2703
  children: shareCopied ? "Copied!" : "Share"
2628
2704
  }
2629
2705
  ),
2630
- /* @__PURE__ */ jsxs6("button", { type: "button", className: cx3("qt-btn", classNames?.button), onClick: () => setShowSaved(true), children: [
2706
+ /* @__PURE__ */ jsxs7("button", { type: "button", className: cx3("qt-btn", classNames?.button), onClick: () => setShowSaved(true), children: [
2631
2707
  "Saved",
2632
2708
  api.saved.items.length > 0 ? ` (${api.saved.items.length})` : ""
2633
2709
  ] }),
2634
- /* @__PURE__ */ jsxs6(
2710
+ /* @__PURE__ */ jsxs7(
2635
2711
  "button",
2636
2712
  {
2637
2713
  type: "button",
@@ -2641,7 +2717,7 @@ function QueryBuilder({
2641
2717
  "aria-controls": bodyId,
2642
2718
  title: isCollapsed ? "Expand query builder" : "Collapse query builder",
2643
2719
  children: [
2644
- /* @__PURE__ */ jsx6(
2720
+ /* @__PURE__ */ jsx7(
2645
2721
  "span",
2646
2722
  {
2647
2723
  className: cx3("qt-qb-collapse-caret", isCollapsed && "qt-qb-collapse-caret--collapsed"),
@@ -2649,38 +2725,38 @@ function QueryBuilder({
2649
2725
  children: "\u25BE"
2650
2726
  }
2651
2727
  ),
2652
- /* @__PURE__ */ jsx6("span", { className: "qt-sr-only", children: isCollapsed ? "Expand query builder" : "Collapse query builder" })
2728
+ /* @__PURE__ */ jsx7("span", { className: "qt-sr-only", children: isCollapsed ? "Expand query builder" : "Collapse query builder" })
2653
2729
  ]
2654
2730
  }
2655
2731
  )
2656
2732
  ] }),
2657
- !isCollapsed ? /* @__PURE__ */ jsxs6("div", { className: "qt-qb-bar qt-qb-editor-bar", children: [
2658
- /* @__PURE__ */ jsxs6("div", { id: bodyId, className: "qt-qb-body", children: [
2659
- /* @__PURE__ */ jsx6(SelectRow, { api, fields, classNames, disabled: isBusy }),
2660
- /* @__PURE__ */ jsx6(WhereRow, { api, byName, fields, classNames, disabled: isBusy }),
2661
- /* @__PURE__ */ jsx6(OrderRow, { api, fields, classNames, disabled: isBusy }),
2662
- /* @__PURE__ */ jsx6(WindowRow, { api, classNames, disabled: isBusy }),
2663
- /* @__PURE__ */ jsx6(MetricsRow, { api, fields, classNames, disabled: isBusy })
2733
+ !isCollapsed ? /* @__PURE__ */ jsxs7("div", { className: "qt-qb-bar qt-qb-editor-bar", children: [
2734
+ /* @__PURE__ */ jsxs7("div", { id: bodyId, className: "qt-qb-body", children: [
2735
+ /* @__PURE__ */ jsx7(SelectRow, { api, fields, classNames, disabled: isBusy }),
2736
+ /* @__PURE__ */ jsx7(WhereRow, { api, byName, fields, classNames, disabled: isBusy }),
2737
+ /* @__PURE__ */ jsx7(OrderRow, { api, fields, classNames, disabled: isBusy }),
2738
+ /* @__PURE__ */ jsx7(WindowRow, { api, classNames, disabled: isBusy }),
2739
+ /* @__PURE__ */ jsx7(MetricsRow, { api, fields, classNames, disabled: isBusy })
2664
2740
  ] }),
2665
- /* @__PURE__ */ jsxs6("div", { className: "qt-qb-editor-stack", children: [
2666
- /* @__PURE__ */ jsx6("button", { type: "button", className: cx3("qt-btn", classNames?.button), onClick: api.undo, disabled: !api.canUndo || isBusy, children: "\u21B6 Undo" }),
2667
- /* @__PURE__ */ jsx6("button", { type: "button", className: cx3("qt-btn", classNames?.button), onClick: api.redo, disabled: !api.canRedo || isBusy, children: "\u21B7 Redo" }),
2668
- /* @__PURE__ */ jsx6("button", { type: "button", className: cx3("qt-btn", classNames?.button), onClick: api.resetAll, disabled: isBusy, children: "Reset All" })
2741
+ /* @__PURE__ */ jsxs7("div", { className: "qt-qb-editor-stack", children: [
2742
+ /* @__PURE__ */ jsx7("button", { type: "button", className: cx3("qt-btn", classNames?.button), onClick: api.undo, disabled: !api.canUndo || isBusy, children: "\u21B6 Undo" }),
2743
+ /* @__PURE__ */ jsx7("button", { type: "button", className: cx3("qt-btn", classNames?.button), onClick: api.redo, disabled: !api.canRedo || isBusy, children: "\u21B7 Redo" }),
2744
+ /* @__PURE__ */ jsx7("button", { type: "button", className: cx3("qt-btn", classNames?.button), onClick: api.resetAll, disabled: isBusy, children: "Reset All" })
2669
2745
  ] })
2670
2746
  ] }) : null,
2671
- /* @__PURE__ */ jsxs6("div", { className: "qt-qb-bar qt-qb-run-bar qt-qb-row", children: [
2672
- /* @__PURE__ */ jsx6("span", { className: "qt-qb-run-metric qt-qb-run-metric--strong", children: api.loading ? "loading\u2026" : `${rowSummary} rows` }),
2673
- /* @__PURE__ */ jsxs6("span", { className: "qt-qb-run-metric", children: [
2747
+ /* @__PURE__ */ jsxs7("div", { className: "qt-qb-bar qt-qb-run-bar qt-qb-row", children: [
2748
+ /* @__PURE__ */ jsx7("span", { className: "qt-qb-run-metric qt-qb-run-metric--strong", children: api.loading ? "loading\u2026" : `${rowSummary} rows` }),
2749
+ /* @__PURE__ */ jsxs7("span", { className: "qt-qb-run-metric", children: [
2674
2750
  "Last updated ",
2675
2751
  lastUpdatedText
2676
2752
  ] }),
2677
- failureText ? /* @__PURE__ */ jsx6("span", { className: "qt-qb-run-error", children: failureText }) : null,
2678
- /* @__PURE__ */ jsxs6("span", { className: "qt-qb-run-actions", children: [
2679
- autoRefreshStatus ? /* @__PURE__ */ jsx6("span", { className: "qt-qb-auto-status", children: `Every ${formatDuration2(autoRefreshStatus.frequencyMs)}; clear after ${formatDuration2(
2753
+ failureText ? /* @__PURE__ */ jsx7("span", { className: "qt-qb-run-error", children: failureText }) : null,
2754
+ /* @__PURE__ */ jsxs7("span", { className: "qt-qb-run-actions", children: [
2755
+ autoRefreshStatus ? /* @__PURE__ */ jsx7("span", { className: "qt-qb-auto-status", children: `Every ${formatDuration2(autoRefreshStatus.frequencyMs)}; clear after ${formatDuration2(
2680
2756
  autoRefreshStatus.turnOffAfterMs
2681
2757
  )} (${autoRefreshStatus.pollCount} polls run)` }) : null,
2682
- /* @__PURE__ */ jsxs6("span", { className: "qt-auto-refresh", ref: autoRefreshRef, children: [
2683
- /* @__PURE__ */ jsx6(
2758
+ /* @__PURE__ */ jsxs7("span", { className: "qt-auto-refresh", ref: autoRefreshRef, children: [
2759
+ /* @__PURE__ */ jsx7(
2684
2760
  "button",
2685
2761
  {
2686
2762
  type: "button",
@@ -2691,7 +2767,7 @@ function QueryBuilder({
2691
2767
  children: autoRefreshButtonText
2692
2768
  }
2693
2769
  ),
2694
- showAutoRefresh ? /* @__PURE__ */ jsxs6(
2770
+ showAutoRefresh ? /* @__PURE__ */ jsxs7(
2695
2771
  "span",
2696
2772
  {
2697
2773
  ref: autoRefreshPopoverRef,
@@ -2699,27 +2775,27 @@ function QueryBuilder({
2699
2775
  role: "dialog",
2700
2776
  "aria-label": "Auto-refresh settings",
2701
2777
  children: [
2702
- /* @__PURE__ */ jsxs6("label", { className: "qt-auto-refresh-field", children: [
2703
- /* @__PURE__ */ jsx6("span", { children: "Frequency" }),
2704
- /* @__PURE__ */ jsx6(
2778
+ /* @__PURE__ */ jsxs7("label", { className: "qt-auto-refresh-field", children: [
2779
+ /* @__PURE__ */ jsx7("span", { children: "Frequency" }),
2780
+ /* @__PURE__ */ jsx7(
2705
2781
  "select",
2706
2782
  {
2707
2783
  className: "qt-auto-refresh-select",
2708
2784
  value: autoRefreshFrequencyMs,
2709
2785
  onChange: (e) => setAutoRefreshFrequencyMs(Number(e.target.value)),
2710
- children: AUTO_REFRESH_FREQUENCIES.map((option) => /* @__PURE__ */ jsx6("option", { value: option.value, children: option.label }, option.value))
2786
+ children: AUTO_REFRESH_FREQUENCIES.map((option) => /* @__PURE__ */ jsx7("option", { value: option.value, children: option.label }, option.value))
2711
2787
  }
2712
2788
  )
2713
2789
  ] }),
2714
- /* @__PURE__ */ jsxs6("label", { className: "qt-auto-refresh-field", children: [
2715
- /* @__PURE__ */ jsx6("span", { children: "Turn off after" }),
2716
- /* @__PURE__ */ jsx6(
2790
+ /* @__PURE__ */ jsxs7("label", { className: "qt-auto-refresh-field", children: [
2791
+ /* @__PURE__ */ jsx7("span", { children: "Turn off after" }),
2792
+ /* @__PURE__ */ jsx7(
2717
2793
  "select",
2718
2794
  {
2719
2795
  className: "qt-auto-refresh-select",
2720
2796
  value: autoRefreshTurnOffAfterMs,
2721
2797
  onChange: (e) => setAutoRefreshTurnOffAfterMs(Number(e.target.value)),
2722
- children: AUTO_REFRESH_TURN_OFF_AFTER.map((option) => /* @__PURE__ */ jsx6(
2798
+ children: AUTO_REFRESH_TURN_OFF_AFTER.map((option) => /* @__PURE__ */ jsx7(
2723
2799
  "option",
2724
2800
  {
2725
2801
  value: option.value,
@@ -2731,8 +2807,8 @@ function QueryBuilder({
2731
2807
  }
2732
2808
  )
2733
2809
  ] }),
2734
- /* @__PURE__ */ jsx6("span", { className: cx3("qt-auto-refresh-status", !canSubmitAutoRefresh && "qt-auto-refresh-status--error"), children: canSubmitAutoRefresh ? `${selectedAutoRefreshPolls} polls maximum` : `Choose between 1 and 1000 polls` }),
2735
- autoRefreshStatus ? /* @__PURE__ */ jsxs6("span", { className: "qt-auto-refresh-status", children: [
2810
+ /* @__PURE__ */ jsx7("span", { className: cx3("qt-auto-refresh-status", !canSubmitAutoRefresh && "qt-auto-refresh-status--error"), children: canSubmitAutoRefresh ? `${selectedAutoRefreshPolls} polls maximum` : `Choose between 1 and 1000 polls` }),
2811
+ autoRefreshStatus ? /* @__PURE__ */ jsxs7("span", { className: "qt-auto-refresh-status", children: [
2736
2812
  "Active: every ",
2737
2813
  formatDuration2(autoRefreshStatus.frequencyMs),
2738
2814
  ", clears after",
@@ -2742,8 +2818,8 @@ function QueryBuilder({
2742
2818
  autoRefreshStatus.pollCount,
2743
2819
  " polls run."
2744
2820
  ] }) : null,
2745
- /* @__PURE__ */ jsxs6("span", { className: "qt-auto-refresh-actions", children: [
2746
- /* @__PURE__ */ jsx6(
2821
+ /* @__PURE__ */ jsxs7("span", { className: "qt-auto-refresh-actions", children: [
2822
+ /* @__PURE__ */ jsx7(
2747
2823
  "button",
2748
2824
  {
2749
2825
  type: "button",
@@ -2753,7 +2829,7 @@ function QueryBuilder({
2753
2829
  children: autoRefreshStatus ? "Update" : "Start"
2754
2830
  }
2755
2831
  ),
2756
- autoRefreshStatus ? /* @__PURE__ */ jsx6(
2832
+ autoRefreshStatus ? /* @__PURE__ */ jsx7(
2757
2833
  "button",
2758
2834
  {
2759
2835
  type: "button",
@@ -2770,7 +2846,7 @@ function QueryBuilder({
2770
2846
  }
2771
2847
  ) : null
2772
2848
  ] }),
2773
- /* @__PURE__ */ jsx6(
2849
+ /* @__PURE__ */ jsx7(
2774
2850
  "button",
2775
2851
  {
2776
2852
  type: "button",
@@ -2782,7 +2858,7 @@ function QueryBuilder({
2782
2858
  )
2783
2859
  ] })
2784
2860
  ] }),
2785
- !isCollapsed && showSaved ? /* @__PURE__ */ jsx6(SavedQueriesModal, { saved: api.saved, onClose: () => setShowSaved(false), onLoad: setLastSavedId }) : null
2861
+ !isCollapsed && showSaved ? /* @__PURE__ */ jsx7(SavedQueriesModal, { saved: api.saved, onClose: () => setShowSaved(false), onLoad: setLastSavedId }) : null
2786
2862
  ] });
2787
2863
  }
2788
2864
  function MoveButtons({
@@ -2793,8 +2869,8 @@ function MoveButtons({
2793
2869
  onMove
2794
2870
  }) {
2795
2871
  if (count < 2) return null;
2796
- return /* @__PURE__ */ jsxs6("span", { className: "qt-chip-move-buttons", children: [
2797
- /* @__PURE__ */ jsx6(
2872
+ return /* @__PURE__ */ jsxs7("span", { className: "qt-chip-move-buttons", children: [
2873
+ /* @__PURE__ */ jsx7(
2798
2874
  "button",
2799
2875
  {
2800
2876
  type: "button",
@@ -2806,7 +2882,7 @@ function MoveButtons({
2806
2882
  children: "\u2190"
2807
2883
  }
2808
2884
  ),
2809
- /* @__PURE__ */ jsx6(
2885
+ /* @__PURE__ */ jsx7(
2810
2886
  "button",
2811
2887
  {
2812
2888
  type: "button",
@@ -2827,8 +2903,8 @@ function SelectRow({
2827
2903
  disabled
2828
2904
  }) {
2829
2905
  const { select, columnDrag } = api;
2830
- const [editingColumns, setEditingColumns] = useState5(false);
2831
- const [adding, setAdding] = useState5(false);
2906
+ const [editingColumns, setEditingColumns] = useState6(false);
2907
+ const [adding, setAdding] = useState6(false);
2832
2908
  const fieldLabelByName = useMemo4(() => new Map(select.fields.map((f) => [f.name, f.label])), [select.fields]);
2833
2909
  function reorderByIndex(from, overIndex) {
2834
2910
  select.move(from, overIndex);
@@ -2836,13 +2912,13 @@ function SelectRow({
2836
2912
  const fieldNames = select.visible.map((c) => c.field);
2837
2913
  const dragSource = columnDrag.source;
2838
2914
  const rendered = columnDrag.preview(fieldNames);
2839
- return /* @__PURE__ */ jsxs6("div", { className: "qt-qb-row", children: [
2840
- /* @__PURE__ */ jsx6("span", { className: "qt-qb-kw", children: "select" }),
2841
- /* @__PURE__ */ jsx6("button", { type: "button", className: "qt-btn", disabled, onClick: () => setEditingColumns(true), children: "Edit columns" }),
2842
- editingColumns && /* @__PURE__ */ jsx6(SelectColumnEditor, { api, onClose: () => setEditingColumns(false) }),
2915
+ return /* @__PURE__ */ jsxs7("div", { className: "qt-qb-row", children: [
2916
+ /* @__PURE__ */ jsx7("span", { className: "qt-qb-kw", children: "select" }),
2917
+ /* @__PURE__ */ jsx7("button", { type: "button", className: "qt-btn", disabled, onClick: () => setEditingColumns(true), children: "Edit columns" }),
2918
+ editingColumns && /* @__PURE__ */ jsx7(SelectColumnEditor, { api, onClose: () => setEditingColumns(false) }),
2843
2919
  rendered.map((name, position) => {
2844
2920
  const label = fieldLabelByName.get(name) ?? name;
2845
- return /* @__PURE__ */ jsxs6(
2921
+ return /* @__PURE__ */ jsxs7(
2846
2922
  "span",
2847
2923
  {
2848
2924
  className: cx3(
@@ -2881,9 +2957,9 @@ function SelectRow({
2881
2957
  onDragEnd: () => columnDrag.end(),
2882
2958
  title: "drag to reorder",
2883
2959
  children: [
2884
- /* @__PURE__ */ jsx6("span", { "aria-hidden": true, className: "qt-chip-grip", children: "\u22EE\u22EE" }),
2885
- /* @__PURE__ */ jsx6("span", { className: "qt-chip-field", children: label }),
2886
- /* @__PURE__ */ jsx6(
2960
+ /* @__PURE__ */ jsx7("span", { "aria-hidden": true, className: "qt-chip-grip", children: "\u22EE\u22EE" }),
2961
+ /* @__PURE__ */ jsx7("span", { className: "qt-chip-field", children: label }),
2962
+ /* @__PURE__ */ jsx7(
2887
2963
  MoveButtons,
2888
2964
  {
2889
2965
  label,
@@ -2893,13 +2969,13 @@ function SelectRow({
2893
2969
  onMove: (nextPosition) => select.move(name, nextPosition)
2894
2970
  }
2895
2971
  ),
2896
- /* @__PURE__ */ jsx6("button", { type: "button", className: "qt-chip-x", onClick: () => select.hide(name), disabled, children: "\u2715" })
2972
+ /* @__PURE__ */ jsx7("button", { type: "button", className: "qt-chip-x", onClick: () => select.hide(name), disabled, children: "\u2715" })
2897
2973
  ]
2898
2974
  },
2899
2975
  name
2900
2976
  );
2901
2977
  }),
2902
- adding ? /* @__PURE__ */ jsx6(
2978
+ adding ? /* @__PURE__ */ jsx7(
2903
2979
  FieldPicker,
2904
2980
  {
2905
2981
  fields: select.hidden.filter(isSelectable2),
@@ -2909,7 +2985,7 @@ function SelectRow({
2909
2985
  },
2910
2986
  onClose: () => setAdding(false)
2911
2987
  }
2912
- ) : /* @__PURE__ */ jsx6(
2988
+ ) : /* @__PURE__ */ jsx7(
2913
2989
  "button",
2914
2990
  {
2915
2991
  type: "button",
@@ -2919,7 +2995,7 @@ function SelectRow({
2919
2995
  children: "+ add column"
2920
2996
  }
2921
2997
  ),
2922
- api.query.select.length > 0 && /* @__PURE__ */ jsx6("button", { type: "button", className: "qt-link-btn", onClick: select.reset, disabled, title: "Reset to default columns", children: "reset" })
2998
+ api.query.select.length > 0 && /* @__PURE__ */ jsx7("button", { type: "button", className: "qt-link-btn", onClick: select.reset, disabled, title: "Reset to default columns", children: "reset" })
2923
2999
  ] });
2924
3000
  }
2925
3001
  function dropModeFor(e) {
@@ -2936,8 +3012,8 @@ function WhereRow({
2936
3012
  classNames,
2937
3013
  disabled
2938
3014
  }) {
2939
- const [adding, setAdding] = useState5(false);
2940
- const [drag, setDrag] = useState5(null);
3015
+ const [adding, setAdding] = useState6(false);
3016
+ const [drag, setDrag] = useState6(null);
2941
3017
  const where = api.query.where;
2942
3018
  const hasOr = where.some(isOrGroup);
2943
3019
  function addClause(f) {
@@ -2968,12 +3044,12 @@ function WhereRow({
2968
3044
  }
2969
3045
  setDrag(null);
2970
3046
  }
2971
- return /* @__PURE__ */ jsxs6("div", { className: "qt-qb-row", children: [
2972
- /* @__PURE__ */ jsx6("span", { className: "qt-qb-kw", children: "where" }),
2973
- where.length === 0 && !adding && /* @__PURE__ */ jsx6("span", { className: "qt-qb-hint", children: "all rows" }),
2974
- where.map((term, index) => /* @__PURE__ */ jsxs6("span", { className: "qt-where-term-wrap", children: [
2975
- index > 0 && hasOr && /* @__PURE__ */ jsx6("span", { className: "qt-where-and", children: "AND" }),
2976
- /* @__PURE__ */ jsx6(
3047
+ return /* @__PURE__ */ jsxs7("div", { className: "qt-qb-row", children: [
3048
+ /* @__PURE__ */ jsx7("span", { className: "qt-qb-kw", children: "where" }),
3049
+ where.length === 0 && !adding && /* @__PURE__ */ jsx7("span", { className: "qt-qb-hint", children: "all rows" }),
3050
+ where.map((term, index) => /* @__PURE__ */ jsxs7("span", { className: "qt-where-term-wrap", children: [
3051
+ index > 0 && hasOr && /* @__PURE__ */ jsx7("span", { className: "qt-where-and", children: "AND" }),
3052
+ /* @__PURE__ */ jsx7(
2977
3053
  TermChip,
2978
3054
  {
2979
3055
  api,
@@ -2991,7 +3067,7 @@ function WhereRow({
2991
3067
  }
2992
3068
  )
2993
3069
  ] }, index)),
2994
- adding ? /* @__PURE__ */ jsx6(
3070
+ adding ? /* @__PURE__ */ jsx7(
2995
3071
  FieldPicker,
2996
3072
  {
2997
3073
  fields: fields.filter(isFilterable2),
@@ -2999,8 +3075,8 @@ function WhereRow({
2999
3075
  onPick: addClause,
3000
3076
  onClose: () => setAdding(false)
3001
3077
  }
3002
- ) : /* @__PURE__ */ jsx6("button", { type: "button", className: "qt-add", onClick: () => setAdding(true), disabled, children: "+ add filter" }),
3003
- where.length > 0 && /* @__PURE__ */ jsx6("button", { type: "button", className: "qt-link-btn", onClick: api.clearFilters, disabled, title: "Reset filters", children: "reset" })
3078
+ ) : /* @__PURE__ */ jsx7("button", { type: "button", className: "qt-add", onClick: () => setAdding(true), disabled, children: "+ add filter" }),
3079
+ where.length > 0 && /* @__PURE__ */ jsx7("button", { type: "button", className: "qt-link-btn", onClick: api.clearFilters, disabled, title: "Reset filters", children: "reset" })
3004
3080
  ] });
3005
3081
  }
3006
3082
  function TermChip({
@@ -3019,7 +3095,7 @@ function TermChip({
3019
3095
  }) {
3020
3096
  const group = isOrGroup(term);
3021
3097
  const predicates = predicatesOf(term);
3022
- const grip = /* @__PURE__ */ jsx6(
3098
+ const grip = /* @__PURE__ */ jsx7(
3023
3099
  "span",
3024
3100
  {
3025
3101
  className: "qt-chip-grip",
@@ -3035,7 +3111,7 @@ function TermChip({
3035
3111
  children: "\u22EE\u22EE"
3036
3112
  }
3037
3113
  );
3038
- return /* @__PURE__ */ jsxs6(
3114
+ return /* @__PURE__ */ jsxs7(
3039
3115
  "span",
3040
3116
  {
3041
3117
  className: cx3(
@@ -3053,9 +3129,9 @@ function TermChip({
3053
3129
  },
3054
3130
  children: [
3055
3131
  grip,
3056
- group ? /* @__PURE__ */ jsx6("span", { className: "qt-or-group", children: predicates.map((clause, predIndex) => /* @__PURE__ */ jsxs6("span", { className: "qt-or-member", children: [
3057
- predIndex > 0 && /* @__PURE__ */ jsx6("span", { className: "qt-chip-and qt-chip-or", children: "OR" }),
3058
- /* @__PURE__ */ jsx6(
3132
+ group ? /* @__PURE__ */ jsx7("span", { className: "qt-or-group", children: predicates.map((clause, predIndex) => /* @__PURE__ */ jsxs7("span", { className: "qt-or-member", children: [
3133
+ predIndex > 0 && /* @__PURE__ */ jsx7("span", { className: "qt-chip-and qt-chip-or", children: "OR" }),
3134
+ /* @__PURE__ */ jsx7(
3059
3135
  PredicateEditor,
3060
3136
  {
3061
3137
  api,
@@ -3067,7 +3143,7 @@ function TermChip({
3067
3143
  onRemove: () => api.removePredicate(index, predIndex)
3068
3144
  }
3069
3145
  )
3070
- ] }, predIndex)) }) : /* @__PURE__ */ jsx6(
3146
+ ] }, predIndex)) }) : /* @__PURE__ */ jsx7(
3071
3147
  PredicateEditor,
3072
3148
  {
3073
3149
  api,
@@ -3109,7 +3185,7 @@ function OpPicker({
3109
3185
  classNames,
3110
3186
  onPick
3111
3187
  }) {
3112
- const [open, setOpen] = useState5(false);
3188
+ const [open, setOpen] = useState6(false);
3113
3189
  const wrapRef = useRef3(null);
3114
3190
  useEffect5(() => {
3115
3191
  if (!open) return;
@@ -3129,8 +3205,8 @@ function OpPicker({
3129
3205
  }, [open]);
3130
3206
  const pairs = useMemo4(() => field ? opPairsForField2(field) : [], [field]);
3131
3207
  const isActive = (choice) => choice.op === clause.op && Boolean(choice.negated) === Boolean(clause.negated);
3132
- return /* @__PURE__ */ jsxs6("span", { className: "qt-op-picker", ref: wrapRef, children: [
3133
- /* @__PURE__ */ jsxs6(
3208
+ return /* @__PURE__ */ jsxs7("span", { className: "qt-op-picker", ref: wrapRef, children: [
3209
+ /* @__PURE__ */ jsxs7(
3134
3210
  "button",
3135
3211
  {
3136
3212
  type: "button",
@@ -3141,15 +3217,15 @@ function OpPicker({
3141
3217
  onClick: () => setOpen((o) => !o),
3142
3218
  children: [
3143
3219
  choiceLabel(clause.op, Boolean(clause.negated)),
3144
- /* @__PURE__ */ jsx6("span", { className: "qt-op-caret", "aria-hidden": true, children: "\u25BE" })
3220
+ /* @__PURE__ */ jsx7("span", { className: "qt-op-caret", "aria-hidden": true, children: "\u25BE" })
3145
3221
  ]
3146
3222
  }
3147
3223
  ),
3148
- open && pairs.length > 0 && /* @__PURE__ */ jsxs6("span", { className: "qt-op-pop", role: "dialog", "aria-label": "Choose condition", children: [
3149
- /* @__PURE__ */ jsx6("span", { className: "qt-cm-col-head", children: "keep" }),
3150
- /* @__PURE__ */ jsx6("span", { className: "qt-cm-col-head qt-cm-col-head--neg", children: "exclude" }),
3151
- pairs.map((pair, i) => /* @__PURE__ */ jsxs6(Fragment5, { children: [
3152
- /* @__PURE__ */ jsx6(
3224
+ open && pairs.length > 0 && /* @__PURE__ */ jsxs7("span", { className: "qt-op-pop", role: "dialog", "aria-label": "Choose condition", children: [
3225
+ /* @__PURE__ */ jsx7("span", { className: "qt-cm-col-head", children: "keep" }),
3226
+ /* @__PURE__ */ jsx7("span", { className: "qt-cm-col-head qt-cm-col-head--neg", children: "exclude" }),
3227
+ pairs.map((pair, i) => /* @__PURE__ */ jsxs7(Fragment6, { children: [
3228
+ /* @__PURE__ */ jsx7(
3153
3229
  "button",
3154
3230
  {
3155
3231
  type: "button",
@@ -3161,7 +3237,7 @@ function OpPicker({
3161
3237
  children: choiceLabel(pair.keep.op, pair.keep.negated)
3162
3238
  }
3163
3239
  ),
3164
- /* @__PURE__ */ jsx6(
3240
+ /* @__PURE__ */ jsx7(
3165
3241
  "button",
3166
3242
  {
3167
3243
  type: "button",
@@ -3193,10 +3269,10 @@ function PredicateEditor({
3193
3269
  if (choice.negated) next.negated = true;
3194
3270
  onChange(next);
3195
3271
  }
3196
- return /* @__PURE__ */ jsxs6("span", { className: "qt-pred", children: [
3197
- /* @__PURE__ */ jsx6("span", { className: "qt-chip-field", children: field?.label ?? clause.field }),
3198
- /* @__PURE__ */ jsx6(OpPicker, { field, clause, disabled, classNames, onPick: pickOp }),
3199
- needsValue && /* @__PURE__ */ jsx6(
3272
+ return /* @__PURE__ */ jsxs7("span", { className: "qt-pred", children: [
3273
+ /* @__PURE__ */ jsx7("span", { className: "qt-chip-field", children: field?.label ?? clause.field }),
3274
+ /* @__PURE__ */ jsx7(OpPicker, { field, clause, disabled, classNames, onPick: pickOp }),
3275
+ needsValue && /* @__PURE__ */ jsx7(
3200
3276
  ValueInput,
3201
3277
  {
3202
3278
  api,
@@ -3208,7 +3284,7 @@ function PredicateEditor({
3208
3284
  onChange: (v) => onChange({ ...clause, value: v })
3209
3285
  }
3210
3286
  ),
3211
- /* @__PURE__ */ jsx6("button", { type: "button", className: "qt-chip-x", onClick: onRemove, disabled, children: "\u2715" })
3287
+ /* @__PURE__ */ jsx7("button", { type: "button", className: "qt-chip-x", onClick: onRemove, disabled, children: "\u2715" })
3212
3288
  ] });
3213
3289
  }
3214
3290
  function ValueInput({
@@ -3220,27 +3296,23 @@ function ValueInput({
3220
3296
  classNames,
3221
3297
  onChange
3222
3298
  }) {
3299
+ const presentation = useFilterValuePresentation();
3223
3300
  const strategy = field ? filterValuesFor(field) : { source: "freeform" };
3224
3301
  if (!forceFreeform && strategy.source === "static") {
3225
- const selectedText = value || "\u2014";
3226
- const widthChars = chipFieldWidthForSelect(selectedText, 4);
3227
- return /* @__PURE__ */ jsxs6(
3228
- "select",
3229
- {
3230
- className: cx3("qt-chip-val", classNames?.select),
3231
- value,
3232
- style: { width: `${widthChars}ch` },
3233
- onChange: (e) => onChange(e.target.value),
3234
- children: [
3235
- /* @__PURE__ */ jsx6("option", { value: "", children: "\u2014" }),
3236
- strategy.options.map((o) => /* @__PURE__ */ jsx6("option", { value: o, children: o }, o))
3237
- ]
3238
- }
3239
- );
3302
+ if (presentation.render || presentation.label || strategy.options.some((o) => typeof o !== "string")) {
3303
+ return /* @__PURE__ */ jsx7(PresentedValueInput, { field: field?.name ?? "", value, options: strategy.options, onChange });
3304
+ }
3305
+ return /* @__PURE__ */ jsxs7("select", { className: cx3("qt-chip-val", classNames?.select), value, onChange: (e) => onChange(e.target.value), children: [
3306
+ /* @__PURE__ */ jsx7("option", { value: "", children: "\u2014" }),
3307
+ strategy.options.map((o) => {
3308
+ const option = typeof o === "string" ? { value: o, label: o } : o;
3309
+ return /* @__PURE__ */ jsx7("option", { value: option.value, children: option.label }, option.value);
3310
+ })
3311
+ ] });
3240
3312
  }
3241
3313
  if (forceFreeform || strategy.source === "freeform" || !field) {
3242
3314
  const widthChars = chipFieldWidthForInput(value || placeholder, field?.type, 5, 4);
3243
- return /* @__PURE__ */ jsx6(
3315
+ return /* @__PURE__ */ jsx7(
3244
3316
  "input",
3245
3317
  {
3246
3318
  className: cx3("qt-chip-val", classNames?.input),
@@ -3252,7 +3324,7 @@ function ValueInput({
3252
3324
  }
3253
3325
  );
3254
3326
  }
3255
- return /* @__PURE__ */ jsx6(AutocompleteInput, { api, field, value, classNames, onChange });
3327
+ return /* @__PURE__ */ jsx7(AutocompleteInput, { api, field, value, classNames, onChange });
3256
3328
  }
3257
3329
  function AutocompleteInput({
3258
3330
  api,
@@ -3261,7 +3333,7 @@ function AutocompleteInput({
3261
3333
  classNames,
3262
3334
  onChange
3263
3335
  }) {
3264
- const [result, setResult] = useState5({ values: [], hasMore: false });
3336
+ const [result, setResult] = useState6({ values: [], hasMore: false });
3265
3337
  const listId = useId2();
3266
3338
  useEffect5(() => {
3267
3339
  let cancelled = false;
@@ -3277,8 +3349,8 @@ function AutocompleteInput({
3277
3349
  clearTimeout(t);
3278
3350
  };
3279
3351
  }, [api, field.name, value]);
3280
- return /* @__PURE__ */ jsxs6("span", { className: "qt-autocomplete", children: [
3281
- /* @__PURE__ */ jsx6(
3352
+ return /* @__PURE__ */ jsxs7("span", { className: "qt-autocomplete", children: [
3353
+ /* @__PURE__ */ jsx7(
3282
3354
  "input",
3283
3355
  {
3284
3356
  className: cx3("qt-chip-val", classNames?.input),
@@ -3290,8 +3362,8 @@ function AutocompleteInput({
3290
3362
  onChange: (e) => onChange(e.target.value)
3291
3363
  }
3292
3364
  ),
3293
- /* @__PURE__ */ jsx6("datalist", { id: listId, children: result.values.map((v) => /* @__PURE__ */ jsx6("option", { value: v }, v)) }),
3294
- result.hasMore && /* @__PURE__ */ jsx6("span", { className: "qt-autocomplete-hint", children: "keep typing to refine\u2026" })
3365
+ /* @__PURE__ */ jsx7("datalist", { id: listId, children: result.values.map((v) => /* @__PURE__ */ jsx7("option", { value: v }, v)) }),
3366
+ result.hasMore && /* @__PURE__ */ jsx7("span", { className: "qt-autocomplete-hint", children: "keep typing to refine\u2026" })
3295
3367
  ] });
3296
3368
  }
3297
3369
  function OrderTermChip({
@@ -3317,7 +3389,7 @@ function OrderTermChip({
3317
3389
  label
3318
3390
  }) {
3319
3391
  const fieldHasNull = useFieldHasNull(api, field?.name);
3320
- return /* @__PURE__ */ jsxs6(
3392
+ return /* @__PURE__ */ jsxs7(
3321
3393
  "span",
3322
3394
  {
3323
3395
  className: cx3("qt-chip", "qt-chip--col", "qt-chip--sort", isDragSource && "qt-chip--dragging", classNames?.chip),
@@ -3335,10 +3407,10 @@ function OrderTermChip({
3335
3407
  onDragEnd,
3336
3408
  title: "drag to reorder sort priority",
3337
3409
  children: [
3338
- /* @__PURE__ */ jsx6("span", { "aria-hidden": true, className: "qt-chip-grip", children: "\u22EE\u22EE" }),
3339
- showPriority && /* @__PURE__ */ jsx6("span", { className: "qt-chip-priority", children: priority }),
3340
- /* @__PURE__ */ jsx6("span", { className: "qt-chip-field", children: label }),
3341
- /* @__PURE__ */ jsx6(
3410
+ /* @__PURE__ */ jsx7("span", { "aria-hidden": true, className: "qt-chip-grip", children: "\u22EE\u22EE" }),
3411
+ showPriority && /* @__PURE__ */ jsx7("span", { className: "qt-chip-priority", children: priority }),
3412
+ /* @__PURE__ */ jsx7("span", { className: "qt-chip-field", children: label }),
3413
+ /* @__PURE__ */ jsx7(
3342
3414
  "button",
3343
3415
  {
3344
3416
  type: "button",
@@ -3348,9 +3420,9 @@ function OrderTermChip({
3348
3420
  children: term.dir === "asc" ? "\u2191 asc" : "\u2193 desc"
3349
3421
  }
3350
3422
  ),
3351
- term.extract ? /* @__PURE__ */ jsxs6("span", { className: "qt-sort-extract", children: [
3352
- /* @__PURE__ */ jsx6("span", { className: "qt-chip-and", children: "extract" }),
3353
- /* @__PURE__ */ jsx6(
3423
+ term.extract ? /* @__PURE__ */ jsxs7("span", { className: "qt-sort-extract", children: [
3424
+ /* @__PURE__ */ jsx7("span", { className: "qt-chip-and", children: "extract" }),
3425
+ /* @__PURE__ */ jsx7(
3354
3426
  "input",
3355
3427
  {
3356
3428
  className: cx3("qt-chip-val", classNames?.input),
@@ -3363,7 +3435,7 @@ function OrderTermChip({
3363
3435
  onChange: (e) => updateTerm(dataIndex, { extract: { regex: e.target.value } })
3364
3436
  }
3365
3437
  ),
3366
- /* @__PURE__ */ jsx6(
3438
+ /* @__PURE__ */ jsx7(
3367
3439
  "button",
3368
3440
  {
3369
3441
  type: "button",
@@ -3375,7 +3447,7 @@ function OrderTermChip({
3375
3447
  children: "\u2715"
3376
3448
  }
3377
3449
  )
3378
- ] }) : /* @__PURE__ */ jsx6(
3450
+ ] }) : /* @__PURE__ */ jsx7(
3379
3451
  "button",
3380
3452
  {
3381
3453
  type: "button",
@@ -3386,7 +3458,7 @@ function OrderTermChip({
3386
3458
  children: "+ regex extract"
3387
3459
  }
3388
3460
  ),
3389
- (term.extract != null || fieldHasNull !== false) && /* @__PURE__ */ jsxs6(
3461
+ (term.extract != null || fieldHasNull !== false) && /* @__PURE__ */ jsxs7(
3390
3462
  "button",
3391
3463
  {
3392
3464
  type: "button",
@@ -3400,7 +3472,7 @@ function OrderTermChip({
3400
3472
  ]
3401
3473
  }
3402
3474
  ),
3403
- /* @__PURE__ */ jsx6(
3475
+ /* @__PURE__ */ jsx7(
3404
3476
  MoveButtons,
3405
3477
  {
3406
3478
  label,
@@ -3410,7 +3482,7 @@ function OrderTermChip({
3410
3482
  onMove: moveTerm
3411
3483
  }
3412
3484
  ),
3413
- /* @__PURE__ */ jsx6("button", { type: "button", className: "qt-chip-x", onClick: () => removeTerm(dataIndex), disabled, children: "\u2715" })
3485
+ /* @__PURE__ */ jsx7("button", { type: "button", className: "qt-chip-x", onClick: () => removeTerm(dataIndex), disabled, children: "\u2715" })
3414
3486
  ]
3415
3487
  }
3416
3488
  );
@@ -3423,8 +3495,8 @@ function OrderRow({
3423
3495
  }) {
3424
3496
  const orderBy = api.query.orderBy;
3425
3497
  const byName = useMemo4(() => new Map(fields.map((f) => [f.name, f])), [fields]);
3426
- const [drag, setDrag] = useState5(null);
3427
- const [adding, setAdding] = useState5(false);
3498
+ const [drag, setDrag] = useState6(null);
3499
+ const [adding, setAdding] = useState6(false);
3428
3500
  function setOrderBy(next) {
3429
3501
  api.setSort(next);
3430
3502
  }
@@ -3497,12 +3569,12 @@ function OrderRow({
3497
3569
  const next = api.defaults.orderBy[i];
3498
3570
  return term.field === next?.field && term.dir === next?.dir && (term.nulls ?? "last") === (next?.nulls ?? "last") && (term.extract?.regex ?? null) === (next?.extract?.regex ?? null);
3499
3571
  });
3500
- return /* @__PURE__ */ jsxs6("div", { className: "qt-qb-row", children: [
3501
- /* @__PURE__ */ jsx6("span", { className: "qt-qb-kw", children: "order by" }),
3502
- orderBy.length === 0 && !adding && /* @__PURE__ */ jsx6("span", { className: "qt-qb-hint", children: "(default)" }),
3572
+ return /* @__PURE__ */ jsxs7("div", { className: "qt-qb-row", children: [
3573
+ /* @__PURE__ */ jsx7("span", { className: "qt-qb-kw", children: "order by" }),
3574
+ orderBy.length === 0 && !adding && /* @__PURE__ */ jsx7("span", { className: "qt-qb-hint", children: "(default)" }),
3503
3575
  rendered.map((f, pos) => {
3504
3576
  const term = termByField.get(f);
3505
- return /* @__PURE__ */ jsx6(
3577
+ return /* @__PURE__ */ jsx7(
3506
3578
  OrderTermChip,
3507
3579
  {
3508
3580
  api,
@@ -3536,8 +3608,8 @@ function OrderRow({
3536
3608
  f
3537
3609
  );
3538
3610
  }),
3539
- adding ? /* @__PURE__ */ jsx6(FieldPicker, { fields: sortable, onPick: addTerm, onClose: () => setAdding(false) }) : /* @__PURE__ */ jsx6("button", { type: "button", className: "qt-add", onClick: () => setAdding(true), disabled, children: "+ add sort" }),
3540
- !isDefaultOrderBy && /* @__PURE__ */ jsx6("button", { type: "button", className: "qt-link-btn", onClick: () => api.setSort(api.defaults.orderBy), disabled, children: "reset" })
3611
+ adding ? /* @__PURE__ */ jsx7(FieldPicker, { fields: sortable, onPick: addTerm, onClose: () => setAdding(false) }) : /* @__PURE__ */ jsx7("button", { type: "button", className: "qt-add", onClick: () => setAdding(true), disabled, children: "+ add sort" }),
3612
+ !isDefaultOrderBy && /* @__PURE__ */ jsx7("button", { type: "button", className: "qt-link-btn", onClick: () => api.setSort(api.defaults.orderBy), disabled, children: "reset" })
3541
3613
  ] });
3542
3614
  }
3543
3615
  function WindowRow({
@@ -3546,8 +3618,8 @@ function WindowRow({
3546
3618
  disabled
3547
3619
  }) {
3548
3620
  const { query } = api;
3549
- const [limitDraft, setLimitDraft] = useState5(String(query.limit));
3550
- const [offsetDraft, setOffsetDraft] = useState5(String(query.offset));
3621
+ const [limitDraft, setLimitDraft] = useState6(String(query.limit));
3622
+ const [offsetDraft, setOffsetDraft] = useState6(String(query.offset));
3551
3623
  useEffect5(() => setLimitDraft(String(query.limit)), [query.limit]);
3552
3624
  useEffect5(() => setOffsetDraft(String(query.offset)), [query.offset]);
3553
3625
  const hasLimitDefault = query.limit === api.defaults.limit;
@@ -3559,10 +3631,10 @@ function WindowRow({
3559
3631
  function commitOffset() {
3560
3632
  api.setOffset(Math.max(0, Number(offsetDraft) || 0));
3561
3633
  }
3562
- return /* @__PURE__ */ jsxs6("div", { className: "qt-qb-row qt-qb-pagination", children: [
3563
- /* @__PURE__ */ jsxs6("label", { className: "qt-qb-window-field", children: [
3564
- /* @__PURE__ */ jsx6("span", { className: "qt-qb-kw", children: "limit" }),
3565
- /* @__PURE__ */ jsx6(
3634
+ return /* @__PURE__ */ jsxs7("div", { className: "qt-qb-row qt-qb-pagination", children: [
3635
+ /* @__PURE__ */ jsxs7("label", { className: "qt-qb-window-field", children: [
3636
+ /* @__PURE__ */ jsx7("span", { className: "qt-qb-kw", children: "limit" }),
3637
+ /* @__PURE__ */ jsx7(
3566
3638
  "input",
3567
3639
  {
3568
3640
  className: cx3("qt-qb-num", classNames?.input),
@@ -3576,9 +3648,9 @@ function WindowRow({
3576
3648
  }
3577
3649
  )
3578
3650
  ] }),
3579
- /* @__PURE__ */ jsxs6("label", { className: "qt-qb-window-field", children: [
3580
- /* @__PURE__ */ jsx6("span", { className: "qt-qb-kw", children: "offset" }),
3581
- /* @__PURE__ */ jsx6(
3651
+ /* @__PURE__ */ jsxs7("label", { className: "qt-qb-window-field", children: [
3652
+ /* @__PURE__ */ jsx7("span", { className: "qt-qb-kw", children: "offset" }),
3653
+ /* @__PURE__ */ jsx7(
3582
3654
  "input",
3583
3655
  {
3584
3656
  className: cx3("qt-qb-num", classNames?.input),
@@ -3592,7 +3664,7 @@ function WindowRow({
3592
3664
  }
3593
3665
  )
3594
3666
  ] }),
3595
- !hasWindowDefault && /* @__PURE__ */ jsx6(
3667
+ !hasWindowDefault && /* @__PURE__ */ jsx7(
3596
3668
  "button",
3597
3669
  {
3598
3670
  type: "button",
@@ -3627,7 +3699,7 @@ function MetricsRow({
3627
3699
  const clauses = aggregations.clauses;
3628
3700
  const measurable = useMemo4(() => fields.filter(isMeasurable), [fields]);
3629
3701
  const groupable = useMemo4(() => fields.filter(isGroupable), [fields]);
3630
- const [drag, setDrag] = useState5(null);
3702
+ const [drag, setDrag] = useState6(null);
3631
3703
  const ids = clauses.map((c) => c.id);
3632
3704
  const byId = useMemo4(() => new Map(clauses.map((c) => [c.id, c])), [clauses]);
3633
3705
  function previewIds() {
@@ -3655,12 +3727,12 @@ function MetricsRow({
3655
3727
  setDrag(null);
3656
3728
  }
3657
3729
  const rendered = previewIds();
3658
- return /* @__PURE__ */ jsxs6("div", { className: "qt-qb-row qt-qb-row--metrics", children: [
3659
- /* @__PURE__ */ jsx6("span", { className: "qt-qb-kw", children: "metrics" }),
3660
- clauses.length === 0 && /* @__PURE__ */ jsx6("span", { className: "qt-qb-hint", children: "none" }),
3730
+ return /* @__PURE__ */ jsxs7("div", { className: "qt-qb-row qt-qb-row--metrics", children: [
3731
+ /* @__PURE__ */ jsx7("span", { className: "qt-qb-kw", children: "metrics" }),
3732
+ clauses.length === 0 && /* @__PURE__ */ jsx7("span", { className: "qt-qb-hint", children: "none" }),
3661
3733
  rendered.map((id, position) => {
3662
3734
  const clause = byId.get(id);
3663
- return /* @__PURE__ */ jsx6(
3735
+ return /* @__PURE__ */ jsx7(
3664
3736
  MetricChip,
3665
3737
  {
3666
3738
  clause,
@@ -3685,8 +3757,8 @@ function MetricsRow({
3685
3757
  id
3686
3758
  );
3687
3759
  }),
3688
- /* @__PURE__ */ jsx6("button", { type: "button", className: "qt-add", onClick: () => aggregations.add(), disabled, children: "+ add metric" }),
3689
- clauses.length > 0 && /* @__PURE__ */ jsx6("button", { type: "button", className: "qt-link-btn", onClick: aggregations.clear, disabled, title: "Remove all metrics", children: "reset" })
3760
+ /* @__PURE__ */ jsx7("button", { type: "button", className: "qt-add", onClick: () => aggregations.add(), disabled, children: "+ add metric" }),
3761
+ clauses.length > 0 && /* @__PURE__ */ jsx7("button", { type: "button", className: "qt-link-btn", onClick: aggregations.clear, disabled, title: "Remove all metrics", children: "reset" })
3690
3762
  ] });
3691
3763
  }
3692
3764
  function changeMetricOp(aggregations, clause, measurable, op) {
@@ -3715,11 +3787,11 @@ function MetricChip({
3715
3787
  count,
3716
3788
  onMove
3717
3789
  }) {
3718
- const [addingGroup, setAddingGroup] = useState5(false);
3790
+ const [addingGroup, setAddingGroup] = useState6(false);
3719
3791
  const byName = useMemo4(() => new Map(groupable.map((f) => [f.name, f])), [groupable]);
3720
3792
  const needsField = aggOpNeedsField(clause.op);
3721
3793
  const measureOptions = measurable.filter((f) => aggOpsForField(f).includes(clause.op));
3722
- return /* @__PURE__ */ jsxs6(
3794
+ return /* @__PURE__ */ jsxs7(
3723
3795
  "span",
3724
3796
  {
3725
3797
  className: cx3("qt-chip", "qt-chip--agg", isDragSource && "qt-chip--dragging", classNames?.chip),
@@ -3737,18 +3809,18 @@ function MetricChip({
3737
3809
  onDragEnd,
3738
3810
  title: "drag to reorder metrics",
3739
3811
  children: [
3740
- /* @__PURE__ */ jsx6("span", { "aria-hidden": true, className: "qt-chip-grip", children: "\u22EE\u22EE" }),
3741
- /* @__PURE__ */ jsx6(
3812
+ /* @__PURE__ */ jsx7("span", { "aria-hidden": true, className: "qt-chip-grip", children: "\u22EE\u22EE" }),
3813
+ /* @__PURE__ */ jsx7(
3742
3814
  "select",
3743
3815
  {
3744
3816
  className: cx3("qt-chip-op", classNames?.select),
3745
3817
  value: clause.op,
3746
3818
  disabled,
3747
3819
  onChange: (e) => onChangeOp(e.target.value),
3748
- children: AGG_OPS.map((op) => /* @__PURE__ */ jsx6("option", { value: op, children: AGG_OP_LABELS[op] }, op))
3820
+ children: AGG_OPS.map((op) => /* @__PURE__ */ jsx7("option", { value: op, children: AGG_OP_LABELS[op] }, op))
3749
3821
  }
3750
3822
  ),
3751
- /* @__PURE__ */ jsxs6(
3823
+ /* @__PURE__ */ jsxs7(
3752
3824
  "select",
3753
3825
  {
3754
3826
  className: cx3("qt-chip-val", classNames?.select),
@@ -3756,18 +3828,18 @@ function MetricChip({
3756
3828
  disabled,
3757
3829
  onChange: (e) => onChangeField(e.target.value || void 0),
3758
3830
  children: [
3759
- !needsField && /* @__PURE__ */ jsx6("option", { value: "", children: "(all rows)" }),
3760
- needsField && clause.field == null && /* @__PURE__ */ jsx6("option", { value: "", children: "measure\u2026" }),
3761
- measureOptions.map((f) => /* @__PURE__ */ jsx6("option", { value: f.name, children: f.label }, f.name))
3831
+ !needsField && /* @__PURE__ */ jsx7("option", { value: "", children: "(all rows)" }),
3832
+ needsField && clause.field == null && /* @__PURE__ */ jsx7("option", { value: "", children: "measure\u2026" }),
3833
+ measureOptions.map((f) => /* @__PURE__ */ jsx7("option", { value: f.name, children: f.label }, f.name))
3762
3834
  ]
3763
3835
  }
3764
3836
  ),
3765
- /* @__PURE__ */ jsxs6("span", { className: "qt-chip-agg-by", children: [
3766
- clause.groupBy.map((g) => /* @__PURE__ */ jsxs6("span", { className: "qt-chip-agg-group", children: [
3767
- /* @__PURE__ */ jsx6("span", { className: "qt-chip-agg-group-label", children: byName.get(g)?.label ?? g }),
3768
- /* @__PURE__ */ jsx6("button", { type: "button", className: "qt-chip-x", onClick: () => onRemoveGroup(g), disabled, children: "\u2715" })
3837
+ /* @__PURE__ */ jsxs7("span", { className: "qt-chip-agg-by", children: [
3838
+ clause.groupBy.map((g) => /* @__PURE__ */ jsxs7("span", { className: "qt-chip-agg-group", children: [
3839
+ /* @__PURE__ */ jsx7("span", { className: "qt-chip-agg-group-label", children: byName.get(g)?.label ?? g }),
3840
+ /* @__PURE__ */ jsx7("button", { type: "button", className: "qt-chip-x", onClick: () => onRemoveGroup(g), disabled, children: "\u2715" })
3769
3841
  ] }, g)),
3770
- addingGroup ? /* @__PURE__ */ jsx6(
3842
+ addingGroup ? /* @__PURE__ */ jsx7(
3771
3843
  FieldPicker,
3772
3844
  {
3773
3845
  fields: groupable,
@@ -3778,7 +3850,7 @@ function MetricChip({
3778
3850
  },
3779
3851
  onClose: () => setAddingGroup(false)
3780
3852
  }
3781
- ) : /* @__PURE__ */ jsx6(
3853
+ ) : /* @__PURE__ */ jsx7(
3782
3854
  "button",
3783
3855
  {
3784
3856
  type: "button",
@@ -3790,7 +3862,7 @@ function MetricChip({
3790
3862
  }
3791
3863
  )
3792
3864
  ] }),
3793
- /* @__PURE__ */ jsx6(
3865
+ /* @__PURE__ */ jsx7(
3794
3866
  MoveButtons,
3795
3867
  {
3796
3868
  label: clause.label ?? `${AGG_OP_LABELS[clause.op]} metric`,
@@ -3800,7 +3872,7 @@ function MetricChip({
3800
3872
  onMove
3801
3873
  }
3802
3874
  ),
3803
- /* @__PURE__ */ jsx6("button", { type: "button", className: "qt-chip-x", onClick: onRemove, disabled, title: "Remove metric", children: "\u2715" })
3875
+ /* @__PURE__ */ jsx7("button", { type: "button", className: "qt-chip-x", onClick: onRemove, disabled, title: "Remove metric", children: "\u2715" })
3804
3876
  ]
3805
3877
  }
3806
3878
  );
@@ -3809,7 +3881,7 @@ function MetricChip({
3809
3881
  // src/MetricsPanel.tsx
3810
3882
  import { useMemo as useMemo5 } from "react";
3811
3883
  import { EMPTY_QUERY } from "@pythia-software/query-table-core";
3812
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
3884
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
3813
3885
  var cx4 = (...parts) => parts.filter((p) => Boolean(p)).join(" ");
3814
3886
  var OP_LABELS = {
3815
3887
  count: "Count",
@@ -3830,15 +3902,15 @@ function MetricsPanel({
3830
3902
  const byName = useMemo5(() => new Map(fields.map((f) => [f.name, f])), [fields]);
3831
3903
  const { clauses, results, loading, error } = aggregations;
3832
3904
  if (clauses.length === 0) {
3833
- return emptyMessage ? /* @__PURE__ */ jsx7("div", { className: cx4("qt-metrics", classNames?.root), children: emptyMessage }) : null;
3905
+ return emptyMessage ? /* @__PURE__ */ jsx8("div", { className: cx4("qt-metrics", classNames?.root), children: emptyMessage }) : null;
3834
3906
  }
3835
3907
  const resultById = new Map((results?.metrics ?? []).map((m) => [m.id, m.buckets]));
3836
- return /* @__PURE__ */ jsxs7("div", { className: cx4("qt-metrics", classNames?.root), children: [
3837
- error ? /* @__PURE__ */ jsxs7("div", { className: "qt-metrics-error", children: [
3908
+ return /* @__PURE__ */ jsxs8("div", { className: cx4("qt-metrics", classNames?.root), children: [
3909
+ error ? /* @__PURE__ */ jsxs8("div", { className: "qt-metrics-error", children: [
3838
3910
  "Metrics failed: ",
3839
3911
  error.message
3840
3912
  ] }) : null,
3841
- clauses.map((clause) => /* @__PURE__ */ jsx7(
3913
+ clauses.map((clause) => /* @__PURE__ */ jsx8(
3842
3914
  MetricCard,
3843
3915
  {
3844
3916
  clause,
@@ -3864,21 +3936,21 @@ function MetricCard({
3864
3936
  const groupLabels = clause.groupBy.map((g) => byName.get(g)?.label ?? g);
3865
3937
  const decimals = useMemo5(() => cardDecimals(buckets), [buckets]);
3866
3938
  const fmt = (v) => formatMetricValue(v, clause.op, measure, renderers, decimals);
3867
- return /* @__PURE__ */ jsxs7("div", { className: cx4("qt-metric", `qt-metric--gb${Math.min(clause.groupBy.length, 3)}`, className), children: [
3868
- /* @__PURE__ */ jsxs7("div", { className: "qt-metric-head", children: [
3869
- /* @__PURE__ */ jsx7("span", { className: "qt-metric-title", children: metricTitle(clause, measure) }),
3870
- groupLabels.length > 0 && /* @__PURE__ */ jsxs7("span", { className: "qt-metric-by", children: [
3939
+ return /* @__PURE__ */ jsxs8("div", { className: cx4("qt-metric", `qt-metric--gb${Math.min(clause.groupBy.length, 3)}`, className), children: [
3940
+ /* @__PURE__ */ jsxs8("div", { className: "qt-metric-head", children: [
3941
+ /* @__PURE__ */ jsx8("span", { className: "qt-metric-title", children: metricTitle(clause, measure) }),
3942
+ groupLabels.length > 0 && /* @__PURE__ */ jsxs8("span", { className: "qt-metric-by", children: [
3871
3943
  "by ",
3872
3944
  groupLabels.join(" \xD7 ")
3873
3945
  ] })
3874
3946
  ] }),
3875
- loading && buckets.length === 0 ? /* @__PURE__ */ jsx7("div", { className: "qt-metric-loading", children: "\u2026" }) : buckets.length === 0 ? /* @__PURE__ */ jsx7("div", { className: "qt-metric-empty", children: "no data" }) : clause.groupBy.length === 0 ? /* @__PURE__ */ jsx7(BigNumber, { bucket: buckets[0], fmt }) : clause.groupBy.length === 1 ? /* @__PURE__ */ jsx7(BarList, { buckets, fmt }) : clause.groupBy.length === 2 ? /* @__PURE__ */ jsx7(Pivot, { buckets, fmt, rowLabel: groupLabels[0], colLabel: groupLabels[1] }) : /* @__PURE__ */ jsx7(FlatTable, { buckets, fmt, groupLabels, valueLabel: metricTitle(clause, measure) })
3947
+ loading && buckets.length === 0 ? /* @__PURE__ */ jsx8("div", { className: "qt-metric-loading", children: "\u2026" }) : buckets.length === 0 ? /* @__PURE__ */ jsx8("div", { className: "qt-metric-empty", children: "no data" }) : clause.groupBy.length === 0 ? /* @__PURE__ */ jsx8(BigNumber, { bucket: buckets[0], fmt }) : clause.groupBy.length === 1 ? /* @__PURE__ */ jsx8(BarList, { buckets, fmt }) : clause.groupBy.length === 2 ? /* @__PURE__ */ jsx8(Pivot, { buckets, fmt, rowLabel: groupLabels[0], colLabel: groupLabels[1] }) : /* @__PURE__ */ jsx8(FlatTable, { buckets, fmt, groupLabels, valueLabel: metricTitle(clause, measure) })
3876
3948
  ] });
3877
3949
  }
3878
3950
  function BigNumber({ bucket, fmt }) {
3879
- return /* @__PURE__ */ jsxs7("div", { className: "qt-metric-big", children: [
3880
- /* @__PURE__ */ jsx7("span", { className: "qt-metric-big-value", children: fmt(bucket.value) }),
3881
- /* @__PURE__ */ jsxs7("span", { className: "qt-metric-big-sub", children: [
3951
+ return /* @__PURE__ */ jsxs8("div", { className: "qt-metric-big", children: [
3952
+ /* @__PURE__ */ jsx8("span", { className: "qt-metric-big-value", children: fmt(bucket.value) }),
3953
+ /* @__PURE__ */ jsxs8("span", { className: "qt-metric-big-sub", children: [
3882
3954
  bucket.count.toLocaleString(),
3883
3955
  " rows"
3884
3956
  ] })
@@ -3886,12 +3958,12 @@ function BigNumber({ bucket, fmt }) {
3886
3958
  }
3887
3959
  function BarList({ buckets, fmt }) {
3888
3960
  const max = Math.max(...buckets.map((b) => barMagnitude(b)), 0);
3889
- return /* @__PURE__ */ jsx7("div", { className: "qt-metric-bars", children: buckets.map((b, i) => {
3961
+ return /* @__PURE__ */ jsx8("div", { className: "qt-metric-bars", children: buckets.map((b, i) => {
3890
3962
  const pct = max > 0 ? barMagnitude(b) / max * 100 : 0;
3891
- return /* @__PURE__ */ jsxs7("div", { className: "qt-metric-bar-row", children: [
3892
- /* @__PURE__ */ jsx7("span", { className: "qt-metric-bar-label", title: keyText(b.keys[0]), children: keyNode(b.keys[0]) }),
3893
- /* @__PURE__ */ jsx7("span", { className: "qt-metric-bar-track", children: /* @__PURE__ */ jsx7("span", { className: "qt-metric-bar-fill", style: { width: `${pct}%` } }) }),
3894
- /* @__PURE__ */ jsx7("span", { className: "qt-metric-bar-value", children: fmt(b.value) })
3963
+ return /* @__PURE__ */ jsxs8("div", { className: "qt-metric-bar-row", children: [
3964
+ /* @__PURE__ */ jsx8("span", { className: "qt-metric-bar-label", title: keyText(b.keys[0]), children: keyNode(b.keys[0]) }),
3965
+ /* @__PURE__ */ jsx8("span", { className: "qt-metric-bar-track", children: /* @__PURE__ */ jsx8("span", { className: "qt-metric-bar-fill", style: { width: `${pct}%` } }) }),
3966
+ /* @__PURE__ */ jsx8("span", { className: "qt-metric-bar-value", children: fmt(b.value) })
3895
3967
  ] }, `${keyText(b.keys[0])}-${i}`);
3896
3968
  }) });
3897
3969
  }
@@ -3905,22 +3977,22 @@ function Pivot({
3905
3977
  const colKeys = distinctKeys(buckets, 1);
3906
3978
  const cell = /* @__PURE__ */ new Map();
3907
3979
  for (const b of buckets) cell.set(`${keyText(b.keys[0])}\0${keyText(b.keys[1])}`, b.value);
3908
- return /* @__PURE__ */ jsx7("div", { className: "qt-metric-pivot-wrap", children: /* @__PURE__ */ jsxs7("table", { className: "qt-metric-pivot", children: [
3909
- /* @__PURE__ */ jsx7("thead", { children: /* @__PURE__ */ jsxs7("tr", { children: [
3910
- /* @__PURE__ */ jsx7("th", { className: "qt-metric-pivot-corner", children: /* @__PURE__ */ jsxs7("span", { className: "qt-metric-pivot-axes", children: [
3980
+ return /* @__PURE__ */ jsx8("div", { className: "qt-metric-pivot-wrap", children: /* @__PURE__ */ jsxs8("table", { className: "qt-metric-pivot", children: [
3981
+ /* @__PURE__ */ jsx8("thead", { children: /* @__PURE__ */ jsxs8("tr", { children: [
3982
+ /* @__PURE__ */ jsx8("th", { className: "qt-metric-pivot-corner", children: /* @__PURE__ */ jsxs8("span", { className: "qt-metric-pivot-axes", children: [
3911
3983
  rowLabel,
3912
3984
  " ",
3913
- /* @__PURE__ */ jsx7("span", { className: "qt-muted", children: "\\" }),
3985
+ /* @__PURE__ */ jsx8("span", { className: "qt-muted", children: "\\" }),
3914
3986
  " ",
3915
3987
  colLabel
3916
3988
  ] }) }),
3917
- colKeys.map((c) => /* @__PURE__ */ jsx7("th", { className: "qt-metric-pivot-col", children: keyNode(c) }, keyText(c)))
3989
+ colKeys.map((c) => /* @__PURE__ */ jsx8("th", { className: "qt-metric-pivot-col", children: keyNode(c) }, keyText(c)))
3918
3990
  ] }) }),
3919
- /* @__PURE__ */ jsx7("tbody", { children: rowKeys.map((r) => /* @__PURE__ */ jsxs7("tr", { children: [
3920
- /* @__PURE__ */ jsx7("th", { className: "qt-metric-pivot-row", children: keyNode(r) }),
3991
+ /* @__PURE__ */ jsx8("tbody", { children: rowKeys.map((r) => /* @__PURE__ */ jsxs8("tr", { children: [
3992
+ /* @__PURE__ */ jsx8("th", { className: "qt-metric-pivot-row", children: keyNode(r) }),
3921
3993
  colKeys.map((c) => {
3922
3994
  const v = cell.get(`${keyText(r)}\0${keyText(c)}`);
3923
- return /* @__PURE__ */ jsx7("td", { className: "qt-metric-pivot-cell", children: v === void 0 ? /* @__PURE__ */ jsx7("span", { className: "qt-muted", children: "\xB7" }) : fmt(v) }, keyText(c));
3995
+ return /* @__PURE__ */ jsx8("td", { className: "qt-metric-pivot-cell", children: v === void 0 ? /* @__PURE__ */ jsx8("span", { className: "qt-muted", children: "\xB7" }) : fmt(v) }, keyText(c));
3924
3996
  })
3925
3997
  ] }, keyText(r))) })
3926
3998
  ] }) });
@@ -3931,14 +4003,14 @@ function FlatTable({
3931
4003
  groupLabels,
3932
4004
  valueLabel: valueLabel2
3933
4005
  }) {
3934
- return /* @__PURE__ */ jsx7("div", { className: "qt-metric-pivot-wrap", children: /* @__PURE__ */ jsxs7("table", { className: "qt-metric-flat", children: [
3935
- /* @__PURE__ */ jsx7("thead", { children: /* @__PURE__ */ jsxs7("tr", { children: [
3936
- groupLabels.map((g) => /* @__PURE__ */ jsx7("th", { children: g }, g)),
3937
- /* @__PURE__ */ jsx7("th", { className: "qt-metric-flat-value", children: valueLabel2 })
4006
+ return /* @__PURE__ */ jsx8("div", { className: "qt-metric-pivot-wrap", children: /* @__PURE__ */ jsxs8("table", { className: "qt-metric-flat", children: [
4007
+ /* @__PURE__ */ jsx8("thead", { children: /* @__PURE__ */ jsxs8("tr", { children: [
4008
+ groupLabels.map((g) => /* @__PURE__ */ jsx8("th", { children: g }, g)),
4009
+ /* @__PURE__ */ jsx8("th", { className: "qt-metric-flat-value", children: valueLabel2 })
3938
4010
  ] }) }),
3939
- /* @__PURE__ */ jsx7("tbody", { children: buckets.map((b, i) => /* @__PURE__ */ jsxs7("tr", { children: [
3940
- groupLabels.map((_, j) => /* @__PURE__ */ jsx7("td", { children: keyNode(b.keys[j]) }, j)),
3941
- /* @__PURE__ */ jsx7("td", { className: "qt-metric-flat-value", children: fmt(b.value) })
4011
+ /* @__PURE__ */ jsx8("tbody", { children: buckets.map((b, i) => /* @__PURE__ */ jsxs8("tr", { children: [
4012
+ groupLabels.map((_, j) => /* @__PURE__ */ jsx8("td", { children: keyNode(b.keys[j]) }, j)),
4013
+ /* @__PURE__ */ jsx8("td", { className: "qt-metric-flat-value", children: fmt(b.value) })
3942
4014
  ] }, i)) })
3943
4015
  ] }) });
3944
4016
  }
@@ -3949,7 +4021,7 @@ function metricTitle(clause, measure) {
3949
4021
  }
3950
4022
  var UNIT_RENDER_KEYS = /* @__PURE__ */ new Set(["duration_ms", "byte_size"]);
3951
4023
  function formatMetricValue(value, op, measure, renderers, decimals) {
3952
- if (value == null) return /* @__PURE__ */ jsx7("span", { className: "qt-muted", children: "\u2014" });
4024
+ if (value == null) return /* @__PURE__ */ jsx8("span", { className: "qt-muted", children: "\u2014" });
3953
4025
  if (op === "count" || op === "count_distinct") {
3954
4026
  return typeof value === "number" ? formatNumber(value, 0) : String(value);
3955
4027
  }
@@ -4012,21 +4084,21 @@ function keyText(k) {
4012
4084
  return k == null ? NULL_KEY : String(k);
4013
4085
  }
4014
4086
  function keyNode(k) {
4015
- return k == null ? /* @__PURE__ */ jsx7("span", { className: "qt-muted", children: NULL_KEY }) : String(k);
4087
+ return k == null ? /* @__PURE__ */ jsx8("span", { className: "qt-muted", children: NULL_KEY }) : String(k);
4016
4088
  }
4017
4089
 
4018
4090
  // src/SelectionToolbar.tsx
4019
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
4091
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
4020
4092
  var cx5 = (...parts) => parts.filter(Boolean).join(" ");
4021
4093
  function SelectionToolbar({ selection, actions, alwaysShow, className }) {
4022
4094
  if (selection.count === 0 && !alwaysShow) return null;
4023
4095
  const selectedIds = [...selection.selected];
4024
- return /* @__PURE__ */ jsxs8("div", { className: cx5("qt-selection-toolbar", className), role: "toolbar", children: [
4025
- /* @__PURE__ */ jsxs8("span", { className: "qt-selection-count", children: [
4096
+ return /* @__PURE__ */ jsxs9("div", { className: cx5("qt-selection-toolbar", className), role: "toolbar", children: [
4097
+ /* @__PURE__ */ jsxs9("span", { className: "qt-selection-count", children: [
4026
4098
  selection.count,
4027
4099
  " selected"
4028
4100
  ] }),
4029
- /* @__PURE__ */ jsx8(
4101
+ /* @__PURE__ */ jsx9(
4030
4102
  "button",
4031
4103
  {
4032
4104
  type: "button",
@@ -4036,14 +4108,16 @@ function SelectionToolbar({ selection, actions, alwaysShow, className }) {
4036
4108
  children: "clear"
4037
4109
  }
4038
4110
  ),
4039
- /* @__PURE__ */ jsx8("span", { className: "qt-selection-actions", children: actions(selectedIds, selection) })
4111
+ /* @__PURE__ */ jsx9("span", { className: "qt-selection-actions", children: actions(selectedIds, selection) })
4040
4112
  ] });
4041
4113
  }
4042
4114
  export {
4043
4115
  CellMenu,
4044
4116
  DataTable,
4045
4117
  FieldPicker,
4118
+ FilterValueProvider,
4046
4119
  MetricsPanel,
4120
+ PresentedFilterValue,
4047
4121
  QueryBuilder,
4048
4122
  SavedQueriesModal,
4049
4123
  SelectColumnEditor,