@upbound/monarch-blocks 0.1.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/LICENSE +21 -0
- package/README.md +58 -0
- package/dist/cel-filter-bar.d.ts +187 -0
- package/dist/cel-filter-bar.js +1850 -0
- package/dist/cel-filter-bar.js.map +1 -0
- package/dist/chart.d.ts +52 -0
- package/dist/chart.js +332 -0
- package/dist/chart.js.map +1 -0
- package/dist/chat-interface.d.ts +143 -0
- package/dist/chat-interface.js +676 -0
- package/dist/chat-interface.js.map +1 -0
- package/dist/code-block.d.ts +21 -0
- package/dist/code-block.js +201 -0
- package/dist/code-block.js.map +1 -0
- package/dist/data-table.d.ts +505 -0
- package/dist/data-table.js +4725 -0
- package/dist/data-table.js.map +1 -0
- package/dist/filter-bar.d.ts +80 -0
- package/dist/filter-bar.js +590 -0
- package/dist/filter-bar.js.map +1 -0
- package/dist/floating-widget.d.ts +36 -0
- package/dist/floating-widget.js +218 -0
- package/dist/floating-widget.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +6217 -0
- package/dist/index.js.map +1 -0
- package/dist/page-header.d.ts +12 -0
- package/dist/page-header.js +120 -0
- package/dist/page-header.js.map +1 -0
- package/dist/relative-time.d.ts +60 -0
- package/dist/relative-time.js +328 -0
- package/dist/relative-time.js.map +1 -0
- package/dist/section-header.d.ts +11 -0
- package/dist/section-header.js +123 -0
- package/dist/section-header.js.map +1 -0
- package/dist/section-nav.d.ts +50 -0
- package/dist/section-nav.js +143 -0
- package/dist/section-nav.js.map +1 -0
- package/dist/timeline.d.ts +8 -0
- package/dist/timeline.js +95 -0
- package/dist/timeline.js.map +1 -0
- package/dist/types-BULiU2qC.d.ts +170 -0
- package/package.json +58 -0
|
@@ -0,0 +1,4725 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
var __objRest = (source, exclude) => {
|
|
21
|
+
var target = {};
|
|
22
|
+
for (var prop in source)
|
|
23
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
24
|
+
target[prop] = source[prop];
|
|
25
|
+
if (source != null && __getOwnPropSymbols)
|
|
26
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
27
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
28
|
+
target[prop] = source[prop];
|
|
29
|
+
}
|
|
30
|
+
return target;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// src/data-table/cell-contextual-filter.tsx
|
|
34
|
+
import {
|
|
35
|
+
ContextMenuContent,
|
|
36
|
+
ContextMenuItem,
|
|
37
|
+
ContextMenuSeparator,
|
|
38
|
+
ContextMenuSub,
|
|
39
|
+
ContextMenuSubContent,
|
|
40
|
+
ContextMenuSubTrigger
|
|
41
|
+
} from "@upbound/monarch-core";
|
|
42
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
43
|
+
function CellContextualFilter({
|
|
44
|
+
filter,
|
|
45
|
+
globalSearch,
|
|
46
|
+
cell,
|
|
47
|
+
onContextCell,
|
|
48
|
+
onContextSearch,
|
|
49
|
+
contextualMenuActions = []
|
|
50
|
+
}) {
|
|
51
|
+
const disabled = !filter && !(globalSearch && onContextSearch);
|
|
52
|
+
function handleSelect() {
|
|
53
|
+
if (globalSearch && onContextSearch) {
|
|
54
|
+
onContextSearch(globalSearch, cell);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (!filter) return;
|
|
58
|
+
onContextCell(filter, cell);
|
|
59
|
+
}
|
|
60
|
+
function renderAction(action) {
|
|
61
|
+
var _a, _b;
|
|
62
|
+
const actionDisabled = typeof action.disabled === "function" ? action.disabled(cell) : (_a = action.disabled) != null ? _a : false;
|
|
63
|
+
if ((_b = action.items) == null ? void 0 : _b.length) {
|
|
64
|
+
return /* @__PURE__ */ jsxs(ContextMenuSub, { children: [
|
|
65
|
+
/* @__PURE__ */ jsx(
|
|
66
|
+
ContextMenuSubTrigger,
|
|
67
|
+
{
|
|
68
|
+
disabled: actionDisabled,
|
|
69
|
+
className: action.className,
|
|
70
|
+
onClick: (event) => event.stopPropagation(),
|
|
71
|
+
children: action.label
|
|
72
|
+
}
|
|
73
|
+
),
|
|
74
|
+
/* @__PURE__ */ jsx(ContextMenuSubContent, { children: action.items.map(renderAction) })
|
|
75
|
+
] }, action.id);
|
|
76
|
+
}
|
|
77
|
+
let handledClick = false;
|
|
78
|
+
return /* @__PURE__ */ jsx(
|
|
79
|
+
ContextMenuItem,
|
|
80
|
+
{
|
|
81
|
+
disabled: actionDisabled,
|
|
82
|
+
onClick: (event) => {
|
|
83
|
+
var _a2;
|
|
84
|
+
event.stopPropagation();
|
|
85
|
+
handledClick = true;
|
|
86
|
+
(_a2 = action.onSelect) == null ? void 0 : _a2.call(action, cell);
|
|
87
|
+
},
|
|
88
|
+
onSelect: () => {
|
|
89
|
+
var _a2;
|
|
90
|
+
if (handledClick) {
|
|
91
|
+
handledClick = false;
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
(_a2 = action.onSelect) == null ? void 0 : _a2.call(action, cell);
|
|
95
|
+
},
|
|
96
|
+
children: action.label
|
|
97
|
+
},
|
|
98
|
+
action.id
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return /* @__PURE__ */ jsxs(ContextMenuContent, { children: [
|
|
102
|
+
/* @__PURE__ */ jsx(ContextMenuItem, { disabled, onClick: (event) => event.stopPropagation(), onSelect: handleSelect, children: "Filter by this value" }),
|
|
103
|
+
contextualMenuActions.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
104
|
+
/* @__PURE__ */ jsx(ContextMenuSeparator, {}),
|
|
105
|
+
contextualMenuActions.map(renderAction)
|
|
106
|
+
] })
|
|
107
|
+
] });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/data-table/column-options.tsx
|
|
111
|
+
import * as React from "react";
|
|
112
|
+
import { flexRender } from "@tanstack/react-table";
|
|
113
|
+
import { Button } from "@upbound/monarch-core";
|
|
114
|
+
import {
|
|
115
|
+
DropdownMenu,
|
|
116
|
+
DropdownMenuCheckboxItem,
|
|
117
|
+
DropdownMenuContent,
|
|
118
|
+
DropdownMenuItem,
|
|
119
|
+
DropdownMenuTrigger
|
|
120
|
+
} from "@upbound/monarch-core";
|
|
121
|
+
import { Icon } from "@upbound/monarch-core";
|
|
122
|
+
|
|
123
|
+
// src/lib/utils.ts
|
|
124
|
+
import { clsx } from "clsx";
|
|
125
|
+
import { extendTailwindMerge } from "tailwind-merge";
|
|
126
|
+
var twMerge = extendTailwindMerge({
|
|
127
|
+
extend: {
|
|
128
|
+
classGroups: {
|
|
129
|
+
"font-size": [
|
|
130
|
+
{
|
|
131
|
+
text: [
|
|
132
|
+
"display-hero",
|
|
133
|
+
"display-kpi-sm",
|
|
134
|
+
"display-kpi",
|
|
135
|
+
"display-kpi-lg",
|
|
136
|
+
"display-feature",
|
|
137
|
+
"h1",
|
|
138
|
+
"h2",
|
|
139
|
+
"h3",
|
|
140
|
+
"h4",
|
|
141
|
+
"body-lg",
|
|
142
|
+
"body",
|
|
143
|
+
"body-sm",
|
|
144
|
+
"caption",
|
|
145
|
+
"eyebrow"
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
function cn(...inputs) {
|
|
153
|
+
return twMerge(clsx(inputs));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// src/lib/data-table/utils.ts
|
|
157
|
+
var TO_EACH_SIDE = 2;
|
|
158
|
+
function normalizeColumnOrdering(columnOrdering, allColumnIds) {
|
|
159
|
+
const validIds = new Set(allColumnIds);
|
|
160
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
161
|
+
const trackedColumnIds = columnOrdering.filter((columnId) => {
|
|
162
|
+
if (!validIds.has(columnId) || seenIds.has(columnId)) return false;
|
|
163
|
+
seenIds.add(columnId);
|
|
164
|
+
return true;
|
|
165
|
+
});
|
|
166
|
+
return [...trackedColumnIds, ...allColumnIds.filter((columnId) => !seenIds.has(columnId))];
|
|
167
|
+
}
|
|
168
|
+
function isSameColumnOrdering(left, right) {
|
|
169
|
+
return left.length === right.length && left.every((columnId, index) => columnId === right[index]);
|
|
170
|
+
}
|
|
171
|
+
function splitColumnOrderByPinning(fullColumnOrder, getColumnPinning2) {
|
|
172
|
+
return {
|
|
173
|
+
leftPinnedColumns: fullColumnOrder.filter((columnId) => getColumnPinning2(columnId) === "left"),
|
|
174
|
+
unpinnedColumns: fullColumnOrder.filter((columnId) => getColumnPinning2(columnId) === false),
|
|
175
|
+
rightPinnedColumns: fullColumnOrder.filter((columnId) => getColumnPinning2(columnId) === "right")
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function mergeUnpinnedColumnOrder(fullColumnOrder, nextUnpinnedOrder, getColumnPinning2) {
|
|
179
|
+
const nextUnpinnedIterator = nextUnpinnedOrder[Symbol.iterator]();
|
|
180
|
+
return fullColumnOrder.map(
|
|
181
|
+
(columnId) => {
|
|
182
|
+
var _a;
|
|
183
|
+
return getColumnPinning2(columnId) === false ? (_a = nextUnpinnedIterator.next().value) != null ? _a : columnId : columnId;
|
|
184
|
+
}
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
function getPaginationInfo(pageIndex, totalRows, pageSize) {
|
|
188
|
+
const currentPage = pageIndex + 1;
|
|
189
|
+
const pageCount = Math.ceil(totalRows / pageSize);
|
|
190
|
+
function getPages() {
|
|
191
|
+
if (pageCount === 0) return [];
|
|
192
|
+
if (pageCount === 1) return [1];
|
|
193
|
+
if (pageCount === 2) return [1, 2];
|
|
194
|
+
const runStart = Math.max(currentPage - TO_EACH_SIDE, 2);
|
|
195
|
+
const runEnd = Math.min(currentPage + TO_EACH_SIDE, pageCount - 1);
|
|
196
|
+
const hasBeginningEllipsis = runStart > 2;
|
|
197
|
+
const hasEndingEllipsis = currentPage + 3 < pageCount;
|
|
198
|
+
return [
|
|
199
|
+
1,
|
|
200
|
+
...hasBeginningEllipsis ? [void 0] : [],
|
|
201
|
+
...Array.from({ length: runEnd - runStart + 1 }).map((_, i) => i + runStart),
|
|
202
|
+
...hasEndingEllipsis ? [void 0] : [],
|
|
203
|
+
pageCount
|
|
204
|
+
];
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
pageCount,
|
|
208
|
+
visiblePages: getPages(),
|
|
209
|
+
itemStart: totalRows === 0 ? 0 : pageIndex * pageSize + 1,
|
|
210
|
+
itemEnd: Math.min(currentPage * pageSize, totalRows)
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function isFilterOnlyColumn(column) {
|
|
214
|
+
var _a;
|
|
215
|
+
return ((_a = column.columnDef.meta) == null ? void 0 : _a.filterOnly) === true;
|
|
216
|
+
}
|
|
217
|
+
function getTableState({
|
|
218
|
+
error,
|
|
219
|
+
loading,
|
|
220
|
+
rowCount
|
|
221
|
+
}) {
|
|
222
|
+
if (error) return "error";
|
|
223
|
+
if (loading) return "loading";
|
|
224
|
+
return rowCount === 0 ? "empty" : "success";
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// src/data-table/column-options.tsx
|
|
228
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
229
|
+
function getColumnPinning(column) {
|
|
230
|
+
var _a;
|
|
231
|
+
if (!column) return false;
|
|
232
|
+
return column.getIsPinned() || ((_a = column.columnDef.meta) == null ? void 0 : _a.pinning) || false;
|
|
233
|
+
}
|
|
234
|
+
function ColumnOptionsItem({
|
|
235
|
+
column,
|
|
236
|
+
disableColumnOrdering,
|
|
237
|
+
isDropTarget,
|
|
238
|
+
onDragStart,
|
|
239
|
+
onDrop,
|
|
240
|
+
onDragOver,
|
|
241
|
+
onDragEnd
|
|
242
|
+
}) {
|
|
243
|
+
var _a;
|
|
244
|
+
const [isDraggedOver, setIsDraggedOver] = React.useState(false);
|
|
245
|
+
const isDraggable = column.getIsPinned() === false && !((_a = column.columnDef.meta) == null ? void 0 : _a.pinning) && !disableColumnOrdering;
|
|
246
|
+
const canHide = column.getCanHide();
|
|
247
|
+
const headerContent = React.useMemo(
|
|
248
|
+
() => flexRender(column.columnDef.header, { column, header: null, table: null }),
|
|
249
|
+
[column]
|
|
250
|
+
);
|
|
251
|
+
const dragProps = {
|
|
252
|
+
draggable: isDraggable,
|
|
253
|
+
onDragStart: isDraggable ? onDragStart(column) : void 0,
|
|
254
|
+
onDrop: isDropTarget ? (e) => {
|
|
255
|
+
onDrop(column)(e);
|
|
256
|
+
setIsDraggedOver(false);
|
|
257
|
+
} : void 0,
|
|
258
|
+
onDragOver: isDropTarget ? (e) => {
|
|
259
|
+
onDragOver(e);
|
|
260
|
+
setIsDraggedOver(true);
|
|
261
|
+
} : void 0,
|
|
262
|
+
onDragLeave: isDropTarget ? () => setIsDraggedOver(false) : void 0,
|
|
263
|
+
onDragEnd: isDraggable ? onDragEnd : void 0,
|
|
264
|
+
className: cn(
|
|
265
|
+
"relative flex items-center gap-2",
|
|
266
|
+
isDraggedOver && "before:bg-primary before:absolute before:inset-x-0 before:top-0 before:h-0.5"
|
|
267
|
+
)
|
|
268
|
+
};
|
|
269
|
+
const itemContent = /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
270
|
+
isDraggable && /* @__PURE__ */ jsx2(Icon, { name: "grip-vertical", size: "sm", className: "text-muted-foreground cursor-move" }),
|
|
271
|
+
/* @__PURE__ */ jsx2("span", { className: "flex min-w-0 flex-1 items-center gap-2", children: headerContent })
|
|
272
|
+
] });
|
|
273
|
+
if (!canHide) {
|
|
274
|
+
return /* @__PURE__ */ jsx2(DropdownMenuItem, __spreadProps(__spreadValues({}, dragProps), { children: itemContent }));
|
|
275
|
+
}
|
|
276
|
+
return /* @__PURE__ */ jsx2(
|
|
277
|
+
DropdownMenuCheckboxItem,
|
|
278
|
+
__spreadProps(__spreadValues({
|
|
279
|
+
checked: column.getIsVisible(),
|
|
280
|
+
onCheckedChange: () => column.toggleVisibility()
|
|
281
|
+
}, dragProps), {
|
|
282
|
+
children: itemContent
|
|
283
|
+
})
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
function ColumnOptions({
|
|
287
|
+
columns: rawColumns,
|
|
288
|
+
columnOrdering,
|
|
289
|
+
onColumnOrderingChange,
|
|
290
|
+
disableColumnOrdering
|
|
291
|
+
}) {
|
|
292
|
+
const [isDragging, setIsDragging] = React.useState(false);
|
|
293
|
+
const [isLastDropZoneActive, setIsLastDropZoneActive] = React.useState(false);
|
|
294
|
+
const columns = React.useMemo(
|
|
295
|
+
() => rawColumns.filter((col) => {
|
|
296
|
+
var _a;
|
|
297
|
+
return !isFilterOnlyColumn(col) && ((_a = col.columnDef.meta) == null ? void 0 : _a.actions) !== true;
|
|
298
|
+
}),
|
|
299
|
+
[rawColumns]
|
|
300
|
+
);
|
|
301
|
+
const allColumnById = React.useMemo(() => new Map(rawColumns.map((col) => [col.id, col])), [rawColumns]);
|
|
302
|
+
const columnById = React.useMemo(() => new Map(columns.map((col) => [col.id, col])), [columns]);
|
|
303
|
+
const fullColumnOrder = React.useMemo(
|
|
304
|
+
() => normalizeColumnOrdering(
|
|
305
|
+
columnOrdering,
|
|
306
|
+
rawColumns.map((col) => col.id)
|
|
307
|
+
),
|
|
308
|
+
[columnOrdering, rawColumns]
|
|
309
|
+
);
|
|
310
|
+
const getColumnPinningFor = React.useCallback(
|
|
311
|
+
(columnId) => getColumnPinning(allColumnById.get(columnId)),
|
|
312
|
+
[allColumnById]
|
|
313
|
+
);
|
|
314
|
+
const { leftPinnedColumns, unpinnedColumns, rightPinnedColumns } = splitColumnOrderByPinning(
|
|
315
|
+
fullColumnOrder,
|
|
316
|
+
getColumnPinningFor
|
|
317
|
+
);
|
|
318
|
+
function handleDragStart(column) {
|
|
319
|
+
return (event) => {
|
|
320
|
+
event.dataTransfer.setData("text/plain", column.id);
|
|
321
|
+
event.dataTransfer.dropEffect = "move";
|
|
322
|
+
event.dataTransfer.effectAllowed = "move";
|
|
323
|
+
setIsDragging(true);
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function handleDrop(targetColumn) {
|
|
327
|
+
return (event) => {
|
|
328
|
+
event.preventDefault();
|
|
329
|
+
event.stopPropagation();
|
|
330
|
+
const draggedColumnId = event.dataTransfer.getData("text/plain");
|
|
331
|
+
const targetColumnId = targetColumn.id;
|
|
332
|
+
if (!draggedColumnId || !targetColumnId || draggedColumnId === targetColumnId) {
|
|
333
|
+
setIsDragging(false);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const draggedIndex = unpinnedColumns.indexOf(draggedColumnId);
|
|
337
|
+
if (draggedIndex === -1) {
|
|
338
|
+
setIsDragging(false);
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
const newOrder = [...unpinnedColumns];
|
|
342
|
+
const [removed] = newOrder.splice(draggedIndex, 1);
|
|
343
|
+
const targetIndex = newOrder.indexOf(targetColumnId);
|
|
344
|
+
if (targetIndex === -1) {
|
|
345
|
+
setIsDragging(false);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
newOrder.splice(targetIndex, 0, removed);
|
|
349
|
+
onColumnOrderingChange(mergeUnpinnedColumnOrder(fullColumnOrder, newOrder, getColumnPinningFor));
|
|
350
|
+
setIsDragging(false);
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
function handleDropAtEnd(event) {
|
|
354
|
+
event.preventDefault();
|
|
355
|
+
event.stopPropagation();
|
|
356
|
+
setIsLastDropZoneActive(false);
|
|
357
|
+
const draggedColumnId = event.dataTransfer.getData("text/plain");
|
|
358
|
+
if (!draggedColumnId) {
|
|
359
|
+
setIsDragging(false);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
const draggedIndex = unpinnedColumns.indexOf(draggedColumnId);
|
|
363
|
+
if (draggedIndex === -1) {
|
|
364
|
+
setIsDragging(false);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
const newOrder = [...unpinnedColumns];
|
|
368
|
+
const [removed] = newOrder.splice(draggedIndex, 1);
|
|
369
|
+
newOrder.push(removed);
|
|
370
|
+
onColumnOrderingChange(mergeUnpinnedColumnOrder(fullColumnOrder, newOrder, getColumnPinningFor));
|
|
371
|
+
setIsDragging(false);
|
|
372
|
+
}
|
|
373
|
+
function handleDragOver(event) {
|
|
374
|
+
event.preventDefault();
|
|
375
|
+
}
|
|
376
|
+
function handleDragEnd() {
|
|
377
|
+
setIsDragging(false);
|
|
378
|
+
setIsLastDropZoneActive(false);
|
|
379
|
+
}
|
|
380
|
+
function orderedColumns(ids) {
|
|
381
|
+
return ids.map((id) => columnById.get(id)).filter((c) => {
|
|
382
|
+
var _a;
|
|
383
|
+
return !!c && !((_a = c.getIsGrouped) == null ? void 0 : _a.call(c));
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
function canDropOnColumn(column) {
|
|
387
|
+
var _a;
|
|
388
|
+
return column.getIsPinned() === false && !((_a = column.columnDef.meta) == null ? void 0 : _a.pinning);
|
|
389
|
+
}
|
|
390
|
+
const leftPinned = orderedColumns(leftPinnedColumns);
|
|
391
|
+
const unpinned = orderedColumns(unpinnedColumns);
|
|
392
|
+
const rightPinned = orderedColumns(rightPinnedColumns);
|
|
393
|
+
return /* @__PURE__ */ jsxs2(DropdownMenu, { children: [
|
|
394
|
+
/* @__PURE__ */ jsx2(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs2(Button, { variant: "outline", className: "shrink-0", children: [
|
|
395
|
+
/* @__PURE__ */ jsx2(Icon, { name: "table-columns", "data-icon": "inline-start" }),
|
|
396
|
+
"Columns",
|
|
397
|
+
/* @__PURE__ */ jsx2(Icon, { name: "chevron-down", "data-icon": "inline-end" })
|
|
398
|
+
] }) }),
|
|
399
|
+
/* @__PURE__ */ jsx2(DropdownMenuContent, { className: "w-58 p-0", children: /* @__PURE__ */ jsxs2("div", { className: "p-1", children: [
|
|
400
|
+
[...leftPinned, ...unpinned].map((column) => /* @__PURE__ */ jsx2(
|
|
401
|
+
ColumnOptionsItem,
|
|
402
|
+
{
|
|
403
|
+
column,
|
|
404
|
+
disableColumnOrdering,
|
|
405
|
+
isDropTarget: canDropOnColumn(column),
|
|
406
|
+
onDragStart: handleDragStart,
|
|
407
|
+
onDrop: handleDrop,
|
|
408
|
+
onDragOver: handleDragOver,
|
|
409
|
+
onDragEnd: handleDragEnd
|
|
410
|
+
},
|
|
411
|
+
column.id
|
|
412
|
+
)),
|
|
413
|
+
!disableColumnOrdering && /* @__PURE__ */ jsx2(
|
|
414
|
+
"div",
|
|
415
|
+
{
|
|
416
|
+
onDrop: handleDropAtEnd,
|
|
417
|
+
onDragOver: (e) => {
|
|
418
|
+
e.preventDefault();
|
|
419
|
+
setIsLastDropZoneActive(true);
|
|
420
|
+
},
|
|
421
|
+
onDragLeave: () => setIsLastDropZoneActive(false),
|
|
422
|
+
className: cn(
|
|
423
|
+
"relative w-full transition-colors",
|
|
424
|
+
isDragging && "h-3",
|
|
425
|
+
isLastDropZoneActive && "bg-muted before:bg-primary before:absolute before:inset-x-0 before:top-0 before:h-0.5"
|
|
426
|
+
)
|
|
427
|
+
}
|
|
428
|
+
),
|
|
429
|
+
rightPinned.map((column) => /* @__PURE__ */ jsx2(
|
|
430
|
+
ColumnOptionsItem,
|
|
431
|
+
{
|
|
432
|
+
column,
|
|
433
|
+
disableColumnOrdering,
|
|
434
|
+
isDropTarget: canDropOnColumn(column),
|
|
435
|
+
onDragStart: handleDragStart,
|
|
436
|
+
onDrop: handleDrop,
|
|
437
|
+
onDragOver: handleDragOver,
|
|
438
|
+
onDragEnd: handleDragEnd
|
|
439
|
+
},
|
|
440
|
+
column.id
|
|
441
|
+
))
|
|
442
|
+
] }) })
|
|
443
|
+
] });
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// src/data-table/columns.tsx
|
|
447
|
+
import { Button as Button2 } from "@upbound/monarch-core";
|
|
448
|
+
import { DropdownMenu as DropdownMenu2, DropdownMenuContent as DropdownMenuContent2, DropdownMenuItem as DropdownMenuItem2, DropdownMenuTrigger as DropdownMenuTrigger2 } from "@upbound/monarch-core";
|
|
449
|
+
import { Icon as Icon2 } from "@upbound/monarch-core";
|
|
450
|
+
|
|
451
|
+
// src/relative-time.tsx
|
|
452
|
+
import * as React2 from "react";
|
|
453
|
+
|
|
454
|
+
// src/hooks/use-mounted.ts
|
|
455
|
+
import { useSyncExternalStore } from "react";
|
|
456
|
+
function subscribe() {
|
|
457
|
+
return () => {
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
function useMounted() {
|
|
461
|
+
return useSyncExternalStore(
|
|
462
|
+
subscribe,
|
|
463
|
+
() => true,
|
|
464
|
+
() => false
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// src/relative-time.tsx
|
|
469
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
470
|
+
function formatRelativeDefault(date, locale) {
|
|
471
|
+
const now = /* @__PURE__ */ new Date();
|
|
472
|
+
const diffMs = now.getTime() - date.getTime();
|
|
473
|
+
if (diffMs < 0) {
|
|
474
|
+
const abs = Math.abs(diffMs);
|
|
475
|
+
const mins2 = Math.floor(abs / 6e4);
|
|
476
|
+
const hrs2 = Math.floor(mins2 / 60);
|
|
477
|
+
const days2 = Math.floor(hrs2 / 24);
|
|
478
|
+
if (abs < 6e4) return "just now";
|
|
479
|
+
if (mins2 < 60) return `in ${mins2} minute${mins2 === 1 ? "" : "s"}`;
|
|
480
|
+
if (hrs2 < 24) return `in ${hrs2} hour${hrs2 === 1 ? "" : "s"}`;
|
|
481
|
+
if (days2 < 7) return `in ${days2} day${days2 === 1 ? "" : "s"}`;
|
|
482
|
+
if (days2 < 30) return `in ${Math.floor(days2 / 7)} week${Math.floor(days2 / 7) === 1 ? "" : "s"}`;
|
|
483
|
+
return `on ${date.toLocaleDateString(locale, __spreadValues({
|
|
484
|
+
month: "short",
|
|
485
|
+
day: "numeric"
|
|
486
|
+
}, date.getFullYear() !== now.getFullYear() ? { year: "numeric" } : {}))}`;
|
|
487
|
+
}
|
|
488
|
+
const secs = Math.floor(diffMs / 1e3);
|
|
489
|
+
const mins = Math.floor(secs / 60);
|
|
490
|
+
const hrs = Math.floor(mins / 60);
|
|
491
|
+
const days = Math.floor(hrs / 24);
|
|
492
|
+
if (secs < 60) return "just now";
|
|
493
|
+
if (mins < 60) return `${mins} minute${mins === 1 ? "" : "s"} ago`;
|
|
494
|
+
if (hrs < 24) return `${hrs} hour${hrs === 1 ? "" : "s"} ago`;
|
|
495
|
+
if (days === 1) return "yesterday";
|
|
496
|
+
if (days < 7) return `${days} days ago`;
|
|
497
|
+
if (days < 14) return "last week";
|
|
498
|
+
if (days < 30) return `${Math.floor(days / 7)} weeks ago`;
|
|
499
|
+
return `on ${date.toLocaleDateString(locale, __spreadValues({
|
|
500
|
+
month: "short",
|
|
501
|
+
day: "numeric"
|
|
502
|
+
}, date.getFullYear() !== now.getFullYear() ? { year: "numeric" } : {}))}`;
|
|
503
|
+
}
|
|
504
|
+
function formatRelativeCompact(date, locale) {
|
|
505
|
+
const now = /* @__PURE__ */ new Date();
|
|
506
|
+
const diffMs = now.getTime() - date.getTime();
|
|
507
|
+
if (diffMs < 0) {
|
|
508
|
+
const abs = Math.abs(diffMs);
|
|
509
|
+
const mins2 = Math.floor(abs / 6e4);
|
|
510
|
+
const hrs2 = Math.floor(mins2 / 60);
|
|
511
|
+
const days2 = Math.floor(hrs2 / 24);
|
|
512
|
+
if (abs < 6e4) return "just now";
|
|
513
|
+
if (mins2 < 60) return `in ${mins2}m`;
|
|
514
|
+
if (hrs2 < 24) return `in ${hrs2}h`;
|
|
515
|
+
if (days2 < 7) return `in ${days2}d`;
|
|
516
|
+
if (days2 < 30) return `in ${Math.floor(days2 / 7)}w`;
|
|
517
|
+
return `on ${date.toLocaleDateString(locale, __spreadValues({
|
|
518
|
+
month: "short",
|
|
519
|
+
day: "numeric"
|
|
520
|
+
}, date.getFullYear() !== now.getFullYear() ? { year: "numeric" } : {}))}`;
|
|
521
|
+
}
|
|
522
|
+
const secs = Math.floor(diffMs / 1e3);
|
|
523
|
+
const mins = Math.floor(secs / 60);
|
|
524
|
+
const hrs = Math.floor(mins / 60);
|
|
525
|
+
const days = Math.floor(hrs / 24);
|
|
526
|
+
if (secs < 60) return "just now";
|
|
527
|
+
if (mins < 60) return `${mins}m ago`;
|
|
528
|
+
if (hrs < 24) return `${hrs}h ago`;
|
|
529
|
+
if (days < 7) return `${days}d ago`;
|
|
530
|
+
if (days < 30) return `${Math.floor(days / 7)}w ago`;
|
|
531
|
+
return `on ${date.toLocaleDateString(locale, __spreadValues({
|
|
532
|
+
month: "short",
|
|
533
|
+
day: "numeric"
|
|
534
|
+
}, date.getFullYear() !== now.getFullYear() ? { year: "numeric" } : {}))}`;
|
|
535
|
+
}
|
|
536
|
+
function formatRelative(date, variant, locale) {
|
|
537
|
+
return variant === "compact" ? formatRelativeCompact(date, locale) : formatRelativeDefault(date, locale);
|
|
538
|
+
}
|
|
539
|
+
function updateInterval(date) {
|
|
540
|
+
const diffMs = Math.abs(Date.now() - date.getTime());
|
|
541
|
+
const diffMin = diffMs / 6e4;
|
|
542
|
+
if (diffMin < 60) return 6e4;
|
|
543
|
+
if (diffMin < 1440) return 3e5;
|
|
544
|
+
return 36e5;
|
|
545
|
+
}
|
|
546
|
+
function absoluteTitle(date, locale) {
|
|
547
|
+
return date.toLocaleString(locale, {
|
|
548
|
+
weekday: "long",
|
|
549
|
+
year: "numeric",
|
|
550
|
+
month: "long",
|
|
551
|
+
day: "numeric",
|
|
552
|
+
hour: "numeric",
|
|
553
|
+
minute: "2-digit",
|
|
554
|
+
timeZoneName: "short"
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
function RelativeTime(_a) {
|
|
558
|
+
var _b = _a, { date, variant = "default", title, className } = _b, props = __objRest(_b, ["date", "variant", "title", "className"]);
|
|
559
|
+
const d = React2.useMemo(() => new Date(date), [date]);
|
|
560
|
+
const mounted = useMounted();
|
|
561
|
+
const locale = mounted ? void 0 : "en-US";
|
|
562
|
+
const [label, setLabel] = React2.useState(() => formatRelative(d, variant, locale));
|
|
563
|
+
React2.useEffect(() => {
|
|
564
|
+
setLabel(formatRelative(d, variant, locale));
|
|
565
|
+
const schedule = () => {
|
|
566
|
+
const id2 = window.setInterval(() => {
|
|
567
|
+
setLabel(formatRelative(d, variant, locale));
|
|
568
|
+
}, updateInterval(d));
|
|
569
|
+
return id2;
|
|
570
|
+
};
|
|
571
|
+
const id = schedule();
|
|
572
|
+
return () => window.clearInterval(id);
|
|
573
|
+
}, [d, variant, locale]);
|
|
574
|
+
return /* @__PURE__ */ jsx3(
|
|
575
|
+
"time",
|
|
576
|
+
__spreadProps(__spreadValues({
|
|
577
|
+
dateTime: d.toISOString(),
|
|
578
|
+
title: title != null ? title : absoluteTitle(d, locale),
|
|
579
|
+
className: cn("tabular-nums", className)
|
|
580
|
+
}, props), {
|
|
581
|
+
children: label
|
|
582
|
+
})
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// src/data-table/columns.tsx
|
|
587
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "@upbound/monarch-core";
|
|
588
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
589
|
+
function RowActions({
|
|
590
|
+
align = "end",
|
|
591
|
+
children,
|
|
592
|
+
contentClassName
|
|
593
|
+
}) {
|
|
594
|
+
return /* @__PURE__ */ jsxs3(DropdownMenu2, { children: [
|
|
595
|
+
/* @__PURE__ */ jsx4(DropdownMenuTrigger2, { asChild: true, children: /* @__PURE__ */ jsx4(Button2, { variant: "ghost", size: "icon-xs", "aria-label": "Row actions", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx4(Icon2, { name: "ellipsis", size: "sm" }) }) }),
|
|
596
|
+
/* @__PURE__ */ jsx4(DropdownMenuContent2, { align, className: contentClassName, children })
|
|
597
|
+
] });
|
|
598
|
+
}
|
|
599
|
+
function RowActionItem({
|
|
600
|
+
disabled,
|
|
601
|
+
className,
|
|
602
|
+
tooltip,
|
|
603
|
+
children,
|
|
604
|
+
onClick
|
|
605
|
+
}) {
|
|
606
|
+
const item = /* @__PURE__ */ jsx4(DropdownMenuItem2, { disabled, className, onClick, children });
|
|
607
|
+
if (!tooltip) return item;
|
|
608
|
+
return /* @__PURE__ */ jsxs3(Tooltip, { children: [
|
|
609
|
+
/* @__PURE__ */ jsx4(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx4("span", { className: "block", children: item }) }),
|
|
610
|
+
/* @__PURE__ */ jsx4(TooltipContent, { children: tooltip })
|
|
611
|
+
] });
|
|
612
|
+
}
|
|
613
|
+
function getActionsColumnDefinition({
|
|
614
|
+
cell
|
|
615
|
+
}) {
|
|
616
|
+
return {
|
|
617
|
+
id: "actions",
|
|
618
|
+
header: "Actions",
|
|
619
|
+
size: 80,
|
|
620
|
+
enableColumnFilter: false,
|
|
621
|
+
enableGlobalFilter: false,
|
|
622
|
+
enableSorting: false,
|
|
623
|
+
enableHiding: false,
|
|
624
|
+
meta: { pinning: "right", actions: true },
|
|
625
|
+
cell
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
function ExpandButton({ row }) {
|
|
629
|
+
if (!row.getCanExpand()) return null;
|
|
630
|
+
const isExpanded = row.getIsExpanded();
|
|
631
|
+
return /* @__PURE__ */ jsx4(
|
|
632
|
+
Button2,
|
|
633
|
+
{
|
|
634
|
+
type: "button",
|
|
635
|
+
variant: "ghost",
|
|
636
|
+
size: "icon-xs",
|
|
637
|
+
"aria-label": isExpanded ? "Collapse row" : "Expand row",
|
|
638
|
+
onClick: (e) => {
|
|
639
|
+
e.stopPropagation();
|
|
640
|
+
row.getToggleExpandedHandler()();
|
|
641
|
+
},
|
|
642
|
+
children: /* @__PURE__ */ jsx4(Icon2, { name: isExpanded ? "chevron-up" : "chevron-down", size: "sm" })
|
|
643
|
+
}
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
function getExpandColumnDefinition(options) {
|
|
647
|
+
var _a;
|
|
648
|
+
return {
|
|
649
|
+
id: "expand",
|
|
650
|
+
header: "",
|
|
651
|
+
size: 28,
|
|
652
|
+
minSize: 28,
|
|
653
|
+
maxSize: 28,
|
|
654
|
+
enableColumnFilter: false,
|
|
655
|
+
enableGlobalFilter: false,
|
|
656
|
+
enableSorting: false,
|
|
657
|
+
enableHiding: false,
|
|
658
|
+
meta: { pinning: "right", actions: true },
|
|
659
|
+
cell: (_a = options == null ? void 0 : options.cell) != null ? _a : (({ row }) => /* @__PURE__ */ jsx4(ExpandButton, { row }))
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
function DataTableValueCell({ content, title, className, href, onClick }) {
|
|
663
|
+
const baseClassName = cn("text-body truncate", className);
|
|
664
|
+
if (href) {
|
|
665
|
+
return /* @__PURE__ */ jsx4("p", { className: baseClassName, children: /* @__PURE__ */ jsx4("a", { href, title, className: "underline hover:no-underline", onClick, children: content }) });
|
|
666
|
+
}
|
|
667
|
+
if (title) {
|
|
668
|
+
return /* @__PURE__ */ jsxs3(Tooltip, { children: [
|
|
669
|
+
/* @__PURE__ */ jsx4(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx4(
|
|
670
|
+
"button",
|
|
671
|
+
{
|
|
672
|
+
type: "button",
|
|
673
|
+
className: cn(
|
|
674
|
+
baseClassName,
|
|
675
|
+
"focus-visible:ring-ring/30 cursor-help underline decoration-dashed underline-offset-2 focus-visible:ring-2"
|
|
676
|
+
),
|
|
677
|
+
onClick,
|
|
678
|
+
children: content
|
|
679
|
+
}
|
|
680
|
+
) }),
|
|
681
|
+
/* @__PURE__ */ jsx4(TooltipContent, { side: "bottom", children: title })
|
|
682
|
+
] });
|
|
683
|
+
}
|
|
684
|
+
return /* @__PURE__ */ jsx4("p", { className: baseClassName, children: content ? /* @__PURE__ */ jsx4("span", { children: content }) : /* @__PURE__ */ jsx4("span", { children: "\u2014" }) });
|
|
685
|
+
}
|
|
686
|
+
function TimestampCell({ timestamp }) {
|
|
687
|
+
if (!timestamp) return /* @__PURE__ */ jsx4(DataTableValueCell, { content: "\u2014" });
|
|
688
|
+
return /* @__PURE__ */ jsx4(RelativeTime, { date: timestamp, className: "block" });
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// src/data-table/data-table.tsx
|
|
692
|
+
import * as React8 from "react";
|
|
693
|
+
import {
|
|
694
|
+
getCoreRowModel,
|
|
695
|
+
getExpandedRowModel,
|
|
696
|
+
getFacetedRowModel,
|
|
697
|
+
getFacetedUniqueValues,
|
|
698
|
+
getFilteredRowModel,
|
|
699
|
+
getGroupedRowModel,
|
|
700
|
+
getPaginationRowModel,
|
|
701
|
+
getSortedRowModel,
|
|
702
|
+
noop,
|
|
703
|
+
useReactTable
|
|
704
|
+
} from "@tanstack/react-table";
|
|
705
|
+
|
|
706
|
+
// src/cel-filter-bar/cel-filter-bar.tsx
|
|
707
|
+
import * as React3 from "react";
|
|
708
|
+
import { Icon as Icon3 } from "@upbound/monarch-core";
|
|
709
|
+
import { Badge } from "@upbound/monarch-core";
|
|
710
|
+
import { Button as Button3 } from "@upbound/monarch-core";
|
|
711
|
+
import { ButtonGroup, ButtonGroupText } from "@upbound/monarch-core";
|
|
712
|
+
import { Calendar } from "@upbound/monarch-core";
|
|
713
|
+
import {
|
|
714
|
+
Combobox,
|
|
715
|
+
ComboboxChip,
|
|
716
|
+
ComboboxClearAll,
|
|
717
|
+
ComboboxCollection,
|
|
718
|
+
ComboboxContent,
|
|
719
|
+
ComboboxEmpty,
|
|
720
|
+
ComboboxGroup,
|
|
721
|
+
ComboboxInput,
|
|
722
|
+
ComboboxItem,
|
|
723
|
+
ComboboxLabel,
|
|
724
|
+
ComboboxList,
|
|
725
|
+
ComboboxSelectedChips,
|
|
726
|
+
ComboboxSeparator,
|
|
727
|
+
ComboboxTrigger,
|
|
728
|
+
ComboboxValue
|
|
729
|
+
} from "@upbound/monarch-core";
|
|
730
|
+
import { Input } from "@upbound/monarch-core";
|
|
731
|
+
import { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText } from "@upbound/monarch-core";
|
|
732
|
+
import { Label } from "@upbound/monarch-core";
|
|
733
|
+
import { Popover, PopoverContent, PopoverTrigger } from "@upbound/monarch-core";
|
|
734
|
+
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@upbound/monarch-core";
|
|
735
|
+
|
|
736
|
+
// src/hooks/use-cel-filter-editor-state.ts
|
|
737
|
+
import { useCallback as useCallback3, useRef, useState as useState3 } from "react";
|
|
738
|
+
|
|
739
|
+
// src/lib/cel-filter/constants.ts
|
|
740
|
+
var RELATIVE_DURATION_PRESET_VALUES = [
|
|
741
|
+
"24h",
|
|
742
|
+
"168h",
|
|
743
|
+
"720h"
|
|
744
|
+
];
|
|
745
|
+
var RELATIVE_DURATION_PRESETS = new Set(RELATIVE_DURATION_PRESET_VALUES);
|
|
746
|
+
var MAX_NESTING_DEPTH = 50;
|
|
747
|
+
var MAX_REGEX_LEN = 1e3;
|
|
748
|
+
var ADD_FILTER_POPOVER_SUPPRESS_MS = 500;
|
|
749
|
+
|
|
750
|
+
// src/hooks/use-cel-filter-editor-state.ts
|
|
751
|
+
function useCelFilterEditorState(initialCommittedIds = []) {
|
|
752
|
+
const [editingConditionId, setEditingConditionId] = useState3(null);
|
|
753
|
+
const [committedConditionIds, setCommittedConditionIds] = useState3(() => new Set(initialCommittedIds));
|
|
754
|
+
const [activeSurface, setActiveSurface] = useState3(null);
|
|
755
|
+
const suppressCloseUntilRef = useRef(null);
|
|
756
|
+
const segmentSwitchRef = useRef(false);
|
|
757
|
+
const isDismissSuppressed = useCallback3((id) => {
|
|
758
|
+
const entry = suppressCloseUntilRef.current;
|
|
759
|
+
return entry !== null && entry.id === id && Date.now() < entry.until;
|
|
760
|
+
}, []);
|
|
761
|
+
const commitCondition = useCallback3((id) => {
|
|
762
|
+
setCommittedConditionIds((prev) => {
|
|
763
|
+
if (prev.has(id)) {
|
|
764
|
+
return prev;
|
|
765
|
+
}
|
|
766
|
+
const next = new Set(prev);
|
|
767
|
+
next.add(id);
|
|
768
|
+
return next;
|
|
769
|
+
});
|
|
770
|
+
setEditingConditionId((current) => current === id ? null : current);
|
|
771
|
+
setActiveSurface(null);
|
|
772
|
+
segmentSwitchRef.current = false;
|
|
773
|
+
}, []);
|
|
774
|
+
const beginEditing = useCallback3((id, surface = "value") => {
|
|
775
|
+
setEditingConditionId(id);
|
|
776
|
+
setActiveSurface(surface);
|
|
777
|
+
}, []);
|
|
778
|
+
const openSurface = useCallback3(
|
|
779
|
+
(id, surface) => {
|
|
780
|
+
if (editingConditionId !== id) {
|
|
781
|
+
beginEditing(id, surface);
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
setActiveSurface(surface);
|
|
785
|
+
},
|
|
786
|
+
[beginEditing, editingConditionId]
|
|
787
|
+
);
|
|
788
|
+
const closeSurface = useCallback3(
|
|
789
|
+
(id) => {
|
|
790
|
+
if (editingConditionId === id) {
|
|
791
|
+
setActiveSurface(null);
|
|
792
|
+
}
|
|
793
|
+
},
|
|
794
|
+
[editingConditionId]
|
|
795
|
+
);
|
|
796
|
+
const handlePopoverDismiss = useCallback3(
|
|
797
|
+
(id) => {
|
|
798
|
+
if (segmentSwitchRef.current) {
|
|
799
|
+
segmentSwitchRef.current = false;
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
if (isDismissSuppressed(id)) {
|
|
803
|
+
return;
|
|
804
|
+
}
|
|
805
|
+
suppressCloseUntilRef.current = null;
|
|
806
|
+
commitCondition(id);
|
|
807
|
+
},
|
|
808
|
+
[commitCondition, isDismissSuppressed]
|
|
809
|
+
);
|
|
810
|
+
const toggleSurface = useCallback3(
|
|
811
|
+
(id, surface) => {
|
|
812
|
+
const isDraft = editingConditionId === id;
|
|
813
|
+
const popoverVisible = isDraft && activeSurface !== null;
|
|
814
|
+
if (isDraft && activeSurface === surface && popoverVisible) {
|
|
815
|
+
closeSurface(id);
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
if (popoverVisible && activeSurface !== surface) {
|
|
819
|
+
segmentSwitchRef.current = true;
|
|
820
|
+
}
|
|
821
|
+
openSurface(id, surface);
|
|
822
|
+
},
|
|
823
|
+
[activeSurface, closeSurface, editingConditionId, openSurface]
|
|
824
|
+
);
|
|
825
|
+
const suppressDismissFor = useCallback3((id, ms = ADD_FILTER_POPOVER_SUPPRESS_MS) => {
|
|
826
|
+
suppressCloseUntilRef.current = {
|
|
827
|
+
id,
|
|
828
|
+
until: Date.now() + ms
|
|
829
|
+
};
|
|
830
|
+
}, []);
|
|
831
|
+
const removeCondition = useCallback3(
|
|
832
|
+
(id) => {
|
|
833
|
+
var _a;
|
|
834
|
+
if (((_a = suppressCloseUntilRef.current) == null ? void 0 : _a.id) === id) {
|
|
835
|
+
suppressCloseUntilRef.current = null;
|
|
836
|
+
}
|
|
837
|
+
setCommittedConditionIds((prev) => {
|
|
838
|
+
if (!prev.has(id)) {
|
|
839
|
+
return prev;
|
|
840
|
+
}
|
|
841
|
+
const next = new Set(prev);
|
|
842
|
+
next.delete(id);
|
|
843
|
+
return next;
|
|
844
|
+
});
|
|
845
|
+
setEditingConditionId((current) => current === id ? null : current);
|
|
846
|
+
if (editingConditionId === id) {
|
|
847
|
+
setActiveSurface(null);
|
|
848
|
+
segmentSwitchRef.current = false;
|
|
849
|
+
}
|
|
850
|
+
},
|
|
851
|
+
[editingConditionId]
|
|
852
|
+
);
|
|
853
|
+
const clearSuppress = useCallback3(() => {
|
|
854
|
+
suppressCloseUntilRef.current = null;
|
|
855
|
+
}, []);
|
|
856
|
+
const getController = useCallback3(
|
|
857
|
+
(conditionId) => {
|
|
858
|
+
const isDraft = editingConditionId === conditionId;
|
|
859
|
+
const surface = isDraft ? activeSurface : null;
|
|
860
|
+
return {
|
|
861
|
+
isDraft,
|
|
862
|
+
activeSurface: surface,
|
|
863
|
+
popoverVisible: isDraft && activeSurface !== null,
|
|
864
|
+
isDismissSuppressed: () => isDismissSuppressed(conditionId),
|
|
865
|
+
beginEditing: () => beginEditing(conditionId),
|
|
866
|
+
openSurface: (s) => openSurface(conditionId, s),
|
|
867
|
+
closeSurface: () => closeSurface(conditionId),
|
|
868
|
+
commit: () => {
|
|
869
|
+
suppressCloseUntilRef.current = null;
|
|
870
|
+
commitCondition(conditionId);
|
|
871
|
+
},
|
|
872
|
+
handlePopoverDismiss: () => handlePopoverDismiss(conditionId),
|
|
873
|
+
toggleSurface: (s) => toggleSurface(conditionId, s)
|
|
874
|
+
};
|
|
875
|
+
},
|
|
876
|
+
[
|
|
877
|
+
activeSurface,
|
|
878
|
+
beginEditing,
|
|
879
|
+
closeSurface,
|
|
880
|
+
commitCondition,
|
|
881
|
+
editingConditionId,
|
|
882
|
+
handlePopoverDismiss,
|
|
883
|
+
isDismissSuppressed,
|
|
884
|
+
openSurface,
|
|
885
|
+
toggleSurface
|
|
886
|
+
]
|
|
887
|
+
);
|
|
888
|
+
return {
|
|
889
|
+
editingConditionId,
|
|
890
|
+
activeSurface,
|
|
891
|
+
committedConditionIds,
|
|
892
|
+
getController,
|
|
893
|
+
beginEditing,
|
|
894
|
+
suppressDismissFor,
|
|
895
|
+
removeCondition,
|
|
896
|
+
clearSuppress
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// src/lib/cel-filter/date-utils.ts
|
|
901
|
+
var CALENDAR_DAY_PATTERN = /^(\d{4}-\d{2}-\d{2})/;
|
|
902
|
+
var MINUTE_PATTERN = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2})/;
|
|
903
|
+
var TIME_OF_DAY_PATTERN = /^\d{4}-\d{2}-\d{2}T(\d{2}:\d{2})/;
|
|
904
|
+
function calendarDayStartInstant(instant) {
|
|
905
|
+
const match = CALENDAR_DAY_PATTERN.exec(instant);
|
|
906
|
+
return match ? `${match[1]}T00:00:00.000Z` : instant;
|
|
907
|
+
}
|
|
908
|
+
function inclusiveEndInstant(instant, granularity) {
|
|
909
|
+
if (granularity === "minute") {
|
|
910
|
+
const minuteMatch = MINUTE_PATTERN.exec(instant);
|
|
911
|
+
return minuteMatch ? `${minuteMatch[1]}:59.999Z` : instant;
|
|
912
|
+
}
|
|
913
|
+
const match = CALENDAR_DAY_PATTERN.exec(instant);
|
|
914
|
+
return match ? `${match[1]}T23:59:59.999Z` : instant;
|
|
915
|
+
}
|
|
916
|
+
function isRealCalendarDay(instant) {
|
|
917
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})/.exec(instant);
|
|
918
|
+
if (!match) {
|
|
919
|
+
return false;
|
|
920
|
+
}
|
|
921
|
+
const [year, month, day] = [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
922
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
923
|
+
return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day;
|
|
924
|
+
}
|
|
925
|
+
function readTimeOfDay(instant) {
|
|
926
|
+
if (!instant) {
|
|
927
|
+
return "";
|
|
928
|
+
}
|
|
929
|
+
const match = TIME_OF_DAY_PATTERN.exec(instant);
|
|
930
|
+
return match ? match[1] : "";
|
|
931
|
+
}
|
|
932
|
+
function withTimeOfDay(instant, timeOfDay) {
|
|
933
|
+
const day = CALENDAR_DAY_PATTERN.exec(instant);
|
|
934
|
+
const time = /^(\d{2}):(\d{2})/.exec(timeOfDay);
|
|
935
|
+
if (!day || !time) {
|
|
936
|
+
return instant;
|
|
937
|
+
}
|
|
938
|
+
return `${day[1]}T${time[1]}:${time[2]}:00.000Z`;
|
|
939
|
+
}
|
|
940
|
+
function formatCalendarDateUtc(date, boundary) {
|
|
941
|
+
const year = date.getFullYear();
|
|
942
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
943
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
944
|
+
const time = boundary === "end" ? "T23:59:59.999Z" : "T00:00:00.000Z";
|
|
945
|
+
return `${year}-${month}-${day}${time}`;
|
|
946
|
+
}
|
|
947
|
+
function parseCalendarDate(value) {
|
|
948
|
+
if (!value) {
|
|
949
|
+
return void 0;
|
|
950
|
+
}
|
|
951
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})/.exec(value);
|
|
952
|
+
if (!match) {
|
|
953
|
+
return void 0;
|
|
954
|
+
}
|
|
955
|
+
return new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]));
|
|
956
|
+
}
|
|
957
|
+
function formatInstantLabel(instant, { withTime = false, locale } = {}) {
|
|
958
|
+
const date = parseCalendarDate(instant);
|
|
959
|
+
if (!date) {
|
|
960
|
+
return "";
|
|
961
|
+
}
|
|
962
|
+
const dateLabel = date.toLocaleDateString(locale);
|
|
963
|
+
const timeOfDay = withTime ? readTimeOfDay(instant) : "";
|
|
964
|
+
return timeOfDay ? `${dateLabel} ${timeOfDay} UTC` : dateLabel;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// src/lib/cel-filter/types.ts
|
|
968
|
+
var isCelFilterGroup = (node) => node.type === "group";
|
|
969
|
+
var isCelFilterCondition = (node) => node.type === "condition";
|
|
970
|
+
var isCheckboxCelValue = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
971
|
+
var isMultiTextCelValue = (value) => typeof value === "object" && value !== null && "tokens" in value;
|
|
972
|
+
var isDateCelValue = (value) => {
|
|
973
|
+
if (typeof value !== "object" || value === null) {
|
|
974
|
+
return false;
|
|
975
|
+
}
|
|
976
|
+
if ("tokens" in value || "key" in value) {
|
|
977
|
+
return false;
|
|
978
|
+
}
|
|
979
|
+
return "preset" in value || "instant" in value || "range" in value || Object.keys(value).length === 0;
|
|
980
|
+
};
|
|
981
|
+
var isMapKeyCelValue = (value) => typeof value === "object" && value !== null && "key" in value;
|
|
982
|
+
|
|
983
|
+
// src/lib/cel-filter/value-utils.ts
|
|
984
|
+
function isRelativeDateCelValue(value) {
|
|
985
|
+
return value.preset != null;
|
|
986
|
+
}
|
|
987
|
+
function readDateCelValue(value) {
|
|
988
|
+
return isDateCelValue(value) ? value : {};
|
|
989
|
+
}
|
|
990
|
+
function readMapKeyCelValue(value) {
|
|
991
|
+
return isMapKeyCelValue(value) ? value : { key: "" };
|
|
992
|
+
}
|
|
993
|
+
function readMultiTextCelValue(value) {
|
|
994
|
+
return isMultiTextCelValue(value) ? value : { tokens: [] };
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
// src/lib/cel-filter/compile/escape-cel-string.ts
|
|
998
|
+
function escapeCelString(input) {
|
|
999
|
+
let out = "";
|
|
1000
|
+
for (const char of input) {
|
|
1001
|
+
switch (char) {
|
|
1002
|
+
case "\\":
|
|
1003
|
+
out += "\\\\";
|
|
1004
|
+
break;
|
|
1005
|
+
case '"':
|
|
1006
|
+
out += '\\"';
|
|
1007
|
+
break;
|
|
1008
|
+
case "\n":
|
|
1009
|
+
out += "\\n";
|
|
1010
|
+
break;
|
|
1011
|
+
case "\r":
|
|
1012
|
+
out += "\\r";
|
|
1013
|
+
break;
|
|
1014
|
+
case " ":
|
|
1015
|
+
out += "\\t";
|
|
1016
|
+
break;
|
|
1017
|
+
case "\f":
|
|
1018
|
+
out += "\\f";
|
|
1019
|
+
break;
|
|
1020
|
+
case "\v":
|
|
1021
|
+
out += "\\v";
|
|
1022
|
+
break;
|
|
1023
|
+
case "\b":
|
|
1024
|
+
out += "\\b";
|
|
1025
|
+
break;
|
|
1026
|
+
case "\0":
|
|
1027
|
+
out += "\\0";
|
|
1028
|
+
break;
|
|
1029
|
+
default:
|
|
1030
|
+
out += char;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
return out;
|
|
1034
|
+
}
|
|
1035
|
+
function celStringLiteral(input) {
|
|
1036
|
+
return `"${escapeCelString(input)}"`;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
// src/lib/cel-filter/compile/operators.ts
|
|
1040
|
+
var RESERVED_COLUMN_CEL_IDENTIFIERS = {
|
|
1041
|
+
namespace: "__namespace__"
|
|
1042
|
+
};
|
|
1043
|
+
var CEL_IDENTIFIER_TO_COLUMN_ID = Object.fromEntries(
|
|
1044
|
+
Object.entries(RESERVED_COLUMN_CEL_IDENTIFIERS).map(([columnId, celIdentifier]) => [celIdentifier, columnId])
|
|
1045
|
+
);
|
|
1046
|
+
var ENUM_OPERATORS = ["is", "is_not"];
|
|
1047
|
+
var TEXT_OPERATORS = [
|
|
1048
|
+
"is",
|
|
1049
|
+
"is_not",
|
|
1050
|
+
"contains",
|
|
1051
|
+
"does_not_contain",
|
|
1052
|
+
"starts_with",
|
|
1053
|
+
"ends_with",
|
|
1054
|
+
"matches"
|
|
1055
|
+
];
|
|
1056
|
+
var DATE_OPERATORS = [
|
|
1057
|
+
"is",
|
|
1058
|
+
"is_not",
|
|
1059
|
+
"is_before",
|
|
1060
|
+
"is_after",
|
|
1061
|
+
"is_on_or_before",
|
|
1062
|
+
"is_on_or_after",
|
|
1063
|
+
"is_between",
|
|
1064
|
+
"is_not_between"
|
|
1065
|
+
];
|
|
1066
|
+
var MAP_OPERATORS = ["key_exists", "key_does_not_exist", "has_value", "does_not_have_value"];
|
|
1067
|
+
var DATE_RELATIVE_OPERATORS = ["is_before", "is_after", "is_on_or_before", "is_on_or_after"];
|
|
1068
|
+
var DATE_WINDOW_OPERATORS = ["is", "is_not"];
|
|
1069
|
+
var DATE_RANGE_OPERATORS = ["is_between", "is_not_between"];
|
|
1070
|
+
var DATE_END_BOUNDARY_OPERATORS = ["is_on_or_before", "is_after"];
|
|
1071
|
+
var MAP_VALUE_OPERATORS = ["has_value", "does_not_have_value"];
|
|
1072
|
+
function getAllowedOperatorsForShape(shape) {
|
|
1073
|
+
switch (shape) {
|
|
1074
|
+
case "checkbox":
|
|
1075
|
+
case "radio":
|
|
1076
|
+
case "static":
|
|
1077
|
+
return ENUM_OPERATORS;
|
|
1078
|
+
case "text":
|
|
1079
|
+
case "multiText":
|
|
1080
|
+
return TEXT_OPERATORS;
|
|
1081
|
+
case "date":
|
|
1082
|
+
return DATE_OPERATORS;
|
|
1083
|
+
case "map":
|
|
1084
|
+
return MAP_OPERATORS;
|
|
1085
|
+
default:
|
|
1086
|
+
return [];
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
function getAllowedOperators(columnDef) {
|
|
1090
|
+
if (!columnDef) {
|
|
1091
|
+
return [];
|
|
1092
|
+
}
|
|
1093
|
+
if (columnDef.allowedOperators) {
|
|
1094
|
+
return columnDef.allowedOperators;
|
|
1095
|
+
}
|
|
1096
|
+
const shape = columnDef.filterType === "keyValue" ? "map" : columnDef.filterType;
|
|
1097
|
+
return getAllowedOperatorsForShape(shape);
|
|
1098
|
+
}
|
|
1099
|
+
function isDateRelativeOperator(operator) {
|
|
1100
|
+
return DATE_RELATIVE_OPERATORS.includes(operator);
|
|
1101
|
+
}
|
|
1102
|
+
function isDateWindowOperator(operator) {
|
|
1103
|
+
return DATE_WINDOW_OPERATORS.includes(operator);
|
|
1104
|
+
}
|
|
1105
|
+
function isDateRangeOperator(operator) {
|
|
1106
|
+
return DATE_RANGE_OPERATORS.includes(operator);
|
|
1107
|
+
}
|
|
1108
|
+
function dateBoundaryForOperator(operator) {
|
|
1109
|
+
return DATE_END_BOUNDARY_OPERATORS.includes(operator) ? "end" : "start";
|
|
1110
|
+
}
|
|
1111
|
+
function resolveColumnDefinition(condition, schema) {
|
|
1112
|
+
if (!condition.columnId) {
|
|
1113
|
+
return void 0;
|
|
1114
|
+
}
|
|
1115
|
+
return schema.columns.find((column) => column.id === condition.columnId);
|
|
1116
|
+
}
|
|
1117
|
+
function resolveFilterShape(condition, schema) {
|
|
1118
|
+
const columnDef = resolveColumnDefinition(condition, schema);
|
|
1119
|
+
if (!columnDef) {
|
|
1120
|
+
return void 0;
|
|
1121
|
+
}
|
|
1122
|
+
if (columnDef.filterType === "keyValue") {
|
|
1123
|
+
return "map";
|
|
1124
|
+
}
|
|
1125
|
+
if (columnDef.filterType === "static") {
|
|
1126
|
+
return Array.isArray(condition.value) ? "checkbox" : "radio";
|
|
1127
|
+
}
|
|
1128
|
+
return columnDef.filterType;
|
|
1129
|
+
}
|
|
1130
|
+
var OPERATOR_LABELS = {
|
|
1131
|
+
is: "is",
|
|
1132
|
+
is_not: "is not",
|
|
1133
|
+
contains: "contains",
|
|
1134
|
+
does_not_contain: "does not contain",
|
|
1135
|
+
starts_with: "starts with",
|
|
1136
|
+
ends_with: "ends with",
|
|
1137
|
+
matches: "matches",
|
|
1138
|
+
is_before: "is before",
|
|
1139
|
+
is_after: "is after",
|
|
1140
|
+
is_on_or_before: "is on or before",
|
|
1141
|
+
is_on_or_after: "is on or after",
|
|
1142
|
+
is_between: "is between",
|
|
1143
|
+
is_not_between: "is not between",
|
|
1144
|
+
key_exists: "key exists",
|
|
1145
|
+
key_does_not_exist: "key does not exist",
|
|
1146
|
+
has_value: "has value",
|
|
1147
|
+
does_not_have_value: "does not have value"
|
|
1148
|
+
};
|
|
1149
|
+
function getOperatorLabel(operator) {
|
|
1150
|
+
return OPERATOR_LABELS[operator];
|
|
1151
|
+
}
|
|
1152
|
+
function getQuantifierLabel(quantifier) {
|
|
1153
|
+
return quantifier === "all" ? "all of" : "any of";
|
|
1154
|
+
}
|
|
1155
|
+
var SINGLE_INSTANCE_FILTER_TYPES = /* @__PURE__ */ new Set(["checkbox", "radio", "static"]);
|
|
1156
|
+
function allowsMultipleConditions(filterType) {
|
|
1157
|
+
return !SINGLE_INSTANCE_FILTER_TYPES.has(filterType);
|
|
1158
|
+
}
|
|
1159
|
+
function getDefaultOperator(filterType) {
|
|
1160
|
+
switch (filterType) {
|
|
1161
|
+
case "checkbox":
|
|
1162
|
+
case "radio":
|
|
1163
|
+
case "text":
|
|
1164
|
+
case "static":
|
|
1165
|
+
return "is";
|
|
1166
|
+
case "multiText":
|
|
1167
|
+
return "contains";
|
|
1168
|
+
case "date":
|
|
1169
|
+
return "is";
|
|
1170
|
+
case "keyValue":
|
|
1171
|
+
return "key_exists";
|
|
1172
|
+
default:
|
|
1173
|
+
return "is";
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
function applyOperatorChange(condition, newOperator, shape) {
|
|
1177
|
+
const next = __spreadProps(__spreadValues({}, condition), { operator: newOperator });
|
|
1178
|
+
const oldOperator = condition.operator;
|
|
1179
|
+
if (shape === "date") {
|
|
1180
|
+
const value = condition.value;
|
|
1181
|
+
const isRelative = isDateCelValue(value) && isRelativeDateCelValue(value);
|
|
1182
|
+
const changesValueShape = isDateRangeOperator(oldOperator) !== isDateRangeOperator(newOperator);
|
|
1183
|
+
const relativeNeedsClear = isRelative && (newOperator === "is" || newOperator === "is_not");
|
|
1184
|
+
if (changesValueShape || relativeNeedsClear) {
|
|
1185
|
+
next.value = void 0;
|
|
1186
|
+
return next;
|
|
1187
|
+
}
|
|
1188
|
+
if (isDateCelValue(value) && value.hasTime && isDateWindowOperator(newOperator)) {
|
|
1189
|
+
const _a = value, { hasTime: _hasTime } = _a, dayOnly = __objRest(_a, ["hasTime"]);
|
|
1190
|
+
next.value = dayOnly;
|
|
1191
|
+
}
|
|
1192
|
+
return next;
|
|
1193
|
+
}
|
|
1194
|
+
if (shape === "map") {
|
|
1195
|
+
const value = condition.value;
|
|
1196
|
+
if (!isMapKeyCelValue(value)) {
|
|
1197
|
+
return next;
|
|
1198
|
+
}
|
|
1199
|
+
const bothValueOps = MAP_VALUE_OPERATORS.includes(oldOperator) && MAP_VALUE_OPERATORS.includes(newOperator);
|
|
1200
|
+
next.value = bothValueOps ? { key: value.key, value: value.value } : { key: value.key };
|
|
1201
|
+
return next;
|
|
1202
|
+
}
|
|
1203
|
+
return next;
|
|
1204
|
+
}
|
|
1205
|
+
var atomic = (expression) => ({ expression, needsGrouping: false });
|
|
1206
|
+
function buildConditionExpression(condition, shape, columnDef) {
|
|
1207
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1208
|
+
if (shape === "map") {
|
|
1209
|
+
return buildMapExpression(condition.columnId, condition.operator, condition.value);
|
|
1210
|
+
}
|
|
1211
|
+
const columnId = (_b = (_a = columnDef == null ? void 0 : columnDef.id) != null ? _a : condition.columnId) != null ? _b : "";
|
|
1212
|
+
const column = (_c = RESERVED_COLUMN_CEL_IDENTIFIERS[columnId]) != null ? _c : columnId;
|
|
1213
|
+
switch (shape) {
|
|
1214
|
+
case "checkbox":
|
|
1215
|
+
return buildCheckboxExpression(column, condition.operator, (_d = condition.value) != null ? _d : []);
|
|
1216
|
+
case "radio":
|
|
1217
|
+
return buildRadioExpression(column, condition.operator, String((_e = condition.value) != null ? _e : ""));
|
|
1218
|
+
case "text":
|
|
1219
|
+
return atomic(buildTextTokenFragment(column, condition.operator, String((_f = condition.value) != null ? _f : "")));
|
|
1220
|
+
case "multiText":
|
|
1221
|
+
return buildMultiTextExpression(column, condition.operator, condition.value);
|
|
1222
|
+
case "date":
|
|
1223
|
+
return atomic(buildDateExpression(column, condition.operator, condition.value));
|
|
1224
|
+
default:
|
|
1225
|
+
return atomic("");
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
function buildCheckboxExpression(column, operator, values) {
|
|
1229
|
+
const list = `${column} in [${values.map(celStringLiteral).join(", ")}]`;
|
|
1230
|
+
return atomic(operator === "is_not" ? `!(${list})` : list);
|
|
1231
|
+
}
|
|
1232
|
+
function buildRadioExpression(column, operator, value) {
|
|
1233
|
+
const literal = celStringLiteral(value);
|
|
1234
|
+
return atomic(operator === "is_not" ? `${column} != ${literal}` : `${column} == ${literal}`);
|
|
1235
|
+
}
|
|
1236
|
+
function buildTextTokenFragment(column, operator, value, forcePositive = false) {
|
|
1237
|
+
const literal = celStringLiteral(value);
|
|
1238
|
+
switch (operator) {
|
|
1239
|
+
case "is":
|
|
1240
|
+
return `${column} == ${literal}`;
|
|
1241
|
+
case "is_not":
|
|
1242
|
+
return forcePositive ? `${column} == ${literal}` : `${column} != ${literal}`;
|
|
1243
|
+
case "contains":
|
|
1244
|
+
return `${column}.contains(${literal})`;
|
|
1245
|
+
case "does_not_contain":
|
|
1246
|
+
return forcePositive ? `${column}.contains(${literal})` : `!${column}.contains(${literal})`;
|
|
1247
|
+
case "starts_with":
|
|
1248
|
+
return `${column}.startsWith(${literal})`;
|
|
1249
|
+
case "ends_with":
|
|
1250
|
+
return `${column}.endsWith(${literal})`;
|
|
1251
|
+
case "matches":
|
|
1252
|
+
return `${column}.matches(${literal})`;
|
|
1253
|
+
default:
|
|
1254
|
+
return "";
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
function isNegatedTextOperator(operator) {
|
|
1258
|
+
return operator === "is_not" || operator === "does_not_contain";
|
|
1259
|
+
}
|
|
1260
|
+
function buildMultiTextExpression(column, operator, value) {
|
|
1261
|
+
const tokens = value.tokens;
|
|
1262
|
+
if (tokens.length === 1) {
|
|
1263
|
+
return atomic(buildTextTokenFragment(column, operator, tokens[0]));
|
|
1264
|
+
}
|
|
1265
|
+
const connective = value.quantifier === "all" ? " && " : " || ";
|
|
1266
|
+
const joined = tokens.map((token) => buildTextTokenFragment(column, operator, token, true)).join(connective);
|
|
1267
|
+
if (isNegatedTextOperator(operator)) {
|
|
1268
|
+
return atomic(`!(${joined})`);
|
|
1269
|
+
}
|
|
1270
|
+
return { expression: joined, needsGrouping: value.quantifier !== "all" };
|
|
1271
|
+
}
|
|
1272
|
+
var DATE_RELATIVE_COMPARATOR_SYMBOLS = {
|
|
1273
|
+
is_before: "<",
|
|
1274
|
+
is_after: ">",
|
|
1275
|
+
is_on_or_before: "<=",
|
|
1276
|
+
is_on_or_after: ">="
|
|
1277
|
+
};
|
|
1278
|
+
function buildCalendarDayRange(column, startInstant, endInstant) {
|
|
1279
|
+
const start = `timestamp(${celStringLiteral(startInstant)})`;
|
|
1280
|
+
const end = `timestamp(${celStringLiteral(endInstant)})`;
|
|
1281
|
+
return `${column} >= ${start} && ${column} <= ${end}`;
|
|
1282
|
+
}
|
|
1283
|
+
function buildDateExpression(column, operator, value) {
|
|
1284
|
+
var _a, _b, _c;
|
|
1285
|
+
if (isRelativeDateCelValue(value)) {
|
|
1286
|
+
const durationStr = (_a = value.preset) != null ? _a : "";
|
|
1287
|
+
if (!durationStr) {
|
|
1288
|
+
return "";
|
|
1289
|
+
}
|
|
1290
|
+
const relativeSymbol = (_b = DATE_RELATIVE_COMPARATOR_SYMBOLS[operator]) != null ? _b : ">";
|
|
1291
|
+
return `${column} ${relativeSymbol} now() - duration(${celStringLiteral(durationStr)})`;
|
|
1292
|
+
}
|
|
1293
|
+
if (isDateRangeOperator(operator) && value.range) {
|
|
1294
|
+
const range = buildCalendarDayRange(column, value.range.start, value.range.end);
|
|
1295
|
+
return operator === "is_not_between" ? `!(${range})` : range;
|
|
1296
|
+
}
|
|
1297
|
+
const startInstant = (_c = value.instant) != null ? _c : "";
|
|
1298
|
+
const granularity = value.hasTime && !isDateWindowOperator(operator) ? "minute" : "day";
|
|
1299
|
+
const endInstant = inclusiveEndInstant(startInstant, granularity);
|
|
1300
|
+
const startTimestamp = `timestamp(${celStringLiteral(startInstant)})`;
|
|
1301
|
+
const endTimestamp = `timestamp(${celStringLiteral(endInstant)})`;
|
|
1302
|
+
switch (operator) {
|
|
1303
|
+
case "is":
|
|
1304
|
+
return buildCalendarDayRange(column, startInstant, endInstant);
|
|
1305
|
+
case "is_not":
|
|
1306
|
+
return `!(${buildCalendarDayRange(column, startInstant, endInstant)})`;
|
|
1307
|
+
case "is_before":
|
|
1308
|
+
return `${column} < ${startTimestamp}`;
|
|
1309
|
+
case "is_on_or_before":
|
|
1310
|
+
return `${column} <= ${endTimestamp}`;
|
|
1311
|
+
case "is_after":
|
|
1312
|
+
return `${column} > ${endTimestamp}`;
|
|
1313
|
+
case "is_on_or_after":
|
|
1314
|
+
return `${column} >= ${startTimestamp}`;
|
|
1315
|
+
default:
|
|
1316
|
+
return `${column} == ${startTimestamp}`;
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
function buildMapExpression(columnId, operator, value) {
|
|
1320
|
+
var _a, _b, _c;
|
|
1321
|
+
const column = (_a = RESERVED_COLUMN_CEL_IDENTIFIERS[columnId]) != null ? _a : columnId;
|
|
1322
|
+
const keyLiteral = celStringLiteral(value.key);
|
|
1323
|
+
switch (operator) {
|
|
1324
|
+
case "key_exists":
|
|
1325
|
+
return atomic(`${keyLiteral} in ${column}`);
|
|
1326
|
+
case "key_does_not_exist":
|
|
1327
|
+
return atomic(`!(${keyLiteral} in ${column})`);
|
|
1328
|
+
case "has_value":
|
|
1329
|
+
return atomic(`${column}[${keyLiteral}] == ${celStringLiteral((_b = value.value) != null ? _b : "")}`);
|
|
1330
|
+
case "does_not_have_value":
|
|
1331
|
+
return atomic(`${column}[${keyLiteral}] != ${celStringLiteral((_c = value.value) != null ? _c : "")}`);
|
|
1332
|
+
default:
|
|
1333
|
+
return atomic("");
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
// src/lib/cel-filter/compile/validate-condition.ts
|
|
1338
|
+
function statusFromIssues(issues) {
|
|
1339
|
+
if (issues.some((issue) => issue.severity === "invalid")) {
|
|
1340
|
+
return "invalid";
|
|
1341
|
+
}
|
|
1342
|
+
if (issues.some((issue) => issue.severity === "incomplete")) {
|
|
1343
|
+
return "incomplete";
|
|
1344
|
+
}
|
|
1345
|
+
return "valid";
|
|
1346
|
+
}
|
|
1347
|
+
var SEVERITY_BY_CODE = {
|
|
1348
|
+
missing_column: "incomplete",
|
|
1349
|
+
missing_value: "incomplete",
|
|
1350
|
+
missing_key: "incomplete",
|
|
1351
|
+
missing_tokens: "incomplete",
|
|
1352
|
+
missing_quantifier: "incomplete",
|
|
1353
|
+
missing_instant: "incomplete",
|
|
1354
|
+
missing_range: "incomplete",
|
|
1355
|
+
missing_duration: "incomplete",
|
|
1356
|
+
unknown_column: "invalid",
|
|
1357
|
+
illegal_operator: "invalid",
|
|
1358
|
+
invalid_date_mode: "invalid",
|
|
1359
|
+
regex_too_long: "invalid",
|
|
1360
|
+
invalid_timestamp: "invalid",
|
|
1361
|
+
invalid_date_range: "invalid",
|
|
1362
|
+
nesting_depth_exceeded: "invalid"
|
|
1363
|
+
};
|
|
1364
|
+
var MESSAGES = {
|
|
1365
|
+
missing_column: "Select a column for this filter.",
|
|
1366
|
+
missing_value: "Enter a value for this filter.",
|
|
1367
|
+
missing_key: "Enter a key for this filter.",
|
|
1368
|
+
missing_tokens: "Enter at least one value for this filter.",
|
|
1369
|
+
missing_quantifier: "Choose whether to match any or all values.",
|
|
1370
|
+
missing_instant: "Select a date for this filter.",
|
|
1371
|
+
missing_range: "Select a start and end date for this filter.",
|
|
1372
|
+
missing_duration: "Select a duration for this filter.",
|
|
1373
|
+
unknown_column: "This column is not available for filtering.",
|
|
1374
|
+
illegal_operator: "This operator is not allowed for this filter.",
|
|
1375
|
+
invalid_date_mode: "This operator cannot be used with this date mode.",
|
|
1376
|
+
regex_too_long: `Pattern exceeds the maximum length of ${MAX_REGEX_LEN} characters.`,
|
|
1377
|
+
invalid_timestamp: "Enter a valid date.",
|
|
1378
|
+
invalid_date_range: "The start must be on or before the end.",
|
|
1379
|
+
nesting_depth_exceeded: "This filter is nested too deeply."
|
|
1380
|
+
};
|
|
1381
|
+
var RFC3339_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
|
|
1382
|
+
function isValidRfc3339(value) {
|
|
1383
|
+
return RFC3339_RE.test(value) && !Number.isNaN(Date.parse(value)) && isRealCalendarDay(value);
|
|
1384
|
+
}
|
|
1385
|
+
function makeIssue({ condition, code, field }) {
|
|
1386
|
+
return {
|
|
1387
|
+
code,
|
|
1388
|
+
message: MESSAGES[code],
|
|
1389
|
+
severity: SEVERITY_BY_CODE[code],
|
|
1390
|
+
nodeId: condition.id,
|
|
1391
|
+
nodeType: "condition",
|
|
1392
|
+
field
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
function validateCondition(condition, schema) {
|
|
1396
|
+
if (!condition.columnId) {
|
|
1397
|
+
return [makeIssue({ condition, code: "missing_column", field: "columnId" })];
|
|
1398
|
+
}
|
|
1399
|
+
const columnDef = resolveColumnDefinition(condition, schema);
|
|
1400
|
+
if (!columnDef) {
|
|
1401
|
+
return [makeIssue({ condition, code: "unknown_column", field: "columnId" })];
|
|
1402
|
+
}
|
|
1403
|
+
return validateColumnCondition(condition, columnDef);
|
|
1404
|
+
}
|
|
1405
|
+
function validateColumnCondition(condition, columnDef) {
|
|
1406
|
+
const allowed = getAllowedOperators(columnDef);
|
|
1407
|
+
if (!allowed.includes(condition.operator)) {
|
|
1408
|
+
return [makeIssue({ condition, code: "illegal_operator", field: "operator" })];
|
|
1409
|
+
}
|
|
1410
|
+
switch (columnDef.filterType) {
|
|
1411
|
+
case "checkbox":
|
|
1412
|
+
case "static":
|
|
1413
|
+
return validateCheckbox(condition);
|
|
1414
|
+
case "radio":
|
|
1415
|
+
case "text":
|
|
1416
|
+
return validateSingleString(condition, columnDef.filterType);
|
|
1417
|
+
case "multiText":
|
|
1418
|
+
return validateMultiText(condition);
|
|
1419
|
+
case "date":
|
|
1420
|
+
return validateDate(condition);
|
|
1421
|
+
case "keyValue":
|
|
1422
|
+
return validateMapCondition(condition);
|
|
1423
|
+
default:
|
|
1424
|
+
return [];
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
function validateCheckbox(condition) {
|
|
1428
|
+
const value = condition.value;
|
|
1429
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
1430
|
+
return [makeIssue({ condition, code: "missing_value", field: "value" })];
|
|
1431
|
+
}
|
|
1432
|
+
return [];
|
|
1433
|
+
}
|
|
1434
|
+
function validateSingleString(condition, filterType) {
|
|
1435
|
+
const value = condition.value;
|
|
1436
|
+
if (typeof value !== "string" || value === "") {
|
|
1437
|
+
return [makeIssue({ condition, code: "missing_value", field: "value" })];
|
|
1438
|
+
}
|
|
1439
|
+
if (filterType === "text" && condition.operator === "matches" && value.length > MAX_REGEX_LEN) {
|
|
1440
|
+
return [makeIssue({ condition, code: "regex_too_long", field: "pattern" })];
|
|
1441
|
+
}
|
|
1442
|
+
return [];
|
|
1443
|
+
}
|
|
1444
|
+
function validateMultiText(condition) {
|
|
1445
|
+
const value = condition.value;
|
|
1446
|
+
if (!isMultiTextCelValue(value) || value.tokens.length === 0) {
|
|
1447
|
+
return [makeIssue({ condition, code: "missing_tokens", field: "tokens" })];
|
|
1448
|
+
}
|
|
1449
|
+
const issues = [];
|
|
1450
|
+
const multi = value;
|
|
1451
|
+
if (multi.tokens.length > 1 && !multi.quantifier) {
|
|
1452
|
+
issues.push(makeIssue({ condition, code: "missing_quantifier", field: "quantifier" }));
|
|
1453
|
+
}
|
|
1454
|
+
if (condition.operator === "matches" && multi.tokens.some((token) => token.length > MAX_REGEX_LEN)) {
|
|
1455
|
+
issues.push(makeIssue({ condition, code: "regex_too_long", field: "pattern" }));
|
|
1456
|
+
}
|
|
1457
|
+
return issues;
|
|
1458
|
+
}
|
|
1459
|
+
function validateDate(condition) {
|
|
1460
|
+
const value = condition.value;
|
|
1461
|
+
if (!isDateCelValue(value)) {
|
|
1462
|
+
return [makeIssue({ condition, code: "missing_instant", field: "instant" })];
|
|
1463
|
+
}
|
|
1464
|
+
const date = value;
|
|
1465
|
+
if (isRelativeDateCelValue(date)) {
|
|
1466
|
+
return validateRelativeDate(condition, date);
|
|
1467
|
+
}
|
|
1468
|
+
return validateAbsoluteDate(condition, date);
|
|
1469
|
+
}
|
|
1470
|
+
function validateAbsoluteDate(condition, value) {
|
|
1471
|
+
const issues = [];
|
|
1472
|
+
if (isDateRangeOperator(condition.operator)) {
|
|
1473
|
+
const range = value.range;
|
|
1474
|
+
if (!range || !range.start || !range.end) {
|
|
1475
|
+
issues.push(makeIssue({ condition, code: "missing_range", field: "range" }));
|
|
1476
|
+
return issues;
|
|
1477
|
+
}
|
|
1478
|
+
if (!isValidRfc3339(range.start)) {
|
|
1479
|
+
issues.push(makeIssue({ condition, code: "invalid_timestamp", field: "start" }));
|
|
1480
|
+
}
|
|
1481
|
+
if (!isValidRfc3339(range.end)) {
|
|
1482
|
+
issues.push(makeIssue({ condition, code: "invalid_timestamp", field: "end" }));
|
|
1483
|
+
}
|
|
1484
|
+
if (issues.length === 0 && Date.parse(range.start) > Date.parse(range.end)) {
|
|
1485
|
+
issues.push(makeIssue({ condition, code: "invalid_date_range", field: "range" }));
|
|
1486
|
+
}
|
|
1487
|
+
return issues;
|
|
1488
|
+
}
|
|
1489
|
+
if (!value.instant) {
|
|
1490
|
+
issues.push(makeIssue({ condition, code: "missing_instant", field: "instant" }));
|
|
1491
|
+
return issues;
|
|
1492
|
+
}
|
|
1493
|
+
if (!isValidRfc3339(value.instant)) {
|
|
1494
|
+
issues.push(makeIssue({ condition, code: "invalid_timestamp", field: "instant" }));
|
|
1495
|
+
}
|
|
1496
|
+
return issues;
|
|
1497
|
+
}
|
|
1498
|
+
function validateRelativeDate(condition, value) {
|
|
1499
|
+
const issues = [];
|
|
1500
|
+
if (!isDateRelativeOperator(condition.operator)) {
|
|
1501
|
+
issues.push(makeIssue({ condition, code: "invalid_date_mode", field: "value" }));
|
|
1502
|
+
return issues;
|
|
1503
|
+
}
|
|
1504
|
+
if (!value.preset) {
|
|
1505
|
+
issues.push(makeIssue({ condition, code: "missing_duration", field: "preset" }));
|
|
1506
|
+
}
|
|
1507
|
+
return issues;
|
|
1508
|
+
}
|
|
1509
|
+
function validateMapCondition(condition) {
|
|
1510
|
+
const issues = [];
|
|
1511
|
+
const value = isMapKeyCelValue(condition.value) ? condition.value : void 0;
|
|
1512
|
+
if (!value || value.key === "") {
|
|
1513
|
+
issues.push(makeIssue({ condition, code: "missing_key", field: "key" }));
|
|
1514
|
+
}
|
|
1515
|
+
const requiresValue = condition.operator === "has_value" || condition.operator === "does_not_have_value";
|
|
1516
|
+
if (requiresValue && (!value || !value.value)) {
|
|
1517
|
+
issues.push(makeIssue({ condition, code: "missing_value", field: "value" }));
|
|
1518
|
+
}
|
|
1519
|
+
return issues;
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
// src/lib/cel-filter/compile/apply-display-rules.ts
|
|
1523
|
+
function applyDisplayRules(raw, meta) {
|
|
1524
|
+
const issues = raw.issues.filter((issue) => {
|
|
1525
|
+
if (issue.nodeType === "group") {
|
|
1526
|
+
return true;
|
|
1527
|
+
}
|
|
1528
|
+
if (issue.nodeId === meta.editingConditionId) {
|
|
1529
|
+
return false;
|
|
1530
|
+
}
|
|
1531
|
+
return meta.committedConditionIds.has(issue.nodeId);
|
|
1532
|
+
});
|
|
1533
|
+
const status = statusFromIssues(issues);
|
|
1534
|
+
const expression = status === "valid" ? raw.expression : void 0;
|
|
1535
|
+
return {
|
|
1536
|
+
status,
|
|
1537
|
+
expression,
|
|
1538
|
+
issues,
|
|
1539
|
+
isEmitReady: false
|
|
1540
|
+
};
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
// src/lib/cel-filter/schema-utils.ts
|
|
1544
|
+
var COMMIT_FILTER_TYPES = /* @__PURE__ */ new Set(["text", "multiText", "keyValue", "date"]);
|
|
1545
|
+
function getColumnEmitOn(columnDef) {
|
|
1546
|
+
if (columnDef.emitOn) {
|
|
1547
|
+
return columnDef.emitOn;
|
|
1548
|
+
}
|
|
1549
|
+
return COMMIT_FILTER_TYPES.has(columnDef.filterType) ? "commit" : "change";
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
// src/lib/cel-filter/compile/compute-is-emit-ready.ts
|
|
1553
|
+
function resolveEditingColumn(tree, schema, editingConditionId) {
|
|
1554
|
+
const condition = tree.root.children.find(
|
|
1555
|
+
(child) => isCelFilterCondition(child) && child.id === editingConditionId
|
|
1556
|
+
);
|
|
1557
|
+
return condition && schema.columns.find((column) => column.id === condition.columnId);
|
|
1558
|
+
}
|
|
1559
|
+
function computeIsEmitReady(raw, editingConditionId, schema, tree, meta) {
|
|
1560
|
+
if (raw.status !== "valid") return false;
|
|
1561
|
+
if (!editingConditionId) return true;
|
|
1562
|
+
const columnDef = resolveEditingColumn(tree, schema, editingConditionId);
|
|
1563
|
+
if (!columnDef || getColumnEmitOn(columnDef) === "change") return true;
|
|
1564
|
+
const popoverClosed = meta.activeSurface === null;
|
|
1565
|
+
return popoverClosed && meta.committedConditionIds.has(editingConditionId);
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
// src/lib/cel-filter/compile/compile-cel-filter-tree.ts
|
|
1569
|
+
function combineGroupFragments(fragments) {
|
|
1570
|
+
if (fragments.length === 0) {
|
|
1571
|
+
return { expression: "", needsGrouping: false };
|
|
1572
|
+
}
|
|
1573
|
+
if (fragments.length === 1) {
|
|
1574
|
+
return fragments[0];
|
|
1575
|
+
}
|
|
1576
|
+
return {
|
|
1577
|
+
expression: fragments.map((fragment) => fragment.needsGrouping ? `(${fragment.expression})` : fragment.expression).join(" && "),
|
|
1578
|
+
needsGrouping: false
|
|
1579
|
+
};
|
|
1580
|
+
}
|
|
1581
|
+
function compileGroup(group, schema) {
|
|
1582
|
+
const depthIssues = group.depth > MAX_NESTING_DEPTH ? [
|
|
1583
|
+
{
|
|
1584
|
+
code: "nesting_depth_exceeded",
|
|
1585
|
+
message: "This filter is nested too deeply.",
|
|
1586
|
+
severity: "invalid",
|
|
1587
|
+
nodeId: group.id,
|
|
1588
|
+
nodeType: "group"
|
|
1589
|
+
}
|
|
1590
|
+
] : [];
|
|
1591
|
+
return group.children.reduce(
|
|
1592
|
+
(acc, child) => {
|
|
1593
|
+
if (isCelFilterGroup(child)) {
|
|
1594
|
+
const nested = compileGroup(child, schema);
|
|
1595
|
+
acc.issues.push(...nested.issues);
|
|
1596
|
+
if (nested.fragments.length > 0) {
|
|
1597
|
+
acc.fragments.push(combineGroupFragments(nested.fragments));
|
|
1598
|
+
}
|
|
1599
|
+
return acc;
|
|
1600
|
+
}
|
|
1601
|
+
if (isCelFilterCondition(child)) {
|
|
1602
|
+
const conditionIssues = validateCondition(child, schema);
|
|
1603
|
+
if (conditionIssues.length > 0) {
|
|
1604
|
+
acc.issues.push(...conditionIssues);
|
|
1605
|
+
return acc;
|
|
1606
|
+
}
|
|
1607
|
+
const shape = resolveFilterShape(child, schema);
|
|
1608
|
+
if (!shape) {
|
|
1609
|
+
return acc;
|
|
1610
|
+
}
|
|
1611
|
+
const columnDef = resolveColumnDefinition(child, schema);
|
|
1612
|
+
acc.fragments.push(buildConditionExpression(child, shape, columnDef));
|
|
1613
|
+
}
|
|
1614
|
+
return acc;
|
|
1615
|
+
},
|
|
1616
|
+
{ issues: depthIssues, fragments: [] }
|
|
1617
|
+
);
|
|
1618
|
+
}
|
|
1619
|
+
function compileCelFilterTree(tree, schema) {
|
|
1620
|
+
const { issues, fragments } = compileGroup(tree.root, schema);
|
|
1621
|
+
const status = statusFromIssues(issues);
|
|
1622
|
+
if (status === "valid") {
|
|
1623
|
+
return { status, expression: combineGroupFragments(fragments).expression, issues, isEmitReady: true };
|
|
1624
|
+
}
|
|
1625
|
+
return { status, issues, isEmitReady: false };
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
// src/lib/cel-filter/tree-utils.ts
|
|
1629
|
+
function createCelNodeId() {
|
|
1630
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
1631
|
+
return crypto.randomUUID();
|
|
1632
|
+
}
|
|
1633
|
+
return `cel-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
1634
|
+
}
|
|
1635
|
+
function createEmptyCelFilterTree() {
|
|
1636
|
+
return {
|
|
1637
|
+
root: {
|
|
1638
|
+
id: createCelNodeId(),
|
|
1639
|
+
type: "group",
|
|
1640
|
+
combinator: "and",
|
|
1641
|
+
depth: 0,
|
|
1642
|
+
children: []
|
|
1643
|
+
}
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
function createDefaultCondition({ schema, columnId }) {
|
|
1647
|
+
const columnDef = schema.columns.find((column) => column.id === columnId);
|
|
1648
|
+
if (!columnDef) {
|
|
1649
|
+
throw new Error(`createDefaultCondition: column "${columnId}" is not in schema.columns`);
|
|
1650
|
+
}
|
|
1651
|
+
return {
|
|
1652
|
+
id: createCelNodeId(),
|
|
1653
|
+
type: "condition",
|
|
1654
|
+
columnId,
|
|
1655
|
+
operator: getDefaultOperator(columnDef.filterType),
|
|
1656
|
+
value: columnDef.defaultValue
|
|
1657
|
+
};
|
|
1658
|
+
}
|
|
1659
|
+
function appendCondition(tree, condition) {
|
|
1660
|
+
return { root: __spreadProps(__spreadValues({}, tree.root), { children: [...tree.root.children, condition] }) };
|
|
1661
|
+
}
|
|
1662
|
+
function replaceCondition(tree, conditionId, updater) {
|
|
1663
|
+
return {
|
|
1664
|
+
root: __spreadProps(__spreadValues({}, tree.root), {
|
|
1665
|
+
children: tree.root.children.map(
|
|
1666
|
+
(child) => isCelFilterCondition(child) && child.id === conditionId ? updater(child) : child
|
|
1667
|
+
)
|
|
1668
|
+
})
|
|
1669
|
+
};
|
|
1670
|
+
}
|
|
1671
|
+
function removeConditionById(tree, conditionId) {
|
|
1672
|
+
return {
|
|
1673
|
+
root: __spreadProps(__spreadValues({}, tree.root), {
|
|
1674
|
+
children: tree.root.children.filter((child) => !(isCelFilterCondition(child) && child.id === conditionId))
|
|
1675
|
+
})
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
// src/cel-filter-bar/cel-filter-bar.tsx
|
|
1680
|
+
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1681
|
+
var RELATIVE_PRESET_LABELS = {
|
|
1682
|
+
"24h": "Last 24 hours",
|
|
1683
|
+
"168h": "Last 7 days",
|
|
1684
|
+
"720h": "Last 30 days"
|
|
1685
|
+
};
|
|
1686
|
+
var SEGMENT_SELECT_TRIGGER_CLASSNAME = "hover:border-input! focus-visible:border-input focus-visible:ring-0 hover:bg-muted focus-visible:bg-muted aria-expanded:bg-muted";
|
|
1687
|
+
function CelFilterBar({
|
|
1688
|
+
tree,
|
|
1689
|
+
onChange,
|
|
1690
|
+
schema,
|
|
1691
|
+
onCompileResultChange,
|
|
1692
|
+
onRestrictedOptionSelect,
|
|
1693
|
+
showClearButton = false,
|
|
1694
|
+
className
|
|
1695
|
+
}) {
|
|
1696
|
+
const editor = useCelFilterEditorState();
|
|
1697
|
+
const onCompileResultChangeRef = React3.useRef(onCompileResultChange);
|
|
1698
|
+
React3.useEffect(() => {
|
|
1699
|
+
onCompileResultChangeRef.current = onCompileResultChange;
|
|
1700
|
+
});
|
|
1701
|
+
const rawResult = React3.useMemo(() => compileCelFilterTree(tree, schema), [tree, schema]);
|
|
1702
|
+
const displayResult = React3.useMemo(
|
|
1703
|
+
() => applyDisplayRules(rawResult, {
|
|
1704
|
+
editingConditionId: editor.editingConditionId,
|
|
1705
|
+
committedConditionIds: editor.committedConditionIds
|
|
1706
|
+
}),
|
|
1707
|
+
[rawResult, editor.editingConditionId, editor.committedConditionIds]
|
|
1708
|
+
);
|
|
1709
|
+
const isEmitReady = React3.useMemo(
|
|
1710
|
+
() => computeIsEmitReady(rawResult, editor.editingConditionId, schema, tree, {
|
|
1711
|
+
activeSurface: editor.activeSurface,
|
|
1712
|
+
committedConditionIds: editor.committedConditionIds
|
|
1713
|
+
}),
|
|
1714
|
+
[rawResult, editor.editingConditionId, editor.activeSurface, editor.committedConditionIds, schema, tree]
|
|
1715
|
+
);
|
|
1716
|
+
React3.useEffect(() => {
|
|
1717
|
+
var _a;
|
|
1718
|
+
(_a = onCompileResultChangeRef.current) == null ? void 0 : _a.call(onCompileResultChangeRef, __spreadProps(__spreadValues({}, displayResult), { isEmitReady }));
|
|
1719
|
+
}, [displayResult, isEmitReady]);
|
|
1720
|
+
const conditions = tree.root.children.filter(isCelFilterCondition);
|
|
1721
|
+
function handleAddFilter(columnId) {
|
|
1722
|
+
const condition = createDefaultCondition({ schema, columnId });
|
|
1723
|
+
onChange(appendCondition(tree, condition));
|
|
1724
|
+
editor.beginEditing(condition.id);
|
|
1725
|
+
editor.suppressDismissFor(condition.id);
|
|
1726
|
+
}
|
|
1727
|
+
function handleRemove(conditionId) {
|
|
1728
|
+
onChange(removeConditionById(tree, conditionId));
|
|
1729
|
+
editor.removeCondition(conditionId);
|
|
1730
|
+
}
|
|
1731
|
+
function handleClearAll() {
|
|
1732
|
+
onChange({ root: __spreadProps(__spreadValues({}, tree.root), { children: [] }) });
|
|
1733
|
+
editor.clearSuppress();
|
|
1734
|
+
}
|
|
1735
|
+
return /* @__PURE__ */ jsxs4("div", { "data-slot": "cel-filter-bar", className: cn("flex flex-wrap items-center gap-2", className), children: [
|
|
1736
|
+
/* @__PURE__ */ jsx5(CelAddFilterButton, { schema, conditions, onSelect: handleAddFilter }),
|
|
1737
|
+
conditions.map((condition) => {
|
|
1738
|
+
const columnDef = resolveColumnDefinition(condition, schema);
|
|
1739
|
+
if (!columnDef) return null;
|
|
1740
|
+
return /* @__PURE__ */ jsx5(
|
|
1741
|
+
CelFilterPill,
|
|
1742
|
+
{
|
|
1743
|
+
condition,
|
|
1744
|
+
columnDef,
|
|
1745
|
+
schema,
|
|
1746
|
+
tree,
|
|
1747
|
+
onChange,
|
|
1748
|
+
controller: editor.getController(condition.id),
|
|
1749
|
+
issues: displayResult.issues.filter((issue) => issue.nodeId === condition.id),
|
|
1750
|
+
onRemove: () => handleRemove(condition.id),
|
|
1751
|
+
onRestrictedOptionSelect
|
|
1752
|
+
},
|
|
1753
|
+
condition.id
|
|
1754
|
+
);
|
|
1755
|
+
}),
|
|
1756
|
+
showClearButton && conditions.length > 0 && /* @__PURE__ */ jsx5(Button3, { variant: "ghost", size: "sm", onClick: handleClearAll, children: "Clear all" })
|
|
1757
|
+
] });
|
|
1758
|
+
}
|
|
1759
|
+
function CelAddFilterButton({
|
|
1760
|
+
schema,
|
|
1761
|
+
conditions,
|
|
1762
|
+
onSelect
|
|
1763
|
+
}) {
|
|
1764
|
+
var _a, _b;
|
|
1765
|
+
const usedSingleInstanceColumnIds = new Set(
|
|
1766
|
+
conditions.map((condition) => resolveColumnDefinition(condition, schema)).filter(
|
|
1767
|
+
(columnDef) => !!columnDef && !allowsMultipleConditions(columnDef.filterType)
|
|
1768
|
+
).map((columnDef) => columnDef.id)
|
|
1769
|
+
);
|
|
1770
|
+
const availableColumns = schema.columns.filter((column) => !usedSingleInstanceColumnIds.has(column.id));
|
|
1771
|
+
const groupMap = /* @__PURE__ */ new Map();
|
|
1772
|
+
for (const column of availableColumns) {
|
|
1773
|
+
const key = (_a = column.group) != null ? _a : "";
|
|
1774
|
+
const list = (_b = groupMap.get(key)) != null ? _b : [];
|
|
1775
|
+
list.push(column);
|
|
1776
|
+
groupMap.set(key, list);
|
|
1777
|
+
}
|
|
1778
|
+
const groups = Array.from(groupMap.entries()).map(([value, items]) => ({ value, items }));
|
|
1779
|
+
return /* @__PURE__ */ jsxs4(
|
|
1780
|
+
Combobox,
|
|
1781
|
+
{
|
|
1782
|
+
items: groups,
|
|
1783
|
+
itemToStringValue: (item) => item.title,
|
|
1784
|
+
itemToStringLabel: (item) => item.title,
|
|
1785
|
+
onValueChange: (column) => {
|
|
1786
|
+
if (column) onSelect(column.id);
|
|
1787
|
+
},
|
|
1788
|
+
children: [
|
|
1789
|
+
/* @__PURE__ */ jsxs4(ComboboxTrigger, { "aria-label": "Add filter", render: /* @__PURE__ */ jsx5(Button3, { variant: "outline" }), children: [
|
|
1790
|
+
/* @__PURE__ */ jsx5(Icon3, { name: "plus", "data-icon": "inline-start" }),
|
|
1791
|
+
"Add filter"
|
|
1792
|
+
] }),
|
|
1793
|
+
/* @__PURE__ */ jsxs4(ComboboxContent, { align: "start", className: "w-64", children: [
|
|
1794
|
+
/* @__PURE__ */ jsx5(ComboboxInput, { showTrigger: false, placeholder: "Search filters\u2026" }),
|
|
1795
|
+
/* @__PURE__ */ jsx5(ComboboxEmpty, { children: "No filters found." }),
|
|
1796
|
+
/* @__PURE__ */ jsx5(ComboboxList, { children: (group) => /* @__PURE__ */ jsxs4(ComboboxGroup, { items: group.items, children: [
|
|
1797
|
+
group.value && /* @__PURE__ */ jsx5(ComboboxLabel, { children: group.value }),
|
|
1798
|
+
/* @__PURE__ */ jsx5(ComboboxCollection, { children: (column) => /* @__PURE__ */ jsx5(ComboboxItem, { value: column, children: column.title }, column.id) })
|
|
1799
|
+
] }, group.value) })
|
|
1800
|
+
] })
|
|
1801
|
+
]
|
|
1802
|
+
}
|
|
1803
|
+
);
|
|
1804
|
+
}
|
|
1805
|
+
function formatConditionSummary(condition, columnDef, locale) {
|
|
1806
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1807
|
+
const shape = columnDef.filterType === "keyValue" ? "map" : columnDef.filterType;
|
|
1808
|
+
switch (shape) {
|
|
1809
|
+
case "checkbox": {
|
|
1810
|
+
const value = isCheckboxCelValue(condition.value) ? condition.value : [];
|
|
1811
|
+
if (value.length === 0) return "Any";
|
|
1812
|
+
if (value.length === 1) {
|
|
1813
|
+
return (_c = (_b = (_a = columnDef.options) == null ? void 0 : _a.find((opt) => opt.value === value[0])) == null ? void 0 : _b.label) != null ? _c : value[0];
|
|
1814
|
+
}
|
|
1815
|
+
return `${value.length} ${columnDef.pluralTitle}`;
|
|
1816
|
+
}
|
|
1817
|
+
case "radio":
|
|
1818
|
+
case "static": {
|
|
1819
|
+
const value = typeof condition.value === "string" ? condition.value : "";
|
|
1820
|
+
if (!value) return "Any";
|
|
1821
|
+
return (_f = (_e = (_d = columnDef.options) == null ? void 0 : _d.find((opt) => opt.value === value)) == null ? void 0 : _e.label) != null ? _f : value;
|
|
1822
|
+
}
|
|
1823
|
+
case "text":
|
|
1824
|
+
return typeof condition.value === "string" && condition.value ? condition.value : "Any";
|
|
1825
|
+
case "multiText": {
|
|
1826
|
+
const value = readMultiTextCelValue(condition.value);
|
|
1827
|
+
if (value.tokens.length === 0) return "Any";
|
|
1828
|
+
if (value.tokens.length === 1) return value.tokens[0];
|
|
1829
|
+
return `${value.tokens.length} values`;
|
|
1830
|
+
}
|
|
1831
|
+
case "date": {
|
|
1832
|
+
const value = readDateCelValue(condition.value);
|
|
1833
|
+
if (isRelativeDateCelValue(value)) return value.preset ? RELATIVE_PRESET_LABELS[value.preset] : "Any";
|
|
1834
|
+
if (value.range)
|
|
1835
|
+
return `${formatInstantLabel(value.range.start, { locale })} \u2013 ${formatInstantLabel(value.range.end, { locale })}`;
|
|
1836
|
+
if (value.instant) return formatInstantLabel(value.instant, { withTime: value.hasTime, locale });
|
|
1837
|
+
return "Any";
|
|
1838
|
+
}
|
|
1839
|
+
case "map": {
|
|
1840
|
+
const value = readMapKeyCelValue(condition.value);
|
|
1841
|
+
if (!value.key) return "Any";
|
|
1842
|
+
return value.value ? `${value.key}=${value.value}` : value.key;
|
|
1843
|
+
}
|
|
1844
|
+
default:
|
|
1845
|
+
return "Any";
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
function CelFilterPill({
|
|
1849
|
+
condition,
|
|
1850
|
+
columnDef,
|
|
1851
|
+
schema,
|
|
1852
|
+
tree,
|
|
1853
|
+
onChange,
|
|
1854
|
+
controller,
|
|
1855
|
+
issues,
|
|
1856
|
+
onRemove,
|
|
1857
|
+
onRestrictedOptionSelect
|
|
1858
|
+
}) {
|
|
1859
|
+
var _a;
|
|
1860
|
+
const shape = (_a = resolveFilterShape(condition, schema)) != null ? _a : columnDef.filterType;
|
|
1861
|
+
const mounted = useMounted();
|
|
1862
|
+
const locale = mounted ? void 0 : "en-US";
|
|
1863
|
+
if (shape === "checkbox") {
|
|
1864
|
+
return /* @__PURE__ */ jsx5(
|
|
1865
|
+
CelCheckboxComboboxPill,
|
|
1866
|
+
{
|
|
1867
|
+
condition,
|
|
1868
|
+
columnDef,
|
|
1869
|
+
tree,
|
|
1870
|
+
onChange,
|
|
1871
|
+
controller,
|
|
1872
|
+
issues,
|
|
1873
|
+
onRemove,
|
|
1874
|
+
onRestrictedOptionSelect
|
|
1875
|
+
}
|
|
1876
|
+
);
|
|
1877
|
+
}
|
|
1878
|
+
if (shape === "radio") {
|
|
1879
|
+
return /* @__PURE__ */ jsx5(
|
|
1880
|
+
CelRadioComboboxPill,
|
|
1881
|
+
{
|
|
1882
|
+
condition,
|
|
1883
|
+
columnDef,
|
|
1884
|
+
tree,
|
|
1885
|
+
onChange,
|
|
1886
|
+
controller,
|
|
1887
|
+
issues,
|
|
1888
|
+
onRemove,
|
|
1889
|
+
onRestrictedOptionSelect
|
|
1890
|
+
}
|
|
1891
|
+
);
|
|
1892
|
+
}
|
|
1893
|
+
function updateValue(value) {
|
|
1894
|
+
onChange(replaceCondition(tree, condition.id, (c) => __spreadProps(__spreadValues({}, c), { value })));
|
|
1895
|
+
}
|
|
1896
|
+
function updateOperator(operator) {
|
|
1897
|
+
const hadValue = condition.value !== void 0;
|
|
1898
|
+
const next = applyOperatorChange(condition, operator, shape);
|
|
1899
|
+
onChange(replaceCondition(tree, condition.id, () => next));
|
|
1900
|
+
if (hadValue && next.value === void 0) controller.beginEditing();
|
|
1901
|
+
}
|
|
1902
|
+
const allowedOperators = getAllowedOperators(columnDef);
|
|
1903
|
+
return /* @__PURE__ */ jsxs4(
|
|
1904
|
+
Popover,
|
|
1905
|
+
{
|
|
1906
|
+
open: controller.popoverVisible,
|
|
1907
|
+
onOpenChange: (open) => {
|
|
1908
|
+
if (open) controller.beginEditing();
|
|
1909
|
+
else if (!controller.isDismissSuppressed()) controller.handlePopoverDismiss();
|
|
1910
|
+
},
|
|
1911
|
+
children: [
|
|
1912
|
+
/* @__PURE__ */ jsxs4(ButtonGroup, { children: [
|
|
1913
|
+
/* @__PURE__ */ jsx5(ButtonGroupText, { children: columnDef.title }),
|
|
1914
|
+
/* @__PURE__ */ jsx5(
|
|
1915
|
+
CelOperatorSegment,
|
|
1916
|
+
{
|
|
1917
|
+
columnTitle: columnDef.title,
|
|
1918
|
+
operator: condition.operator,
|
|
1919
|
+
allowedOperators,
|
|
1920
|
+
hideOnSingleOperator: columnDef.hideOnSingleOperator,
|
|
1921
|
+
onChangeOperator: updateOperator
|
|
1922
|
+
}
|
|
1923
|
+
),
|
|
1924
|
+
shape === "multiText" && /* @__PURE__ */ jsx5(
|
|
1925
|
+
CelQuantifierSegment,
|
|
1926
|
+
{
|
|
1927
|
+
columnTitle: columnDef.title,
|
|
1928
|
+
value: readMultiTextCelValue(condition.value),
|
|
1929
|
+
onChangeValue: updateValue
|
|
1930
|
+
}
|
|
1931
|
+
),
|
|
1932
|
+
/* @__PURE__ */ jsx5(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs4(Button3, { variant: "outline", className: "gap-1 font-normal", children: [
|
|
1933
|
+
/* @__PURE__ */ jsx5("span", { className: cn(issues.length > 0 && "text-destructive"), children: formatConditionSummary(condition, columnDef, locale) }),
|
|
1934
|
+
/* @__PURE__ */ jsx5(Icon3, { name: "chevron-down", size: "sm", className: "text-muted-foreground" })
|
|
1935
|
+
] }) }),
|
|
1936
|
+
/* @__PURE__ */ jsx5(Button3, { variant: "outline", size: "icon", "aria-label": `Remove ${columnDef.title} filter`, onClick: onRemove, children: /* @__PURE__ */ jsx5(Icon3, { name: "xmark" }) })
|
|
1937
|
+
] }),
|
|
1938
|
+
/* @__PURE__ */ jsxs4(PopoverContent, { align: "start", className: shape === "date" ? "w-fit" : "w-72", children: [
|
|
1939
|
+
shape === "text" && /* @__PURE__ */ jsx5(CelTextValueEditor, { condition, onChangeValue: updateValue, onCommit: controller.commit }),
|
|
1940
|
+
shape === "multiText" && /* @__PURE__ */ jsx5(CelMultiTextValueEditor, { condition, onChangeValue: updateValue }),
|
|
1941
|
+
shape === "date" && /* @__PURE__ */ jsx5(CelDateValueEditor, { condition, onChangeValue: updateValue }),
|
|
1942
|
+
shape === "map" && /* @__PURE__ */ jsx5(CelKeyValueValueEditor, { condition, onChangeValue: updateValue, onCommit: controller.commit }),
|
|
1943
|
+
issues.length > 0 && /* @__PURE__ */ jsx5("p", { className: "text-body-sm text-destructive", children: issues.map((issue) => issue.message).join(" ") })
|
|
1944
|
+
] })
|
|
1945
|
+
]
|
|
1946
|
+
}
|
|
1947
|
+
);
|
|
1948
|
+
}
|
|
1949
|
+
function CelOperatorSegment({
|
|
1950
|
+
columnTitle,
|
|
1951
|
+
operator,
|
|
1952
|
+
allowedOperators,
|
|
1953
|
+
hideOnSingleOperator,
|
|
1954
|
+
onChangeOperator
|
|
1955
|
+
}) {
|
|
1956
|
+
if (allowedOperators.length > 1) {
|
|
1957
|
+
return /* @__PURE__ */ jsxs4(Select, { value: operator, onValueChange: (value) => onChangeOperator(value), children: [
|
|
1958
|
+
/* @__PURE__ */ jsx5(SelectTrigger, { "aria-label": `${columnTitle} operator`, className: SEGMENT_SELECT_TRIGGER_CLASSNAME, children: /* @__PURE__ */ jsx5(SelectValue, {}) }),
|
|
1959
|
+
/* @__PURE__ */ jsx5(SelectContent, { position: "popper", children: /* @__PURE__ */ jsx5(SelectGroup, { children: allowedOperators.map((op) => /* @__PURE__ */ jsx5(SelectItem, { value: op, children: getOperatorLabel(op) }, op)) }) })
|
|
1960
|
+
] });
|
|
1961
|
+
}
|
|
1962
|
+
if (allowedOperators.length === 1 && !hideOnSingleOperator) {
|
|
1963
|
+
return /* @__PURE__ */ jsx5(ButtonGroupText, { className: "text-muted-foreground font-normal", children: getOperatorLabel(allowedOperators[0]) });
|
|
1964
|
+
}
|
|
1965
|
+
return null;
|
|
1966
|
+
}
|
|
1967
|
+
function CelQuantifierSegment({
|
|
1968
|
+
columnTitle,
|
|
1969
|
+
value,
|
|
1970
|
+
onChangeValue
|
|
1971
|
+
}) {
|
|
1972
|
+
var _a;
|
|
1973
|
+
if (value.tokens.length <= 1) return null;
|
|
1974
|
+
return /* @__PURE__ */ jsxs4(
|
|
1975
|
+
Select,
|
|
1976
|
+
{
|
|
1977
|
+
value: (_a = value.quantifier) != null ? _a : "any",
|
|
1978
|
+
onValueChange: (next) => {
|
|
1979
|
+
if (next === "any" || next === "all") onChangeValue(__spreadProps(__spreadValues({}, value), { quantifier: next }));
|
|
1980
|
+
},
|
|
1981
|
+
children: [
|
|
1982
|
+
/* @__PURE__ */ jsx5(SelectTrigger, { "aria-label": `${columnTitle} quantifier`, className: SEGMENT_SELECT_TRIGGER_CLASSNAME, children: /* @__PURE__ */ jsx5(SelectValue, {}) }),
|
|
1983
|
+
/* @__PURE__ */ jsx5(SelectContent, { position: "popper", children: /* @__PURE__ */ jsxs4(SelectGroup, { children: [
|
|
1984
|
+
/* @__PURE__ */ jsx5(SelectItem, { value: "any", children: getQuantifierLabel("any") }),
|
|
1985
|
+
/* @__PURE__ */ jsx5(SelectItem, { value: "all", children: getQuantifierLabel("all") })
|
|
1986
|
+
] }) })
|
|
1987
|
+
]
|
|
1988
|
+
}
|
|
1989
|
+
);
|
|
1990
|
+
}
|
|
1991
|
+
function CelCheckboxComboboxPill({
|
|
1992
|
+
condition,
|
|
1993
|
+
columnDef,
|
|
1994
|
+
tree,
|
|
1995
|
+
onChange,
|
|
1996
|
+
controller,
|
|
1997
|
+
issues,
|
|
1998
|
+
onRemove,
|
|
1999
|
+
onRestrictedOptionSelect
|
|
2000
|
+
}) {
|
|
2001
|
+
var _a;
|
|
2002
|
+
const options = (_a = columnDef.options) != null ? _a : [];
|
|
2003
|
+
const value = isCheckboxCelValue(condition.value) ? condition.value : [];
|
|
2004
|
+
const selected = options.filter((option) => value.includes(option.value));
|
|
2005
|
+
const allowedOperators = getAllowedOperators(columnDef);
|
|
2006
|
+
function updateOperator(operator) {
|
|
2007
|
+
onChange(replaceCondition(tree, condition.id, (c) => applyOperatorChange(c, operator, "checkbox")));
|
|
2008
|
+
}
|
|
2009
|
+
function applySelection(nextSelected) {
|
|
2010
|
+
const current = new Set(value);
|
|
2011
|
+
const nextValues = new Set(nextSelected.map((option) => option.value));
|
|
2012
|
+
for (const option of nextSelected) {
|
|
2013
|
+
if (!current.has(option.value) && option.disabled) {
|
|
2014
|
+
onRestrictedOptionSelect == null ? void 0 : onRestrictedOptionSelect({ columnId: columnDef.id, value: option.value, label: option.label });
|
|
2015
|
+
nextValues.delete(option.value);
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
onChange(replaceCondition(tree, condition.id, (c) => __spreadProps(__spreadValues({}, c), { value: Array.from(nextValues) })));
|
|
2019
|
+
const added = nextSelected.find((option) => !current.has(option.value) && !option.disabled && option.operator);
|
|
2020
|
+
if (added == null ? void 0 : added.operator) updateOperator(added.operator);
|
|
2021
|
+
}
|
|
2022
|
+
return /* @__PURE__ */ jsxs4(
|
|
2023
|
+
Combobox,
|
|
2024
|
+
{
|
|
2025
|
+
items: options,
|
|
2026
|
+
itemToStringValue: (item) => item.label,
|
|
2027
|
+
multiple: true,
|
|
2028
|
+
value: selected,
|
|
2029
|
+
onValueChange: (next) => applySelection(next),
|
|
2030
|
+
open: controller.popoverVisible,
|
|
2031
|
+
onOpenChange: (open) => {
|
|
2032
|
+
if (open) controller.beginEditing();
|
|
2033
|
+
else if (!controller.isDismissSuppressed()) controller.handlePopoverDismiss();
|
|
2034
|
+
},
|
|
2035
|
+
children: [
|
|
2036
|
+
/* @__PURE__ */ jsxs4(ButtonGroup, { children: [
|
|
2037
|
+
/* @__PURE__ */ jsx5(ButtonGroupText, { children: columnDef.title }),
|
|
2038
|
+
/* @__PURE__ */ jsx5(
|
|
2039
|
+
CelOperatorSegment,
|
|
2040
|
+
{
|
|
2041
|
+
columnTitle: columnDef.title,
|
|
2042
|
+
operator: condition.operator,
|
|
2043
|
+
allowedOperators,
|
|
2044
|
+
hideOnSingleOperator: columnDef.hideOnSingleOperator,
|
|
2045
|
+
onChangeOperator: updateOperator
|
|
2046
|
+
}
|
|
2047
|
+
),
|
|
2048
|
+
/* @__PURE__ */ jsx5(
|
|
2049
|
+
ComboboxTrigger,
|
|
2050
|
+
{
|
|
2051
|
+
"aria-label": `${columnDef.title} value`,
|
|
2052
|
+
render: /* @__PURE__ */ jsx5(Button3, { variant: "outline", className: "gap-1 font-normal [&>svg:last-child]:size-(--icon-sm)" }),
|
|
2053
|
+
children: /* @__PURE__ */ jsx5("span", { className: cn(issues.length > 0 && "text-destructive"), children: formatConditionSummary(condition, columnDef) })
|
|
2054
|
+
}
|
|
2055
|
+
),
|
|
2056
|
+
/* @__PURE__ */ jsx5(Button3, { variant: "outline", size: "icon", "aria-label": `Remove ${columnDef.title} filter`, onClick: onRemove, children: /* @__PURE__ */ jsx5(Icon3, { name: "xmark" }) })
|
|
2057
|
+
] }),
|
|
2058
|
+
/* @__PURE__ */ jsxs4(ComboboxContent, { className: "min-w-64", collisionAvoidance: { side: "none", align: "shift" }, children: [
|
|
2059
|
+
/* @__PURE__ */ jsx5(ComboboxInput, { showTrigger: false, placeholder: `Search ${columnDef.title.toLowerCase()}\u2026` }),
|
|
2060
|
+
selected.length > 0 && /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
2061
|
+
/* @__PURE__ */ jsxs4(ComboboxSelectedChips, { children: [
|
|
2062
|
+
/* @__PURE__ */ jsx5(ComboboxValue, { children: (items) => /* @__PURE__ */ jsx5(Fragment3, { children: items.map((item) => /* @__PURE__ */ jsx5(ComboboxChip, { children: item.label }, item.value)) }) }),
|
|
2063
|
+
/* @__PURE__ */ jsx5(ComboboxClearAll, { onClick: () => applySelection([]) })
|
|
2064
|
+
] }),
|
|
2065
|
+
/* @__PURE__ */ jsx5(ComboboxSeparator, {})
|
|
2066
|
+
] }),
|
|
2067
|
+
/* @__PURE__ */ jsxs4(ComboboxEmpty, { children: [
|
|
2068
|
+
"No ",
|
|
2069
|
+
columnDef.title.toLowerCase(),
|
|
2070
|
+
" found."
|
|
2071
|
+
] }),
|
|
2072
|
+
/* @__PURE__ */ jsx5(ComboboxList, { children: (item) => /* @__PURE__ */ jsx5(ComboboxItem, { value: item, className: cn(item.disabled && "text-muted-foreground"), children: item.label }, item.value) }),
|
|
2073
|
+
issues.length > 0 && /* @__PURE__ */ jsx5("p", { className: "text-body-sm text-destructive", children: issues.map((issue) => issue.message).join(" ") })
|
|
2074
|
+
] })
|
|
2075
|
+
]
|
|
2076
|
+
}
|
|
2077
|
+
);
|
|
2078
|
+
}
|
|
2079
|
+
function CelRadioComboboxPill({
|
|
2080
|
+
condition,
|
|
2081
|
+
columnDef,
|
|
2082
|
+
tree,
|
|
2083
|
+
onChange,
|
|
2084
|
+
controller,
|
|
2085
|
+
issues,
|
|
2086
|
+
onRemove,
|
|
2087
|
+
onRestrictedOptionSelect
|
|
2088
|
+
}) {
|
|
2089
|
+
var _a, _b;
|
|
2090
|
+
const options = (_a = columnDef.options) != null ? _a : [];
|
|
2091
|
+
const value = typeof condition.value === "string" ? condition.value : "";
|
|
2092
|
+
const selected = (_b = options.find((option) => option.value === value)) != null ? _b : null;
|
|
2093
|
+
const allowedOperators = getAllowedOperators(columnDef);
|
|
2094
|
+
function updateOperator(operator) {
|
|
2095
|
+
onChange(replaceCondition(tree, condition.id, (c) => applyOperatorChange(c, operator, "radio")));
|
|
2096
|
+
}
|
|
2097
|
+
function applySelection(option) {
|
|
2098
|
+
if (!option) return;
|
|
2099
|
+
if (option.disabled) {
|
|
2100
|
+
onRestrictedOptionSelect == null ? void 0 : onRestrictedOptionSelect({ columnId: columnDef.id, value: option.value, label: option.label });
|
|
2101
|
+
return;
|
|
2102
|
+
}
|
|
2103
|
+
onChange(replaceCondition(tree, condition.id, (c) => __spreadProps(__spreadValues({}, c), { value: option.value })));
|
|
2104
|
+
if (option.operator) updateOperator(option.operator);
|
|
2105
|
+
controller.commit();
|
|
2106
|
+
}
|
|
2107
|
+
return /* @__PURE__ */ jsxs4(
|
|
2108
|
+
Combobox,
|
|
2109
|
+
{
|
|
2110
|
+
items: options,
|
|
2111
|
+
itemToStringValue: (item) => item.label,
|
|
2112
|
+
value: selected,
|
|
2113
|
+
onValueChange: (next) => applySelection(next),
|
|
2114
|
+
open: controller.popoverVisible,
|
|
2115
|
+
onOpenChange: (open) => {
|
|
2116
|
+
if (open) controller.beginEditing();
|
|
2117
|
+
else if (!controller.isDismissSuppressed()) controller.handlePopoverDismiss();
|
|
2118
|
+
},
|
|
2119
|
+
children: [
|
|
2120
|
+
/* @__PURE__ */ jsxs4(ButtonGroup, { children: [
|
|
2121
|
+
/* @__PURE__ */ jsx5(ButtonGroupText, { children: columnDef.title }),
|
|
2122
|
+
/* @__PURE__ */ jsx5(
|
|
2123
|
+
CelOperatorSegment,
|
|
2124
|
+
{
|
|
2125
|
+
columnTitle: columnDef.title,
|
|
2126
|
+
operator: condition.operator,
|
|
2127
|
+
allowedOperators,
|
|
2128
|
+
hideOnSingleOperator: columnDef.hideOnSingleOperator,
|
|
2129
|
+
onChangeOperator: updateOperator
|
|
2130
|
+
}
|
|
2131
|
+
),
|
|
2132
|
+
/* @__PURE__ */ jsx5(
|
|
2133
|
+
ComboboxTrigger,
|
|
2134
|
+
{
|
|
2135
|
+
"aria-label": `${columnDef.title} value`,
|
|
2136
|
+
render: /* @__PURE__ */ jsx5(Button3, { variant: "outline", className: "gap-1 font-normal [&>svg:last-child]:size-(--icon-sm)" }),
|
|
2137
|
+
children: /* @__PURE__ */ jsx5("span", { className: cn(issues.length > 0 && "text-destructive"), children: formatConditionSummary(condition, columnDef) })
|
|
2138
|
+
}
|
|
2139
|
+
),
|
|
2140
|
+
/* @__PURE__ */ jsx5(Button3, { variant: "outline", size: "icon", "aria-label": `Remove ${columnDef.title} filter`, onClick: onRemove, children: /* @__PURE__ */ jsx5(Icon3, { name: "xmark" }) })
|
|
2141
|
+
] }),
|
|
2142
|
+
/* @__PURE__ */ jsxs4(ComboboxContent, { className: "min-w-64", collisionAvoidance: { side: "none", align: "shift" }, children: [
|
|
2143
|
+
/* @__PURE__ */ jsx5(ComboboxInput, { showTrigger: false, placeholder: `Search ${columnDef.title.toLowerCase()}\u2026` }),
|
|
2144
|
+
/* @__PURE__ */ jsxs4(ComboboxEmpty, { children: [
|
|
2145
|
+
"No ",
|
|
2146
|
+
columnDef.title.toLowerCase(),
|
|
2147
|
+
" found."
|
|
2148
|
+
] }),
|
|
2149
|
+
/* @__PURE__ */ jsx5(ComboboxList, { children: (item) => /* @__PURE__ */ jsx5(ComboboxItem, { value: item, className: cn(item.disabled && "text-muted-foreground"), children: item.label }, item.value) }),
|
|
2150
|
+
issues.length > 0 && /* @__PURE__ */ jsx5("p", { className: "text-body-sm text-destructive", children: issues.map((issue) => issue.message).join(" ") })
|
|
2151
|
+
] })
|
|
2152
|
+
]
|
|
2153
|
+
}
|
|
2154
|
+
);
|
|
2155
|
+
}
|
|
2156
|
+
function CelTextValueEditor({
|
|
2157
|
+
condition,
|
|
2158
|
+
onChangeValue,
|
|
2159
|
+
onCommit
|
|
2160
|
+
}) {
|
|
2161
|
+
const value = typeof condition.value === "string" ? condition.value : "";
|
|
2162
|
+
return /* @__PURE__ */ jsx5(
|
|
2163
|
+
Input,
|
|
2164
|
+
{
|
|
2165
|
+
autoFocus: true,
|
|
2166
|
+
value,
|
|
2167
|
+
placeholder: "Enter a value\u2026",
|
|
2168
|
+
onChange: (e) => onChangeValue(e.target.value),
|
|
2169
|
+
onKeyDown: (e) => {
|
|
2170
|
+
if (e.key === "Enter") onCommit();
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
);
|
|
2174
|
+
}
|
|
2175
|
+
function CelMultiTextValueEditor({
|
|
2176
|
+
condition,
|
|
2177
|
+
onChangeValue
|
|
2178
|
+
}) {
|
|
2179
|
+
const value = readMultiTextCelValue(condition.value);
|
|
2180
|
+
const [draft, setDraft] = React3.useState("");
|
|
2181
|
+
function addToken() {
|
|
2182
|
+
var _a;
|
|
2183
|
+
const token = draft.trim();
|
|
2184
|
+
if (!token || value.tokens.includes(token)) {
|
|
2185
|
+
setDraft("");
|
|
2186
|
+
return;
|
|
2187
|
+
}
|
|
2188
|
+
const nextTokens = [...value.tokens, token];
|
|
2189
|
+
const quantifier = nextTokens.length > 1 ? (_a = value.quantifier) != null ? _a : "any" : value.quantifier;
|
|
2190
|
+
onChangeValue(__spreadProps(__spreadValues({}, value), { tokens: nextTokens, quantifier }));
|
|
2191
|
+
setDraft("");
|
|
2192
|
+
}
|
|
2193
|
+
function removeToken(token) {
|
|
2194
|
+
onChangeValue(__spreadProps(__spreadValues({}, value), { tokens: value.tokens.filter((t) => t !== token) }));
|
|
2195
|
+
}
|
|
2196
|
+
return /* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-2", children: [
|
|
2197
|
+
value.tokens.length > 0 && /* @__PURE__ */ jsx5("div", { className: "flex flex-wrap gap-1", children: value.tokens.map((token) => /* @__PURE__ */ jsxs4(Badge, { variant: "secondary", className: "gap-1", children: [
|
|
2198
|
+
token,
|
|
2199
|
+
/* @__PURE__ */ jsx5(
|
|
2200
|
+
"button",
|
|
2201
|
+
{
|
|
2202
|
+
type: "button",
|
|
2203
|
+
"aria-label": `Remove ${token}`,
|
|
2204
|
+
onClick: () => removeToken(token),
|
|
2205
|
+
className: "cursor-pointer",
|
|
2206
|
+
children: /* @__PURE__ */ jsx5(Icon3, { name: "xmark", size: "xs" })
|
|
2207
|
+
}
|
|
2208
|
+
)
|
|
2209
|
+
] }, token)) }),
|
|
2210
|
+
/* @__PURE__ */ jsx5(
|
|
2211
|
+
Input,
|
|
2212
|
+
{
|
|
2213
|
+
autoFocus: true,
|
|
2214
|
+
value: draft,
|
|
2215
|
+
placeholder: "Type a value, press Enter\u2026",
|
|
2216
|
+
onChange: (e) => setDraft(e.target.value),
|
|
2217
|
+
onKeyDown: (e) => {
|
|
2218
|
+
if (e.key === "Enter") {
|
|
2219
|
+
e.preventDefault();
|
|
2220
|
+
addToken();
|
|
2221
|
+
} else if (e.key === "Backspace" && draft === "" && value.tokens.length > 0) {
|
|
2222
|
+
removeToken(value.tokens[value.tokens.length - 1]);
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
)
|
|
2227
|
+
] });
|
|
2228
|
+
}
|
|
2229
|
+
function CelKeyValueValueEditor({
|
|
2230
|
+
condition,
|
|
2231
|
+
onChangeValue,
|
|
2232
|
+
onCommit
|
|
2233
|
+
}) {
|
|
2234
|
+
var _a;
|
|
2235
|
+
const value = readMapKeyCelValue(condition.value);
|
|
2236
|
+
const needsValue = condition.operator === "has_value" || condition.operator === "does_not_have_value";
|
|
2237
|
+
return /* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-2", children: [
|
|
2238
|
+
/* @__PURE__ */ jsxs4(InputGroup, { children: [
|
|
2239
|
+
/* @__PURE__ */ jsx5(InputGroupAddon, { children: /* @__PURE__ */ jsx5(InputGroupText, { children: "Key" }) }),
|
|
2240
|
+
/* @__PURE__ */ jsx5(
|
|
2241
|
+
InputGroupInput,
|
|
2242
|
+
{
|
|
2243
|
+
autoFocus: true,
|
|
2244
|
+
value: value.key,
|
|
2245
|
+
onChange: (e) => onChangeValue(__spreadProps(__spreadValues({}, value), { key: e.target.value })),
|
|
2246
|
+
onKeyDown: (e) => {
|
|
2247
|
+
if (e.key === "Enter" && !needsValue) onCommit();
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
)
|
|
2251
|
+
] }),
|
|
2252
|
+
needsValue && /* @__PURE__ */ jsxs4(InputGroup, { children: [
|
|
2253
|
+
/* @__PURE__ */ jsx5(InputGroupAddon, { children: /* @__PURE__ */ jsx5(InputGroupText, { children: "Value" }) }),
|
|
2254
|
+
/* @__PURE__ */ jsx5(
|
|
2255
|
+
InputGroupInput,
|
|
2256
|
+
{
|
|
2257
|
+
value: (_a = value.value) != null ? _a : "",
|
|
2258
|
+
onChange: (e) => onChangeValue(__spreadProps(__spreadValues({}, value), { value: e.target.value })),
|
|
2259
|
+
onKeyDown: (e) => {
|
|
2260
|
+
if (e.key === "Enter") onCommit();
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
)
|
|
2264
|
+
] })
|
|
2265
|
+
] });
|
|
2266
|
+
}
|
|
2267
|
+
function CelDateValueEditor({
|
|
2268
|
+
condition,
|
|
2269
|
+
onChangeValue
|
|
2270
|
+
}) {
|
|
2271
|
+
const value = readDateCelValue(condition.value);
|
|
2272
|
+
const operator = condition.operator;
|
|
2273
|
+
const relativeCapable = isDateRelativeOperator(operator);
|
|
2274
|
+
const isRange = isDateRangeOperator(operator);
|
|
2275
|
+
const showTime = !isDateWindowOperator(operator) && !isRange;
|
|
2276
|
+
const isRelative = isRelativeDateCelValue(value);
|
|
2277
|
+
function pickInstant(date) {
|
|
2278
|
+
if (!date) return;
|
|
2279
|
+
const boundary = dateBoundaryForOperator(operator);
|
|
2280
|
+
const instant = formatCalendarDateUtc(date, showTime ? boundary : "start");
|
|
2281
|
+
onChangeValue({ instant });
|
|
2282
|
+
}
|
|
2283
|
+
function pickRange(range) {
|
|
2284
|
+
if (!(range == null ? void 0 : range.from)) return;
|
|
2285
|
+
const start = calendarDayStartInstant(formatCalendarDateUtc(range.from, "start"));
|
|
2286
|
+
const end = range.to ? formatCalendarDateUtc(range.to, "end") : formatCalendarDateUtc(range.from, "end");
|
|
2287
|
+
onChangeValue({ range: { start, end } });
|
|
2288
|
+
}
|
|
2289
|
+
function pickTime(timeOfDay) {
|
|
2290
|
+
if (!value.instant) return;
|
|
2291
|
+
onChangeValue({ instant: withTimeOfDay(value.instant, timeOfDay), hasTime: true });
|
|
2292
|
+
}
|
|
2293
|
+
return /* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-2", children: [
|
|
2294
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex", children: [
|
|
2295
|
+
relativeCapable && /* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-1 border-r pr-2", children: [
|
|
2296
|
+
/* @__PURE__ */ jsx5("p", { className: "text-body-sm text-muted-foreground px-2 font-medium", children: "Quick select" }),
|
|
2297
|
+
RELATIVE_DURATION_PRESET_VALUES.map((preset) => /* @__PURE__ */ jsx5(
|
|
2298
|
+
Button3,
|
|
2299
|
+
{
|
|
2300
|
+
type: "button",
|
|
2301
|
+
variant: isRelative && value.preset === preset ? "secondary" : "ghost",
|
|
2302
|
+
size: "sm",
|
|
2303
|
+
className: "justify-start",
|
|
2304
|
+
onClick: () => onChangeValue({ preset }),
|
|
2305
|
+
children: RELATIVE_PRESET_LABELS[preset]
|
|
2306
|
+
},
|
|
2307
|
+
preset
|
|
2308
|
+
))
|
|
2309
|
+
] }),
|
|
2310
|
+
isRange ? /* @__PURE__ */ jsx5(
|
|
2311
|
+
Calendar,
|
|
2312
|
+
{
|
|
2313
|
+
mode: "range",
|
|
2314
|
+
selected: value.range ? { from: parseCalendarDate(value.range.start), to: parseCalendarDate(value.range.end) } : void 0,
|
|
2315
|
+
onSelect: pickRange
|
|
2316
|
+
}
|
|
2317
|
+
) : /* @__PURE__ */ jsx5(
|
|
2318
|
+
Calendar,
|
|
2319
|
+
{
|
|
2320
|
+
mode: "single",
|
|
2321
|
+
selected: isRelative ? void 0 : parseCalendarDate(value.instant),
|
|
2322
|
+
onSelect: pickInstant
|
|
2323
|
+
}
|
|
2324
|
+
)
|
|
2325
|
+
] }),
|
|
2326
|
+
showTime && !isRelative && /* @__PURE__ */ jsxs4("div", { className: "flex w-full items-center gap-2", children: [
|
|
2327
|
+
/* @__PURE__ */ jsx5(Label, { htmlFor: "cel-date-time", className: "text-body-sm text-muted-foreground shrink-0", children: "Time (UTC)" }),
|
|
2328
|
+
/* @__PURE__ */ jsx5(
|
|
2329
|
+
Input,
|
|
2330
|
+
{
|
|
2331
|
+
id: "cel-date-time",
|
|
2332
|
+
type: "time",
|
|
2333
|
+
className: "w-full",
|
|
2334
|
+
value: readTimeOfDay(value.instant),
|
|
2335
|
+
onChange: (e) => pickTime(e.target.value),
|
|
2336
|
+
disabled: !value.instant
|
|
2337
|
+
}
|
|
2338
|
+
)
|
|
2339
|
+
] })
|
|
2340
|
+
] });
|
|
2341
|
+
}
|
|
2342
|
+
|
|
2343
|
+
// src/data-table/data-table.tsx
|
|
2344
|
+
import { Icon as Icon8 } from "@upbound/monarch-core";
|
|
2345
|
+
import { InputGroup as InputGroup2, InputGroupAddon as InputGroupAddon2, InputGroupInput as InputGroupInput2 } from "@upbound/monarch-core";
|
|
2346
|
+
|
|
2347
|
+
// src/lib/data-table/contextual-filters.ts
|
|
2348
|
+
function valueToString(value) {
|
|
2349
|
+
if (value === void 0 || value === null) return void 0;
|
|
2350
|
+
const normalized = String(value).trim();
|
|
2351
|
+
return normalized || void 0;
|
|
2352
|
+
}
|
|
2353
|
+
function stringArrayFromValue(value) {
|
|
2354
|
+
if (Array.isArray(value)) {
|
|
2355
|
+
return value.map(valueToString).filter((v) => !!v);
|
|
2356
|
+
}
|
|
2357
|
+
const normalized = valueToString(value);
|
|
2358
|
+
return normalized ? [normalized] : [];
|
|
2359
|
+
}
|
|
2360
|
+
function columnFilterValueToStrings(value) {
|
|
2361
|
+
if (Array.isArray(value)) {
|
|
2362
|
+
return value.map((item) => String(item).trim()).filter(Boolean);
|
|
2363
|
+
}
|
|
2364
|
+
const normalized = String(value != null ? value : "").trim();
|
|
2365
|
+
return normalized ? [normalized] : [];
|
|
2366
|
+
}
|
|
2367
|
+
function hasContextualFilterValue(value) {
|
|
2368
|
+
var _a;
|
|
2369
|
+
if (value === void 0) return false;
|
|
2370
|
+
if (typeof value === "string") return value.trim() !== "";
|
|
2371
|
+
if (Array.isArray(value)) {
|
|
2372
|
+
return value.filter((item) => typeof item === "string" && item.trim() !== "").length > 0;
|
|
2373
|
+
}
|
|
2374
|
+
return !!((_a = value.startDate) != null ? _a : value.endDate);
|
|
2375
|
+
}
|
|
2376
|
+
function getDefaultContextualFilterValue(cell, filter) {
|
|
2377
|
+
const value = cell.getValue();
|
|
2378
|
+
if (filter.type === "checkbox" || filter.type === "scrollableCheckbox" || filter.type === "multiText") {
|
|
2379
|
+
const values = stringArrayFromValue(value);
|
|
2380
|
+
return values.length > 0 ? values : void 0;
|
|
2381
|
+
}
|
|
2382
|
+
if (filter.type === "radio" || filter.type === "scrollableRadio" || filter.type === "text") {
|
|
2383
|
+
return valueToString(value);
|
|
2384
|
+
}
|
|
2385
|
+
return void 0;
|
|
2386
|
+
}
|
|
2387
|
+
function getContextualColumnFilter(cell) {
|
|
2388
|
+
const meta = cell.column.columnDef.meta;
|
|
2389
|
+
const filter = meta == null ? void 0 : meta.filter;
|
|
2390
|
+
if (!filter) return void 0;
|
|
2391
|
+
const value = (meta == null ? void 0 : meta.contextualFilterValue) ? meta.contextualFilterValue(cell) : getDefaultContextualFilterValue(cell, filter);
|
|
2392
|
+
if (!hasContextualFilterValue(value)) return void 0;
|
|
2393
|
+
return { id: cell.column.id, value };
|
|
2394
|
+
}
|
|
2395
|
+
function getContextualGlobalSearch(cell) {
|
|
2396
|
+
var _a;
|
|
2397
|
+
const globalSearchValue = (_a = cell.column.columnDef.meta) == null ? void 0 : _a.contextualGlobalSearchValue;
|
|
2398
|
+
if (!globalSearchValue) return void 0;
|
|
2399
|
+
return valueToString(globalSearchValue(cell));
|
|
2400
|
+
}
|
|
2401
|
+
function mergeColumnFilter(columnFilters, nextFilter, filterDefinition) {
|
|
2402
|
+
const shouldMergeArrayValue = (filterDefinition == null ? void 0 : filterDefinition.type) === "checkbox" || (filterDefinition == null ? void 0 : filterDefinition.type) === "scrollableCheckbox" || (filterDefinition == null ? void 0 : filterDefinition.type) === "multiText";
|
|
2403
|
+
if (!shouldMergeArrayValue) {
|
|
2404
|
+
return [...columnFilters.filter((filter) => filter.id !== nextFilter.id), nextFilter];
|
|
2405
|
+
}
|
|
2406
|
+
const nextValues = stringArrayFromValue(nextFilter.value);
|
|
2407
|
+
if (nextValues.length === 0) return columnFilters;
|
|
2408
|
+
const existingFilter = columnFilters.find((filter) => filter.id === nextFilter.id);
|
|
2409
|
+
const existingValues = stringArrayFromValue(existingFilter == null ? void 0 : existingFilter.value);
|
|
2410
|
+
const mergedValues = Array.from(/* @__PURE__ */ new Set([...existingValues, ...nextValues]));
|
|
2411
|
+
if (existingFilter && mergedValues.length === existingValues.length) return columnFilters;
|
|
2412
|
+
return [...columnFilters.filter((filter) => filter.id !== nextFilter.id), { id: nextFilter.id, value: mergedValues }];
|
|
2413
|
+
}
|
|
2414
|
+
function getColumnFilterCount(filterValue, filter) {
|
|
2415
|
+
const isCheckboxValue = (value) => value === void 0 || Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
2416
|
+
const isRadioValue = (value) => value === void 0 || typeof value === "string";
|
|
2417
|
+
const isDateRangeValue = (value) => value === void 0 || typeof value === "object" && value !== null && "startDate" in value && "endDate" in value;
|
|
2418
|
+
if ((filter == null ? void 0 : filter.type) === "checkbox" || (filter == null ? void 0 : filter.type) === "scrollableCheckbox") {
|
|
2419
|
+
return isCheckboxValue(filterValue) ? (filterValue || []).length : 0;
|
|
2420
|
+
}
|
|
2421
|
+
if ((filter == null ? void 0 : filter.type) === "radio" || (filter == null ? void 0 : filter.type) === "scrollableRadio") {
|
|
2422
|
+
return isRadioValue(filterValue) && filterValue !== void 0 ? 1 : 0;
|
|
2423
|
+
}
|
|
2424
|
+
if ((filter == null ? void 0 : filter.type) === "dateRange") {
|
|
2425
|
+
if (!isDateRangeValue(filterValue)) return 0;
|
|
2426
|
+
return Number(!!(filterValue == null ? void 0 : filterValue.startDate)) + Number(!!(filterValue == null ? void 0 : filterValue.endDate));
|
|
2427
|
+
}
|
|
2428
|
+
if (isCheckboxValue(filterValue)) {
|
|
2429
|
+
return (filterValue || []).length;
|
|
2430
|
+
}
|
|
2431
|
+
if (isRadioValue(filterValue) && filterValue !== void 0) {
|
|
2432
|
+
return 1;
|
|
2433
|
+
}
|
|
2434
|
+
if (isDateRangeValue(filterValue)) {
|
|
2435
|
+
return Number(!!(filterValue == null ? void 0 : filterValue.startDate)) + Number(!!(filterValue == null ? void 0 : filterValue.endDate));
|
|
2436
|
+
}
|
|
2437
|
+
return 0;
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2440
|
+
// src/hooks/use-table-column-resizing.ts
|
|
2441
|
+
import { useCallback as useCallback4, useEffect as useEffect3, useRef as useRef3, useState as useState5 } from "react";
|
|
2442
|
+
var RESIZE_MIN = 40;
|
|
2443
|
+
var RESIZE_MAX = 500;
|
|
2444
|
+
var RESIZE_MAX_UNBOUNDED = Number.MAX_SAFE_INTEGER;
|
|
2445
|
+
var DEFAULT_COLUMN_SIZE = 150;
|
|
2446
|
+
var FIT_CONTENT_PLACEHOLDER_SIZE = 400;
|
|
2447
|
+
var PERSIST_DEBOUNCE_MS = 300;
|
|
2448
|
+
var MIN_FR_VALUE = 0.01;
|
|
2449
|
+
function clampSizing(sizing, maxSize = RESIZE_MAX) {
|
|
2450
|
+
return Object.entries(sizing).reduce(
|
|
2451
|
+
(acc, [colId, size]) => __spreadProps(__spreadValues({}, acc), { [colId]: Math.min(maxSize, Math.max(RESIZE_MIN, size)) }),
|
|
2452
|
+
{}
|
|
2453
|
+
);
|
|
2454
|
+
}
|
|
2455
|
+
function computeGridResizeFrValues({
|
|
2456
|
+
resizingColumnId,
|
|
2457
|
+
deltaOffset,
|
|
2458
|
+
visualOrder,
|
|
2459
|
+
snapshotWidths,
|
|
2460
|
+
snapshotMeta
|
|
2461
|
+
}) {
|
|
2462
|
+
var _a, _b, _c, _d;
|
|
2463
|
+
if (!resizingColumnId || deltaOffset == null || snapshotMeta.containerWidth <= 0) {
|
|
2464
|
+
return {};
|
|
2465
|
+
}
|
|
2466
|
+
const { fixedTotal, flexIds, mins, containerWidth } = snapshotMeta;
|
|
2467
|
+
const snapshotPx = snapshotWidths[resizingColumnId];
|
|
2468
|
+
if (!snapshotPx || !flexIds.includes(resizingColumnId)) {
|
|
2469
|
+
return {};
|
|
2470
|
+
}
|
|
2471
|
+
const desiredPx = Math.max((_a = mins[resizingColumnId]) != null ? _a : 0, snapshotPx + deltaOffset);
|
|
2472
|
+
const resizeIdx = visualOrder.indexOf(resizingColumnId);
|
|
2473
|
+
const otherFlexIds = flexIds.filter((colId) => colId !== resizingColumnId);
|
|
2474
|
+
const rightFlexIds = otherFlexIds.filter((colId) => visualOrder.indexOf(colId) > resizeIdx);
|
|
2475
|
+
const leftFlexIds = otherFlexIds.filter((colId) => visualOrder.indexOf(colId) < resizeIdx);
|
|
2476
|
+
const absorbingIds = rightFlexIds.length > 0 ? rightFlexIds : leftFlexIds;
|
|
2477
|
+
const frozenIds = rightFlexIds.length > 0 ? leftFlexIds : rightFlexIds;
|
|
2478
|
+
const nextFr = {};
|
|
2479
|
+
for (const colId of frozenIds) {
|
|
2480
|
+
nextFr[colId] = (_b = snapshotWidths[colId]) != null ? _b : MIN_FR_VALUE;
|
|
2481
|
+
}
|
|
2482
|
+
const frozenTotal = frozenIds.reduce((sum, colId) => {
|
|
2483
|
+
var _a2;
|
|
2484
|
+
return sum + ((_a2 = snapshotWidths[colId]) != null ? _a2 : 0);
|
|
2485
|
+
}, 0);
|
|
2486
|
+
const availableForAbsorbing = containerWidth - fixedTotal - desiredPx - frozenTotal;
|
|
2487
|
+
const absorbingSnapshotTotal = absorbingIds.reduce((sum, colId) => {
|
|
2488
|
+
var _a2;
|
|
2489
|
+
return sum + ((_a2 = snapshotWidths[colId]) != null ? _a2 : 0);
|
|
2490
|
+
}, 0);
|
|
2491
|
+
for (const colId of absorbingIds) {
|
|
2492
|
+
const snap = (_c = snapshotWidths[colId]) != null ? _c : 0;
|
|
2493
|
+
const share = absorbingSnapshotTotal > 0 ? snap / absorbingSnapshotTotal : 1 / absorbingIds.length;
|
|
2494
|
+
const targetPx = Math.max((_d = mins[colId]) != null ? _d : 0, availableForAbsorbing * share);
|
|
2495
|
+
nextFr[colId] = Math.max(MIN_FR_VALUE, targetPx);
|
|
2496
|
+
}
|
|
2497
|
+
nextFr[resizingColumnId] = Math.max(MIN_FR_VALUE, desiredPx);
|
|
2498
|
+
return nextFr;
|
|
2499
|
+
}
|
|
2500
|
+
function resolveGridPersistedFr({
|
|
2501
|
+
visualOrder,
|
|
2502
|
+
persistedFr,
|
|
2503
|
+
columnSizing,
|
|
2504
|
+
measuredMins,
|
|
2505
|
+
getGridSizing
|
|
2506
|
+
}) {
|
|
2507
|
+
var _a;
|
|
2508
|
+
const nextFr = __spreadValues({}, persistedFr);
|
|
2509
|
+
for (const colId of visualOrder) {
|
|
2510
|
+
const grid = getGridSizing(colId);
|
|
2511
|
+
if (!grid || grid.flex == null) continue;
|
|
2512
|
+
if (!nextFr[colId] && columnSizing[colId]) {
|
|
2513
|
+
nextFr[colId] = columnSizing[colId];
|
|
2514
|
+
}
|
|
2515
|
+
if (nextFr[colId]) {
|
|
2516
|
+
const minPx = (_a = measuredMins[colId]) != null ? _a : grid.min ? parseFloat(grid.min) || 0 : 0;
|
|
2517
|
+
const maxPx = grid.max ? parseFloat(grid.max) || Infinity : Infinity;
|
|
2518
|
+
nextFr[colId] = Math.max(minPx, Math.min(maxPx, nextFr[colId]));
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
return nextFr;
|
|
2522
|
+
}
|
|
2523
|
+
function useTableColumnResizing({
|
|
2524
|
+
initialSizing,
|
|
2525
|
+
onColumnSizingPersist,
|
|
2526
|
+
maxSize
|
|
2527
|
+
} = {}) {
|
|
2528
|
+
const [columnSizing, setColumnSizing] = useState5(() => clampSizing(initialSizing != null ? initialSizing : {}, maxSize));
|
|
2529
|
+
const persistTimerRef = useRef3(null);
|
|
2530
|
+
useEffect3(() => {
|
|
2531
|
+
if (!initialSizing) return;
|
|
2532
|
+
const next = clampSizing(initialSizing, maxSize);
|
|
2533
|
+
setColumnSizing((prev) => {
|
|
2534
|
+
const keys = Object.keys(next);
|
|
2535
|
+
if (Object.keys(prev).length !== keys.length) return next;
|
|
2536
|
+
return keys.every((k) => prev[k] === next[k]) ? prev : next;
|
|
2537
|
+
});
|
|
2538
|
+
}, [initialSizing, maxSize]);
|
|
2539
|
+
useEffect3(() => {
|
|
2540
|
+
return () => {
|
|
2541
|
+
if (persistTimerRef.current) clearTimeout(persistTimerRef.current);
|
|
2542
|
+
};
|
|
2543
|
+
}, []);
|
|
2544
|
+
const debouncedPersist = useCallback4(
|
|
2545
|
+
(sizing) => {
|
|
2546
|
+
if (persistTimerRef.current) clearTimeout(persistTimerRef.current);
|
|
2547
|
+
persistTimerRef.current = setTimeout(() => onColumnSizingPersist == null ? void 0 : onColumnSizingPersist(sizing), PERSIST_DEBOUNCE_MS);
|
|
2548
|
+
},
|
|
2549
|
+
[onColumnSizingPersist]
|
|
2550
|
+
);
|
|
2551
|
+
const handleColumnSizingChange = useCallback4(
|
|
2552
|
+
(updaterOrValue) => {
|
|
2553
|
+
setColumnSizing((prev) => {
|
|
2554
|
+
const raw = typeof updaterOrValue === "function" ? updaterOrValue(prev) : updaterOrValue;
|
|
2555
|
+
const next = clampSizing(raw, maxSize);
|
|
2556
|
+
debouncedPersist(next);
|
|
2557
|
+
return next;
|
|
2558
|
+
});
|
|
2559
|
+
},
|
|
2560
|
+
[debouncedPersist, maxSize]
|
|
2561
|
+
);
|
|
2562
|
+
const cancelPendingPersist = useCallback4(() => {
|
|
2563
|
+
if (persistTimerRef.current) {
|
|
2564
|
+
clearTimeout(persistTimerRef.current);
|
|
2565
|
+
persistTimerRef.current = null;
|
|
2566
|
+
}
|
|
2567
|
+
}, []);
|
|
2568
|
+
const handleAutosizeAll = useCallback4(() => {
|
|
2569
|
+
cancelPendingPersist();
|
|
2570
|
+
setColumnSizing({});
|
|
2571
|
+
onColumnSizingPersist == null ? void 0 : onColumnSizingPersist({});
|
|
2572
|
+
}, [cancelPendingPersist, onColumnSizingPersist]);
|
|
2573
|
+
const handleAutosizeColumn = useCallback4(
|
|
2574
|
+
(columnId) => {
|
|
2575
|
+
cancelPendingPersist();
|
|
2576
|
+
setColumnSizing((prev) => {
|
|
2577
|
+
var _a;
|
|
2578
|
+
const current = (_a = prev[columnId]) != null ? _a : DEFAULT_COLUMN_SIZE;
|
|
2579
|
+
const next = __spreadValues({}, prev);
|
|
2580
|
+
next[columnId] = current <= DEFAULT_COLUMN_SIZE ? FIT_CONTENT_PLACEHOLDER_SIZE : DEFAULT_COLUMN_SIZE;
|
|
2581
|
+
onColumnSizingPersist == null ? void 0 : onColumnSizingPersist(next);
|
|
2582
|
+
return next;
|
|
2583
|
+
});
|
|
2584
|
+
},
|
|
2585
|
+
[cancelPendingPersist, onColumnSizingPersist]
|
|
2586
|
+
);
|
|
2587
|
+
const handleResetColumnSize = useCallback4(
|
|
2588
|
+
(columnId) => {
|
|
2589
|
+
cancelPendingPersist();
|
|
2590
|
+
setColumnSizing((prev) => {
|
|
2591
|
+
const next = __spreadValues({}, prev);
|
|
2592
|
+
delete next[columnId];
|
|
2593
|
+
onColumnSizingPersist == null ? void 0 : onColumnSizingPersist(next);
|
|
2594
|
+
return next;
|
|
2595
|
+
});
|
|
2596
|
+
},
|
|
2597
|
+
[cancelPendingPersist, onColumnSizingPersist]
|
|
2598
|
+
);
|
|
2599
|
+
return { columnSizing, handleColumnSizingChange, handleAutosizeAll, handleAutosizeColumn, handleResetColumnSize };
|
|
2600
|
+
}
|
|
2601
|
+
|
|
2602
|
+
// src/hooks/use-grid-layout.ts
|
|
2603
|
+
import * as React4 from "react";
|
|
2604
|
+
|
|
2605
|
+
// src/lib/data-table/grid-layout.ts
|
|
2606
|
+
function computeGridResizeSnapshot({
|
|
2607
|
+
headers,
|
|
2608
|
+
visualOrder,
|
|
2609
|
+
getColumnGrid
|
|
2610
|
+
}) {
|
|
2611
|
+
let fixedTotal = 0;
|
|
2612
|
+
const flexIds = [];
|
|
2613
|
+
const mins = {};
|
|
2614
|
+
const widths = {};
|
|
2615
|
+
const needsMaxContentMeasure = [];
|
|
2616
|
+
Array.from(headers).forEach((header, idx) => {
|
|
2617
|
+
const columnId = visualOrder[idx];
|
|
2618
|
+
if (!columnId) return;
|
|
2619
|
+
const px = header.getBoundingClientRect().width;
|
|
2620
|
+
widths[columnId] = px;
|
|
2621
|
+
const grid = getColumnGrid(columnId);
|
|
2622
|
+
if (grid && "flex" in grid && grid.flex != null) {
|
|
2623
|
+
flexIds.push(columnId);
|
|
2624
|
+
const minVal = grid.min;
|
|
2625
|
+
if (minVal && minVal !== "max-content" && minVal !== "min-content") {
|
|
2626
|
+
mins[columnId] = parseFloat(minVal) || 0;
|
|
2627
|
+
} else if (minVal === "max-content" || minVal === "min-content") {
|
|
2628
|
+
needsMaxContentMeasure.push(columnId);
|
|
2629
|
+
}
|
|
2630
|
+
} else {
|
|
2631
|
+
fixedTotal += px;
|
|
2632
|
+
}
|
|
2633
|
+
});
|
|
2634
|
+
return { widths, fixedTotal, flexIds, mins, needsMaxContentMeasure };
|
|
2635
|
+
}
|
|
2636
|
+
function measureMaxContentMins(tableEl, headers, visualOrder, columnsToMeasure, getColumnGrid) {
|
|
2637
|
+
const mins = {};
|
|
2638
|
+
if (columnsToMeasure.length === 0) return mins;
|
|
2639
|
+
const origTemplate = tableEl.style.gridTemplateColumns;
|
|
2640
|
+
tableEl.style.gridTemplateColumns = visualOrder.map(() => "max-content").join(" ");
|
|
2641
|
+
Array.from(headers).forEach((header, idx) => {
|
|
2642
|
+
const colId = visualOrder[idx];
|
|
2643
|
+
if (colId && columnsToMeasure.includes(colId)) {
|
|
2644
|
+
let measured = header.getBoundingClientRect().width;
|
|
2645
|
+
const grid = getColumnGrid(colId);
|
|
2646
|
+
if (grid && "minCap" in grid && grid.minCap) {
|
|
2647
|
+
measured = Math.min(measured, parseFloat(grid.minCap) || measured);
|
|
2648
|
+
}
|
|
2649
|
+
mins[colId] = measured;
|
|
2650
|
+
}
|
|
2651
|
+
});
|
|
2652
|
+
tableEl.style.gridTemplateColumns = origTemplate;
|
|
2653
|
+
return mins;
|
|
2654
|
+
}
|
|
2655
|
+
function getGridColumnTemplate({ headers, gridMeasuredMins }) {
|
|
2656
|
+
return headers.map((h) => {
|
|
2657
|
+
var _a, _b;
|
|
2658
|
+
const { grid } = h;
|
|
2659
|
+
if (!grid) return `${h.size}px`;
|
|
2660
|
+
if ("fixed" in grid && grid.fixed) return grid.fixed;
|
|
2661
|
+
if ("flex" in grid && grid.flex != null) {
|
|
2662
|
+
const varName = `--col-fr-${h.columnId}`;
|
|
2663
|
+
const measuredMin = gridMeasuredMins[h.columnId];
|
|
2664
|
+
const min = measuredMin != null ? `${measuredMin}px` : (_a = grid.min) != null ? _a : "auto";
|
|
2665
|
+
const max = (_b = grid.max) != null ? _b : `var(${varName}, ${grid.flex}fr)`;
|
|
2666
|
+
return `minmax(${min}, ${max})`;
|
|
2667
|
+
}
|
|
2668
|
+
return `${h.size}px`;
|
|
2669
|
+
}).join(" ");
|
|
2670
|
+
}
|
|
2671
|
+
function findContentMinColumns(visualOrder, getColumnGrid) {
|
|
2672
|
+
return visualOrder.filter((colId) => {
|
|
2673
|
+
const grid = getColumnGrid(colId);
|
|
2674
|
+
return grid && "flex" in grid && grid.flex != null && (grid.min === "max-content" || grid.min === "min-content");
|
|
2675
|
+
});
|
|
2676
|
+
}
|
|
2677
|
+
function snapshotResizeStart({
|
|
2678
|
+
headers,
|
|
2679
|
+
visualOrder,
|
|
2680
|
+
getColumnGrid,
|
|
2681
|
+
tableEl
|
|
2682
|
+
}) {
|
|
2683
|
+
var _a;
|
|
2684
|
+
if (!headers || visualOrder.length !== headers.length) return null;
|
|
2685
|
+
const snapshot = computeGridResizeSnapshot({ headers, visualOrder, getColumnGrid });
|
|
2686
|
+
if (tableEl && snapshot.needsMaxContentMeasure.length > 0) {
|
|
2687
|
+
const measuredMins = measureMaxContentMins(
|
|
2688
|
+
tableEl,
|
|
2689
|
+
headers,
|
|
2690
|
+
visualOrder,
|
|
2691
|
+
snapshot.needsMaxContentMeasure,
|
|
2692
|
+
getColumnGrid
|
|
2693
|
+
);
|
|
2694
|
+
Object.assign(snapshot.mins, measuredMins);
|
|
2695
|
+
}
|
|
2696
|
+
const containerWidth = (_a = tableEl == null ? void 0 : tableEl.getBoundingClientRect().width) != null ? _a : 0;
|
|
2697
|
+
return {
|
|
2698
|
+
widths: snapshot.widths,
|
|
2699
|
+
meta: {
|
|
2700
|
+
containerWidth,
|
|
2701
|
+
fixedTotal: snapshot.fixedTotal,
|
|
2702
|
+
flexIds: snapshot.flexIds,
|
|
2703
|
+
mins: snapshot.mins
|
|
2704
|
+
}
|
|
2705
|
+
};
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
// src/hooks/use-grid-layout.ts
|
|
2709
|
+
function useGridLayout({
|
|
2710
|
+
layout,
|
|
2711
|
+
table,
|
|
2712
|
+
tableBodyScrollRef,
|
|
2713
|
+
displayableColumns,
|
|
2714
|
+
columnOrdering,
|
|
2715
|
+
gridMeasuredMins,
|
|
2716
|
+
setGridMeasuredMins,
|
|
2717
|
+
handleColumnSizingChange,
|
|
2718
|
+
rawHandleAutosizeAll,
|
|
2719
|
+
rawHandleAutosizeColumn,
|
|
2720
|
+
rawHandleResetColumnSize
|
|
2721
|
+
}) {
|
|
2722
|
+
const isGrid = layout === "grid";
|
|
2723
|
+
const gridRootRef = React4.useRef(null);
|
|
2724
|
+
const gridSnapshotWidths = React4.useRef({});
|
|
2725
|
+
const gridVisualColumnOrder = React4.useRef([]);
|
|
2726
|
+
const gridPersistedFr = React4.useRef({});
|
|
2727
|
+
const gridSnapshotMeta = React4.useRef({
|
|
2728
|
+
containerWidth: 0,
|
|
2729
|
+
fixedTotal: 0,
|
|
2730
|
+
flexIds: [],
|
|
2731
|
+
mins: {}
|
|
2732
|
+
});
|
|
2733
|
+
const prevResizingColumn = React4.useRef(false);
|
|
2734
|
+
const prevResizingForCorrection = React4.useRef(false);
|
|
2735
|
+
const clearGridFr = React4.useCallback(
|
|
2736
|
+
(columnId) => {
|
|
2737
|
+
if (!isGrid) return;
|
|
2738
|
+
const tableEl = gridRootRef.current;
|
|
2739
|
+
if (columnId) {
|
|
2740
|
+
delete gridPersistedFr.current[columnId];
|
|
2741
|
+
tableEl == null ? void 0 : tableEl.style.removeProperty(`--col-fr-${columnId}`);
|
|
2742
|
+
} else {
|
|
2743
|
+
for (const colId of Object.keys(gridPersistedFr.current)) {
|
|
2744
|
+
tableEl == null ? void 0 : tableEl.style.removeProperty(`--col-fr-${colId}`);
|
|
2745
|
+
}
|
|
2746
|
+
gridPersistedFr.current = {};
|
|
2747
|
+
}
|
|
2748
|
+
gridSnapshotWidths.current = {};
|
|
2749
|
+
},
|
|
2750
|
+
[isGrid]
|
|
2751
|
+
);
|
|
2752
|
+
const headerGroups = table.getHeaderGroups();
|
|
2753
|
+
const gridTemplate = React4.useMemo(() => {
|
|
2754
|
+
if (!isGrid) return void 0;
|
|
2755
|
+
const firstGroup = headerGroups[0];
|
|
2756
|
+
if (!firstGroup) return void 0;
|
|
2757
|
+
const displayableIds = new Set(displayableColumns.map((c) => c.id));
|
|
2758
|
+
const visibleHeaders = firstGroup.headers.filter((h) => displayableIds.has(h.column.id));
|
|
2759
|
+
return {
|
|
2760
|
+
visualOrder: visibleHeaders.map((h) => h.column.id),
|
|
2761
|
+
template: getGridColumnTemplate({
|
|
2762
|
+
headers: visibleHeaders.map((h) => {
|
|
2763
|
+
var _a;
|
|
2764
|
+
return {
|
|
2765
|
+
columnId: h.column.id,
|
|
2766
|
+
size: h.column.getSize(),
|
|
2767
|
+
grid: (_a = h.column.columnDef.meta) == null ? void 0 : _a.grid
|
|
2768
|
+
};
|
|
2769
|
+
}),
|
|
2770
|
+
gridMeasuredMins
|
|
2771
|
+
})
|
|
2772
|
+
};
|
|
2773
|
+
}, [isGrid, headerGroups, displayableColumns, gridMeasuredMins]);
|
|
2774
|
+
const gridTemplateColumns = gridTemplate == null ? void 0 : gridTemplate.template;
|
|
2775
|
+
React4.useLayoutEffect(() => {
|
|
2776
|
+
if (gridTemplate) gridVisualColumnOrder.current = gridTemplate.visualOrder;
|
|
2777
|
+
}, [gridTemplate]);
|
|
2778
|
+
const resizingColumn = table.getState().columnSizingInfo.isResizingColumn;
|
|
2779
|
+
React4.useLayoutEffect(() => {
|
|
2780
|
+
var _a;
|
|
2781
|
+
if (resizingColumn && !prevResizingColumn.current) {
|
|
2782
|
+
const headers = (_a = tableBodyScrollRef.current) == null ? void 0 : _a.querySelectorAll('[role="columnheader"]');
|
|
2783
|
+
if (headers) {
|
|
2784
|
+
const result = snapshotResizeStart({
|
|
2785
|
+
headers,
|
|
2786
|
+
visualOrder: gridVisualColumnOrder.current,
|
|
2787
|
+
getColumnGrid: (colId) => {
|
|
2788
|
+
var _a2, _b;
|
|
2789
|
+
return (_b = (_a2 = table.getColumn(colId)) == null ? void 0 : _a2.columnDef.meta) == null ? void 0 : _b.grid;
|
|
2790
|
+
},
|
|
2791
|
+
tableEl: gridRootRef.current
|
|
2792
|
+
});
|
|
2793
|
+
if (result) {
|
|
2794
|
+
Object.assign(gridSnapshotWidths.current, result.widths);
|
|
2795
|
+
gridSnapshotMeta.current = result.meta;
|
|
2796
|
+
}
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
prevResizingColumn.current = resizingColumn || false;
|
|
2800
|
+
}, [resizingColumn, table, tableBodyScrollRef]);
|
|
2801
|
+
const measureContentMins = React4.useCallback(() => {
|
|
2802
|
+
var _a;
|
|
2803
|
+
const tableEl = gridRootRef.current;
|
|
2804
|
+
const headers = (_a = tableBodyScrollRef.current) == null ? void 0 : _a.querySelectorAll('[role="columnheader"]');
|
|
2805
|
+
const visualOrder = gridVisualColumnOrder.current;
|
|
2806
|
+
if (!tableEl || !headers || visualOrder.length !== headers.length) return;
|
|
2807
|
+
const getColumnGrid = (colId) => {
|
|
2808
|
+
var _a2, _b;
|
|
2809
|
+
return (_b = (_a2 = table.getColumn(colId)) == null ? void 0 : _a2.columnDef.meta) == null ? void 0 : _b.grid;
|
|
2810
|
+
};
|
|
2811
|
+
const columnsToMeasure = findContentMinColumns(visualOrder, getColumnGrid);
|
|
2812
|
+
if (columnsToMeasure.length === 0) return;
|
|
2813
|
+
const newMins = measureMaxContentMins(tableEl, headers, visualOrder, columnsToMeasure, getColumnGrid);
|
|
2814
|
+
setGridMeasuredMins((prev) => {
|
|
2815
|
+
const keys = Object.keys(newMins);
|
|
2816
|
+
if (keys.length === Object.keys(prev).length && keys.every((k) => {
|
|
2817
|
+
var _a2;
|
|
2818
|
+
return Math.abs(((_a2 = prev[k]) != null ? _a2 : 0) - newMins[k]) < 0.5;
|
|
2819
|
+
})) {
|
|
2820
|
+
return prev;
|
|
2821
|
+
}
|
|
2822
|
+
return newMins;
|
|
2823
|
+
});
|
|
2824
|
+
}, [table, tableBodyScrollRef, setGridMeasuredMins]);
|
|
2825
|
+
const rowCount = table.getRowCount();
|
|
2826
|
+
const tableRows = table.getRowModel().rows;
|
|
2827
|
+
const contentMinKey = displayableColumns.map((c) => c.id).join(",");
|
|
2828
|
+
React4.useLayoutEffect(() => {
|
|
2829
|
+
if (!isGrid || resizingColumn) return;
|
|
2830
|
+
measureContentMins();
|
|
2831
|
+
}, [isGrid, resizingColumn, rowCount, contentMinKey, tableRows, measureContentMins]);
|
|
2832
|
+
React4.useEffect(() => {
|
|
2833
|
+
if (!isGrid) return;
|
|
2834
|
+
const scrollEl = tableBodyScrollRef.current;
|
|
2835
|
+
if (!scrollEl) return;
|
|
2836
|
+
const observer = new ResizeObserver(() => {
|
|
2837
|
+
if (!table.getState().columnSizingInfo.isResizingColumn) {
|
|
2838
|
+
measureContentMins();
|
|
2839
|
+
}
|
|
2840
|
+
});
|
|
2841
|
+
observer.observe(scrollEl);
|
|
2842
|
+
return () => observer.disconnect();
|
|
2843
|
+
}, [isGrid, measureContentMins, table, tableBodyScrollRef]);
|
|
2844
|
+
React4.useLayoutEffect(() => {
|
|
2845
|
+
if (!isGrid) return;
|
|
2846
|
+
const tableEl = gridRootRef.current;
|
|
2847
|
+
if (!tableEl) return;
|
|
2848
|
+
const { isResizingColumn, deltaOffset } = table.getState().columnSizingInfo;
|
|
2849
|
+
if (isResizingColumn && deltaOffset != null) {
|
|
2850
|
+
const nextFr = computeGridResizeFrValues({
|
|
2851
|
+
resizingColumnId: isResizingColumn,
|
|
2852
|
+
deltaOffset,
|
|
2853
|
+
visualOrder: gridVisualColumnOrder.current,
|
|
2854
|
+
snapshotWidths: gridSnapshotWidths.current,
|
|
2855
|
+
snapshotMeta: gridSnapshotMeta.current
|
|
2856
|
+
});
|
|
2857
|
+
for (const [colId, fr] of Object.entries(nextFr)) {
|
|
2858
|
+
tableEl.style.setProperty(`--col-fr-${colId}`, `${fr}fr`);
|
|
2859
|
+
gridPersistedFr.current[colId] = fr;
|
|
2860
|
+
}
|
|
2861
|
+
} else {
|
|
2862
|
+
gridPersistedFr.current = resolveGridPersistedFr({
|
|
2863
|
+
visualOrder: gridVisualColumnOrder.current,
|
|
2864
|
+
persistedFr: gridPersistedFr.current,
|
|
2865
|
+
columnSizing: table.getState().columnSizing,
|
|
2866
|
+
measuredMins: gridMeasuredMins,
|
|
2867
|
+
getGridSizing: (colId) => {
|
|
2868
|
+
var _a, _b;
|
|
2869
|
+
const grid = (_b = (_a = table.getColumn(colId)) == null ? void 0 : _a.columnDef.meta) == null ? void 0 : _b.grid;
|
|
2870
|
+
return grid && "flex" in grid ? grid : void 0;
|
|
2871
|
+
}
|
|
2872
|
+
});
|
|
2873
|
+
}
|
|
2874
|
+
for (const [colId, fr] of Object.entries(gridPersistedFr.current)) {
|
|
2875
|
+
tableEl.style.setProperty(`--col-fr-${colId}`, `${fr}fr`);
|
|
2876
|
+
}
|
|
2877
|
+
});
|
|
2878
|
+
React4.useLayoutEffect(() => {
|
|
2879
|
+
var _a;
|
|
2880
|
+
const wasResizing = prevResizingForCorrection.current;
|
|
2881
|
+
prevResizingForCorrection.current = resizingColumn || false;
|
|
2882
|
+
if (!isGrid || resizingColumn || !wasResizing) return;
|
|
2883
|
+
const headers = (_a = tableBodyScrollRef.current) == null ? void 0 : _a.querySelectorAll('[role="columnheader"]');
|
|
2884
|
+
const visualOrder = gridVisualColumnOrder.current;
|
|
2885
|
+
if (!headers || visualOrder.length !== headers.length) return;
|
|
2886
|
+
const corrected = {};
|
|
2887
|
+
Array.from(headers).forEach((header, idx) => {
|
|
2888
|
+
var _a2, _b;
|
|
2889
|
+
const colId = visualOrder[idx];
|
|
2890
|
+
if (!colId) return;
|
|
2891
|
+
const grid = (_b = (_a2 = table.getColumn(colId)) == null ? void 0 : _a2.columnDef.meta) == null ? void 0 : _b.grid;
|
|
2892
|
+
if (grid && "flex" in grid && grid.flex != null) {
|
|
2893
|
+
corrected[colId] = Math.round(header.getBoundingClientRect().width);
|
|
2894
|
+
}
|
|
2895
|
+
});
|
|
2896
|
+
if (Object.keys(corrected).length > 0) {
|
|
2897
|
+
handleColumnSizingChange((prev) => __spreadValues(__spreadValues({}, prev), corrected));
|
|
2898
|
+
}
|
|
2899
|
+
});
|
|
2900
|
+
const handleAutosizeAll = React4.useCallback(() => {
|
|
2901
|
+
clearGridFr();
|
|
2902
|
+
rawHandleAutosizeAll();
|
|
2903
|
+
}, [clearGridFr, rawHandleAutosizeAll]);
|
|
2904
|
+
const handleAutosizeColumn = React4.useCallback(
|
|
2905
|
+
(columnId) => {
|
|
2906
|
+
clearGridFr(columnId);
|
|
2907
|
+
rawHandleAutosizeColumn(columnId);
|
|
2908
|
+
},
|
|
2909
|
+
[clearGridFr, rawHandleAutosizeColumn]
|
|
2910
|
+
);
|
|
2911
|
+
const handleResetColumnSize = React4.useCallback(
|
|
2912
|
+
(columnId) => {
|
|
2913
|
+
clearGridFr(columnId);
|
|
2914
|
+
rawHandleResetColumnSize(columnId);
|
|
2915
|
+
},
|
|
2916
|
+
[clearGridFr, rawHandleResetColumnSize]
|
|
2917
|
+
);
|
|
2918
|
+
const prevColumnOrderingRef = React4.useRef(columnOrdering);
|
|
2919
|
+
React4.useEffect(() => {
|
|
2920
|
+
const prev = prevColumnOrderingRef.current;
|
|
2921
|
+
prevColumnOrderingRef.current = columnOrdering;
|
|
2922
|
+
if (isGrid && prev.length > 0 && prev.join(",") !== columnOrdering.join(",")) {
|
|
2923
|
+
gridSnapshotWidths.current = {};
|
|
2924
|
+
gridPersistedFr.current = {};
|
|
2925
|
+
handleAutosizeAll();
|
|
2926
|
+
}
|
|
2927
|
+
}, [isGrid, columnOrdering, handleAutosizeAll]);
|
|
2928
|
+
return {
|
|
2929
|
+
gridTemplateColumns,
|
|
2930
|
+
gridRootRef,
|
|
2931
|
+
gridVisualColumnOrder,
|
|
2932
|
+
gridPersistedFr,
|
|
2933
|
+
gridSnapshotWidths,
|
|
2934
|
+
clearGridFr,
|
|
2935
|
+
measureContentMins,
|
|
2936
|
+
handleAutosizeAll,
|
|
2937
|
+
handleAutosizeColumn,
|
|
2938
|
+
handleResetColumnSize
|
|
2939
|
+
};
|
|
2940
|
+
}
|
|
2941
|
+
|
|
2942
|
+
// src/data-table/empty-view.tsx
|
|
2943
|
+
import { Alert, AlertDescription } from "@upbound/monarch-core";
|
|
2944
|
+
import { Button as Button4 } from "@upbound/monarch-core";
|
|
2945
|
+
import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "@upbound/monarch-core";
|
|
2946
|
+
import { Icon as Icon4 } from "@upbound/monarch-core";
|
|
2947
|
+
import { IconTile } from "@upbound/monarch-core";
|
|
2948
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2949
|
+
var defaultErrorConfig = {
|
|
2950
|
+
icon: "circle-exclamation",
|
|
2951
|
+
header: "Something went wrong",
|
|
2952
|
+
subheader: "We couldn't load this data. Try again in a moment."
|
|
2953
|
+
};
|
|
2954
|
+
var defaultEmptyConfig = {
|
|
2955
|
+
icon: "inbox",
|
|
2956
|
+
header: "No results",
|
|
2957
|
+
subheader: "There's nothing here yet."
|
|
2958
|
+
};
|
|
2959
|
+
var defaultNoFilterFoundConfig = {
|
|
2960
|
+
icon: "magnifying-glass",
|
|
2961
|
+
header: "No matching results",
|
|
2962
|
+
subheader: "Try adjusting your search or filters."
|
|
2963
|
+
};
|
|
2964
|
+
function DataTableEmptyView({
|
|
2965
|
+
emptyView,
|
|
2966
|
+
tableState,
|
|
2967
|
+
filterCount,
|
|
2968
|
+
resetFilters,
|
|
2969
|
+
className
|
|
2970
|
+
}) {
|
|
2971
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
2972
|
+
const isFilteredEmpty = tableState === "empty" && filterCount > 0;
|
|
2973
|
+
const config = tableState === "error" ? (_a = emptyView == null ? void 0 : emptyView.error) != null ? _a : defaultErrorConfig : tableState === "empty" ? isFilteredEmpty ? (_b = emptyView == null ? void 0 : emptyView.filter) != null ? _b : defaultNoFilterFoundConfig : (_c = emptyView == null ? void 0 : emptyView.empty) != null ? _c : defaultEmptyConfig : null;
|
|
2974
|
+
const wrapperClassName = tableState === "error" ? (_f = (_d = emptyView == null ? void 0 : emptyView.error) == null ? void 0 : _d.wrapperClassName) != null ? _f : (_e = emptyView == null ? void 0 : emptyView.empty) == null ? void 0 : _e.wrapperClassName : config == null ? void 0 : config.wrapperClassName;
|
|
2975
|
+
const defaultAction = isFilteredEmpty && !(config == null ? void 0 : config.action) ? /* @__PURE__ */ jsxs5(Button4, { variant: "outline", size: "sm", onClick: resetFilters, children: [
|
|
2976
|
+
/* @__PURE__ */ jsx6(Icon4, { name: "xmark" }),
|
|
2977
|
+
"Clear filters"
|
|
2978
|
+
] }) : null;
|
|
2979
|
+
return /* @__PURE__ */ jsx6("div", { className: cn("flex size-full flex-col justify-center p-6", wrapperClassName, className), children: config && // The error state ignores its own config's `className` for outer
|
|
2980
|
+
// padding, matching the source's forced `pt-0` on that branch.
|
|
2981
|
+
/* @__PURE__ */ jsxs5(Empty, { className: tableState === "error" ? "pt-0" : config.className, children: [
|
|
2982
|
+
/* @__PURE__ */ jsxs5(EmptyHeader, { children: [
|
|
2983
|
+
config.icon && /* @__PURE__ */ jsx6(EmptyMedia, { children: /* @__PURE__ */ jsx6(IconTile, { variant: "branded", children: /* @__PURE__ */ jsx6(Icon4, { name: config.icon }) }) }),
|
|
2984
|
+
config.header && /* @__PURE__ */ jsx6(EmptyTitle, { children: config.header }),
|
|
2985
|
+
config.subheader && /* @__PURE__ */ jsx6(EmptyDescription, { children: config.subheader })
|
|
2986
|
+
] }),
|
|
2987
|
+
(config.details || config.action || defaultAction) && /* @__PURE__ */ jsxs5(EmptyContent, { children: [
|
|
2988
|
+
config.details && /* @__PURE__ */ jsx6(Alert, { children: /* @__PURE__ */ jsx6(AlertDescription, { children: config.details }) }),
|
|
2989
|
+
(_g = config.action) != null ? _g : defaultAction
|
|
2990
|
+
] })
|
|
2991
|
+
] }) });
|
|
2992
|
+
}
|
|
2993
|
+
|
|
2994
|
+
// src/data-table/pagination.tsx
|
|
2995
|
+
import { Button as Button5 } from "@upbound/monarch-core";
|
|
2996
|
+
import { Icon as Icon5 } from "@upbound/monarch-core";
|
|
2997
|
+
import { Label as Label2 } from "@upbound/monarch-core";
|
|
2998
|
+
import {
|
|
2999
|
+
Pagination,
|
|
3000
|
+
PaginationContent,
|
|
3001
|
+
PaginationEllipsis,
|
|
3002
|
+
PaginationItem,
|
|
3003
|
+
PaginationLink
|
|
3004
|
+
} from "@upbound/monarch-core";
|
|
3005
|
+
import { Select as Select2, SelectContent as SelectContent2, SelectGroup as SelectGroup2, SelectItem as SelectItem2, SelectTrigger as SelectTrigger2, SelectValue as SelectValue2 } from "@upbound/monarch-core";
|
|
3006
|
+
import { Tooltip as Tooltip2, TooltipContent as TooltipContent2, TooltipTrigger as TooltipTrigger2 } from "@upbound/monarch-core";
|
|
3007
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
3008
|
+
var DEFAULT_PAGINATION_CONFIG = {
|
|
3009
|
+
summary: true,
|
|
3010
|
+
arrows: true,
|
|
3011
|
+
numbers: false,
|
|
3012
|
+
pageSizeSelector: true,
|
|
3013
|
+
pageSizeOptions: [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
|
|
3014
|
+
};
|
|
3015
|
+
var PAGE_SIZE_SELECT_ID = "table-page-size-select";
|
|
3016
|
+
function getPageSizeOptions(pageSizeOptions) {
|
|
3017
|
+
return Array.from(new Set(pageSizeOptions)).filter((option) => option > 0).sort((a, b) => a - b);
|
|
3018
|
+
}
|
|
3019
|
+
function getEffectivePageSize(pageSize, pageSizeOptions) {
|
|
3020
|
+
if (pageSizeOptions.length === 0 || pageSizeOptions.includes(pageSize)) return pageSize;
|
|
3021
|
+
return pageSizeOptions.reduce(
|
|
3022
|
+
(closest, option) => Math.abs(option - pageSize) < Math.abs(closest - pageSize) ? option : closest,
|
|
3023
|
+
pageSizeOptions[0]
|
|
3024
|
+
);
|
|
3025
|
+
}
|
|
3026
|
+
function normalizePageSizeOptions(pageSize, pageSizeOptions) {
|
|
3027
|
+
const normalizedPageSizeOptions = getPageSizeOptions(pageSizeOptions);
|
|
3028
|
+
return { normalizedPageSizeOptions, effectivePageSize: getEffectivePageSize(pageSize, normalizedPageSizeOptions) };
|
|
3029
|
+
}
|
|
3030
|
+
function DataTablePagination({
|
|
3031
|
+
pageIndex,
|
|
3032
|
+
pageSize,
|
|
3033
|
+
rowCount,
|
|
3034
|
+
rowCountRelation = "eq",
|
|
3035
|
+
paginationConfig = true,
|
|
3036
|
+
onPageChange,
|
|
3037
|
+
onPageSizeChange
|
|
3038
|
+
}) {
|
|
3039
|
+
const isRowCountExact = rowCountRelation === "eq";
|
|
3040
|
+
const resolved = typeof paginationConfig === "object" ? __spreadValues(__spreadValues({}, DEFAULT_PAGINATION_CONFIG), paginationConfig) : DEFAULT_PAGINATION_CONFIG;
|
|
3041
|
+
const { normalizedPageSizeOptions, effectivePageSize } = normalizePageSizeOptions(pageSize, resolved.pageSizeOptions);
|
|
3042
|
+
const { visiblePages, pageCount, itemStart, itemEnd } = getPaginationInfo(pageIndex, rowCount, effectivePageSize);
|
|
3043
|
+
const currentPage = pageIndex + 1;
|
|
3044
|
+
const mounted = useMounted();
|
|
3045
|
+
const locale = mounted ? void 0 : "en-US";
|
|
3046
|
+
return /* @__PURE__ */ jsxs6("div", { "data-testid": "table-footer", className: "flex items-center justify-between px-2 pt-4", children: [
|
|
3047
|
+
resolved.summary ? /* @__PURE__ */ jsxs6("div", { className: "text-body text-muted-foreground", "data-testid": "table-pagination-summary", children: [
|
|
3048
|
+
"Showing ",
|
|
3049
|
+
/* @__PURE__ */ jsx7("span", { className: "text-foreground font-medium", children: itemStart.toLocaleString(locale) }),
|
|
3050
|
+
" to",
|
|
3051
|
+
" ",
|
|
3052
|
+
/* @__PURE__ */ jsx7("span", { className: "text-foreground font-medium", children: itemEnd.toLocaleString(locale) }),
|
|
3053
|
+
" of",
|
|
3054
|
+
" ",
|
|
3055
|
+
/* @__PURE__ */ jsxs6("span", { className: "text-foreground font-medium", children: [
|
|
3056
|
+
rowCount.toLocaleString(locale),
|
|
3057
|
+
!isRowCountExact && "+"
|
|
3058
|
+
] }),
|
|
3059
|
+
" ",
|
|
3060
|
+
"results",
|
|
3061
|
+
!isRowCountExact && /* @__PURE__ */ jsxs6(Tooltip2, { children: [
|
|
3062
|
+
/* @__PURE__ */ jsx7(TooltipTrigger2, { className: "ml-1 align-middle", children: /* @__PURE__ */ jsx7(Icon5, { name: "circle-info", size: "sm" }) }),
|
|
3063
|
+
/* @__PURE__ */ jsx7(TooltipContent2, { children: "Add filters or refine your search to reduce the result set." })
|
|
3064
|
+
] })
|
|
3065
|
+
] }) : /* @__PURE__ */ jsx7("div", {}),
|
|
3066
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-4", children: [
|
|
3067
|
+
resolved.pageSizeSelector && /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
3068
|
+
/* @__PURE__ */ jsx7(Label2, { htmlFor: PAGE_SIZE_SELECT_ID, className: "font-semibold", children: "Rows per page" }),
|
|
3069
|
+
/* @__PURE__ */ jsxs6(Select2, { value: String(effectivePageSize), onValueChange: (value) => onPageSizeChange(Number(value)), children: [
|
|
3070
|
+
/* @__PURE__ */ jsx7(SelectTrigger2, { id: PAGE_SIZE_SELECT_ID, size: "sm", className: "w-18", "data-testid": "table-page-size-select", children: /* @__PURE__ */ jsx7(SelectValue2, {}) }),
|
|
3071
|
+
/* @__PURE__ */ jsx7(SelectContent2, { align: "end", children: /* @__PURE__ */ jsx7(SelectGroup2, { children: normalizedPageSizeOptions.map((option) => /* @__PURE__ */ jsx7(SelectItem2, { value: String(option), children: option }, option)) }) })
|
|
3072
|
+
] })
|
|
3073
|
+
] }),
|
|
3074
|
+
pageCount > 1 && (resolved.arrows || resolved.numbers) && /* @__PURE__ */ jsx7(Pagination, { className: "mx-0 w-auto justify-end", children: /* @__PURE__ */ jsxs6(PaginationContent, { children: [
|
|
3075
|
+
resolved.arrows && /* @__PURE__ */ jsx7(PaginationItem, { children: /* @__PURE__ */ jsx7(
|
|
3076
|
+
Button5,
|
|
3077
|
+
{
|
|
3078
|
+
variant: "outline",
|
|
3079
|
+
size: "icon",
|
|
3080
|
+
"aria-label": "Go to first page",
|
|
3081
|
+
disabled: currentPage <= 1,
|
|
3082
|
+
onClick: () => onPageChange(1),
|
|
3083
|
+
children: /* @__PURE__ */ jsx7(Icon5, { name: "chevrons-left", className: "cn-rtl-flip" })
|
|
3084
|
+
}
|
|
3085
|
+
) }),
|
|
3086
|
+
resolved.arrows && /* @__PURE__ */ jsx7(PaginationItem, { children: /* @__PURE__ */ jsx7(
|
|
3087
|
+
Button5,
|
|
3088
|
+
{
|
|
3089
|
+
variant: "outline",
|
|
3090
|
+
size: "icon",
|
|
3091
|
+
"aria-label": "Go to previous page",
|
|
3092
|
+
disabled: currentPage <= 1,
|
|
3093
|
+
onClick: () => onPageChange(currentPage - 1),
|
|
3094
|
+
children: /* @__PURE__ */ jsx7(Icon5, { name: "chevron-left", className: "cn-rtl-flip" })
|
|
3095
|
+
}
|
|
3096
|
+
) }),
|
|
3097
|
+
resolved.numbers && visiblePages.map(
|
|
3098
|
+
(page, index) => page === void 0 ? /* @__PURE__ */ jsx7(PaginationItem, { children: /* @__PURE__ */ jsx7(PaginationEllipsis, {}) }, `ellipsis-${index}`) : /* @__PURE__ */ jsx7(PaginationItem, { children: /* @__PURE__ */ jsx7(
|
|
3099
|
+
PaginationLink,
|
|
3100
|
+
{
|
|
3101
|
+
href: "#",
|
|
3102
|
+
isActive: page === currentPage,
|
|
3103
|
+
onClick: (e) => {
|
|
3104
|
+
e.preventDefault();
|
|
3105
|
+
onPageChange(page);
|
|
3106
|
+
},
|
|
3107
|
+
children: page
|
|
3108
|
+
}
|
|
3109
|
+
) }, page)
|
|
3110
|
+
),
|
|
3111
|
+
resolved.arrows && /* @__PURE__ */ jsx7(PaginationItem, { children: /* @__PURE__ */ jsx7(
|
|
3112
|
+
Button5,
|
|
3113
|
+
{
|
|
3114
|
+
variant: "outline",
|
|
3115
|
+
size: "icon",
|
|
3116
|
+
"aria-label": "Go to next page",
|
|
3117
|
+
disabled: currentPage >= pageCount,
|
|
3118
|
+
onClick: () => onPageChange(currentPage + 1),
|
|
3119
|
+
children: /* @__PURE__ */ jsx7(Icon5, { name: "chevron-right", className: "cn-rtl-flip" })
|
|
3120
|
+
}
|
|
3121
|
+
) }),
|
|
3122
|
+
resolved.arrows && /* @__PURE__ */ jsx7(PaginationItem, { children: /* @__PURE__ */ jsx7(
|
|
3123
|
+
Button5,
|
|
3124
|
+
{
|
|
3125
|
+
variant: "outline",
|
|
3126
|
+
size: "icon",
|
|
3127
|
+
"aria-label": "Go to last page",
|
|
3128
|
+
disabled: currentPage >= pageCount,
|
|
3129
|
+
onClick: () => onPageChange(pageCount),
|
|
3130
|
+
children: /* @__PURE__ */ jsx7(Icon5, { name: "chevrons-right", className: "cn-rtl-flip" })
|
|
3131
|
+
}
|
|
3132
|
+
) })
|
|
3133
|
+
] }) })
|
|
3134
|
+
] })
|
|
3135
|
+
] });
|
|
3136
|
+
}
|
|
3137
|
+
|
|
3138
|
+
// src/data-table/table-primitives.tsx
|
|
3139
|
+
import * as React5 from "react";
|
|
3140
|
+
import {
|
|
3141
|
+
flexRender as flexRender2
|
|
3142
|
+
} from "@tanstack/react-table";
|
|
3143
|
+
import { ContextMenu, ContextMenuTrigger } from "@upbound/monarch-core";
|
|
3144
|
+
import {
|
|
3145
|
+
DropdownMenu as DropdownMenu3,
|
|
3146
|
+
DropdownMenuContent as DropdownMenuContent3,
|
|
3147
|
+
DropdownMenuItem as DropdownMenuItem3,
|
|
3148
|
+
DropdownMenuSeparator,
|
|
3149
|
+
DropdownMenuTrigger as DropdownMenuTrigger3
|
|
3150
|
+
} from "@upbound/monarch-core";
|
|
3151
|
+
import { Icon as Icon6 } from "@upbound/monarch-core";
|
|
3152
|
+
import { Skeleton } from "@upbound/monarch-core";
|
|
3153
|
+
import {
|
|
3154
|
+
Table as BaseTable,
|
|
3155
|
+
TableBody as BaseTableBody,
|
|
3156
|
+
TableCell as BaseTableCell,
|
|
3157
|
+
TableHead as BaseTableHead,
|
|
3158
|
+
TableHeader as BaseTableHeader,
|
|
3159
|
+
TableRow as BaseTableRow
|
|
3160
|
+
} from "@upbound/monarch-core";
|
|
3161
|
+
import { Tooltip as Tooltip3, TooltipContent as TooltipContent3, TooltipTrigger as TooltipTrigger3 } from "@upbound/monarch-core";
|
|
3162
|
+
import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
3163
|
+
var HEADER_SURFACE_BG = "bg-[color-mix(in_oklch,var(--muted)_50%,var(--card))]";
|
|
3164
|
+
var TABLE_HEAD_CLASSES = "text-body-sm text-muted-foreground h-10 px-4 text-left align-middle font-medium whitespace-nowrap has-[[role=checkbox]]:pr-0";
|
|
3165
|
+
var TABLE_CELL_CLASSES = "px-4 py-2 align-middle whitespace-nowrap has-[[role=checkbox]]:pr-0";
|
|
3166
|
+
var TABLE_ROW_CLASSES = "hover:bg-muted/50 has-aria-expanded:bg-muted/50 data-[state=selected]:bg-muted border-b motion-safe:transition-colors";
|
|
3167
|
+
function DataTableRoot({
|
|
3168
|
+
layout = "auto",
|
|
3169
|
+
gridTemplateColumns,
|
|
3170
|
+
gridRootRef,
|
|
3171
|
+
className,
|
|
3172
|
+
style,
|
|
3173
|
+
children
|
|
3174
|
+
}) {
|
|
3175
|
+
if (layout === "grid") {
|
|
3176
|
+
return /* @__PURE__ */ jsx8(
|
|
3177
|
+
"div",
|
|
3178
|
+
{
|
|
3179
|
+
ref: gridRootRef,
|
|
3180
|
+
role: "table",
|
|
3181
|
+
className: cn("text-body grid w-full", className),
|
|
3182
|
+
style: __spreadProps(__spreadValues({}, style), { gridTemplateColumns }),
|
|
3183
|
+
children
|
|
3184
|
+
}
|
|
3185
|
+
);
|
|
3186
|
+
}
|
|
3187
|
+
return /* @__PURE__ */ jsx8(BaseTable, { className, style, children });
|
|
3188
|
+
}
|
|
3189
|
+
function getColumnPinningProps(column, surface = "body") {
|
|
3190
|
+
const isPinned = column.getIsPinned();
|
|
3191
|
+
if (!isPinned) return { className: "", style: {} };
|
|
3192
|
+
const isLastLeft = isPinned === "left" && column.getIsLastColumn("left");
|
|
3193
|
+
const isFirstRight = isPinned === "right" && column.getIsFirstColumn("right");
|
|
3194
|
+
return {
|
|
3195
|
+
className: cn(
|
|
3196
|
+
"sticky",
|
|
3197
|
+
surface === "header" ? HEADER_SURFACE_BG : "bg-card",
|
|
3198
|
+
isLastLeft && "border-r-2 border-r-border",
|
|
3199
|
+
isFirstRight && "border-l-2 border-l-border"
|
|
3200
|
+
),
|
|
3201
|
+
style: {
|
|
3202
|
+
left: isPinned === "left" ? `${column.getStart("left")}px` : void 0,
|
|
3203
|
+
right: isPinned === "right" ? `${column.getAfter("right")}px` : void 0,
|
|
3204
|
+
width: column.getSize()
|
|
3205
|
+
}
|
|
3206
|
+
};
|
|
3207
|
+
}
|
|
3208
|
+
function DataTableSortIcon({ sortOrder }) {
|
|
3209
|
+
if (!sortOrder) return null;
|
|
3210
|
+
return /* @__PURE__ */ jsx8(
|
|
3211
|
+
Icon6,
|
|
3212
|
+
{
|
|
3213
|
+
name: sortOrder === "asc" ? "arrow-up" : "arrow-down",
|
|
3214
|
+
size: "xs",
|
|
3215
|
+
className: "text-primary group-hover/col-actions:text-foreground group-data-[state=open]/col-actions:text-foreground mr-0.5 shrink-0"
|
|
3216
|
+
}
|
|
3217
|
+
);
|
|
3218
|
+
}
|
|
3219
|
+
function ColumnActionsMenuItems({
|
|
3220
|
+
header,
|
|
3221
|
+
onAutosizeAll,
|
|
3222
|
+
onAutosizeColumn,
|
|
3223
|
+
layout = "auto"
|
|
3224
|
+
}) {
|
|
3225
|
+
const isGrid = layout === "grid";
|
|
3226
|
+
const canSort = header.column.getCanSort();
|
|
3227
|
+
const canResize = header.column.getCanResize();
|
|
3228
|
+
const canHide = header.column.getCanHide();
|
|
3229
|
+
const canPin = !isGrid && header.column.getCanPin();
|
|
3230
|
+
return /* @__PURE__ */ jsxs7(DropdownMenuContent3, { align: "start", className: "w-45", children: [
|
|
3231
|
+
canSort && /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
3232
|
+
/* @__PURE__ */ jsxs7(
|
|
3233
|
+
DropdownMenuItem3,
|
|
3234
|
+
{
|
|
3235
|
+
disabled: header.column.getIsSorted() === "asc",
|
|
3236
|
+
onClick: () => header.column.toggleSorting(false),
|
|
3237
|
+
children: [
|
|
3238
|
+
/* @__PURE__ */ jsx8(Icon6, { name: "arrow-up" }),
|
|
3239
|
+
"Sort ascending"
|
|
3240
|
+
]
|
|
3241
|
+
}
|
|
3242
|
+
),
|
|
3243
|
+
/* @__PURE__ */ jsxs7(
|
|
3244
|
+
DropdownMenuItem3,
|
|
3245
|
+
{
|
|
3246
|
+
disabled: header.column.getIsSorted() === "desc",
|
|
3247
|
+
onClick: () => header.column.toggleSorting(true),
|
|
3248
|
+
children: [
|
|
3249
|
+
/* @__PURE__ */ jsx8(Icon6, { name: "arrow-down" }),
|
|
3250
|
+
"Sort descending"
|
|
3251
|
+
]
|
|
3252
|
+
}
|
|
3253
|
+
),
|
|
3254
|
+
!!header.column.getIsSorted() && /* @__PURE__ */ jsxs7(DropdownMenuItem3, { onClick: () => header.column.clearSorting(), children: [
|
|
3255
|
+
/* @__PURE__ */ jsx8(Icon6, { name: "xmark" }),
|
|
3256
|
+
"Remove sorting"
|
|
3257
|
+
] })
|
|
3258
|
+
] }),
|
|
3259
|
+
canResize && /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
3260
|
+
canSort && /* @__PURE__ */ jsx8(DropdownMenuSeparator, {}),
|
|
3261
|
+
!isGrid && /* @__PURE__ */ jsxs7(DropdownMenuItem3, { onClick: () => onAutosizeColumn(header.column.id), children: [
|
|
3262
|
+
/* @__PURE__ */ jsx8(Icon6, { name: "arrows-left-right" }),
|
|
3263
|
+
"Autosize column"
|
|
3264
|
+
] }),
|
|
3265
|
+
/* @__PURE__ */ jsxs7(DropdownMenuItem3, { onClick: () => onAutosizeAll(), children: [
|
|
3266
|
+
/* @__PURE__ */ jsx8(Icon6, { name: "table-columns" }),
|
|
3267
|
+
isGrid ? "Reset all columns" : "Autosize all columns"
|
|
3268
|
+
] })
|
|
3269
|
+
] }),
|
|
3270
|
+
(canHide || canPin) && /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
3271
|
+
(canSort || canResize) && /* @__PURE__ */ jsx8(DropdownMenuSeparator, {}),
|
|
3272
|
+
canHide && /* @__PURE__ */ jsxs7(DropdownMenuItem3, { onClick: () => header.column.toggleVisibility(), children: [
|
|
3273
|
+
/* @__PURE__ */ jsx8(Icon6, { name: "eye-slash" }),
|
|
3274
|
+
"Hide column"
|
|
3275
|
+
] }),
|
|
3276
|
+
canPin && (header.column.getIsPinned() ? /* @__PURE__ */ jsxs7(DropdownMenuItem3, { onClick: () => header.column.pin(false), children: [
|
|
3277
|
+
/* @__PURE__ */ jsx8(Icon6, { name: "thumbtack" }),
|
|
3278
|
+
"Unpin column"
|
|
3279
|
+
] }) : /* @__PURE__ */ jsxs7(DropdownMenuItem3, { onClick: () => header.column.pin("left"), children: [
|
|
3280
|
+
/* @__PURE__ */ jsx8(Icon6, { name: "thumbtack" }),
|
|
3281
|
+
"Pin column"
|
|
3282
|
+
] }))
|
|
3283
|
+
] })
|
|
3284
|
+
] });
|
|
3285
|
+
}
|
|
3286
|
+
function HeaderCellContent({
|
|
3287
|
+
header,
|
|
3288
|
+
canResize,
|
|
3289
|
+
isActionColumn,
|
|
3290
|
+
isGroupedColumn,
|
|
3291
|
+
shouldShowActionsMenu,
|
|
3292
|
+
onAutosizeAll,
|
|
3293
|
+
onAutosizeColumn,
|
|
3294
|
+
onResetColumnSize,
|
|
3295
|
+
layout = "auto"
|
|
3296
|
+
}) {
|
|
3297
|
+
const resizeHandler = header.getResizeHandler();
|
|
3298
|
+
const headerTitle = typeof header.column.columnDef.header === "string" ? header.column.columnDef.header : "";
|
|
3299
|
+
const sorted = header.column.getIsSorted();
|
|
3300
|
+
const labelButton = /* @__PURE__ */ jsxs7(
|
|
3301
|
+
"button",
|
|
3302
|
+
{
|
|
3303
|
+
type: "button",
|
|
3304
|
+
"aria-label": shouldShowActionsMenu ? headerTitle ? `${headerTitle} column actions` : "Column actions" : void 0,
|
|
3305
|
+
className: cn(
|
|
3306
|
+
"group/col-actions text-muted-foreground -mx-2 -my-1 flex min-w-0 items-center gap-1 truncate rounded-md px-2 py-1 text-left font-medium motion-safe:transition-colors",
|
|
3307
|
+
sorted && "text-primary",
|
|
3308
|
+
shouldShowActionsMenu ? "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50 cursor-pointer" : "cursor-default"
|
|
3309
|
+
),
|
|
3310
|
+
children: [
|
|
3311
|
+
/* @__PURE__ */ jsx8(DataTableSortIcon, { sortOrder: sorted }),
|
|
3312
|
+
/* @__PURE__ */ jsx8("span", { className: "min-w-0 truncate", children: flexRender2(header.column.columnDef.header, header.getContext()) }),
|
|
3313
|
+
shouldShowActionsMenu && /* @__PURE__ */ jsx8(
|
|
3314
|
+
Icon6,
|
|
3315
|
+
{
|
|
3316
|
+
size: "sm",
|
|
3317
|
+
name: "ellipsis",
|
|
3318
|
+
className: "ml-1 shrink-0 opacity-0 transition-none group-hover/col-actions:opacity-100 group-focus-visible/col-actions:opacity-100 group-data-[state=open]/col-actions:opacity-100"
|
|
3319
|
+
}
|
|
3320
|
+
)
|
|
3321
|
+
]
|
|
3322
|
+
}
|
|
3323
|
+
);
|
|
3324
|
+
const label = shouldShowActionsMenu ? /* @__PURE__ */ jsxs7(DropdownMenu3, { children: [
|
|
3325
|
+
/* @__PURE__ */ jsx8(DropdownMenuTrigger3, { asChild: true, children: labelButton }),
|
|
3326
|
+
/* @__PURE__ */ jsx8(
|
|
3327
|
+
ColumnActionsMenuItems,
|
|
3328
|
+
{
|
|
3329
|
+
header,
|
|
3330
|
+
onAutosizeAll,
|
|
3331
|
+
onAutosizeColumn,
|
|
3332
|
+
layout
|
|
3333
|
+
}
|
|
3334
|
+
)
|
|
3335
|
+
] }) : labelButton;
|
|
3336
|
+
return /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
3337
|
+
/* @__PURE__ */ jsx8("div", { className: "flex min-w-0 items-center gap-1", children: /* @__PURE__ */ jsx8("div", { className: "min-w-0 flex-1", children: !isActionColumn && !isGroupedColumn && (headerTitle ? /* @__PURE__ */ jsxs7(Tooltip3, { children: [
|
|
3338
|
+
/* @__PURE__ */ jsx8(TooltipTrigger3, { asChild: true, children: label }),
|
|
3339
|
+
/* @__PURE__ */ jsx8(TooltipContent3, { children: headerTitle })
|
|
3340
|
+
] }) : label) }) }),
|
|
3341
|
+
canResize && /* @__PURE__ */ jsx8(
|
|
3342
|
+
"button",
|
|
3343
|
+
{
|
|
3344
|
+
type: "button",
|
|
3345
|
+
"aria-label": "Resize column",
|
|
3346
|
+
className: "hover:border-primary absolute top-0 right-0 z-10 h-full w-2 cursor-col-resize border-r border-transparent opacity-0 group-hover:opacity-100 hover:opacity-100 motion-safe:transition-opacity",
|
|
3347
|
+
onMouseDown: resizeHandler,
|
|
3348
|
+
onDoubleClick: (e) => {
|
|
3349
|
+
e.preventDefault();
|
|
3350
|
+
onResetColumnSize(header.column.id);
|
|
3351
|
+
}
|
|
3352
|
+
}
|
|
3353
|
+
)
|
|
3354
|
+
] });
|
|
3355
|
+
}
|
|
3356
|
+
var DEFAULT_STICKY_HEADER_OFFSET_PX = 0;
|
|
3357
|
+
var DEFAULT_STICKY_HEADER_ROW_HEIGHT_PX = 48;
|
|
3358
|
+
function DataTableHeader({
|
|
3359
|
+
headerGroups,
|
|
3360
|
+
onAutosizeAll,
|
|
3361
|
+
onAutosizeColumn,
|
|
3362
|
+
onResetColumnSize,
|
|
3363
|
+
stickyHeader,
|
|
3364
|
+
layout = "auto"
|
|
3365
|
+
}) {
|
|
3366
|
+
var _a, _b;
|
|
3367
|
+
const isGrid = layout === "grid";
|
|
3368
|
+
const stickyHeaderOffset = typeof stickyHeader === "object" ? (_a = stickyHeader == null ? void 0 : stickyHeader.offset) != null ? _a : DEFAULT_STICKY_HEADER_OFFSET_PX : DEFAULT_STICKY_HEADER_OFFSET_PX;
|
|
3369
|
+
const stickyHeaderRowHeight = typeof stickyHeader === "object" ? (_b = stickyHeader == null ? void 0 : stickyHeader.rowHeight) != null ? _b : DEFAULT_STICKY_HEADER_ROW_HEIGHT_PX : DEFAULT_STICKY_HEADER_ROW_HEIGHT_PX;
|
|
3370
|
+
const renderHeaders = (headerGroup, headerGroupIndex) => {
|
|
3371
|
+
const visibleHeaders = headerGroup.headers.filter((header) => !isFilterOnlyColumn(header.column));
|
|
3372
|
+
return visibleHeaders.map((header, headerIndex) => {
|
|
3373
|
+
const meta = header.column.columnDef.meta;
|
|
3374
|
+
const isActionColumn = !!(meta == null ? void 0 : meta.actions);
|
|
3375
|
+
const isGroupedColumn = header.column.getIsGrouped();
|
|
3376
|
+
const canSort = header.column.getCanSort();
|
|
3377
|
+
const isLastColumn = isGrid && headerIndex === visibleHeaders.length - 1;
|
|
3378
|
+
const canResize = header.column.getCanResize() && !isLastColumn;
|
|
3379
|
+
const canHide = header.column.getCanHide();
|
|
3380
|
+
const canPin = !isGrid && header.column.getCanPin();
|
|
3381
|
+
const shouldShowActionsMenu = !isGroupedColumn && !isActionColumn && (canSort || canResize || canHide || canPin);
|
|
3382
|
+
const stickyTopPx = stickyHeader ? stickyHeaderOffset + headerGroupIndex * stickyHeaderRowHeight : void 0;
|
|
3383
|
+
const isPinned = !isGrid && header.column.getIsPinned();
|
|
3384
|
+
const pinning = isGrid ? { className: "", style: {} } : getColumnPinningProps(header.column, "header");
|
|
3385
|
+
const content = /* @__PURE__ */ jsx8(
|
|
3386
|
+
HeaderCellContent,
|
|
3387
|
+
{
|
|
3388
|
+
header,
|
|
3389
|
+
canResize,
|
|
3390
|
+
isActionColumn,
|
|
3391
|
+
isGroupedColumn,
|
|
3392
|
+
shouldShowActionsMenu,
|
|
3393
|
+
onAutosizeAll,
|
|
3394
|
+
onAutosizeColumn,
|
|
3395
|
+
onResetColumnSize,
|
|
3396
|
+
layout
|
|
3397
|
+
}
|
|
3398
|
+
);
|
|
3399
|
+
const cellClassName = cn(
|
|
3400
|
+
"group relative overflow-visible text-left",
|
|
3401
|
+
!!stickyHeader && cn(HEADER_SURFACE_BG, "sticky z-20"),
|
|
3402
|
+
pinning.className,
|
|
3403
|
+
isPinned && "z-30"
|
|
3404
|
+
);
|
|
3405
|
+
if (isGrid) {
|
|
3406
|
+
return /* @__PURE__ */ jsx8(
|
|
3407
|
+
"div",
|
|
3408
|
+
{
|
|
3409
|
+
role: "columnheader",
|
|
3410
|
+
className: cn(TABLE_HEAD_CLASSES, cellClassName, "h-auto py-1.5 whitespace-normal"),
|
|
3411
|
+
style: __spreadValues({
|
|
3412
|
+
minWidth: header.column.columnDef.minSize
|
|
3413
|
+
}, stickyTopPx !== void 0 ? { top: stickyTopPx } : {}),
|
|
3414
|
+
children: content
|
|
3415
|
+
},
|
|
3416
|
+
header.id
|
|
3417
|
+
);
|
|
3418
|
+
}
|
|
3419
|
+
return /* @__PURE__ */ jsx8(
|
|
3420
|
+
BaseTableHead,
|
|
3421
|
+
{
|
|
3422
|
+
className: cn(cellClassName, "h-auto py-1.5 whitespace-normal"),
|
|
3423
|
+
style: __spreadValues(__spreadValues(__spreadProps(__spreadValues({}, pinning.style), {
|
|
3424
|
+
minWidth: header.column.columnDef.minSize,
|
|
3425
|
+
maxWidth: header.column.columnDef.maxSize
|
|
3426
|
+
}), !isPinned ? { width: header.column.getSize() } : {}), stickyTopPx !== void 0 ? { top: stickyTopPx } : {}),
|
|
3427
|
+
children: content
|
|
3428
|
+
},
|
|
3429
|
+
header.id
|
|
3430
|
+
);
|
|
3431
|
+
});
|
|
3432
|
+
};
|
|
3433
|
+
if (isGrid) {
|
|
3434
|
+
return /* @__PURE__ */ jsx8(
|
|
3435
|
+
"div",
|
|
3436
|
+
{
|
|
3437
|
+
role: "rowgroup",
|
|
3438
|
+
className: cn("col-span-full grid grid-cols-subgrid", HEADER_SURFACE_BG, !!stickyHeader && "sticky z-20"),
|
|
3439
|
+
style: stickyHeader ? { top: stickyHeaderOffset } : void 0,
|
|
3440
|
+
children: headerGroups.map((headerGroup, headerGroupIndex) => /* @__PURE__ */ jsx8("div", { role: "row", className: "col-span-full grid grid-cols-subgrid border-b", children: renderHeaders(headerGroup, headerGroupIndex) }, headerGroup.id))
|
|
3441
|
+
}
|
|
3442
|
+
);
|
|
3443
|
+
}
|
|
3444
|
+
return /* @__PURE__ */ jsx8(BaseTableHeader, { children: headerGroups.map((headerGroup, headerGroupIndex) => /* @__PURE__ */ jsx8(BaseTableRow, { children: renderHeaders(headerGroup, headerGroupIndex) }, headerGroup.id)) });
|
|
3445
|
+
}
|
|
3446
|
+
var DataTableRow = React5.forwardRef(
|
|
3447
|
+
(_a, ref) => {
|
|
3448
|
+
var _b = _a, { hoverable, disabled, className, layout = "auto" } = _b, props = __objRest(_b, ["hoverable", "disabled", "className", "layout"]);
|
|
3449
|
+
const classes = cn(
|
|
3450
|
+
"break-all",
|
|
3451
|
+
hoverable && "cursor-pointer",
|
|
3452
|
+
disabled && "cursor-not-allowed opacity-80",
|
|
3453
|
+
className
|
|
3454
|
+
);
|
|
3455
|
+
if (layout === "grid") {
|
|
3456
|
+
return /* @__PURE__ */ jsx8(
|
|
3457
|
+
"div",
|
|
3458
|
+
__spreadValues({
|
|
3459
|
+
ref,
|
|
3460
|
+
role: "row",
|
|
3461
|
+
className: cn(TABLE_ROW_CLASSES, "col-span-full grid grid-cols-subgrid", classes)
|
|
3462
|
+
}, props)
|
|
3463
|
+
);
|
|
3464
|
+
}
|
|
3465
|
+
return /* @__PURE__ */ jsx8(BaseTableRow, __spreadValues({ ref, className: classes }, props));
|
|
3466
|
+
}
|
|
3467
|
+
);
|
|
3468
|
+
DataTableRow.displayName = "DataTableRow";
|
|
3469
|
+
function DataTableCell({
|
|
3470
|
+
cell,
|
|
3471
|
+
className,
|
|
3472
|
+
showContextualFilter,
|
|
3473
|
+
onContextCell,
|
|
3474
|
+
onContextSearch,
|
|
3475
|
+
contextualMenuActions,
|
|
3476
|
+
layout = "auto"
|
|
3477
|
+
}) {
|
|
3478
|
+
const isGrid = layout === "grid";
|
|
3479
|
+
const meta = cell.column.columnDef.meta;
|
|
3480
|
+
const isActions = !!(meta == null ? void 0 : meta.actions);
|
|
3481
|
+
const shouldTruncate = !isActions;
|
|
3482
|
+
const isPinned = !isGrid && cell.column.getIsPinned();
|
|
3483
|
+
const pinning = isGrid ? { className: "", style: {} } : getColumnPinningProps(cell.column);
|
|
3484
|
+
const shouldShowContextualMenu = !!showContextualFilter && !!onContextCell && !isActions;
|
|
3485
|
+
const contextualGlobalSearch = shouldShowContextualMenu ? getContextualGlobalSearch(cell) : void 0;
|
|
3486
|
+
const contextualFilter = shouldShowContextualMenu ? getContextualColumnFilter(cell) : void 0;
|
|
3487
|
+
const content = flexRender2(cell.column.columnDef.cell, cell.getContext());
|
|
3488
|
+
const cellClassName = cn(
|
|
3489
|
+
isActions && "text-right",
|
|
3490
|
+
shouldTruncate && "overflow-hidden text-ellipsis whitespace-nowrap",
|
|
3491
|
+
isGrid && "flex items-center",
|
|
3492
|
+
pinning.className,
|
|
3493
|
+
isPinned && "z-10",
|
|
3494
|
+
className
|
|
3495
|
+
);
|
|
3496
|
+
const cellElement = isGrid ? /* @__PURE__ */ jsx8(
|
|
3497
|
+
"div",
|
|
3498
|
+
{
|
|
3499
|
+
role: "cell",
|
|
3500
|
+
className: cn(TABLE_CELL_CLASSES, cellClassName),
|
|
3501
|
+
style: { minWidth: cell.column.columnDef.minSize },
|
|
3502
|
+
children: content
|
|
3503
|
+
}
|
|
3504
|
+
) : /* @__PURE__ */ jsx8(
|
|
3505
|
+
BaseTableCell,
|
|
3506
|
+
{
|
|
3507
|
+
className: cellClassName,
|
|
3508
|
+
style: __spreadProps(__spreadValues(__spreadValues({}, pinning.style), !isPinned ? { width: cell.column.getSize() } : {}), {
|
|
3509
|
+
minWidth: cell.column.columnDef.minSize,
|
|
3510
|
+
maxWidth: cell.column.columnDef.maxSize
|
|
3511
|
+
}),
|
|
3512
|
+
children: content
|
|
3513
|
+
}
|
|
3514
|
+
);
|
|
3515
|
+
if (!shouldShowContextualMenu || !onContextCell) return cellElement;
|
|
3516
|
+
return /* @__PURE__ */ jsxs7(ContextMenu, { children: [
|
|
3517
|
+
/* @__PURE__ */ jsx8(ContextMenuTrigger, { asChild: true, children: cellElement }),
|
|
3518
|
+
/* @__PURE__ */ jsx8(
|
|
3519
|
+
CellContextualFilter,
|
|
3520
|
+
{
|
|
3521
|
+
filter: contextualFilter,
|
|
3522
|
+
globalSearch: contextualGlobalSearch,
|
|
3523
|
+
cell,
|
|
3524
|
+
onContextCell,
|
|
3525
|
+
onContextSearch,
|
|
3526
|
+
contextualMenuActions
|
|
3527
|
+
}
|
|
3528
|
+
)
|
|
3529
|
+
] });
|
|
3530
|
+
}
|
|
3531
|
+
function DataTableGroupRow({
|
|
3532
|
+
groupLabel,
|
|
3533
|
+
colSpan,
|
|
3534
|
+
layout = "auto"
|
|
3535
|
+
}) {
|
|
3536
|
+
if (layout === "grid") {
|
|
3537
|
+
return /* @__PURE__ */ jsx8("div", { role: "row", className: "bg-muted/50 hover:bg-muted/50 col-span-full grid grid-cols-subgrid", children: /* @__PURE__ */ jsx8(
|
|
3538
|
+
"div",
|
|
3539
|
+
{
|
|
3540
|
+
role: "cell",
|
|
3541
|
+
style: { gridColumn: `span ${colSpan}` },
|
|
3542
|
+
className: "text-foreground border-b px-4 py-2 font-semibold whitespace-nowrap",
|
|
3543
|
+
children: groupLabel
|
|
3544
|
+
}
|
|
3545
|
+
) });
|
|
3546
|
+
}
|
|
3547
|
+
return /* @__PURE__ */ jsx8(BaseTableRow, { className: "bg-muted/50 hover:bg-muted/50", children: /* @__PURE__ */ jsx8(BaseTableCell, { colSpan, className: "text-foreground border-b font-semibold whitespace-nowrap", children: groupLabel }) });
|
|
3548
|
+
}
|
|
3549
|
+
function DataTableSkeletonBody({
|
|
3550
|
+
rowCount = 10,
|
|
3551
|
+
columns,
|
|
3552
|
+
renderCell,
|
|
3553
|
+
layout = "auto"
|
|
3554
|
+
}) {
|
|
3555
|
+
const isGrid = layout === "grid";
|
|
3556
|
+
const rows = Array.from({ length: rowCount }).map((_, rowIndex) => /* @__PURE__ */ jsx8(DataTableRow, { layout, children: columns.map(
|
|
3557
|
+
(col) => {
|
|
3558
|
+
var _a, _b;
|
|
3559
|
+
return isGrid ? /* @__PURE__ */ jsx8(
|
|
3560
|
+
"div",
|
|
3561
|
+
{
|
|
3562
|
+
role: "cell",
|
|
3563
|
+
className: cn(TABLE_CELL_CLASSES, "flex items-center overflow-hidden"),
|
|
3564
|
+
style: { minWidth: col.minSize },
|
|
3565
|
+
children: (_a = renderCell == null ? void 0 : renderCell(col.id)) != null ? _a : /* @__PURE__ */ jsx8(Skeleton, { className: "h-4 w-full" })
|
|
3566
|
+
},
|
|
3567
|
+
`skeleton-col-${col.id}-row-${rowIndex}`
|
|
3568
|
+
) : /* @__PURE__ */ jsx8(
|
|
3569
|
+
BaseTableCell,
|
|
3570
|
+
{
|
|
3571
|
+
style: { width: col.size, minWidth: col.minSize, maxWidth: col.maxSize },
|
|
3572
|
+
children: (_b = renderCell == null ? void 0 : renderCell(col.id)) != null ? _b : /* @__PURE__ */ jsx8(Skeleton, { className: "h-4 w-full" })
|
|
3573
|
+
},
|
|
3574
|
+
`skeleton-col-${col.id}-row-${rowIndex}`
|
|
3575
|
+
);
|
|
3576
|
+
}
|
|
3577
|
+
) }, `skeleton-row-${rowIndex}`));
|
|
3578
|
+
if (isGrid) {
|
|
3579
|
+
return /* @__PURE__ */ jsx8("div", { role: "rowgroup", className: "col-span-full grid grid-cols-subgrid", "data-testid": "table-skeleton-loader", children: rows });
|
|
3580
|
+
}
|
|
3581
|
+
return /* @__PURE__ */ jsx8(BaseTableBody, { "data-testid": "table-skeleton-loader", children: rows });
|
|
3582
|
+
}
|
|
3583
|
+
function DataTableExpandedRow({
|
|
3584
|
+
colSpan,
|
|
3585
|
+
show,
|
|
3586
|
+
children,
|
|
3587
|
+
layout = "auto"
|
|
3588
|
+
}) {
|
|
3589
|
+
if (!show) return null;
|
|
3590
|
+
if (layout === "grid") {
|
|
3591
|
+
return /* @__PURE__ */ jsx8("div", { role: "row", className: "col-span-full grid grid-cols-subgrid", children: /* @__PURE__ */ jsx8("div", { role: "cell", style: { gridColumn: `span ${colSpan}` }, className: "bg-card p-0 align-top whitespace-normal", children }) });
|
|
3592
|
+
}
|
|
3593
|
+
return /* @__PURE__ */ jsx8(BaseTableRow, { className: "hover:bg-transparent", children: /* @__PURE__ */ jsx8(BaseTableCell, { colSpan, className: "bg-card p-0 align-top whitespace-normal", children }) });
|
|
3594
|
+
}
|
|
3595
|
+
function DataTableBody({
|
|
3596
|
+
tableRows,
|
|
3597
|
+
tableState,
|
|
3598
|
+
columns,
|
|
3599
|
+
skeletonRowCount,
|
|
3600
|
+
renderSkeletonCell,
|
|
3601
|
+
onRowRender,
|
|
3602
|
+
renderExpandedRow,
|
|
3603
|
+
showContextualFilter,
|
|
3604
|
+
onContextCell,
|
|
3605
|
+
onContextSearch,
|
|
3606
|
+
contextualMenuActions,
|
|
3607
|
+
layout = "auto"
|
|
3608
|
+
}) {
|
|
3609
|
+
const isGrid = layout === "grid";
|
|
3610
|
+
const visibleColumns = columns.filter((column) => !isFilterOnlyColumn(column));
|
|
3611
|
+
const colSpan = visibleColumns.length;
|
|
3612
|
+
if (tableState === "loading") {
|
|
3613
|
+
const skeletonColumns = visibleColumns.map((c) => ({
|
|
3614
|
+
id: c.id,
|
|
3615
|
+
size: c.columnDef.size,
|
|
3616
|
+
minSize: c.columnDef.minSize,
|
|
3617
|
+
maxSize: c.columnDef.maxSize
|
|
3618
|
+
}));
|
|
3619
|
+
return /* @__PURE__ */ jsx8(
|
|
3620
|
+
DataTableSkeletonBody,
|
|
3621
|
+
{
|
|
3622
|
+
columns: skeletonColumns,
|
|
3623
|
+
rowCount: skeletonRowCount,
|
|
3624
|
+
renderCell: renderSkeletonCell,
|
|
3625
|
+
layout
|
|
3626
|
+
}
|
|
3627
|
+
);
|
|
3628
|
+
}
|
|
3629
|
+
const rows = tableRows.map((row) => {
|
|
3630
|
+
var _a, _b, _c, _d;
|
|
3631
|
+
if ((_a = row.getIsGrouped) == null ? void 0 : _a.call(row)) {
|
|
3632
|
+
const groupLabel = (_c = row.groupingValue) != null ? _c : row.groupingColumnId ? (_b = row.getGroupingValue) == null ? void 0 : _b.call(row, row.groupingColumnId) : void 0;
|
|
3633
|
+
return /* @__PURE__ */ jsx8(DataTableGroupRow, { groupLabel: String(groupLabel != null ? groupLabel : ""), colSpan, layout }, row.id);
|
|
3634
|
+
}
|
|
3635
|
+
const isExpanded = !!(renderExpandedRow && ((_d = row.getIsExpanded) == null ? void 0 : _d.call(row)));
|
|
3636
|
+
const expandedRow = renderExpandedRow ? renderExpandedRow(row.original) : null;
|
|
3637
|
+
return /* @__PURE__ */ jsxs7(React5.Fragment, { children: [
|
|
3638
|
+
/* @__PURE__ */ jsx8(
|
|
3639
|
+
DataTableRow,
|
|
3640
|
+
__spreadProps(__spreadValues({}, onRowRender ? onRowRender(row.original) : {}), {
|
|
3641
|
+
"data-expanded": isExpanded || void 0,
|
|
3642
|
+
layout,
|
|
3643
|
+
children: row.getVisibleCells().filter((cell) => !isFilterOnlyColumn(cell.column)).map((cell) => /* @__PURE__ */ jsx8(
|
|
3644
|
+
DataTableCell,
|
|
3645
|
+
{
|
|
3646
|
+
cell,
|
|
3647
|
+
showContextualFilter,
|
|
3648
|
+
onContextCell,
|
|
3649
|
+
onContextSearch,
|
|
3650
|
+
contextualMenuActions,
|
|
3651
|
+
layout
|
|
3652
|
+
},
|
|
3653
|
+
cell.id
|
|
3654
|
+
))
|
|
3655
|
+
})
|
|
3656
|
+
),
|
|
3657
|
+
/* @__PURE__ */ jsx8(DataTableExpandedRow, { colSpan, show: isExpanded, layout, children: expandedRow })
|
|
3658
|
+
] }, row.id);
|
|
3659
|
+
});
|
|
3660
|
+
if (isGrid) {
|
|
3661
|
+
return /* @__PURE__ */ jsx8("div", { role: "rowgroup", className: "col-span-full grid grid-cols-subgrid", children: rows });
|
|
3662
|
+
}
|
|
3663
|
+
return /* @__PURE__ */ jsx8(BaseTableBody, { children: rows });
|
|
3664
|
+
}
|
|
3665
|
+
|
|
3666
|
+
// src/data-table/view-filter.tsx
|
|
3667
|
+
import * as React7 from "react";
|
|
3668
|
+
|
|
3669
|
+
// src/filter-bar/filter-bar.tsx
|
|
3670
|
+
import * as React6 from "react";
|
|
3671
|
+
import { Icon as Icon7 } from "@upbound/monarch-core";
|
|
3672
|
+
import { Badge as Badge2 } from "@upbound/monarch-core";
|
|
3673
|
+
import { Button as Button6 } from "@upbound/monarch-core";
|
|
3674
|
+
import { ButtonGroup as ButtonGroup2, ButtonGroupText as ButtonGroupText2 } from "@upbound/monarch-core";
|
|
3675
|
+
import { Calendar as Calendar2 } from "@upbound/monarch-core";
|
|
3676
|
+
import {
|
|
3677
|
+
Combobox as Combobox2,
|
|
3678
|
+
ComboboxChip as ComboboxChip2,
|
|
3679
|
+
ComboboxClearAll as ComboboxClearAll2,
|
|
3680
|
+
ComboboxContent as ComboboxContent2,
|
|
3681
|
+
ComboboxEmpty as ComboboxEmpty2,
|
|
3682
|
+
ComboboxInput as ComboboxInput2,
|
|
3683
|
+
ComboboxItem as ComboboxItem2,
|
|
3684
|
+
ComboboxList as ComboboxList2,
|
|
3685
|
+
ComboboxSelectedChips as ComboboxSelectedChips2,
|
|
3686
|
+
ComboboxSeparator as ComboboxSeparator2,
|
|
3687
|
+
ComboboxTrigger as ComboboxTrigger2,
|
|
3688
|
+
ComboboxValue as ComboboxValue2
|
|
3689
|
+
} from "@upbound/monarch-core";
|
|
3690
|
+
import {
|
|
3691
|
+
DropdownMenu as DropdownMenu4,
|
|
3692
|
+
DropdownMenuCheckboxItem as DropdownMenuCheckboxItem2,
|
|
3693
|
+
DropdownMenuContent as DropdownMenuContent4,
|
|
3694
|
+
DropdownMenuItem as DropdownMenuItem4,
|
|
3695
|
+
DropdownMenuRadioGroup,
|
|
3696
|
+
DropdownMenuRadioItem,
|
|
3697
|
+
DropdownMenuTrigger as DropdownMenuTrigger4
|
|
3698
|
+
} from "@upbound/monarch-core";
|
|
3699
|
+
import { Input as Input2 } from "@upbound/monarch-core";
|
|
3700
|
+
import { Label as Label3 } from "@upbound/monarch-core";
|
|
3701
|
+
import { Popover as Popover2, PopoverContent as PopoverContent2, PopoverTrigger as PopoverTrigger2 } from "@upbound/monarch-core";
|
|
3702
|
+
import { Fragment as Fragment6, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
3703
|
+
function asCheckboxValue(value) {
|
|
3704
|
+
return Array.isArray(value) ? value : [];
|
|
3705
|
+
}
|
|
3706
|
+
function asRadioValue(value) {
|
|
3707
|
+
return typeof value === "string" ? value : "";
|
|
3708
|
+
}
|
|
3709
|
+
function asTextValue(value) {
|
|
3710
|
+
return typeof value === "string" ? value : "";
|
|
3711
|
+
}
|
|
3712
|
+
function asMultiTextValue(value) {
|
|
3713
|
+
return Array.isArray(value) ? value : [];
|
|
3714
|
+
}
|
|
3715
|
+
function asDateValue(value) {
|
|
3716
|
+
if (value && typeof value === "object" && !Array.isArray(value)) return value;
|
|
3717
|
+
return { startDate: null, endDate: null };
|
|
3718
|
+
}
|
|
3719
|
+
function hasExplicitTime(date) {
|
|
3720
|
+
if (!date) return false;
|
|
3721
|
+
return date.getHours() !== 0 || date.getMinutes() !== 0;
|
|
3722
|
+
}
|
|
3723
|
+
function formatTimeForInput(date) {
|
|
3724
|
+
if (!date) return "";
|
|
3725
|
+
return `${String(date.getHours()).padStart(2, "0")}:${String(date.getMinutes()).padStart(2, "0")}`;
|
|
3726
|
+
}
|
|
3727
|
+
function applyTimeToDate(date, time) {
|
|
3728
|
+
const [hours, minutes] = time.split(":").map(Number);
|
|
3729
|
+
const next = new Date(date);
|
|
3730
|
+
next.setHours(hours || 0, minutes || 0, 0, 0);
|
|
3731
|
+
return next;
|
|
3732
|
+
}
|
|
3733
|
+
function formatDateLabel(date) {
|
|
3734
|
+
return date.toLocaleDateString(void 0, { month: "short", day: "numeric" });
|
|
3735
|
+
}
|
|
3736
|
+
function FilterBar(_a) {
|
|
3737
|
+
var _b = _a, {
|
|
3738
|
+
filters,
|
|
3739
|
+
activeFilters,
|
|
3740
|
+
onAddFilter,
|
|
3741
|
+
onRemoveFilter,
|
|
3742
|
+
onChangeFilter,
|
|
3743
|
+
className,
|
|
3744
|
+
children
|
|
3745
|
+
} = _b, props = __objRest(_b, [
|
|
3746
|
+
"filters",
|
|
3747
|
+
"activeFilters",
|
|
3748
|
+
"onAddFilter",
|
|
3749
|
+
"onRemoveFilter",
|
|
3750
|
+
"onChangeFilter",
|
|
3751
|
+
"className",
|
|
3752
|
+
"children"
|
|
3753
|
+
]);
|
|
3754
|
+
const usedKeys = new Set(activeFilters.map((f) => f.key));
|
|
3755
|
+
const availableFilters = filters.filter((f) => !usedKeys.has(f.key));
|
|
3756
|
+
const shouldShowFilters = availableFilters.length > 0 || activeFilters.length > 0;
|
|
3757
|
+
const [pendingOpenKey, setPendingOpenKey] = React6.useState(null);
|
|
3758
|
+
function handleAddFilter(key) {
|
|
3759
|
+
onAddFilter(key);
|
|
3760
|
+
setPendingOpenKey(key);
|
|
3761
|
+
}
|
|
3762
|
+
return /* @__PURE__ */ jsxs8(
|
|
3763
|
+
"div",
|
|
3764
|
+
__spreadProps(__spreadValues({
|
|
3765
|
+
"data-slot": "filter-bar",
|
|
3766
|
+
"data-visible-filters": shouldShowFilters,
|
|
3767
|
+
className: cn("flex flex-wrap items-center gap-2", className)
|
|
3768
|
+
}, props), {
|
|
3769
|
+
children: [
|
|
3770
|
+
availableFilters.length > 0 && /* @__PURE__ */ jsxs8(DropdownMenu4, { children: [
|
|
3771
|
+
/* @__PURE__ */ jsx9(DropdownMenuTrigger4, { asChild: true, children: /* @__PURE__ */ jsxs8(Button6, { variant: "outline", children: [
|
|
3772
|
+
/* @__PURE__ */ jsx9(Icon7, { name: "plus", "data-icon": "inline-start" }),
|
|
3773
|
+
"Add filter"
|
|
3774
|
+
] }) }),
|
|
3775
|
+
/* @__PURE__ */ jsx9(
|
|
3776
|
+
DropdownMenuContent4,
|
|
3777
|
+
{
|
|
3778
|
+
align: "start",
|
|
3779
|
+
className: "w-48",
|
|
3780
|
+
onCloseAutoFocus: (e) => e.preventDefault(),
|
|
3781
|
+
children: availableFilters.map((filter) => /* @__PURE__ */ jsx9(DropdownMenuItem4, { onSelect: () => handleAddFilter(filter.key), children: filter.label }, filter.key))
|
|
3782
|
+
}
|
|
3783
|
+
)
|
|
3784
|
+
] }),
|
|
3785
|
+
activeFilters.map((active) => {
|
|
3786
|
+
const definition = filters.find((f) => f.key === active.key);
|
|
3787
|
+
if (!definition) return null;
|
|
3788
|
+
return /* @__PURE__ */ jsx9(
|
|
3789
|
+
FilterChip,
|
|
3790
|
+
{
|
|
3791
|
+
definition,
|
|
3792
|
+
value: active.value,
|
|
3793
|
+
autoOpen: active.key === pendingOpenKey,
|
|
3794
|
+
onChangeValue: (value) => onChangeFilter(active.key, value),
|
|
3795
|
+
onRemove: () => onRemoveFilter(active.key)
|
|
3796
|
+
},
|
|
3797
|
+
active.key
|
|
3798
|
+
);
|
|
3799
|
+
}),
|
|
3800
|
+
children
|
|
3801
|
+
]
|
|
3802
|
+
})
|
|
3803
|
+
);
|
|
3804
|
+
}
|
|
3805
|
+
function FilterChip({ definition, value, autoOpen, onChangeValue, onRemove }) {
|
|
3806
|
+
var _a;
|
|
3807
|
+
const type = (_a = definition.type) != null ? _a : "checkbox";
|
|
3808
|
+
switch (type) {
|
|
3809
|
+
case "checkbox":
|
|
3810
|
+
return /* @__PURE__ */ jsx9(
|
|
3811
|
+
CheckboxFilterChip,
|
|
3812
|
+
{
|
|
3813
|
+
definition,
|
|
3814
|
+
value,
|
|
3815
|
+
autoOpen,
|
|
3816
|
+
onChangeValue,
|
|
3817
|
+
onRemove
|
|
3818
|
+
}
|
|
3819
|
+
);
|
|
3820
|
+
case "radio":
|
|
3821
|
+
return /* @__PURE__ */ jsx9(
|
|
3822
|
+
RadioFilterChip,
|
|
3823
|
+
{
|
|
3824
|
+
definition,
|
|
3825
|
+
value,
|
|
3826
|
+
autoOpen,
|
|
3827
|
+
onChangeValue,
|
|
3828
|
+
onRemove
|
|
3829
|
+
}
|
|
3830
|
+
);
|
|
3831
|
+
case "text":
|
|
3832
|
+
return /* @__PURE__ */ jsx9(
|
|
3833
|
+
TextFilterChip,
|
|
3834
|
+
{
|
|
3835
|
+
definition,
|
|
3836
|
+
value,
|
|
3837
|
+
autoOpen,
|
|
3838
|
+
onChangeValue,
|
|
3839
|
+
onRemove
|
|
3840
|
+
}
|
|
3841
|
+
);
|
|
3842
|
+
case "multiText":
|
|
3843
|
+
return /* @__PURE__ */ jsx9(
|
|
3844
|
+
MultiTextFilterChip,
|
|
3845
|
+
{
|
|
3846
|
+
definition,
|
|
3847
|
+
value,
|
|
3848
|
+
autoOpen,
|
|
3849
|
+
onChangeValue,
|
|
3850
|
+
onRemove
|
|
3851
|
+
}
|
|
3852
|
+
);
|
|
3853
|
+
case "date":
|
|
3854
|
+
return /* @__PURE__ */ jsx9(
|
|
3855
|
+
DateFilterChip,
|
|
3856
|
+
{
|
|
3857
|
+
definition,
|
|
3858
|
+
value,
|
|
3859
|
+
autoOpen,
|
|
3860
|
+
onChangeValue,
|
|
3861
|
+
onRemove
|
|
3862
|
+
}
|
|
3863
|
+
);
|
|
3864
|
+
}
|
|
3865
|
+
}
|
|
3866
|
+
function FilterChipRemoveButton({ label, onRemove }) {
|
|
3867
|
+
return /* @__PURE__ */ jsx9(Button6, { variant: "outline", size: "icon", "aria-label": `Remove ${label} filter`, onClick: onRemove, children: /* @__PURE__ */ jsx9(Icon7, { name: "xmark" }) });
|
|
3868
|
+
}
|
|
3869
|
+
function CheckboxFilterChip({
|
|
3870
|
+
definition,
|
|
3871
|
+
value,
|
|
3872
|
+
autoOpen,
|
|
3873
|
+
onChangeValue,
|
|
3874
|
+
onRemove
|
|
3875
|
+
}) {
|
|
3876
|
+
var _a, _b;
|
|
3877
|
+
const { label, options, searchable = false } = definition;
|
|
3878
|
+
const values = asCheckboxValue(value);
|
|
3879
|
+
const displayLabel = values.length === 0 ? "Any" : values.length === 1 ? (_b = (_a = options.find((o) => o.value === values[0])) == null ? void 0 : _a.label) != null ? _b : values[0] : `${values.length} selected`;
|
|
3880
|
+
function toggle(optionValue) {
|
|
3881
|
+
const next = values.includes(optionValue) ? values.filter((v) => v !== optionValue) : [...values, optionValue];
|
|
3882
|
+
onChangeValue(next);
|
|
3883
|
+
}
|
|
3884
|
+
return /* @__PURE__ */ jsxs8(ButtonGroup2, { children: [
|
|
3885
|
+
/* @__PURE__ */ jsx9(ButtonGroupText2, { children: label }),
|
|
3886
|
+
searchable ? /* @__PURE__ */ jsxs8(
|
|
3887
|
+
Combobox2,
|
|
3888
|
+
{
|
|
3889
|
+
items: options,
|
|
3890
|
+
itemToStringValue: (item) => item.label,
|
|
3891
|
+
multiple: true,
|
|
3892
|
+
defaultOpen: autoOpen,
|
|
3893
|
+
value: options.filter((o) => values.includes(o.value)),
|
|
3894
|
+
onValueChange: (selected) => onChangeValue(selected.map((s) => s.value)),
|
|
3895
|
+
children: [
|
|
3896
|
+
/* @__PURE__ */ jsx9(
|
|
3897
|
+
ComboboxTrigger2,
|
|
3898
|
+
{
|
|
3899
|
+
render: /* @__PURE__ */ jsx9(Button6, { variant: "outline", className: "gap-1 font-normal [&>svg:last-child]:size-(--icon-sm)" }),
|
|
3900
|
+
children: /* @__PURE__ */ jsx9("span", { className: values.length === 0 ? "text-muted-foreground" : "", children: displayLabel })
|
|
3901
|
+
}
|
|
3902
|
+
),
|
|
3903
|
+
/* @__PURE__ */ jsxs8(ComboboxContent2, { className: "min-w-64", collisionAvoidance: { side: "none", align: "shift" }, children: [
|
|
3904
|
+
/* @__PURE__ */ jsx9(ComboboxInput2, { showTrigger: false, placeholder: `Search ${label.toLowerCase()}\u2026` }),
|
|
3905
|
+
values.length > 0 && /* @__PURE__ */ jsxs8(Fragment6, { children: [
|
|
3906
|
+
/* @__PURE__ */ jsxs8(ComboboxSelectedChips2, { children: [
|
|
3907
|
+
/* @__PURE__ */ jsx9(ComboboxValue2, { children: (selected) => /* @__PURE__ */ jsx9(Fragment6, { children: selected.map((item) => /* @__PURE__ */ jsx9(ComboboxChip2, { children: item.label }, item.value)) }) }),
|
|
3908
|
+
/* @__PURE__ */ jsx9(ComboboxClearAll2, { onClick: () => onChangeValue([]) })
|
|
3909
|
+
] }),
|
|
3910
|
+
/* @__PURE__ */ jsx9(ComboboxSeparator2, {})
|
|
3911
|
+
] }),
|
|
3912
|
+
/* @__PURE__ */ jsxs8(ComboboxEmpty2, { children: [
|
|
3913
|
+
"No ",
|
|
3914
|
+
label.toLowerCase(),
|
|
3915
|
+
" found."
|
|
3916
|
+
] }),
|
|
3917
|
+
/* @__PURE__ */ jsx9(ComboboxList2, { children: (item) => /* @__PURE__ */ jsxs8(ComboboxItem2, { value: item, children: [
|
|
3918
|
+
item.icon,
|
|
3919
|
+
item.label
|
|
3920
|
+
] }, item.value) })
|
|
3921
|
+
] })
|
|
3922
|
+
]
|
|
3923
|
+
}
|
|
3924
|
+
) : /* @__PURE__ */ jsxs8(DropdownMenu4, { defaultOpen: autoOpen, children: [
|
|
3925
|
+
/* @__PURE__ */ jsx9(DropdownMenuTrigger4, { asChild: true, children: /* @__PURE__ */ jsxs8(Button6, { variant: "outline", className: "gap-1 font-normal", children: [
|
|
3926
|
+
/* @__PURE__ */ jsx9("span", { className: values.length === 0 ? "text-muted-foreground" : "", children: displayLabel }),
|
|
3927
|
+
/* @__PURE__ */ jsx9(Icon7, { name: "chevron-down", size: "sm", className: "text-muted-foreground" })
|
|
3928
|
+
] }) }),
|
|
3929
|
+
/* @__PURE__ */ jsx9(DropdownMenuContent4, { align: "start", className: "w-48", children: options.map((opt) => /* @__PURE__ */ jsxs8(
|
|
3930
|
+
DropdownMenuCheckboxItem2,
|
|
3931
|
+
{
|
|
3932
|
+
checked: values.includes(opt.value),
|
|
3933
|
+
onCheckedChange: () => toggle(opt.value),
|
|
3934
|
+
children: [
|
|
3935
|
+
opt.icon,
|
|
3936
|
+
opt.label
|
|
3937
|
+
]
|
|
3938
|
+
},
|
|
3939
|
+
opt.value
|
|
3940
|
+
)) })
|
|
3941
|
+
] }),
|
|
3942
|
+
/* @__PURE__ */ jsx9(FilterChipRemoveButton, { label, onRemove })
|
|
3943
|
+
] });
|
|
3944
|
+
}
|
|
3945
|
+
function RadioFilterChip({
|
|
3946
|
+
definition,
|
|
3947
|
+
value,
|
|
3948
|
+
autoOpen,
|
|
3949
|
+
onChangeValue,
|
|
3950
|
+
onRemove
|
|
3951
|
+
}) {
|
|
3952
|
+
var _a, _b, _c;
|
|
3953
|
+
const { label, options, searchable = false } = definition;
|
|
3954
|
+
const selectedValue = asRadioValue(value);
|
|
3955
|
+
const displayLabel = selectedValue ? (_b = (_a = options.find((o) => o.value === selectedValue)) == null ? void 0 : _a.label) != null ? _b : selectedValue : "Any";
|
|
3956
|
+
const selected = (_c = options.find((o) => o.value === selectedValue)) != null ? _c : null;
|
|
3957
|
+
return /* @__PURE__ */ jsxs8(ButtonGroup2, { children: [
|
|
3958
|
+
/* @__PURE__ */ jsx9(ButtonGroupText2, { children: label }),
|
|
3959
|
+
searchable ? /* @__PURE__ */ jsxs8(
|
|
3960
|
+
Combobox2,
|
|
3961
|
+
{
|
|
3962
|
+
items: options,
|
|
3963
|
+
itemToStringValue: (item) => item.label,
|
|
3964
|
+
defaultOpen: autoOpen,
|
|
3965
|
+
value: selected,
|
|
3966
|
+
onValueChange: (next) => {
|
|
3967
|
+
var _a2;
|
|
3968
|
+
return onChangeValue((_a2 = next == null ? void 0 : next.value) != null ? _a2 : "");
|
|
3969
|
+
},
|
|
3970
|
+
children: [
|
|
3971
|
+
/* @__PURE__ */ jsx9(
|
|
3972
|
+
ComboboxTrigger2,
|
|
3973
|
+
{
|
|
3974
|
+
render: /* @__PURE__ */ jsx9(Button6, { variant: "outline", className: "gap-1 font-normal [&>svg:last-child]:size-(--icon-sm)" }),
|
|
3975
|
+
children: /* @__PURE__ */ jsx9("span", { className: selectedValue ? "" : "text-muted-foreground", children: displayLabel })
|
|
3976
|
+
}
|
|
3977
|
+
),
|
|
3978
|
+
/* @__PURE__ */ jsxs8(ComboboxContent2, { className: "min-w-64", collisionAvoidance: { side: "none", align: "shift" }, children: [
|
|
3979
|
+
/* @__PURE__ */ jsx9(ComboboxInput2, { showTrigger: false, placeholder: `Search ${label.toLowerCase()}\u2026` }),
|
|
3980
|
+
/* @__PURE__ */ jsxs8(ComboboxEmpty2, { children: [
|
|
3981
|
+
"No ",
|
|
3982
|
+
label.toLowerCase(),
|
|
3983
|
+
" found."
|
|
3984
|
+
] }),
|
|
3985
|
+
/* @__PURE__ */ jsx9(ComboboxList2, { children: (item) => /* @__PURE__ */ jsxs8(ComboboxItem2, { value: item, children: [
|
|
3986
|
+
item.icon,
|
|
3987
|
+
item.label
|
|
3988
|
+
] }, item.value) })
|
|
3989
|
+
] })
|
|
3990
|
+
]
|
|
3991
|
+
}
|
|
3992
|
+
) : /* @__PURE__ */ jsxs8(DropdownMenu4, { defaultOpen: autoOpen, children: [
|
|
3993
|
+
/* @__PURE__ */ jsx9(DropdownMenuTrigger4, { asChild: true, children: /* @__PURE__ */ jsxs8(Button6, { variant: "outline", className: "gap-1 font-normal", children: [
|
|
3994
|
+
/* @__PURE__ */ jsx9("span", { className: selectedValue ? "" : "text-muted-foreground", children: displayLabel }),
|
|
3995
|
+
/* @__PURE__ */ jsx9(Icon7, { name: "chevron-down", size: "sm", className: "text-muted-foreground" })
|
|
3996
|
+
] }) }),
|
|
3997
|
+
/* @__PURE__ */ jsx9(DropdownMenuContent4, { align: "start", className: "w-48", children: /* @__PURE__ */ jsx9(DropdownMenuRadioGroup, { value: selectedValue, onValueChange: onChangeValue, children: options.map((opt) => /* @__PURE__ */ jsxs8(DropdownMenuRadioItem, { value: opt.value, children: [
|
|
3998
|
+
opt.icon,
|
|
3999
|
+
opt.label
|
|
4000
|
+
] }, opt.value)) }) })
|
|
4001
|
+
] }),
|
|
4002
|
+
/* @__PURE__ */ jsx9(FilterChipRemoveButton, { label, onRemove })
|
|
4003
|
+
] });
|
|
4004
|
+
}
|
|
4005
|
+
function TextFilterChip({
|
|
4006
|
+
definition,
|
|
4007
|
+
value,
|
|
4008
|
+
autoOpen,
|
|
4009
|
+
onChangeValue,
|
|
4010
|
+
onRemove
|
|
4011
|
+
}) {
|
|
4012
|
+
const { label, placeholder } = definition;
|
|
4013
|
+
const text = asTextValue(value);
|
|
4014
|
+
const [open, setOpen] = React6.useState(!!autoOpen);
|
|
4015
|
+
return /* @__PURE__ */ jsxs8(ButtonGroup2, { children: [
|
|
4016
|
+
/* @__PURE__ */ jsx9(ButtonGroupText2, { children: label }),
|
|
4017
|
+
/* @__PURE__ */ jsxs8(Popover2, { open, onOpenChange: setOpen, children: [
|
|
4018
|
+
/* @__PURE__ */ jsx9(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsx9(Button6, { variant: "outline", className: "gap-1 font-normal", children: /* @__PURE__ */ jsx9("span", { className: text ? "" : "text-muted-foreground", children: text || "Any" }) }) }),
|
|
4019
|
+
/* @__PURE__ */ jsx9(PopoverContent2, { align: "start", children: /* @__PURE__ */ jsx9(
|
|
4020
|
+
Input2,
|
|
4021
|
+
{
|
|
4022
|
+
autoFocus: true,
|
|
4023
|
+
value: text,
|
|
4024
|
+
placeholder: placeholder != null ? placeholder : "Enter a value\u2026",
|
|
4025
|
+
onChange: (e) => onChangeValue(e.target.value),
|
|
4026
|
+
onKeyDown: (e) => {
|
|
4027
|
+
if (e.key === "Enter") setOpen(false);
|
|
4028
|
+
}
|
|
4029
|
+
}
|
|
4030
|
+
) })
|
|
4031
|
+
] }),
|
|
4032
|
+
/* @__PURE__ */ jsx9(FilterChipRemoveButton, { label, onRemove })
|
|
4033
|
+
] });
|
|
4034
|
+
}
|
|
4035
|
+
function MultiTextFilterChip({
|
|
4036
|
+
definition,
|
|
4037
|
+
value,
|
|
4038
|
+
autoOpen,
|
|
4039
|
+
onChangeValue,
|
|
4040
|
+
onRemove
|
|
4041
|
+
}) {
|
|
4042
|
+
const { label, placeholder } = definition;
|
|
4043
|
+
const tokens = asMultiTextValue(value);
|
|
4044
|
+
const [draft, setDraft] = React6.useState("");
|
|
4045
|
+
const displayLabel = tokens.length === 0 ? "Any" : tokens.length === 1 ? tokens[0] : `${tokens.length} values`;
|
|
4046
|
+
function addToken() {
|
|
4047
|
+
const token = draft.trim();
|
|
4048
|
+
if (!token || tokens.includes(token)) {
|
|
4049
|
+
setDraft("");
|
|
4050
|
+
return;
|
|
4051
|
+
}
|
|
4052
|
+
onChangeValue([...tokens, token]);
|
|
4053
|
+
setDraft("");
|
|
4054
|
+
}
|
|
4055
|
+
function removeToken(token) {
|
|
4056
|
+
onChangeValue(tokens.filter((t) => t !== token));
|
|
4057
|
+
}
|
|
4058
|
+
return /* @__PURE__ */ jsxs8(ButtonGroup2, { children: [
|
|
4059
|
+
/* @__PURE__ */ jsx9(ButtonGroupText2, { children: label }),
|
|
4060
|
+
/* @__PURE__ */ jsxs8(Popover2, { defaultOpen: autoOpen, children: [
|
|
4061
|
+
/* @__PURE__ */ jsx9(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsx9(Button6, { variant: "outline", className: "gap-1 font-normal", children: /* @__PURE__ */ jsx9("span", { className: tokens.length === 0 ? "text-muted-foreground" : "", children: displayLabel }) }) }),
|
|
4062
|
+
/* @__PURE__ */ jsx9(PopoverContent2, { align: "start", children: /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-2", children: [
|
|
4063
|
+
tokens.length > 0 && /* @__PURE__ */ jsx9("div", { className: "flex flex-wrap gap-1", children: tokens.map((token) => /* @__PURE__ */ jsxs8(Badge2, { variant: "secondary", className: "gap-1", children: [
|
|
4064
|
+
token,
|
|
4065
|
+
/* @__PURE__ */ jsx9(
|
|
4066
|
+
"button",
|
|
4067
|
+
{
|
|
4068
|
+
type: "button",
|
|
4069
|
+
"aria-label": `Remove ${token}`,
|
|
4070
|
+
onClick: () => removeToken(token),
|
|
4071
|
+
className: "cursor-pointer",
|
|
4072
|
+
children: /* @__PURE__ */ jsx9(Icon7, { name: "xmark", size: "xs" })
|
|
4073
|
+
}
|
|
4074
|
+
)
|
|
4075
|
+
] }, token)) }),
|
|
4076
|
+
/* @__PURE__ */ jsx9(
|
|
4077
|
+
Input2,
|
|
4078
|
+
{
|
|
4079
|
+
autoFocus: true,
|
|
4080
|
+
value: draft,
|
|
4081
|
+
placeholder: placeholder != null ? placeholder : "Type a value, press Enter\u2026",
|
|
4082
|
+
onChange: (e) => setDraft(e.target.value),
|
|
4083
|
+
onKeyDown: (e) => {
|
|
4084
|
+
if (e.key === "Enter") {
|
|
4085
|
+
e.preventDefault();
|
|
4086
|
+
addToken();
|
|
4087
|
+
} else if (e.key === "Backspace" && draft === "" && tokens.length > 0) {
|
|
4088
|
+
removeToken(tokens[tokens.length - 1]);
|
|
4089
|
+
}
|
|
4090
|
+
}
|
|
4091
|
+
}
|
|
4092
|
+
)
|
|
4093
|
+
] }) })
|
|
4094
|
+
] }),
|
|
4095
|
+
/* @__PURE__ */ jsx9(FilterChipRemoveButton, { label, onRemove })
|
|
4096
|
+
] });
|
|
4097
|
+
}
|
|
4098
|
+
function DateFilterChip({
|
|
4099
|
+
definition,
|
|
4100
|
+
value,
|
|
4101
|
+
autoOpen,
|
|
4102
|
+
onChangeValue,
|
|
4103
|
+
onRemove
|
|
4104
|
+
}) {
|
|
4105
|
+
const { label, includeTime } = definition;
|
|
4106
|
+
const { startDate, endDate } = asDateValue(value);
|
|
4107
|
+
const showTimeInputs = includeTime != null ? includeTime : hasExplicitTime(startDate) || hasExplicitTime(endDate);
|
|
4108
|
+
const displayLabel = !startDate ? "Any" : !endDate || startDate.getTime() === endDate.getTime() ? formatDateLabel(startDate) : `${formatDateLabel(startDate)} \u2013 ${formatDateLabel(endDate)}`;
|
|
4109
|
+
function pickRange(range) {
|
|
4110
|
+
var _a;
|
|
4111
|
+
if (!(range == null ? void 0 : range.from)) {
|
|
4112
|
+
onChangeValue({ startDate: null, endDate: null });
|
|
4113
|
+
return;
|
|
4114
|
+
}
|
|
4115
|
+
onChangeValue({ startDate: range.from, endDate: (_a = range.to) != null ? _a : range.from });
|
|
4116
|
+
}
|
|
4117
|
+
function pickStartTime(time) {
|
|
4118
|
+
if (!startDate) return;
|
|
4119
|
+
onChangeValue({ startDate: applyTimeToDate(startDate, time), endDate });
|
|
4120
|
+
}
|
|
4121
|
+
function pickEndTime(time) {
|
|
4122
|
+
if (!endDate) return;
|
|
4123
|
+
onChangeValue({ startDate, endDate: applyTimeToDate(endDate, time) });
|
|
4124
|
+
}
|
|
4125
|
+
return /* @__PURE__ */ jsxs8(ButtonGroup2, { children: [
|
|
4126
|
+
/* @__PURE__ */ jsx9(ButtonGroupText2, { children: label }),
|
|
4127
|
+
/* @__PURE__ */ jsxs8(Popover2, { defaultOpen: autoOpen, children: [
|
|
4128
|
+
/* @__PURE__ */ jsx9(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsx9(Button6, { variant: "outline", className: "gap-1 font-normal", children: /* @__PURE__ */ jsx9("span", { className: startDate ? "" : "text-muted-foreground", children: displayLabel }) }) }),
|
|
4129
|
+
/* @__PURE__ */ jsx9(PopoverContent2, { align: "start", className: "w-fit", children: /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-2", children: [
|
|
4130
|
+
/* @__PURE__ */ jsx9(
|
|
4131
|
+
Calendar2,
|
|
4132
|
+
{
|
|
4133
|
+
mode: "range",
|
|
4134
|
+
selected: { from: startDate != null ? startDate : void 0, to: endDate != null ? endDate : void 0 },
|
|
4135
|
+
onSelect: pickRange
|
|
4136
|
+
}
|
|
4137
|
+
),
|
|
4138
|
+
showTimeInputs && /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-2", children: [
|
|
4139
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex w-full items-center gap-2", children: [
|
|
4140
|
+
/* @__PURE__ */ jsx9(
|
|
4141
|
+
Label3,
|
|
4142
|
+
{
|
|
4143
|
+
htmlFor: `${definition.key}-start-time`,
|
|
4144
|
+
className: "text-body-sm text-muted-foreground w-10 shrink-0",
|
|
4145
|
+
children: "Start"
|
|
4146
|
+
}
|
|
4147
|
+
),
|
|
4148
|
+
/* @__PURE__ */ jsx9(
|
|
4149
|
+
Input2,
|
|
4150
|
+
{
|
|
4151
|
+
id: `${definition.key}-start-time`,
|
|
4152
|
+
type: "time",
|
|
4153
|
+
className: "w-full",
|
|
4154
|
+
value: formatTimeForInput(startDate),
|
|
4155
|
+
onChange: (e) => pickStartTime(e.target.value),
|
|
4156
|
+
disabled: !startDate
|
|
4157
|
+
}
|
|
4158
|
+
)
|
|
4159
|
+
] }),
|
|
4160
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex w-full items-center gap-2", children: [
|
|
4161
|
+
/* @__PURE__ */ jsx9(
|
|
4162
|
+
Label3,
|
|
4163
|
+
{
|
|
4164
|
+
htmlFor: `${definition.key}-end-time`,
|
|
4165
|
+
className: "text-body-sm text-muted-foreground w-10 shrink-0",
|
|
4166
|
+
children: "End"
|
|
4167
|
+
}
|
|
4168
|
+
),
|
|
4169
|
+
/* @__PURE__ */ jsx9(
|
|
4170
|
+
Input2,
|
|
4171
|
+
{
|
|
4172
|
+
id: `${definition.key}-end-time`,
|
|
4173
|
+
type: "time",
|
|
4174
|
+
className: "w-full",
|
|
4175
|
+
value: formatTimeForInput(endDate),
|
|
4176
|
+
onChange: (e) => pickEndTime(e.target.value),
|
|
4177
|
+
disabled: !endDate
|
|
4178
|
+
}
|
|
4179
|
+
)
|
|
4180
|
+
] })
|
|
4181
|
+
] })
|
|
4182
|
+
] }) })
|
|
4183
|
+
] }),
|
|
4184
|
+
/* @__PURE__ */ jsx9(FilterChipRemoveButton, { label, onRemove })
|
|
4185
|
+
] });
|
|
4186
|
+
}
|
|
4187
|
+
|
|
4188
|
+
// src/lib/data-table/filter-types.ts
|
|
4189
|
+
var isDateRangeColumnFilter = (definition) => definition.type === "dateRange";
|
|
4190
|
+
var isRadioColumnFilter = (definition) => definition.type === "radio" || definition.type === "scrollableRadio";
|
|
4191
|
+
var isCheckboxColumnFilter = (definition) => definition.type === "checkbox" || definition.type === "scrollableCheckbox";
|
|
4192
|
+
var isMultiTextColumnFilter = (definition) => definition.type === "multiText";
|
|
4193
|
+
|
|
4194
|
+
// src/data-table/view-filter.tsx
|
|
4195
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
4196
|
+
function toFilterOption(opt) {
|
|
4197
|
+
return typeof opt === "string" ? { value: opt, label: opt } : { value: opt.value, label: opt.label };
|
|
4198
|
+
}
|
|
4199
|
+
function toFilterBarDefinition(key, filter) {
|
|
4200
|
+
var _a;
|
|
4201
|
+
const base = { key, label: filter.title, order: (_a = filter.order) != null ? _a : 0 };
|
|
4202
|
+
if (isCheckboxColumnFilter(filter)) {
|
|
4203
|
+
const options = "options" in filter && filter.options ? filter.options : [];
|
|
4204
|
+
return __spreadProps(__spreadValues({}, base), {
|
|
4205
|
+
type: "checkbox",
|
|
4206
|
+
options: options.map(toFilterOption),
|
|
4207
|
+
searchable: filter.type === "scrollableCheckbox"
|
|
4208
|
+
});
|
|
4209
|
+
}
|
|
4210
|
+
if (isRadioColumnFilter(filter)) {
|
|
4211
|
+
return __spreadProps(__spreadValues({}, base), {
|
|
4212
|
+
type: "radio",
|
|
4213
|
+
options: filter.options.map(toFilterOption),
|
|
4214
|
+
searchable: filter.type === "scrollableRadio"
|
|
4215
|
+
});
|
|
4216
|
+
}
|
|
4217
|
+
if (isDateRangeColumnFilter(filter)) {
|
|
4218
|
+
return __spreadProps(__spreadValues({}, base), { type: "date", includeTime: filter.includeTime });
|
|
4219
|
+
}
|
|
4220
|
+
if (isMultiTextColumnFilter(filter)) {
|
|
4221
|
+
return __spreadProps(__spreadValues({}, base), { type: "multiText", placeholder: filter.placeholder });
|
|
4222
|
+
}
|
|
4223
|
+
return __spreadProps(__spreadValues({}, base), { type: "text", placeholder: filter.placeholder });
|
|
4224
|
+
}
|
|
4225
|
+
function emptyValueFor(filter) {
|
|
4226
|
+
if (isCheckboxColumnFilter(filter)) return [];
|
|
4227
|
+
if (isRadioColumnFilter(filter)) return void 0;
|
|
4228
|
+
if (isDateRangeColumnFilter(filter)) return { startDate: null, endDate: null };
|
|
4229
|
+
if (isMultiTextColumnFilter(filter)) return [];
|
|
4230
|
+
return void 0;
|
|
4231
|
+
}
|
|
4232
|
+
function ViewFilter({
|
|
4233
|
+
columns,
|
|
4234
|
+
columnFilters,
|
|
4235
|
+
onColumnFiltersChange,
|
|
4236
|
+
className
|
|
4237
|
+
}) {
|
|
4238
|
+
const filterableColumns = React7.useMemo(
|
|
4239
|
+
() => columns.filter((column) => !isFilterOnlyColumn(column) && column.getCanFilter()).flatMap((column) => {
|
|
4240
|
+
var _a;
|
|
4241
|
+
const filter = (_a = column.columnDef.meta) == null ? void 0 : _a.filter;
|
|
4242
|
+
return filter ? [{ key: column.id, filter }] : [];
|
|
4243
|
+
}),
|
|
4244
|
+
[columns]
|
|
4245
|
+
);
|
|
4246
|
+
const filterDefinitions = React7.useMemo(
|
|
4247
|
+
() => filterableColumns.map(({ key, filter }) => toFilterBarDefinition(key, filter)).sort((a, b) => a.order - b.order),
|
|
4248
|
+
[filterableColumns]
|
|
4249
|
+
);
|
|
4250
|
+
const emptyValueByKey = React7.useMemo(
|
|
4251
|
+
() => new Map(filterableColumns.map(({ key, filter }) => [key, emptyValueFor(filter)])),
|
|
4252
|
+
[filterableColumns]
|
|
4253
|
+
);
|
|
4254
|
+
const activeFilters = React7.useMemo(
|
|
4255
|
+
() => columnFilters.map((filter) => ({ key: filter.id, value: filter.value })),
|
|
4256
|
+
[columnFilters]
|
|
4257
|
+
);
|
|
4258
|
+
return /* @__PURE__ */ jsx10(
|
|
4259
|
+
FilterBar,
|
|
4260
|
+
{
|
|
4261
|
+
className,
|
|
4262
|
+
filters: filterDefinitions,
|
|
4263
|
+
activeFilters,
|
|
4264
|
+
onAddFilter: (key) => onColumnFiltersChange((prev) => [...prev.filter((f) => f.id !== key), { id: key, value: emptyValueByKey.get(key) }]),
|
|
4265
|
+
onRemoveFilter: (key) => onColumnFiltersChange((prev) => prev.filter((f) => f.id !== key)),
|
|
4266
|
+
onChangeFilter: (key, value) => onColumnFiltersChange((prev) => [...prev.filter((f) => f.id !== key), { id: key, value }])
|
|
4267
|
+
}
|
|
4268
|
+
);
|
|
4269
|
+
}
|
|
4270
|
+
|
|
4271
|
+
// src/section-header.tsx
|
|
4272
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
4273
|
+
function SectionHeader(_a) {
|
|
4274
|
+
var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
|
|
4275
|
+
return /* @__PURE__ */ jsx11(
|
|
4276
|
+
"div",
|
|
4277
|
+
__spreadProps(__spreadValues({
|
|
4278
|
+
"data-slot": "section-header",
|
|
4279
|
+
className: cn("flex w-full items-start justify-between gap-4", className)
|
|
4280
|
+
}, props), {
|
|
4281
|
+
children
|
|
4282
|
+
})
|
|
4283
|
+
);
|
|
4284
|
+
}
|
|
4285
|
+
function SectionHeaderContent(_a) {
|
|
4286
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
4287
|
+
return /* @__PURE__ */ jsx11("div", __spreadValues({ "data-slot": "section-header-content", className: cn("flex flex-col gap-1", className) }, props));
|
|
4288
|
+
}
|
|
4289
|
+
function SectionHeaderTitle(_a) {
|
|
4290
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
4291
|
+
return /* @__PURE__ */ jsx11("h2", __spreadValues({ "data-slot": "section-header-title", className: cn("text-h3 text-foreground", className) }, props));
|
|
4292
|
+
}
|
|
4293
|
+
function SectionHeaderDescription(_a) {
|
|
4294
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
4295
|
+
return /* @__PURE__ */ jsx11("p", __spreadValues({ "data-slot": "section-header-description", className: cn("text-body text-muted-foreground", className) }, props));
|
|
4296
|
+
}
|
|
4297
|
+
|
|
4298
|
+
// src/data-table/data-table.tsx
|
|
4299
|
+
import { Fragment as Fragment7, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
4300
|
+
var DEFAULT_PAGE_SIZE = 20;
|
|
4301
|
+
function DataTable({
|
|
4302
|
+
id,
|
|
4303
|
+
config,
|
|
4304
|
+
title,
|
|
4305
|
+
description,
|
|
4306
|
+
emptyView,
|
|
4307
|
+
showError,
|
|
4308
|
+
className,
|
|
4309
|
+
fitContent = false,
|
|
4310
|
+
loading = false,
|
|
4311
|
+
renderSkeletonCell,
|
|
4312
|
+
serverSidePagination = false,
|
|
4313
|
+
ActionsComponent: Actions,
|
|
4314
|
+
onRowRender,
|
|
4315
|
+
renderExpandedRow,
|
|
4316
|
+
expanded: parentExpanded,
|
|
4317
|
+
onExpandedChange: parentOnExpandedChange,
|
|
4318
|
+
disableSearch = false,
|
|
4319
|
+
disableFilters = false,
|
|
4320
|
+
disableSorting = false,
|
|
4321
|
+
paginationConfig = true,
|
|
4322
|
+
disableColumnReordering = false,
|
|
4323
|
+
disableColumnVisibility = false,
|
|
4324
|
+
disableColumnResizing = false,
|
|
4325
|
+
disableColumnPinning = false,
|
|
4326
|
+
searchTerm: parentGlobalFilter,
|
|
4327
|
+
onSearchTermChange: parentSetGlobalFilter,
|
|
4328
|
+
filters: parentColumnFilters,
|
|
4329
|
+
onFiltersChange: parentSetColumnFilters,
|
|
4330
|
+
pagination: parentPagination,
|
|
4331
|
+
onPaginationChange: parentSetPagination,
|
|
4332
|
+
sorting: parentSorting,
|
|
4333
|
+
onSortingChange: parentSetSorting,
|
|
4334
|
+
columnOrdering: parentColumnOrdering,
|
|
4335
|
+
onColumnOrderingChange: parentSetColumnOrdering,
|
|
4336
|
+
columnVisibility: parentColumnVisibility,
|
|
4337
|
+
onColumnVisibilityChange: parentSetColumnVisibility,
|
|
4338
|
+
columnPinning: parentColumnPinning,
|
|
4339
|
+
onColumnPinningChange: parentSetColumnPinning,
|
|
4340
|
+
grouping: parentGrouping,
|
|
4341
|
+
onGroupingChange: parentSetGrouping,
|
|
4342
|
+
celFilterClassName,
|
|
4343
|
+
showContextualFilter = false,
|
|
4344
|
+
onContextCell,
|
|
4345
|
+
contextualMenuActions,
|
|
4346
|
+
layout = "auto",
|
|
4347
|
+
initialColumnSizing,
|
|
4348
|
+
onColumnSizingPersist,
|
|
4349
|
+
stickyHeader = false,
|
|
4350
|
+
celFilterConfig
|
|
4351
|
+
}) {
|
|
4352
|
+
var _a, _b, _c, _d, _e, _f;
|
|
4353
|
+
const isGrid = layout === "grid";
|
|
4354
|
+
const tableBodyScrollRef = React8.useRef(null);
|
|
4355
|
+
const [innerGlobalFilter, setInnerGlobalFilter] = React8.useState("");
|
|
4356
|
+
const [innerColumnOrdering, setInnerColumnOrdering] = React8.useState([]);
|
|
4357
|
+
const [innerColumnFilters, setInnerColumnFilters] = React8.useState([]);
|
|
4358
|
+
const [innerSorting, setInnerSorting] = React8.useState(((_a = config.state) == null ? void 0 : _a.sorting) || []);
|
|
4359
|
+
const [innerColumnPinning, setInnerColumnPinning] = React8.useState({ left: [], right: [] });
|
|
4360
|
+
const [innerPagination, setInnerPagination] = React8.useState({
|
|
4361
|
+
pageIndex: ((_c = (_b = config.state) == null ? void 0 : _b.pagination) == null ? void 0 : _c.pageIndex) || 0,
|
|
4362
|
+
pageSize: ((_e = (_d = config.state) == null ? void 0 : _d.pagination) == null ? void 0 : _e.pageSize) || DEFAULT_PAGE_SIZE
|
|
4363
|
+
});
|
|
4364
|
+
const [innerGrouping, setInnerGrouping] = React8.useState([]);
|
|
4365
|
+
const [innerColumnVisibility, setInnerColumnVisibility] = React8.useState({});
|
|
4366
|
+
const [innerExpanded, setInnerExpanded] = React8.useState({});
|
|
4367
|
+
const {
|
|
4368
|
+
columnSizing,
|
|
4369
|
+
handleColumnSizingChange,
|
|
4370
|
+
handleAutosizeAll: rawHandleAutosizeAll,
|
|
4371
|
+
handleAutosizeColumn: rawHandleAutosizeColumn,
|
|
4372
|
+
handleResetColumnSize: rawHandleResetColumnSize
|
|
4373
|
+
} = useTableColumnResizing({
|
|
4374
|
+
initialSizing: initialColumnSizing,
|
|
4375
|
+
onColumnSizingPersist,
|
|
4376
|
+
maxSize: isGrid ? RESIZE_MAX_UNBOUNDED : void 0
|
|
4377
|
+
});
|
|
4378
|
+
const globalFilter = parentGlobalFilter != null ? parentGlobalFilter : innerGlobalFilter;
|
|
4379
|
+
const applyGlobalFilter = parentSetGlobalFilter != null ? parentSetGlobalFilter : setInnerGlobalFilter;
|
|
4380
|
+
const columnFilters = parentColumnFilters || innerColumnFilters;
|
|
4381
|
+
const applyColumnFilters = parentSetColumnFilters != null ? parentSetColumnFilters : setInnerColumnFilters;
|
|
4382
|
+
const pagination = parentPagination || innerPagination;
|
|
4383
|
+
const setPagination = parentSetPagination != null ? parentSetPagination : setInnerPagination;
|
|
4384
|
+
const shouldDisablePagination = paginationConfig === false;
|
|
4385
|
+
const resetPageIndexOnFilterChange = React8.useCallback(() => {
|
|
4386
|
+
if (!serverSidePagination || pagination.pageIndex === 0) return;
|
|
4387
|
+
setPagination((prev) => __spreadProps(__spreadValues({}, prev), { pageIndex: 0 }));
|
|
4388
|
+
}, [serverSidePagination, pagination.pageIndex, setPagination]);
|
|
4389
|
+
const setGlobalFilter = React8.useCallback(
|
|
4390
|
+
(value) => {
|
|
4391
|
+
applyGlobalFilter(value);
|
|
4392
|
+
resetPageIndexOnFilterChange();
|
|
4393
|
+
},
|
|
4394
|
+
[applyGlobalFilter, resetPageIndexOnFilterChange]
|
|
4395
|
+
);
|
|
4396
|
+
const setColumnFilters = React8.useCallback(
|
|
4397
|
+
(value) => {
|
|
4398
|
+
applyColumnFilters(value);
|
|
4399
|
+
resetPageIndexOnFilterChange();
|
|
4400
|
+
},
|
|
4401
|
+
[applyColumnFilters, resetPageIndexOnFilterChange]
|
|
4402
|
+
);
|
|
4403
|
+
React8.useLayoutEffect(() => {
|
|
4404
|
+
var _a2;
|
|
4405
|
+
if (shouldDisablePagination) return;
|
|
4406
|
+
(_a2 = tableBodyScrollRef.current) == null ? void 0 : _a2.scrollTo({ top: 0 });
|
|
4407
|
+
}, [shouldDisablePagination, pagination.pageIndex]);
|
|
4408
|
+
const sorting = parentSorting || innerSorting;
|
|
4409
|
+
const setSorting = parentSetSorting != null ? parentSetSorting : setInnerSorting;
|
|
4410
|
+
const columnOrdering = parentColumnOrdering || innerColumnOrdering;
|
|
4411
|
+
const setColumnOrdering = parentSetColumnOrdering != null ? parentSetColumnOrdering : setInnerColumnOrdering;
|
|
4412
|
+
const columnVisibility = parentColumnVisibility != null ? parentColumnVisibility : innerColumnVisibility;
|
|
4413
|
+
const setColumnVisibility = parentSetColumnVisibility != null ? parentSetColumnVisibility : setInnerColumnVisibility;
|
|
4414
|
+
const expanded = parentExpanded != null ? parentExpanded : innerExpanded;
|
|
4415
|
+
const setExpanded = parentOnExpandedChange != null ? parentOnExpandedChange : setInnerExpanded;
|
|
4416
|
+
const columnPinning = parentColumnPinning != null ? parentColumnPinning : innerColumnPinning;
|
|
4417
|
+
const setColumnPinning = parentSetColumnPinning != null ? parentSetColumnPinning : setInnerColumnPinning;
|
|
4418
|
+
const grouping = parentGrouping != null ? parentGrouping : innerGrouping;
|
|
4419
|
+
const setGrouping = parentSetGrouping != null ? parentSetGrouping : setInnerGrouping;
|
|
4420
|
+
const hasGrouping = grouping.length > 0;
|
|
4421
|
+
const hasExternalSearch = parentGlobalFilter !== void 0;
|
|
4422
|
+
const hasExternalFilters = parentColumnFilters !== void 0;
|
|
4423
|
+
const shouldDisableFiltersModels = !!disableFilters && !!disableSearch && !hasExternalSearch && !hasExternalFilters;
|
|
4424
|
+
const table = useReactTable(__spreadProps(__spreadValues(__spreadProps(__spreadValues(__spreadProps(__spreadValues({}, config), {
|
|
4425
|
+
getCoreRowModel: getCoreRowModel(),
|
|
4426
|
+
getSortedRowModel: !disableSorting ? getSortedRowModel() : void 0,
|
|
4427
|
+
getPaginationRowModel: !shouldDisablePagination ? getPaginationRowModel() : void 0,
|
|
4428
|
+
getFilteredRowModel: !shouldDisableFiltersModels ? getFilteredRowModel() : void 0,
|
|
4429
|
+
getFacetedRowModel: !shouldDisableFiltersModels ? getFacetedRowModel() : void 0,
|
|
4430
|
+
getFacetedUniqueValues: !shouldDisableFiltersModels ? getFacetedUniqueValues() : void 0
|
|
4431
|
+
}), !!renderExpandedRow && {
|
|
4432
|
+
getExpandedRowModel: getExpandedRowModel(),
|
|
4433
|
+
getRowCanExpand: () => true,
|
|
4434
|
+
paginateExpandedRows: false
|
|
4435
|
+
}), {
|
|
4436
|
+
getGroupedRowModel: hasGrouping ? getGroupedRowModel() : void 0,
|
|
4437
|
+
getExpandedRowModel: hasGrouping ? getExpandedRowModel() : void 0,
|
|
4438
|
+
groupedColumnMode: hasGrouping ? "reorder" : void 0,
|
|
4439
|
+
enableFilters: !shouldDisableFiltersModels,
|
|
4440
|
+
enableGlobalFilter: !shouldDisableFiltersModels,
|
|
4441
|
+
enableColumnFilters: !shouldDisableFiltersModels,
|
|
4442
|
+
enableColumnResizing: !disableColumnResizing,
|
|
4443
|
+
enableColumnPinning: !disableColumnPinning,
|
|
4444
|
+
enableHiding: !disableColumnVisibility,
|
|
4445
|
+
columnResizeMode: disableColumnResizing ? void 0 : isGrid ? "onEnd" : "onChange",
|
|
4446
|
+
defaultColumn: {
|
|
4447
|
+
size: 150,
|
|
4448
|
+
minSize: 40,
|
|
4449
|
+
maxSize: isGrid ? RESIZE_MAX_UNBOUNDED : 500
|
|
4450
|
+
},
|
|
4451
|
+
state: __spreadValues(__spreadProps(__spreadValues({
|
|
4452
|
+
sorting: disableSorting ? [] : sorting,
|
|
4453
|
+
globalFilter: shouldDisableFiltersModels ? "" : globalFilter,
|
|
4454
|
+
columnFilters: shouldDisableFiltersModels ? [] : columnFilters,
|
|
4455
|
+
pagination: shouldDisablePagination ? void 0 : pagination,
|
|
4456
|
+
columnOrder: disableColumnReordering ? [] : columnOrdering,
|
|
4457
|
+
columnVisibility: disableColumnVisibility ? {} : columnVisibility,
|
|
4458
|
+
columnSizing: disableColumnResizing ? {} : columnSizing,
|
|
4459
|
+
columnPinning: disableColumnPinning ? { left: [], right: [] } : columnPinning
|
|
4460
|
+
}, !!renderExpandedRow && { expanded }), {
|
|
4461
|
+
grouping
|
|
4462
|
+
}), hasGrouping && { expanded: true }),
|
|
4463
|
+
manualSorting: serverSidePagination,
|
|
4464
|
+
manualFiltering: serverSidePagination,
|
|
4465
|
+
manualPagination: serverSidePagination,
|
|
4466
|
+
onSortingChange: disableSorting ? noop : setSorting,
|
|
4467
|
+
onColumnFiltersChange: shouldDisableFiltersModels ? noop : setColumnFilters,
|
|
4468
|
+
onGlobalFilterChange: shouldDisableFiltersModels ? noop : setGlobalFilter,
|
|
4469
|
+
onPaginationChange: shouldDisablePagination ? noop : setPagination,
|
|
4470
|
+
onColumnOrderChange: disableColumnReordering ? noop : setColumnOrdering,
|
|
4471
|
+
onColumnVisibilityChange: disableColumnVisibility ? noop : setColumnVisibility,
|
|
4472
|
+
onColumnSizingChange: disableColumnResizing ? noop : handleColumnSizingChange,
|
|
4473
|
+
onColumnPinningChange: disableColumnPinning ? noop : setColumnPinning
|
|
4474
|
+
}), !!renderExpandedRow && {
|
|
4475
|
+
onExpandedChange: (updater) => setExpanded((prev) => typeof updater === "function" ? updater(prev) : updater)
|
|
4476
|
+
}), {
|
|
4477
|
+
onGroupingChange: setGrouping
|
|
4478
|
+
}));
|
|
4479
|
+
const headerGroups = table.getHeaderGroups();
|
|
4480
|
+
const tableRows = table.getRowModel().rows;
|
|
4481
|
+
const rowCount = table.getRowCount();
|
|
4482
|
+
const flatColumns = table.getAllFlatColumns();
|
|
4483
|
+
const displayableColumns = flatColumns.filter((col) => !isFilterOnlyColumn(col));
|
|
4484
|
+
const orderedVisibleColumns = table.getVisibleLeafColumns().filter((col) => !isFilterOnlyColumn(col));
|
|
4485
|
+
const [gridMeasuredMins, setGridMeasuredMins] = React8.useState({});
|
|
4486
|
+
const { gridTemplateColumns, gridRootRef, handleAutosizeAll, handleAutosizeColumn, handleResetColumnSize } = useGridLayout({
|
|
4487
|
+
layout,
|
|
4488
|
+
table,
|
|
4489
|
+
tableBodyScrollRef,
|
|
4490
|
+
displayableColumns,
|
|
4491
|
+
columnOrdering,
|
|
4492
|
+
gridMeasuredMins,
|
|
4493
|
+
setGridMeasuredMins,
|
|
4494
|
+
handleColumnSizingChange,
|
|
4495
|
+
rawHandleAutosizeAll,
|
|
4496
|
+
rawHandleAutosizeColumn,
|
|
4497
|
+
rawHandleResetColumnSize
|
|
4498
|
+
});
|
|
4499
|
+
const handleContextCell = React8.useCallback(
|
|
4500
|
+
(filter, cell) => {
|
|
4501
|
+
var _a2, _b2;
|
|
4502
|
+
if (celFilterConfig == null ? void 0 : celFilterConfig.onContextualFilter) {
|
|
4503
|
+
celFilterConfig.onContextualFilter({
|
|
4504
|
+
columnId: filter.id,
|
|
4505
|
+
values: columnFilterValueToStrings(filter.value),
|
|
4506
|
+
cell
|
|
4507
|
+
});
|
|
4508
|
+
return;
|
|
4509
|
+
}
|
|
4510
|
+
const filterDefinition = (_b2 = (_a2 = table.getColumn(filter.id)) == null ? void 0 : _a2.columnDef.meta) == null ? void 0 : _b2.filter;
|
|
4511
|
+
setColumnFilters((prev) => mergeColumnFilter(prev, filter, filterDefinition));
|
|
4512
|
+
onContextCell == null ? void 0 : onContextCell(filter, cell);
|
|
4513
|
+
},
|
|
4514
|
+
[celFilterConfig, onContextCell, setColumnFilters, table]
|
|
4515
|
+
);
|
|
4516
|
+
const handleContextSearch = React8.useCallback(
|
|
4517
|
+
(searchTerm) => {
|
|
4518
|
+
setGlobalFilter(searchTerm);
|
|
4519
|
+
},
|
|
4520
|
+
[setGlobalFilter]
|
|
4521
|
+
);
|
|
4522
|
+
const totalTableWidth = React8.useMemo(() => {
|
|
4523
|
+
if (isGrid) return 0;
|
|
4524
|
+
const firstGroup = headerGroups[0];
|
|
4525
|
+
if (!firstGroup) return 0;
|
|
4526
|
+
const displayableIds = new Set(displayableColumns.map((c) => c.id));
|
|
4527
|
+
return firstGroup.headers.filter((h) => displayableIds.has(h.column.id)).reduce((sum, h) => sum + h.column.getSize(), 0);
|
|
4528
|
+
}, [isGrid, headerGroups, displayableColumns]);
|
|
4529
|
+
const filterCount = celFilterConfig ? celFilterConfig.activeFilterCount : table.getState().columnFilters.map(
|
|
4530
|
+
({ id: columnFilterId, value }) => {
|
|
4531
|
+
var _a2, _b2;
|
|
4532
|
+
return getColumnFilterCount(value, (_b2 = (_a2 = table.getColumn(columnFilterId)) == null ? void 0 : _a2.columnDef.meta) == null ? void 0 : _b2.filter);
|
|
4533
|
+
}
|
|
4534
|
+
).reduce((prev, curr) => prev + curr, 0);
|
|
4535
|
+
const tableState = getTableState({ error: !!showError, loading, rowCount });
|
|
4536
|
+
const shouldDisable = tableState === "error";
|
|
4537
|
+
const shouldRenderTableContent = tableState !== "error" && tableState !== "empty";
|
|
4538
|
+
const resetFilters = () => {
|
|
4539
|
+
if (celFilterConfig) {
|
|
4540
|
+
celFilterConfig.onTreeChange(createEmptyCelFilterTree());
|
|
4541
|
+
} else {
|
|
4542
|
+
table.resetColumnFilters();
|
|
4543
|
+
}
|
|
4544
|
+
setGlobalFilter("");
|
|
4545
|
+
};
|
|
4546
|
+
React8.useEffect(() => {
|
|
4547
|
+
if (parentGlobalFilter !== void 0) {
|
|
4548
|
+
setInnerGlobalFilter(parentGlobalFilter);
|
|
4549
|
+
}
|
|
4550
|
+
}, [parentGlobalFilter]);
|
|
4551
|
+
React8.useEffect(() => {
|
|
4552
|
+
if (disableColumnReordering) return;
|
|
4553
|
+
const allColumnIds = flatColumns.map((col) => col.id);
|
|
4554
|
+
const normalizedColumnOrdering = normalizeColumnOrdering(columnOrdering, allColumnIds);
|
|
4555
|
+
if (!isSameColumnOrdering(columnOrdering, normalizedColumnOrdering)) {
|
|
4556
|
+
setColumnOrdering(normalizedColumnOrdering);
|
|
4557
|
+
}
|
|
4558
|
+
}, [columnOrdering, disableColumnReordering, flatColumns, setColumnOrdering]);
|
|
4559
|
+
const showViewHeader = !!title || !!Actions;
|
|
4560
|
+
const showColumnOptions = !disableColumnReordering || !disableColumnVisibility;
|
|
4561
|
+
const toolbarSearch = !disableSearch && /* @__PURE__ */ jsxs9(InputGroup2, { className: "w-70", children: [
|
|
4562
|
+
/* @__PURE__ */ jsx12(InputGroupAddon2, { align: "inline-start", children: /* @__PURE__ */ jsx12(Icon8, { name: "magnifying-glass" }) }),
|
|
4563
|
+
/* @__PURE__ */ jsx12(
|
|
4564
|
+
InputGroupInput2,
|
|
4565
|
+
{
|
|
4566
|
+
"aria-label": "Search",
|
|
4567
|
+
placeholder: "Search\u2026",
|
|
4568
|
+
disabled: shouldDisable,
|
|
4569
|
+
value: globalFilter,
|
|
4570
|
+
onChange: (e) => setGlobalFilter(e.target.value)
|
|
4571
|
+
}
|
|
4572
|
+
)
|
|
4573
|
+
] });
|
|
4574
|
+
const toolbarColumns = !!showColumnOptions && /* @__PURE__ */ jsx12(
|
|
4575
|
+
ColumnOptions,
|
|
4576
|
+
{
|
|
4577
|
+
columns: flatColumns,
|
|
4578
|
+
columnOrdering,
|
|
4579
|
+
onColumnOrderingChange: setColumnOrdering,
|
|
4580
|
+
disableColumnOrdering: disableColumnReordering
|
|
4581
|
+
}
|
|
4582
|
+
);
|
|
4583
|
+
return /* @__PURE__ */ jsxs9(
|
|
4584
|
+
"div",
|
|
4585
|
+
{
|
|
4586
|
+
id: `table-${id}`,
|
|
4587
|
+
"data-testid": `table-${id}`,
|
|
4588
|
+
className: cn(
|
|
4589
|
+
"flex w-full flex-col",
|
|
4590
|
+
!fitContent && (shouldRenderTableContent ? "h-full min-h-0" : "h-screen max-h-[calc(100vh-100px)]"),
|
|
4591
|
+
className
|
|
4592
|
+
),
|
|
4593
|
+
children: [
|
|
4594
|
+
showViewHeader && /* @__PURE__ */ jsx12(SectionHeader, { className: "mb-4 flex w-full gap-2", children: /* @__PURE__ */ jsxs9(SectionHeaderContent, { children: [
|
|
4595
|
+
!!title && /* @__PURE__ */ jsx12(SectionHeaderTitle, { children: title }),
|
|
4596
|
+
!!description && /* @__PURE__ */ jsx12(SectionHeaderDescription, { children: description })
|
|
4597
|
+
] }) }),
|
|
4598
|
+
/* @__PURE__ */ jsxs9("div", { className: "mb-4 flex flex-row gap-2", children: [
|
|
4599
|
+
toolbarSearch,
|
|
4600
|
+
/* @__PURE__ */ jsxs9("div", { className: "ml-auto flex items-center gap-2", children: [
|
|
4601
|
+
!!Actions && /* @__PURE__ */ jsx12(Actions, { state: tableState }),
|
|
4602
|
+
toolbarColumns
|
|
4603
|
+
] })
|
|
4604
|
+
] }),
|
|
4605
|
+
!disableFilters && /* @__PURE__ */ jsx12("div", { className: "flex w-full", children: celFilterConfig ? /* @__PURE__ */ jsx12("div", { className: cn("mr-2 mb-4 min-w-0 flex-1", celFilterClassName), children: /* @__PURE__ */ jsx12(
|
|
4606
|
+
CelFilterBar,
|
|
4607
|
+
{
|
|
4608
|
+
schema: celFilterConfig.schema,
|
|
4609
|
+
tree: celFilterConfig.tree,
|
|
4610
|
+
onChange: celFilterConfig.onTreeChange,
|
|
4611
|
+
onCompileResultChange: celFilterConfig.onCompileResultChange,
|
|
4612
|
+
onRestrictedOptionSelect: celFilterConfig.onRestrictedOptionSelect,
|
|
4613
|
+
showClearButton: celFilterConfig.showClearButton
|
|
4614
|
+
}
|
|
4615
|
+
) }) : /* @__PURE__ */ jsx12(
|
|
4616
|
+
ViewFilter,
|
|
4617
|
+
{
|
|
4618
|
+
columns: flatColumns,
|
|
4619
|
+
columnFilters,
|
|
4620
|
+
onColumnFiltersChange: setColumnFilters,
|
|
4621
|
+
className: "data-[visible-filters=true]:mb-4"
|
|
4622
|
+
}
|
|
4623
|
+
) }),
|
|
4624
|
+
shouldRenderTableContent ? /* @__PURE__ */ jsxs9(Fragment7, { children: [
|
|
4625
|
+
/* @__PURE__ */ jsx12("div", { className: "flex min-h-0 flex-1 flex-col", "data-testid": "table-main", children: /* @__PURE__ */ jsx12(
|
|
4626
|
+
"div",
|
|
4627
|
+
{
|
|
4628
|
+
ref: tableBodyScrollRef,
|
|
4629
|
+
className: cn(
|
|
4630
|
+
"min-h-0 flex-1 overflow-auto rounded-lg border **:data-[slot=table-container]:overflow-visible",
|
|
4631
|
+
!!stickyHeader && "max-h-[calc(100svh-250px)]"
|
|
4632
|
+
),
|
|
4633
|
+
children: /* @__PURE__ */ jsxs9(
|
|
4634
|
+
DataTableRoot,
|
|
4635
|
+
{
|
|
4636
|
+
layout,
|
|
4637
|
+
gridTemplateColumns,
|
|
4638
|
+
gridRootRef,
|
|
4639
|
+
style: isGrid ? { width: "100%" } : totalTableWidth > 0 ? { width: `max(100%, ${totalTableWidth}px)`, minWidth: "100%" } : { width: "100%" },
|
|
4640
|
+
children: [
|
|
4641
|
+
/* @__PURE__ */ jsx12(
|
|
4642
|
+
DataTableHeader,
|
|
4643
|
+
{
|
|
4644
|
+
headerGroups,
|
|
4645
|
+
onAutosizeAll: handleAutosizeAll,
|
|
4646
|
+
onAutosizeColumn: handleAutosizeColumn,
|
|
4647
|
+
onResetColumnSize: handleResetColumnSize,
|
|
4648
|
+
stickyHeader,
|
|
4649
|
+
layout
|
|
4650
|
+
}
|
|
4651
|
+
),
|
|
4652
|
+
/* @__PURE__ */ jsx12(
|
|
4653
|
+
DataTableBody,
|
|
4654
|
+
{
|
|
4655
|
+
tableRows,
|
|
4656
|
+
tableState,
|
|
4657
|
+
columns: orderedVisibleColumns,
|
|
4658
|
+
skeletonRowCount: pagination.pageSize,
|
|
4659
|
+
renderSkeletonCell,
|
|
4660
|
+
onRowRender,
|
|
4661
|
+
renderExpandedRow,
|
|
4662
|
+
showContextualFilter,
|
|
4663
|
+
onContextCell: handleContextCell,
|
|
4664
|
+
onContextSearch: handleContextSearch,
|
|
4665
|
+
contextualMenuActions,
|
|
4666
|
+
layout
|
|
4667
|
+
}
|
|
4668
|
+
)
|
|
4669
|
+
]
|
|
4670
|
+
}
|
|
4671
|
+
)
|
|
4672
|
+
}
|
|
4673
|
+
) }),
|
|
4674
|
+
!shouldDisablePagination && !!pagination && /* @__PURE__ */ jsx12(
|
|
4675
|
+
DataTablePagination,
|
|
4676
|
+
{
|
|
4677
|
+
rowCount,
|
|
4678
|
+
rowCountRelation: (_f = config.rowCountRelation) != null ? _f : "eq",
|
|
4679
|
+
paginationConfig,
|
|
4680
|
+
pageSize: pagination.pageSize,
|
|
4681
|
+
pageIndex: pagination.pageIndex,
|
|
4682
|
+
onPageChange: (p) => table.setPageIndex(p - 1),
|
|
4683
|
+
onPageSizeChange: (nextPageSize) => setPagination((prev) => __spreadProps(__spreadValues({}, prev || pagination), { pageIndex: 0, pageSize: nextPageSize }))
|
|
4684
|
+
}
|
|
4685
|
+
)
|
|
4686
|
+
] }) : /* @__PURE__ */ jsx12(
|
|
4687
|
+
DataTableEmptyView,
|
|
4688
|
+
{
|
|
4689
|
+
emptyView,
|
|
4690
|
+
tableState,
|
|
4691
|
+
filterCount: filterCount + (!!globalFilter.trim() ? 1 : 0),
|
|
4692
|
+
resetFilters
|
|
4693
|
+
}
|
|
4694
|
+
)
|
|
4695
|
+
]
|
|
4696
|
+
}
|
|
4697
|
+
);
|
|
4698
|
+
}
|
|
4699
|
+
export {
|
|
4700
|
+
CellContextualFilter,
|
|
4701
|
+
ColumnOptions,
|
|
4702
|
+
DataTable,
|
|
4703
|
+
DataTableBody,
|
|
4704
|
+
DataTableCell,
|
|
4705
|
+
DataTableEmptyView,
|
|
4706
|
+
DataTableExpandedRow,
|
|
4707
|
+
DataTableGroupRow,
|
|
4708
|
+
DataTableHeader,
|
|
4709
|
+
DataTablePagination,
|
|
4710
|
+
DataTableRow,
|
|
4711
|
+
DataTableSkeletonBody,
|
|
4712
|
+
DataTableValueCell,
|
|
4713
|
+
ExpandButton,
|
|
4714
|
+
RowActionItem,
|
|
4715
|
+
RowActions,
|
|
4716
|
+
TimestampCell,
|
|
4717
|
+
ViewFilter,
|
|
4718
|
+
defaultEmptyConfig,
|
|
4719
|
+
defaultErrorConfig,
|
|
4720
|
+
defaultNoFilterFoundConfig,
|
|
4721
|
+
getActionsColumnDefinition,
|
|
4722
|
+
getExpandColumnDefinition,
|
|
4723
|
+
normalizePageSizeOptions
|
|
4724
|
+
};
|
|
4725
|
+
//# sourceMappingURL=data-table.js.map
|