@marktiderman/genesis-ui 2.3.1 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +137 -0
- package/dist/{AppShell-D_E_Hk4g.d.ts → AppShell-CX0M-dfc.d.ts} +24 -6
- package/dist/chunk-CDYZRZ6U.js +141 -0
- package/dist/chunk-CDYZRZ6U.js.map +1 -0
- package/dist/{chunk-UBCYXOXT.js → chunk-DWM7ELFI.js} +28 -7
- package/dist/chunk-DWM7ELFI.js.map +1 -0
- package/dist/{chunk-GDFNAHI4.js → chunk-IXGAEECT.js} +4 -2
- package/dist/chunk-IXGAEECT.js.map +1 -0
- package/dist/{chunk-D4JTQYP5.js → chunk-JA3ZKULS.js} +3 -3
- package/dist/{chunk-D4JTQYP5.js.map → chunk-JA3ZKULS.js.map} +1 -1
- package/dist/chunk-VFO3I7PV.js +24 -0
- package/dist/chunk-VFO3I7PV.js.map +1 -0
- package/dist/components/data/index.d.ts +42 -9
- package/dist/components/data/index.js +208 -76
- package/dist/components/data/index.js.map +1 -1
- package/dist/components/layout/index.d.ts +2 -2
- package/dist/components/layout/index.js +6 -6
- package/dist/components/patterns/index.js +3 -3
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.js +4 -4
- package/dist/hooks/use-data-filters.d.ts +1 -1
- package/dist/hooks/use-data-filters.js +2 -2
- package/dist/hooks/use-mobile.d.ts +1 -0
- package/dist/hooks/use-mobile.js +1 -1
- package/dist/hooks/use-resource-page.d.ts +1 -1
- package/dist/hooks/use-resource-page.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +12 -12
- package/dist/navigation-DBwcZ6vb.d.ts +163 -0
- package/dist/styles.css +11 -0
- package/dist/{use-resource-page-DTQS011Q.d.ts → use-resource-page-Dd2VUv30.d.ts} +15 -1
- package/package.json +8 -6
- package/dist/chunk-6NPEMLBA.js +0 -51
- package/dist/chunk-6NPEMLBA.js.map +0 -1
- package/dist/chunk-GDFNAHI4.js.map +0 -1
- package/dist/chunk-M7AU5DDM.js +0 -26
- package/dist/chunk-M7AU5DDM.js.map +0 -1
- package/dist/chunk-UBCYXOXT.js.map +0 -1
- package/dist/navigation-CpOEyUSb.d.ts +0 -94
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { AppShell, PageHeader } from '../../chunk-
|
|
2
|
+
import { AppShell, PageHeader } from '../../chunk-DWM7ELFI.js';
|
|
3
3
|
export { ViewSettings, ViewToggle } from '../../chunk-46TZGMFW.js';
|
|
4
4
|
import { renderSlot } from '../../chunk-7S7LKQBD.js';
|
|
5
5
|
import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../../chunk-N2ZFNOOT.js';
|
|
@@ -16,18 +16,18 @@ import '../../chunk-B2GIBUQD.js';
|
|
|
16
16
|
import { Badge } from '../../chunk-NPNADZHM.js';
|
|
17
17
|
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '../../chunk-FK42ZGGV.js';
|
|
18
18
|
import { Popover, PopoverTrigger, PopoverContent } from '../../chunk-22XB3Q6H.js';
|
|
19
|
-
import { PageLoading } from '../../chunk-YRYQXU3G.js';
|
|
20
|
-
import { Spinner } from '../../chunk-OVU3Z2MT.js';
|
|
21
19
|
import { Switch } from '../../chunk-27ELYTGE.js';
|
|
22
|
-
import { DetailPage } from '../../chunk-AFZ76Q26.js';
|
|
23
|
-
import '../../chunk-D2LIXA2Y.js';
|
|
24
|
-
import '../../chunk-AVFZ4P4B.js';
|
|
25
20
|
import { EmptyState } from '../../chunk-65SPT7EA.js';
|
|
26
21
|
export { EmptyState } from '../../chunk-65SPT7EA.js';
|
|
27
22
|
import { Button } from '../../chunk-NWSCYLPT.js';
|
|
23
|
+
import { PageLoading } from '../../chunk-YRYQXU3G.js';
|
|
24
|
+
import { Spinner } from '../../chunk-OVU3Z2MT.js';
|
|
28
25
|
import { FormField, FormLabel, FormError, FormDescription } from '../../chunk-R7QFP6EL.js';
|
|
29
26
|
import '../../chunk-F47U5KNW.js';
|
|
30
|
-
import {
|
|
27
|
+
import { DetailPage } from '../../chunk-AFZ76Q26.js';
|
|
28
|
+
import '../../chunk-D2LIXA2Y.js';
|
|
29
|
+
import '../../chunk-AVFZ4P4B.js';
|
|
30
|
+
import { titleCase, useResourcePage } from '../../chunk-IXGAEECT.js';
|
|
31
31
|
export { useSavedViews } from '../../chunk-GCQFVMPI.js';
|
|
32
32
|
import '../../chunk-FTTNGGLA.js';
|
|
33
33
|
import { useViewSettings } from '../../chunk-OZ7ZAYCS.js';
|
|
@@ -35,10 +35,10 @@ export { CommandPalette, useCommandPaletteHotkey } from '../../chunk-CNTWQSUT.js
|
|
|
35
35
|
import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator } from '../../chunk-SEFK4NZV.js';
|
|
36
36
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription } from '../../chunk-7XMZVISM.js';
|
|
37
37
|
import { cn } from '../../chunk-NZ5WBA4R.js';
|
|
38
|
-
import { DefaultLink, defaultNavigate } from '../../chunk-
|
|
39
|
-
export { DefaultLink, defaultNavigate, isPathActive } from '../../chunk-
|
|
38
|
+
import { DefaultLink, defaultNavigate } from '../../chunk-CDYZRZ6U.js';
|
|
39
|
+
export { DefaultLink, defaultNavigate, isPathActive, resolveNavigation } from '../../chunk-CDYZRZ6U.js';
|
|
40
40
|
import { useKeyboardNavigation } from '../../chunk-YJ6MPS6U.js';
|
|
41
|
-
import { useIsMobile } from '../../chunk-
|
|
41
|
+
import { useIsMobile } from '../../chunk-VFO3I7PV.js';
|
|
42
42
|
import { AlertTriangle, RefreshCw, ChevronDown, Check, Search, X, ArrowUpDown, Bookmark, Trash2, BookmarkPlus, Loader2, Columns3, ArrowUp, ArrowDown, ChevronLeft, ChevronRight, ExternalLink, Pencil, ChevronsUpDown, ImageIcon, Upload, AlertCircle, FileIcon, Plus } from 'lucide-react';
|
|
43
43
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
44
44
|
import { useState, useRef, useEffect, useCallback, useMemo, Fragment as Fragment$1 } from 'react';
|
|
@@ -61,7 +61,7 @@ function DataPageShell({
|
|
|
61
61
|
emptyMessage,
|
|
62
62
|
emptyAction,
|
|
63
63
|
hasError = false,
|
|
64
|
-
errorMessage,
|
|
64
|
+
errorMessage: errorMessage2,
|
|
65
65
|
onRetry,
|
|
66
66
|
count,
|
|
67
67
|
totalCount,
|
|
@@ -71,6 +71,7 @@ function DataPageShell({
|
|
|
71
71
|
onPageSizeChange,
|
|
72
72
|
density,
|
|
73
73
|
onDensityChange,
|
|
74
|
+
stats,
|
|
74
75
|
filters,
|
|
75
76
|
hasActiveFilters = false,
|
|
76
77
|
onClearFilters,
|
|
@@ -110,6 +111,7 @@ function DataPageShell({
|
|
|
110
111
|
onDensityChange,
|
|
111
112
|
createAction,
|
|
112
113
|
secondaryActions,
|
|
114
|
+
stats,
|
|
113
115
|
optionsStorageKey: headerOptionsStorageKey
|
|
114
116
|
};
|
|
115
117
|
const Header = header === null ? (() => null) : header ?? PageHeader;
|
|
@@ -146,7 +148,7 @@ function DataPageShell({
|
|
|
146
148
|
) : hasError ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [
|
|
147
149
|
/* @__PURE__ */ jsx(AlertTriangle, { className: "h-10 w-10 text-destructive mb-3" }),
|
|
148
150
|
/* @__PURE__ */ jsx("p", { className: "mb-1 text-sm font-medium text-foreground", children: "Something went wrong" }),
|
|
149
|
-
/* @__PURE__ */ jsx("p", { className: "mb-4 text-sm text-muted-foreground", children:
|
|
151
|
+
/* @__PURE__ */ jsx("p", { className: "mb-4 text-sm text-muted-foreground", children: errorMessage2 || `Failed to load ${entity}s. Please try again.` }),
|
|
150
152
|
onRetry && /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: onRetry, children: [
|
|
151
153
|
/* @__PURE__ */ jsx(RefreshCw, { className: "mr-1 h-4 w-4" }),
|
|
152
154
|
" Retry"
|
|
@@ -285,6 +287,10 @@ function DataFilters({
|
|
|
285
287
|
const [saveDialogOpen, setSaveDialogOpen] = useState(false);
|
|
286
288
|
const [newViewName, setNewViewName] = useState("");
|
|
287
289
|
const hasFilters = filters.some((f) => f.selected.length > 0) || (statusChips?.selected.length ?? 0) > 0;
|
|
290
|
+
const statusOptions = (statusChips?.options ?? []).map(
|
|
291
|
+
(o) => typeof o === "string" ? { value: o, label: o } : { value: o.value, label: o.label ?? o.value, count: o.count }
|
|
292
|
+
);
|
|
293
|
+
const statusVariant = statusChips?.variant ?? "chips";
|
|
288
294
|
const toggleStatus = (status) => {
|
|
289
295
|
if (!statusChips) return;
|
|
290
296
|
const { selected, onChange } = statusChips;
|
|
@@ -300,6 +306,35 @@ function DataFilters({
|
|
|
300
306
|
onViewSaved?.(newViewName.trim());
|
|
301
307
|
};
|
|
302
308
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
309
|
+
statusChips && statusVariant === "tabs" && /* @__PURE__ */ jsx(
|
|
310
|
+
"div",
|
|
311
|
+
{
|
|
312
|
+
className: "flex items-center border rounded-lg overflow-x-auto w-fit max-w-full",
|
|
313
|
+
role: "group",
|
|
314
|
+
"aria-label": "Status",
|
|
315
|
+
"data-testid": "status-tabs",
|
|
316
|
+
children: statusOptions.map((o) => {
|
|
317
|
+
const pressed = statusChips.selected.includes(o.value);
|
|
318
|
+
return /* @__PURE__ */ jsxs(
|
|
319
|
+
Button,
|
|
320
|
+
{
|
|
321
|
+
type: "button",
|
|
322
|
+
variant: pressed ? "default" : "ghost",
|
|
323
|
+
size: "sm",
|
|
324
|
+
className: "h-8 rounded-none gap-1.5",
|
|
325
|
+
onClick: () => toggleStatus(o.value),
|
|
326
|
+
"aria-pressed": pressed,
|
|
327
|
+
testID: `status-tab-${o.value}`,
|
|
328
|
+
children: [
|
|
329
|
+
o.label,
|
|
330
|
+
o.count !== void 0 && /* @__PURE__ */ jsx("span", { className: "text-[10px] tabular-nums opacity-70", children: o.count })
|
|
331
|
+
]
|
|
332
|
+
},
|
|
333
|
+
o.value
|
|
334
|
+
);
|
|
335
|
+
})
|
|
336
|
+
}
|
|
337
|
+
),
|
|
303
338
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row gap-2", children: [
|
|
304
339
|
/* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
|
|
305
340
|
/* @__PURE__ */ jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
|
|
@@ -399,18 +434,27 @@ function DataFilters({
|
|
|
399
434
|
}
|
|
400
435
|
)
|
|
401
436
|
] }),
|
|
402
|
-
statusChips && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 mr-1", children:
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
437
|
+
statusChips && statusVariant === "chips" && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 mr-1", children: statusOptions.map((o) => {
|
|
438
|
+
const pressed = statusChips.selected.includes(o.value);
|
|
439
|
+
return /* @__PURE__ */ jsxs(
|
|
440
|
+
"button",
|
|
441
|
+
{
|
|
442
|
+
type: "button",
|
|
443
|
+
onClick: () => toggleStatus(o.value),
|
|
444
|
+
"aria-pressed": pressed,
|
|
445
|
+
"data-testid": `status-chip-${o.value}`,
|
|
446
|
+
className: cn(
|
|
447
|
+
"text-xs px-2.5 py-1 rounded-full border transition-all font-medium",
|
|
448
|
+
pressed ? "bg-primary text-primary-foreground border-primary" : "bg-background text-muted-foreground border-border hover:border-primary/40"
|
|
449
|
+
),
|
|
450
|
+
children: [
|
|
451
|
+
o.label,
|
|
452
|
+
o.count !== void 0 && /* @__PURE__ */ jsx("span", { className: "ml-1 text-[10px] tabular-nums opacity-70", children: o.count })
|
|
453
|
+
]
|
|
454
|
+
},
|
|
455
|
+
o.value
|
|
456
|
+
);
|
|
457
|
+
}) }),
|
|
414
458
|
filters.map(
|
|
415
459
|
(f) => f.options.length > 0 ? /* @__PURE__ */ jsx(
|
|
416
460
|
FilterCombobox,
|
|
@@ -595,6 +639,9 @@ function getCellClasses(col) {
|
|
|
595
639
|
const hide = col.hideBelow ? col.hideBelow === "sm" ? "hidden sm:table-cell" : col.hideBelow === "md" ? "hidden md:table-cell" : col.hideBelow === "lg" ? "hidden lg:table-cell" : "hidden xl:table-cell" : "";
|
|
596
640
|
return cn(col.width, hide);
|
|
597
641
|
}
|
|
642
|
+
function errorMessage(error) {
|
|
643
|
+
return error instanceof Error ? error.message : String(error);
|
|
644
|
+
}
|
|
598
645
|
function EditableCell({
|
|
599
646
|
item,
|
|
600
647
|
column,
|
|
@@ -602,13 +649,49 @@ function EditableCell({
|
|
|
602
649
|
}) {
|
|
603
650
|
const [editing, setEditing] = useState(false);
|
|
604
651
|
const [draft, setDraft] = useState(String(value ?? ""));
|
|
652
|
+
const [saving, setSaving] = useState(false);
|
|
653
|
+
const [error, setError] = useState(null);
|
|
654
|
+
const inFlight = useRef(false);
|
|
655
|
+
const failedDraft = useRef(null);
|
|
605
656
|
const editable = column.editable;
|
|
657
|
+
const close = useCallback(() => {
|
|
658
|
+
setEditing(false);
|
|
659
|
+
setError(null);
|
|
660
|
+
failedDraft.current = null;
|
|
661
|
+
}, []);
|
|
606
662
|
const commit = useCallback(
|
|
607
663
|
(v) => {
|
|
608
|
-
|
|
609
|
-
|
|
664
|
+
if (inFlight.current) return;
|
|
665
|
+
let result;
|
|
666
|
+
try {
|
|
667
|
+
result = editable.onSave(item, v);
|
|
668
|
+
} catch (e) {
|
|
669
|
+
setError(errorMessage(e));
|
|
670
|
+
failedDraft.current = v;
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
if (!result || typeof result.then !== "function") {
|
|
674
|
+
close();
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
inFlight.current = true;
|
|
678
|
+
setSaving(true);
|
|
679
|
+
setError(null);
|
|
680
|
+
result.then(
|
|
681
|
+
() => {
|
|
682
|
+
inFlight.current = false;
|
|
683
|
+
setSaving(false);
|
|
684
|
+
close();
|
|
685
|
+
},
|
|
686
|
+
(e) => {
|
|
687
|
+
inFlight.current = false;
|
|
688
|
+
setSaving(false);
|
|
689
|
+
setError(errorMessage(e));
|
|
690
|
+
failedDraft.current = v;
|
|
691
|
+
}
|
|
692
|
+
);
|
|
610
693
|
},
|
|
611
|
-
[editable, item]
|
|
694
|
+
[editable, item, close]
|
|
612
695
|
);
|
|
613
696
|
if (!editing) {
|
|
614
697
|
return /* @__PURE__ */ jsx(
|
|
@@ -618,32 +701,80 @@ function EditableCell({
|
|
|
618
701
|
onClick: (e) => {
|
|
619
702
|
e.stopPropagation();
|
|
620
703
|
setDraft(String(value ?? ""));
|
|
704
|
+
setError(null);
|
|
705
|
+
failedDraft.current = null;
|
|
621
706
|
setEditing(true);
|
|
622
707
|
},
|
|
623
708
|
children: column.render ? column.render(item, value) : String(value ?? "\u2014")
|
|
624
709
|
}
|
|
625
710
|
);
|
|
626
711
|
}
|
|
712
|
+
const feedback = error ? /* @__PURE__ */ jsx("p", { role: "alert", className: "mt-1 text-[11px] leading-snug text-destructive", children: error }) : null;
|
|
627
713
|
if (editable.type === "select" && editable.options) {
|
|
628
|
-
return /* @__PURE__ */
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
714
|
+
return /* @__PURE__ */ jsxs(
|
|
715
|
+
"div",
|
|
716
|
+
{
|
|
717
|
+
onClick: (e) => e.stopPropagation(),
|
|
718
|
+
onKeyDown: (e) => {
|
|
719
|
+
if (e.key === "Escape" && !inFlight.current) close();
|
|
720
|
+
},
|
|
721
|
+
"aria-busy": saving || void 0,
|
|
722
|
+
children: [
|
|
723
|
+
/* @__PURE__ */ jsxs(
|
|
724
|
+
Select,
|
|
725
|
+
{
|
|
726
|
+
value: draft,
|
|
727
|
+
disabled: saving,
|
|
728
|
+
onValueChange: (v) => {
|
|
729
|
+
setDraft(v);
|
|
730
|
+
commit(v);
|
|
731
|
+
},
|
|
732
|
+
children: [
|
|
733
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-7 text-xs w-28", "aria-invalid": error ? true : void 0, children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
734
|
+
/* @__PURE__ */ jsx(SelectContent, { children: editable.options.map((opt) => /* @__PURE__ */ jsx(SelectItem, { value: opt, children: opt }, opt)) })
|
|
735
|
+
]
|
|
736
|
+
}
|
|
737
|
+
),
|
|
738
|
+
feedback,
|
|
739
|
+
error && /* @__PURE__ */ jsx(
|
|
740
|
+
"button",
|
|
741
|
+
{
|
|
742
|
+
type: "button",
|
|
743
|
+
className: "mt-0.5 text-[11px] text-muted-foreground underline-offset-2 hover:underline",
|
|
744
|
+
onClick: close,
|
|
745
|
+
children: "Cancel"
|
|
746
|
+
}
|
|
747
|
+
)
|
|
748
|
+
]
|
|
644
749
|
}
|
|
645
|
-
|
|
646
|
-
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
return /* @__PURE__ */ jsxs("div", { onClick: (e) => e.stopPropagation(), "aria-busy": saving || void 0, children: [
|
|
753
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
754
|
+
/* @__PURE__ */ jsx(
|
|
755
|
+
Input,
|
|
756
|
+
{
|
|
757
|
+
autoFocus: true,
|
|
758
|
+
className: cn("h-7 text-xs w-full", saving && "pr-7 opacity-70"),
|
|
759
|
+
value: draft,
|
|
760
|
+
readOnly: saving,
|
|
761
|
+
"aria-invalid": error ? true : void 0,
|
|
762
|
+
onChange: (e) => setDraft(e.target.value),
|
|
763
|
+
onBlur: () => {
|
|
764
|
+
if (inFlight.current) return;
|
|
765
|
+
if (failedDraft.current === draft) close();
|
|
766
|
+
else commit(draft);
|
|
767
|
+
},
|
|
768
|
+
onKeyDown: (e) => {
|
|
769
|
+
if (e.key === "Enter") commit(draft);
|
|
770
|
+
if (e.key === "Escape" && !inFlight.current) close();
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
),
|
|
774
|
+
saving && /* @__PURE__ */ jsx(Spinner, { className: "absolute right-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2", "aria-label": "Saving" })
|
|
775
|
+
] }),
|
|
776
|
+
feedback
|
|
777
|
+
] });
|
|
647
778
|
}
|
|
648
779
|
function ResizeHandle({
|
|
649
780
|
onResize,
|
|
@@ -1992,15 +2123,15 @@ function ResourceFormFieldRenderer({
|
|
|
1992
2123
|
name: field.key,
|
|
1993
2124
|
control,
|
|
1994
2125
|
render: ({ field: f, fieldState }) => {
|
|
1995
|
-
const
|
|
2126
|
+
const errorMessage2 = fieldState.error?.message;
|
|
1996
2127
|
const ariaProps = {
|
|
1997
|
-
"aria-invalid": !!
|
|
1998
|
-
"aria-describedby":
|
|
2128
|
+
"aria-invalid": !!errorMessage2 || void 0,
|
|
2129
|
+
"aria-describedby": errorMessage2 ? `${field.key}-error` : field.description ? `${field.key}-desc` : void 0,
|
|
1999
2130
|
"aria-required": field.required || void 0
|
|
2000
2131
|
};
|
|
2001
2132
|
if (fieldType === "switch") {
|
|
2002
2133
|
return /* @__PURE__ */ jsxs(FormField, { className: "flex flex-row items-center justify-between rounded-lg border p-4", children: [
|
|
2003
|
-
/* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: /* @__PURE__ */ jsx(FormLabel, { error: !!
|
|
2134
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: /* @__PURE__ */ jsx(FormLabel, { error: !!errorMessage2, children: label }) }),
|
|
2004
2135
|
/* @__PURE__ */ jsx(
|
|
2005
2136
|
Switch,
|
|
2006
2137
|
{
|
|
@@ -2024,14 +2155,14 @@ function ResourceFormFieldRenderer({
|
|
|
2024
2155
|
}
|
|
2025
2156
|
),
|
|
2026
2157
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1 leading-none", children: [
|
|
2027
|
-
/* @__PURE__ */ jsx(FormLabel, { error: !!
|
|
2028
|
-
/* @__PURE__ */ jsx(FormError, { id: `${field.key}-error`, children:
|
|
2158
|
+
/* @__PURE__ */ jsx(FormLabel, { error: !!errorMessage2, children: label }),
|
|
2159
|
+
/* @__PURE__ */ jsx(FormError, { id: `${field.key}-error`, children: errorMessage2 })
|
|
2029
2160
|
] })
|
|
2030
2161
|
] });
|
|
2031
2162
|
}
|
|
2032
2163
|
if (fieldType === "select" && field.options) {
|
|
2033
2164
|
return /* @__PURE__ */ jsxs(FormField, { children: [
|
|
2034
|
-
/* @__PURE__ */ jsx(FormLabel, { error: !!
|
|
2165
|
+
/* @__PURE__ */ jsx(FormLabel, { error: !!errorMessage2, required: field.required, children: label }),
|
|
2035
2166
|
/* @__PURE__ */ jsxs(
|
|
2036
2167
|
Select,
|
|
2037
2168
|
{
|
|
@@ -2051,12 +2182,12 @@ function ResourceFormFieldRenderer({
|
|
|
2051
2182
|
}
|
|
2052
2183
|
),
|
|
2053
2184
|
field.description && /* @__PURE__ */ jsx(FormDescription, { id: `${field.key}-desc`, children: field.description }),
|
|
2054
|
-
/* @__PURE__ */ jsx(FormError, { id: `${field.key}-error`, children:
|
|
2185
|
+
/* @__PURE__ */ jsx(FormError, { id: `${field.key}-error`, children: errorMessage2 })
|
|
2055
2186
|
] });
|
|
2056
2187
|
}
|
|
2057
2188
|
if (fieldType === "relation" && field.relation) {
|
|
2058
2189
|
return /* @__PURE__ */ jsxs(FormField, { children: [
|
|
2059
|
-
/* @__PURE__ */ jsx(FormLabel, { error: !!
|
|
2190
|
+
/* @__PURE__ */ jsx(FormLabel, { error: !!errorMessage2, required: field.required, children: label }),
|
|
2060
2191
|
/* @__PURE__ */ jsx(
|
|
2061
2192
|
RelationField,
|
|
2062
2193
|
{
|
|
@@ -2067,12 +2198,12 @@ function ResourceFormFieldRenderer({
|
|
|
2067
2198
|
}
|
|
2068
2199
|
),
|
|
2069
2200
|
field.description && /* @__PURE__ */ jsx(FormDescription, { id: `${field.key}-desc`, children: field.description }),
|
|
2070
|
-
/* @__PURE__ */ jsx(FormError, { id: `${field.key}-error`, children:
|
|
2201
|
+
/* @__PURE__ */ jsx(FormError, { id: `${field.key}-error`, children: errorMessage2 })
|
|
2071
2202
|
] });
|
|
2072
2203
|
}
|
|
2073
2204
|
if (fieldType === "file" || fieldType === "image") {
|
|
2074
2205
|
return /* @__PURE__ */ jsxs(FormField, { children: [
|
|
2075
|
-
/* @__PURE__ */ jsx(FormLabel, { error: !!
|
|
2206
|
+
/* @__PURE__ */ jsx(FormLabel, { error: !!errorMessage2, required: field.required, children: label }),
|
|
2076
2207
|
/* @__PURE__ */ jsx(
|
|
2077
2208
|
FileUploadField,
|
|
2078
2209
|
{
|
|
@@ -2083,12 +2214,12 @@ function ResourceFormFieldRenderer({
|
|
|
2083
2214
|
}
|
|
2084
2215
|
),
|
|
2085
2216
|
field.description && /* @__PURE__ */ jsx(FormDescription, { id: `${field.key}-desc`, children: field.description }),
|
|
2086
|
-
/* @__PURE__ */ jsx(FormError, { id: `${field.key}-error`, children:
|
|
2217
|
+
/* @__PURE__ */ jsx(FormError, { id: `${field.key}-error`, children: errorMessage2 })
|
|
2087
2218
|
] });
|
|
2088
2219
|
}
|
|
2089
2220
|
if (fieldType === "textarea") {
|
|
2090
2221
|
return /* @__PURE__ */ jsxs(FormField, { children: [
|
|
2091
|
-
/* @__PURE__ */ jsx(FormLabel, { error: !!
|
|
2222
|
+
/* @__PURE__ */ jsx(FormLabel, { error: !!errorMessage2, required: field.required, children: label }),
|
|
2092
2223
|
/* @__PURE__ */ jsx(
|
|
2093
2224
|
Textarea,
|
|
2094
2225
|
{
|
|
@@ -2102,12 +2233,12 @@ function ResourceFormFieldRenderer({
|
|
|
2102
2233
|
}
|
|
2103
2234
|
),
|
|
2104
2235
|
field.description && /* @__PURE__ */ jsx(FormDescription, { id: `${field.key}-desc`, children: field.description }),
|
|
2105
|
-
/* @__PURE__ */ jsx(FormError, { id: `${field.key}-error`, children:
|
|
2236
|
+
/* @__PURE__ */ jsx(FormError, { id: `${field.key}-error`, children: errorMessage2 })
|
|
2106
2237
|
] });
|
|
2107
2238
|
}
|
|
2108
2239
|
if (fieldType === "number") {
|
|
2109
2240
|
return /* @__PURE__ */ jsxs(FormField, { children: [
|
|
2110
|
-
/* @__PURE__ */ jsx(FormLabel, { error: !!
|
|
2241
|
+
/* @__PURE__ */ jsx(FormLabel, { error: !!errorMessage2, required: field.required, children: label }),
|
|
2111
2242
|
/* @__PURE__ */ jsx(
|
|
2112
2243
|
Input,
|
|
2113
2244
|
{
|
|
@@ -2126,11 +2257,11 @@ function ResourceFormFieldRenderer({
|
|
|
2126
2257
|
}
|
|
2127
2258
|
),
|
|
2128
2259
|
field.description && /* @__PURE__ */ jsx(FormDescription, { id: `${field.key}-desc`, children: field.description }),
|
|
2129
|
-
/* @__PURE__ */ jsx(FormError, { id: `${field.key}-error`, children:
|
|
2260
|
+
/* @__PURE__ */ jsx(FormError, { id: `${field.key}-error`, children: errorMessage2 })
|
|
2130
2261
|
] });
|
|
2131
2262
|
}
|
|
2132
2263
|
return /* @__PURE__ */ jsxs(FormField, { children: [
|
|
2133
|
-
/* @__PURE__ */ jsx(FormLabel, { error: !!
|
|
2264
|
+
/* @__PURE__ */ jsx(FormLabel, { error: !!errorMessage2, required: field.required, children: label }),
|
|
2134
2265
|
/* @__PURE__ */ jsx(
|
|
2135
2266
|
Input,
|
|
2136
2267
|
{
|
|
@@ -2144,7 +2275,7 @@ function ResourceFormFieldRenderer({
|
|
|
2144
2275
|
}
|
|
2145
2276
|
),
|
|
2146
2277
|
field.description && /* @__PURE__ */ jsx(FormDescription, { id: `${field.key}-desc`, children: field.description }),
|
|
2147
|
-
/* @__PURE__ */ jsx(FormError, { id: `${field.key}-error`, children:
|
|
2278
|
+
/* @__PURE__ */ jsx(FormError, { id: `${field.key}-error`, children: errorMessage2 })
|
|
2148
2279
|
] });
|
|
2149
2280
|
}
|
|
2150
2281
|
}
|
|
@@ -2431,6 +2562,7 @@ function ResourcePage(props) {
|
|
|
2431
2562
|
subtitle,
|
|
2432
2563
|
icon,
|
|
2433
2564
|
columns: columnsProp,
|
|
2565
|
+
getKey: getKeyProp,
|
|
2434
2566
|
detail = "panel",
|
|
2435
2567
|
detailWidth = "md",
|
|
2436
2568
|
titleField: titleFieldProp,
|
|
@@ -2451,7 +2583,7 @@ function ResourcePage(props) {
|
|
|
2451
2583
|
onSearchChange,
|
|
2452
2584
|
loading: loadingProp,
|
|
2453
2585
|
error: errorProp,
|
|
2454
|
-
errorMessage,
|
|
2586
|
+
errorMessage: errorMessage2,
|
|
2455
2587
|
onRetry: onRetryProp,
|
|
2456
2588
|
savedViews,
|
|
2457
2589
|
onLoadView,
|
|
@@ -2548,6 +2680,10 @@ function ResourcePage(props) {
|
|
|
2548
2680
|
resourceHook.remove,
|
|
2549
2681
|
resourceHook.list
|
|
2550
2682
|
]);
|
|
2683
|
+
const keyOf = useCallback(
|
|
2684
|
+
(item) => getKeyProp ? getKeyProp(item) : String(item.id ?? ""),
|
|
2685
|
+
[getKeyProp]
|
|
2686
|
+
);
|
|
2551
2687
|
const [selectedIds, setSelectedIds] = useState(/* @__PURE__ */ new Set());
|
|
2552
2688
|
const handleToggleSelect = useCallback((id) => {
|
|
2553
2689
|
setSelectedIds((prev) => {
|
|
@@ -2560,13 +2696,9 @@ function ResourcePage(props) {
|
|
|
2560
2696
|
const handleToggleAll = useCallback(() => {
|
|
2561
2697
|
setSelectedIds((prev) => {
|
|
2562
2698
|
if (prev.size === page.data.length) return /* @__PURE__ */ new Set();
|
|
2563
|
-
return new Set(
|
|
2564
|
-
page.data.map(
|
|
2565
|
-
(item) => String(item.id ?? "")
|
|
2566
|
-
)
|
|
2567
|
-
);
|
|
2699
|
+
return new Set(page.data.map(keyOf));
|
|
2568
2700
|
});
|
|
2569
|
-
}, [page.data]);
|
|
2701
|
+
}, [page.data, keyOf]);
|
|
2570
2702
|
const handleClearSelection = useCallback(() => {
|
|
2571
2703
|
setSelectedIds(/* @__PURE__ */ new Set());
|
|
2572
2704
|
}, []);
|
|
@@ -2602,6 +2734,8 @@ function ResourcePage(props) {
|
|
|
2602
2734
|
header: col.header ?? col.key,
|
|
2603
2735
|
sortable: col.sortable ?? true,
|
|
2604
2736
|
hideBelow: col.hideBelow,
|
|
2737
|
+
editable: col.editable,
|
|
2738
|
+
accessor: col.accessor,
|
|
2605
2739
|
render: col.render ? (item, value) => col.render(item, value, actions) : void 0
|
|
2606
2740
|
})) : page.tableColumns;
|
|
2607
2741
|
if (!isServerControlled) return base;
|
|
@@ -2721,9 +2855,7 @@ function ResourcePage(props) {
|
|
|
2721
2855
|
onToggleSelect: hasBulkSelect ? (index) => {
|
|
2722
2856
|
const item = page.data[index];
|
|
2723
2857
|
if (item) {
|
|
2724
|
-
handleToggleSelect(
|
|
2725
|
-
String(item.id ?? "")
|
|
2726
|
-
);
|
|
2858
|
+
handleToggleSelect(keyOf(item));
|
|
2727
2859
|
}
|
|
2728
2860
|
} : void 0,
|
|
2729
2861
|
// Supplied only while there is an open detail to close — the hook
|
|
@@ -2837,7 +2969,7 @@ function ResourcePage(props) {
|
|
|
2837
2969
|
isLoading,
|
|
2838
2970
|
hasError,
|
|
2839
2971
|
isEmpty,
|
|
2840
|
-
errorMessage,
|
|
2972
|
+
errorMessage: errorMessage2,
|
|
2841
2973
|
onRetry: isClientMode ? () => resourceHook.list.refetch() : onRetryProp,
|
|
2842
2974
|
viewMode: page.viewMode,
|
|
2843
2975
|
onViewModeChange: page.setViewMode,
|
|
@@ -2902,7 +3034,7 @@ function ResourcePage(props) {
|
|
|
2902
3034
|
items: page.data,
|
|
2903
3035
|
viewMode: page.viewMode,
|
|
2904
3036
|
gridCols: gridColsProp,
|
|
2905
|
-
getKey:
|
|
3037
|
+
getKey: keyOf,
|
|
2906
3038
|
focusedIndex: keyboardNav.focusedIndex,
|
|
2907
3039
|
keyboardContainerRef: keyboardNav.containerRef,
|
|
2908
3040
|
renderTable: (items) => renderTableProp ? renderTableProp(items) : renderSlot(
|
|
@@ -2911,7 +3043,7 @@ function ResourcePage(props) {
|
|
|
2911
3043
|
{
|
|
2912
3044
|
items,
|
|
2913
3045
|
columns: tableColumns,
|
|
2914
|
-
getKey:
|
|
3046
|
+
getKey: keyOf,
|
|
2915
3047
|
onRowClick: detail !== "none" ? handleRowClick : void 0,
|
|
2916
3048
|
selectable: !!bulkActions && bulkActions.length > 0,
|
|
2917
3049
|
selected: selectedIds,
|