@acmekit/dashboard 2.13.7 → 2.13.8

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.
Files changed (60) hide show
  1. package/dist/api-key-management-create-D57V3NN2.mjs +170 -0
  2. package/dist/api-key-management-detail-QURSBB6T.mjs +307 -0
  3. package/dist/api-key-management-edit-GG5V77GY.mjs +106 -0
  4. package/dist/api-key-management-list-PL64LD22.mjs +400 -0
  5. package/dist/app.js +16930 -1004
  6. package/dist/app.mjs +793 -884
  7. package/dist/chunk-22YYMH6M.mjs +382 -0
  8. package/dist/chunk-2U3RK3JG.mjs +474 -0
  9. package/dist/chunk-535OVBXR.mjs +226 -0
  10. package/dist/chunk-6SQCO25J.mjs +65 -0
  11. package/dist/chunk-774WSTCC.mjs +19 -0
  12. package/dist/chunk-7ZHDHEUH.mjs +1837 -0
  13. package/dist/chunk-C76H5USB.mjs +16 -0
  14. package/dist/chunk-DFFLVEZ5.mjs +40 -0
  15. package/dist/chunk-DN3MIYQH.mjs +140 -0
  16. package/dist/chunk-DQCEH3X2.mjs +28 -0
  17. package/dist/chunk-DTY37DDZ.mjs +20 -0
  18. package/dist/chunk-FXYH54JP.mjs +16 -0
  19. package/dist/chunk-G22WWLPG.mjs +44 -0
  20. package/dist/chunk-G2VJOHHV.mjs +32 -0
  21. package/dist/chunk-GBFVWROS.mjs +58 -0
  22. package/dist/chunk-ITNQKZQQ.mjs +142 -0
  23. package/dist/chunk-IUCDCPJU.mjs +0 -0
  24. package/dist/chunk-LKWTBYYC.mjs +35 -0
  25. package/dist/{chunk-4VYJHIB3.mjs → chunk-ND3ODI36.mjs} +0 -72
  26. package/dist/chunk-OAHCJFG3.mjs +17 -0
  27. package/dist/chunk-OHAFITSB.mjs +54 -0
  28. package/dist/chunk-RPAL6FHW.mjs +73 -0
  29. package/dist/{chunk-JSJZMTQG.mjs → chunk-RREPQMYC.mjs} +14 -41
  30. package/dist/chunk-S3REQHPQ.mjs +86 -0
  31. package/dist/chunk-S4DMV3ZT.mjs +35 -0
  32. package/dist/chunk-TCNCAWYD.mjs +9 -0
  33. package/dist/chunk-ULSPL3DR.mjs +126 -0
  34. package/dist/chunk-VBT5YZ4K.mjs +129 -0
  35. package/dist/chunk-WILMJYUB.mjs +35 -0
  36. package/dist/chunk-XIM7X4FB.mjs +83 -0
  37. package/dist/chunk-YB52HEIR.mjs +387 -0
  38. package/dist/chunk-YRWSG3YM.mjs +80 -0
  39. package/dist/{invite-S5USGDOZ.mjs → invite-BAFXQBLJ.mjs} +15 -7
  40. package/dist/{login-AIMR26AL.mjs → login-YURMNRCS.mjs} +23 -9
  41. package/dist/profile-detail-SJWODS2K.mjs +96 -0
  42. package/dist/profile-edit-HSGF4UXZ.mjs +173 -0
  43. package/dist/{reset-password-UQPRHMB3.mjs → reset-password-RQ5M7HQC.mjs} +8 -4
  44. package/dist/settings-3XWLL5LG.mjs +545 -0
  45. package/dist/store-detail-SQKV5KBD.mjs +109 -0
  46. package/dist/store-edit-WGGIJMYJ.mjs +97 -0
  47. package/dist/store-metadata-CSBUGX6Z.mjs +49 -0
  48. package/dist/translation-list-H5X4DVCC.mjs +587 -0
  49. package/dist/translations-edit-NPAUN2GZ.mjs +5376 -0
  50. package/dist/user-detail-7SUQ35G7.mjs +169 -0
  51. package/dist/user-edit-KUZV37AH.mjs +114 -0
  52. package/dist/user-invite-OREFWWYL.mjs +361 -0
  53. package/dist/user-list-OWUR75OP.mjs +1116 -0
  54. package/dist/user-metadata-QHUX5SHZ.mjs +51 -0
  55. package/dist/workflow-execution-detail-MWNM25TF.mjs +820 -0
  56. package/dist/workflow-execution-list-IGYF44UH.mjs +175 -0
  57. package/package.json +9 -9
  58. package/src/components/layout/settings-layout/settings-layout.tsx +8 -2
  59. package/dist/chunk-FBTP4AJM.mjs +0 -221
  60. package/dist/chunk-QYOO4QR6.mjs +0 -73
