@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,1116 @@
1
+ import {
2
+ useFeatureFlag
3
+ } from "./chunk-DQCEH3X2.mjs";
4
+ import {
5
+ SingleColumnPage
6
+ } from "./chunk-22YYMH6M.mjs";
7
+ import {
8
+ useExtension
9
+ } from "./chunk-C5P5PL3E.mjs";
10
+ import {
11
+ useActiveViewConfiguration,
12
+ useCreateViewConfiguration,
13
+ useDeleteViewConfiguration,
14
+ useSetActiveViewConfiguration,
15
+ useUpdateViewConfiguration,
16
+ useViewConfigurations
17
+ } from "./chunk-DN3MIYQH.mjs";
18
+ import {
19
+ useUsers
20
+ } from "./chunk-YRWSG3YM.mjs";
21
+ import {
22
+ useQueryParams
23
+ } from "./chunk-C76H5USB.mjs";
24
+ import {
25
+ useDate
26
+ } from "./chunk-DFFLVEZ5.mjs";
27
+ import "./chunk-535OVBXR.mjs";
28
+ import {
29
+ ActionMenu
30
+ } from "./chunk-S3REQHPQ.mjs";
31
+ import "./chunk-OAHCJFG3.mjs";
32
+ import "./chunk-S4DMV3ZT.mjs";
33
+ import "./chunk-FXYH54JP.mjs";
34
+ import "./chunk-774WSTCC.mjs";
35
+ import "./chunk-DTY37DDZ.mjs";
36
+ import "./chunk-QZ7TP4HQ.mjs";
37
+
38
+ // src/routes/users/user-list/components/user-list-table/user-list-table.tsx
39
+ import { Container, createDataTableColumnHelper as createDataTableColumnHelper2 } from "@acmekit/ui";
40
+ import { keepPreviousData } from "@tanstack/react-query";
41
+ import { useMemo as useMemo5 } from "react";
42
+ import { useTranslation as useTranslation4 } from "react-i18next";
43
+ import { useNavigate as useNavigate2 } from "react-router-dom";
44
+ import { PencilSquare as PencilSquare3 } from "@acmekit/icons";
45
+
46
+ // src/components/data-table/data-table.tsx
47
+ import {
48
+ DataTable as UiDataTable,
49
+ useDataTable,
50
+ Heading as Heading2,
51
+ Text as Text2,
52
+ Button as Button3
53
+ } from "@acmekit/ui";
54
+ import React4, { useCallback, useMemo as useMemo2 } from "react";
55
+ import { useTranslation } from "react-i18next";
56
+ import { Link, useNavigate, useSearchParams } from "react-router-dom";
57
+
58
+ // src/components/table/view-selector/view-selector.tsx
59
+ import { useEffect, useState as useState2 } from "react";
60
+ import {
61
+ Button as Button2,
62
+ Tooltip,
63
+ DropdownMenu,
64
+ usePrompt
65
+ } from "@acmekit/ui";
66
+ import {
67
+ Eye,
68
+ Plus,
69
+ Trash,
70
+ PencilSquare,
71
+ Star,
72
+ CheckCircleSolid,
73
+ ArrowUturnLeft
74
+ } from "@acmekit/icons";
75
+
76
+ // src/hooks/use-view-configurations.tsx
77
+ import { useMemo } from "react";
78
+ import { toast } from "@acmekit/ui";
79
+ import { FetchError } from "@acmekit/js-sdk";
80
+ var handleError = (error, message) => {
81
+ let errorMessage = message;
82
+ if (!errorMessage) {
83
+ if (error instanceof FetchError) {
84
+ errorMessage = error.message;
85
+ } else if (error.message) {
86
+ errorMessage = error.message;
87
+ } else {
88
+ errorMessage = "An error occurred";
89
+ }
90
+ }
91
+ toast.error(errorMessage);
92
+ };
93
+ var useViewConfigurations2 = (entity) => {
94
+ const isViewConfigEnabled = useFeatureFlag("view_configurations");
95
+ const listViews = useViewConfigurations(entity, { limit: 100 }, {
96
+ enabled: isViewConfigEnabled && !!entity
97
+ });
98
+ const activeView = useActiveViewConfiguration(entity, {
99
+ enabled: isViewConfigEnabled && !!entity
100
+ });
101
+ const createView = useCreateViewConfiguration(entity, {
102
+ onSuccess: () => {
103
+ toast.success(`View created`);
104
+ },
105
+ onError: (error) => {
106
+ handleError(error, "Failed to create view");
107
+ }
108
+ });
109
+ const setActiveView = useSetActiveViewConfiguration(entity, {
110
+ onSuccess: () => {
111
+ },
112
+ onError: (error) => {
113
+ handleError(error, "Failed to update active view");
114
+ }
115
+ });
116
+ return useMemo(() => ({
117
+ isViewConfigEnabled,
118
+ listViews,
119
+ activeView,
120
+ createView,
121
+ setActiveView,
122
+ isDefaultViewActive: activeView?.is_default_active ?? true
123
+ }), [
124
+ isViewConfigEnabled,
125
+ listViews,
126
+ activeView,
127
+ createView,
128
+ setActiveView
129
+ ]);
130
+ };
131
+ var useViewConfiguration = (entity, viewId) => {
132
+ const updateView = useUpdateViewConfiguration(entity, viewId, {
133
+ onSuccess: () => {
134
+ toast.success(`View updated`);
135
+ },
136
+ onError: (error) => {
137
+ handleError(error, "Failed to update view");
138
+ }
139
+ });
140
+ const deleteView = useDeleteViewConfiguration(entity, viewId, {
141
+ onSuccess: () => {
142
+ toast.success("View deleted successfully");
143
+ },
144
+ onError: (error) => {
145
+ handleError(error, "Failed to delete view");
146
+ }
147
+ });
148
+ return {
149
+ updateView,
150
+ deleteView
151
+ };
152
+ };
153
+
154
+ // src/components/table/save-view-dialog/save-view-dialog.tsx
155
+ import { useState } from "react";
156
+ import {
157
+ Button,
158
+ Input,
159
+ Label,
160
+ Drawer,
161
+ Heading,
162
+ Text
163
+ } from "@acmekit/ui";
164
+ import { useForm } from "react-hook-form";
165
+ import { jsx, jsxs } from "react/jsx-runtime";
166
+ var SaveViewDialog = ({
167
+ entity,
168
+ currentColumns,
169
+ currentConfiguration,
170
+ editingView,
171
+ onClose,
172
+ onSaved
173
+ }) => {
174
+ const { createView } = useViewConfigurations2(entity);
175
+ const { updateView } = useViewConfiguration(entity, editingView?.id || "");
176
+ const [isLoading, setIsLoading] = useState(false);
177
+ const {
178
+ register,
179
+ handleSubmit,
180
+ formState: { errors }
181
+ } = useForm({
182
+ defaultValues: {
183
+ name: editingView?.name || ""
184
+ }
185
+ });
186
+ const onSubmit = async (data) => {
187
+ if (!data.name.trim()) {
188
+ return;
189
+ }
190
+ setIsLoading(true);
191
+ try {
192
+ if (editingView) {
193
+ const result = await updateView.mutateAsync({
194
+ name: data.name.trim(),
195
+ configuration: {
196
+ visible_columns: currentColumns?.visible || editingView.configuration.visible_columns,
197
+ column_order: currentColumns?.order || editingView.configuration.column_order,
198
+ filters: currentConfiguration?.filters || editingView.configuration.filters || {},
199
+ sorting: currentConfiguration?.sorting || editingView.configuration.sorting || null,
200
+ search: currentConfiguration?.search || editingView.configuration.search || ""
201
+ }
202
+ });
203
+ onSaved(result.view_configuration);
204
+ } else {
205
+ const result = await createView.mutateAsync({
206
+ name: data.name.trim(),
207
+ set_active: true,
208
+ configuration: {
209
+ visible_columns: currentColumns?.visible || [],
210
+ column_order: currentColumns?.order || [],
211
+ filters: currentConfiguration?.filters || {},
212
+ sorting: currentConfiguration?.sorting || null,
213
+ search: currentConfiguration?.search || ""
214
+ }
215
+ });
216
+ onSaved(result.view_configuration);
217
+ }
218
+ } catch (error) {
219
+ } finally {
220
+ setIsLoading(false);
221
+ }
222
+ };
223
+ return /* @__PURE__ */ jsx(Drawer, { open: true, onOpenChange: onClose, children: /* @__PURE__ */ jsxs(Drawer.Content, { className: "flex flex-col", children: [
224
+ /* @__PURE__ */ jsxs(Drawer.Header, { children: [
225
+ /* @__PURE__ */ jsx(Drawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: editingView ? "Edit View Name" : "Save as New View" }) }),
226
+ /* @__PURE__ */ jsx(Drawer.Description, { asChild: true, children: /* @__PURE__ */ jsx(Text, { children: editingView ? "Change the name of your saved view" : "Save your current configuration as a new view" }) })
227
+ ] }),
228
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit(onSubmit), className: "flex flex-1 flex-col", children: [
229
+ /* @__PURE__ */ jsx(Drawer.Body, { className: "flex-1", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-2", children: [
230
+ /* @__PURE__ */ jsx(Label, { htmlFor: "name", weight: "plus", children: "View Name" }),
231
+ /* @__PURE__ */ jsx(
232
+ Input,
233
+ {
234
+ ...register("name", {
235
+ required: "Name is required",
236
+ validate: (value) => value.trim().length > 0 || "Name cannot be empty"
237
+ }),
238
+ type: "text",
239
+ placeholder: "Enter view name",
240
+ autoFocus: true
241
+ }
242
+ ),
243
+ errors.name && /* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-error", children: errors.name.message })
244
+ ] }) }),
245
+ /* @__PURE__ */ jsxs(Drawer.Footer, { children: [
246
+ /* @__PURE__ */ jsx(Drawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(
247
+ Button,
248
+ {
249
+ variant: "secondary",
250
+ size: "small",
251
+ type: "button",
252
+ children: "Cancel"
253
+ }
254
+ ) }),
255
+ /* @__PURE__ */ jsx(
256
+ Button,
257
+ {
258
+ variant: "primary",
259
+ size: "small",
260
+ type: "submit",
261
+ isLoading,
262
+ children: editingView ? "Update" : "Save"
263
+ }
264
+ )
265
+ ] })
266
+ ] })
267
+ ] }) });
268
+ };
269
+
270
+ // src/components/table/view-selector/view-selector.tsx
271
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
272
+
273
+ // src/components/table/view-selector/view-pills.tsx
274
+ import { useEffect as useEffect2, useState as useState3 } from "react";
275
+ import {
276
+ Badge as Badge2,
277
+ usePrompt as usePrompt2,
278
+ toast as toast3,
279
+ DropdownMenu as DropdownMenu2
280
+ } from "@acmekit/ui";
281
+ import {
282
+ Trash as Trash2,
283
+ PencilSquare as PencilSquare2,
284
+ ArrowUturnLeft as ArrowUturnLeft2
285
+ } from "@acmekit/icons";
286
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
287
+ var ViewPills = ({
288
+ entity,
289
+ currentColumns,
290
+ currentConfiguration
291
+ }) => {
292
+ const {
293
+ listViews,
294
+ activeView,
295
+ setActiveView,
296
+ isDefaultViewActive
297
+ } = useViewConfigurations2(entity);
298
+ const views = listViews?.view_configurations || [];
299
+ const [saveDialogOpen, setSaveDialogOpen] = useState3(false);
300
+ const [editingView, setEditingView] = useState3(null);
301
+ const [contextMenuOpen, setContextMenuOpen] = useState3(null);
302
+ const [contextMenuPosition, setContextMenuPosition] = useState3({ x: 0, y: 0 });
303
+ const [deletingViewId, setDeletingViewId] = useState3(null);
304
+ const prompt = usePrompt2();
305
+ const currentActiveView = activeView?.view_configuration || null;
306
+ const { deleteView } = useViewConfiguration(entity, deletingViewId || "");
307
+ const handleViewSelect = async (viewId) => {
308
+ try {
309
+ if (viewId === null) {
310
+ await setActiveView.mutateAsync(null);
311
+ return;
312
+ }
313
+ const view = views.find((v) => v.id === viewId);
314
+ if (view) {
315
+ await setActiveView.mutateAsync(viewId);
316
+ }
317
+ } catch (error) {
318
+ console.error("Error in handleViewSelect:", error);
319
+ }
320
+ };
321
+ const handleDeleteView = async (view) => {
322
+ const result = await prompt({
323
+ title: "Delete view",
324
+ description: `Are you sure you want to delete "${view.name}"? This action cannot be undone.`,
325
+ confirmText: "Delete",
326
+ cancelText: "Cancel"
327
+ });
328
+ if (result) {
329
+ setDeletingViewId(view.id);
330
+ }
331
+ };
332
+ useEffect2(() => {
333
+ if (deletingViewId && deleteView.mutateAsync) {
334
+ deleteView.mutateAsync().then(() => {
335
+ setDeletingViewId(null);
336
+ }).catch(() => {
337
+ setDeletingViewId(null);
338
+ });
339
+ }
340
+ }, [deletingViewId, deleteView.mutateAsync]);
341
+ const handleEditView = (view) => {
342
+ setEditingView(view);
343
+ setSaveDialogOpen(true);
344
+ };
345
+ const handleResetSystemDefault = async (systemDefaultView2) => {
346
+ const result = await prompt({
347
+ title: "Reset system default",
348
+ description: "This will delete the saved system default and revert to the original code-level defaults. All users will be affected. Are you sure?",
349
+ confirmText: "Reset",
350
+ cancelText: "Cancel"
351
+ });
352
+ if (result) {
353
+ setDeletingViewId(systemDefaultView2.id);
354
+ }
355
+ };
356
+ const systemDefaultView = views.find((v) => v.is_system_default);
357
+ const personalViews = views.filter((v) => !v.is_system_default);
358
+ const isDefaultActive = isDefaultViewActive;
359
+ const defaultLabel = "Default";
360
+ return /* @__PURE__ */ jsxs3(Fragment2, { children: [
361
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2", children: [
362
+ /* @__PURE__ */ jsxs3("div", { className: "relative inline-block", children: [
363
+ /* @__PURE__ */ jsx3(
364
+ Badge2,
365
+ {
366
+ color: isDefaultActive ? "blue" : "grey",
367
+ size: "xsmall",
368
+ className: "cursor-pointer",
369
+ onClick: () => handleViewSelect(null),
370
+ onContextMenu: (e) => {
371
+ e.preventDefault();
372
+ if (systemDefaultView) {
373
+ setContextMenuPosition({ x: e.clientX, y: e.clientY });
374
+ setContextMenuOpen("default");
375
+ }
376
+ },
377
+ children: defaultLabel
378
+ }
379
+ ),
380
+ systemDefaultView && contextMenuOpen === "default" && /* @__PURE__ */ jsxs3(
381
+ DropdownMenu2,
382
+ {
383
+ open: true,
384
+ onOpenChange: (open) => {
385
+ if (!open) setContextMenuOpen(null);
386
+ },
387
+ children: [
388
+ /* @__PURE__ */ jsx3(DropdownMenu2.Trigger, { asChild: true, children: /* @__PURE__ */ jsx3(
389
+ "div",
390
+ {
391
+ style: {
392
+ position: "fixed",
393
+ left: contextMenuPosition.x,
394
+ top: contextMenuPosition.y,
395
+ width: 0,
396
+ height: 0
397
+ }
398
+ }
399
+ ) }),
400
+ /* @__PURE__ */ jsx3(DropdownMenu2.Content, { align: "start", sideOffset: 0, children: /* @__PURE__ */ jsxs3(
401
+ DropdownMenu2.Item,
402
+ {
403
+ onClick: () => {
404
+ handleResetSystemDefault(systemDefaultView);
405
+ setContextMenuOpen(null);
406
+ },
407
+ className: "flex items-center gap-x-2",
408
+ children: [
409
+ /* @__PURE__ */ jsx3(ArrowUturnLeft2, { className: "text-ui-fg-subtle" }),
410
+ /* @__PURE__ */ jsx3("span", { children: "Reset to code defaults" })
411
+ ]
412
+ }
413
+ ) })
414
+ ]
415
+ }
416
+ )
417
+ ] }),
418
+ personalViews.length > 0 && /* @__PURE__ */ jsx3("div", { className: "text-ui-fg-muted", children: "|" }),
419
+ personalViews.map((view) => /* @__PURE__ */ jsxs3("div", { className: "relative inline-block", children: [
420
+ /* @__PURE__ */ jsx3(
421
+ Badge2,
422
+ {
423
+ color: currentActiveView?.id === view.id ? "blue" : "grey",
424
+ size: "xsmall",
425
+ className: "cursor-pointer",
426
+ onClick: () => handleViewSelect(view.id),
427
+ onContextMenu: (e) => {
428
+ e.preventDefault();
429
+ setContextMenuPosition({ x: e.clientX, y: e.clientY });
430
+ setContextMenuOpen(view.id);
431
+ },
432
+ children: view.name
433
+ }
434
+ ),
435
+ contextMenuOpen === view.id && /* @__PURE__ */ jsxs3(
436
+ DropdownMenu2,
437
+ {
438
+ open: true,
439
+ onOpenChange: (open) => {
440
+ if (!open) setContextMenuOpen(null);
441
+ },
442
+ children: [
443
+ /* @__PURE__ */ jsx3(DropdownMenu2.Trigger, { asChild: true, children: /* @__PURE__ */ jsx3(
444
+ "div",
445
+ {
446
+ style: {
447
+ position: "fixed",
448
+ left: contextMenuPosition.x,
449
+ top: contextMenuPosition.y,
450
+ width: 0,
451
+ height: 0
452
+ }
453
+ }
454
+ ) }),
455
+ /* @__PURE__ */ jsxs3(DropdownMenu2.Content, { align: "start", sideOffset: 0, children: [
456
+ /* @__PURE__ */ jsxs3(
457
+ DropdownMenu2.Item,
458
+ {
459
+ onClick: () => {
460
+ handleEditView(view);
461
+ setContextMenuOpen(null);
462
+ },
463
+ className: "flex items-center gap-x-2",
464
+ children: [
465
+ /* @__PURE__ */ jsx3(PencilSquare2, { className: "text-ui-fg-subtle" }),
466
+ /* @__PURE__ */ jsx3("span", { children: "Edit name" })
467
+ ]
468
+ }
469
+ ),
470
+ /* @__PURE__ */ jsxs3(
471
+ DropdownMenu2.Item,
472
+ {
473
+ onClick: () => {
474
+ handleDeleteView(view);
475
+ setContextMenuOpen(null);
476
+ },
477
+ className: "flex items-center gap-x-2 text-ui-fg-error",
478
+ children: [
479
+ /* @__PURE__ */ jsx3(Trash2, {}),
480
+ /* @__PURE__ */ jsx3("span", { children: "Delete" })
481
+ ]
482
+ }
483
+ )
484
+ ] })
485
+ ]
486
+ }
487
+ )
488
+ ] }, view.id))
489
+ ] }),
490
+ saveDialogOpen && /* @__PURE__ */ jsx3(
491
+ SaveViewDialog,
492
+ {
493
+ entity,
494
+ currentColumns,
495
+ currentConfiguration,
496
+ editingView,
497
+ onClose: () => {
498
+ setSaveDialogOpen(false);
499
+ setEditingView(null);
500
+ },
501
+ onSaved: async (newView) => {
502
+ setSaveDialogOpen(false);
503
+ setEditingView(null);
504
+ toast3.success(`View "${newView.name}" saved successfully`);
505
+ }
506
+ }
507
+ )
508
+ ] });
509
+ };
510
+
511
+ // src/components/data-table/data-table.tsx
512
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
513
+ var DataTable = ({
514
+ data = [],
515
+ columns,
516
+ filters,
517
+ commands,
518
+ action,
519
+ actions,
520
+ actionMenu,
521
+ getRowId,
522
+ rowCount = 0,
523
+ enablePagination = true,
524
+ enableSearch = true,
525
+ autoFocusSearch = false,
526
+ enableFilterMenu,
527
+ rowHref,
528
+ heading,
529
+ headingLevel = "h1",
530
+ subHeading,
531
+ prefix,
532
+ pageSize = 10,
533
+ emptyState,
534
+ rowSelection,
535
+ isLoading = false,
536
+ layout = "auto",
537
+ enableColumnVisibility = false,
538
+ initialColumnVisibility = {},
539
+ onColumnVisibilityChange,
540
+ columnOrder,
541
+ onColumnOrderChange,
542
+ enableViewSelector = false,
543
+ entity,
544
+ currentColumns,
545
+ filterBarContent
546
+ }) => {
547
+ const { t } = useTranslation();
548
+ const isViewConfigEnabled = useFeatureFlag("view_configurations");
549
+ const effectiveEnableColumnVisibility = isViewConfigEnabled && enableColumnVisibility;
550
+ const effectiveEnableViewSelector = isViewConfigEnabled && enableViewSelector;
551
+ const enableFiltering = filters && filters.length > 0;
552
+ const showFilterMenu = enableFilterMenu !== void 0 ? enableFilterMenu : enableFiltering;
553
+ const enableCommands = commands && commands.length > 0;
554
+ const enableSorting = columns.some((column) => column.enableSorting);
555
+ const [columnVisibility, setColumnVisibility] = React4.useState(initialColumnVisibility);
556
+ React4.useEffect(() => {
557
+ const currentKeys = Object.keys(columnVisibility).sort();
558
+ const newKeys = Object.keys(initialColumnVisibility).sort();
559
+ const hasChanged = currentKeys.length !== newKeys.length || currentKeys.some((key, index) => key !== newKeys[index]) || Object.entries(initialColumnVisibility).some(
560
+ ([key, value]) => columnVisibility[key] !== value
561
+ );
562
+ if (hasChanged) {
563
+ setColumnVisibility(initialColumnVisibility);
564
+ }
565
+ }, [initialColumnVisibility]);
566
+ const handleColumnVisibilityChange = React4.useCallback(
567
+ (visibility) => {
568
+ setColumnVisibility(visibility);
569
+ onColumnVisibilityChange?.(visibility);
570
+ },
571
+ [onColumnVisibilityChange]
572
+ );
573
+ const filterIds = useMemo2(() => filters?.map((f) => f.id) ?? [], [filters]);
574
+ const prefixedFilterIds = filterIds.map((id) => getQueryParamKey(id, prefix));
575
+ const { offset, order, q, ...filterParams } = useQueryParams(
576
+ [
577
+ ...filterIds,
578
+ ...enableSorting ? ["order"] : [],
579
+ ...enableSearch ? ["q"] : [],
580
+ ...enablePagination ? ["offset"] : []
581
+ ],
582
+ prefix
583
+ );
584
+ const [_, setSearchParams] = useSearchParams();
585
+ const search = useMemo2(() => {
586
+ return q ?? "";
587
+ }, [q]);
588
+ const handleSearchChange = (value) => {
589
+ setSearchParams((prev) => {
590
+ if (value) {
591
+ prev.set(getQueryParamKey("q", prefix), value);
592
+ } else {
593
+ prev.delete(getQueryParamKey("q", prefix));
594
+ }
595
+ return prev;
596
+ });
597
+ };
598
+ const pagination = useMemo2(() => {
599
+ return offset ? parsePaginationState(offset, pageSize) : { pageIndex: 0, pageSize };
600
+ }, [offset, pageSize]);
601
+ const handlePaginationChange = (value) => {
602
+ setSearchParams((prev) => {
603
+ if (value.pageIndex === 0) {
604
+ prev.delete(getQueryParamKey("offset", prefix));
605
+ } else {
606
+ prev.set(
607
+ getQueryParamKey("offset", prefix),
608
+ transformPaginationState(value).toString()
609
+ );
610
+ }
611
+ return prev;
612
+ });
613
+ };
614
+ const filtering = useMemo2(
615
+ () => parseFilterState(filterIds, filterParams),
616
+ [filterIds, filterParams]
617
+ );
618
+ const handleFilteringChange = (value) => {
619
+ setSearchParams((prev) => {
620
+ Array.from(prev.keys()).forEach((key) => {
621
+ if (prefixedFilterIds.includes(key)) {
622
+ const unprefixedKey = prefix ? key.replace(`${prefix}_`, "") : key;
623
+ if (!(unprefixedKey in value)) {
624
+ prev.delete(key);
625
+ }
626
+ }
627
+ });
628
+ Object.entries(value).forEach(([key, filter]) => {
629
+ const prefixedKey = getQueryParamKey(key, prefix);
630
+ if (filter !== void 0) {
631
+ prev.set(prefixedKey, JSON.stringify(filter));
632
+ } else {
633
+ prev.delete(prefixedKey);
634
+ }
635
+ });
636
+ return prev;
637
+ });
638
+ };
639
+ const sorting = useMemo2(() => {
640
+ return order ? parseSortingState(order) : null;
641
+ }, [order]);
642
+ const currentConfiguration = useMemo2(
643
+ () => ({
644
+ filters: filtering,
645
+ sorting,
646
+ search
647
+ }),
648
+ [filtering, sorting, search]
649
+ );
650
+ const handleSortingChange = (value) => {
651
+ setSearchParams((prev) => {
652
+ if (value) {
653
+ const valueToStore = transformSortingState(value);
654
+ prev.set(getQueryParamKey("order", prefix), valueToStore);
655
+ } else {
656
+ prev.delete(getQueryParamKey("order", prefix));
657
+ }
658
+ return prev;
659
+ });
660
+ };
661
+ const { pagination: paginationTranslations, toolbar: toolbarTranslations } = useDataTableTranslations();
662
+ const navigate = useNavigate();
663
+ const onRowClick = useCallback(
664
+ (event, row) => {
665
+ if (!rowHref) {
666
+ return;
667
+ }
668
+ const href = rowHref(row);
669
+ const basePath = __BASE__ || "/";
670
+ const hrefWithBasePath = `${basePath === "/" ? "" : basePath}${href}`;
671
+ if (event.metaKey || event.ctrlKey || event.button === 1) {
672
+ window.open(hrefWithBasePath, "_blank", "noreferrer");
673
+ return;
674
+ }
675
+ if (event.shiftKey) {
676
+ window.open(hrefWithBasePath, void 0, "noreferrer");
677
+ return;
678
+ }
679
+ navigate(href);
680
+ },
681
+ [navigate, rowHref]
682
+ );
683
+ const instance = useDataTable({
684
+ data,
685
+ columns,
686
+ filters,
687
+ commands,
688
+ rowCount,
689
+ getRowId,
690
+ onRowClick: rowHref ? onRowClick : void 0,
691
+ pagination: enablePagination ? {
692
+ state: pagination,
693
+ onPaginationChange: handlePaginationChange
694
+ } : void 0,
695
+ filtering: enableFiltering ? {
696
+ state: filtering,
697
+ onFilteringChange: handleFilteringChange
698
+ } : void 0,
699
+ sorting: enableSorting ? {
700
+ state: sorting,
701
+ onSortingChange: handleSortingChange
702
+ } : void 0,
703
+ search: enableSearch ? {
704
+ state: search,
705
+ onSearchChange: handleSearchChange
706
+ } : void 0,
707
+ rowSelection,
708
+ isLoading,
709
+ columnVisibility: effectiveEnableColumnVisibility ? {
710
+ state: columnVisibility,
711
+ onColumnVisibilityChange: handleColumnVisibilityChange
712
+ } : void 0,
713
+ columnOrder: effectiveEnableColumnVisibility && columnOrder && onColumnOrderChange ? {
714
+ state: columnOrder,
715
+ onColumnOrderChange
716
+ } : void 0
717
+ });
718
+ const shouldRenderHeading = heading || subHeading;
719
+ return /* @__PURE__ */ jsxs4(
720
+ UiDataTable,
721
+ {
722
+ instance,
723
+ className: layout === "fill" ? "h-full [&_tr]:last-of-type:!border-b" : void 0,
724
+ children: [
725
+ /* @__PURE__ */ jsx4(
726
+ UiDataTable.Toolbar,
727
+ {
728
+ className: "flex flex-col items-start justify-between gap-2 md:flex-row md:items-center",
729
+ translations: toolbarTranslations,
730
+ filterBarContent,
731
+ children: /* @__PURE__ */ jsxs4("div", { className: "flex w-full items-center justify-between gap-2", children: [
732
+ /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-x-4", children: [
733
+ shouldRenderHeading && /* @__PURE__ */ jsxs4("div", { children: [
734
+ heading && /* @__PURE__ */ jsx4(Heading2, { level: headingLevel, children: heading }),
735
+ subHeading && /* @__PURE__ */ jsx4(Text2, { size: "small", className: "text-ui-fg-subtle", children: subHeading })
736
+ ] }),
737
+ effectiveEnableViewSelector && entity && /* @__PURE__ */ jsx4(
738
+ ViewPills,
739
+ {
740
+ entity,
741
+ currentColumns,
742
+ currentConfiguration
743
+ }
744
+ )
745
+ ] }),
746
+ /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-x-2", children: [
747
+ showFilterMenu && /* @__PURE__ */ jsx4(UiDataTable.FilterMenu, {}),
748
+ enableSorting && /* @__PURE__ */ jsx4(UiDataTable.SortingMenu, {}),
749
+ enableSearch && /* @__PURE__ */ jsx4("div", { className: "w-full md:w-auto", children: /* @__PURE__ */ jsx4(
750
+ UiDataTable.Search,
751
+ {
752
+ placeholder: t("filters.searchLabel"),
753
+ autoFocus: autoFocusSearch
754
+ }
755
+ ) }),
756
+ actionMenu && /* @__PURE__ */ jsx4(ActionMenu, { variant: "primary", ...actionMenu }),
757
+ actions && actions.length > 0 && /* @__PURE__ */ jsx4(DataTableActions, { actions }),
758
+ !actions && action && /* @__PURE__ */ jsx4(DataTableAction, { ...action })
759
+ ] })
760
+ ] })
761
+ }
762
+ ),
763
+ /* @__PURE__ */ jsx4(UiDataTable.Table, { emptyState }),
764
+ enablePagination && /* @__PURE__ */ jsx4(UiDataTable.Pagination, { translations: paginationTranslations }),
765
+ enableCommands && /* @__PURE__ */ jsx4(
766
+ UiDataTable.CommandBar,
767
+ {
768
+ selectedLabel: (count) => `${count} selected`
769
+ }
770
+ )
771
+ ]
772
+ }
773
+ );
774
+ };
775
+ function transformSortingState(value) {
776
+ return value.desc ? `-${value.id}` : value.id;
777
+ }
778
+ function parseSortingState(value) {
779
+ return value.startsWith("-") ? { id: value.slice(1), desc: true } : { id: value, desc: false };
780
+ }
781
+ function transformPaginationState(value) {
782
+ return value.pageIndex * value.pageSize;
783
+ }
784
+ function parsePaginationState(value, pageSize) {
785
+ const offset = parseInt(value);
786
+ return {
787
+ pageIndex: Math.floor(offset / pageSize),
788
+ pageSize
789
+ };
790
+ }
791
+ function parseFilterState(filterIds, value) {
792
+ if (!value) {
793
+ return {};
794
+ }
795
+ const filters = {};
796
+ for (const id of filterIds) {
797
+ const filterValue = value[id];
798
+ if (filterValue !== void 0) {
799
+ filters[id] = JSON.parse(filterValue);
800
+ }
801
+ }
802
+ return filters;
803
+ }
804
+ function getQueryParamKey(key, prefix) {
805
+ return prefix ? `${prefix}_${key}` : key;
806
+ }
807
+ var useDataTableTranslations = () => {
808
+ const { t } = useTranslation();
809
+ const paginationTranslations = {
810
+ of: t("general.of"),
811
+ results: t("general.results"),
812
+ pages: t("general.pages"),
813
+ prev: t("general.prev"),
814
+ next: t("general.next")
815
+ };
816
+ const toolbarTranslations = {
817
+ clearAll: t("actions.clearAll"),
818
+ sort: t("filters.sortLabel"),
819
+ columns: "Columns"
820
+ };
821
+ return {
822
+ pagination: paginationTranslations,
823
+ toolbar: toolbarTranslations
824
+ };
825
+ };
826
+ var DataTableAction = ({
827
+ label,
828
+ disabled,
829
+ ...props
830
+ }) => {
831
+ const buttonProps = {
832
+ size: "small",
833
+ disabled: disabled ?? false,
834
+ type: "button",
835
+ variant: "secondary"
836
+ };
837
+ if ("to" in props) {
838
+ return /* @__PURE__ */ jsx4(Button3, { ...buttonProps, asChild: true, children: /* @__PURE__ */ jsx4(Link, { to: props.to, children: label }) });
839
+ }
840
+ return /* @__PURE__ */ jsx4(Button3, { ...buttonProps, onClick: props.onClick, children: label });
841
+ };
842
+ var DataTableActions = ({ actions }) => {
843
+ return /* @__PURE__ */ jsx4("div", { className: "flex items-center gap-x-2", children: actions.map((action, index) => /* @__PURE__ */ jsx4(DataTableAction, { ...action }, index)) });
844
+ };
845
+
846
+ // src/components/data-table/helpers/general/use-data-table-date-columns.tsx
847
+ import {
848
+ createDataTableColumnHelper,
849
+ Tooltip as Tooltip2
850
+ } from "@acmekit/ui";
851
+ import { useMemo as useMemo3 } from "react";
852
+ import { useTranslation as useTranslation2 } from "react-i18next";
853
+ import { jsx as jsx5 } from "react/jsx-runtime";
854
+ var columnHelper = createDataTableColumnHelper();
855
+ var useDataTableDateColumns = () => {
856
+ const { t } = useTranslation2();
857
+ const { getFullDate } = useDate();
858
+ return useMemo3(() => {
859
+ return [
860
+ columnHelper.accessor("created_at", {
861
+ header: t("fields.createdAt"),
862
+ cell: ({ row }) => {
863
+ return /* @__PURE__ */ jsx5(
864
+ Tooltip2,
865
+ {
866
+ content: getFullDate({
867
+ date: row.original.created_at,
868
+ includeTime: true
869
+ }),
870
+ children: /* @__PURE__ */ jsx5("span", { children: getFullDate({ date: row.original.created_at }) })
871
+ }
872
+ );
873
+ },
874
+ enableSorting: true,
875
+ sortAscLabel: t("filters.sorting.dateAsc"),
876
+ sortDescLabel: t("filters.sorting.dateDesc")
877
+ }),
878
+ columnHelper.accessor("updated_at", {
879
+ header: t("fields.updatedAt"),
880
+ cell: ({ row }) => {
881
+ return /* @__PURE__ */ jsx5(
882
+ Tooltip2,
883
+ {
884
+ content: getFullDate({
885
+ date: row.original.updated_at,
886
+ includeTime: true
887
+ }),
888
+ children: /* @__PURE__ */ jsx5("span", { children: getFullDate({ date: row.original.updated_at }) })
889
+ }
890
+ );
891
+ },
892
+ enableSorting: true,
893
+ sortAscLabel: t("filters.sorting.dateAsc"),
894
+ sortDescLabel: t("filters.sorting.dateDesc")
895
+ })
896
+ ];
897
+ }, [t, getFullDate]);
898
+ };
899
+
900
+ // src/components/data-table/helpers/general/use-data-table-date-filters.tsx
901
+ import { createDataTableFilterHelper } from "@acmekit/ui";
902
+ import { subDays, subMonths } from "date-fns";
903
+ import { useMemo as useMemo4 } from "react";
904
+ import { useTranslation as useTranslation3 } from "react-i18next";
905
+ var filterHelper = createDataTableFilterHelper();
906
+ var useDateFilterOptions = () => {
907
+ const { t } = useTranslation3();
908
+ const today = useMemo4(() => {
909
+ const date = /* @__PURE__ */ new Date();
910
+ date.setHours(0, 0, 0, 0);
911
+ return date;
912
+ }, []);
913
+ return useMemo4(() => {
914
+ return [
915
+ {
916
+ label: t("filters.date.today"),
917
+ value: {
918
+ $gte: today.toISOString()
919
+ }
920
+ },
921
+ {
922
+ label: t("filters.date.lastSevenDays"),
923
+ value: {
924
+ $gte: subDays(today, 7).toISOString()
925
+ // 7 days ago
926
+ }
927
+ },
928
+ {
929
+ label: t("filters.date.lastThirtyDays"),
930
+ value: {
931
+ $gte: subDays(today, 30).toISOString()
932
+ // 30 days ago
933
+ }
934
+ },
935
+ {
936
+ label: t("filters.date.lastNinetyDays"),
937
+ value: {
938
+ $gte: subDays(today, 90).toISOString()
939
+ // 90 days ago
940
+ }
941
+ },
942
+ {
943
+ label: t("filters.date.lastTwelveMonths"),
944
+ value: {
945
+ $gte: subMonths(today, 12).toISOString()
946
+ // 12 months ago
947
+ }
948
+ }
949
+ ];
950
+ }, [today, t]);
951
+ };
952
+ var useDataTableDateFilters = (disableRangeOption) => {
953
+ const { t } = useTranslation3();
954
+ const { getFullDate } = useDate();
955
+ const dateFilterOptions = useDateFilterOptions();
956
+ const rangeOptions = useMemo4(() => {
957
+ if (disableRangeOption) {
958
+ return {
959
+ disableRangeOption: true
960
+ };
961
+ }
962
+ return {
963
+ rangeOptionStartLabel: t("filters.date.starting"),
964
+ rangeOptionEndLabel: t("filters.date.ending"),
965
+ rangeOptionLabel: t("filters.date.custom"),
966
+ options: dateFilterOptions
967
+ };
968
+ }, [disableRangeOption, t, dateFilterOptions]);
969
+ return useMemo4(() => {
970
+ return [
971
+ filterHelper.accessor("created_at", {
972
+ type: "date",
973
+ label: t("fields.createdAt"),
974
+ format: "date",
975
+ formatDateValue: (date) => getFullDate({ date }),
976
+ options: dateFilterOptions,
977
+ ...rangeOptions
978
+ }),
979
+ filterHelper.accessor("updated_at", {
980
+ type: "date",
981
+ label: t("fields.updatedAt"),
982
+ format: "date",
983
+ formatDateValue: (date) => getFullDate({ date }),
984
+ options: dateFilterOptions,
985
+ ...rangeOptions
986
+ })
987
+ ];
988
+ }, [t, dateFilterOptions, getFullDate, rangeOptions]);
989
+ };
990
+
991
+ // src/routes/users/user-list/components/user-list-table/user-list-table.tsx
992
+ import { jsx as jsx6 } from "react/jsx-runtime";
993
+ var PAGE_SIZE = 20;
994
+ var UserListTable = () => {
995
+ const { q, order, offset } = useQueryParams(["q", "order", "offset"]);
996
+ const { users, count, isPending, isError, error } = useUsers(
997
+ {
998
+ q,
999
+ order,
1000
+ offset: offset ? parseInt(offset) : 0,
1001
+ limit: PAGE_SIZE
1002
+ },
1003
+ {
1004
+ placeholderData: keepPreviousData
1005
+ }
1006
+ );
1007
+ const columns = useColumns();
1008
+ const filters = useFilters();
1009
+ const { t } = useTranslation4();
1010
+ if (isError) {
1011
+ throw error;
1012
+ }
1013
+ return /* @__PURE__ */ jsx6(Container, { className: "divide-y p-0", children: /* @__PURE__ */ jsx6(
1014
+ DataTable,
1015
+ {
1016
+ data: users,
1017
+ columns,
1018
+ filters,
1019
+ getRowId: (row) => row.id,
1020
+ rowCount: count,
1021
+ pageSize: PAGE_SIZE,
1022
+ heading: t("users.domain"),
1023
+ rowHref: (row) => `${row.id}`,
1024
+ isLoading: isPending,
1025
+ action: {
1026
+ label: t("users.invite"),
1027
+ to: "invite"
1028
+ },
1029
+ emptyState: {
1030
+ empty: {
1031
+ heading: t("users.list.empty.heading"),
1032
+ description: t("users.list.empty.description")
1033
+ },
1034
+ filtered: {
1035
+ heading: t("users.list.filtered.heading"),
1036
+ description: t("users.list.filtered.description")
1037
+ }
1038
+ }
1039
+ }
1040
+ ) });
1041
+ };
1042
+ var columnHelper2 = createDataTableColumnHelper2();
1043
+ var useColumns = () => {
1044
+ const { t } = useTranslation4();
1045
+ const navigate = useNavigate2();
1046
+ const dateColumns = useDataTableDateColumns();
1047
+ return useMemo5(
1048
+ () => [
1049
+ columnHelper2.accessor("email", {
1050
+ header: t("fields.email"),
1051
+ cell: ({ row }) => {
1052
+ return row.original.email;
1053
+ },
1054
+ enableSorting: true,
1055
+ sortAscLabel: t("filters.sorting.alphabeticallyAsc"),
1056
+ sortDescLabel: t("filters.sorting.alphabeticallyDesc")
1057
+ }),
1058
+ columnHelper2.accessor("first_name", {
1059
+ header: t("fields.firstName"),
1060
+ cell: ({ row }) => {
1061
+ return row.original.first_name || "-";
1062
+ },
1063
+ enableSorting: true,
1064
+ sortAscLabel: t("filters.sorting.alphabeticallyAsc"),
1065
+ sortDescLabel: t("filters.sorting.alphabeticallyDesc")
1066
+ }),
1067
+ columnHelper2.accessor("last_name", {
1068
+ header: t("fields.lastName"),
1069
+ cell: ({ row }) => {
1070
+ return row.original.last_name || "-";
1071
+ },
1072
+ enableSorting: true,
1073
+ sortAscLabel: t("filters.sorting.alphabeticallyAsc"),
1074
+ sortDescLabel: t("filters.sorting.alphabeticallyDesc")
1075
+ }),
1076
+ ...dateColumns,
1077
+ columnHelper2.action({
1078
+ actions: [
1079
+ {
1080
+ label: t("actions.edit"),
1081
+ icon: /* @__PURE__ */ jsx6(PencilSquare3, {}),
1082
+ onClick: (ctx) => {
1083
+ navigate(`${ctx.row.original.id}/edit`);
1084
+ }
1085
+ }
1086
+ ]
1087
+ })
1088
+ ],
1089
+ [t, navigate, dateColumns]
1090
+ );
1091
+ };
1092
+ var useFilters = () => {
1093
+ const dateFilters = useDataTableDateFilters();
1094
+ return useMemo5(() => {
1095
+ return dateFilters;
1096
+ }, [dateFilters]);
1097
+ };
1098
+
1099
+ // src/routes/users/user-list/user-list.tsx
1100
+ import { jsx as jsx7 } from "react/jsx-runtime";
1101
+ var UserList = () => {
1102
+ const { getWidgets } = useExtension();
1103
+ return /* @__PURE__ */ jsx7(
1104
+ SingleColumnPage,
1105
+ {
1106
+ widgets: {
1107
+ after: getWidgets("user.list.after"),
1108
+ before: getWidgets("user.list.before")
1109
+ },
1110
+ children: /* @__PURE__ */ jsx7(UserListTable, {})
1111
+ }
1112
+ );
1113
+ };
1114
+ export {
1115
+ UserList as Component
1116
+ };