@wordrhyme/auto-crud 1.3.0 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1225 -1675
- package/dist/index.d.cts +70 -50
- package/dist/index.d.ts +86 -66
- package/dist/index.js +959 -1414
- package/package.json +5 -9
package/dist/index.js
CHANGED
|
@@ -1,23 +1,17 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useReducer, useRef, useState } from "react";
|
|
3
|
-
import { ArrowDownUp, BadgeCheck, CalendarIcon, Check, CheckCircle2, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, ChevronsLeft, ChevronsRight, ChevronsUpDown, CommandIcon, Download, Ellipsis, EyeOff, FileDown, FileSpreadsheetIcon, GripVertical, ListFilter, ListFilterIcon, Loader2, PlusCircle, Settings2, Text, Trash2, Upload, X, XCircle } from "lucide-react";
|
|
3
|
+
import { ArrowDownUp, BadgeCheck, CalendarIcon, Check, CheckCircle2, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, ChevronsLeft, ChevronsRight, ChevronsUpDown, CommandIcon, Download, Ellipsis, EyeOff, FileDown, FileSpreadsheetIcon, GripVertical, ListFilter, ListFilterIcon, Loader2, PlusCircle, RefreshCw, Settings2, Text, Trash2, Upload, X, XCircle } from "lucide-react";
|
|
4
4
|
import { flexRender, getCoreRowModel, getFacetedMinMaxValues, getFacetedRowModel, getFacetedUniqueValues, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
|
|
5
|
-
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, Badge, Button, Calendar, Checkbox, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList,
|
|
5
|
+
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, Badge, Button, Calendar, Checkbox, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger, Input, Label, Popover, PopoverContent, PopoverTrigger, Select as Select$1, SelectContent, SelectItem, SelectTrigger, SelectValue, Separator, Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, Slider, Switch, Table as Table$1, TableBody, TableCell, TableHead, TableHeader, TableRow, cn as cn$1 } from "@wordrhyme/shadcn";
|
|
6
6
|
import { clsx } from "clsx";
|
|
7
7
|
import { twMerge } from "tailwind-merge";
|
|
8
8
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
import { customAlphabet } from "nanoid";
|
|
10
|
-
import {
|
|
11
|
-
import { restrictToHorizontalAxis, restrictToParentElement, restrictToVerticalAxis } from "@dnd-kit/modifiers";
|
|
12
|
-
import { SortableContext, arrayMove, horizontalListSortingStrategy, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable";
|
|
13
|
-
import { CSS } from "@dnd-kit/utilities";
|
|
14
|
-
import { Slot } from "@radix-ui/react-slot";
|
|
15
|
-
import * as ReactDOM from "react-dom";
|
|
16
|
-
import { useDirection } from "@radix-ui/react-direction";
|
|
10
|
+
import { ActionBar, ActionBarClose, ActionBarGroup, ActionBarItem, ActionBarSelection, ActionBarSeparator, Faceted, FacetedBadgeList, FacetedContent, FacetedEmpty, FacetedGroup, FacetedInput, FacetedItem, FacetedList, FacetedTrigger, MultiCombobox, Select, Select as Select$2, Sortable, SortableContent, SortableItem, SortableItemHandle, SortableOverlay } from "@wordrhyme/shadcn-ui";
|
|
17
11
|
import { z } from "zod";
|
|
18
|
-
import { createForm
|
|
19
|
-
import {
|
|
20
|
-
import { connect, mapProps } from "@formily
|
|
12
|
+
import { createForm } from "@formily/core";
|
|
13
|
+
import { action, observable } from "@formily/reactive";
|
|
14
|
+
import { Form, JsonSchemaField, connect, mapProps } from "@wordrhyme/formily-shadcn";
|
|
21
15
|
import { toast } from "sonner";
|
|
22
16
|
import { keepPreviousData } from "@tanstack/react-query";
|
|
23
17
|
|
|
@@ -55,7 +49,7 @@ function DataTablePagination({ table, pageSizeOptions = [
|
|
|
55
49
|
children: [/* @__PURE__ */ jsx("p", {
|
|
56
50
|
className: "whitespace-nowrap font-medium text-sm",
|
|
57
51
|
children: "Rows per page"
|
|
58
|
-
}), /* @__PURE__ */ jsxs(Select, {
|
|
52
|
+
}), /* @__PURE__ */ jsxs(Select$1, {
|
|
59
53
|
value: `${table.getState().pagination.pageSize}`,
|
|
60
54
|
onValueChange: (value) => {
|
|
61
55
|
table.setPageSize(Number(value));
|
|
@@ -128,55 +122,6 @@ function DataTablePagination({ table, pageSizeOptions = [
|
|
|
128
122
|
});
|
|
129
123
|
}
|
|
130
124
|
|
|
131
|
-
//#endregion
|
|
132
|
-
//#region src/components/ui/table.tsx
|
|
133
|
-
function Table$1({ className,...props }) {
|
|
134
|
-
return /* @__PURE__ */ jsx("div", {
|
|
135
|
-
"data-slot": "table-container",
|
|
136
|
-
className: "relative w-full overflow-x-auto",
|
|
137
|
-
children: /* @__PURE__ */ jsx("table", {
|
|
138
|
-
"data-slot": "table",
|
|
139
|
-
className: cn("w-full caption-bottom text-sm", className),
|
|
140
|
-
...props
|
|
141
|
-
})
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
function TableHeader({ className,...props }) {
|
|
145
|
-
return /* @__PURE__ */ jsx("thead", {
|
|
146
|
-
"data-slot": "table-header",
|
|
147
|
-
className: cn("[&_tr]:border-b", className),
|
|
148
|
-
...props
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
function TableBody({ className,...props }) {
|
|
152
|
-
return /* @__PURE__ */ jsx("tbody", {
|
|
153
|
-
"data-slot": "table-body",
|
|
154
|
-
className: cn("[&_tr:last-child]:border-0", className),
|
|
155
|
-
...props
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
function TableRow({ className,...props }) {
|
|
159
|
-
return /* @__PURE__ */ jsx("tr", {
|
|
160
|
-
"data-slot": "table-row",
|
|
161
|
-
className: cn("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted", className),
|
|
162
|
-
...props
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
function TableHead({ className,...props }) {
|
|
166
|
-
return /* @__PURE__ */ jsx("th", {
|
|
167
|
-
"data-slot": "table-head",
|
|
168
|
-
className: cn("h-10 whitespace-nowrap px-2 text-left align-middle font-medium text-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", className),
|
|
169
|
-
...props
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
function TableCell({ className,...props }) {
|
|
173
|
-
return /* @__PURE__ */ jsx("td", {
|
|
174
|
-
"data-slot": "table-cell",
|
|
175
|
-
className: cn("whitespace-nowrap p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", className),
|
|
176
|
-
...props
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
|
|
180
125
|
//#endregion
|
|
181
126
|
//#region src/config/data-table.ts
|
|
182
127
|
const dataTableConfig = {
|
|
@@ -911,454 +856,6 @@ function DataTableRangeFilter({ filter, column, inputId, onFilterUpdate, classNa
|
|
|
911
856
|
});
|
|
912
857
|
}
|
|
913
858
|
|
|
914
|
-
//#endregion
|
|
915
|
-
//#region src/components/ui/faceted.tsx
|
|
916
|
-
const FacetedContext = React.createContext(null);
|
|
917
|
-
function useFacetedContext(name) {
|
|
918
|
-
const context = React.useContext(FacetedContext);
|
|
919
|
-
if (!context) throw new Error(`\`${name}\` must be within Faceted`);
|
|
920
|
-
return context;
|
|
921
|
-
}
|
|
922
|
-
function Faceted(props) {
|
|
923
|
-
const { open: openProp, onOpenChange: onOpenChangeProp, value, onValueChange, children, multiple = false,...facetedProps } = props;
|
|
924
|
-
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false);
|
|
925
|
-
const isControlled = openProp !== void 0;
|
|
926
|
-
const open = isControlled ? openProp : uncontrolledOpen;
|
|
927
|
-
const onOpenChange = React.useCallback((newOpen) => {
|
|
928
|
-
if (!isControlled) setUncontrolledOpen(newOpen);
|
|
929
|
-
onOpenChangeProp?.(newOpen);
|
|
930
|
-
}, [isControlled, onOpenChangeProp]);
|
|
931
|
-
const onItemSelect = React.useCallback((selectedValue) => {
|
|
932
|
-
if (!onValueChange) return;
|
|
933
|
-
if (multiple) {
|
|
934
|
-
const currentValue = Array.isArray(value) ? value : [];
|
|
935
|
-
onValueChange(currentValue.includes(selectedValue) ? currentValue.filter((v) => v !== selectedValue) : [...currentValue, selectedValue]);
|
|
936
|
-
} else {
|
|
937
|
-
if (value === selectedValue) onValueChange(void 0);
|
|
938
|
-
else onValueChange(selectedValue);
|
|
939
|
-
requestAnimationFrame(() => onOpenChange(false));
|
|
940
|
-
}
|
|
941
|
-
}, [
|
|
942
|
-
multiple,
|
|
943
|
-
value,
|
|
944
|
-
onValueChange,
|
|
945
|
-
onOpenChange
|
|
946
|
-
]);
|
|
947
|
-
const contextValue = React.useMemo(() => ({
|
|
948
|
-
value,
|
|
949
|
-
onItemSelect,
|
|
950
|
-
multiple
|
|
951
|
-
}), [
|
|
952
|
-
value,
|
|
953
|
-
onItemSelect,
|
|
954
|
-
multiple
|
|
955
|
-
]);
|
|
956
|
-
return /* @__PURE__ */ jsx(FacetedContext.Provider, {
|
|
957
|
-
value: contextValue,
|
|
958
|
-
children: /* @__PURE__ */ jsx(Popover, {
|
|
959
|
-
open,
|
|
960
|
-
onOpenChange,
|
|
961
|
-
...facetedProps,
|
|
962
|
-
children
|
|
963
|
-
})
|
|
964
|
-
});
|
|
965
|
-
}
|
|
966
|
-
function FacetedTrigger(props) {
|
|
967
|
-
const { className, children,...triggerProps } = props;
|
|
968
|
-
return /* @__PURE__ */ jsx(PopoverTrigger, {
|
|
969
|
-
...triggerProps,
|
|
970
|
-
className: cn("justify-between text-left", className),
|
|
971
|
-
children
|
|
972
|
-
});
|
|
973
|
-
}
|
|
974
|
-
function FacetedBadgeList(props) {
|
|
975
|
-
const { options = [], max = 2, placeholder = "Select options...", className, badgeClassName,...badgeListProps } = props;
|
|
976
|
-
const context = useFacetedContext("FacetedBadgeList");
|
|
977
|
-
const values = Array.isArray(context.value) ? context.value : [context.value].filter(Boolean);
|
|
978
|
-
const getLabel = React.useCallback((value) => {
|
|
979
|
-
return options.find((opt) => opt.value === value)?.label ?? value;
|
|
980
|
-
}, [options]);
|
|
981
|
-
if (!values || values.length === 0) return /* @__PURE__ */ jsxs("div", {
|
|
982
|
-
...badgeListProps,
|
|
983
|
-
className: "flex w-full items-center gap-1 text-muted-foreground",
|
|
984
|
-
children: [placeholder, /* @__PURE__ */ jsx(ChevronsUpDown, { className: "ml-auto size-4 shrink-0 opacity-50" })]
|
|
985
|
-
});
|
|
986
|
-
return /* @__PURE__ */ jsx("div", {
|
|
987
|
-
...badgeListProps,
|
|
988
|
-
className: cn("flex flex-wrap items-center gap-1", className),
|
|
989
|
-
children: values.length > max ? /* @__PURE__ */ jsxs(Badge, {
|
|
990
|
-
variant: "secondary",
|
|
991
|
-
className: cn("rounded-sm px-1 font-normal", badgeClassName),
|
|
992
|
-
children: [values.length, " selected"]
|
|
993
|
-
}) : values.map((value) => /* @__PURE__ */ jsx(Badge, {
|
|
994
|
-
variant: "secondary",
|
|
995
|
-
className: cn("rounded-sm px-1 font-normal", badgeClassName),
|
|
996
|
-
children: /* @__PURE__ */ jsx("span", {
|
|
997
|
-
className: "truncate",
|
|
998
|
-
children: getLabel(value)
|
|
999
|
-
})
|
|
1000
|
-
}, value))
|
|
1001
|
-
});
|
|
1002
|
-
}
|
|
1003
|
-
function FacetedContent(props) {
|
|
1004
|
-
const { className, children,...contentProps } = props;
|
|
1005
|
-
return /* @__PURE__ */ jsx(PopoverContent, {
|
|
1006
|
-
...contentProps,
|
|
1007
|
-
align: "start",
|
|
1008
|
-
className: cn("w-[200px] origin-(--radix-popover-content-transform-origin) p-0", className),
|
|
1009
|
-
children: /* @__PURE__ */ jsx(Command, { children })
|
|
1010
|
-
});
|
|
1011
|
-
}
|
|
1012
|
-
const FacetedInput = CommandInput;
|
|
1013
|
-
const FacetedList = CommandList;
|
|
1014
|
-
const FacetedEmpty = CommandEmpty;
|
|
1015
|
-
const FacetedGroup = CommandGroup;
|
|
1016
|
-
function FacetedItem(props) {
|
|
1017
|
-
const { value, onSelect, className, children,...itemProps } = props;
|
|
1018
|
-
const context = useFacetedContext("FacetedItem");
|
|
1019
|
-
const isSelected = context.multiple ? Array.isArray(context.value) && context.value.includes(value) : context.value === value;
|
|
1020
|
-
const onItemSelect = React.useCallback((currentValue) => {
|
|
1021
|
-
if (onSelect) onSelect(currentValue);
|
|
1022
|
-
else if (context.onItemSelect) context.onItemSelect(currentValue);
|
|
1023
|
-
}, [onSelect, context]);
|
|
1024
|
-
return /* @__PURE__ */ jsxs(CommandItem, {
|
|
1025
|
-
value,
|
|
1026
|
-
"aria-selected": isSelected,
|
|
1027
|
-
"data-selected": isSelected,
|
|
1028
|
-
className: cn("gap-2", className),
|
|
1029
|
-
onSelect: () => onItemSelect(value),
|
|
1030
|
-
...itemProps,
|
|
1031
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
1032
|
-
className: cn("flex size-4 items-center justify-center rounded-sm border border-primary", isSelected ? "bg-primary text-primary-foreground" : "opacity-50 [&_svg]:invisible"),
|
|
1033
|
-
children: /* @__PURE__ */ jsx(Check, { className: "size-4" })
|
|
1034
|
-
}), children]
|
|
1035
|
-
});
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
//#endregion
|
|
1039
|
-
//#region src/lib/compose-refs.ts
|
|
1040
|
-
/**
|
|
1041
|
-
* Set a given ref to a given value
|
|
1042
|
-
* This utility takes care of different types of refs: callback refs and RefObject(s)
|
|
1043
|
-
*/
|
|
1044
|
-
function setRef(ref, value) {
|
|
1045
|
-
if (typeof ref === "function") return ref(value);
|
|
1046
|
-
if (ref !== null && ref !== void 0) ref.current = value;
|
|
1047
|
-
}
|
|
1048
|
-
/**
|
|
1049
|
-
* A utility to compose multiple refs together
|
|
1050
|
-
* Accepts callback refs and RefObject(s)
|
|
1051
|
-
*/
|
|
1052
|
-
function composeRefs(...refs) {
|
|
1053
|
-
return (node) => {
|
|
1054
|
-
let hasCleanup = false;
|
|
1055
|
-
const cleanups = refs.map((ref) => {
|
|
1056
|
-
const cleanup = setRef(ref, node);
|
|
1057
|
-
if (!hasCleanup && typeof cleanup === "function") hasCleanup = true;
|
|
1058
|
-
return cleanup;
|
|
1059
|
-
});
|
|
1060
|
-
if (hasCleanup) return () => {
|
|
1061
|
-
for (let i = 0; i < cleanups.length; i++) {
|
|
1062
|
-
const cleanup = cleanups[i];
|
|
1063
|
-
if (typeof cleanup === "function") cleanup();
|
|
1064
|
-
else setRef(refs[i], null);
|
|
1065
|
-
}
|
|
1066
|
-
};
|
|
1067
|
-
};
|
|
1068
|
-
}
|
|
1069
|
-
/**
|
|
1070
|
-
* A custom hook that composes multiple refs
|
|
1071
|
-
* Accepts callback refs and RefObject(s)
|
|
1072
|
-
*/
|
|
1073
|
-
function useComposedRefs(...refs) {
|
|
1074
|
-
return React.useCallback(composeRefs(...refs), refs);
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
|
-
//#endregion
|
|
1078
|
-
//#region src/components/ui/sortable.tsx
|
|
1079
|
-
const orientationConfig = {
|
|
1080
|
-
vertical: {
|
|
1081
|
-
modifiers: [restrictToVerticalAxis, restrictToParentElement],
|
|
1082
|
-
strategy: verticalListSortingStrategy,
|
|
1083
|
-
collisionDetection: closestCenter
|
|
1084
|
-
},
|
|
1085
|
-
horizontal: {
|
|
1086
|
-
modifiers: [restrictToHorizontalAxis, restrictToParentElement],
|
|
1087
|
-
strategy: horizontalListSortingStrategy,
|
|
1088
|
-
collisionDetection: closestCenter
|
|
1089
|
-
},
|
|
1090
|
-
mixed: {
|
|
1091
|
-
modifiers: [restrictToParentElement],
|
|
1092
|
-
strategy: void 0,
|
|
1093
|
-
collisionDetection: closestCorners
|
|
1094
|
-
}
|
|
1095
|
-
};
|
|
1096
|
-
const ROOT_NAME$1 = "Sortable";
|
|
1097
|
-
const CONTENT_NAME = "SortableContent";
|
|
1098
|
-
const ITEM_NAME$1 = "SortableItem";
|
|
1099
|
-
const ITEM_HANDLE_NAME = "SortableItemHandle";
|
|
1100
|
-
const OVERLAY_NAME = "SortableOverlay";
|
|
1101
|
-
const SortableRootContext = React.createContext(null);
|
|
1102
|
-
function useSortableContext(consumerName) {
|
|
1103
|
-
const context = React.useContext(SortableRootContext);
|
|
1104
|
-
if (!context) throw new Error(`\`${consumerName}\` must be used within \`${ROOT_NAME$1}\``);
|
|
1105
|
-
return context;
|
|
1106
|
-
}
|
|
1107
|
-
function SortableRoot(props) {
|
|
1108
|
-
const { value, onValueChange, collisionDetection, modifiers, strategy, onMove, orientation = "vertical", flatCursor = false, getItemValue: getItemValueProp, accessibility, onDragStart: onDragStartProp, onDragEnd: onDragEndProp, onDragCancel: onDragCancelProp,...sortableProps } = props;
|
|
1109
|
-
const id = React.useId();
|
|
1110
|
-
const [activeId, setActiveId] = React.useState(null);
|
|
1111
|
-
const sensors = useSensors(useSensor(MouseSensor), useSensor(TouchSensor), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }));
|
|
1112
|
-
const config = React.useMemo(() => orientationConfig[orientation], [orientation]);
|
|
1113
|
-
const getItemValue = React.useCallback((item) => {
|
|
1114
|
-
if (typeof item === "object" && !getItemValueProp) throw new Error("getItemValue is required when using array of objects");
|
|
1115
|
-
return getItemValueProp ? getItemValueProp(item) : item;
|
|
1116
|
-
}, [getItemValueProp]);
|
|
1117
|
-
const items = React.useMemo(() => {
|
|
1118
|
-
return value.map((item) => getItemValue(item));
|
|
1119
|
-
}, [value, getItemValue]);
|
|
1120
|
-
const onDragStart = React.useCallback((event) => {
|
|
1121
|
-
onDragStartProp?.(event);
|
|
1122
|
-
if (event.activatorEvent.defaultPrevented) return;
|
|
1123
|
-
setActiveId(event.active.id);
|
|
1124
|
-
}, [onDragStartProp]);
|
|
1125
|
-
const onDragEnd = React.useCallback((event) => {
|
|
1126
|
-
onDragEndProp?.(event);
|
|
1127
|
-
if (event.activatorEvent.defaultPrevented) return;
|
|
1128
|
-
const { active, over } = event;
|
|
1129
|
-
if (over && active.id !== over?.id) {
|
|
1130
|
-
const activeIndex = value.findIndex((item) => getItemValue(item) === active.id);
|
|
1131
|
-
const overIndex = value.findIndex((item) => getItemValue(item) === over.id);
|
|
1132
|
-
if (onMove) onMove({
|
|
1133
|
-
...event,
|
|
1134
|
-
activeIndex,
|
|
1135
|
-
overIndex
|
|
1136
|
-
});
|
|
1137
|
-
else onValueChange?.(arrayMove(value, activeIndex, overIndex));
|
|
1138
|
-
}
|
|
1139
|
-
setActiveId(null);
|
|
1140
|
-
}, [
|
|
1141
|
-
value,
|
|
1142
|
-
onValueChange,
|
|
1143
|
-
onMove,
|
|
1144
|
-
getItemValue,
|
|
1145
|
-
onDragEndProp
|
|
1146
|
-
]);
|
|
1147
|
-
const onDragCancel = React.useCallback((event) => {
|
|
1148
|
-
onDragCancelProp?.(event);
|
|
1149
|
-
if (event.activatorEvent.defaultPrevented) return;
|
|
1150
|
-
setActiveId(null);
|
|
1151
|
-
}, [onDragCancelProp]);
|
|
1152
|
-
const announcements = React.useMemo(() => ({
|
|
1153
|
-
onDragStart({ active }) {
|
|
1154
|
-
return `Grabbed sortable item "${active.id.toString()}". Current position is ${active.data.current?.sortable.index + 1} of ${value.length}. Use arrow keys to move, space to drop.`;
|
|
1155
|
-
},
|
|
1156
|
-
onDragOver({ active, over }) {
|
|
1157
|
-
if (over) {
|
|
1158
|
-
const overIndex = over.data.current?.sortable.index ?? 0;
|
|
1159
|
-
const moveDirection = overIndex > (active.data.current?.sortable.index ?? 0) ? "down" : "up";
|
|
1160
|
-
return `Sortable item "${active.id.toString()}" moved ${moveDirection} to position ${overIndex + 1} of ${value.length}.`;
|
|
1161
|
-
}
|
|
1162
|
-
return "Sortable item is no longer over a droppable area. Press escape to cancel.";
|
|
1163
|
-
},
|
|
1164
|
-
onDragEnd({ active, over }) {
|
|
1165
|
-
const activeValue = active.id.toString();
|
|
1166
|
-
if (over) return `Sortable item "${activeValue}" dropped at position ${(over.data.current?.sortable.index ?? 0) + 1} of ${value.length}.`;
|
|
1167
|
-
return `Sortable item "${activeValue}" dropped. No changes were made.`;
|
|
1168
|
-
},
|
|
1169
|
-
onDragCancel({ active }) {
|
|
1170
|
-
const activeIndex = active.data.current?.sortable.index ?? 0;
|
|
1171
|
-
return `Sorting cancelled. Sortable item "${active.id.toString()}" returned to position ${activeIndex + 1} of ${value.length}.`;
|
|
1172
|
-
},
|
|
1173
|
-
onDragMove({ active, over }) {
|
|
1174
|
-
if (over) {
|
|
1175
|
-
const overIndex = over.data.current?.sortable.index ?? 0;
|
|
1176
|
-
const moveDirection = overIndex > (active.data.current?.sortable.index ?? 0) ? "down" : "up";
|
|
1177
|
-
return `Sortable item "${active.id.toString()}" is moving ${moveDirection} to position ${overIndex + 1} of ${value.length}.`;
|
|
1178
|
-
}
|
|
1179
|
-
return "Sortable item is no longer over a droppable area. Press escape to cancel.";
|
|
1180
|
-
}
|
|
1181
|
-
}), [value]);
|
|
1182
|
-
const screenReaderInstructions = React.useMemo(() => ({ draggable: `
|
|
1183
|
-
To pick up a sortable item, press space or enter.
|
|
1184
|
-
While dragging, use the ${orientation === "vertical" ? "up and down" : orientation === "horizontal" ? "left and right" : "arrow"} keys to move the item.
|
|
1185
|
-
Press space or enter again to drop the item in its new position, or press escape to cancel.
|
|
1186
|
-
` }), [orientation]);
|
|
1187
|
-
const contextValue = React.useMemo(() => ({
|
|
1188
|
-
id,
|
|
1189
|
-
items,
|
|
1190
|
-
modifiers: modifiers ?? config.modifiers,
|
|
1191
|
-
strategy: strategy ?? config.strategy,
|
|
1192
|
-
activeId,
|
|
1193
|
-
setActiveId,
|
|
1194
|
-
getItemValue,
|
|
1195
|
-
flatCursor
|
|
1196
|
-
}), [
|
|
1197
|
-
id,
|
|
1198
|
-
items,
|
|
1199
|
-
modifiers,
|
|
1200
|
-
strategy,
|
|
1201
|
-
config.modifiers,
|
|
1202
|
-
config.strategy,
|
|
1203
|
-
activeId,
|
|
1204
|
-
getItemValue,
|
|
1205
|
-
flatCursor
|
|
1206
|
-
]);
|
|
1207
|
-
return /* @__PURE__ */ jsx(SortableRootContext.Provider, {
|
|
1208
|
-
value: contextValue,
|
|
1209
|
-
children: /* @__PURE__ */ jsx(DndContext, {
|
|
1210
|
-
collisionDetection: collisionDetection ?? config.collisionDetection,
|
|
1211
|
-
modifiers: modifiers ?? config.modifiers,
|
|
1212
|
-
sensors,
|
|
1213
|
-
...sortableProps,
|
|
1214
|
-
id,
|
|
1215
|
-
onDragStart,
|
|
1216
|
-
onDragEnd,
|
|
1217
|
-
onDragCancel,
|
|
1218
|
-
accessibility: {
|
|
1219
|
-
announcements,
|
|
1220
|
-
screenReaderInstructions,
|
|
1221
|
-
...accessibility
|
|
1222
|
-
}
|
|
1223
|
-
})
|
|
1224
|
-
});
|
|
1225
|
-
}
|
|
1226
|
-
const SortableContentContext = React.createContext(false);
|
|
1227
|
-
function SortableContent(props) {
|
|
1228
|
-
const { strategy: strategyProp, asChild, withoutSlot, children, ref,...contentProps } = props;
|
|
1229
|
-
const context = useSortableContext(CONTENT_NAME);
|
|
1230
|
-
const ContentPrimitive = asChild ? Slot : "div";
|
|
1231
|
-
return /* @__PURE__ */ jsx(SortableContentContext.Provider, {
|
|
1232
|
-
value: true,
|
|
1233
|
-
children: /* @__PURE__ */ jsx(SortableContext, {
|
|
1234
|
-
items: context.items,
|
|
1235
|
-
strategy: strategyProp ?? context.strategy,
|
|
1236
|
-
children: withoutSlot ? children : /* @__PURE__ */ jsx(ContentPrimitive, {
|
|
1237
|
-
"data-slot": "sortable-content",
|
|
1238
|
-
...contentProps,
|
|
1239
|
-
ref,
|
|
1240
|
-
children
|
|
1241
|
-
})
|
|
1242
|
-
})
|
|
1243
|
-
});
|
|
1244
|
-
}
|
|
1245
|
-
const SortableItemContext = React.createContext(null);
|
|
1246
|
-
function useSortableItemContext(consumerName) {
|
|
1247
|
-
const context = React.useContext(SortableItemContext);
|
|
1248
|
-
if (!context) throw new Error(`\`${consumerName}\` must be used within \`${ITEM_NAME$1}\``);
|
|
1249
|
-
return context;
|
|
1250
|
-
}
|
|
1251
|
-
function SortableItem(props) {
|
|
1252
|
-
const { value, style, asHandle, asChild, disabled, className, ref,...itemProps } = props;
|
|
1253
|
-
const inSortableContent = React.useContext(SortableContentContext);
|
|
1254
|
-
const inSortableOverlay = React.useContext(SortableOverlayContext);
|
|
1255
|
-
if (!inSortableContent && !inSortableOverlay) throw new Error(`\`${ITEM_NAME$1}\` must be used within \`${CONTENT_NAME}\` or \`${OVERLAY_NAME}\``);
|
|
1256
|
-
if (value === "") throw new Error(`\`${ITEM_NAME$1}\` value cannot be an empty string`);
|
|
1257
|
-
const context = useSortableContext(ITEM_NAME$1);
|
|
1258
|
-
const id = React.useId();
|
|
1259
|
-
const { attributes, listeners: listeners$1, setNodeRef, setActivatorNodeRef, transform, transition, isDragging } = useSortable({
|
|
1260
|
-
id: value,
|
|
1261
|
-
disabled
|
|
1262
|
-
});
|
|
1263
|
-
const composedRef = useComposedRefs(ref, (node) => {
|
|
1264
|
-
if (disabled) return;
|
|
1265
|
-
setNodeRef(node);
|
|
1266
|
-
if (asHandle) setActivatorNodeRef(node);
|
|
1267
|
-
});
|
|
1268
|
-
const composedStyle = React.useMemo(() => {
|
|
1269
|
-
return {
|
|
1270
|
-
transform: CSS.Translate.toString(transform),
|
|
1271
|
-
transition,
|
|
1272
|
-
...style
|
|
1273
|
-
};
|
|
1274
|
-
}, [
|
|
1275
|
-
transform,
|
|
1276
|
-
transition,
|
|
1277
|
-
style
|
|
1278
|
-
]);
|
|
1279
|
-
const itemContext = React.useMemo(() => ({
|
|
1280
|
-
id,
|
|
1281
|
-
attributes,
|
|
1282
|
-
listeners: listeners$1,
|
|
1283
|
-
setActivatorNodeRef,
|
|
1284
|
-
isDragging,
|
|
1285
|
-
disabled
|
|
1286
|
-
}), [
|
|
1287
|
-
id,
|
|
1288
|
-
attributes,
|
|
1289
|
-
listeners$1,
|
|
1290
|
-
setActivatorNodeRef,
|
|
1291
|
-
isDragging,
|
|
1292
|
-
disabled
|
|
1293
|
-
]);
|
|
1294
|
-
const ItemPrimitive = asChild ? Slot : "div";
|
|
1295
|
-
return /* @__PURE__ */ jsx(SortableItemContext.Provider, {
|
|
1296
|
-
value: itemContext,
|
|
1297
|
-
children: /* @__PURE__ */ jsx(ItemPrimitive, {
|
|
1298
|
-
id,
|
|
1299
|
-
"data-disabled": disabled,
|
|
1300
|
-
"data-dragging": isDragging ? "" : void 0,
|
|
1301
|
-
"data-slot": "sortable-item",
|
|
1302
|
-
...itemProps,
|
|
1303
|
-
...asHandle && !disabled ? attributes : {},
|
|
1304
|
-
...asHandle && !disabled ? listeners$1 : {},
|
|
1305
|
-
ref: composedRef,
|
|
1306
|
-
style: composedStyle,
|
|
1307
|
-
className: cn("focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1", {
|
|
1308
|
-
"touch-none select-none": asHandle,
|
|
1309
|
-
"cursor-default": context.flatCursor,
|
|
1310
|
-
"data-dragging:cursor-grabbing": !context.flatCursor,
|
|
1311
|
-
"cursor-grab": !isDragging && asHandle && !context.flatCursor,
|
|
1312
|
-
"opacity-50": isDragging,
|
|
1313
|
-
"pointer-events-none opacity-50": disabled
|
|
1314
|
-
}, className)
|
|
1315
|
-
})
|
|
1316
|
-
});
|
|
1317
|
-
}
|
|
1318
|
-
function SortableItemHandle(props) {
|
|
1319
|
-
const { asChild, disabled, className, ref,...itemHandleProps } = props;
|
|
1320
|
-
const context = useSortableContext(ITEM_HANDLE_NAME);
|
|
1321
|
-
const itemContext = useSortableItemContext(ITEM_HANDLE_NAME);
|
|
1322
|
-
const isDisabled = disabled ?? itemContext.disabled;
|
|
1323
|
-
const composedRef = useComposedRefs(ref, (node) => {
|
|
1324
|
-
if (!isDisabled) return;
|
|
1325
|
-
itemContext.setActivatorNodeRef(node);
|
|
1326
|
-
});
|
|
1327
|
-
return /* @__PURE__ */ jsx(asChild ? Slot : "button", {
|
|
1328
|
-
type: "button",
|
|
1329
|
-
"aria-controls": itemContext.id,
|
|
1330
|
-
"data-disabled": isDisabled,
|
|
1331
|
-
"data-dragging": itemContext.isDragging ? "" : void 0,
|
|
1332
|
-
"data-slot": "sortable-item-handle",
|
|
1333
|
-
...itemHandleProps,
|
|
1334
|
-
...isDisabled ? {} : itemContext.attributes,
|
|
1335
|
-
...isDisabled ? {} : itemContext.listeners,
|
|
1336
|
-
ref: composedRef,
|
|
1337
|
-
className: cn("select-none disabled:pointer-events-none disabled:opacity-50", context.flatCursor ? "cursor-default" : "cursor-grab data-dragging:cursor-grabbing", className),
|
|
1338
|
-
disabled: isDisabled
|
|
1339
|
-
});
|
|
1340
|
-
}
|
|
1341
|
-
const SortableOverlayContext = React.createContext(false);
|
|
1342
|
-
const dropAnimation = { sideEffects: defaultDropAnimationSideEffects({ styles: { active: { opacity: "0.4" } } }) };
|
|
1343
|
-
function SortableOverlay(props) {
|
|
1344
|
-
const { container: containerProp, children,...overlayProps } = props;
|
|
1345
|
-
const context = useSortableContext(OVERLAY_NAME);
|
|
1346
|
-
const [mounted, setMounted] = React.useState(false);
|
|
1347
|
-
React.useLayoutEffect(() => setMounted(true), []);
|
|
1348
|
-
const container = containerProp ?? (mounted ? globalThis.document?.body : null);
|
|
1349
|
-
if (!container) return null;
|
|
1350
|
-
return ReactDOM.createPortal(/* @__PURE__ */ jsx(DragOverlay, {
|
|
1351
|
-
dropAnimation,
|
|
1352
|
-
modifiers: context.modifiers,
|
|
1353
|
-
className: cn(!context.flatCursor && "cursor-grabbing"),
|
|
1354
|
-
...overlayProps,
|
|
1355
|
-
children: /* @__PURE__ */ jsx(SortableOverlayContext.Provider, {
|
|
1356
|
-
value: true,
|
|
1357
|
-
children: context.activeId ? typeof children === "function" ? children({ value: context.activeId }) : children : null
|
|
1358
|
-
})
|
|
1359
|
-
}), container);
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
859
|
//#endregion
|
|
1363
860
|
//#region src/hooks/use-callback-ref.ts
|
|
1364
861
|
/**
|
|
@@ -1475,7 +972,7 @@ function DataTableFilterList({ table, debounceMs = DEBOUNCE_MS$2, throttleMs = T
|
|
|
1475
972
|
window.addEventListener("keydown", onKeyDown);
|
|
1476
973
|
return () => window.removeEventListener("keydown", onKeyDown);
|
|
1477
974
|
}, []);
|
|
1478
|
-
return /* @__PURE__ */ jsxs(
|
|
975
|
+
return /* @__PURE__ */ jsxs(Sortable, {
|
|
1479
976
|
value: filters,
|
|
1480
977
|
onValueChange: setFilters,
|
|
1481
978
|
getItemValue: (item) => item.filterId,
|
|
@@ -1612,7 +1109,7 @@ function DataTableFilterItem$1({ filter, index: index$1, filterItemId, joinOpera
|
|
|
1612
1109
|
children: index$1 === 0 ? /* @__PURE__ */ jsx("span", {
|
|
1613
1110
|
className: "text-muted-foreground text-sm",
|
|
1614
1111
|
children: "Where"
|
|
1615
|
-
}) : index$1 === 1 ? /* @__PURE__ */ jsxs(Select, {
|
|
1112
|
+
}) : index$1 === 1 ? /* @__PURE__ */ jsxs(Select$1, {
|
|
1616
1113
|
value: joinOperator,
|
|
1617
1114
|
onValueChange: (value) => setJoinOperator(value),
|
|
1618
1115
|
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
@@ -1672,7 +1169,7 @@ function DataTableFilterItem$1({ filter, index: index$1, filterItemId, joinOpera
|
|
|
1672
1169
|
}, column$1.id)) })] })] })
|
|
1673
1170
|
})]
|
|
1674
1171
|
}),
|
|
1675
|
-
/* @__PURE__ */ jsxs(Select, {
|
|
1172
|
+
/* @__PURE__ */ jsxs(Select$1, {
|
|
1676
1173
|
open: showOperatorSelector,
|
|
1677
1174
|
onOpenChange: setShowOperatorSelector,
|
|
1678
1175
|
value: filter.operator,
|
|
@@ -1764,7 +1261,7 @@ function onFilterInputRender$1({ filter, inputId, column, columnMeta, onFilterUp
|
|
|
1764
1261
|
case "boolean": {
|
|
1765
1262
|
if (Array.isArray(filter.value)) return null;
|
|
1766
1263
|
const inputListboxId = `${inputId}-listbox`;
|
|
1767
|
-
return /* @__PURE__ */ jsxs(Select, {
|
|
1264
|
+
return /* @__PURE__ */ jsxs(Select$1, {
|
|
1768
1265
|
open: showValueSelector,
|
|
1769
1266
|
onOpenChange: setShowValueSelector,
|
|
1770
1267
|
value: filter.value,
|
|
@@ -1791,6 +1288,7 @@ function onFilterInputRender$1({ filter, inputId, column, columnMeta, onFilterUp
|
|
|
1791
1288
|
case "select":
|
|
1792
1289
|
case "multiSelect": {
|
|
1793
1290
|
const inputListboxId = `${inputId}-listbox`;
|
|
1291
|
+
const optionList = columnMeta?.autoCrudFilterOptions ?? columnMeta?.options;
|
|
1794
1292
|
const multiple = filter.variant === "multiSelect";
|
|
1795
1293
|
return /* @__PURE__ */ jsxs(Faceted, {
|
|
1796
1294
|
open: showValueSelector,
|
|
@@ -1817,20 +1315,41 @@ function onFilterInputRender$1({ filter, inputId, column, columnMeta, onFilterUp
|
|
|
1817
1315
|
}), /* @__PURE__ */ jsxs(FacetedContent, {
|
|
1818
1316
|
id: inputListboxId,
|
|
1819
1317
|
className: "w-[200px]",
|
|
1318
|
+
commandProps: { shouldFilter: columnMeta?.autoCrudFilterShouldFilter },
|
|
1820
1319
|
children: [/* @__PURE__ */ jsx(FacetedInput, {
|
|
1821
1320
|
"aria-label": `Search ${columnMeta?.label} options`,
|
|
1822
|
-
placeholder: columnMeta?.placeholder ?? "Search options..."
|
|
1823
|
-
|
|
1824
|
-
|
|
1321
|
+
placeholder: columnMeta?.placeholder ?? "Search options...",
|
|
1322
|
+
value: columnMeta?.autoCrudFilterSearchValue,
|
|
1323
|
+
onValueChange: columnMeta?.autoCrudFilterOnSearch
|
|
1324
|
+
}), /* @__PURE__ */ jsxs(FacetedList, {
|
|
1325
|
+
onScroll: columnMeta?.autoCrudFilterOnPopupScroll,
|
|
1825
1326
|
children: [
|
|
1826
|
-
|
|
1827
|
-
/* @__PURE__ */ jsx(
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1327
|
+
/* @__PURE__ */ jsx(FacetedEmpty, { children: "No options found." }),
|
|
1328
|
+
/* @__PURE__ */ jsx(FacetedGroup, { children: optionList?.map((option) => /* @__PURE__ */ jsxs(FacetedItem, {
|
|
1329
|
+
value: option.value,
|
|
1330
|
+
children: [
|
|
1331
|
+
option.icon && /* @__PURE__ */ jsx(option.icon, {}),
|
|
1332
|
+
/* @__PURE__ */ jsx("span", { children: option.label }),
|
|
1333
|
+
option.count && /* @__PURE__ */ jsx("span", {
|
|
1334
|
+
className: "ml-auto font-mono text-xs",
|
|
1335
|
+
children: option.count
|
|
1336
|
+
})
|
|
1337
|
+
]
|
|
1338
|
+
}, option.value)) }),
|
|
1339
|
+
columnMeta?.autoCrudFilterLoading && /* @__PURE__ */ jsx(FacetedGroup, { children: /* @__PURE__ */ jsx("div", {
|
|
1340
|
+
role: "status",
|
|
1341
|
+
"aria-live": "polite",
|
|
1342
|
+
className: "py-2 text-center text-sm text-muted-foreground",
|
|
1343
|
+
children: "Loading..."
|
|
1344
|
+
}) }),
|
|
1345
|
+
!columnMeta?.autoCrudFilterLoading && columnMeta?.autoCrudFilterHasMore && /* @__PURE__ */ jsx("div", {
|
|
1346
|
+
role: "status",
|
|
1347
|
+
"aria-live": "polite",
|
|
1348
|
+
className: "sr-only",
|
|
1349
|
+
children: "Load more"
|
|
1831
1350
|
})
|
|
1832
1351
|
]
|
|
1833
|
-
}
|
|
1352
|
+
})]
|
|
1834
1353
|
})]
|
|
1835
1354
|
});
|
|
1836
1355
|
}
|
|
@@ -1909,6 +1428,9 @@ function getOptionCommandValue(option) {
|
|
|
1909
1428
|
option.searchText
|
|
1910
1429
|
].filter(Boolean).join(" ");
|
|
1911
1430
|
}
|
|
1431
|
+
function getColumnFilterOptions(column) {
|
|
1432
|
+
return column.columnDef.meta?.autoCrudFilterOptions ?? column.columnDef.meta?.options;
|
|
1433
|
+
}
|
|
1912
1434
|
function DataTableFilterMenu({ table, debounceMs = DEBOUNCE_MS$1, throttleMs = THROTTLE_MS$1, shallow = true, disabled,...props }) {
|
|
1913
1435
|
const id = React.useId();
|
|
1914
1436
|
const columnDefs = table.options.columns;
|
|
@@ -1994,6 +1516,12 @@ function DataTableFilterMenu({ table, debounceMs = DEBOUNCE_MS$1, throttleMs = T
|
|
|
1994
1516
|
onFilterRemove(filters[filters.length - 1]?.filterId ?? "");
|
|
1995
1517
|
}
|
|
1996
1518
|
}, [filters, onFilterRemove]);
|
|
1519
|
+
const selectedColumnMeta = selectedColumn?.columnDef.meta;
|
|
1520
|
+
const commandInputValue = selectedColumnMeta?.autoCrudFilterOnSearch !== void 0 ? selectedColumnMeta.autoCrudFilterSearchValue ?? "" : inputValue;
|
|
1521
|
+
const onCommandInputValueChange = React.useCallback((value) => {
|
|
1522
|
+
setInputValue(value);
|
|
1523
|
+
selectedColumn?.columnDef.meta?.autoCrudFilterOnSearch?.(value);
|
|
1524
|
+
}, [selectedColumn]);
|
|
1997
1525
|
return /* @__PURE__ */ jsxs("div", {
|
|
1998
1526
|
role: "list",
|
|
1999
1527
|
className: "flex flex-wrap items-center gap-2",
|
|
@@ -2033,31 +1561,50 @@ function DataTableFilterMenu({ table, debounceMs = DEBOUNCE_MS$1, throttleMs = T
|
|
|
2033
1561
|
...props,
|
|
2034
1562
|
children: /* @__PURE__ */ jsxs(Command, {
|
|
2035
1563
|
loop: true,
|
|
1564
|
+
shouldFilter: selectedColumnMeta?.autoCrudFilterShouldFilter,
|
|
2036
1565
|
className: "[&_[cmdk-input-wrapper]_svg]:hidden",
|
|
2037
1566
|
children: [/* @__PURE__ */ jsx(CommandInput, {
|
|
2038
1567
|
ref: inputRef,
|
|
2039
1568
|
placeholder: selectedColumn ? selectedColumn.columnDef.meta?.label ?? selectedColumn.id : "Search fields...",
|
|
2040
|
-
value:
|
|
2041
|
-
onValueChange:
|
|
1569
|
+
value: commandInputValue,
|
|
1570
|
+
onValueChange: onCommandInputValueChange,
|
|
2042
1571
|
onKeyDown: onInputKeyDown
|
|
2043
|
-
}), /* @__PURE__ */ jsx(CommandList, {
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
1572
|
+
}), /* @__PURE__ */ jsx(CommandList, {
|
|
1573
|
+
onScroll: selectedColumnMeta?.autoCrudFilterOnPopupScroll,
|
|
1574
|
+
children: selectedColumn ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1575
|
+
selectedColumn.columnDef.meta?.options && /* @__PURE__ */ jsx(CommandEmpty, { children: "No options found." }),
|
|
1576
|
+
/* @__PURE__ */ jsx(FilterValueSelector, {
|
|
1577
|
+
column: selectedColumn,
|
|
1578
|
+
value: inputValue,
|
|
1579
|
+
onSelect: (value) => onFilterAdd(selectedColumn, value)
|
|
1580
|
+
}),
|
|
1581
|
+
selectedColumnMeta?.autoCrudFilterLoading && /* @__PURE__ */ jsx(CommandGroup, { children: /* @__PURE__ */ jsx("div", {
|
|
1582
|
+
role: "status",
|
|
1583
|
+
"aria-live": "polite",
|
|
1584
|
+
className: "py-2 text-center text-sm text-muted-foreground",
|
|
1585
|
+
children: "Loading..."
|
|
1586
|
+
}) }),
|
|
1587
|
+
!selectedColumnMeta?.autoCrudFilterLoading && selectedColumnMeta?.autoCrudFilterHasMore && /* @__PURE__ */ jsx("div", {
|
|
1588
|
+
role: "status",
|
|
1589
|
+
"aria-live": "polite",
|
|
1590
|
+
className: "sr-only",
|
|
1591
|
+
children: "Load more"
|
|
1592
|
+
})
|
|
1593
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(CommandEmpty, { children: "No fields found." }), /* @__PURE__ */ jsx(CommandGroup, { children: columns.map((column) => /* @__PURE__ */ jsxs(CommandItem, {
|
|
1594
|
+
value: column.id,
|
|
1595
|
+
onSelect: () => {
|
|
1596
|
+
setSelectedColumn(column);
|
|
1597
|
+
setInputValue("");
|
|
1598
|
+
requestAnimationFrame(() => {
|
|
1599
|
+
inputRef.current?.focus();
|
|
1600
|
+
});
|
|
1601
|
+
},
|
|
1602
|
+
children: [column.columnDef.meta?.icon && /* @__PURE__ */ jsx(column.columnDef.meta.icon, {}), /* @__PURE__ */ jsx("span", {
|
|
1603
|
+
className: "truncate",
|
|
1604
|
+
children: column.columnDef.meta?.label ?? column.id
|
|
1605
|
+
})]
|
|
1606
|
+
}, column.id)) })] })
|
|
1607
|
+
})]
|
|
2061
1608
|
})
|
|
2062
1609
|
})]
|
|
2063
1610
|
})
|
|
@@ -2134,7 +1681,7 @@ function DataTableFilterItem({ filter, filterItemId, columns, onFilterUpdate, on
|
|
|
2134
1681
|
})
|
|
2135
1682
|
})]
|
|
2136
1683
|
}),
|
|
2137
|
-
/* @__PURE__ */ jsxs(Select, {
|
|
1684
|
+
/* @__PURE__ */ jsxs(Select$1, {
|
|
2138
1685
|
open: showOperatorSelector,
|
|
2139
1686
|
onOpenChange: setShowOperatorSelector,
|
|
2140
1687
|
value: filter.operator,
|
|
@@ -2187,7 +1734,7 @@ function FilterValueSelector({ column, value, onSelect }) {
|
|
|
2187
1734
|
children: "False"
|
|
2188
1735
|
})] });
|
|
2189
1736
|
case "select":
|
|
2190
|
-
case "multiSelect": return /* @__PURE__ */ jsx(CommandGroup, { children: column
|
|
1737
|
+
case "multiSelect": return /* @__PURE__ */ jsx(CommandGroup, { children: getColumnFilterOptions(column)?.map((option) => /* @__PURE__ */ jsxs(CommandItem, {
|
|
2191
1738
|
value: getOptionCommandValue(option),
|
|
2192
1739
|
onSelect: () => onSelect(option.value),
|
|
2193
1740
|
children: [
|
|
@@ -2260,7 +1807,7 @@ function onFilterInputRender({ filter, column, inputId, onFilterUpdate, showValu
|
|
|
2260
1807
|
}
|
|
2261
1808
|
case "boolean": {
|
|
2262
1809
|
const inputListboxId = `${inputId}-listbox`;
|
|
2263
|
-
return /* @__PURE__ */ jsxs(Select, {
|
|
1810
|
+
return /* @__PURE__ */ jsxs(Select$1, {
|
|
2264
1811
|
open: showValueSelector,
|
|
2265
1812
|
onOpenChange: setShowValueSelector,
|
|
2266
1813
|
value: typeof filter.value === "string" ? filter.value : "true",
|
|
@@ -2286,6 +1833,7 @@ function onFilterInputRender({ filter, column, inputId, onFilterUpdate, showValu
|
|
|
2286
1833
|
case "multiSelect": {
|
|
2287
1834
|
const inputListboxId = `${inputId}-listbox`;
|
|
2288
1835
|
const options = column.columnDef.meta?.options ?? [];
|
|
1836
|
+
const optionList = getColumnFilterOptions(column) ?? [];
|
|
2289
1837
|
const selectedValues = Array.isArray(filter.value) ? filter.value : [filter.value];
|
|
2290
1838
|
const selectedOptions = options.filter((option) => selectedValues.includes(option.value));
|
|
2291
1839
|
return /* @__PURE__ */ jsxs(Popover, {
|
|
@@ -2314,21 +1862,46 @@ function onFilterInputRender({ filter, column, inputId, onFilterUpdate, showValu
|
|
|
2314
1862
|
id: inputListboxId,
|
|
2315
1863
|
align: "start",
|
|
2316
1864
|
className: "w-48 p-0",
|
|
2317
|
-
children: /* @__PURE__ */ jsxs(Command, {
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
children: option
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
1865
|
+
children: /* @__PURE__ */ jsxs(Command, {
|
|
1866
|
+
shouldFilter: column.columnDef.meta?.autoCrudFilterShouldFilter,
|
|
1867
|
+
children: [/* @__PURE__ */ jsx(CommandInput, {
|
|
1868
|
+
placeholder: "Search options...",
|
|
1869
|
+
value: column.columnDef.meta?.autoCrudFilterSearchValue,
|
|
1870
|
+
onValueChange: column.columnDef.meta?.autoCrudFilterOnSearch
|
|
1871
|
+
}), /* @__PURE__ */ jsxs(CommandList, {
|
|
1872
|
+
onScroll: column.columnDef.meta?.autoCrudFilterOnPopupScroll,
|
|
1873
|
+
children: [
|
|
1874
|
+
/* @__PURE__ */ jsx(CommandEmpty, { children: "No options found." }),
|
|
1875
|
+
/* @__PURE__ */ jsx(CommandGroup, { children: optionList.map((option) => /* @__PURE__ */ jsxs(CommandItem, {
|
|
1876
|
+
value: getOptionCommandValue(option),
|
|
1877
|
+
onSelect: () => {
|
|
1878
|
+
const value = filter.variant === "multiSelect" ? selectedValues.includes(option.value) ? selectedValues.filter((v) => v !== option.value) : [...selectedValues, option.value] : option.value;
|
|
1879
|
+
onFilterUpdate(filter.filterId, { value });
|
|
1880
|
+
},
|
|
1881
|
+
children: [
|
|
1882
|
+
option.icon && /* @__PURE__ */ jsx(option.icon, {}),
|
|
1883
|
+
/* @__PURE__ */ jsx("span", {
|
|
1884
|
+
className: "truncate",
|
|
1885
|
+
children: option.label
|
|
1886
|
+
}),
|
|
1887
|
+
filter.variant === "multiSelect" && /* @__PURE__ */ jsx(Check, { className: cn("ml-auto", selectedValues.includes(option.value) ? "opacity-100" : "opacity-0") })
|
|
1888
|
+
]
|
|
1889
|
+
}, option.value)) }),
|
|
1890
|
+
column.columnDef.meta?.autoCrudFilterLoading && /* @__PURE__ */ jsx(CommandGroup, { children: /* @__PURE__ */ jsx("div", {
|
|
1891
|
+
role: "status",
|
|
1892
|
+
"aria-live": "polite",
|
|
1893
|
+
className: "py-2 text-center text-sm text-muted-foreground",
|
|
1894
|
+
children: "Loading..."
|
|
1895
|
+
}) }),
|
|
1896
|
+
!column.columnDef.meta?.autoCrudFilterLoading && column.columnDef.meta?.autoCrudFilterHasMore && /* @__PURE__ */ jsx("div", {
|
|
1897
|
+
role: "status",
|
|
1898
|
+
"aria-live": "polite",
|
|
1899
|
+
className: "sr-only",
|
|
1900
|
+
children: "Load more"
|
|
1901
|
+
})
|
|
1902
|
+
]
|
|
1903
|
+
})]
|
|
1904
|
+
})
|
|
2332
1905
|
})]
|
|
2333
1906
|
});
|
|
2334
1907
|
}
|
|
@@ -2452,7 +2025,7 @@ function DataTableSortList({ table, disabled,...props }) {
|
|
|
2452
2025
|
window.addEventListener("keydown", onKeyDown);
|
|
2453
2026
|
return () => window.removeEventListener("keydown", onKeyDown);
|
|
2454
2027
|
}, []);
|
|
2455
|
-
return /* @__PURE__ */ jsxs(
|
|
2028
|
+
return /* @__PURE__ */ jsxs(Sortable, {
|
|
2456
2029
|
value: sorting,
|
|
2457
2030
|
onValueChange: onSortingChange,
|
|
2458
2031
|
getItemValue: (item) => item.id,
|
|
@@ -2603,7 +2176,7 @@ function DataTableSortItem({ sort, sortItemId, columns, columnLabels, onSortUpda
|
|
|
2603
2176
|
}, column.id)) })] })] })
|
|
2604
2177
|
})]
|
|
2605
2178
|
}),
|
|
2606
|
-
/* @__PURE__ */ jsxs(Select, {
|
|
2179
|
+
/* @__PURE__ */ jsxs(Select$1, {
|
|
2607
2180
|
open: showDirectionSelector,
|
|
2608
2181
|
onOpenChange: setShowDirectionSelector,
|
|
2609
2182
|
value: sort.desc ? "desc" : "asc",
|
|
@@ -2672,207 +2245,12 @@ function DataTableViewOptions({ table, disabled,...props }) {
|
|
|
2672
2245
|
})] });
|
|
2673
2246
|
}
|
|
2674
2247
|
|
|
2675
|
-
//#endregion
|
|
2676
|
-
//#region src/components/ui/multi-combobox.tsx
|
|
2677
|
-
const DEFAULT_OPTIONS = [];
|
|
2678
|
-
const SCROLLABLE_COMMAND_GROUP_STYLE = {
|
|
2679
|
-
maxHeight: "300px",
|
|
2680
|
-
overscrollBehavior: "contain",
|
|
2681
|
-
overflowX: "hidden",
|
|
2682
|
-
overflowY: "auto"
|
|
2683
|
-
};
|
|
2684
|
-
function getWheelDeltaY(event) {
|
|
2685
|
-
if (event.deltaMode === 1) return event.deltaY * 16;
|
|
2686
|
-
if (event.deltaMode === 2) return event.deltaY * event.currentTarget.clientHeight;
|
|
2687
|
-
return event.deltaY;
|
|
2688
|
-
}
|
|
2689
|
-
function handleScrollableCommandGroupWheel(event) {
|
|
2690
|
-
const target = event.currentTarget;
|
|
2691
|
-
if (target.scrollHeight <= target.clientHeight) return;
|
|
2692
|
-
const maxScrollTop = target.scrollHeight - target.clientHeight;
|
|
2693
|
-
const nextScrollTop = Math.max(0, Math.min(target.scrollTop + getWheelDeltaY(event), maxScrollTop));
|
|
2694
|
-
if (nextScrollTop === target.scrollTop) return;
|
|
2695
|
-
event.preventDefault();
|
|
2696
|
-
event.stopPropagation();
|
|
2697
|
-
target.scrollTop = nextScrollTop;
|
|
2698
|
-
}
|
|
2699
|
-
function collectSearchText(...parts) {
|
|
2700
|
-
const texts = [];
|
|
2701
|
-
for (const part of parts) {
|
|
2702
|
-
if (!part) continue;
|
|
2703
|
-
if (Array.isArray(part)) texts.push(...part.map(String));
|
|
2704
|
-
else if (typeof part === "object") texts.push(...Object.values(part).filter(Boolean).map(String));
|
|
2705
|
-
else texts.push(String(part));
|
|
2706
|
-
}
|
|
2707
|
-
return texts.join(" ");
|
|
2708
|
-
}
|
|
2709
|
-
function getOptionKeywords(option) {
|
|
2710
|
-
return collectSearchText(typeof option.label === "string" || typeof option.label === "number" ? option.label : void 0, option.searchText, option.keywords).split(/\s+/).filter(Boolean);
|
|
2711
|
-
}
|
|
2712
|
-
function getOptionText(option) {
|
|
2713
|
-
if (typeof option.label === "string" || typeof option.label === "number") return String(option.label);
|
|
2714
|
-
return option.value;
|
|
2715
|
-
}
|
|
2716
|
-
function createNextValue(currentValue, optionValue, isSelected, selectionMode) {
|
|
2717
|
-
if (selectionMode === "single") return isSelected ? [] : [optionValue];
|
|
2718
|
-
return isSelected ? currentValue.filter((value) => value !== optionValue) : [...currentValue, optionValue];
|
|
2719
|
-
}
|
|
2720
|
-
function DefaultMultiComboboxTrigger({ open, selectedOptions, selectedValues, clearSelection, disabled, readOnly, placeholder, selectedText, className,...buttonProps }) {
|
|
2721
|
-
return /* @__PURE__ */ jsxs(Button, {
|
|
2722
|
-
...buttonProps,
|
|
2723
|
-
type: "button",
|
|
2724
|
-
variant: "outline",
|
|
2725
|
-
role: "combobox",
|
|
2726
|
-
"aria-expanded": open,
|
|
2727
|
-
disabled,
|
|
2728
|
-
className: cn$1("w-full justify-between", className),
|
|
2729
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
2730
|
-
className: "flex min-w-0 flex-1 items-center gap-1 overflow-hidden",
|
|
2731
|
-
children: selectedValues.length === 0 ? /* @__PURE__ */ jsx("span", {
|
|
2732
|
-
className: "truncate text-muted-foreground",
|
|
2733
|
-
children: placeholder
|
|
2734
|
-
}) : selectedOptions.length <= 2 ? selectedOptions.map((option) => /* @__PURE__ */ jsx(Badge, {
|
|
2735
|
-
variant: "secondary",
|
|
2736
|
-
className: "max-w-[8rem] rounded-sm px-1 font-normal",
|
|
2737
|
-
children: /* @__PURE__ */ jsx("span", {
|
|
2738
|
-
className: "truncate",
|
|
2739
|
-
children: option.label
|
|
2740
|
-
})
|
|
2741
|
-
}, option.value)) : /* @__PURE__ */ jsxs(Badge, {
|
|
2742
|
-
variant: "secondary",
|
|
2743
|
-
className: "rounded-sm px-1 font-normal",
|
|
2744
|
-
children: [
|
|
2745
|
-
selectedValues.length,
|
|
2746
|
-
" ",
|
|
2747
|
-
selectedText
|
|
2748
|
-
]
|
|
2749
|
-
})
|
|
2750
|
-
}), /* @__PURE__ */ jsxs("span", {
|
|
2751
|
-
className: "ml-2 flex shrink-0 items-center gap-1",
|
|
2752
|
-
children: [selectedValues.length > 0 && !readOnly && /* @__PURE__ */ jsx("span", {
|
|
2753
|
-
role: "button",
|
|
2754
|
-
"aria-label": "Clear selection",
|
|
2755
|
-
tabIndex: 0,
|
|
2756
|
-
className: "rounded-sm px-1 text-muted-foreground opacity-70 transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
2757
|
-
onClick: clearSelection,
|
|
2758
|
-
onKeyDown: (event) => {
|
|
2759
|
-
if (event.key === "Enter" || event.key === " ") {
|
|
2760
|
-
event.preventDefault();
|
|
2761
|
-
clearSelection(event);
|
|
2762
|
-
}
|
|
2763
|
-
},
|
|
2764
|
-
children: /* @__PURE__ */ jsx(X, { className: "size-3" })
|
|
2765
|
-
}), /* @__PURE__ */ jsx(ChevronsUpDown, { className: "h-4 w-4 opacity-50" })]
|
|
2766
|
-
})]
|
|
2767
|
-
});
|
|
2768
|
-
}
|
|
2769
|
-
const MultiCombobox = ({ value, defaultValue, onChange, options = DEFAULT_OPTIONS, placeholder = "Select options...", searchPlaceholder = "Search...", emptyText = "No options found.", clearText = "Clear selection", selectedText = "selected", selectionMode = "multiple", disabled, readOnly, className, contentClassName, triggerClassName, matchTriggerWidth = true, renderTrigger, filter,...commandProps }) => {
|
|
2770
|
-
const [open, setOpen] = React.useState(false);
|
|
2771
|
-
const [internalValue, setInternalValue] = React.useState(defaultValue ?? []);
|
|
2772
|
-
const selectedValues = value ?? internalValue;
|
|
2773
|
-
const selectedValueSet = React.useMemo(() => new Set(selectedValues), [selectedValues]);
|
|
2774
|
-
const selectedOptions = React.useMemo(() => options.filter((option) => selectedValueSet.has(option.value)), [options, selectedValueSet]);
|
|
2775
|
-
const commitChange = React.useCallback((nextValue) => {
|
|
2776
|
-
if (value === void 0) setInternalValue(nextValue);
|
|
2777
|
-
onChange?.(nextValue);
|
|
2778
|
-
}, [onChange, value]);
|
|
2779
|
-
const clearSelection = React.useCallback((event) => {
|
|
2780
|
-
event?.preventDefault();
|
|
2781
|
-
event?.stopPropagation();
|
|
2782
|
-
if (readOnly) return;
|
|
2783
|
-
commitChange([]);
|
|
2784
|
-
}, [commitChange, readOnly]);
|
|
2785
|
-
const onItemSelect = React.useCallback((option) => {
|
|
2786
|
-
if (option.disabled || readOnly) return;
|
|
2787
|
-
const isSelected = selectedValueSet.has(option.value);
|
|
2788
|
-
commitChange(createNextValue(selectedValues, option.value, isSelected, selectionMode));
|
|
2789
|
-
if (selectionMode === "single") setOpen(false);
|
|
2790
|
-
}, [
|
|
2791
|
-
commitChange,
|
|
2792
|
-
readOnly,
|
|
2793
|
-
selectedValues,
|
|
2794
|
-
selectedValueSet,
|
|
2795
|
-
selectionMode
|
|
2796
|
-
]);
|
|
2797
|
-
return /* @__PURE__ */ jsxs(Popover, {
|
|
2798
|
-
open,
|
|
2799
|
-
onOpenChange: setOpen,
|
|
2800
|
-
children: [/* @__PURE__ */ jsx(PopoverTrigger, {
|
|
2801
|
-
asChild: true,
|
|
2802
|
-
children: renderTrigger ? renderTrigger({
|
|
2803
|
-
open,
|
|
2804
|
-
selectedOptions,
|
|
2805
|
-
selectedValues,
|
|
2806
|
-
clearSelection,
|
|
2807
|
-
disabled,
|
|
2808
|
-
readOnly
|
|
2809
|
-
}) : /* @__PURE__ */ jsx(DefaultMultiComboboxTrigger, {
|
|
2810
|
-
open,
|
|
2811
|
-
selectedOptions,
|
|
2812
|
-
selectedValues,
|
|
2813
|
-
clearSelection,
|
|
2814
|
-
disabled,
|
|
2815
|
-
readOnly,
|
|
2816
|
-
placeholder,
|
|
2817
|
-
selectedText,
|
|
2818
|
-
className: triggerClassName
|
|
2819
|
-
})
|
|
2820
|
-
}), /* @__PURE__ */ jsx(PopoverContent, {
|
|
2821
|
-
className: cn$1("w-full p-0", contentClassName),
|
|
2822
|
-
style: matchTriggerWidth ? { width: "var(--radix-popover-trigger-width)" } : void 0,
|
|
2823
|
-
children: /* @__PURE__ */ jsxs(Command, {
|
|
2824
|
-
className,
|
|
2825
|
-
filter,
|
|
2826
|
-
...commandProps,
|
|
2827
|
-
children: [/* @__PURE__ */ jsx(CommandInput, { placeholder: searchPlaceholder }), /* @__PURE__ */ jsxs(CommandList, {
|
|
2828
|
-
className: "max-h-full",
|
|
2829
|
-
children: [
|
|
2830
|
-
/* @__PURE__ */ jsx(CommandEmpty, { children: emptyText }),
|
|
2831
|
-
/* @__PURE__ */ jsx(CommandGroup, {
|
|
2832
|
-
className: "max-h-[300px] scroll-py-1 overflow-y-auto overflow-x-hidden",
|
|
2833
|
-
onWheelCapture: handleScrollableCommandGroupWheel,
|
|
2834
|
-
style: SCROLLABLE_COMMAND_GROUP_STYLE,
|
|
2835
|
-
children: options.map((option) => {
|
|
2836
|
-
const isSelected = selectedValueSet.has(option.value);
|
|
2837
|
-
const Icon = option.icon;
|
|
2838
|
-
return /* @__PURE__ */ jsxs(CommandItem, {
|
|
2839
|
-
value: option.value,
|
|
2840
|
-
keywords: getOptionKeywords(option),
|
|
2841
|
-
disabled: option.disabled,
|
|
2842
|
-
onSelect: () => onItemSelect(option),
|
|
2843
|
-
children: [
|
|
2844
|
-
/* @__PURE__ */ jsx("div", {
|
|
2845
|
-
className: cn$1("flex size-4 items-center justify-center rounded-sm border border-primary", isSelected ? "bg-primary text-primary-foreground" : "opacity-50 [&_svg]:invisible"),
|
|
2846
|
-
children: /* @__PURE__ */ jsx(Check, {})
|
|
2847
|
-
}),
|
|
2848
|
-
Icon && /* @__PURE__ */ jsx(Icon, { className: "size-4" }),
|
|
2849
|
-
/* @__PURE__ */ jsx("span", {
|
|
2850
|
-
className: "truncate",
|
|
2851
|
-
children: getOptionText(option)
|
|
2852
|
-
}),
|
|
2853
|
-
option.count !== void 0 && /* @__PURE__ */ jsx("span", {
|
|
2854
|
-
className: "ml-auto font-mono text-xs",
|
|
2855
|
-
children: option.count
|
|
2856
|
-
})
|
|
2857
|
-
]
|
|
2858
|
-
}, option.value);
|
|
2859
|
-
})
|
|
2860
|
-
}),
|
|
2861
|
-
selectedValues.length > 0 && !readOnly && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(CommandSeparator, {}), /* @__PURE__ */ jsx(CommandGroup, { children: /* @__PURE__ */ jsx(CommandItem, {
|
|
2862
|
-
onSelect: () => commitChange([]),
|
|
2863
|
-
className: "justify-center text-center",
|
|
2864
|
-
children: clearText
|
|
2865
|
-
}) })] })
|
|
2866
|
-
]
|
|
2867
|
-
})]
|
|
2868
|
-
})
|
|
2869
|
-
})]
|
|
2870
|
-
});
|
|
2871
|
-
};
|
|
2872
|
-
MultiCombobox.displayName = "MultiCombobox";
|
|
2873
|
-
|
|
2874
2248
|
//#endregion
|
|
2875
2249
|
//#region src/components/auto-crud/auto-table-simple-filters.tsx
|
|
2250
|
+
function mergeSelectedFilterOptions(currentOptions, labelOptions, selectedValues) {
|
|
2251
|
+
const currentValues = new Set(currentOptions.map((option) => option.value));
|
|
2252
|
+
return [...labelOptions.filter((option) => selectedValues.includes(option.value) && !currentValues.has(option.value)), ...currentOptions];
|
|
2253
|
+
}
|
|
2876
2254
|
function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilters, onFiltersChange, leading }) {
|
|
2877
2255
|
const columnDefs = table.options.columns;
|
|
2878
2256
|
const columns = React.useMemo(() => table.getAllColumns().filter((col) => col.getCanFilter()).sort((a, b) => {
|
|
@@ -3061,17 +2439,27 @@ function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilte
|
|
|
3061
2439
|
})
|
|
3062
2440
|
}, column.id);
|
|
3063
2441
|
case "select":
|
|
3064
|
-
case "multiSelect":
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
2442
|
+
case "multiSelect": {
|
|
2443
|
+
const selectedValues = Array.isArray(value) ? value : value ? [value] : [];
|
|
2444
|
+
const filterOptions = mergeSelectedFilterOptions(meta.autoCrudFilterOptions ?? meta.options ?? [], meta.options ?? [], selectedValues);
|
|
2445
|
+
return /* @__PURE__ */ jsx("div", {
|
|
2446
|
+
className: isHidden ? "hidden" : "",
|
|
2447
|
+
"data-filter-item": true,
|
|
2448
|
+
children: /* @__PURE__ */ jsx(SimpleFacetedFilter, {
|
|
2449
|
+
title: meta.label ?? column.id,
|
|
2450
|
+
options: filterOptions,
|
|
2451
|
+
multiple: meta.variant === "multiSelect",
|
|
2452
|
+
value: selectedValues,
|
|
2453
|
+
hasMore: meta.autoCrudFilterHasMore,
|
|
2454
|
+
loading: meta.autoCrudFilterLoading,
|
|
2455
|
+
searchValue: meta.autoCrudFilterSearchValue,
|
|
2456
|
+
shouldFilter: meta.autoCrudFilterShouldFilter,
|
|
2457
|
+
onChange: (v) => updateFilter(column.id, v.length ? v : void 0),
|
|
2458
|
+
onPopupScroll: meta.autoCrudFilterOnPopupScroll,
|
|
2459
|
+
onSearch: meta.autoCrudFilterOnSearch
|
|
2460
|
+
})
|
|
2461
|
+
}, column.id);
|
|
2462
|
+
}
|
|
3075
2463
|
case "range": return /* @__PURE__ */ jsx("div", {
|
|
3076
2464
|
className: isHidden ? "hidden" : "",
|
|
3077
2465
|
"data-filter-item": true,
|
|
@@ -3118,13 +2506,23 @@ function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilte
|
|
|
3118
2506
|
]
|
|
3119
2507
|
});
|
|
3120
2508
|
}
|
|
3121
|
-
function SimpleFacetedFilter({ title, options, multiple, value, onChange }) {
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
2509
|
+
function SimpleFacetedFilter({ title, options, multiple, value, hasMore, loading, searchValue, shouldFilter, onChange, onPopupScroll, onSearch }) {
|
|
2510
|
+
const onSelectChange = (nextValue) => {
|
|
2511
|
+
onChange(Array.isArray(nextValue) ? nextValue : nextValue ? [nextValue] : []);
|
|
2512
|
+
};
|
|
2513
|
+
return /* @__PURE__ */ jsx(Select$2, {
|
|
2514
|
+
mode: "searchable",
|
|
2515
|
+
multiple: Boolean(multiple),
|
|
2516
|
+
value: multiple ? value : value[0] ?? "",
|
|
2517
|
+
onChange: onSelectChange,
|
|
3125
2518
|
options,
|
|
3126
|
-
selectionMode: multiple ? "multiple" : "single",
|
|
3127
2519
|
searchPlaceholder: title,
|
|
2520
|
+
hasMore,
|
|
2521
|
+
loading,
|
|
2522
|
+
searchValue,
|
|
2523
|
+
shouldFilter,
|
|
2524
|
+
onPopupScroll,
|
|
2525
|
+
onSearch,
|
|
3128
2526
|
contentClassName: "w-50",
|
|
3129
2527
|
matchTriggerWidth: false,
|
|
3130
2528
|
clearText: "Clear filters",
|
|
@@ -3422,386 +2820,6 @@ function SimpleDateFilter({ title, multiple, value, onChange }) {
|
|
|
3422
2820
|
})] });
|
|
3423
2821
|
}
|
|
3424
2822
|
|
|
3425
|
-
//#endregion
|
|
3426
|
-
//#region src/hooks/use-isomorphic-layout-effect.ts
|
|
3427
|
-
const useIsomorphicLayoutEffect = typeof window !== "undefined" ? React.useLayoutEffect : React.useEffect;
|
|
3428
|
-
|
|
3429
|
-
//#endregion
|
|
3430
|
-
//#region src/hooks/use-as-ref.ts
|
|
3431
|
-
function useAsRef(props) {
|
|
3432
|
-
const ref = React.useRef(props);
|
|
3433
|
-
useIsomorphicLayoutEffect(() => {
|
|
3434
|
-
ref.current = props;
|
|
3435
|
-
});
|
|
3436
|
-
return ref;
|
|
3437
|
-
}
|
|
3438
|
-
|
|
3439
|
-
//#endregion
|
|
3440
|
-
//#region src/components/ui/action-bar.tsx
|
|
3441
|
-
const ROOT_NAME = "ActionBar";
|
|
3442
|
-
const GROUP_NAME = "ActionBarGroup";
|
|
3443
|
-
const ITEM_NAME = "ActionBarItem";
|
|
3444
|
-
const CLOSE_NAME = "ActionBarClose";
|
|
3445
|
-
const SEPARATOR_NAME = "ActionBarSeparator";
|
|
3446
|
-
const ITEM_SELECT = "actionbar.itemSelect";
|
|
3447
|
-
const ENTRY_FOCUS = "actionbarFocusGroup.onEntryFocus";
|
|
3448
|
-
const EVENT_OPTIONS = {
|
|
3449
|
-
bubbles: false,
|
|
3450
|
-
cancelable: true
|
|
3451
|
-
};
|
|
3452
|
-
function focusFirst(candidates, preventScroll = false) {
|
|
3453
|
-
const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;
|
|
3454
|
-
for (const candidateRef of candidates) {
|
|
3455
|
-
const candidate = candidateRef.current;
|
|
3456
|
-
if (!candidate) continue;
|
|
3457
|
-
if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;
|
|
3458
|
-
candidate.focus({ preventScroll });
|
|
3459
|
-
if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;
|
|
3460
|
-
}
|
|
3461
|
-
}
|
|
3462
|
-
function wrapArray(array, startIndex) {
|
|
3463
|
-
return array.map((_, index$1) => array[(startIndex + index$1) % array.length]);
|
|
3464
|
-
}
|
|
3465
|
-
function getDirectionAwareKey(key, dir) {
|
|
3466
|
-
if (dir !== "rtl") return key;
|
|
3467
|
-
return key === "ArrowLeft" ? "ArrowRight" : key === "ArrowRight" ? "ArrowLeft" : key;
|
|
3468
|
-
}
|
|
3469
|
-
const ActionBarContext = React.createContext(null);
|
|
3470
|
-
function useActionBarContext(consumerName) {
|
|
3471
|
-
const context = React.useContext(ActionBarContext);
|
|
3472
|
-
if (!context) throw new Error(`\`${consumerName}\` must be used within \`${ROOT_NAME}\``);
|
|
3473
|
-
return context;
|
|
3474
|
-
}
|
|
3475
|
-
const FocusContext = React.createContext(null);
|
|
3476
|
-
function useFocusContext(consumerName) {
|
|
3477
|
-
const context = React.useContext(FocusContext);
|
|
3478
|
-
if (!context) throw new Error(`\`${consumerName}\` must be used within \`FocusProvider\``);
|
|
3479
|
-
return context;
|
|
3480
|
-
}
|
|
3481
|
-
function ActionBar(props) {
|
|
3482
|
-
const { open = false, onOpenChange, onEscapeKeyDown, side = "bottom", alignOffset = 0, align = "center", sideOffset = 16, portalContainer: portalContainerProp, dir: dirProp, orientation = "horizontal", loop = true, className, style, ref, asChild,...rootProps } = props;
|
|
3483
|
-
const [mounted, setMounted] = React.useState(false);
|
|
3484
|
-
const rootRef = React.useRef(null);
|
|
3485
|
-
const composedRef = useComposedRefs(ref, rootRef);
|
|
3486
|
-
const propsRef = useAsRef({
|
|
3487
|
-
onEscapeKeyDown,
|
|
3488
|
-
onOpenChange
|
|
3489
|
-
});
|
|
3490
|
-
const dir = useDirection(dirProp);
|
|
3491
|
-
React.useLayoutEffect(() => {
|
|
3492
|
-
setMounted(true);
|
|
3493
|
-
}, []);
|
|
3494
|
-
React.useEffect(() => {
|
|
3495
|
-
if (!open) return;
|
|
3496
|
-
const ownerDocument = rootRef.current?.ownerDocument ?? document;
|
|
3497
|
-
function onKeyDown(event) {
|
|
3498
|
-
if (event.key === "Escape") {
|
|
3499
|
-
propsRef.current.onEscapeKeyDown?.(event);
|
|
3500
|
-
if (!event.defaultPrevented) propsRef.current.onOpenChange?.(false);
|
|
3501
|
-
}
|
|
3502
|
-
}
|
|
3503
|
-
ownerDocument.addEventListener("keydown", onKeyDown);
|
|
3504
|
-
return () => ownerDocument.removeEventListener("keydown", onKeyDown);
|
|
3505
|
-
}, [open, propsRef]);
|
|
3506
|
-
const contextValue = React.useMemo(() => ({
|
|
3507
|
-
onOpenChange,
|
|
3508
|
-
dir,
|
|
3509
|
-
orientation,
|
|
3510
|
-
loop
|
|
3511
|
-
}), [
|
|
3512
|
-
onOpenChange,
|
|
3513
|
-
dir,
|
|
3514
|
-
orientation,
|
|
3515
|
-
loop
|
|
3516
|
-
]);
|
|
3517
|
-
const portalContainer = portalContainerProp ?? (mounted ? globalThis.document?.body : null);
|
|
3518
|
-
if (!portalContainer || !open) return null;
|
|
3519
|
-
const RootPrimitive = asChild ? Slot : "div";
|
|
3520
|
-
return /* @__PURE__ */ jsx(ActionBarContext.Provider, {
|
|
3521
|
-
value: contextValue,
|
|
3522
|
-
children: ReactDOM.createPortal(/* @__PURE__ */ jsx(RootPrimitive, {
|
|
3523
|
-
role: "toolbar",
|
|
3524
|
-
"aria-orientation": orientation,
|
|
3525
|
-
"data-slot": "action-bar",
|
|
3526
|
-
"data-side": side,
|
|
3527
|
-
"data-align": align,
|
|
3528
|
-
"data-orientation": orientation,
|
|
3529
|
-
dir,
|
|
3530
|
-
...rootProps,
|
|
3531
|
-
ref: composedRef,
|
|
3532
|
-
className: cn("fixed z-50 rounded-lg border bg-card shadow-lg outline-none", "fade-in-0 zoom-in-95 animate-in duration-250 [animation-timing-function:cubic-bezier(0.16,1,0.3,1)]", "data-[side=bottom]:slide-in-from-bottom-4 data-[side=top]:slide-in-from-top-4", "motion-reduce:animate-none motion-reduce:transition-none", orientation === "horizontal" ? "flex flex-row items-center gap-2 px-2 py-1.5" : "flex flex-col items-start gap-2 px-1.5 py-2", className),
|
|
3533
|
-
style: {
|
|
3534
|
-
[side]: `${sideOffset}px`,
|
|
3535
|
-
...align === "center" && {
|
|
3536
|
-
left: "50%",
|
|
3537
|
-
translate: "-50% 0"
|
|
3538
|
-
},
|
|
3539
|
-
...align === "start" && { left: `${alignOffset}px` },
|
|
3540
|
-
...align === "end" && { right: `${alignOffset}px` },
|
|
3541
|
-
...style
|
|
3542
|
-
}
|
|
3543
|
-
}), portalContainer)
|
|
3544
|
-
});
|
|
3545
|
-
}
|
|
3546
|
-
function ActionBarSelection(props) {
|
|
3547
|
-
const { className, asChild,...selectionProps } = props;
|
|
3548
|
-
return /* @__PURE__ */ jsx(asChild ? Slot : "div", {
|
|
3549
|
-
"data-slot": "action-bar-selection",
|
|
3550
|
-
...selectionProps,
|
|
3551
|
-
className: cn("flex items-center gap-1 rounded-sm border px-2 py-1 font-medium text-sm tabular-nums", className)
|
|
3552
|
-
});
|
|
3553
|
-
}
|
|
3554
|
-
function ActionBarGroup(props) {
|
|
3555
|
-
const { onBlur: onBlurProp, onFocus: onFocusProp, onMouseDown: onMouseDownProp, className, asChild, ref,...groupProps } = props;
|
|
3556
|
-
const [tabStopId, setTabStopId] = React.useState(null);
|
|
3557
|
-
const [isTabbingBackOut, setIsTabbingBackOut] = React.useState(false);
|
|
3558
|
-
const [focusableItemCount, setFocusableItemCount] = React.useState(0);
|
|
3559
|
-
const composedRef = useComposedRefs(ref, React.useRef(null));
|
|
3560
|
-
const isClickFocusRef = React.useRef(false);
|
|
3561
|
-
const itemsRef = React.useRef(/* @__PURE__ */ new Map());
|
|
3562
|
-
const { dir, orientation } = useActionBarContext(GROUP_NAME);
|
|
3563
|
-
const onItemFocus = React.useCallback((tabStopId$1) => {
|
|
3564
|
-
setTabStopId(tabStopId$1);
|
|
3565
|
-
}, []);
|
|
3566
|
-
const onItemShiftTab = React.useCallback(() => {
|
|
3567
|
-
setIsTabbingBackOut(true);
|
|
3568
|
-
}, []);
|
|
3569
|
-
const onFocusableItemAdd = React.useCallback(() => {
|
|
3570
|
-
setFocusableItemCount((prevCount) => prevCount + 1);
|
|
3571
|
-
}, []);
|
|
3572
|
-
const onFocusableItemRemove = React.useCallback(() => {
|
|
3573
|
-
setFocusableItemCount((prevCount) => prevCount - 1);
|
|
3574
|
-
}, []);
|
|
3575
|
-
const onItemRegister = React.useCallback((item) => {
|
|
3576
|
-
itemsRef.current.set(item.id, item);
|
|
3577
|
-
}, []);
|
|
3578
|
-
const onItemUnregister = React.useCallback((id) => {
|
|
3579
|
-
itemsRef.current.delete(id);
|
|
3580
|
-
}, []);
|
|
3581
|
-
const getItems = React.useCallback(() => {
|
|
3582
|
-
return Array.from(itemsRef.current.values()).filter((item) => item.ref.current).sort((a, b) => {
|
|
3583
|
-
const elementA = a.ref.current;
|
|
3584
|
-
const elementB = b.ref.current;
|
|
3585
|
-
if (!elementA || !elementB) return 0;
|
|
3586
|
-
const position = elementA.compareDocumentPosition(elementB);
|
|
3587
|
-
if (position & Node.DOCUMENT_POSITION_FOLLOWING) return -1;
|
|
3588
|
-
if (position & Node.DOCUMENT_POSITION_PRECEDING) return 1;
|
|
3589
|
-
return 0;
|
|
3590
|
-
});
|
|
3591
|
-
}, []);
|
|
3592
|
-
const onBlur = React.useCallback((event) => {
|
|
3593
|
-
onBlurProp?.(event);
|
|
3594
|
-
if (event.defaultPrevented) return;
|
|
3595
|
-
setIsTabbingBackOut(false);
|
|
3596
|
-
}, [onBlurProp]);
|
|
3597
|
-
const onFocus = React.useCallback((event) => {
|
|
3598
|
-
onFocusProp?.(event);
|
|
3599
|
-
if (event.defaultPrevented) return;
|
|
3600
|
-
const isKeyboardFocus = !isClickFocusRef.current;
|
|
3601
|
-
if (event.target === event.currentTarget && isKeyboardFocus && !isTabbingBackOut) {
|
|
3602
|
-
const entryFocusEvent = new CustomEvent(ENTRY_FOCUS, EVENT_OPTIONS);
|
|
3603
|
-
event.currentTarget.dispatchEvent(entryFocusEvent);
|
|
3604
|
-
if (!entryFocusEvent.defaultPrevented) {
|
|
3605
|
-
const items = Array.from(itemsRef.current.values()).filter((item) => !item.disabled);
|
|
3606
|
-
focusFirst([items.find((item) => item.id === tabStopId), ...items].filter(Boolean).map((item) => item.ref), false);
|
|
3607
|
-
}
|
|
3608
|
-
}
|
|
3609
|
-
isClickFocusRef.current = false;
|
|
3610
|
-
}, [
|
|
3611
|
-
onFocusProp,
|
|
3612
|
-
isTabbingBackOut,
|
|
3613
|
-
tabStopId
|
|
3614
|
-
]);
|
|
3615
|
-
const onMouseDown = React.useCallback((event) => {
|
|
3616
|
-
onMouseDownProp?.(event);
|
|
3617
|
-
if (event.defaultPrevented) return;
|
|
3618
|
-
isClickFocusRef.current = true;
|
|
3619
|
-
}, [onMouseDownProp]);
|
|
3620
|
-
const focusContextValue = React.useMemo(() => ({
|
|
3621
|
-
tabStopId,
|
|
3622
|
-
onItemFocus,
|
|
3623
|
-
onItemShiftTab,
|
|
3624
|
-
onFocusableItemAdd,
|
|
3625
|
-
onFocusableItemRemove,
|
|
3626
|
-
onItemRegister,
|
|
3627
|
-
onItemUnregister,
|
|
3628
|
-
getItems
|
|
3629
|
-
}), [
|
|
3630
|
-
tabStopId,
|
|
3631
|
-
onItemFocus,
|
|
3632
|
-
onItemShiftTab,
|
|
3633
|
-
onFocusableItemAdd,
|
|
3634
|
-
onFocusableItemRemove,
|
|
3635
|
-
onItemRegister,
|
|
3636
|
-
onItemUnregister,
|
|
3637
|
-
getItems
|
|
3638
|
-
]);
|
|
3639
|
-
const GroupPrimitive = asChild ? Slot : "div";
|
|
3640
|
-
return /* @__PURE__ */ jsx(FocusContext.Provider, {
|
|
3641
|
-
value: focusContextValue,
|
|
3642
|
-
children: /* @__PURE__ */ jsx(GroupPrimitive, {
|
|
3643
|
-
role: "group",
|
|
3644
|
-
"data-slot": "action-bar-group",
|
|
3645
|
-
"data-orientation": orientation,
|
|
3646
|
-
dir,
|
|
3647
|
-
tabIndex: isTabbingBackOut || focusableItemCount === 0 ? -1 : 0,
|
|
3648
|
-
...groupProps,
|
|
3649
|
-
ref: composedRef,
|
|
3650
|
-
className: cn("flex gap-2 outline-none", orientation === "horizontal" ? "items-center" : "w-full flex-col items-start", className),
|
|
3651
|
-
onBlur,
|
|
3652
|
-
onFocus,
|
|
3653
|
-
onMouseDown
|
|
3654
|
-
})
|
|
3655
|
-
});
|
|
3656
|
-
}
|
|
3657
|
-
function ActionBarItem(props) {
|
|
3658
|
-
const { onSelect, onClick: onClickProp, onFocus: onFocusProp, onKeyDown: onKeyDownProp, onMouseDown: onMouseDownProp, className, disabled, ref,...itemProps } = props;
|
|
3659
|
-
const itemRef = React.useRef(null);
|
|
3660
|
-
const composedRef = useComposedRefs(ref, itemRef);
|
|
3661
|
-
const isMouseClickRef = React.useRef(false);
|
|
3662
|
-
const { onOpenChange, dir, orientation, loop } = useActionBarContext(ITEM_NAME);
|
|
3663
|
-
const focusContext = useFocusContext(ITEM_NAME);
|
|
3664
|
-
const itemId = React.useId();
|
|
3665
|
-
const isTabStop = focusContext.tabStopId === itemId;
|
|
3666
|
-
useIsomorphicLayoutEffect(() => {
|
|
3667
|
-
focusContext.onItemRegister({
|
|
3668
|
-
id: itemId,
|
|
3669
|
-
ref: itemRef,
|
|
3670
|
-
disabled: !!disabled
|
|
3671
|
-
});
|
|
3672
|
-
if (!disabled) focusContext.onFocusableItemAdd();
|
|
3673
|
-
return () => {
|
|
3674
|
-
focusContext.onItemUnregister(itemId);
|
|
3675
|
-
if (!disabled) focusContext.onFocusableItemRemove();
|
|
3676
|
-
};
|
|
3677
|
-
}, [
|
|
3678
|
-
focusContext,
|
|
3679
|
-
itemId,
|
|
3680
|
-
disabled
|
|
3681
|
-
]);
|
|
3682
|
-
const onClick = React.useCallback((event) => {
|
|
3683
|
-
onClickProp?.(event);
|
|
3684
|
-
if (event.defaultPrevented) return;
|
|
3685
|
-
const item = itemRef.current;
|
|
3686
|
-
if (!item) return;
|
|
3687
|
-
const itemSelectEvent = new CustomEvent(ITEM_SELECT, {
|
|
3688
|
-
bubbles: true,
|
|
3689
|
-
cancelable: true
|
|
3690
|
-
});
|
|
3691
|
-
item.addEventListener(ITEM_SELECT, (event$1) => onSelect?.(event$1), { once: true });
|
|
3692
|
-
item.dispatchEvent(itemSelectEvent);
|
|
3693
|
-
if (!itemSelectEvent.defaultPrevented) onOpenChange?.(false);
|
|
3694
|
-
}, [
|
|
3695
|
-
onClickProp,
|
|
3696
|
-
onOpenChange,
|
|
3697
|
-
onSelect
|
|
3698
|
-
]);
|
|
3699
|
-
const onFocus = React.useCallback((event) => {
|
|
3700
|
-
onFocusProp?.(event);
|
|
3701
|
-
if (event.defaultPrevented) return;
|
|
3702
|
-
focusContext.onItemFocus(itemId);
|
|
3703
|
-
isMouseClickRef.current = false;
|
|
3704
|
-
}, [
|
|
3705
|
-
onFocusProp,
|
|
3706
|
-
focusContext,
|
|
3707
|
-
itemId
|
|
3708
|
-
]);
|
|
3709
|
-
const onKeyDown = React.useCallback((event) => {
|
|
3710
|
-
onKeyDownProp?.(event);
|
|
3711
|
-
if (event.defaultPrevented) return;
|
|
3712
|
-
if (event.key === "Tab" && event.shiftKey) {
|
|
3713
|
-
focusContext.onItemShiftTab();
|
|
3714
|
-
return;
|
|
3715
|
-
}
|
|
3716
|
-
if (event.target !== event.currentTarget) return;
|
|
3717
|
-
const key = getDirectionAwareKey(event.key, dir);
|
|
3718
|
-
let focusIntent;
|
|
3719
|
-
if (orientation === "horizontal") {
|
|
3720
|
-
if (key === "ArrowLeft") focusIntent = "prev";
|
|
3721
|
-
else if (key === "ArrowRight") focusIntent = "next";
|
|
3722
|
-
else if (key === "Home") focusIntent = "first";
|
|
3723
|
-
else if (key === "End") focusIntent = "last";
|
|
3724
|
-
} else if (key === "ArrowUp") focusIntent = "prev";
|
|
3725
|
-
else if (key === "ArrowDown") focusIntent = "next";
|
|
3726
|
-
else if (key === "Home") focusIntent = "first";
|
|
3727
|
-
else if (key === "End") focusIntent = "last";
|
|
3728
|
-
if (focusIntent !== void 0) {
|
|
3729
|
-
if (event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return;
|
|
3730
|
-
event.preventDefault();
|
|
3731
|
-
let candidateRefs = focusContext.getItems().filter((item) => !item.disabled).map((item) => item.ref);
|
|
3732
|
-
if (focusIntent === "last") candidateRefs.reverse();
|
|
3733
|
-
else if (focusIntent === "prev" || focusIntent === "next") {
|
|
3734
|
-
if (focusIntent === "prev") candidateRefs.reverse();
|
|
3735
|
-
const currentIndex = candidateRefs.findIndex((ref$1) => ref$1.current === event.currentTarget);
|
|
3736
|
-
candidateRefs = loop ? wrapArray(candidateRefs, currentIndex + 1) : candidateRefs.slice(currentIndex + 1);
|
|
3737
|
-
}
|
|
3738
|
-
queueMicrotask(() => focusFirst(candidateRefs));
|
|
3739
|
-
}
|
|
3740
|
-
}, [
|
|
3741
|
-
onKeyDownProp,
|
|
3742
|
-
focusContext,
|
|
3743
|
-
dir,
|
|
3744
|
-
orientation,
|
|
3745
|
-
loop
|
|
3746
|
-
]);
|
|
3747
|
-
const onMouseDown = React.useCallback((event) => {
|
|
3748
|
-
onMouseDownProp?.(event);
|
|
3749
|
-
if (event.defaultPrevented) return;
|
|
3750
|
-
isMouseClickRef.current = true;
|
|
3751
|
-
if (disabled) event.preventDefault();
|
|
3752
|
-
else focusContext.onItemFocus(itemId);
|
|
3753
|
-
}, [
|
|
3754
|
-
onMouseDownProp,
|
|
3755
|
-
focusContext,
|
|
3756
|
-
itemId,
|
|
3757
|
-
disabled
|
|
3758
|
-
]);
|
|
3759
|
-
return /* @__PURE__ */ jsx(Button, {
|
|
3760
|
-
type: "button",
|
|
3761
|
-
"data-slot": "action-bar-item",
|
|
3762
|
-
variant: "secondary",
|
|
3763
|
-
size: "sm",
|
|
3764
|
-
disabled,
|
|
3765
|
-
tabIndex: isTabStop ? 0 : -1,
|
|
3766
|
-
...itemProps,
|
|
3767
|
-
className: cn(orientation === "vertical" && "w-full", className),
|
|
3768
|
-
ref: composedRef,
|
|
3769
|
-
onClick,
|
|
3770
|
-
onFocus,
|
|
3771
|
-
onKeyDown,
|
|
3772
|
-
onMouseDown
|
|
3773
|
-
});
|
|
3774
|
-
}
|
|
3775
|
-
function ActionBarClose(props) {
|
|
3776
|
-
const { asChild, className, onClick,...closeProps } = props;
|
|
3777
|
-
const { onOpenChange } = useActionBarContext(CLOSE_NAME);
|
|
3778
|
-
const onCloseClick = React.useCallback((event) => {
|
|
3779
|
-
onClick?.(event);
|
|
3780
|
-
if (event.defaultPrevented) return;
|
|
3781
|
-
onOpenChange?.(false);
|
|
3782
|
-
}, [onOpenChange, onClick]);
|
|
3783
|
-
return /* @__PURE__ */ jsx(asChild ? Slot : "button", {
|
|
3784
|
-
type: "button",
|
|
3785
|
-
"data-slot": "action-bar-close",
|
|
3786
|
-
...closeProps,
|
|
3787
|
-
className: cn("rounded-xs opacity-70 outline-none hover:opacity-100 focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/50 disabled:pointer-events-none [&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:shrink-0", className),
|
|
3788
|
-
onClick: onCloseClick
|
|
3789
|
-
});
|
|
3790
|
-
}
|
|
3791
|
-
function ActionBarSeparator(props) {
|
|
3792
|
-
const { orientation: orientationProp, asChild, className,...separatorProps } = props;
|
|
3793
|
-
const context = useActionBarContext(SEPARATOR_NAME);
|
|
3794
|
-
const orientation = orientationProp ?? context.orientation;
|
|
3795
|
-
return /* @__PURE__ */ jsx(asChild ? Slot : "div", {
|
|
3796
|
-
role: "separator",
|
|
3797
|
-
"aria-orientation": orientation,
|
|
3798
|
-
"aria-hidden": "true",
|
|
3799
|
-
"data-slot": "action-bar-separator",
|
|
3800
|
-
...separatorProps,
|
|
3801
|
-
className: cn("in-data-[slot=action-bar-selection]:ml-0.5 in-data-[slot=action-bar-selection]:h-4 in-data-[slot=action-bar-selection]:w-px bg-border", orientation === "horizontal" ? "h-6 w-px" : "h-px w-full", className)
|
|
3802
|
-
});
|
|
3803
|
-
}
|
|
3804
|
-
|
|
3805
2823
|
//#endregion
|
|
3806
2824
|
//#region src/components/data-table/data-table-column-header.tsx
|
|
3807
2825
|
function DataTableColumnHeader({ column, label, className,...props }) {
|
|
@@ -4462,12 +3480,22 @@ function downloadCSV(csvContent, filename) {
|
|
|
4462
3480
|
|
|
4463
3481
|
//#endregion
|
|
4464
3482
|
//#region src/components/auto-crud/auto-table-action-bar.tsx
|
|
4465
|
-
|
|
4466
|
-
|
|
3483
|
+
const DEFAULT_DELETE_CONFIRMATION = {
|
|
3484
|
+
title: "确认批量删除",
|
|
3485
|
+
description: (count) => `此操作无法撤销。确定要删除选中的 ${count} 条记录吗?`,
|
|
3486
|
+
cancel: "取消",
|
|
3487
|
+
confirm: "确认删除"
|
|
3488
|
+
};
|
|
3489
|
+
function isBatchCustomAction(action$1) {
|
|
3490
|
+
return action$1.type === "custom";
|
|
4467
3491
|
}
|
|
4468
|
-
function AutoTableActionBar({ table, onDeleteSelected, onUpdateSelected, batchUpdateFields, enableExport = true, showDefaultExport = true, enableDelete = true, extraActions, actions }) {
|
|
3492
|
+
function AutoTableActionBar({ table, onDeleteSelected, onUpdateSelected, batchUpdateFields, enableExport = true, showDefaultExport = true, enableDelete = true, extraActions, actions, deleteConfirmation = DEFAULT_DELETE_CONFIRMATION }) {
|
|
4469
3493
|
const rows = table.getFilteredSelectedRowModel().rows;
|
|
4470
3494
|
const selectedRows = React.useMemo(() => rows.map((row) => row.original), [rows]);
|
|
3495
|
+
const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false);
|
|
3496
|
+
React.useEffect(() => {
|
|
3497
|
+
if (selectedRows.length === 0) setDeleteDialogOpen(false);
|
|
3498
|
+
}, [selectedRows.length]);
|
|
4471
3499
|
const clearSelection = React.useCallback(() => {
|
|
4472
3500
|
table.toggleAllRowsSelected(false);
|
|
4473
3501
|
}, [table]);
|
|
@@ -4490,8 +3518,34 @@ function AutoTableActionBar({ table, onDeleteSelected, onUpdateSelected, batchUp
|
|
|
4490
3518
|
});
|
|
4491
3519
|
}, [table]);
|
|
4492
3520
|
const onDelete = React.useCallback(() => {
|
|
4493
|
-
if (onDeleteSelected
|
|
4494
|
-
|
|
3521
|
+
if (onDeleteSelected && selectedRows.length > 0) {
|
|
3522
|
+
onDeleteSelected(selectedRows);
|
|
3523
|
+
clearSelection();
|
|
3524
|
+
}
|
|
3525
|
+
setDeleteDialogOpen(false);
|
|
3526
|
+
}, [
|
|
3527
|
+
selectedRows,
|
|
3528
|
+
onDeleteSelected,
|
|
3529
|
+
clearSelection
|
|
3530
|
+
]);
|
|
3531
|
+
const runDeleteAction = React.useCallback((action$1, event) => {
|
|
3532
|
+
if (selectedRows.length === 0) {
|
|
3533
|
+
setDeleteDialogOpen(false);
|
|
3534
|
+
return;
|
|
3535
|
+
}
|
|
3536
|
+
if (action$1.onClick) {
|
|
3537
|
+
action$1.onClick(selectedRows, actionContext, event);
|
|
3538
|
+
clearSelection();
|
|
3539
|
+
setDeleteDialogOpen(false);
|
|
3540
|
+
return;
|
|
3541
|
+
}
|
|
3542
|
+
onDelete();
|
|
3543
|
+
}, [
|
|
3544
|
+
actionContext,
|
|
3545
|
+
clearSelection,
|
|
3546
|
+
onDelete,
|
|
3547
|
+
selectedRows
|
|
3548
|
+
]);
|
|
4495
3549
|
const handleBatchUpdate = React.useCallback((field, value) => {
|
|
4496
3550
|
if (onUpdateSelected) {
|
|
4497
3551
|
onUpdateSelected(selectedRows, { [field]: value });
|
|
@@ -4518,18 +3572,28 @@ function AutoTableActionBar({ table, onDeleteSelected, onUpdateSelected, batchUp
|
|
|
4518
3572
|
children: option.label
|
|
4519
3573
|
}, option.value))
|
|
4520
3574
|
})] }, `${keyPrefix}-${fieldConfig.field}`)), [batchUpdateFields, handleBatchUpdate]);
|
|
4521
|
-
const renderBuiltinAction = React.useCallback((action) => {
|
|
4522
|
-
if (!(action.type === "batchUpdate" ? !!onUpdateSelected && !!batchUpdateFields?.length : action.type === "export" ? enableExport : enableDelete && !!onDeleteSelected)) return null;
|
|
4523
|
-
if (action.component) return renderComponent(action.component);
|
|
4524
|
-
if (action.type === "batchUpdate") return renderBatchUpdate(action.type);
|
|
4525
|
-
if (action.type === "export") return /* @__PURE__ */ jsxs(ActionBarItem, {
|
|
4526
|
-
onClick: (event) => action.onClick ? action.onClick(selectedRows, actionContext, event) : onExport(),
|
|
4527
|
-
children: [/* @__PURE__ */ jsx(Download, {}), action.label ?? "Export"]
|
|
3575
|
+
const renderBuiltinAction = React.useCallback((action$1) => {
|
|
3576
|
+
if (!(action$1.type === "batchUpdate" ? !!onUpdateSelected && !!batchUpdateFields?.length : action$1.type === "export" ? enableExport : enableDelete && !!onDeleteSelected)) return null;
|
|
3577
|
+
if (action$1.component) return renderComponent(action$1.component);
|
|
3578
|
+
if (action$1.type === "batchUpdate") return renderBatchUpdate(action$1.type);
|
|
3579
|
+
if (action$1.type === "export") return /* @__PURE__ */ jsxs(ActionBarItem, {
|
|
3580
|
+
onClick: (event) => action$1.onClick ? action$1.onClick(selectedRows, actionContext, event) : onExport(),
|
|
3581
|
+
children: [/* @__PURE__ */ jsx(Download, {}), action$1.label ?? "Export"]
|
|
4528
3582
|
}, "export");
|
|
4529
|
-
if (action.type === "delete") return /* @__PURE__ */ jsxs(
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
children: [/* @__PURE__ */
|
|
3583
|
+
if (action$1.type === "delete") return /* @__PURE__ */ jsxs(AlertDialog, {
|
|
3584
|
+
open: deleteDialogOpen,
|
|
3585
|
+
onOpenChange: setDeleteDialogOpen,
|
|
3586
|
+
children: [/* @__PURE__ */ jsxs(ActionBarItem, {
|
|
3587
|
+
variant: "destructive",
|
|
3588
|
+
onClick: () => setDeleteDialogOpen(true),
|
|
3589
|
+
onSelect: (event) => event.preventDefault(),
|
|
3590
|
+
children: [/* @__PURE__ */ jsx(Trash2, {}), action$1.label ?? "Delete"]
|
|
3591
|
+
}), /* @__PURE__ */ jsxs(AlertDialogContent, { children: [/* @__PURE__ */ jsxs(AlertDialogHeader, { children: [/* @__PURE__ */ jsx(AlertDialogTitle, { children: deleteConfirmation.title }), /* @__PURE__ */ jsx(AlertDialogDescription, { children: deleteConfirmation.description(selectedRows.length) })] }), /* @__PURE__ */ jsxs(AlertDialogFooter, { children: [/* @__PURE__ */ jsx(AlertDialogCancel, { children: deleteConfirmation.cancel }), /* @__PURE__ */ jsx(AlertDialogAction, {
|
|
3592
|
+
className: "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30",
|
|
3593
|
+
disabled: selectedRows.length === 0,
|
|
3594
|
+
onClick: (event) => runDeleteAction(action$1, event),
|
|
3595
|
+
children: deleteConfirmation.confirm
|
|
3596
|
+
})] })] })]
|
|
4533
3597
|
}, "delete");
|
|
4534
3598
|
return null;
|
|
4535
3599
|
}, [
|
|
@@ -4537,21 +3601,24 @@ function AutoTableActionBar({ table, onDeleteSelected, onUpdateSelected, batchUp
|
|
|
4537
3601
|
batchUpdateFields?.length,
|
|
4538
3602
|
enableDelete,
|
|
4539
3603
|
enableExport,
|
|
3604
|
+
deleteConfirmation,
|
|
3605
|
+
deleteDialogOpen,
|
|
4540
3606
|
onDelete,
|
|
4541
3607
|
onDeleteSelected,
|
|
4542
3608
|
onUpdateSelected,
|
|
4543
3609
|
onExport,
|
|
4544
3610
|
renderBatchUpdate,
|
|
4545
3611
|
renderComponent,
|
|
3612
|
+
runDeleteAction,
|
|
4546
3613
|
selectedRows
|
|
4547
3614
|
]);
|
|
4548
|
-
const renderCustomAction = React.useCallback((action, index$1) => {
|
|
4549
|
-
if (action.component) return /* @__PURE__ */ jsx(React.Fragment, { children: renderComponent(action.component) }, `custom-${index$1}`);
|
|
4550
|
-
if (!action.label || !action.onClick) return null;
|
|
3615
|
+
const renderCustomAction = React.useCallback((action$1, index$1) => {
|
|
3616
|
+
if (action$1.component) return /* @__PURE__ */ jsx(React.Fragment, { children: renderComponent(action$1.component) }, `custom-${index$1}`);
|
|
3617
|
+
if (!action$1.label || !action$1.onClick) return null;
|
|
4551
3618
|
return /* @__PURE__ */ jsx(ActionBarItem, {
|
|
4552
|
-
variant: action.variant === "destructive" ? "destructive" : "secondary",
|
|
4553
|
-
onClick: (event) => action.onClick?.(selectedRows, actionContext, event),
|
|
4554
|
-
children: action.label
|
|
3619
|
+
variant: action$1.variant === "destructive" ? "destructive" : "secondary",
|
|
3620
|
+
onClick: (event) => action$1.onClick?.(selectedRows, actionContext, event),
|
|
3621
|
+
children: action$1.label
|
|
4555
3622
|
}, `custom-${index$1}`);
|
|
4556
3623
|
}, [
|
|
4557
3624
|
actionContext,
|
|
@@ -4564,7 +3631,7 @@ function AutoTableActionBar({ table, onDeleteSelected, onUpdateSelected, batchUp
|
|
|
4564
3631
|
{ type: "export" },
|
|
4565
3632
|
{ type: "delete" }
|
|
4566
3633
|
]) : actions;
|
|
4567
|
-
const resolvedActions = configuredActions?.filter((action) => !action.hidden);
|
|
3634
|
+
const resolvedActions = configuredActions?.filter((action$1) => !action$1.hidden);
|
|
4568
3635
|
if (configuredActions === void 0) return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4569
3636
|
renderBuiltinAction({ type: "batchUpdate" }),
|
|
4570
3637
|
extraActions,
|
|
@@ -4572,9 +3639,9 @@ function AutoTableActionBar({ table, onDeleteSelected, onUpdateSelected, batchUp
|
|
|
4572
3639
|
renderBuiltinAction({ type: "delete" })
|
|
4573
3640
|
] });
|
|
4574
3641
|
if (!resolvedActions || resolvedActions.length === 0) return null;
|
|
4575
|
-
if (!resolvedActions.some((action) => action.type !== "custom")) {
|
|
4576
|
-
const startNodes = resolvedActions.filter(isBatchCustomAction).filter((action) => action.position === "start").map((action, index$1) => renderCustomAction(action, index$1));
|
|
4577
|
-
const endNodes = resolvedActions.filter(isBatchCustomAction).filter((action) => action.position !== "start").map((action, index$1) => renderCustomAction(action, index$1));
|
|
3642
|
+
if (!resolvedActions.some((action$1) => action$1.type !== "custom")) {
|
|
3643
|
+
const startNodes = resolvedActions.filter(isBatchCustomAction).filter((action$1) => action$1.position === "start").map((action$1, index$1) => renderCustomAction(action$1, index$1));
|
|
3644
|
+
const endNodes = resolvedActions.filter(isBatchCustomAction).filter((action$1) => action$1.position !== "start").map((action$1, index$1) => renderCustomAction(action$1, index$1));
|
|
4578
3645
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4579
3646
|
startNodes,
|
|
4580
3647
|
renderBuiltinAction({ type: "batchUpdate" }),
|
|
@@ -4584,9 +3651,9 @@ function AutoTableActionBar({ table, onDeleteSelected, onUpdateSelected, batchUp
|
|
|
4584
3651
|
endNodes
|
|
4585
3652
|
] });
|
|
4586
3653
|
}
|
|
4587
|
-
return resolvedActions.map((action, index$1) => {
|
|
4588
|
-
if (action.type === "custom") return renderCustomAction(action, index$1);
|
|
4589
|
-
return /* @__PURE__ */ jsx(React.Fragment, { children: renderBuiltinAction(action) }, action.type);
|
|
3654
|
+
return resolvedActions.map((action$1, index$1) => {
|
|
3655
|
+
if (action$1.type === "custom") return renderCustomAction(action$1, index$1);
|
|
3656
|
+
return /* @__PURE__ */ jsx(React.Fragment, { children: renderBuiltinAction(action$1) }, action$1.type);
|
|
4590
3657
|
});
|
|
4591
3658
|
}, [
|
|
4592
3659
|
actions,
|
|
@@ -4870,7 +3937,7 @@ const filterModeConfig = {
|
|
|
4870
3937
|
tooltip: "Linear-style command filters"
|
|
4871
3938
|
}
|
|
4872
3939
|
};
|
|
4873
|
-
function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode = "simple", search = false, onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, actionBarActions, initialSorting, enableExport = true, showDefaultExport = true, onSelectedCountChange, onSelectedRowsChange, getSelectedRows }) {
|
|
3940
|
+
function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode = "simple", search = false, onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, actionBarActions, deleteConfirmation, initialSorting, enableExport = true, showDefaultExport = true, onSelectedCountChange, onSelectedRowsChange, getSelectedRows }) {
|
|
4874
3941
|
const modes = filterMode ? Array.isArray(filterMode) ? filterMode : [filterMode] : DEFAULT_MODES;
|
|
4875
3942
|
const [currentMode, setCurrentMode] = useQueryState("filterMode", parseAsStringEnum(modes).withDefault(modes[0] ?? "simple"));
|
|
4876
3943
|
const showToggle = modes.length > 1;
|
|
@@ -5047,7 +4114,8 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
|
|
|
5047
4114
|
enableExport,
|
|
5048
4115
|
showDefaultExport,
|
|
5049
4116
|
extraActions: actionBarExtra,
|
|
5050
|
-
actions: actionBarActions
|
|
4117
|
+
actions: actionBarActions,
|
|
4118
|
+
deleteConfirmation
|
|
5051
4119
|
})
|
|
5052
4120
|
]
|
|
5053
4121
|
});
|
|
@@ -5249,11 +4317,19 @@ function normalizeDataSourceRegistration(registration) {
|
|
|
5249
4317
|
if (typeof registration === "function") return {
|
|
5250
4318
|
dependencies: [],
|
|
5251
4319
|
reset: false,
|
|
4320
|
+
search: false,
|
|
4321
|
+
debounceMs: 300,
|
|
4322
|
+
loadMore: false,
|
|
4323
|
+
pageSize: 20,
|
|
5252
4324
|
load: registration
|
|
5253
4325
|
};
|
|
5254
4326
|
return {
|
|
5255
4327
|
dependencies: Array.isArray(registration.dependencies) ? registration.dependencies : [],
|
|
5256
4328
|
reset: registration.reset === true,
|
|
4329
|
+
search: registration.search === true,
|
|
4330
|
+
debounceMs: typeof registration.debounceMs === "number" && registration.debounceMs >= 0 ? registration.debounceMs : 300,
|
|
4331
|
+
loadMore: registration.loadMore === true,
|
|
4332
|
+
pageSize: typeof registration.pageSize === "number" && registration.pageSize > 0 ? registration.pageSize : 20,
|
|
5257
4333
|
load: registration.load
|
|
5258
4334
|
};
|
|
5259
4335
|
}
|
|
@@ -5280,10 +4356,63 @@ function normalizeOptions(result) {
|
|
|
5280
4356
|
value: String(option.value)
|
|
5281
4357
|
}));
|
|
5282
4358
|
}
|
|
4359
|
+
function normalizeHasMore(result) {
|
|
4360
|
+
return !Array.isArray(result) && result?.hasMore === true;
|
|
4361
|
+
}
|
|
4362
|
+
|
|
4363
|
+
//#endregion
|
|
4364
|
+
//#region src/lib/field-config.ts
|
|
4365
|
+
function normalizeFieldOptions$1(options) {
|
|
4366
|
+
if (!options || options.length === 0) return void 0;
|
|
4367
|
+
return options.map((option) => ({
|
|
4368
|
+
...option,
|
|
4369
|
+
value: String(option.value)
|
|
4370
|
+
}));
|
|
4371
|
+
}
|
|
4372
|
+
/**
|
|
4373
|
+
* 从统一字段配置生成 Formily overrides。
|
|
4374
|
+
* `legacyOverrides` 保持兼容旧 API,字段级 `form` 配置优先级最高。
|
|
4375
|
+
*/
|
|
4376
|
+
function buildFormOverrides(fields, legacyOverrides, denyFields) {
|
|
4377
|
+
const result = { ...legacyOverrides };
|
|
4378
|
+
if (denyFields) for (const field of denyFields) result[field] = {
|
|
4379
|
+
...result[field],
|
|
4380
|
+
"x-hidden": true
|
|
4381
|
+
};
|
|
4382
|
+
if (fields) for (const [key, config] of Object.entries(fields)) {
|
|
4383
|
+
const fieldOptions = normalizeFieldOptions$1((config.form && typeof config.form === "object" ? config.form : void 0)?.enum) ?? normalizeFieldOptions$1(config.enum);
|
|
4384
|
+
const fieldDataSource = fieldOptions || !config.dataSource ? void 0 : normalizeDataSourceConfig(config.dataSource);
|
|
4385
|
+
if (config.label) result[key] = {
|
|
4386
|
+
...result[key],
|
|
4387
|
+
title: config.label
|
|
4388
|
+
};
|
|
4389
|
+
if (config.hidden) result[key] = {
|
|
4390
|
+
...result[key],
|
|
4391
|
+
"x-hidden": true
|
|
4392
|
+
};
|
|
4393
|
+
if (fieldOptions) result[key] = {
|
|
4394
|
+
...result[key],
|
|
4395
|
+
enum: fieldOptions
|
|
4396
|
+
};
|
|
4397
|
+
if (fieldDataSource) result[key] = {
|
|
4398
|
+
...result[key],
|
|
4399
|
+
"x-data-source": config.dataSource
|
|
4400
|
+
};
|
|
4401
|
+
if (config.form === false) result[key] = {
|
|
4402
|
+
...result[key],
|
|
4403
|
+
"x-hidden": true
|
|
4404
|
+
};
|
|
4405
|
+
else if (config.form && typeof config.form === "object") result[key] = {
|
|
4406
|
+
...result[key],
|
|
4407
|
+
...config.form
|
|
4408
|
+
};
|
|
4409
|
+
}
|
|
4410
|
+
return result;
|
|
4411
|
+
}
|
|
5283
4412
|
|
|
5284
4413
|
//#endregion
|
|
5285
4414
|
//#region src/components/auto-crud/auto-form.tsx
|
|
5286
|
-
const COMBOBOX_LIST_CLASS = "[&_[
|
|
4415
|
+
const COMBOBOX_LIST_CLASS = "[&_[data-multi-combobox-viewport]]:max-h-[360px] [&_[data-multi-combobox-viewport]]:overflow-x-hidden [&_[data-multi-combobox-viewport]]:overflow-y-auto";
|
|
5287
4416
|
const FormilySwitch = connect(Switch, mapProps({
|
|
5288
4417
|
value: "checked",
|
|
5289
4418
|
onInput: "onCheckedChange"
|
|
@@ -5293,25 +4422,27 @@ const FormilyMultiCombobox = connect(AutoCrudMultiCombobox, mapProps({
|
|
|
5293
4422
|
dataSource: "options",
|
|
5294
4423
|
onInput: "onChange"
|
|
5295
4424
|
}, (props, field) => {
|
|
5296
|
-
const fieldValue = field.value;
|
|
4425
|
+
const fieldValue = field && typeof field === "object" && "value" in field ? field.value : props.value;
|
|
5297
4426
|
return {
|
|
5298
4427
|
...props,
|
|
5299
4428
|
value: Array.isArray(fieldValue) ? fieldValue.map(String) : []
|
|
5300
4429
|
};
|
|
5301
4430
|
}));
|
|
5302
4431
|
function AutoCrudCombobox({ options = [], className, value, onChange,...props }) {
|
|
5303
|
-
return /* @__PURE__ */ jsx(
|
|
4432
|
+
return /* @__PURE__ */ jsx(Select$2, {
|
|
5304
4433
|
...props,
|
|
5305
|
-
|
|
4434
|
+
mode: "searchable",
|
|
4435
|
+
value: value ?? "",
|
|
5306
4436
|
options,
|
|
5307
|
-
|
|
5308
|
-
onChange: (nextValues) => onChange?.(nextValues[0] ?? ""),
|
|
4437
|
+
onChange: (nextValue) => onChange?.(nextValue),
|
|
5309
4438
|
className: cn$1(COMBOBOX_LIST_CLASS, className)
|
|
5310
4439
|
});
|
|
5311
4440
|
}
|
|
5312
4441
|
function AutoCrudMultiCombobox({ options = [],...props }) {
|
|
5313
|
-
return /* @__PURE__ */ jsx(
|
|
4442
|
+
return /* @__PURE__ */ jsx(Select$2, {
|
|
5314
4443
|
...props,
|
|
4444
|
+
mode: "searchable",
|
|
4445
|
+
multiple: true,
|
|
5315
4446
|
options
|
|
5316
4447
|
});
|
|
5317
4448
|
}
|
|
@@ -5329,99 +4460,280 @@ const defaultFieldComponents = {
|
|
|
5329
4460
|
decorator: "FormItem"
|
|
5330
4461
|
}
|
|
5331
4462
|
};
|
|
5332
|
-
|
|
4463
|
+
const AUTO_CRUD_DATA_SOURCE_SCOPE_KEY = "$autoCrudDataSource";
|
|
4464
|
+
const POPUP_SCROLL_LOAD_THRESHOLD$1 = 24;
|
|
4465
|
+
const dataSourceReactionStates = /* @__PURE__ */ new WeakMap();
|
|
4466
|
+
function createBoundAction(callback) {
|
|
4467
|
+
return action.bound?.(callback) ?? ((...args) => action(() => callback(...args)));
|
|
4468
|
+
}
|
|
4469
|
+
function useRegistryVersion$1(subscribe, onChange) {
|
|
5333
4470
|
const [version$1, setVersion] = useState(0);
|
|
5334
|
-
useEffect(() => subscribe(() =>
|
|
4471
|
+
useEffect(() => subscribe(() => {
|
|
4472
|
+
onChange?.();
|
|
4473
|
+
setVersion((current) => current + 1);
|
|
4474
|
+
}), [onChange, subscribe]);
|
|
5335
4475
|
return version$1;
|
|
5336
4476
|
}
|
|
5337
4477
|
function isDataSourceConfig(value) {
|
|
5338
4478
|
return typeof value === "string" && value.length > 0;
|
|
5339
4479
|
}
|
|
5340
|
-
function
|
|
4480
|
+
function getSchemaDataSourceConfig(schema) {
|
|
4481
|
+
const customDataSource = schema["x-data-source"];
|
|
4482
|
+
const schemaDataSource = schema.dataSource;
|
|
4483
|
+
return isDataSourceConfig(customDataSource) ? customDataSource : isDataSourceConfig(schemaDataSource) ? schemaDataSource : void 0;
|
|
4484
|
+
}
|
|
4485
|
+
function mergeReactions(existing, reaction) {
|
|
4486
|
+
if (existing == null) return reaction;
|
|
4487
|
+
if (existing === reaction) return existing;
|
|
4488
|
+
if (Array.isArray(existing)) return existing.includes(reaction) ? existing : [...existing, reaction];
|
|
4489
|
+
return [existing, reaction];
|
|
4490
|
+
}
|
|
4491
|
+
function applyDataSourceReactions(schema) {
|
|
4492
|
+
const dataSourceConfig = getSchemaDataSourceConfig(schema);
|
|
4493
|
+
if (dataSourceConfig) {
|
|
4494
|
+
const reaction = `{{${AUTO_CRUD_DATA_SOURCE_SCOPE_KEY}(${JSON.stringify(dataSourceConfig)})}}`;
|
|
4495
|
+
schema["x-reactions"] = mergeReactions(schema["x-reactions"], reaction);
|
|
4496
|
+
}
|
|
5341
4497
|
const properties = schema.properties;
|
|
5342
|
-
if (
|
|
5343
|
-
|
|
5344
|
-
if (!property || typeof property !== "object" || Array.isArray(property)) continue;
|
|
5345
|
-
const record = property;
|
|
5346
|
-
const customDataSource = record["x-data-source"];
|
|
5347
|
-
const schemaDataSource = record.dataSource;
|
|
5348
|
-
const dataSourceConfig = isDataSourceConfig(customDataSource) ? customDataSource : isDataSourceConfig(schemaDataSource) ? schemaDataSource : void 0;
|
|
5349
|
-
if (dataSourceConfig) result[key] = dataSourceConfig;
|
|
5350
|
-
collectDataSourceConfigs(record, result);
|
|
4498
|
+
if (properties && typeof properties === "object" && !Array.isArray(properties)) {
|
|
4499
|
+
for (const property of Object.values(properties)) if (property && typeof property === "object" && !Array.isArray(property)) applyDataSourceReactions(property);
|
|
5351
4500
|
}
|
|
5352
|
-
|
|
4501
|
+
const items = schema.items;
|
|
4502
|
+
if (Array.isArray(items)) {
|
|
4503
|
+
for (const item of items) if (item && typeof item === "object") applyDataSourceReactions(item);
|
|
4504
|
+
} else if (items && typeof items === "object") applyDataSourceReactions(items);
|
|
4505
|
+
}
|
|
4506
|
+
function getDataSourceReactionState(field) {
|
|
4507
|
+
const existing = dataSourceReactionStates.get(field);
|
|
4508
|
+
if (existing) return existing;
|
|
4509
|
+
const next = {
|
|
4510
|
+
hasMore: false,
|
|
4511
|
+
initialized: false,
|
|
4512
|
+
appendLoading: false,
|
|
4513
|
+
options: [],
|
|
4514
|
+
page: 0,
|
|
4515
|
+
requestVersion: 0
|
|
4516
|
+
};
|
|
4517
|
+
dataSourceReactionStates.set(field, next);
|
|
4518
|
+
return next;
|
|
4519
|
+
}
|
|
4520
|
+
function mergeDataSourceOptions(current, incoming) {
|
|
4521
|
+
const optionsByValue = new Map(current.map((option) => [option.value, option]));
|
|
4522
|
+
for (const option of incoming) optionsByValue.set(option.value, option);
|
|
4523
|
+
return Array.from(optionsByValue.values());
|
|
4524
|
+
}
|
|
4525
|
+
function isNearPopupScrollBottom$1(target) {
|
|
4526
|
+
return target.scrollHeight - target.scrollTop - target.clientHeight <= POPUP_SCROLL_LOAD_THRESHOLD$1;
|
|
4527
|
+
}
|
|
4528
|
+
function getDataSourceDependencyValues(entry, field) {
|
|
4529
|
+
return Object.fromEntries(entry.dependencies.map((dependency) => [dependency, field.form.getValuesIn(dependency)]));
|
|
4530
|
+
}
|
|
4531
|
+
function loadAutoCrudDataSource({ entry, field, registryVersion, search, sourceKey, state, append = false }) {
|
|
4532
|
+
const values = getDataSourceDependencyValues(entry, field);
|
|
4533
|
+
const dependencyKey = JSON.stringify(values);
|
|
4534
|
+
const searchValue = entry.search ? search ?? "" : void 0;
|
|
4535
|
+
const page = entry.loadMore ? append ? state.page + 1 : 1 : void 0;
|
|
4536
|
+
const loadKey = JSON.stringify({
|
|
4537
|
+
values,
|
|
4538
|
+
search: searchValue
|
|
4539
|
+
});
|
|
4540
|
+
if (!append && state.loadKey === loadKey && state.registryVersion === registryVersion) return;
|
|
4541
|
+
if (entry.reset && state.dependencyKey !== void 0 && state.dependencyKey !== dependencyKey) field.setValue(void 0);
|
|
4542
|
+
state.dependencyKey = dependencyKey;
|
|
4543
|
+
if (!append) {
|
|
4544
|
+
state.loadKey = loadKey;
|
|
4545
|
+
state.options = [];
|
|
4546
|
+
state.page = 0;
|
|
4547
|
+
state.hasMore = false;
|
|
4548
|
+
}
|
|
4549
|
+
state.registryVersion = registryVersion;
|
|
4550
|
+
state.controller?.abort();
|
|
4551
|
+
const requestVersion = state.requestVersion + 1;
|
|
4552
|
+
state.requestVersion = requestVersion;
|
|
4553
|
+
const controller = typeof AbortController === "undefined" ? void 0 : new AbortController();
|
|
4554
|
+
state.controller = controller;
|
|
4555
|
+
if (append) {
|
|
4556
|
+
state.appendLoading = true;
|
|
4557
|
+
field.setComponentProps({ loading: true });
|
|
4558
|
+
} else {
|
|
4559
|
+
field.setLoading(true);
|
|
4560
|
+
field.setComponentProps({
|
|
4561
|
+
loading: true,
|
|
4562
|
+
...entry.loadMore ? { hasMore: false } : {}
|
|
4563
|
+
});
|
|
4564
|
+
}
|
|
4565
|
+
Promise.resolve(entry.load({
|
|
4566
|
+
field: field.path.toString(),
|
|
4567
|
+
page,
|
|
4568
|
+
pageSize: entry.loadMore ? entry.pageSize : void 0,
|
|
4569
|
+
search: searchValue,
|
|
4570
|
+
values,
|
|
4571
|
+
signal: controller?.signal
|
|
4572
|
+
})).then(createBoundAction((result) => {
|
|
4573
|
+
if (dataSourceReactionStates.get(field)?.requestVersion !== requestVersion || controller?.signal.aborted) return;
|
|
4574
|
+
const options = normalizeOptions(result);
|
|
4575
|
+
const nextOptions = append ? mergeDataSourceOptions(state.options, options) : options;
|
|
4576
|
+
state.options = nextOptions;
|
|
4577
|
+
state.page = page ?? 0;
|
|
4578
|
+
state.hasMore = entry.loadMore ? normalizeHasMore(result) : false;
|
|
4579
|
+
state.appendLoading = false;
|
|
4580
|
+
field.setDataSource(nextOptions);
|
|
4581
|
+
field.setLoading(false);
|
|
4582
|
+
field.setComponentProps({
|
|
4583
|
+
loading: false,
|
|
4584
|
+
...entry.loadMore ? { hasMore: state.hasMore } : {}
|
|
4585
|
+
});
|
|
4586
|
+
}), createBoundAction((error) => {
|
|
4587
|
+
if (dataSourceReactionStates.get(field)?.requestVersion !== requestVersion || controller?.signal.aborted) return;
|
|
4588
|
+
console.warn(`[AutoCrud] Failed to load data source "${sourceKey}".`, error);
|
|
4589
|
+
if (!append) {
|
|
4590
|
+
state.options = [];
|
|
4591
|
+
state.hasMore = false;
|
|
4592
|
+
field.setDataSource([]);
|
|
4593
|
+
}
|
|
4594
|
+
state.appendLoading = false;
|
|
4595
|
+
field.setLoading(false);
|
|
4596
|
+
field.setComponentProps({
|
|
4597
|
+
loading: false,
|
|
4598
|
+
...entry.loadMore ? { hasMore: state.hasMore } : {}
|
|
4599
|
+
});
|
|
4600
|
+
}));
|
|
5353
4601
|
}
|
|
5354
|
-
function
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
}
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
}));
|
|
5381
|
-
if (!active || loadVersions.get(fieldName) !== version$1) return;
|
|
5382
|
-
form.setFieldState(fieldName, (state) => {
|
|
5383
|
-
state.dataSource = options;
|
|
4602
|
+
function applySearchComponentProps({ entry, field, registryState, sourceKey, state }) {
|
|
4603
|
+
if (!entry.search) return;
|
|
4604
|
+
field.setComponentProps({
|
|
4605
|
+
searchValue: state.search ?? "",
|
|
4606
|
+
shouldFilter: false,
|
|
4607
|
+
onSearch: (search) => {
|
|
4608
|
+
if (state.search === search) return;
|
|
4609
|
+
state.search = search;
|
|
4610
|
+
field.setComponentProps({ searchValue: search });
|
|
4611
|
+
if (state.searchTimer) clearTimeout(state.searchTimer);
|
|
4612
|
+
state.searchTimer = setTimeout(() => {
|
|
4613
|
+
const currentEntry = dataSources.get(sourceKey);
|
|
4614
|
+
if (!currentEntry) {
|
|
4615
|
+
state.controller?.abort();
|
|
4616
|
+
field.setDataSource([]);
|
|
4617
|
+
field.setLoading(false);
|
|
4618
|
+
field.setComponentProps({ loading: false });
|
|
4619
|
+
return;
|
|
4620
|
+
}
|
|
4621
|
+
loadAutoCrudDataSource({
|
|
4622
|
+
entry: currentEntry,
|
|
4623
|
+
field,
|
|
4624
|
+
registryVersion: registryState.version,
|
|
4625
|
+
search,
|
|
4626
|
+
sourceKey,
|
|
4627
|
+
state
|
|
5384
4628
|
});
|
|
5385
|
-
}
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
4629
|
+
}, entry.debounceMs);
|
|
4630
|
+
}
|
|
4631
|
+
});
|
|
4632
|
+
}
|
|
4633
|
+
function applyLoadMoreComponentProps({ entry, field, registryState, sourceKey, state }) {
|
|
4634
|
+
if (!entry.loadMore) return;
|
|
4635
|
+
field.setComponentProps({
|
|
4636
|
+
hasMore: state.hasMore,
|
|
4637
|
+
loading: state.appendLoading,
|
|
4638
|
+
onPopupScroll: (event) => {
|
|
4639
|
+
if (!isNearPopupScrollBottom$1(event.currentTarget)) return;
|
|
4640
|
+
if (!state.hasMore || state.appendLoading) return;
|
|
4641
|
+
const currentEntry = dataSources.get(sourceKey);
|
|
4642
|
+
if (!currentEntry) {
|
|
4643
|
+
state.controller?.abort();
|
|
4644
|
+
state.hasMore = false;
|
|
4645
|
+
state.appendLoading = false;
|
|
4646
|
+
field.setDataSource([]);
|
|
4647
|
+
field.setLoading(false);
|
|
4648
|
+
field.setComponentProps({
|
|
4649
|
+
hasMore: false,
|
|
4650
|
+
loading: false
|
|
5390
4651
|
});
|
|
4652
|
+
return;
|
|
5391
4653
|
}
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
4654
|
+
loadAutoCrudDataSource({
|
|
4655
|
+
append: true,
|
|
4656
|
+
entry: currentEntry,
|
|
4657
|
+
field,
|
|
4658
|
+
registryVersion: registryState.version,
|
|
4659
|
+
search: state.search,
|
|
4660
|
+
sourceKey,
|
|
4661
|
+
state
|
|
4662
|
+
});
|
|
4663
|
+
}
|
|
4664
|
+
});
|
|
4665
|
+
}
|
|
4666
|
+
function createAutoCrudDataSourceReaction(config, registryState) {
|
|
4667
|
+
const source = normalizeDataSourceConfig(config);
|
|
4668
|
+
return (field) => {
|
|
4669
|
+
const registryVersion = registryState.version;
|
|
4670
|
+
const state = getDataSourceReactionState(field);
|
|
4671
|
+
if (!state.initialized) {
|
|
4672
|
+
field.disposers.push(() => {
|
|
4673
|
+
state.controller?.abort();
|
|
4674
|
+
if (state.searchTimer) clearTimeout(state.searchTimer);
|
|
5402
4675
|
});
|
|
4676
|
+
state.initialized = true;
|
|
4677
|
+
}
|
|
4678
|
+
if (!source) {
|
|
4679
|
+
field.setDataSource([]);
|
|
4680
|
+
field.setLoading(false);
|
|
4681
|
+
return;
|
|
4682
|
+
}
|
|
4683
|
+
const entry = dataSources.get(source.key);
|
|
4684
|
+
if (!entry) {
|
|
4685
|
+
state.controller?.abort();
|
|
4686
|
+
field.setDataSource([]);
|
|
4687
|
+
field.setLoading(false);
|
|
4688
|
+
return;
|
|
4689
|
+
}
|
|
4690
|
+
applySearchComponentProps({
|
|
4691
|
+
entry,
|
|
4692
|
+
field,
|
|
4693
|
+
registryState,
|
|
4694
|
+
sourceKey: source.key,
|
|
4695
|
+
state
|
|
5403
4696
|
});
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
4697
|
+
applyLoadMoreComponentProps({
|
|
4698
|
+
entry,
|
|
4699
|
+
field,
|
|
4700
|
+
registryState,
|
|
4701
|
+
sourceKey: source.key,
|
|
4702
|
+
state
|
|
4703
|
+
});
|
|
4704
|
+
loadAutoCrudDataSource({
|
|
4705
|
+
entry,
|
|
4706
|
+
field,
|
|
4707
|
+
registryVersion,
|
|
4708
|
+
search: state.search,
|
|
4709
|
+
sourceKey: source.key,
|
|
4710
|
+
state
|
|
4711
|
+
});
|
|
4712
|
+
};
|
|
5414
4713
|
}
|
|
5415
|
-
function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, overrides, mode = "create", loading = false, gridColumns = 1, labelAlign = "top", labelWidth, showSubmitButton = true }, ref) {
|
|
4714
|
+
function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, fields, overrides, scope: scopeProp, mode = "create", loading = false, gridColumns = 1, labelAlign = "top", labelWidth, showSubmitButton = true }, ref) {
|
|
5416
4715
|
const form = useMemo(() => createForm({ initialValues }), [JSON.stringify(initialValues)]);
|
|
5417
|
-
const
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
4716
|
+
const dataSourceRegistryState = useMemo(() => observable({ version: 0 }), []);
|
|
4717
|
+
const updateDataSourceRegistryState = useCallback(() => {
|
|
4718
|
+
action(() => {
|
|
4719
|
+
dataSourceRegistryState.version += 1;
|
|
4720
|
+
});
|
|
4721
|
+
}, [dataSourceRegistryState]);
|
|
4722
|
+
const dataSourceRegistryVersion = useRegistryVersion$1(dataSources.subscribe, updateDataSourceRegistryState);
|
|
4723
|
+
const formOverrides = useMemo(() => buildFormOverrides(fields, overrides), [fields, overrides]);
|
|
4724
|
+
const formSchema = useMemo(() => {
|
|
4725
|
+
const nextSchema = createEditFormSchema(zodSchema, {
|
|
4726
|
+
overrides: formOverrides,
|
|
4727
|
+
layout: "grid",
|
|
4728
|
+
gridColumns
|
|
4729
|
+
});
|
|
4730
|
+
applyDataSourceReactions(nextSchema);
|
|
4731
|
+
return nextSchema;
|
|
4732
|
+
}, [
|
|
5422
4733
|
zodSchema,
|
|
5423
|
-
|
|
5424
|
-
gridColumns
|
|
4734
|
+
formOverrides,
|
|
4735
|
+
gridColumns,
|
|
4736
|
+
dataSourceRegistryVersion
|
|
5425
4737
|
]);
|
|
5426
4738
|
const formLayout = useMemo(() => {
|
|
5427
4739
|
const inlineLabel = labelAlign === "left" || labelAlign === "right";
|
|
@@ -5437,7 +4749,10 @@ function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, overrides,
|
|
|
5437
4749
|
...defaultFieldComponents,
|
|
5438
4750
|
...components.all()
|
|
5439
4751
|
} }), [useRegistryVersion$1(components.subscribe)]);
|
|
5440
|
-
|
|
4752
|
+
const scope = useMemo(() => ({
|
|
4753
|
+
...scopeProp,
|
|
4754
|
+
[AUTO_CRUD_DATA_SOURCE_SCOPE_KEY]: (config) => createAutoCrudDataSourceReaction(config, dataSourceRegistryState)
|
|
4755
|
+
}), [dataSourceRegistryState, scopeProp]);
|
|
5441
4756
|
const handleSubmit = async () => {
|
|
5442
4757
|
await form.validate();
|
|
5443
4758
|
if (form.valid) await onSubmit(form.values);
|
|
@@ -5448,7 +4763,8 @@ function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, overrides,
|
|
|
5448
4763
|
layout: formLayout,
|
|
5449
4764
|
children: [/* @__PURE__ */ jsx(JsonSchemaField, {
|
|
5450
4765
|
schema: formSchema,
|
|
5451
|
-
components: fieldComponents
|
|
4766
|
+
components: fieldComponents,
|
|
4767
|
+
scope
|
|
5452
4768
|
}), showSubmitButton && /* @__PURE__ */ jsx("div", {
|
|
5453
4769
|
className: "flex justify-end gap-2 mt-6",
|
|
5454
4770
|
children: /* @__PURE__ */ jsx(Button, {
|
|
@@ -5466,6 +4782,7 @@ const AutoForm = forwardRef(AutoFormInner);
|
|
|
5466
4782
|
//#region src/i18n/locale.ts
|
|
5467
4783
|
const zhCN = {
|
|
5468
4784
|
toolbar: {
|
|
4785
|
+
refresh: "刷新",
|
|
5469
4786
|
create: "新建",
|
|
5470
4787
|
import: "导入",
|
|
5471
4788
|
export: "导出",
|
|
@@ -5497,6 +4814,12 @@ const zhCN = {
|
|
|
5497
4814
|
confirm: "确认删除",
|
|
5498
4815
|
confirming: "删除中..."
|
|
5499
4816
|
},
|
|
4817
|
+
bulkDeleteModal: {
|
|
4818
|
+
title: "确认批量删除",
|
|
4819
|
+
description: (count) => `此操作无法撤销。确定要删除选中的 ${count} 条记录吗?`,
|
|
4820
|
+
cancel: "取消",
|
|
4821
|
+
confirm: "确认删除"
|
|
4822
|
+
},
|
|
5500
4823
|
importDialog: {
|
|
5501
4824
|
title: "导入数据",
|
|
5502
4825
|
uploadDescription: "上传 CSV 或 JSON 文件以批量导入数据",
|
|
@@ -5526,6 +4849,7 @@ const zhCN = {
|
|
|
5526
4849
|
};
|
|
5527
4850
|
const enUS = {
|
|
5528
4851
|
toolbar: {
|
|
4852
|
+
refresh: "Refresh",
|
|
5529
4853
|
create: "New",
|
|
5530
4854
|
import: "Import",
|
|
5531
4855
|
export: "Export",
|
|
@@ -5557,6 +4881,12 @@ const enUS = {
|
|
|
5557
4881
|
confirm: "Delete",
|
|
5558
4882
|
confirming: "Deleting..."
|
|
5559
4883
|
},
|
|
4884
|
+
bulkDeleteModal: {
|
|
4885
|
+
title: "Confirm Bulk Delete",
|
|
4886
|
+
description: (count) => `This action cannot be undone. Are you sure you want to delete ${count} selected ${count === 1 ? "record" : "records"}?`,
|
|
4887
|
+
cancel: "Cancel",
|
|
4888
|
+
confirm: "Delete"
|
|
4889
|
+
},
|
|
5560
4890
|
importDialog: {
|
|
5561
4891
|
title: "Import Data",
|
|
5562
4892
|
uploadDescription: "Upload a CSV or JSON file to bulk import data",
|
|
@@ -5586,6 +4916,7 @@ const enUS = {
|
|
|
5586
4916
|
};
|
|
5587
4917
|
const jaJP = {
|
|
5588
4918
|
toolbar: {
|
|
4919
|
+
refresh: "更新",
|
|
5589
4920
|
create: "新規作成",
|
|
5590
4921
|
import: "インポート",
|
|
5591
4922
|
export: "エクスポート",
|
|
@@ -5617,6 +4948,12 @@ const jaJP = {
|
|
|
5617
4948
|
confirm: "削除する",
|
|
5618
4949
|
confirming: "削除中..."
|
|
5619
4950
|
},
|
|
4951
|
+
bulkDeleteModal: {
|
|
4952
|
+
title: "一括削除の確認",
|
|
4953
|
+
description: (count) => `この操作は元に戻せません。選択した${count}件のレコードを削除してもよろしいですか?`,
|
|
4954
|
+
cancel: "キャンセル",
|
|
4955
|
+
confirm: "削除する"
|
|
4956
|
+
},
|
|
5620
4957
|
importDialog: {
|
|
5621
4958
|
title: "データのインポート",
|
|
5622
4959
|
uploadDescription: "CSVまたはJSONファイルをアップロードして一括インポート",
|
|
@@ -5646,6 +4983,7 @@ const jaJP = {
|
|
|
5646
4983
|
};
|
|
5647
4984
|
const koKR = {
|
|
5648
4985
|
toolbar: {
|
|
4986
|
+
refresh: "새로고침",
|
|
5649
4987
|
create: "새로 만들기",
|
|
5650
4988
|
import: "가져오기",
|
|
5651
4989
|
export: "내보내기",
|
|
@@ -5677,6 +5015,12 @@ const koKR = {
|
|
|
5677
5015
|
confirm: "삭제",
|
|
5678
5016
|
confirming: "삭제 중..."
|
|
5679
5017
|
},
|
|
5018
|
+
bulkDeleteModal: {
|
|
5019
|
+
title: "일괄 삭제 확인",
|
|
5020
|
+
description: (count) => `이 작업은 취소할 수 없습니다. 선택한 ${count}개 레코드를 삭제하시겠습니까?`,
|
|
5021
|
+
cancel: "취소",
|
|
5022
|
+
confirm: "삭제"
|
|
5023
|
+
},
|
|
5680
5024
|
importDialog: {
|
|
5681
5025
|
title: "데이터 가져오기",
|
|
5682
5026
|
uploadDescription: "CSV 또는 JSON 파일을 업로드하여 일괄 가져오기",
|
|
@@ -5706,6 +5050,7 @@ const koKR = {
|
|
|
5706
5050
|
};
|
|
5707
5051
|
const frFR = {
|
|
5708
5052
|
toolbar: {
|
|
5053
|
+
refresh: "Actualiser",
|
|
5709
5054
|
create: "Nouveau",
|
|
5710
5055
|
import: "Importer",
|
|
5711
5056
|
export: "Exporter",
|
|
@@ -5737,6 +5082,12 @@ const frFR = {
|
|
|
5737
5082
|
confirm: "Supprimer",
|
|
5738
5083
|
confirming: "Suppression..."
|
|
5739
5084
|
},
|
|
5085
|
+
bulkDeleteModal: {
|
|
5086
|
+
title: "Confirmer la suppression en masse",
|
|
5087
|
+
description: (count) => `Cette action est irréversible. Voulez-vous vraiment supprimer les ${count} enregistrements sélectionnés ?`,
|
|
5088
|
+
cancel: "Annuler",
|
|
5089
|
+
confirm: "Supprimer"
|
|
5090
|
+
},
|
|
5740
5091
|
importDialog: {
|
|
5741
5092
|
title: "Importer des données",
|
|
5742
5093
|
uploadDescription: "Téléchargez un fichier CSV ou JSON pour importer en masse",
|
|
@@ -5766,6 +5117,7 @@ const frFR = {
|
|
|
5766
5117
|
};
|
|
5767
5118
|
const deDE = {
|
|
5768
5119
|
toolbar: {
|
|
5120
|
+
refresh: "Aktualisieren",
|
|
5769
5121
|
create: "Neu",
|
|
5770
5122
|
import: "Importieren",
|
|
5771
5123
|
export: "Exportieren",
|
|
@@ -5797,6 +5149,12 @@ const deDE = {
|
|
|
5797
5149
|
confirm: "Löschen",
|
|
5798
5150
|
confirming: "Wird gelöscht..."
|
|
5799
5151
|
},
|
|
5152
|
+
bulkDeleteModal: {
|
|
5153
|
+
title: "Mehrfaches Löschen bestätigen",
|
|
5154
|
+
description: (count) => `Diese Aktion kann nicht rückgängig gemacht werden. Möchten Sie die ${count} ausgewählten Datensätze wirklich löschen?`,
|
|
5155
|
+
cancel: "Abbrechen",
|
|
5156
|
+
confirm: "Löschen"
|
|
5157
|
+
},
|
|
5800
5158
|
importDialog: {
|
|
5801
5159
|
title: "Daten importieren",
|
|
5802
5160
|
uploadDescription: "CSV- oder JSON-Datei hochladen, um Daten massenweise zu importieren",
|
|
@@ -5826,6 +5184,7 @@ const deDE = {
|
|
|
5826
5184
|
};
|
|
5827
5185
|
const esES = {
|
|
5828
5186
|
toolbar: {
|
|
5187
|
+
refresh: "Actualizar",
|
|
5829
5188
|
create: "Nuevo",
|
|
5830
5189
|
import: "Importar",
|
|
5831
5190
|
export: "Exportar",
|
|
@@ -5857,6 +5216,12 @@ const esES = {
|
|
|
5857
5216
|
confirm: "Eliminar",
|
|
5858
5217
|
confirming: "Eliminando..."
|
|
5859
5218
|
},
|
|
5219
|
+
bulkDeleteModal: {
|
|
5220
|
+
title: "Confirmar eliminación masiva",
|
|
5221
|
+
description: (count) => `Esta acción no se puede deshacer. ¿Está seguro de que desea eliminar los ${count} registros seleccionados?`,
|
|
5222
|
+
cancel: "Cancelar",
|
|
5223
|
+
confirm: "Eliminar"
|
|
5224
|
+
},
|
|
5860
5225
|
importDialog: {
|
|
5861
5226
|
title: "Importar datos",
|
|
5862
5227
|
uploadDescription: "Suba un archivo CSV o JSON para importar datos de forma masiva",
|
|
@@ -5916,7 +5281,7 @@ function resolveLocale(localeProp) {
|
|
|
5916
5281
|
|
|
5917
5282
|
//#endregion
|
|
5918
5283
|
//#region src/components/auto-crud/crud-form-modal.tsx
|
|
5919
|
-
function CrudFormModal({ open, onOpenChange, mode, schema, initialValues, onSubmit, loading = false, variant = "dialog", overrides, title, locale = zhCN.formModal, gridColumns, labelAlign, labelWidth, className }) {
|
|
5284
|
+
function CrudFormModal({ open, onOpenChange, mode, schema, initialValues, onSubmit, loading = false, variant = "dialog", overrides, scope, title, locale = zhCN.formModal, gridColumns, labelAlign, labelWidth, className }) {
|
|
5920
5285
|
const defaultTitle = mode === "create" ? locale.createTitle : locale.editTitle;
|
|
5921
5286
|
const formRef = useRef(null);
|
|
5922
5287
|
const handleSubmit = async () => {
|
|
@@ -5950,6 +5315,7 @@ function CrudFormModal({ open, onOpenChange, mode, schema, initialValues, onSubm
|
|
|
5950
5315
|
loading,
|
|
5951
5316
|
onSubmit,
|
|
5952
5317
|
overrides,
|
|
5318
|
+
scope,
|
|
5953
5319
|
gridColumns,
|
|
5954
5320
|
labelAlign,
|
|
5955
5321
|
labelWidth,
|
|
@@ -6028,7 +5394,7 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title, local
|
|
|
6028
5394
|
open,
|
|
6029
5395
|
onOpenChange: handleOpenChange,
|
|
6030
5396
|
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
6031
|
-
className: "sm:max-w-
|
|
5397
|
+
className: "w-[calc(100vw-2rem)] sm:max-w-5xl",
|
|
6032
5398
|
children: [/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: title ?? locale.title }), /* @__PURE__ */ jsxs(DialogDescription, { children: [
|
|
6033
5399
|
step === "upload" && locale.uploadDescription,
|
|
6034
5400
|
step === "preview" && locale.previewDescription(parsedData?.rows.length ?? 0),
|
|
@@ -6089,41 +5455,30 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title, local
|
|
|
6089
5455
|
/* @__PURE__ */ jsx("div", {
|
|
6090
5456
|
className: "rounded-md border",
|
|
6091
5457
|
children: /* @__PURE__ */ jsx("div", {
|
|
6092
|
-
className: "max-h-[
|
|
5458
|
+
className: "max-h-[45vh] overflow-auto",
|
|
6093
5459
|
children: /* @__PURE__ */ jsxs("table", {
|
|
6094
|
-
className: "w-
|
|
5460
|
+
className: "min-w-max text-sm",
|
|
6095
5461
|
children: [/* @__PURE__ */ jsx("thead", {
|
|
6096
5462
|
className: "sticky top-0 bg-muted",
|
|
6097
|
-
children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
children: h
|
|
6105
|
-
}, h)),
|
|
6106
|
-
parsedData.headers.length > 6 && /* @__PURE__ */ jsx("th", {
|
|
6107
|
-
className: "px-3 py-2 text-left font-medium text-muted-foreground",
|
|
6108
|
-
children: locale.moreColumns(parsedData.headers.length - 6)
|
|
6109
|
-
})
|
|
6110
|
-
] })
|
|
5463
|
+
children: /* @__PURE__ */ jsxs("tr", { children: [/* @__PURE__ */ jsx("th", {
|
|
5464
|
+
className: "sticky left-0 z-10 bg-muted px-3 py-2 text-left font-medium text-muted-foreground",
|
|
5465
|
+
children: "#"
|
|
5466
|
+
}), parsedData.headers.map((h) => /* @__PURE__ */ jsx("th", {
|
|
5467
|
+
className: "max-w-[180px] whitespace-nowrap px-3 py-2 text-left font-medium text-muted-foreground",
|
|
5468
|
+
children: h
|
|
5469
|
+
}, h))] })
|
|
6111
5470
|
}), /* @__PURE__ */ jsx("tbody", { children: parsedData.rows.slice(0, 10).map((row, i) => /* @__PURE__ */ jsxs("tr", {
|
|
6112
5471
|
className: "border-t",
|
|
6113
|
-
children: [
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
5472
|
+
children: [/* @__PURE__ */ jsx("td", {
|
|
5473
|
+
className: "sticky left-0 bg-background px-3 py-2 text-muted-foreground",
|
|
5474
|
+
children: i + 1
|
|
5475
|
+
}), parsedData.headers.map((h) => /* @__PURE__ */ jsx("td", {
|
|
5476
|
+
className: "max-w-[180px] truncate px-3 py-2",
|
|
5477
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
5478
|
+
title: String(row[h] ?? ""),
|
|
6120
5479
|
children: String(row[h] ?? "")
|
|
6121
|
-
}, h)),
|
|
6122
|
-
parsedData.headers.length > 6 && /* @__PURE__ */ jsx("td", {
|
|
6123
|
-
className: "px-3 py-2 text-muted-foreground",
|
|
6124
|
-
children: "..."
|
|
6125
5480
|
})
|
|
6126
|
-
]
|
|
5481
|
+
}, h))]
|
|
6127
5482
|
}, i)) })]
|
|
6128
5483
|
})
|
|
6129
5484
|
})
|
|
@@ -6255,12 +5610,12 @@ const listeners = /* @__PURE__ */ new Set();
|
|
|
6255
5610
|
let seq = 0;
|
|
6256
5611
|
let version = 0;
|
|
6257
5612
|
let notifyScheduled = false;
|
|
6258
|
-
function actionKey(registration, action, index$1) {
|
|
5613
|
+
function actionKey(registration, action$1, index$1) {
|
|
6259
5614
|
return [
|
|
6260
5615
|
registration.ownerId,
|
|
6261
5616
|
registration.targetId,
|
|
6262
5617
|
registration.zone,
|
|
6263
|
-
action.id ?? action.type,
|
|
5618
|
+
action$1.id ?? action$1.type,
|
|
6264
5619
|
index$1
|
|
6265
5620
|
].join(":");
|
|
6266
5621
|
}
|
|
@@ -6308,15 +5663,15 @@ function sortEntries(left, right) {
|
|
|
6308
5663
|
if (ownerDiff !== 0) return ownerDiff;
|
|
6309
5664
|
return left.seq - right.seq;
|
|
6310
5665
|
}
|
|
6311
|
-
function withoutRegistryMeta(action) {
|
|
6312
|
-
const { id, order,...rest } = action;
|
|
5666
|
+
function withoutRegistryMeta(action$1) {
|
|
5667
|
+
const { id, order,...rest } = action$1;
|
|
6313
5668
|
return rest;
|
|
6314
5669
|
}
|
|
6315
|
-
function isCustomAction$1(action) {
|
|
6316
|
-
return action.type === "custom";
|
|
5670
|
+
function isCustomAction$1(action$1) {
|
|
5671
|
+
return action$1.type === "custom";
|
|
6317
5672
|
}
|
|
6318
5673
|
function resolveActions$1(targetId, zone, ownerActions) {
|
|
6319
|
-
const baseActions = ownerActions.filter((action) => !action.hidden).map((action) => withoutRegistryMeta(action));
|
|
5674
|
+
const baseActions = ownerActions.filter((action$1) => !action$1.hidden).map((action$1) => withoutRegistryMeta(action$1));
|
|
6320
5675
|
if (!targetId) return baseActions;
|
|
6321
5676
|
const registered = crudActions.get(targetId, zone);
|
|
6322
5677
|
if (registered.length === 0) return baseActions;
|
|
@@ -6324,20 +5679,20 @@ function resolveActions$1(targetId, zone, ownerActions) {
|
|
|
6324
5679
|
const startCustomActions = [];
|
|
6325
5680
|
const endCustomActions = [];
|
|
6326
5681
|
for (const entry of registered) {
|
|
6327
|
-
const action = entry.action;
|
|
6328
|
-
if (action.hidden && isCustomAction$1(action)) continue;
|
|
6329
|
-
if (isCustomAction$1(action)) {
|
|
6330
|
-
const custom = withoutRegistryMeta(action);
|
|
5682
|
+
const action$1 = entry.action;
|
|
5683
|
+
if (action$1.hidden && isCustomAction$1(action$1)) continue;
|
|
5684
|
+
if (isCustomAction$1(action$1)) {
|
|
5685
|
+
const custom = withoutRegistryMeta(action$1);
|
|
6331
5686
|
if (custom.position === "start") startCustomActions.push(custom);
|
|
6332
5687
|
else endCustomActions.push(custom);
|
|
6333
5688
|
continue;
|
|
6334
5689
|
}
|
|
6335
|
-
const existingIndex = nextActions.findIndex((item) => item.type === action.type);
|
|
6336
|
-
if (action.hidden) {
|
|
5690
|
+
const existingIndex = nextActions.findIndex((item) => item.type === action$1.type);
|
|
5691
|
+
if (action$1.hidden) {
|
|
6337
5692
|
if (existingIndex >= 0) nextActions.splice(existingIndex, 1);
|
|
6338
5693
|
continue;
|
|
6339
5694
|
}
|
|
6340
|
-
const builtin = withoutRegistryMeta(action);
|
|
5695
|
+
const builtin = withoutRegistryMeta(action$1);
|
|
6341
5696
|
if (existingIndex >= 0) nextActions[existingIndex] = {
|
|
6342
5697
|
...nextActions[existingIndex],
|
|
6343
5698
|
...builtin
|
|
@@ -6356,14 +5711,14 @@ const crudActions = {
|
|
|
6356
5711
|
targetId: registration.targetId,
|
|
6357
5712
|
zone: registration.zone
|
|
6358
5713
|
}, false);
|
|
6359
|
-
registration.actions.forEach((action, index$1) => {
|
|
6360
|
-
const key = actionKey(registration, action, index$1);
|
|
5714
|
+
registration.actions.forEach((action$1, index$1) => {
|
|
5715
|
+
const key = actionKey(registration, action$1, index$1);
|
|
6361
5716
|
const entry = {
|
|
6362
5717
|
targetId: registration.targetId,
|
|
6363
5718
|
zone: registration.zone,
|
|
6364
5719
|
ownerId: registration.ownerId,
|
|
6365
|
-
action,
|
|
6366
|
-
order: action.order ?? 100,
|
|
5720
|
+
action: action$1,
|
|
5721
|
+
order: action$1.order ?? 100,
|
|
6367
5722
|
seq: seq++
|
|
6368
5723
|
};
|
|
6369
5724
|
entries.set(key, entry);
|
|
@@ -6402,6 +5757,7 @@ function setToolbarResolver(resolver) {
|
|
|
6402
5757
|
}
|
|
6403
5758
|
function getDefaultToolbarActions() {
|
|
6404
5759
|
return [
|
|
5760
|
+
{ type: "refresh" },
|
|
6405
5761
|
{ type: "import" },
|
|
6406
5762
|
{ type: "export" },
|
|
6407
5763
|
{ type: "create" }
|
|
@@ -6418,8 +5774,8 @@ function getDefaultRowActions() {
|
|
|
6418
5774
|
function getDefaultBatchActions() {
|
|
6419
5775
|
return [{ type: "batchUpdate" }, { type: "delete" }];
|
|
6420
5776
|
}
|
|
6421
|
-
function isCustomAction(action) {
|
|
6422
|
-
return action.type === "custom";
|
|
5777
|
+
function isCustomAction(action$1) {
|
|
5778
|
+
return action$1.type === "custom";
|
|
6423
5779
|
}
|
|
6424
5780
|
function resolveOwnerActions(config, defaults) {
|
|
6425
5781
|
const resolved = typeof config === "function" ? config([...defaults]) : config;
|
|
@@ -6467,7 +5823,7 @@ function haveSameRowSelection(left, right, idKey) {
|
|
|
6467
5823
|
return left.every((row, index$1) => row === right[index$1]);
|
|
6468
5824
|
}
|
|
6469
5825
|
function readCreateAction(actions) {
|
|
6470
|
-
return actions.find((action) => action.type === "create");
|
|
5826
|
+
return actions.find((action$1) => action$1.type === "create");
|
|
6471
5827
|
}
|
|
6472
5828
|
function resolveToolbarActionsWithResolver(targetId, ownerActions, context) {
|
|
6473
5829
|
const resolver = autoCrudToolbarResolver;
|
|
@@ -6519,6 +5875,15 @@ function toBatchOptions(options) {
|
|
|
6519
5875
|
value
|
|
6520
5876
|
}));
|
|
6521
5877
|
}
|
|
5878
|
+
const POPUP_SCROLL_LOAD_THRESHOLD = 24;
|
|
5879
|
+
function isNearPopupScrollBottom(target) {
|
|
5880
|
+
return target.scrollHeight - target.scrollTop - target.clientHeight <= POPUP_SCROLL_LOAD_THRESHOLD;
|
|
5881
|
+
}
|
|
5882
|
+
function mergeFilterOptions(current, incoming) {
|
|
5883
|
+
const optionsByValue = new Map((current ?? []).map((option) => [option.value, option]));
|
|
5884
|
+
for (const option of incoming) optionsByValue.set(option.value, option);
|
|
5885
|
+
return Array.from(optionsByValue.values());
|
|
5886
|
+
}
|
|
6522
5887
|
function getFilterDataSource(config) {
|
|
6523
5888
|
if (config.filter && typeof config.filter === "object") return config.filter.dataSource ?? config.dataSource;
|
|
6524
5889
|
return config.dataSource;
|
|
@@ -6542,7 +5907,20 @@ function useCrudActionsVersion() {
|
|
|
6542
5907
|
}
|
|
6543
5908
|
function useDynamicFilterOptions(fields) {
|
|
6544
5909
|
const registryVersion = useRegistryVersion(dataSources.subscribe);
|
|
5910
|
+
const [searchValues, setSearchValues] = React.useState({});
|
|
5911
|
+
const [hasMoreByField, setHasMoreByField] = React.useState({});
|
|
5912
|
+
const [labelOptionsByField, setLabelOptionsByField] = React.useState({});
|
|
5913
|
+
const [loadingByField, setLoadingByField] = React.useState({});
|
|
6545
5914
|
const [optionsByField, setOptionsByField] = React.useState({});
|
|
5915
|
+
const controllersRef = React.useRef({});
|
|
5916
|
+
const hasMoreByFieldRef = React.useRef({});
|
|
5917
|
+
const loadingByFieldRef = React.useRef({});
|
|
5918
|
+
const optionsByFieldRef = React.useRef({});
|
|
5919
|
+
const pageByFieldRef = React.useRef({});
|
|
5920
|
+
const requestVersionsRef = React.useRef({});
|
|
5921
|
+
const searchValuesRef = React.useRef({});
|
|
5922
|
+
const sourceEntriesByFieldRef = React.useRef({});
|
|
5923
|
+
const timersRef = React.useRef({});
|
|
6546
5924
|
const sourceEntries = React.useMemo(() => {
|
|
6547
5925
|
if (!fields) return [];
|
|
6548
5926
|
return Object.entries(fields).flatMap(([field, config]) => {
|
|
@@ -6554,36 +5932,185 @@ function useDynamicFilterOptions(fields) {
|
|
|
6554
5932
|
}] : [];
|
|
6555
5933
|
});
|
|
6556
5934
|
}, [fields]);
|
|
5935
|
+
const sourceEntriesByField = React.useMemo(() => Object.fromEntries(sourceEntries.map(({ field, source }) => [field, source])), [sourceEntries]);
|
|
6557
5936
|
React.useEffect(() => {
|
|
6558
|
-
|
|
6559
|
-
|
|
5937
|
+
searchValuesRef.current = searchValues;
|
|
5938
|
+
}, [searchValues]);
|
|
5939
|
+
React.useEffect(() => {
|
|
5940
|
+
sourceEntriesByFieldRef.current = sourceEntriesByField;
|
|
5941
|
+
}, [sourceEntriesByField]);
|
|
5942
|
+
const registeredByField = React.useMemo(() => Object.fromEntries(sourceEntries.map(({ field, source }) => [field, dataSources.get(source.key) !== void 0])), [sourceEntries, registryVersion]);
|
|
5943
|
+
const searchableByField = React.useMemo(() => Object.fromEntries(sourceEntries.map(({ field, source }) => [field, dataSources.get(source.key)?.search === true])), [sourceEntries, registryVersion]);
|
|
5944
|
+
const setFieldState = React.useCallback((setter, ref, field, value) => {
|
|
5945
|
+
ref.current = {
|
|
5946
|
+
...ref.current,
|
|
5947
|
+
[field]: value
|
|
5948
|
+
};
|
|
5949
|
+
setter(ref.current);
|
|
5950
|
+
}, []);
|
|
5951
|
+
const removeInactiveFieldState = React.useCallback((setter, ref, activeFields) => {
|
|
5952
|
+
const nextEntries = Object.entries(ref.current).filter(([field]) => activeFields.has(field));
|
|
5953
|
+
if (nextEntries.length === Object.keys(ref.current).length) return;
|
|
5954
|
+
ref.current = Object.fromEntries(nextEntries);
|
|
5955
|
+
setter(ref.current);
|
|
5956
|
+
}, []);
|
|
5957
|
+
const setFieldOptions = React.useCallback((field, options) => {
|
|
5958
|
+
optionsByFieldRef.current = {
|
|
5959
|
+
...optionsByFieldRef.current,
|
|
5960
|
+
[field]: options
|
|
5961
|
+
};
|
|
5962
|
+
setOptionsByField(optionsByFieldRef.current);
|
|
5963
|
+
}, []);
|
|
5964
|
+
const setFieldLoading = React.useCallback((field, loading) => {
|
|
5965
|
+
setFieldState(setLoadingByField, loadingByFieldRef, field, loading);
|
|
5966
|
+
}, [setFieldState]);
|
|
5967
|
+
const setFieldHasMore = React.useCallback((field, hasMore) => {
|
|
5968
|
+
setFieldState(setHasMoreByField, hasMoreByFieldRef, field, hasMore);
|
|
5969
|
+
}, [setFieldState]);
|
|
5970
|
+
const clearFieldRequest = React.useCallback((field) => {
|
|
5971
|
+
const timer = timersRef.current[field];
|
|
5972
|
+
if (timer) clearTimeout(timer);
|
|
5973
|
+
timersRef.current[field] = void 0;
|
|
5974
|
+
controllersRef.current[field]?.abort();
|
|
5975
|
+
controllersRef.current[field] = void 0;
|
|
5976
|
+
}, []);
|
|
5977
|
+
const resetField = React.useCallback((field, { clearLabels = false } = {}) => {
|
|
5978
|
+
clearFieldRequest(field);
|
|
5979
|
+
setFieldOptions(field, []);
|
|
5980
|
+
setFieldLoading(field, false);
|
|
5981
|
+
setFieldHasMore(field, false);
|
|
5982
|
+
pageByFieldRef.current = {
|
|
5983
|
+
...pageByFieldRef.current,
|
|
5984
|
+
[field]: 0
|
|
5985
|
+
};
|
|
5986
|
+
if (clearLabels) setLabelOptionsByField((current) => {
|
|
5987
|
+
const { [field]: _,...rest } = current;
|
|
5988
|
+
return rest;
|
|
5989
|
+
});
|
|
5990
|
+
}, [
|
|
5991
|
+
clearFieldRequest,
|
|
5992
|
+
setFieldHasMore,
|
|
5993
|
+
setFieldLoading,
|
|
5994
|
+
setFieldOptions
|
|
5995
|
+
]);
|
|
5996
|
+
const loadFieldOptions = React.useCallback((field, append = false) => {
|
|
5997
|
+
if (append) {
|
|
5998
|
+
if (loadingByFieldRef.current[field] || !hasMoreByFieldRef.current[field]) return;
|
|
5999
|
+
}
|
|
6000
|
+
const source = sourceEntriesByFieldRef.current[field];
|
|
6001
|
+
const entry = source ? dataSources.get(source.key) : void 0;
|
|
6002
|
+
if (!source || !entry) {
|
|
6003
|
+
resetField(field);
|
|
6560
6004
|
return;
|
|
6561
6005
|
}
|
|
6562
|
-
|
|
6006
|
+
const requestVersion = (requestVersionsRef.current[field] ?? 0) + 1;
|
|
6007
|
+
requestVersionsRef.current = {
|
|
6008
|
+
...requestVersionsRef.current,
|
|
6009
|
+
[field]: requestVersion
|
|
6010
|
+
};
|
|
6011
|
+
clearFieldRequest(field);
|
|
6563
6012
|
const controller = typeof AbortController === "undefined" ? void 0 : new AbortController();
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6013
|
+
controllersRef.current[field] = controller;
|
|
6014
|
+
const search = entry.search ? searchValuesRef.current[field] ?? "" : void 0;
|
|
6015
|
+
const page = entry.loadMore ? append ? (pageByFieldRef.current[field] ?? 0) + 1 : 1 : void 0;
|
|
6016
|
+
setFieldLoading(field, true);
|
|
6017
|
+
if (!append) setFieldHasMore(field, false);
|
|
6018
|
+
const timer = setTimeout(() => {
|
|
6019
|
+
Promise.resolve(entry.load({
|
|
6020
|
+
field,
|
|
6021
|
+
page,
|
|
6022
|
+
pageSize: entry.loadMore ? entry.pageSize : void 0,
|
|
6023
|
+
search,
|
|
6024
|
+
values: {},
|
|
6025
|
+
signal: controller?.signal
|
|
6026
|
+
})).then((result) => {
|
|
6027
|
+
if (requestVersionsRef.current[field] !== requestVersion || controller?.signal.aborted) return;
|
|
6028
|
+
const options = normalizeOptions(result);
|
|
6029
|
+
const nextOptions = append ? mergeFilterOptions(optionsByFieldRef.current[field], options) : options;
|
|
6030
|
+
const hasMore = normalizeHasMore(result);
|
|
6031
|
+
setFieldOptions(field, nextOptions);
|
|
6032
|
+
setLabelOptionsByField((current) => ({
|
|
6033
|
+
...current,
|
|
6034
|
+
[field]: mergeFilterOptions(current[field], nextOptions)
|
|
6035
|
+
}));
|
|
6036
|
+
pageByFieldRef.current = {
|
|
6037
|
+
...pageByFieldRef.current,
|
|
6038
|
+
[field]: page ?? 0
|
|
6039
|
+
};
|
|
6040
|
+
setFieldHasMore(field, hasMore);
|
|
6041
|
+
setFieldLoading(field, false);
|
|
6042
|
+
}, (error) => {
|
|
6043
|
+
if (controller?.signal.aborted) return;
|
|
6044
|
+
console.warn(`[AutoCrud] Failed to load filter data source "${source.key}".`, error);
|
|
6045
|
+
if (!append) {
|
|
6046
|
+
setFieldOptions(field, []);
|
|
6047
|
+
setFieldHasMore(field, false);
|
|
6048
|
+
pageByFieldRef.current = {
|
|
6049
|
+
...pageByFieldRef.current,
|
|
6050
|
+
[field]: 0
|
|
6051
|
+
};
|
|
6052
|
+
}
|
|
6053
|
+
setFieldLoading(field, false);
|
|
6054
|
+
});
|
|
6055
|
+
}, !append && entry.search ? entry.debounceMs : 0);
|
|
6056
|
+
timersRef.current[field] = timer;
|
|
6057
|
+
}, [
|
|
6058
|
+
clearFieldRequest,
|
|
6059
|
+
resetField,
|
|
6060
|
+
setFieldHasMore,
|
|
6061
|
+
setFieldLoading,
|
|
6062
|
+
setFieldOptions
|
|
6063
|
+
]);
|
|
6064
|
+
const setSearchValue = React.useCallback((field, value) => {
|
|
6065
|
+
searchValuesRef.current = {
|
|
6066
|
+
...searchValuesRef.current,
|
|
6067
|
+
[field]: value
|
|
6584
6068
|
};
|
|
6585
|
-
|
|
6586
|
-
|
|
6069
|
+
setSearchValues((current) => current[field] === value ? current : {
|
|
6070
|
+
...current,
|
|
6071
|
+
[field]: value
|
|
6072
|
+
});
|
|
6073
|
+
}, []);
|
|
6074
|
+
React.useEffect(() => {
|
|
6075
|
+
if (sourceEntries.length === 0) {
|
|
6076
|
+
hasMoreByFieldRef.current = {};
|
|
6077
|
+
loadingByFieldRef.current = {};
|
|
6078
|
+
optionsByFieldRef.current = {};
|
|
6079
|
+
pageByFieldRef.current = {};
|
|
6080
|
+
Object.keys(controllersRef.current).forEach(clearFieldRequest);
|
|
6081
|
+
setHasMoreByField({});
|
|
6082
|
+
setLoadingByField({});
|
|
6083
|
+
setOptionsByField({});
|
|
6084
|
+
return;
|
|
6085
|
+
}
|
|
6086
|
+
const activeFields = new Set(sourceEntries.map(({ field }) => field));
|
|
6087
|
+
removeInactiveFieldState(setHasMoreByField, hasMoreByFieldRef, activeFields);
|
|
6088
|
+
removeInactiveFieldState(setLoadingByField, loadingByFieldRef, activeFields);
|
|
6089
|
+
removeInactiveFieldState(setOptionsByField, optionsByFieldRef, activeFields);
|
|
6090
|
+
for (const field of Object.keys(controllersRef.current)) if (!activeFields.has(field)) clearFieldRequest(field);
|
|
6091
|
+
for (const { field } of sourceEntries) loadFieldOptions(field);
|
|
6092
|
+
}, [
|
|
6093
|
+
clearFieldRequest,
|
|
6094
|
+
loadFieldOptions,
|
|
6095
|
+
removeInactiveFieldState,
|
|
6096
|
+
sourceEntries,
|
|
6097
|
+
registryVersion,
|
|
6098
|
+
searchValues
|
|
6099
|
+
]);
|
|
6100
|
+
React.useEffect(() => () => {
|
|
6101
|
+
for (const field of Object.keys(controllersRef.current)) clearFieldRequest(field);
|
|
6102
|
+
}, [clearFieldRequest]);
|
|
6103
|
+
return {
|
|
6104
|
+
hasMoreByField,
|
|
6105
|
+
labelOptionsByField,
|
|
6106
|
+
loadingByField,
|
|
6107
|
+
optionsByField,
|
|
6108
|
+
registeredByField,
|
|
6109
|
+
searchValues,
|
|
6110
|
+
searchableByField,
|
|
6111
|
+
loadMore: (field) => loadFieldOptions(field, true),
|
|
6112
|
+
setSearchValue
|
|
6113
|
+
};
|
|
6587
6114
|
}
|
|
6588
6115
|
function getOptionLabel(value, options) {
|
|
6589
6116
|
const stringValue = String(value);
|
|
@@ -6593,12 +6120,15 @@ function getOptionLabel(value, options) {
|
|
|
6593
6120
|
* 从统一配置生成表格 overrides
|
|
6594
6121
|
* 当 filter 配置存在时,合并到 meta 中(不影响列隐藏)
|
|
6595
6122
|
*/
|
|
6596
|
-
function buildTableOverrides(fields, legacyOverrides,
|
|
6123
|
+
function buildTableOverrides(fields, legacyOverrides, dynamicFilterState) {
|
|
6597
6124
|
const result = { ...legacyOverrides };
|
|
6598
6125
|
if (fields) for (const [key, config] of Object.entries(fields)) {
|
|
6599
6126
|
const fieldOptions = normalizeFieldOptions(config.enum);
|
|
6600
6127
|
const tableOptions = toTableOptions(fieldOptions);
|
|
6601
|
-
const
|
|
6128
|
+
const filterDataSourceRegistered = dynamicFilterState?.registeredByField[key];
|
|
6129
|
+
const filterDataSourceSearchable = dynamicFilterState?.searchableByField[key];
|
|
6130
|
+
const currentDynamicOptions = !fieldOptions && filterDataSourceRegistered ? toTableOptions(dynamicFilterState?.optionsByField[key] ?? []) : void 0;
|
|
6131
|
+
const dynamicOptions = !fieldOptions && filterDataSourceRegistered ? toTableOptions(dynamicFilterState?.labelOptionsByField[key] ?? dynamicFilterState?.optionsByField[key] ?? []) : void 0;
|
|
6602
6132
|
const tableMeta = config.table !== false && typeof config.table === "object" ? config.table.meta : void 0;
|
|
6603
6133
|
const fieldEnumMeta = tableOptions ? {
|
|
6604
6134
|
options: tableOptions,
|
|
@@ -6606,7 +6136,19 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterOptions) {
|
|
|
6606
6136
|
} : void 0;
|
|
6607
6137
|
const fieldDataSourceMeta = dynamicOptions ? {
|
|
6608
6138
|
options: dynamicOptions,
|
|
6609
|
-
|
|
6139
|
+
autoCrudFilterOptions: currentDynamicOptions ?? dynamicOptions,
|
|
6140
|
+
autoCrudFilterHasMore: dynamicFilterState?.hasMoreByField[key] ?? false,
|
|
6141
|
+
autoCrudFilterLoading: dynamicFilterState?.loadingByField[key] ?? false,
|
|
6142
|
+
autoCrudFilterOnPopupScroll: (event) => {
|
|
6143
|
+
if (!isNearPopupScrollBottom(event.currentTarget)) return;
|
|
6144
|
+
dynamicFilterState?.loadMore(key);
|
|
6145
|
+
},
|
|
6146
|
+
variant: "multiSelect",
|
|
6147
|
+
...filterDataSourceSearchable ? {
|
|
6148
|
+
autoCrudFilterSearchValue: dynamicFilterState?.searchValues[key] ?? "",
|
|
6149
|
+
autoCrudFilterOnSearch: (value) => dynamicFilterState?.setSearchValue(key, value),
|
|
6150
|
+
autoCrudFilterShouldFilter: false
|
|
6151
|
+
} : void 0
|
|
6610
6152
|
} : void 0;
|
|
6611
6153
|
let filterMeta;
|
|
6612
6154
|
if (config.filter && typeof config.filter === "object") {
|
|
@@ -6658,46 +6200,6 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterOptions) {
|
|
|
6658
6200
|
return result;
|
|
6659
6201
|
}
|
|
6660
6202
|
/**
|
|
6661
|
-
* 从统一配置生成表单 overrides
|
|
6662
|
-
* Critical #2: 支持 denyFields 隐藏敏感字段
|
|
6663
|
-
*/
|
|
6664
|
-
function buildFormOverrides(fields, legacyOverrides, denyFields) {
|
|
6665
|
-
const result = { ...legacyOverrides };
|
|
6666
|
-
if (denyFields) for (const field of denyFields) result[field] = {
|
|
6667
|
-
...result[field],
|
|
6668
|
-
"x-hidden": true
|
|
6669
|
-
};
|
|
6670
|
-
if (fields) for (const [key, config] of Object.entries(fields)) {
|
|
6671
|
-
const fieldOptions = normalizeFieldOptions((config.form && typeof config.form === "object" ? config.form : void 0)?.enum) ?? normalizeFieldOptions(config.enum);
|
|
6672
|
-
const fieldDataSource = fieldOptions || !config.dataSource ? void 0 : normalizeDataSourceConfig(config.dataSource);
|
|
6673
|
-
if (config.label) result[key] = {
|
|
6674
|
-
...result[key],
|
|
6675
|
-
title: config.label
|
|
6676
|
-
};
|
|
6677
|
-
if (config.hidden) result[key] = {
|
|
6678
|
-
...result[key],
|
|
6679
|
-
"x-hidden": true
|
|
6680
|
-
};
|
|
6681
|
-
if (fieldOptions) result[key] = {
|
|
6682
|
-
...result[key],
|
|
6683
|
-
enum: fieldOptions
|
|
6684
|
-
};
|
|
6685
|
-
if (fieldDataSource) result[key] = {
|
|
6686
|
-
...result[key],
|
|
6687
|
-
"x-data-source": config.dataSource
|
|
6688
|
-
};
|
|
6689
|
-
if (config.form === false) result[key] = {
|
|
6690
|
-
...result[key],
|
|
6691
|
-
"x-hidden": true
|
|
6692
|
-
};
|
|
6693
|
-
else if (config.form && typeof config.form === "object") result[key] = {
|
|
6694
|
-
...result[key],
|
|
6695
|
-
...config.form
|
|
6696
|
-
};
|
|
6697
|
-
}
|
|
6698
|
-
return result;
|
|
6699
|
-
}
|
|
6700
|
-
/**
|
|
6701
6203
|
* 从统一配置生成隐藏列列表
|
|
6702
6204
|
*/
|
|
6703
6205
|
function buildHiddenColumns(fields, legacyHidden, denyFields) {
|
|
@@ -7004,6 +6506,8 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
7004
6506
|
rowIds,
|
|
7005
6507
|
selectedRowIds,
|
|
7006
6508
|
selectedCount,
|
|
6509
|
+
isRefreshing: resource.tableData.isFetching,
|
|
6510
|
+
...resource.handlers.refresh ? { refresh: resource.handlers.refresh } : {},
|
|
7007
6511
|
...toolbarOpenCreate ? { openCreate: toolbarOpenCreate } : {}
|
|
7008
6512
|
}), [
|
|
7009
6513
|
id,
|
|
@@ -7011,6 +6515,8 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
7011
6515
|
rowIds,
|
|
7012
6516
|
selectedRowIds,
|
|
7013
6517
|
selectedCount,
|
|
6518
|
+
resource.handlers.refresh,
|
|
6519
|
+
resource.tableData.isFetching,
|
|
7014
6520
|
toolbarOpenCreate
|
|
7015
6521
|
]);
|
|
7016
6522
|
const resolvedToolbarActions = resolveToolbarActionsWithResolver(id, registryToolbarActions, toolbarContext);
|
|
@@ -7124,6 +6630,17 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
7124
6630
|
className: "flex items-center justify-end gap-4",
|
|
7125
6631
|
children: (() => {
|
|
7126
6632
|
const renderBuiltinButton = (type, overrides) => {
|
|
6633
|
+
if (type === "refresh") {
|
|
6634
|
+
const onRefresh = overrides?.onClick ?? resource.handlers.refresh;
|
|
6635
|
+
if (!onRefresh) return null;
|
|
6636
|
+
return /* @__PURE__ */ jsxs(Button, {
|
|
6637
|
+
variant: "outline",
|
|
6638
|
+
size: "sm",
|
|
6639
|
+
onClick: onRefresh,
|
|
6640
|
+
disabled: resource.tableData.isFetching,
|
|
6641
|
+
children: [/* @__PURE__ */ jsx(RefreshCw, { className: resource.tableData.isFetching ? "mr-2 h-4 w-4 animate-spin" : "mr-2 h-4 w-4" }), overrides?.label ?? locale.toolbar.refresh]
|
|
6642
|
+
}, "refresh");
|
|
6643
|
+
}
|
|
7127
6644
|
if (type === "import" && canImport) return /* @__PURE__ */ jsxs(Button, {
|
|
7128
6645
|
variant: "outline",
|
|
7129
6646
|
size: "sm",
|
|
@@ -7152,6 +6669,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
7152
6669
|
className: "flex items-center gap-2",
|
|
7153
6670
|
children: [
|
|
7154
6671
|
startNodes,
|
|
6672
|
+
renderBuiltinButton("refresh"),
|
|
7155
6673
|
renderBuiltinButton("import"),
|
|
7156
6674
|
renderBuiltinButton("export"),
|
|
7157
6675
|
renderBuiltinButton("create"),
|
|
@@ -7161,13 +6679,20 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
7161
6679
|
}
|
|
7162
6680
|
return /* @__PURE__ */ jsx("div", {
|
|
7163
6681
|
className: "flex items-center gap-2",
|
|
7164
|
-
children: resolvedToolbarActions.map((action, index$1) => {
|
|
7165
|
-
if (action.type === "custom") return /* @__PURE__ */ jsx(React.Fragment, { children: renderToolbarComponent(action.component) }, `custom-${index$1}`);
|
|
7166
|
-
if (!(
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
6682
|
+
children: resolvedToolbarActions.map((action$1, index$1) => {
|
|
6683
|
+
if (action$1.type === "custom") return /* @__PURE__ */ jsx(React.Fragment, { children: renderToolbarComponent(action$1.component) }, `custom-${index$1}`);
|
|
6684
|
+
if (!(() => {
|
|
6685
|
+
switch (action$1.type) {
|
|
6686
|
+
case "refresh": return !!(resource.handlers.refresh || action$1.onClick || action$1.component);
|
|
6687
|
+
case "import": return canImport;
|
|
6688
|
+
case "export": return canExport;
|
|
6689
|
+
case "create": return can.create;
|
|
6690
|
+
}
|
|
6691
|
+
})()) return null;
|
|
6692
|
+
if (action$1.component) return /* @__PURE__ */ jsx(React.Fragment, { children: renderToolbarComponent(action$1.component) }, action$1.type);
|
|
6693
|
+
return renderBuiltinButton(action$1.type, {
|
|
6694
|
+
onClick: action$1.onClick,
|
|
6695
|
+
label: action$1.label
|
|
7171
6696
|
});
|
|
7172
6697
|
})
|
|
7173
6698
|
});
|
|
@@ -7186,6 +6711,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
7186
6711
|
onUpdateSelected: can.update ? resource.handlers.updateMany : void 0,
|
|
7187
6712
|
batchUpdateFields: can.update ? batchFields : void 0,
|
|
7188
6713
|
actionBarActions: registryBatchActions,
|
|
6714
|
+
deleteConfirmation: locale.bulkDeleteModal,
|
|
7189
6715
|
enableExport: canExport,
|
|
7190
6716
|
showDefaultExport: false,
|
|
7191
6717
|
initialSorting: tableConfig?.defaultSort,
|
|
@@ -7205,6 +6731,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
7205
6731
|
loading: resource.mutations.isCreating || resource.mutations.isUpdating,
|
|
7206
6732
|
variant: resource.modal.variant,
|
|
7207
6733
|
overrides: formOverrides,
|
|
6734
|
+
scope: formConfig?.scope,
|
|
7208
6735
|
locale: locale.formModal,
|
|
7209
6736
|
gridColumns: formConfig?.columns,
|
|
7210
6737
|
className: formConfig?.className
|
|
@@ -7216,7 +6743,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
7216
6743
|
data: resource.modal.selected,
|
|
7217
6744
|
schema: resolvedSchema,
|
|
7218
6745
|
fields: resolvedFields,
|
|
7219
|
-
dynamicOptions: dynamicFilterOptions,
|
|
6746
|
+
dynamicOptions: dynamicFilterOptions.optionsByField,
|
|
7220
6747
|
denyFields,
|
|
7221
6748
|
locale
|
|
7222
6749
|
}),
|
|
@@ -7339,15 +6866,29 @@ function DataTableAdvancedToolbar({ table, children, className,...props }) {
|
|
|
7339
6866
|
function DataTableFacetedFilter({ column, title, options, multiple }) {
|
|
7340
6867
|
const columnFilterValue = column?.getFilterValue();
|
|
7341
6868
|
const selectedValues = Array.isArray(columnFilterValue) ? columnFilterValue.filter((value) => typeof value === "string") : [];
|
|
6869
|
+
const currentOptions = column?.columnDef.meta?.autoCrudFilterOptions ?? options;
|
|
6870
|
+
const currentOptionValues = new Set(currentOptions.map((option) => option.value));
|
|
6871
|
+
const selectedOptionValues = new Set(selectedValues);
|
|
6872
|
+
const comboboxOptions = currentOptions === options ? currentOptions : [...options.filter((option) => selectedOptionValues.has(option.value) && !currentOptionValues.has(option.value)), ...currentOptions];
|
|
7342
6873
|
const onChange = (nextValues) => {
|
|
7343
6874
|
column?.setFilterValue(nextValues.length ? nextValues : void 0);
|
|
7344
6875
|
};
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
|
|
7348
|
-
|
|
7349
|
-
|
|
6876
|
+
const onSelectChange = (nextValue) => {
|
|
6877
|
+
onChange(Array.isArray(nextValue) ? nextValue : nextValue ? [nextValue] : []);
|
|
6878
|
+
};
|
|
6879
|
+
return /* @__PURE__ */ jsx(Select$2, {
|
|
6880
|
+
mode: "searchable",
|
|
6881
|
+
multiple: Boolean(multiple),
|
|
6882
|
+
value: multiple ? selectedValues : selectedValues[0] ?? "",
|
|
6883
|
+
onChange: onSelectChange,
|
|
6884
|
+
options: comboboxOptions,
|
|
7350
6885
|
searchPlaceholder: title,
|
|
6886
|
+
hasMore: column?.columnDef.meta?.autoCrudFilterHasMore,
|
|
6887
|
+
loading: column?.columnDef.meta?.autoCrudFilterLoading,
|
|
6888
|
+
searchValue: column?.columnDef.meta?.autoCrudFilterSearchValue,
|
|
6889
|
+
shouldFilter: column?.columnDef.meta?.autoCrudFilterShouldFilter,
|
|
6890
|
+
onPopupScroll: column?.columnDef.meta?.autoCrudFilterOnPopupScroll,
|
|
6891
|
+
onSearch: column?.columnDef.meta?.autoCrudFilterOnSearch,
|
|
7351
6892
|
contentClassName: "w-50",
|
|
7352
6893
|
matchTriggerWidth: false,
|
|
7353
6894
|
clearText: "Clear filters",
|
|
@@ -7926,8 +7467,8 @@ function readMetadataFields(fields) {
|
|
|
7926
7467
|
/**
|
|
7927
7468
|
* Modal 状态 Reducer
|
|
7928
7469
|
*/
|
|
7929
|
-
function modalReducer(state, action) {
|
|
7930
|
-
switch (action.type) {
|
|
7470
|
+
function modalReducer(state, action$1) {
|
|
7471
|
+
switch (action$1.type) {
|
|
7931
7472
|
case "OPEN_CREATE": return {
|
|
7932
7473
|
...state,
|
|
7933
7474
|
createOpen: true,
|
|
@@ -7938,22 +7479,22 @@ function modalReducer(state, action) {
|
|
|
7938
7479
|
...state,
|
|
7939
7480
|
createOpen: true,
|
|
7940
7481
|
selected: null,
|
|
7941
|
-
copySource: action.payload
|
|
7482
|
+
copySource: action$1.payload
|
|
7942
7483
|
};
|
|
7943
7484
|
case "OPEN_EDIT": return {
|
|
7944
7485
|
...state,
|
|
7945
7486
|
editOpen: true,
|
|
7946
|
-
selected: action.payload
|
|
7487
|
+
selected: action$1.payload
|
|
7947
7488
|
};
|
|
7948
7489
|
case "OPEN_DELETE": return {
|
|
7949
7490
|
...state,
|
|
7950
7491
|
deleteOpen: true,
|
|
7951
|
-
selected: action.payload
|
|
7492
|
+
selected: action$1.payload
|
|
7952
7493
|
};
|
|
7953
7494
|
case "OPEN_VIEW": return {
|
|
7954
7495
|
...state,
|
|
7955
7496
|
viewOpen: true,
|
|
7956
|
-
selected: action.payload
|
|
7497
|
+
selected: action$1.payload
|
|
7957
7498
|
};
|
|
7958
7499
|
case "CLOSE_ALL": return {
|
|
7959
7500
|
...state,
|
|
@@ -7966,7 +7507,7 @@ function modalReducer(state, action) {
|
|
|
7966
7507
|
};
|
|
7967
7508
|
case "SET_VARIANT": return {
|
|
7968
7509
|
...state,
|
|
7969
|
-
variant: action.payload
|
|
7510
|
+
variant: action$1.payload
|
|
7970
7511
|
};
|
|
7971
7512
|
default: return state;
|
|
7972
7513
|
}
|
|
@@ -8263,6 +7804,9 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
8263
7804
|
queryInput
|
|
8264
7805
|
]);
|
|
8265
7806
|
const canExport = !!(exportFetcher || exportQuery);
|
|
7807
|
+
const refresh = useCallback(async () => {
|
|
7808
|
+
return listQuery.refetch();
|
|
7809
|
+
}, [listQuery]);
|
|
8266
7810
|
return {
|
|
8267
7811
|
idKey,
|
|
8268
7812
|
tableData: {
|
|
@@ -8293,6 +7837,7 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
8293
7837
|
deleteMany,
|
|
8294
7838
|
updateMany,
|
|
8295
7839
|
setVariant,
|
|
7840
|
+
refresh,
|
|
8296
7841
|
import: importMutation ? handleImport : null,
|
|
8297
7842
|
export: canExport ? handleExport : null
|
|
8298
7843
|
}
|
|
@@ -8604,4 +8149,4 @@ function createMemoryDataSource(initialData = []) {
|
|
|
8604
8149
|
}
|
|
8605
8150
|
|
|
8606
8151
|
//#endregion
|
|
8607
|
-
export { AutoCrudTable, AutoForm, AutoTable, AutoTableActionBar, AutoTableSimpleFilters, CrudFormModal, DataTable, DataTableAdvancedToolbar, DataTableColumnHeader, DataTableFacetedFilter, DataTablePagination, DataTableToolbar, DataTableViewOptions, ExportDialog, ImportDialog, MultiCombobox, SchemaAdapter, cn, coerceRowValues, components, createActionsColumn, createEditFormSchema, createFormSchema, createMemoryDataSource, createSelectColumn, createTRPCDataSource, createTableSchema, crudActions, dataSources, dataToCSV, deDE, downloadCSVTemplate, enUS, esES, exportAllToCSV, exportTableToCSV, formComponents, formatDate, frFR, generateCSVTemplate, getUrlParams, humanize, jaJP, koKR, noopToastAdapter, normalizeDataSourceConfig, normalizeOptions, parseAsArrayOf, parseAsInteger, parseAsString, parseAsStringEnum, parseCSV, parseImportFile, parseJSON, parseZodField, resolveLocale, setSearchParams, setToolbarResolver, useAutoCrudResource, useDataTable, useQueryState, useQueryStates, useReadableFilters, useUrlState, useUrlStates, zhCN };
|
|
8152
|
+
export { AutoCrudTable, AutoForm, AutoTable, AutoTableActionBar, AutoTableSimpleFilters, CrudFormModal, DataTable, DataTableAdvancedToolbar, DataTableColumnHeader, DataTableFacetedFilter, DataTablePagination, DataTableToolbar, DataTableViewOptions, ExportDialog, ImportDialog, MultiCombobox, SchemaAdapter, Select, cn, coerceRowValues, components, createActionsColumn, createEditFormSchema, createFormSchema, createMemoryDataSource, createSelectColumn, createTRPCDataSource, createTableSchema, crudActions, dataSources, dataToCSV, deDE, downloadCSVTemplate, enUS, esES, exportAllToCSV, exportTableToCSV, formComponents, formatDate, frFR, generateCSVTemplate, getUrlParams, humanize, jaJP, koKR, noopToastAdapter, normalizeDataSourceConfig, normalizeOptions, parseAsArrayOf, parseAsInteger, parseAsString, parseAsStringEnum, parseCSV, parseImportFile, parseJSON, parseZodField, resolveLocale, setSearchParams, setToolbarResolver, useAutoCrudResource, useDataTable, useQueryState, useQueryStates, useReadableFilters, useUrlState, useUrlStates, zhCN };
|