@@ -0,0 +1,1837 @@
1
+ import {
2
+ TableSkeleton
3
+ } from "./chunk-ITNQKZQQ.mjs";
4
+ import {
5
+ useDate
6
+ } from "./chunk-DFFLVEZ5.mjs";
7
+ import {
8
+ useDocumentDirection
9
+ } from "./chunk-S4DMV3ZT.mjs";
10
+
11
+ // src/components/table/data-table/data-table.tsx
12
+ import { clx as clx9 } from "@acmekit/ui";
13
+ import { memo } from "react";
14
+
15
+ // src/components/common/empty-table-content/empty-table-content.tsx
16
+ import { ExclamationCircle, MagnifyingGlass, PlusMini } from "@acmekit/icons";
17
+ import { Button, Text, clx } from "@acmekit/ui";
18
+ import { useTranslation } from "react-i18next";
19
+ import { Link } from "react-router-dom";
20
+ import { jsx, jsxs } from "react/jsx-runtime";
21
+ var NoResults = ({ title, message, className }) => {
22
+ const { t: t2 } = useTranslation();
23
+ return /* @__PURE__ */ jsx(
24
+ "div",
25
+ {
26
+ className: clx(
27
+ "flex h-[400px] w-full items-center justify-center",
28
+ className
29
+ ),
30
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-y-2", children: [
31
+ /* @__PURE__ */ jsx(MagnifyingGlass, {}),
32
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", weight: "plus", children: title ?? t2("general.noResultsTitle") }),
33
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: message ?? t2("general.noResultsMessage") })
34
+ ] })
35
+ }
36
+ );
37
+ };
38
+ var DefaultButton = ({ action }) => action && /* @__PURE__ */ jsx(Link, { to: action.to, children: /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", children: action.label }) });
39
+ var TransparentIconLeftButton = ({ action }) => action && /* @__PURE__ */ jsx(Link, { to: action.to, children: /* @__PURE__ */ jsxs(Button, { variant: "transparent", className: "text-ui-fg-interactive", children: [
40
+ /* @__PURE__ */ jsx(PlusMini, {}),
41
+ " ",
42
+ action.label
43
+ ] }) });
44
+ var NoRecords = ({
45
+ title,
46
+ message,
47
+ action,
48
+ className,
49
+ buttonVariant = "default",
50
+ icon = /* @__PURE__ */ jsx(ExclamationCircle, { className: "text-ui-fg-subtle" })
51
+ }) => {
52
+ const { t: t2 } = useTranslation();
53
+ return /* @__PURE__ */ jsxs(
54
+ "div",
55
+ {
56
+ className: clx(
57
+ "flex h-[150px] w-full flex-col items-center justify-center gap-y-4",
58
+ className
59
+ ),
60
+ children: [
61
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-y-3", children: [
62
+ icon,
63
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-y-1", children: [
64
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", weight: "plus", children: title ?? t2("general.noRecordsTitle") }),
65
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: message ?? t2("general.noRecordsMessage") })
66
+ ] })
67
+ ] }),
68
+ buttonVariant === "default" && /* @__PURE__ */ jsx(DefaultButton, { action }),
69
+ buttonVariant === "transparentIconLeft" && /* @__PURE__ */ jsx(TransparentIconLeftButton, { action })
70
+ ]
71
+ }
72
+ );
73
+ };
74
+
75
+ // src/components/table/data-table/data-table-filter/data-table-filter.tsx
76
+ import { Button as Button2, clx as clx7 } from "@acmekit/ui";
77
+ import { Popover as RadixPopover6 } from "radix-ui";
78
+ import { useCallback as useCallback3, useEffect as useEffect3, useMemo as useMemo2, useRef, useState as useState5 } from "react";
79
+ import { useSearchParams as useSearchParams2 } from "react-router-dom";
80
+ import { useTranslation as useTranslation6 } from "react-i18next";
81
+
82
+ // src/components/table/data-table/data-table-filter/context.tsx
83
+ import { createContext, useContext } from "react";
84
+ var DataTableFilterContext = createContext(null);
85
+ var useDataTableFilterContext = () => {
86
+ const ctx = useContext(DataTableFilterContext);
87
+ if (!ctx) {
88
+ throw new Error(
89
+ "useDataTableFacetedFilterContext must be used within a DataTableFacetedFilter"
90
+ );
91
+ }
92
+ return ctx;
93
+ };
94
+
95
+ // src/components/table/data-table/data-table-filter/date-filter.tsx
96
+ import { EllipseMiniSolid } from "@acmekit/icons";
97
+ import { DatePicker, Text as Text3, clx as clx3 } from "@acmekit/ui";
98
+ import isEqual from "lodash.isequal";
99
+ import { Popover as RadixPopover2 } from "radix-ui";
100
+ import { useMemo, useState } from "react";
101
+ import { t } from "i18next";
102
+ import { useTranslation as useTranslation3 } from "react-i18next";
103
+
104
+ // src/components/table/data-table/hooks.tsx
105
+ import { useSearchParams } from "react-router-dom";
106
+ var useSelectedParams = ({
107
+ param,
108
+ prefix,
109
+ multiple = false
110
+ }) => {
111
+ const [searchParams, setSearchParams] = useSearchParams();
112
+ const identifier = prefix ? `${prefix}_${param}` : param;
113
+ const offsetKey = prefix ? `${prefix}_offset` : "offset";
114
+ const add = (value) => {
115
+ setSearchParams((prev) => {
116
+ const newValue = new URLSearchParams(prev);
117
+ const updateMultipleValues = () => {
118
+ const existingValues = newValue.get(identifier)?.split(",") || [];
119
+ if (!existingValues.includes(value)) {
120
+ existingValues.push(value);
121
+ newValue.set(identifier, existingValues.join(","));
122
+ }
123
+ };
124
+ const updateSingleValue = () => {
125
+ newValue.set(identifier, value);
126
+ };
127
+ multiple ? updateMultipleValues() : updateSingleValue();
128
+ newValue.delete(offsetKey);
129
+ return newValue;
130
+ });
131
+ };
132
+ const deleteParam = (value) => {
133
+ const deleteMultipleValues = (prev) => {
134
+ const existingValues = prev.get(identifier)?.split(",") || [];
135
+ const index = existingValues.indexOf(value || "");
136
+ if (index > -1) {
137
+ existingValues.splice(index, 1);
138
+ prev.set(identifier, existingValues.join(","));
139
+ }
140
+ };
141
+ const deleteSingleValue = (prev) => {
142
+ prev.delete(identifier);
143
+ };
144
+ setSearchParams((prev) => {
145
+ if (value) {
146
+ multiple ? deleteMultipleValues(prev) : deleteSingleValue(prev);
147
+ if (!prev.get(identifier)) {
148
+ prev.delete(identifier);
149
+ }
150
+ } else {
151
+ prev.delete(identifier);
152
+ }
153
+ prev.delete(offsetKey);
154
+ return prev;
155
+ });
156
+ };
157
+ const get = () => {
158
+ return searchParams.get(identifier)?.split(",").filter(Boolean) || [];
159
+ };
160
+ return { add, delete: deleteParam, get };
161
+ };
162
+
163
+ // src/components/table/data-table/data-table-filter/filter-chip.tsx
164
+ import { XMarkMini } from "@acmekit/icons";
165
+ import { Text as Text2, clx as clx2 } from "@acmekit/ui";
166
+ import { Popover as RadixPopover } from "radix-ui";
167
+ import { useTranslation as useTranslation2 } from "react-i18next";
168
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
169
+ var FilterChip = ({
170
+ hadPreviousValue,
171
+ label,
172
+ value,
173
+ readonly,
174
+ hasOperator,
175
+ onRemove
176
+ }) => {
177
+ const { t: t2 } = useTranslation2();
178
+ const handleRemove = (e) => {
179
+ e.stopPropagation();
180
+ onRemove();
181
+ };
182
+ return /* @__PURE__ */ jsxs2("div", { className: "bg-ui-bg-field transition-fg shadow-borders-base text-ui-fg-subtle flex cursor-default select-none items-stretch overflow-hidden rounded-md", children: [
183
+ !hadPreviousValue && /* @__PURE__ */ jsx2(RadixPopover.Anchor, {}),
184
+ /* @__PURE__ */ jsx2(
185
+ "div",
186
+ {
187
+ className: clx2(
188
+ "flex items-center justify-center whitespace-nowrap px-2 py-1",
189
+ {
190
+ "border-r": !!(value || hadPreviousValue)
191
+ }
192
+ ),
193
+ children: /* @__PURE__ */ jsx2(Text2, { size: "small", weight: "plus", leading: "compact", children: label })
194
+ }
195
+ ),
196
+ /* @__PURE__ */ jsxs2("div", { className: "flex w-full items-center overflow-hidden", children: [
197
+ hasOperator && !!(value || hadPreviousValue) && /* @__PURE__ */ jsx2("div", { className: "border-r p-1 px-2", children: /* @__PURE__ */ jsx2(
198
+ Text2,
199
+ {
200
+ size: "small",
201
+ weight: "plus",
202
+ leading: "compact",
203
+ className: "text-ui-fg-muted",
204
+ children: t2("general.is")
205
+ }
206
+ ) }),
207
+ !!(value || hadPreviousValue) && /* @__PURE__ */ jsx2(
208
+ RadixPopover.Trigger,
209
+ {
210
+ asChild: true,
211
+ className: clx2(
212
+ "flex-1 cursor-pointer overflow-hidden border-r p-1 px-2",
213
+ {
214
+ "hover:bg-ui-bg-field-hover": !readonly,
215
+ "data-[state=open]:bg-ui-bg-field-hover": !readonly
216
+ }
217
+ ),
218
+ children: /* @__PURE__ */ jsx2(
219
+ Text2,
220
+ {
221
+ size: "small",
222
+ leading: "compact",
223
+ weight: "plus",
224
+ className: "truncate text-nowrap",
225
+ children: value || "\xA0"
226
+ }
227
+ )
228
+ }
229
+ )
230
+ ] }),
231
+ !readonly && !!(value || hadPreviousValue) && /* @__PURE__ */ jsx2(
232
+ "button",
233
+ {
234
+ onClick: handleRemove,
235
+ className: clx2(
236
+ "text-ui-fg-muted transition-fg flex items-center justify-center p-1",
237
+ "hover:bg-ui-bg-subtle-hover",
238
+ "active:bg-ui-bg-subtle-pressed active:text-ui-fg-base"
239
+ ),
240
+ children: /* @__PURE__ */ jsx2(XMarkMini, {})
241
+ }
242
+ )
243
+ ] });
244
+ };
245
+ var filter_chip_default = FilterChip;
246
+
247
+ // src/components/table/data-table/data-table-filter/date-filter.tsx
248
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
249
+ var DateFilter = ({
250
+ filter,
251
+ prefix,
252
+ readonly,
253
+ openOnMount
254
+ }) => {
255
+ const [open, setOpen] = useState(openOnMount);
256
+ const [showCustom, setShowCustom] = useState(false);
257
+ const { getFullDate } = useDate();
258
+ const { key, label } = filter;
259
+ const { removeFilter } = useDataTableFilterContext();
260
+ const selectedParams = useSelectedParams({ param: key, prefix });
261
+ const presets = usePresets();
262
+ const handleSelectPreset = (value) => {
263
+ selectedParams.add(JSON.stringify(value));
264
+ setShowCustom(false);
265
+ };
266
+ const handleSelectCustom = () => {
267
+ selectedParams.delete();
268
+ setShowCustom((prev) => !prev);
269
+ };
270
+ const currentValue = selectedParams.get();
271
+ const currentDateComparison = parseDateComparison(currentValue);
272
+ const customStartValue = getDateFromComparison(currentDateComparison, "$gte");
273
+ const customEndValue = getDateFromComparison(currentDateComparison, "$lte");
274
+ const handleCustomDateChange = (value, pos) => {
275
+ const key2 = pos === "start" ? "$gte" : "$lte";
276
+ let dateValue = value;
277
+ if (key2 === "$lte" && value) {
278
+ dateValue = new Date(value.getTime());
279
+ dateValue.setHours(23, 59, 59, 999);
280
+ }
281
+ selectedParams.add(
282
+ JSON.stringify({
283
+ ...currentDateComparison || {},
284
+ [key2]: dateValue?.toISOString()
285
+ })
286
+ );
287
+ };
288
+ const getDisplayValueFromPresets = () => {
289
+ const preset = presets.find((p) => isEqual(p.value, currentDateComparison));
290
+ return preset?.label;
291
+ };
292
+ const formatCustomDate = (date) => {
293
+ return date ? getFullDate({ date }) : void 0;
294
+ };
295
+ const getCustomDisplayValue = () => {
296
+ const formattedDates = [customStartValue, customEndValue].map(
297
+ formatCustomDate
298
+ );
299
+ return formattedDates.filter(Boolean).join(" - ");
300
+ };
301
+ const displayValue = getDisplayValueFromPresets() || getCustomDisplayValue();
302
+ const [previousValue, setPreviousValue] = useState(
303
+ displayValue
304
+ );
305
+ const handleRemove = () => {
306
+ selectedParams.delete();
307
+ removeFilter(key);
308
+ };
309
+ let timeoutId = null;
310
+ const handleOpenChange = (open2) => {
311
+ setOpen(open2);
312
+ setPreviousValue(displayValue);
313
+ if (timeoutId) {
314
+ clearTimeout(timeoutId);
315
+ }
316
+ if (!open2 && !currentValue.length) {
317
+ timeoutId = setTimeout(() => {
318
+ removeFilter(key);
319
+ }, 200);
320
+ }
321
+ };
322
+ return /* @__PURE__ */ jsxs3(RadixPopover2.Root, { modal: true, open, onOpenChange: handleOpenChange, children: [
323
+ /* @__PURE__ */ jsx3(
324
+ filter_chip_default,
325
+ {
326
+ hadPreviousValue: !!previousValue,
327
+ label,
328
+ value: displayValue,
329
+ onRemove: handleRemove,
330
+ readonly
331
+ }
332
+ ),
333
+ !readonly && /* @__PURE__ */ jsx3(RadixPopover2.Portal, { children: /* @__PURE__ */ jsxs3(
334
+ RadixPopover2.Content,
335
+ {
336
+ "data-name": "date_filter_content",
337
+ align: "start",
338
+ sideOffset: 8,
339
+ collisionPadding: 24,
340
+ className: clx3(
341
+ "bg-ui-bg-base text-ui-fg-base shadow-elevation-flyout h-full max-h-[var(--radix-popper-available-height)] w-[300px] overflow-auto rounded-lg"
342
+ ),
343
+ onInteractOutside: (e) => {
344
+ if (e.target instanceof HTMLElement) {
345
+ if (e.target.attributes.getNamedItem("data-name")?.value === "filters_menu_content") {
346
+ e.preventDefault();
347
+ }
348
+ }
349
+ },
350
+ children: [
351
+ /* @__PURE__ */ jsxs3("ul", { className: "w-full p-1", children: [
352
+ presets.map((preset) => {
353
+ const isSelected = selectedParams.get().includes(JSON.stringify(preset.value));
354
+ return /* @__PURE__ */ jsx3("li", { children: /* @__PURE__ */ jsxs3(
355
+ "button",
356
+ {
357
+ className: "bg-ui-bg-base hover:bg-ui-bg-base-hover focus-visible:bg-ui-bg-base-pressed text-ui-fg-base data-[disabled]:text-ui-fg-disabled txt-compact-small relative flex w-full cursor-pointer select-none items-center rounded-md px-2 py-1.5 outline-none transition-colors data-[disabled]:pointer-events-none",
358
+ type: "button",
359
+ onClick: () => {
360
+ handleSelectPreset(preset.value);
361
+ },
362
+ children: [
363
+ /* @__PURE__ */ jsx3(
364
+ "div",
365
+ {
366
+ className: clx3(
367
+ "transition-fg flex h-5 w-5 items-center justify-center",
368
+ {
369
+ "[&_svg]:invisible": !isSelected
370
+ }
371
+ ),
372
+ children: /* @__PURE__ */ jsx3(EllipseMiniSolid, {})
373
+ }
374
+ ),
375
+ preset.label
376
+ ]
377
+ }
378
+ ) }, preset.label);
379
+ }),
380
+ /* @__PURE__ */ jsx3("li", { children: /* @__PURE__ */ jsxs3(
381
+ "button",
382
+ {
383
+ className: "bg-ui-bg-base hover:bg-ui-bg-base-hover focus-visible:bg-ui-bg-base-pressed text-ui-fg-base data-[disabled]:text-ui-fg-disabled txt-compact-small relative flex w-full cursor-pointer select-none items-center rounded-md px-2 py-1.5 outline-none transition-colors data-[disabled]:pointer-events-none",
384
+ type: "button",
385
+ onClick: handleSelectCustom,
386
+ children: [
387
+ /* @__PURE__ */ jsx3(
388
+ "div",
389
+ {
390
+ className: clx3(
391
+ "transition-fg flex h-5 w-5 items-center justify-center",
392
+ {
393
+ "[&_svg]:invisible": !showCustom
394
+ }
395
+ ),
396
+ children: /* @__PURE__ */ jsx3(EllipseMiniSolid, {})
397
+ }
398
+ ),
399
+ t("filters.date.custom")
400
+ ]
401
+ }
402
+ ) })
403
+ ] }),
404
+ showCustom && /* @__PURE__ */ jsxs3("div", { className: "border-t px-1 pb-3 pt-1", children: [
405
+ /* @__PURE__ */ jsxs3("div", { children: [
406
+ /* @__PURE__ */ jsx3("div", { className: "px-2 py-1", children: /* @__PURE__ */ jsx3(Text3, { size: "xsmall", leading: "compact", weight: "plus", children: t("filters.date.from") }) }),
407
+ /* @__PURE__ */ jsx3("div", { className: "px-2 py-1", children: /* @__PURE__ */ jsx3(
408
+ DatePicker,
409
+ {
410
+ modal: true,
411
+ maxValue: customEndValue,
412
+ value: customStartValue,
413
+ onChange: (d) => handleCustomDateChange(d, "start")
414
+ }
415
+ ) })
416
+ ] }),
417
+ /* @__PURE__ */ jsxs3("div", { children: [
418
+ /* @__PURE__ */ jsx3("div", { className: "px-2 py-1", children: /* @__PURE__ */ jsx3(Text3, { size: "xsmall", leading: "compact", weight: "plus", children: t("filters.date.to") }) }),
419
+ /* @__PURE__ */ jsx3("div", { className: "px-2 py-1", children: /* @__PURE__ */ jsx3(
420
+ DatePicker,
421
+ {
422
+ modal: true,
423
+ minValue: customStartValue,
424
+ value: customEndValue || void 0,
425
+ onChange: (d) => {
426
+ handleCustomDateChange(d, "end");
427
+ }
428
+ }
429
+ ) })
430
+ ] })
431
+ ] })
432
+ ]
433
+ }
434
+ ) })
435
+ ] });
436
+ };
437
+ var today = /* @__PURE__ */ new Date();
438
+ today.setHours(0, 0, 0, 0);
439
+ var usePresets = () => {
440
+ const { t: t2 } = useTranslation3();
441
+ return useMemo(
442
+ () => [
443
+ {
444
+ label: t2("filters.date.today"),
445
+ value: {
446
+ $gte: today.toISOString()
447
+ }
448
+ },
449
+ {
450
+ label: t2("filters.date.lastSevenDays"),
451
+ value: {
452
+ $gte: new Date(
453
+ today.getTime() - 7 * 24 * 60 * 60 * 1e3
454
+ ).toISOString()
455
+ // 7 days ago
456
+ }
457
+ },
458
+ {
459
+ label: t2("filters.date.lastThirtyDays"),
460
+ value: {
461
+ $gte: new Date(
462
+ today.getTime() - 30 * 24 * 60 * 60 * 1e3
463
+ ).toISOString()
464
+ // 30 days ago
465
+ }
466
+ },
467
+ {
468
+ label: t2("filters.date.lastNinetyDays"),
469
+ value: {
470
+ $gte: new Date(
471
+ today.getTime() - 90 * 24 * 60 * 60 * 1e3
472
+ ).toISOString()
473
+ // 90 days ago
474
+ }
475
+ },
476
+ {
477
+ label: t2("filters.date.lastTwelveMonths"),
478
+ value: {
479
+ $gte: new Date(
480
+ today.getTime() - 365 * 24 * 60 * 60 * 1e3
481
+ ).toISOString()
482
+ // 365 days ago
483
+ }
484
+ }
485
+ ],
486
+ [t2]
487
+ );
488
+ };
489
+ var parseDateComparison = (value) => {
490
+ return value?.length ? JSON.parse(value.join(",")) : null;
491
+ };
492
+ var getDateFromComparison = (comparison, key) => {
493
+ if (!comparison?.[key]) {
494
+ return void 0;
495
+ }
496
+ const compareDate = new Date(comparison[key]);
497
+ if (key === "$lte") {
498
+ compareDate.setHours(0, 0, 0, 0);
499
+ }
500
+ return compareDate;
501
+ };
502
+
503
+ // src/components/table/data-table/data-table-filter/number-filter.tsx
504
+ import { EllipseMiniSolid as EllipseMiniSolid2 } from "@acmekit/icons";
505
+ import { Input, Label, clx as clx4 } from "@acmekit/ui";
506
+ import debounce from "lodash.debounce";
507
+ import {
508
+ Popover as RadixPopover3,
509
+ RadioGroup as RadixRadioGroup
510
+ } from "radix-ui";
511
+ import { useCallback, useEffect, useState as useState2 } from "react";
512
+ import { useTranslation as useTranslation4 } from "react-i18next";
513
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
514
+ var NumberFilter = ({
515
+ filter,
516
+ prefix,
517
+ readonly,
518
+ openOnMount
519
+ }) => {
520
+ const { t: t2 } = useTranslation4();
521
+ const [open, setOpen] = useState2(openOnMount);
522
+ const { key, label } = filter;
523
+ const { removeFilter } = useDataTableFilterContext();
524
+ const selectedParams = useSelectedParams({
525
+ param: key,
526
+ prefix,
527
+ multiple: false
528
+ });
529
+ const currentValue = selectedParams.get();
530
+ const [previousValue, setPreviousValue] = useState2(
531
+ currentValue
532
+ );
533
+ const [operator, setOperator] = useState2(
534
+ getOperator(currentValue)
535
+ );
536
+ const debouncedOnChange = useCallback(
537
+ debounce((e, operator2) => {
538
+ const value = e.target.value;
539
+ const curr = JSON.parse(currentValue?.join(",") || "{}");
540
+ const isCurrentNumber = !isNaN(Number(curr));
541
+ const handleValue = (operator3) => {
542
+ if (!value && isCurrentNumber) {
543
+ selectedParams.delete();
544
+ return;
545
+ }
546
+ if (curr && !value) {
547
+ delete curr[operator3];
548
+ selectedParams.add(JSON.stringify(curr));
549
+ return;
550
+ }
551
+ if (!curr) {
552
+ selectedParams.add(JSON.stringify({ [operator3]: value }));
553
+ return;
554
+ }
555
+ selectedParams.add(JSON.stringify({ ...curr, [operator3]: value }));
556
+ };
557
+ switch (operator2) {
558
+ case "eq":
559
+ if (!value) {
560
+ selectedParams.delete();
561
+ } else {
562
+ selectedParams.add(value);
563
+ }
564
+ break;
565
+ case "lt":
566
+ case "gt":
567
+ handleValue(operator2);
568
+ break;
569
+ }
570
+ }, 500),
571
+ [selectedParams, currentValue]
572
+ );
573
+ useEffect(() => {
574
+ return () => {
575
+ debouncedOnChange.cancel();
576
+ };
577
+ }, [debouncedOnChange]);
578
+ let timeoutId = null;
579
+ const handleOpenChange = (open2) => {
580
+ setOpen(open2);
581
+ setPreviousValue(currentValue);
582
+ if (timeoutId) {
583
+ clearTimeout(timeoutId);
584
+ }
585
+ if (!open2 && !currentValue.length) {
586
+ timeoutId = setTimeout(() => {
587
+ removeFilter(key);
588
+ }, 200);
589
+ }
590
+ };
591
+ const handleRemove = () => {
592
+ selectedParams.delete();
593
+ removeFilter(key);
594
+ };
595
+ const operators = [
596
+ {
597
+ operator: "exact",
598
+ label: t2("filters.compare.exact")
599
+ },
600
+ {
601
+ operator: "range",
602
+ label: t2("filters.compare.range")
603
+ }
604
+ ];
605
+ const GT_KEY = `${key}-gt`;
606
+ const LT_KEY = `${key}-lt`;
607
+ const EQ_KEY = key;
608
+ const displayValue = parseDisplayValue(currentValue, t2);
609
+ const previousDisplayValue = parseDisplayValue(previousValue, t2);
610
+ return /* @__PURE__ */ jsxs4(RadixPopover3.Root, { modal: true, open, onOpenChange: handleOpenChange, children: [
611
+ /* @__PURE__ */ jsx4(
612
+ filter_chip_default,
613
+ {
614
+ hasOperator: true,
615
+ hadPreviousValue: !!previousDisplayValue,
616
+ label,
617
+ value: displayValue,
618
+ onRemove: handleRemove,
619
+ readonly
620
+ }
621
+ ),
622
+ !readonly && /* @__PURE__ */ jsx4(RadixPopover3.Portal, { children: /* @__PURE__ */ jsxs4(
623
+ RadixPopover3.Content,
624
+ {
625
+ "data-name": "number_filter_content",
626
+ align: "start",
627
+ sideOffset: 8,
628
+ collisionPadding: 24,
629
+ className: clx4(
630
+ "bg-ui-bg-base text-ui-fg-base shadow-elevation-flyout max-h-[var(--radix-popper-available-height)] w-[300px] divide-y overflow-y-auto rounded-lg outline-none"
631
+ ),
632
+ onInteractOutside: (e) => {
633
+ if (e.target instanceof HTMLElement) {
634
+ if (e.target.attributes.getNamedItem("data-name")?.value === "filters_menu_content") {
635
+ e.preventDefault();
636
+ }
637
+ }
638
+ },
639
+ children: [
640
+ /* @__PURE__ */ jsx4("div", { className: "p-1", children: /* @__PURE__ */ jsx4(
641
+ RadixRadioGroup.Root,
642
+ {
643
+ value: operator,
644
+ onValueChange: (val) => setOperator(val),
645
+ className: "flex flex-col items-start",
646
+ orientation: "vertical",
647
+ autoFocus: true,
648
+ children: operators.map((o) => /* @__PURE__ */ jsxs4(
649
+ RadixRadioGroup.Item,
650
+ {
651
+ value: o.operator,
652
+ className: "txt-compact-small hover:bg-ui-bg-base-hover focus-visible:bg-ui-bg-base-hover active:bg-ui-bg-base-pressed transition-fg grid w-full grid-cols-[20px_1fr] gap-2 rounded-[4px] px-2 py-1.5 text-left outline-none",
653
+ children: [
654
+ /* @__PURE__ */ jsx4("div", { className: "size-5", children: /* @__PURE__ */ jsx4(RadixRadioGroup.Indicator, { children: /* @__PURE__ */ jsx4(EllipseMiniSolid2, {}) }) }),
655
+ /* @__PURE__ */ jsx4("span", { className: "w-full", children: o.label })
656
+ ]
657
+ },
658
+ o.operator
659
+ ))
660
+ }
661
+ ) }),
662
+ /* @__PURE__ */ jsx4("div", { children: operator === "range" ? /* @__PURE__ */ jsxs4("div", { className: "px-1 pb-3 pt-1", children: [
663
+ /* @__PURE__ */ jsx4("div", { className: "px-2 py-1.5", children: /* @__PURE__ */ jsx4(Label, { size: "xsmall", weight: "plus", htmlFor: GT_KEY, children: t2("filters.compare.greaterThan") }) }),
664
+ /* @__PURE__ */ jsx4("div", { className: "px-2 py-0.5", children: /* @__PURE__ */ jsx4(
665
+ Input,
666
+ {
667
+ name: GT_KEY,
668
+ size: "small",
669
+ type: "number",
670
+ defaultValue: getValue(currentValue, "gt"),
671
+ onChange: (e) => debouncedOnChange(e, "gt")
672
+ }
673
+ ) }),
674
+ /* @__PURE__ */ jsx4("div", { className: "px-2 py-1.5", children: /* @__PURE__ */ jsx4(Label, { size: "xsmall", weight: "plus", htmlFor: LT_KEY, children: t2("filters.compare.lessThan") }) }),
675
+ /* @__PURE__ */ jsx4("div", { className: "px-2 py-0.5", children: /* @__PURE__ */ jsx4(
676
+ Input,
677
+ {
678
+ name: LT_KEY,
679
+ size: "small",
680
+ type: "number",
681
+ defaultValue: getValue(currentValue, "lt"),
682
+ onChange: (e) => debouncedOnChange(e, "lt")
683
+ }
684
+ ) })
685
+ ] }, "range") : /* @__PURE__ */ jsxs4("div", { className: "px-1 pb-3 pt-1", children: [
686
+ /* @__PURE__ */ jsx4("div", { className: "px-2 py-1.5", children: /* @__PURE__ */ jsx4(Label, { size: "xsmall", weight: "plus", htmlFor: EQ_KEY, children: label }) }),
687
+ /* @__PURE__ */ jsx4("div", { className: "px-2 py-0.5", children: /* @__PURE__ */ jsx4(
688
+ Input,
689
+ {
690
+ name: EQ_KEY,
691
+ size: "small",
692
+ type: "number",
693
+ defaultValue: getValue(currentValue, "eq"),
694
+ onChange: (e) => debouncedOnChange(e, "eq")
695
+ }
696
+ ) })
697
+ ] }, "exact") })
698
+ ]
699
+ }
700
+ ) })
701
+ ] });
702
+ };
703
+ var parseDisplayValue = (value, t2) => {
704
+ const parsed = JSON.parse(value?.join(",") || "{}");
705
+ let displayValue = "";
706
+ if (typeof parsed === "object") {
707
+ const parts = [];
708
+ if (parsed.gt) {
709
+ parts.push(t2("filters.compare.greaterThanLabel", { value: parsed.gt }));
710
+ }
711
+ if (parsed.lt) {
712
+ parts.push(
713
+ t2("filters.compare.lessThanLabel", {
714
+ value: parsed.lt
715
+ })
716
+ );
717
+ }
718
+ displayValue = parts.join(` ${t2("filters.compare.andLabel")} `);
719
+ }
720
+ if (typeof parsed === "number") {
721
+ displayValue = parsed.toString();
722
+ }
723
+ return displayValue;
724
+ };
725
+ var parseValue = (value) => {
726
+ if (!value) {
727
+ return void 0;
728
+ }
729
+ const val = value.join(",");
730
+ if (!val) {
731
+ return void 0;
732
+ }
733
+ return JSON.parse(val);
734
+ };
735
+ var getValue = (value, key) => {
736
+ const parsed = parseValue(value);
737
+ if (typeof parsed === "object") {
738
+ return parsed[key];
739
+ }
740
+ if (typeof parsed === "number" && key === "eq") {
741
+ return parsed;
742
+ }
743
+ return void 0;
744
+ };
745
+ var getOperator = (value) => {
746
+ const parsed = parseValue(value);
747
+ return typeof parsed === "object" ? "range" : "exact";
748
+ };
749
+
750
+ // src/components/table/data-table/data-table-filter/select-filter.tsx
751
+ import { CheckMini, EllipseMiniSolid as EllipseMiniSolid3, XMarkMini as XMarkMini2 } from "@acmekit/icons";
752
+ import { clx as clx5 } from "@acmekit/ui";
753
+ import { Command } from "cmdk";
754
+ import { Popover as RadixPopover4 } from "radix-ui";
755
+ import { useState as useState3 } from "react";
756
+ import { useTranslation as useTranslation5 } from "react-i18next";
757
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
758
+ var SelectFilter = ({
759
+ filter,
760
+ prefix,
761
+ readonly,
762
+ multiple,
763
+ searchable,
764
+ options,
765
+ openOnMount
766
+ }) => {
767
+ const [open, setOpen] = useState3(openOnMount);
768
+ const [search, setSearch] = useState3("");
769
+ const [searchRef, setSearchRef] = useState3(null);
770
+ const { t: t2 } = useTranslation5();
771
+ const { removeFilter } = useDataTableFilterContext();
772
+ const { key, label } = filter;
773
+ const selectedParams = useSelectedParams({ param: key, prefix, multiple });
774
+ const currentValue = selectedParams.get();
775
+ const labelValues = currentValue.map((v) => options.find((o) => o.value === v)?.label).filter(Boolean);
776
+ const [previousValue, setPreviousValue] = useState3(labelValues);
777
+ const handleRemove = () => {
778
+ selectedParams.delete();
779
+ removeFilter(key);
780
+ };
781
+ let timeoutId = null;
782
+ const handleOpenChange = (open2) => {
783
+ setOpen(open2);
784
+ setPreviousValue(labelValues);
785
+ if (timeoutId) {
786
+ clearTimeout(timeoutId);
787
+ }
788
+ if (!open2 && !currentValue.length) {
789
+ timeoutId = setTimeout(() => {
790
+ removeFilter(key);
791
+ }, 200);
792
+ }
793
+ };
794
+ const handleClearSearch = () => {
795
+ setSearch("");
796
+ if (searchRef) {
797
+ searchRef.focus();
798
+ }
799
+ };
800
+ const handleSelect = (value) => {
801
+ const isSelected = selectedParams.get().includes(String(value));
802
+ if (isSelected) {
803
+ selectedParams.delete(String(value));
804
+ } else {
805
+ selectedParams.add(String(value));
806
+ }
807
+ };
808
+ const normalizedValues = labelValues ? Array.isArray(labelValues) ? labelValues : [labelValues] : null;
809
+ const normalizedPrev = previousValue ? Array.isArray(previousValue) ? previousValue : [previousValue] : null;
810
+ return /* @__PURE__ */ jsxs5(RadixPopover4.Root, { modal: true, open, onOpenChange: handleOpenChange, children: [
811
+ /* @__PURE__ */ jsx5(
812
+ filter_chip_default,
813
+ {
814
+ hasOperator: true,
815
+ hadPreviousValue: !!normalizedPrev?.length,
816
+ readonly,
817
+ label,
818
+ value: normalizedValues?.join(", "),
819
+ onRemove: handleRemove
820
+ }
821
+ ),
822
+ !readonly && /* @__PURE__ */ jsx5(RadixPopover4.Portal, { children: /* @__PURE__ */ jsx5(
823
+ RadixPopover4.Content,
824
+ {
825
+ hideWhenDetached: true,
826
+ align: "start",
827
+ sideOffset: 8,
828
+ collisionPadding: 8,
829
+ className: clx5(
830
+ "bg-ui-bg-base text-ui-fg-base shadow-elevation-flyout z-[1] h-full max-h-[200px] w-[300px] overflow-hidden rounded-lg outline-none"
831
+ ),
832
+ onInteractOutside: (e) => {
833
+ if (e.target instanceof HTMLElement) {
834
+ if (e.target.attributes.getNamedItem("data-name")?.value === "filters_menu_content") {
835
+ e.preventDefault();
836
+ e.stopPropagation();
837
+ }
838
+ }
839
+ },
840
+ children: /* @__PURE__ */ jsxs5(Command, { className: "h-full", children: [
841
+ searchable && /* @__PURE__ */ jsx5("div", { className: "border-b p-1", children: /* @__PURE__ */ jsxs5("div", { className: "grid grid-cols-[1fr_20px] gap-x-2 rounded-md px-2 py-1", children: [
842
+ /* @__PURE__ */ jsx5(
843
+ Command.Input,
844
+ {
845
+ ref: setSearchRef,
846
+ value: search,
847
+ onValueChange: setSearch,
848
+ className: "txt-compact-small placeholder:text-ui-fg-muted bg-transparent outline-none",
849
+ placeholder: "Search"
850
+ }
851
+ ),
852
+ /* @__PURE__ */ jsx5("div", { className: "flex h-5 w-5 items-center justify-center", children: /* @__PURE__ */ jsx5(
853
+ "button",
854
+ {
855
+ disabled: !search,
856
+ onClick: handleClearSearch,
857
+ className: clx5(
858
+ "transition-fg text-ui-fg-muted focus-visible:bg-ui-bg-base-pressed rounded-md outline-none",
859
+ {
860
+ invisible: !search
861
+ }
862
+ ),
863
+ children: /* @__PURE__ */ jsx5(XMarkMini2, {})
864
+ }
865
+ ) })
866
+ ] }) }),
867
+ /* @__PURE__ */ jsx5(Command.Empty, { className: "txt-compact-small flex items-center justify-center p-1", children: /* @__PURE__ */ jsx5("span", { className: "w-full px-2 py-1 text-center", children: t2("general.noResultsTitle") }) }),
868
+ /* @__PURE__ */ jsx5(Command.List, { className: "h-full max-h-[163px] min-h-[0] overflow-auto p-1 outline-none", children: options.map((option) => {
869
+ const isSelected = selectedParams.get().includes(String(option.value));
870
+ return /* @__PURE__ */ jsxs5(
871
+ Command.Item,
872
+ {
873
+ className: "bg-ui-bg-base hover:bg-ui-bg-base-hover aria-selected:bg-ui-bg-base-pressed focus-visible:bg-ui-bg-base-pressed text-ui-fg-base data-[disabled]:text-ui-fg-disabled txt-compact-small relative flex cursor-pointer select-none items-center gap-x-2 rounded-md px-2 py-1.5 outline-none transition-colors data-[disabled]:pointer-events-none",
874
+ value: option.label,
875
+ onSelect: () => {
876
+ handleSelect(option.value);
877
+ },
878
+ children: [
879
+ /* @__PURE__ */ jsx5(
880
+ "div",
881
+ {
882
+ className: clx5(
883
+ "transition-fg flex h-5 w-5 items-center justify-center",
884
+ {
885
+ "[&_svg]:invisible": !isSelected
886
+ }
887
+ ),
888
+ children: multiple ? /* @__PURE__ */ jsx5(CheckMini, {}) : /* @__PURE__ */ jsx5(EllipseMiniSolid3, {})
889
+ }
890
+ ),
891
+ option.label
892
+ ]
893
+ },
894
+ String(option.value)
895
+ );
896
+ }) })
897
+ ] })
898
+ }
899
+ ) })
900
+ ] });
901
+ };
902
+
903
+ // src/components/table/data-table/data-table-filter/string-filter.tsx
904
+ import { Input as Input2, Label as Label2, clx as clx6 } from "@acmekit/ui";
905
+ import debounce2 from "lodash.debounce";
906
+ import { Popover as RadixPopover5 } from "radix-ui";
907
+ import { useCallback as useCallback2, useEffect as useEffect2, useState as useState4 } from "react";
908
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
909
+ var StringFilter = ({
910
+ filter,
911
+ prefix,
912
+ readonly,
913
+ openOnMount
914
+ }) => {
915
+ const [open, setOpen] = useState4(openOnMount);
916
+ const { key, label } = filter;
917
+ const { removeFilter } = useDataTableFilterContext();
918
+ const selectedParams = useSelectedParams({ param: key, prefix });
919
+ const query = selectedParams.get();
920
+ const [previousValue, setPreviousValue] = useState4(
921
+ query?.[0]
922
+ );
923
+ const debouncedOnChange = useCallback2(
924
+ debounce2((e) => {
925
+ const value = e.target.value;
926
+ if (!value) {
927
+ selectedParams.delete();
928
+ } else {
929
+ selectedParams.add(value);
930
+ }
931
+ }, 500),
932
+ [selectedParams]
933
+ );
934
+ useEffect2(() => {
935
+ return () => {
936
+ debouncedOnChange.cancel();
937
+ };
938
+ }, [debouncedOnChange]);
939
+ let timeoutId = null;
940
+ const handleOpenChange = (open2) => {
941
+ setOpen(open2);
942
+ setPreviousValue(query?.[0]);
943
+ if (timeoutId) {
944
+ clearTimeout(timeoutId);
945
+ }
946
+ if (!open2 && !query.length) {
947
+ timeoutId = setTimeout(() => {
948
+ removeFilter(key);
949
+ }, 200);
950
+ }
951
+ };
952
+ const handleRemove = () => {
953
+ selectedParams.delete();
954
+ removeFilter(key);
955
+ };
956
+ return /* @__PURE__ */ jsxs6(RadixPopover5.Root, { modal: true, open, onOpenChange: handleOpenChange, children: [
957
+ /* @__PURE__ */ jsx6(
958
+ filter_chip_default,
959
+ {
960
+ hasOperator: true,
961
+ hadPreviousValue: !!previousValue,
962
+ label,
963
+ value: query?.[0],
964
+ onRemove: handleRemove,
965
+ readonly
966
+ }
967
+ ),
968
+ !readonly && /* @__PURE__ */ jsx6(RadixPopover5.Portal, { children: /* @__PURE__ */ jsx6(
969
+ RadixPopover5.Content,
970
+ {
971
+ hideWhenDetached: true,
972
+ align: "start",
973
+ sideOffset: 8,
974
+ collisionPadding: 8,
975
+ className: clx6(
976
+ "bg-ui-bg-base text-ui-fg-base shadow-elevation-flyout z-[1] h-full max-h-[200px] w-[300px] overflow-hidden rounded-lg outline-none"
977
+ ),
978
+ onInteractOutside: (e) => {
979
+ if (e.target instanceof HTMLElement) {
980
+ if (e.target.attributes.getNamedItem("data-name")?.value === "filters_menu_content") {
981
+ e.preventDefault();
982
+ e.stopPropagation();
983
+ }
984
+ }
985
+ },
986
+ children: /* @__PURE__ */ jsxs6("div", { className: "px-1 pb-3 pt-1", children: [
987
+ /* @__PURE__ */ jsx6("div", { className: "px-2 py-1.5", children: /* @__PURE__ */ jsx6(Label2, { size: "xsmall", weight: "plus", htmlFor: key, children: label }) }),
988
+ /* @__PURE__ */ jsx6("div", { className: "px-2 py-0.5", children: /* @__PURE__ */ jsx6(
989
+ Input2,
990
+ {
991
+ name: key,
992
+ size: "small",
993
+ defaultValue: query?.[0] || void 0,
994
+ onChange: debouncedOnChange
995
+ }
996
+ ) })
997
+ ] })
998
+ }
999
+ ) })
1000
+ ] });
1001
+ };
1002
+
1003
+ // src/components/table/data-table/data-table-filter/data-table-filter.tsx
1004
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1005
+ var DataTableFilter = ({
1006
+ filters,
1007
+ readonly,
1008
+ prefix
1009
+ }) => {
1010
+ const { t: t2 } = useTranslation6();
1011
+ const [searchParams] = useSearchParams2();
1012
+ const [open, setOpen] = useState5(false);
1013
+ const [activeFilters, setActiveFilters] = useState5(
1014
+ getInitialFilters({ searchParams, filters, prefix })
1015
+ );
1016
+ const availableFilters = filters.filter(
1017
+ (f) => !activeFilters.find((af) => af.key === f.key)
1018
+ );
1019
+ const initialMount = useRef(true);
1020
+ useEffect3(() => {
1021
+ if (initialMount.current) {
1022
+ const params = new URLSearchParams(searchParams);
1023
+ filters.forEach((filter) => {
1024
+ const key = prefix ? `${prefix}_${filter.key}` : filter.key;
1025
+ const value = params.get(key);
1026
+ if (value && !activeFilters.find((af) => af.key === filter.key)) {
1027
+ if (filter.type === "select") {
1028
+ setActiveFilters((prev) => [
1029
+ ...prev,
1030
+ {
1031
+ ...filter,
1032
+ multiple: filter.multiple,
1033
+ options: filter.options,
1034
+ openOnMount: false
1035
+ }
1036
+ ]);
1037
+ } else {
1038
+ setActiveFilters((prev) => [
1039
+ ...prev,
1040
+ { ...filter, openOnMount: false }
1041
+ ]);
1042
+ }
1043
+ }
1044
+ });
1045
+ }
1046
+ initialMount.current = false;
1047
+ }, [activeFilters, filters, prefix, searchParams]);
1048
+ const addFilter = (filter) => {
1049
+ setOpen(false);
1050
+ setActiveFilters((prev) => [...prev, { ...filter, openOnMount: true }]);
1051
+ };
1052
+ const removeFilter = useCallback3((key) => {
1053
+ setActiveFilters((prev) => prev.filter((f) => f.key !== key));
1054
+ }, []);
1055
+ const removeAllFilters = useCallback3(() => {
1056
+ setActiveFilters([]);
1057
+ }, []);
1058
+ return /* @__PURE__ */ jsx7(
1059
+ DataTableFilterContext.Provider,
1060
+ {
1061
+ value: useMemo2(
1062
+ () => ({
1063
+ removeFilter,
1064
+ removeAllFilters
1065
+ }),
1066
+ [removeAllFilters, removeFilter]
1067
+ ),
1068
+ children: /* @__PURE__ */ jsxs7("div", { className: "max-w-2/3 flex flex-wrap items-center gap-2", children: [
1069
+ activeFilters.map((filter) => {
1070
+ switch (filter.type) {
1071
+ case "select":
1072
+ return /* @__PURE__ */ jsx7(
1073
+ SelectFilter,
1074
+ {
1075
+ filter,
1076
+ prefix,
1077
+ readonly,
1078
+ options: filter.options,
1079
+ multiple: filter.multiple,
1080
+ searchable: filter.searchable,
1081
+ openOnMount: filter.openOnMount
1082
+ },
1083
+ filter.key
1084
+ );
1085
+ case "date":
1086
+ return /* @__PURE__ */ jsx7(
1087
+ DateFilter,
1088
+ {
1089
+ filter,
1090
+ prefix,
1091
+ readonly,
1092
+ openOnMount: filter.openOnMount
1093
+ },
1094
+ filter.key
1095
+ );
1096
+ case "string":
1097
+ return /* @__PURE__ */ jsx7(
1098
+ StringFilter,
1099
+ {
1100
+ filter,
1101
+ prefix,
1102
+ readonly,
1103
+ openOnMount: filter.openOnMount
1104
+ },
1105
+ filter.key
1106
+ );
1107
+ case "number":
1108
+ return /* @__PURE__ */ jsx7(
1109
+ NumberFilter,
1110
+ {
1111
+ filter,
1112
+ prefix,
1113
+ readonly,
1114
+ openOnMount: filter.openOnMount
1115
+ },
1116
+ filter.key
1117
+ );
1118
+ default:
1119
+ break;
1120
+ }
1121
+ }),
1122
+ !readonly && availableFilters.length > 0 && /* @__PURE__ */ jsxs7(RadixPopover6.Root, { modal: true, open, onOpenChange: setOpen, children: [
1123
+ /* @__PURE__ */ jsx7(RadixPopover6.Trigger, { asChild: true, id: "filters_menu_trigger", children: /* @__PURE__ */ jsx7(Button2, { size: "small", variant: "secondary", children: t2("filters.addFilter") }) }),
1124
+ /* @__PURE__ */ jsx7(RadixPopover6.Portal, { children: /* @__PURE__ */ jsx7(
1125
+ RadixPopover6.Content,
1126
+ {
1127
+ className: clx7(
1128
+ "bg-ui-bg-base text-ui-fg-base shadow-elevation-flyout z-[1] h-full max-h-[200px] w-[300px] overflow-auto rounded-lg p-1 outline-none"
1129
+ ),
1130
+ "data-name": "filters_menu_content",
1131
+ align: "start",
1132
+ sideOffset: 8,
1133
+ collisionPadding: 8,
1134
+ onCloseAutoFocus: (e) => {
1135
+ const hasOpenFilter = activeFilters.find(
1136
+ (filter) => filter.openOnMount
1137
+ );
1138
+ if (hasOpenFilter) {
1139
+ e.preventDefault();
1140
+ }
1141
+ },
1142
+ children: availableFilters.map((filter) => {
1143
+ return /* @__PURE__ */ jsx7(
1144
+ "div",
1145
+ {
1146
+ className: "bg-ui-bg-base hover:bg-ui-bg-base-hover focus-visible:bg-ui-bg-base-pressed text-ui-fg-base data-[disabled]:text-ui-fg-disabled txt-compact-small relative flex cursor-pointer select-none items-center rounded-md px-2 py-1.5 outline-none transition-colors data-[disabled]:pointer-events-none",
1147
+ role: "menuitem",
1148
+ onClick: () => {
1149
+ addFilter(filter);
1150
+ },
1151
+ children: filter.label
1152
+ },
1153
+ filter.key
1154
+ );
1155
+ })
1156
+ }
1157
+ ) })
1158
+ ] }),
1159
+ !readonly && activeFilters.length > 0 && /* @__PURE__ */ jsx7(ClearAllFilters, { filters, prefix })
1160
+ ] })
1161
+ }
1162
+ );
1163
+ };
1164
+ var ClearAllFilters = ({ filters, prefix }) => {
1165
+ const { removeAllFilters } = useDataTableFilterContext();
1166
+ const [_, setSearchParams] = useSearchParams2();
1167
+ const handleRemoveAll = () => {
1168
+ setSearchParams((prev) => {
1169
+ const newValues = new URLSearchParams(prev);
1170
+ filters.forEach((filter) => {
1171
+ newValues.delete(prefix ? `${prefix}_${filter.key}` : filter.key);
1172
+ });
1173
+ return newValues;
1174
+ });
1175
+ removeAllFilters();
1176
+ };
1177
+ return /* @__PURE__ */ jsx7(
1178
+ "button",
1179
+ {
1180
+ type: "button",
1181
+ onClick: handleRemoveAll,
1182
+ className: clx7(
1183
+ "text-ui-fg-muted transition-fg txt-compact-small-plus rounded-md px-2 py-1",
1184
+ "hover:text-ui-fg-subtle",
1185
+ "focus-visible:shadow-borders-focus"
1186
+ ),
1187
+ children: "Clear all"
1188
+ }
1189
+ );
1190
+ };
1191
+ var getInitialFilters = ({
1192
+ searchParams,
1193
+ filters,
1194
+ prefix
1195
+ }) => {
1196
+ const params = new URLSearchParams(searchParams);
1197
+ const activeFilters = [];
1198
+ filters.forEach((filter) => {
1199
+ const key = prefix ? `${prefix}_${filter.key}` : filter.key;
1200
+ const value = params.get(key);
1201
+ if (value) {
1202
+ if (filter.type === "select") {
1203
+ activeFilters.push({
1204
+ ...filter,
1205
+ multiple: filter.multiple,
1206
+ options: filter.options,
1207
+ openOnMount: false
1208
+ });
1209
+ } else {
1210
+ activeFilters.push({ ...filter, openOnMount: false });
1211
+ }
1212
+ }
1213
+ });
1214
+ return activeFilters;
1215
+ };
1216
+
1217
+ // src/components/table/data-table/data-table-order-by/data-table-order-by.tsx
1218
+ import { DescendingSorting } from "@acmekit/icons";
1219
+ import { DropdownMenu, IconButton } from "@acmekit/ui";
1220
+ import { useState as useState6 } from "react";
1221
+ import { useTranslation as useTranslation7 } from "react-i18next";
1222
+ import { useSearchParams as useSearchParams3 } from "react-router-dom";
1223
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1224
+ var initState = (params, prefix) => {
1225
+ const param = prefix ? `${prefix}_order` : "order";
1226
+ const sortParam = params.get(param);
1227
+ if (!sortParam) {
1228
+ return {
1229
+ dir: "asc" /* ASC */
1230
+ };
1231
+ }
1232
+ const dir = sortParam.startsWith("-") ? "desc" /* DESC */ : "asc" /* ASC */;
1233
+ const key = sortParam.replace("-", "");
1234
+ return {
1235
+ key,
1236
+ dir
1237
+ };
1238
+ };
1239
+ var DataTableOrderBy = ({
1240
+ keys,
1241
+ prefix
1242
+ }) => {
1243
+ const [searchParams, setSearchParams] = useSearchParams3();
1244
+ const [state, setState] = useState6(initState(searchParams, prefix));
1245
+ const param = prefix ? `${prefix}_order` : "order";
1246
+ const { t: t2 } = useTranslation7();
1247
+ const direction = useDocumentDirection();
1248
+ const handleDirChange = (dir) => {
1249
+ setState((prev) => ({
1250
+ ...prev,
1251
+ dir
1252
+ }));
1253
+ updateOrderParam({
1254
+ key: state.key,
1255
+ dir
1256
+ });
1257
+ };
1258
+ const handleKeyChange = (value) => {
1259
+ setState((prev) => ({
1260
+ ...prev,
1261
+ key: value
1262
+ }));
1263
+ updateOrderParam({
1264
+ key: value,
1265
+ dir: state.dir
1266
+ });
1267
+ };
1268
+ const updateOrderParam = (state2) => {
1269
+ if (!state2.key) {
1270
+ setSearchParams((prev) => {
1271
+ prev.delete(param);
1272
+ return prev;
1273
+ });
1274
+ return;
1275
+ }
1276
+ const orderParam = state2.dir === "asc" /* ASC */ ? state2.key : `-${state2.key}`;
1277
+ setSearchParams((prev) => {
1278
+ prev.set(param, orderParam);
1279
+ return prev;
1280
+ });
1281
+ };
1282
+ return /* @__PURE__ */ jsxs8(DropdownMenu, { dir: direction, children: [
1283
+ /* @__PURE__ */ jsx8(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx8(IconButton, { size: "small", children: /* @__PURE__ */ jsx8(DescendingSorting, {}) }) }),
1284
+ /* @__PURE__ */ jsxs8(DropdownMenu.Content, { className: "z-[1]", align: "end", children: [
1285
+ /* @__PURE__ */ jsx8(
1286
+ DropdownMenu.RadioGroup,
1287
+ {
1288
+ value: state.key,
1289
+ onValueChange: handleKeyChange,
1290
+ children: keys.map((key) => {
1291
+ const stringKey = String(key.key);
1292
+ return /* @__PURE__ */ jsx8(
1293
+ DropdownMenu.RadioItem,
1294
+ {
1295
+ value: stringKey,
1296
+ onSelect: (event) => event.preventDefault(),
1297
+ children: key.label
1298
+ },
1299
+ stringKey
1300
+ );
1301
+ })
1302
+ }
1303
+ ),
1304
+ /* @__PURE__ */ jsx8(DropdownMenu.Separator, {}),
1305
+ /* @__PURE__ */ jsxs8(
1306
+ DropdownMenu.RadioGroup,
1307
+ {
1308
+ value: state.dir,
1309
+ onValueChange: handleDirChange,
1310
+ children: [
1311
+ /* @__PURE__ */ jsxs8(
1312
+ DropdownMenu.RadioItem,
1313
+ {
1314
+ className: "flex items-center justify-between",
1315
+ value: "asc",
1316
+ onSelect: (event) => event.preventDefault(),
1317
+ children: [
1318
+ t2("general.ascending"),
1319
+ /* @__PURE__ */ jsx8(DropdownMenu.Label, { children: "1 - 30" })
1320
+ ]
1321
+ }
1322
+ ),
1323
+ /* @__PURE__ */ jsxs8(
1324
+ DropdownMenu.RadioItem,
1325
+ {
1326
+ className: "flex items-center justify-between",
1327
+ value: "desc",
1328
+ onSelect: (event) => event.preventDefault(),
1329
+ children: [
1330
+ t2("general.descending"),
1331
+ /* @__PURE__ */ jsx8(DropdownMenu.Label, { children: "30 - 1" })
1332
+ ]
1333
+ }
1334
+ )
1335
+ ]
1336
+ }
1337
+ )
1338
+ ] })
1339
+ ] });
1340
+ };
1341
+
1342
+ // src/components/table/data-table/data-table-search/data-table-search.tsx
1343
+ import { Input as Input3 } from "@acmekit/ui";
1344
+ import { useCallback as useCallback4, useEffect as useEffect4 } from "react";
1345
+ import { useTranslation as useTranslation8 } from "react-i18next";
1346
+ import debounce3 from "lodash.debounce";
1347
+ import { jsx as jsx9 } from "react/jsx-runtime";
1348
+ var DataTableSearch = ({
1349
+ placeholder,
1350
+ prefix,
1351
+ autofocus
1352
+ }) => {
1353
+ const { t: t2 } = useTranslation8();
1354
+ const placeholderText = placeholder || t2("general.search");
1355
+ const selectedParams = useSelectedParams({
1356
+ param: "q",
1357
+ prefix,
1358
+ multiple: false
1359
+ });
1360
+ const query = selectedParams.get();
1361
+ const debouncedOnChange = useCallback4(
1362
+ debounce3((e) => {
1363
+ const value = e.target.value;
1364
+ if (!value) {
1365
+ selectedParams.delete();
1366
+ } else {
1367
+ selectedParams.add(value);
1368
+ }
1369
+ }, 500),
1370
+ [selectedParams]
1371
+ );
1372
+ useEffect4(() => {
1373
+ return () => {
1374
+ debouncedOnChange.cancel();
1375
+ };
1376
+ }, [debouncedOnChange]);
1377
+ return /* @__PURE__ */ jsx9(
1378
+ Input3,
1379
+ {
1380
+ autoComplete: "off",
1381
+ name: "q",
1382
+ type: "search",
1383
+ size: "small",
1384
+ autoFocus: autofocus,
1385
+ defaultValue: query?.[0] || void 0,
1386
+ onChange: debouncedOnChange,
1387
+ placeholder: placeholderText
1388
+ }
1389
+ );
1390
+ };
1391
+
1392
+ // src/components/table/data-table/data-table-query/data-table-query.tsx
1393
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1394
+ var DataTableQuery = ({
1395
+ search,
1396
+ orderBy,
1397
+ filters,
1398
+ prefix
1399
+ }) => {
1400
+ return (search || orderBy || filters || prefix) && /* @__PURE__ */ jsxs9("div", { className: "flex items-start justify-between gap-x-4 px-6 py-4", children: [
1401
+ /* @__PURE__ */ jsx10("div", { className: "w-full max-w-[60%]", children: filters && filters.length > 0 && /* @__PURE__ */ jsx10(DataTableFilter, { filters, prefix }) }),
1402
+ /* @__PURE__ */ jsxs9("div", { className: "flex shrink-0 items-center gap-x-2", children: [
1403
+ search && /* @__PURE__ */ jsx10(
1404
+ DataTableSearch,
1405
+ {
1406
+ prefix,
1407
+ autofocus: search === "autofocus"
1408
+ }
1409
+ ),
1410
+ orderBy && /* @__PURE__ */ jsx10(DataTableOrderBy, { keys: orderBy, prefix })
1411
+ ] })
1412
+ ] });
1413
+ };
1414
+
1415
+ // src/components/table/data-table/data-table-root/data-table-root.tsx
1416
+ import { CommandBar, Table, clx as clx8 } from "@acmekit/ui";
1417
+ import {
1418
+ flexRender
1419
+ } from "@tanstack/react-table";
1420
+ import {
1421
+ Fragment,
1422
+ useEffect as useEffect5,
1423
+ useRef as useRef2,
1424
+ useState as useState7
1425
+ } from "react";
1426
+ import { useTranslation as useTranslation9 } from "react-i18next";
1427
+ import { Link as Link2 } from "react-router-dom";
1428
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1429
+ var DataTableRoot = ({
1430
+ table,
1431
+ columns,
1432
+ pagination,
1433
+ navigateTo,
1434
+ commands,
1435
+ count = 0,
1436
+ noResults = false,
1437
+ noHeader = false,
1438
+ layout = "fit"
1439
+ }) => {
1440
+ const { t: t2 } = useTranslation9();
1441
+ const [showStickyBorder, setShowStickyBorder] = useState7(false);
1442
+ const scrollableRef = useRef2(null);
1443
+ const hasSelect = columns.find((c) => c.id === "select");
1444
+ const hasActions = columns.find((c) => c.id === "actions");
1445
+ const hasCommandBar = commands && commands.length > 0;
1446
+ const rowSelection = table.getState().rowSelection;
1447
+ const { pageIndex, pageSize } = table.getState().pagination;
1448
+ const colCount = columns.length - (hasSelect ? 1 : 0) - (hasActions ? 1 : 0);
1449
+ const colWidth = 100 / colCount;
1450
+ const handleHorizontalScroll = (e) => {
1451
+ const scrollLeft = e.currentTarget.scrollLeft;
1452
+ if (scrollLeft > 0) {
1453
+ setShowStickyBorder(true);
1454
+ } else {
1455
+ setShowStickyBorder(false);
1456
+ }
1457
+ };
1458
+ const handleAction = async (action) => {
1459
+ await action(rowSelection).then(() => {
1460
+ table.resetRowSelection();
1461
+ });
1462
+ };
1463
+ useEffect5(() => {
1464
+ scrollableRef.current?.scroll({ top: 0, left: 0 });
1465
+ }, [pageIndex]);
1466
+ return /* @__PURE__ */ jsxs10(
1467
+ "div",
1468
+ {
1469
+ className: clx8("flex w-full flex-col overflow-hidden", {
1470
+ "flex flex-1 flex-col": layout === "fill"
1471
+ }),
1472
+ children: [
1473
+ /* @__PURE__ */ jsx11(
1474
+ "div",
1475
+ {
1476
+ ref: scrollableRef,
1477
+ onScroll: handleHorizontalScroll,
1478
+ className: clx8("w-full", {
1479
+ "min-h-0 flex-grow overflow-auto": layout === "fill",
1480
+ "overflow-x-auto": layout === "fit"
1481
+ }),
1482
+ children: !noResults ? /* @__PURE__ */ jsxs10(Table, { className: "relative w-full", children: [
1483
+ !noHeader && /* @__PURE__ */ jsx11(Table.Header, { className: "border-t-0", children: table.getHeaderGroups().map((headerGroup) => {
1484
+ return /* @__PURE__ */ jsx11(
1485
+ Table.Row,
1486
+ {
1487
+ className: clx8({
1488
+ "relative border-b-0 [&_th:last-of-type]:w-[1%] [&_th:last-of-type]:whitespace-nowrap": hasActions,
1489
+ "[&_th:first-of-type]:w-[1%] [&_th:first-of-type]:whitespace-nowrap": hasSelect
1490
+ }),
1491
+ children: headerGroup.headers.map((header, index) => {
1492
+ const isActionHeader = header.id === "actions";
1493
+ const isSelectHeader = header.id === "select";
1494
+ const isSpecialHeader = isActionHeader || isSelectHeader;
1495
+ const firstHeader = headerGroup.headers.findIndex(
1496
+ (h) => h.id !== "select"
1497
+ );
1498
+ const isFirstHeader = firstHeader !== -1 ? header.id === headerGroup.headers[firstHeader].id : index === 0;
1499
+ const isStickyHeader = isSelectHeader || isFirstHeader;
1500
+ return /* @__PURE__ */ jsx11(
1501
+ Table.HeaderCell,
1502
+ {
1503
+ "data-table-header-id": header.id,
1504
+ style: {
1505
+ width: !isSpecialHeader ? `${colWidth}%` : void 0
1506
+ },
1507
+ className: clx8({
1508
+ "bg-ui-bg-subtle sticky start-0 after:absolute after:inset-y-0 after:right-0 after:h-full after:w-px after:bg-transparent after:content-['']": isStickyHeader,
1509
+ "start-[68px]": isStickyHeader && hasSelect && !isSelectHeader,
1510
+ "after:bg-ui-border-base": showStickyBorder && isStickyHeader && !isSpecialHeader
1511
+ }),
1512
+ children: flexRender(
1513
+ header.column.columnDef.header,
1514
+ header.getContext()
1515
+ )
1516
+ },
1517
+ header.id
1518
+ );
1519
+ })
1520
+ },
1521
+ headerGroup.id
1522
+ );
1523
+ }) }),
1524
+ /* @__PURE__ */ jsx11(Table.Body, { className: "border-b-0", children: table.getRowModel().rows.map((row) => {
1525
+ const to = navigateTo ? navigateTo(row) : void 0;
1526
+ const isRowDisabled = hasSelect && !row.getCanSelect();
1527
+ const isOdd = row.depth % 2 !== 0;
1528
+ const cells = row.getVisibleCells();
1529
+ return /* @__PURE__ */ jsx11(
1530
+ Table.Row,
1531
+ {
1532
+ "data-selected": row.getIsSelected(),
1533
+ className: clx8(
1534
+ "transition-fg group/row group relative [&_td:last-of-type]:w-[1%] [&_td:last-of-type]:whitespace-nowrap",
1535
+ "has-[[data-row-link]:focus-visible]:bg-ui-bg-base-hover",
1536
+ {
1537
+ "bg-ui-bg-subtle hover:bg-ui-bg-subtle-hover": isOdd,
1538
+ "cursor-pointer": !!to,
1539
+ "bg-ui-bg-highlight hover:bg-ui-bg-highlight-hover": row.getIsSelected(),
1540
+ "!bg-ui-bg-disabled !hover:bg-ui-bg-disabled": isRowDisabled
1541
+ }
1542
+ ),
1543
+ children: cells.map((cell, index) => {
1544
+ const visibleCells = row.getVisibleCells();
1545
+ const isSelectCell = cell.column.id === "select";
1546
+ const firstCell = visibleCells.findIndex(
1547
+ (h) => h.column.id !== "select"
1548
+ );
1549
+ const isFirstCell = firstCell !== -1 ? cell.column.id === visibleCells[firstCell].column.id : index === 0;
1550
+ const isStickyCell = isSelectCell || isFirstCell;
1551
+ const depthOffset = row.depth > 0 && isFirstCell ? row.depth * 14 + 24 : void 0;
1552
+ const hasLeftOffset = isStickyCell && hasSelect && !isSelectCell;
1553
+ const Inner = flexRender(
1554
+ cell.column.columnDef.cell,
1555
+ cell.getContext()
1556
+ );
1557
+ const isTabableLink = isFirstCell && !!to;
1558
+ const shouldRenderAsLink = !!to && !isSelectCell;
1559
+ return /* @__PURE__ */ jsx11(
1560
+ Table.Cell,
1561
+ {
1562
+ className: clx8({
1563
+ "!ps-0 !pe-0": shouldRenderAsLink,
1564
+ "bg-ui-bg-base group-data-[selected=true]/row:bg-ui-bg-highlight group-data-[selected=true]/row:group-hover/row:bg-ui-bg-highlight-hover group-hover/row:bg-ui-bg-base-hover transition-fg group-has-[[data-row-link]:focus-visible]:bg-ui-bg-base-hover sticky start-0 after:absolute after:inset-y-0 after:right-0 after:h-full after:w-px after:bg-transparent after:content-['']": isStickyCell,
1565
+ "bg-ui-bg-subtle group-hover/row:bg-ui-bg-subtle-hover": isOdd && isStickyCell,
1566
+ "start-[68px]": hasLeftOffset,
1567
+ "after:bg-ui-border-base": showStickyBorder && isStickyCell && !isSelectCell,
1568
+ "!bg-ui-bg-disabled !hover:bg-ui-bg-disabled": isRowDisabled
1569
+ }),
1570
+ style: {
1571
+ paddingLeft: depthOffset ? `${depthOffset}px` : void 0
1572
+ },
1573
+ children: shouldRenderAsLink ? /* @__PURE__ */ jsx11(
1574
+ Link2,
1575
+ {
1576
+ to,
1577
+ className: "size-full outline-none",
1578
+ "data-row-link": true,
1579
+ tabIndex: isTabableLink ? 0 : -1,
1580
+ children: /* @__PURE__ */ jsx11(
1581
+ "div",
1582
+ {
1583
+ className: clx8(
1584
+ "flex size-full items-center pe-6",
1585
+ {
1586
+ "ps-6": isTabableLink && !hasLeftOffset
1587
+ }
1588
+ ),
1589
+ children: Inner
1590
+ }
1591
+ )
1592
+ }
1593
+ ) : Inner
1594
+ },
1595
+ cell.id
1596
+ );
1597
+ })
1598
+ },
1599
+ row.id
1600
+ );
1601
+ }) })
1602
+ ] }) : /* @__PURE__ */ jsx11("div", { className: clx8({ "border-b": layout === "fit" }), children: /* @__PURE__ */ jsx11(NoResults, {}) })
1603
+ }
1604
+ ),
1605
+ pagination && /* @__PURE__ */ jsx11("div", { className: clx8({ "border-t": layout === "fill" }), children: /* @__PURE__ */ jsx11(
1606
+ Pagination,
1607
+ {
1608
+ canNextPage: table.getCanNextPage(),
1609
+ canPreviousPage: table.getCanPreviousPage(),
1610
+ nextPage: table.nextPage,
1611
+ previousPage: table.previousPage,
1612
+ count,
1613
+ pageIndex,
1614
+ pageCount: table.getPageCount(),
1615
+ pageSize
1616
+ }
1617
+ ) }),
1618
+ hasCommandBar && /* @__PURE__ */ jsx11(CommandBar, { open: !!Object.keys(rowSelection).length, children: /* @__PURE__ */ jsxs10(CommandBar.Bar, { children: [
1619
+ /* @__PURE__ */ jsx11(CommandBar.Value, { children: t2("general.countSelected", {
1620
+ count: Object.keys(rowSelection).length
1621
+ }) }),
1622
+ /* @__PURE__ */ jsx11(CommandBar.Seperator, {}),
1623
+ commands?.map((command, index) => {
1624
+ return /* @__PURE__ */ jsxs10(Fragment, { children: [
1625
+ /* @__PURE__ */ jsx11(
1626
+ CommandBar.Command,
1627
+ {
1628
+ label: command.label,
1629
+ shortcut: command.shortcut,
1630
+ action: () => handleAction(command.action)
1631
+ }
1632
+ ),
1633
+ index < commands.length - 1 && /* @__PURE__ */ jsx11(CommandBar.Seperator, {})
1634
+ ] }, index);
1635
+ })
1636
+ ] }) })
1637
+ ]
1638
+ }
1639
+ );
1640
+ };
1641
+ var Pagination = (props) => {
1642
+ const { t: t2 } = useTranslation9();
1643
+ const translations = {
1644
+ of: t2("general.of"),
1645
+ results: t2("general.results"),
1646
+ pages: t2("general.pages"),
1647
+ prev: t2("general.prev"),
1648
+ next: t2("general.next")
1649
+ };
1650
+ return /* @__PURE__ */ jsx11(
1651
+ Table.Pagination,
1652
+ {
1653
+ className: "flex-shrink-0",
1654
+ ...props,
1655
+ translations
1656
+ }
1657
+ );
1658
+ };
1659
+
1660
+ // src/components/table/data-table/data-table.tsx
1661
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
1662
+ var MemoizedDataTableQuery = memo(DataTableQuery);
1663
+ var _DataTable = ({
1664
+ table,
1665
+ columns,
1666
+ pagination,
1667
+ navigateTo,
1668
+ commands,
1669
+ count = 0,
1670
+ search = false,
1671
+ orderBy,
1672
+ filters,
1673
+ prefix,
1674
+ queryObject = {},
1675
+ pageSize,
1676
+ isLoading = false,
1677
+ noHeader = false,
1678
+ layout = "fit",
1679
+ noRecords: noRecordsProps = {}
1680
+ }) => {
1681
+ if (isLoading) {
1682
+ return /* @__PURE__ */ jsx12(
1683
+ TableSkeleton,
1684
+ {
1685
+ layout,
1686
+ rowCount: pageSize,
1687
+ search: !!search,
1688
+ filters: !!filters?.length,
1689
+ orderBy: !!orderBy?.length,
1690
+ pagination: !!pagination
1691
+ }
1692
+ );
1693
+ }
1694
+ const noQuery = Object.values(queryObject).filter((v) => Boolean(v)).length === 0;
1695
+ const noResults = !isLoading && count === 0 && !noQuery;
1696
+ const noRecords = !isLoading && count === 0 && noQuery;
1697
+ if (noRecords) {
1698
+ return /* @__PURE__ */ jsx12(
1699
+ NoRecords,
1700
+ {
1701
+ className: clx9({
1702
+ "flex h-full flex-col overflow-hidden": layout === "fill"
1703
+ }),
1704
+ ...noRecordsProps
1705
+ }
1706
+ );
1707
+ }
1708
+ return /* @__PURE__ */ jsxs11(
1709
+ "div",
1710
+ {
1711
+ className: clx9("divide-y", {
1712
+ "flex h-full flex-col overflow-hidden": layout === "fill"
1713
+ }),
1714
+ children: [
1715
+ /* @__PURE__ */ jsx12(
1716
+ MemoizedDataTableQuery,
1717
+ {
1718
+ search,
1719
+ orderBy,
1720
+ filters,
1721
+ prefix
1722
+ }
1723
+ ),
1724
+ /* @__PURE__ */ jsx12(
1725
+ DataTableRoot,
1726
+ {
1727
+ table,
1728
+ count,
1729
+ columns,
1730
+ pagination: true,
1731
+ navigateTo,
1732
+ commands,
1733
+ noResults,
1734
+ noHeader,
1735
+ layout
1736
+ }
1737
+ )
1738
+ ]
1739
+ }
1740
+ );
1741
+ };
1742
+
1743
+ // src/hooks/use-data-table.tsx
1744
+ import {
1745
+ getCoreRowModel,
1746
+ getExpandedRowModel,
1747
+ getPaginationRowModel,
1748
+ useReactTable
1749
+ } from "@tanstack/react-table";
1750
+ import { useEffect as useEffect6, useMemo as useMemo3, useState as useState8 } from "react";
1751
+ import { useSearchParams as useSearchParams4 } from "react-router-dom";
1752
+ var useDataTable = ({
1753
+ data = [],
1754
+ columns,
1755
+ count = 0,
1756
+ pageSize: _pageSize = 20,
1757
+ enablePagination = true,
1758
+ enableRowSelection = false,
1759
+ enableExpandableRows = false,
1760
+ rowSelection: _rowSelection,
1761
+ getSubRows,
1762
+ getRowId,
1763
+ meta,
1764
+ prefix
1765
+ }) => {
1766
+ const [searchParams, setSearchParams] = useSearchParams4();
1767
+ const offsetKey = `${prefix ? `${prefix}_` : ""}offset`;
1768
+ const offset = searchParams.get(offsetKey);
1769
+ const [{ pageIndex, pageSize }, setPagination] = useState8({
1770
+ pageIndex: offset ? Math.ceil(Number(offset) / _pageSize) : 0,
1771
+ pageSize: _pageSize
1772
+ });
1773
+ const pagination = useMemo3(
1774
+ () => ({
1775
+ pageIndex,
1776
+ pageSize
1777
+ }),
1778
+ [pageIndex, pageSize]
1779
+ );
1780
+ const [localRowSelection, setLocalRowSelection] = useState8({});
1781
+ const rowSelection = _rowSelection?.state ?? localRowSelection;
1782
+ const setRowSelection = _rowSelection?.updater ?? setLocalRowSelection;
1783
+ useEffect6(() => {
1784
+ if (!enablePagination) {
1785
+ return;
1786
+ }
1787
+ const index = offset ? Math.ceil(Number(offset) / _pageSize) : 0;
1788
+ if (index === pageIndex) {
1789
+ return;
1790
+ }
1791
+ setPagination((prev) => ({
1792
+ ...prev,
1793
+ pageIndex: index
1794
+ }));
1795
+ }, [offset, enablePagination, _pageSize, pageIndex]);
1796
+ const onPaginationChange = (updater) => {
1797
+ const state = updater(pagination);
1798
+ const { pageIndex: pageIndex2, pageSize: pageSize2 } = state;
1799
+ setSearchParams((prev) => {
1800
+ if (!pageIndex2) {
1801
+ prev.delete(offsetKey);
1802
+ return prev;
1803
+ }
1804
+ const newSearch = new URLSearchParams(prev);
1805
+ newSearch.set(offsetKey, String(pageIndex2 * pageSize2));
1806
+ return newSearch;
1807
+ });
1808
+ setPagination(state);
1809
+ return state;
1810
+ };
1811
+ const table = useReactTable({
1812
+ data,
1813
+ columns,
1814
+ state: {
1815
+ rowSelection,
1816
+ // We always pass a selection state to the table even if it's not enabled
1817
+ pagination: enablePagination ? pagination : void 0
1818
+ },
1819
+ pageCount: Math.ceil((count ?? 0) / pageSize),
1820
+ enableRowSelection,
1821
+ getRowId,
1822
+ getSubRows,
1823
+ onRowSelectionChange: enableRowSelection ? setRowSelection : void 0,
1824
+ onPaginationChange: enablePagination ? onPaginationChange : void 0,
1825
+ getCoreRowModel: getCoreRowModel(),
1826
+ getPaginationRowModel: enablePagination ? getPaginationRowModel() : void 0,
1827
+ getExpandedRowModel: enableExpandableRows ? getExpandedRowModel() : void 0,
1828
+ manualPagination: enablePagination ? true : void 0,
1829
+ meta
1830
+ });
1831
+ return { table };
1832
+ };
1833
+
1834
+ export {
1835
+ _DataTable,
1836
+ useDataTable
1837
+ };