@wordrhyme/auto-crud 1.5.7 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +245 -0
- package/dist/index.cjs +527 -305
- package/dist/index.d.cts +1118 -1058
- package/dist/index.d.ts +1103 -1043
- package/dist/index.js +527 -306
- package/dist/styles.css +2 -0
- package/dist/tailwind.css +3 -0
- package/package.json +23 -19
package/dist/index.cjs
CHANGED
|
@@ -39,6 +39,8 @@ let nanoid = require("nanoid");
|
|
|
39
39
|
nanoid = __toESM(nanoid);
|
|
40
40
|
let __wordrhyme_shadcn_ui = require("@wordrhyme/shadcn-ui");
|
|
41
41
|
__wordrhyme_shadcn_ui = __toESM(__wordrhyme_shadcn_ui);
|
|
42
|
+
let __wordrhyme_ui = require("@wordrhyme/ui");
|
|
43
|
+
__wordrhyme_ui = __toESM(__wordrhyme_ui);
|
|
42
44
|
let zod = require("zod");
|
|
43
45
|
zod = __toESM(zod);
|
|
44
46
|
let __formily_core = require("@formily/core");
|
|
@@ -420,13 +422,15 @@ function hasValidCanonicalDateTimePrefix(value) {
|
|
|
420
422
|
const match = canonicalDateTimePrefixPattern.exec(value);
|
|
421
423
|
return !match || isValidCalendarDate(match[1], match[2], match[3]);
|
|
422
424
|
}
|
|
425
|
+
function getDateLocaleOptions() {
|
|
426
|
+
return hostDateFormatters[hostDateFormatters.length - 1]?.options;
|
|
427
|
+
}
|
|
423
428
|
/**
|
|
424
|
-
* Register the host's
|
|
425
|
-
*
|
|
426
|
-
* this registration, so overlapping registrations may be disposed out of order.
|
|
429
|
+
* Register the host's date formatter and optional calendar locale policy.
|
|
430
|
+
* Cleanup removes only this registration, including out-of-order cleanup.
|
|
427
431
|
* Passing undefined clears every registration.
|
|
428
432
|
*/
|
|
429
|
-
function setDateFormatter(formatter) {
|
|
433
|
+
function setDateFormatter(formatter, options) {
|
|
430
434
|
if (formatter === void 0) {
|
|
431
435
|
const hadFormatter = hostDateFormatters.length > 0;
|
|
432
436
|
hostDateFormatters = [];
|
|
@@ -435,15 +439,16 @@ function setDateFormatter(formatter) {
|
|
|
435
439
|
}
|
|
436
440
|
const registration = {
|
|
437
441
|
formatter,
|
|
442
|
+
...options ? { options } : {},
|
|
438
443
|
token: Symbol("date-formatter")
|
|
439
444
|
};
|
|
440
445
|
hostDateFormatters.push(registration);
|
|
441
446
|
notifyDateFormatterChange();
|
|
442
447
|
return () => {
|
|
443
|
-
const
|
|
448
|
+
const currentRegistration = hostDateFormatters[hostDateFormatters.length - 1];
|
|
444
449
|
const previousLength = hostDateFormatters.length;
|
|
445
450
|
hostDateFormatters = hostDateFormatters.filter(({ token }) => token !== registration.token);
|
|
446
|
-
if (hostDateFormatters.length !== previousLength &&
|
|
451
|
+
if (hostDateFormatters.length !== previousLength && hostDateFormatters[hostDateFormatters.length - 1] !== currentRegistration) notifyDateFormatterChange();
|
|
447
452
|
};
|
|
448
453
|
}
|
|
449
454
|
function formatDate(date, opts = {}, preset) {
|
|
@@ -492,8 +497,14 @@ function formatDate(date, opts = {}, preset) {
|
|
|
492
497
|
|
|
493
498
|
//#endregion
|
|
494
499
|
//#region src/components/data-table/data-table.tsx
|
|
495
|
-
function DataTable({ table, actionBar, children, className,...props }) {
|
|
500
|
+
function DataTable({ table, actionBar, children, className, classNames,...props }) {
|
|
496
501
|
useDateFormatterVersion();
|
|
502
|
+
const columns = [
|
|
503
|
+
...table.getLeftVisibleLeafColumns(),
|
|
504
|
+
...table.getCenterVisibleLeafColumns(),
|
|
505
|
+
...table.getRightVisibleLeafColumns()
|
|
506
|
+
];
|
|
507
|
+
const hasWidthCap = columns.some((column) => (column.columnDef.maxSize ?? Number.MAX_SAFE_INTEGER) < Number.MAX_SAFE_INTEGER);
|
|
497
508
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
498
509
|
className: cn("flex w-full flex-col gap-2.5 overflow-auto", className),
|
|
499
510
|
...props,
|
|
@@ -501,21 +512,53 @@ function DataTable({ table, actionBar, children, className,...props }) {
|
|
|
501
512
|
children,
|
|
502
513
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
503
514
|
className: "overflow-hidden rounded-md border",
|
|
504
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Table, {
|
|
505
|
-
|
|
506
|
-
style:
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
children:
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
515
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Table, {
|
|
516
|
+
className: classNames?.table,
|
|
517
|
+
style: hasWidthCap ? {
|
|
518
|
+
tableLayout: "fixed",
|
|
519
|
+
width: columns.reduce((width, column) => width + column.getSize(), 0)
|
|
520
|
+
} : void 0,
|
|
521
|
+
children: [
|
|
522
|
+
hasWidthCap && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("colgroup", { children: columns.map((column) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("col", { style: { width: column.getSize() } }, column.id)) }),
|
|
523
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableHeader, {
|
|
524
|
+
className: classNames?.thead,
|
|
525
|
+
children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableRow, {
|
|
526
|
+
className: classNames?.tr,
|
|
527
|
+
children: headerGroup.headers.map((header) => {
|
|
528
|
+
const columnClassName = header.column.columnDef.meta?.classNames?.th;
|
|
529
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableHead, {
|
|
530
|
+
colSpan: header.colSpan,
|
|
531
|
+
className: cn(hasWidthCap && "overflow-hidden text-ellipsis", classNames?.th, typeof columnClassName === "string" ? columnClassName : void 0),
|
|
532
|
+
style: { ...getColumnPinningStyle({ column: header.column }) },
|
|
533
|
+
children: header.isPlaceholder ? null : (0, __tanstack_react_table.flexRender)(header.column.columnDef.header, header.getContext())
|
|
534
|
+
}, header.id);
|
|
535
|
+
})
|
|
536
|
+
}, headerGroup.id))
|
|
537
|
+
}),
|
|
538
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableBody, {
|
|
539
|
+
className: classNames?.tbody,
|
|
540
|
+
children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableRow, {
|
|
541
|
+
className: classNames?.tr,
|
|
542
|
+
"data-state": row.getIsSelected() && "selected",
|
|
543
|
+
children: row.getVisibleCells().map((cell) => {
|
|
544
|
+
const columnClassName = cell.column.columnDef.meta?.classNames?.td;
|
|
545
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableCell, {
|
|
546
|
+
className: cn(hasWidthCap && "overflow-hidden text-ellipsis", classNames?.td, typeof columnClassName === "string" ? columnClassName : void 0),
|
|
547
|
+
style: { ...getColumnPinningStyle({ column: cell.column }) },
|
|
548
|
+
children: (0, __tanstack_react_table.flexRender)(cell.column.columnDef.cell, cell.getContext())
|
|
549
|
+
}, cell.id);
|
|
550
|
+
})
|
|
551
|
+
}, row.id)) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableRow, {
|
|
552
|
+
className: classNames?.tr,
|
|
553
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableCell, {
|
|
554
|
+
colSpan: table.getAllColumns().length,
|
|
555
|
+
className: cn("h-24 text-center", classNames?.td),
|
|
556
|
+
children: "No results."
|
|
557
|
+
})
|
|
558
|
+
})
|
|
559
|
+
})
|
|
560
|
+
]
|
|
561
|
+
})
|
|
519
562
|
}),
|
|
520
563
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
521
564
|
className: "flex flex-col gap-2.5",
|
|
@@ -1043,6 +1086,71 @@ function useDebouncedCallback(callback, delay) {
|
|
|
1043
1086
|
}, [handleCallback, delay]);
|
|
1044
1087
|
}
|
|
1045
1088
|
|
|
1089
|
+
//#endregion
|
|
1090
|
+
//#region src/lib/calendar-date.ts
|
|
1091
|
+
/** Calendar days are wall dates, never instants in the host's time zone. */
|
|
1092
|
+
function serializeCalendarDate(date) {
|
|
1093
|
+
return `${String(date.getFullYear()).padStart(4, "0")}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
|
|
1094
|
+
}
|
|
1095
|
+
function parseCalendarDate(value) {
|
|
1096
|
+
if (value === void 0 || value === "") return void 0;
|
|
1097
|
+
if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
1098
|
+
const date$1 = /* @__PURE__ */ new Date(`${value}T00:00:00`);
|
|
1099
|
+
return !Number.isNaN(date$1.getTime()) && serializeCalendarDate(date$1) === value ? date$1 : void 0;
|
|
1100
|
+
}
|
|
1101
|
+
const date = new Date(Number(value));
|
|
1102
|
+
return Number.isNaN(date.getTime()) ? void 0 : date;
|
|
1103
|
+
}
|
|
1104
|
+
function calendarPresentation() {
|
|
1105
|
+
const localeOptions = getDateLocaleOptions();
|
|
1106
|
+
const locale = localeOptions?.locale ?? "en-US";
|
|
1107
|
+
const chinese = locale.toLowerCase().startsWith("zh");
|
|
1108
|
+
const localeInfo = new Intl.Locale(locale);
|
|
1109
|
+
const firstDay = localeInfo.getWeekInfo?.().firstDay ?? localeInfo.weekInfo?.firstDay ?? (chinese ? 1 : 7);
|
|
1110
|
+
const format = (date, options) => new Intl.DateTimeFormat(locale, {
|
|
1111
|
+
...options,
|
|
1112
|
+
timeZone: "UTC"
|
|
1113
|
+
}).format(/* @__PURE__ */ new Date(`${serializeCalendarDate(date)}T00:00:00Z`));
|
|
1114
|
+
return {
|
|
1115
|
+
locale,
|
|
1116
|
+
weekStartsOn: firstDay % 7,
|
|
1117
|
+
formatDate: (date) => {
|
|
1118
|
+
if (!localeOptions) return formatDate(date);
|
|
1119
|
+
return date ? format(date, {
|
|
1120
|
+
year: "numeric",
|
|
1121
|
+
month: "long",
|
|
1122
|
+
day: "numeric"
|
|
1123
|
+
}) : "";
|
|
1124
|
+
},
|
|
1125
|
+
clearLabel: (title) => chinese ? `清除${title ?? ""}筛选` : `Clear ${title ?? ""} filter`,
|
|
1126
|
+
formatters: {
|
|
1127
|
+
formatCaption: (date) => format(date, {
|
|
1128
|
+
year: "numeric",
|
|
1129
|
+
month: "long"
|
|
1130
|
+
}),
|
|
1131
|
+
formatMonthDropdown: (date) => format(date, { month: "long" }),
|
|
1132
|
+
formatWeekdayName: (date) => format(date, { weekday: "short" })
|
|
1133
|
+
},
|
|
1134
|
+
labels: {
|
|
1135
|
+
labelNext: () => chinese ? "下个月" : "Go to the Next Month",
|
|
1136
|
+
labelPrevious: () => chinese ? "上个月" : "Go to the Previous Month",
|
|
1137
|
+
labelMonthDropdown: () => chinese ? "选择月份" : "Choose the Month",
|
|
1138
|
+
labelYearDropdown: () => chinese ? "选择年份" : "Choose the Year",
|
|
1139
|
+
labelGrid: (date) => format(date, {
|
|
1140
|
+
year: "numeric",
|
|
1141
|
+
month: "long"
|
|
1142
|
+
}),
|
|
1143
|
+
labelWeekday: (date) => format(date, { weekday: "long" }),
|
|
1144
|
+
labelDayButton: (date) => format(date, {
|
|
1145
|
+
year: "numeric",
|
|
1146
|
+
month: "long",
|
|
1147
|
+
day: "numeric",
|
|
1148
|
+
weekday: "long"
|
|
1149
|
+
})
|
|
1150
|
+
}
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1046
1154
|
//#endregion
|
|
1047
1155
|
//#region src/components/data-table/data-table-filter-list.tsx
|
|
1048
1156
|
const DEBOUNCE_MS$2 = 300;
|
|
@@ -1214,6 +1322,7 @@ function DataTableFilterList({ table, debounceMs = DEBOUNCE_MS$2, throttleMs = T
|
|
|
1214
1322
|
});
|
|
1215
1323
|
}
|
|
1216
1324
|
function DataTableFilterItem$1({ filter, index: index$1, filterItemId, joinOperator, setJoinOperator, columns, onFilterUpdate, onFilterRemove }) {
|
|
1325
|
+
useDateFormatterVersion();
|
|
1217
1326
|
const [showFieldSelector, setShowFieldSelector] = react.useState(false);
|
|
1218
1327
|
const [showOperatorSelector, setShowOperatorSelector] = react.useState(false);
|
|
1219
1328
|
const [showValueSelector, setShowValueSelector] = react.useState(false);
|
|
@@ -1502,10 +1611,10 @@ function onFilterInputRender$1({ filter, inputId, column, columnMeta, onFilterUp
|
|
|
1502
1611
|
case "dateRange": {
|
|
1503
1612
|
const inputListboxId = `${inputId}-listbox`;
|
|
1504
1613
|
const dateValue = Array.isArray(filter.value) ? filter.value.filter(Boolean) : [filter.value, filter.value].filter(Boolean);
|
|
1505
|
-
const startDate = dateValue[0] ?
|
|
1506
|
-
const endDate = dateValue[1] ?
|
|
1614
|
+
const startDate = dateValue[0] ? parseCalendarDate(dateValue[0]) : void 0;
|
|
1615
|
+
const endDate = dateValue[1] ? parseCalendarDate(dateValue[1]) : void 0;
|
|
1507
1616
|
const isSameDate = startDate && endDate && startDate.toDateString() === endDate.toDateString();
|
|
1508
|
-
const displayValue = filter.operator === "isBetween" && dateValue.length === 2 && !isSameDate ? `${formatDate(startDate
|
|
1617
|
+
const displayValue = filter.operator === "isBetween" && dateValue.length === 2 && !isSameDate ? `${calendarPresentation().formatDate(startDate)} - ${calendarPresentation().formatDate(endDate)}` : startDate ? calendarPresentation().formatDate(startDate) : "Pick a date";
|
|
1509
1618
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Popover, {
|
|
1510
1619
|
open: showValueSelector,
|
|
1511
1620
|
onOpenChange: setShowValueSelector,
|
|
@@ -1528,28 +1637,36 @@ function onFilterInputRender$1({ filter, inputId, column, columnMeta, onFilterUp
|
|
|
1528
1637
|
align: "start",
|
|
1529
1638
|
className: "w-auto p-0",
|
|
1530
1639
|
children: filter.operator === "isBetween" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Calendar, {
|
|
1640
|
+
lang: calendarPresentation().locale,
|
|
1641
|
+
weekStartsOn: calendarPresentation().weekStartsOn,
|
|
1642
|
+
formatters: calendarPresentation().formatters,
|
|
1643
|
+
labels: calendarPresentation().labels,
|
|
1531
1644
|
"aria-label": `Select ${columnMeta?.label} date range`,
|
|
1532
1645
|
autoFocus: true,
|
|
1533
1646
|
captionLayout: "dropdown",
|
|
1534
1647
|
mode: "range",
|
|
1535
1648
|
selected: dateValue.length === 2 ? {
|
|
1536
|
-
from:
|
|
1537
|
-
to:
|
|
1649
|
+
from: parseCalendarDate(dateValue[0]),
|
|
1650
|
+
to: parseCalendarDate(dateValue[1])
|
|
1538
1651
|
} : {
|
|
1539
1652
|
from: /* @__PURE__ */ new Date(),
|
|
1540
1653
|
to: /* @__PURE__ */ new Date()
|
|
1541
1654
|
},
|
|
1542
1655
|
onSelect: (date) => {
|
|
1543
|
-
onFilterUpdate(filter.filterId, { value: date ? [(date.from
|
|
1656
|
+
onFilterUpdate(filter.filterId, { value: date ? [date.from ? serializeCalendarDate(date.from) : "", date.to ? serializeCalendarDate(date.to) : ""] : [] });
|
|
1544
1657
|
}
|
|
1545
1658
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Calendar, {
|
|
1659
|
+
lang: calendarPresentation().locale,
|
|
1660
|
+
weekStartsOn: calendarPresentation().weekStartsOn,
|
|
1661
|
+
formatters: calendarPresentation().formatters,
|
|
1662
|
+
labels: calendarPresentation().labels,
|
|
1546
1663
|
"aria-label": `Select ${columnMeta?.label} date`,
|
|
1547
1664
|
autoFocus: true,
|
|
1548
1665
|
captionLayout: "dropdown",
|
|
1549
1666
|
mode: "single",
|
|
1550
|
-
selected: dateValue[0] ?
|
|
1667
|
+
selected: dateValue[0] ? parseCalendarDate(dateValue[0]) : void 0,
|
|
1551
1668
|
onSelect: (date) => {
|
|
1552
|
-
onFilterUpdate(filter.filterId, { value: (date
|
|
1669
|
+
onFilterUpdate(filter.filterId, { value: date ? serializeCalendarDate(date) : "" });
|
|
1553
1670
|
setShowValueSelector(false);
|
|
1554
1671
|
}
|
|
1555
1672
|
})
|
|
@@ -1761,6 +1878,7 @@ function DataTableFilterMenu({ table, debounceMs = DEBOUNCE_MS$1, throttleMs = T
|
|
|
1761
1878
|
}
|
|
1762
1879
|
function DataTableFilterItem({ filter, filterItemId, columns, onFilterUpdate, onFilterRemove }) {
|
|
1763
1880
|
{
|
|
1881
|
+
useDateFormatterVersion();
|
|
1764
1882
|
const [showFieldSelector, setShowFieldSelector] = react.useState(false);
|
|
1765
1883
|
const [showOperatorSelector, setShowOperatorSelector] = react.useState(false);
|
|
1766
1884
|
const [showValueSelector, setShowValueSelector] = react.useState(false);
|
|
@@ -1871,6 +1989,7 @@ function DataTableFilterItem({ filter, filterItemId, columns, onFilterUpdate, on
|
|
|
1871
1989
|
}
|
|
1872
1990
|
}
|
|
1873
1991
|
function FilterValueSelector({ column, value, onSelect }) {
|
|
1992
|
+
useDateFormatterVersion();
|
|
1874
1993
|
switch (column.columnDef.meta?.variant ?? "text") {
|
|
1875
1994
|
case "boolean": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.CommandGroup, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.CommandItem, {
|
|
1876
1995
|
value: "true",
|
|
@@ -1899,11 +2018,15 @@ function FilterValueSelector({ column, value, onSelect }) {
|
|
|
1899
2018
|
}, option.value)) });
|
|
1900
2019
|
case "date":
|
|
1901
2020
|
case "dateRange": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Calendar, {
|
|
2021
|
+
lang: calendarPresentation().locale,
|
|
2022
|
+
weekStartsOn: calendarPresentation().weekStartsOn,
|
|
2023
|
+
formatters: calendarPresentation().formatters,
|
|
2024
|
+
labels: calendarPresentation().labels,
|
|
1902
2025
|
autoFocus: true,
|
|
1903
2026
|
captionLayout: "dropdown",
|
|
1904
2027
|
mode: "single",
|
|
1905
|
-
selected:
|
|
1906
|
-
onSelect: (date) => onSelect(date
|
|
2028
|
+
selected: parseCalendarDate(value),
|
|
2029
|
+
onSelect: (date) => onSelect(date ? serializeCalendarDate(date) : "")
|
|
1907
2030
|
});
|
|
1908
2031
|
default: {
|
|
1909
2032
|
const isEmpty = !value.trim();
|
|
@@ -2057,10 +2180,10 @@ function onFilterInputRender({ filter, column, inputId, onFilterUpdate, showValu
|
|
|
2057
2180
|
case "dateRange": {
|
|
2058
2181
|
const inputListboxId = `${inputId}-listbox`;
|
|
2059
2182
|
const dateValue = Array.isArray(filter.value) ? filter.value.filter(Boolean) : [filter.value, filter.value].filter(Boolean);
|
|
2060
|
-
const startDate = dateValue[0] ?
|
|
2061
|
-
const endDate = dateValue[1] ?
|
|
2183
|
+
const startDate = dateValue[0] ? parseCalendarDate(dateValue[0]) : void 0;
|
|
2184
|
+
const endDate = dateValue[1] ? parseCalendarDate(dateValue[1]) : void 0;
|
|
2062
2185
|
const isSameDate = startDate && endDate && startDate.toDateString() === endDate.toDateString();
|
|
2063
|
-
const displayValue = filter.operator === "isBetween" && dateValue.length === 2 && !isSameDate ? `${formatDate(startDate
|
|
2186
|
+
const displayValue = filter.operator === "isBetween" && dateValue.length === 2 && !isSameDate ? `${calendarPresentation().formatDate(startDate)} - ${calendarPresentation().formatDate(endDate)}` : startDate ? calendarPresentation().formatDate(startDate) : "Pick date...";
|
|
2064
2187
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Popover, {
|
|
2065
2188
|
open: showValueSelector,
|
|
2066
2189
|
onOpenChange: setShowValueSelector,
|
|
@@ -2082,26 +2205,34 @@ function onFilterInputRender({ filter, column, inputId, onFilterUpdate, showValu
|
|
|
2082
2205
|
align: "start",
|
|
2083
2206
|
className: "w-auto p-0",
|
|
2084
2207
|
children: filter.operator === "isBetween" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Calendar, {
|
|
2208
|
+
lang: calendarPresentation().locale,
|
|
2209
|
+
weekStartsOn: calendarPresentation().weekStartsOn,
|
|
2210
|
+
formatters: calendarPresentation().formatters,
|
|
2211
|
+
labels: calendarPresentation().labels,
|
|
2085
2212
|
autoFocus: true,
|
|
2086
2213
|
captionLayout: "dropdown",
|
|
2087
2214
|
mode: "range",
|
|
2088
2215
|
selected: dateValue.length === 2 ? {
|
|
2089
|
-
from:
|
|
2090
|
-
to:
|
|
2216
|
+
from: parseCalendarDate(dateValue[0]),
|
|
2217
|
+
to: parseCalendarDate(dateValue[1])
|
|
2091
2218
|
} : {
|
|
2092
2219
|
from: /* @__PURE__ */ new Date(),
|
|
2093
2220
|
to: /* @__PURE__ */ new Date()
|
|
2094
2221
|
},
|
|
2095
2222
|
onSelect: (date) => {
|
|
2096
|
-
onFilterUpdate(filter.filterId, { value: date ? [(date.from
|
|
2223
|
+
onFilterUpdate(filter.filterId, { value: date ? [date.from ? serializeCalendarDate(date.from) : "", date.to ? serializeCalendarDate(date.to) : ""] : [] });
|
|
2097
2224
|
}
|
|
2098
2225
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Calendar, {
|
|
2226
|
+
lang: calendarPresentation().locale,
|
|
2227
|
+
weekStartsOn: calendarPresentation().weekStartsOn,
|
|
2228
|
+
formatters: calendarPresentation().formatters,
|
|
2229
|
+
labels: calendarPresentation().labels,
|
|
2099
2230
|
autoFocus: true,
|
|
2100
2231
|
captionLayout: "dropdown",
|
|
2101
2232
|
mode: "single",
|
|
2102
|
-
selected: dateValue[0] ?
|
|
2233
|
+
selected: dateValue[0] ? parseCalendarDate(dateValue[0]) : void 0,
|
|
2103
2234
|
onSelect: (date) => {
|
|
2104
|
-
onFilterUpdate(filter.filterId, { value: (date
|
|
2235
|
+
onFilterUpdate(filter.filterId, { value: date ? serializeCalendarDate(date) : "" });
|
|
2105
2236
|
}
|
|
2106
2237
|
})
|
|
2107
2238
|
})]
|
|
@@ -2850,11 +2981,17 @@ function SimpleSliderFilter({ title, range, unit, value, onChange }) {
|
|
|
2850
2981
|
})] });
|
|
2851
2982
|
}
|
|
2852
2983
|
function SimpleDateFilter({ title, multiple, value, onChange }) {
|
|
2984
|
+
const [open, setOpen] = react.useState(false);
|
|
2985
|
+
const commit = (next) => {
|
|
2986
|
+
setOpen(false);
|
|
2987
|
+
onChange(next);
|
|
2988
|
+
};
|
|
2989
|
+
const formatterVersion = useDateFormatterVersion();
|
|
2990
|
+
const presentation = react.useMemo(() => calendarPresentation(), [formatterVersion]);
|
|
2991
|
+
const { formatDate: formatDate$1 } = presentation;
|
|
2853
2992
|
const timestamps = Array.isArray(value) ? value : value ? [value] : [];
|
|
2854
|
-
const
|
|
2855
|
-
const
|
|
2856
|
-
const fromDate = fromTimestamp ? new Date(fromTimestamp) : void 0;
|
|
2857
|
-
const toDate = toTimestamp ? new Date(toTimestamp) : void 0;
|
|
2993
|
+
const fromDate = parseCalendarDate(timestamps[0]);
|
|
2994
|
+
const toDate = parseCalendarDate(timestamps[1]);
|
|
2858
2995
|
const [localRange, setLocalRange] = react.useState({
|
|
2859
2996
|
from: void 0,
|
|
2860
2997
|
to: void 0
|
|
@@ -2873,100 +3010,114 @@ function SimpleDateFilter({ title, multiple, value, onChange }) {
|
|
|
2873
3010
|
const hasValue = multiple ? fromDate || toDate : fromDate;
|
|
2874
3011
|
const onReset = (e) => {
|
|
2875
3012
|
e.stopPropagation();
|
|
2876
|
-
|
|
3013
|
+
commit(void 0);
|
|
2877
3014
|
};
|
|
2878
|
-
const label = multiple ? fromDate && toDate ? `${formatDate(fromDate)} - ${formatDate(toDate)}` : fromDate ? formatDate(fromDate) : void 0 : fromDate ? formatDate(fromDate) : void 0;
|
|
2879
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Popover, {
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
3015
|
+
const label = multiple ? fromDate && toDate ? `${formatDate$1(fromDate)} - ${formatDate$1(toDate)}` : fromDate ? formatDate$1(fromDate) : void 0 : fromDate ? formatDate$1(fromDate) : void 0;
|
|
3016
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Popover, {
|
|
3017
|
+
open,
|
|
3018
|
+
onOpenChange: setOpen,
|
|
3019
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.PopoverTrigger, {
|
|
3020
|
+
asChild: true,
|
|
3021
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Button, {
|
|
3022
|
+
variant: "outline",
|
|
3023
|
+
size: "sm",
|
|
3024
|
+
className: "border-dashed font-normal",
|
|
3025
|
+
children: [
|
|
3026
|
+
hasValue ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3027
|
+
role: "button",
|
|
3028
|
+
tabIndex: 0,
|
|
3029
|
+
className: "rounded-sm opacity-70 hover:opacity-100",
|
|
3030
|
+
onClick: onReset,
|
|
3031
|
+
onKeyDown: (e) => {
|
|
3032
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
3033
|
+
e.preventDefault();
|
|
3034
|
+
onReset(e);
|
|
3035
|
+
}
|
|
3036
|
+
},
|
|
3037
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.XCircle, {})
|
|
3038
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.CalendarIcon, {}),
|
|
3039
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: title }),
|
|
3040
|
+
label && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Separator, {
|
|
3041
|
+
orientation: "vertical",
|
|
3042
|
+
className: "mx-0.5 h-4"
|
|
3043
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label })] })
|
|
3044
|
+
]
|
|
3045
|
+
})
|
|
3046
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.PopoverContent, {
|
|
3047
|
+
className: "w-auto p-0",
|
|
3048
|
+
align: "start",
|
|
3049
|
+
children: multiple ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Calendar, {
|
|
3050
|
+
lang: presentation.locale,
|
|
3051
|
+
weekStartsOn: presentation.weekStartsOn,
|
|
3052
|
+
formatters: presentation.formatters,
|
|
3053
|
+
labels: presentation.labels,
|
|
3054
|
+
defaultMonth: fromDate,
|
|
3055
|
+
autoFocus: true,
|
|
3056
|
+
captionLayout: "dropdown",
|
|
3057
|
+
mode: "range",
|
|
3058
|
+
selected: localRange,
|
|
3059
|
+
onSelect: (range) => {
|
|
3060
|
+
if (!range?.from && !range?.to) {
|
|
3061
|
+
commit(void 0);
|
|
3062
|
+
setLocalRange({
|
|
3063
|
+
from: void 0,
|
|
3064
|
+
to: void 0
|
|
3065
|
+
});
|
|
3066
|
+
return;
|
|
3067
|
+
}
|
|
3068
|
+
const hadFrom = Boolean(localRange.from);
|
|
3069
|
+
const hadTo = Boolean(localRange.to);
|
|
3070
|
+
const from = range.from?.getTime();
|
|
3071
|
+
const to = range.to?.getTime();
|
|
3072
|
+
if (from != null && to != null && from === to) {
|
|
3073
|
+
if (!hadFrom || hadTo) {
|
|
3074
|
+
setLocalRange({
|
|
3075
|
+
from: range.from,
|
|
3076
|
+
to: void 0
|
|
3077
|
+
});
|
|
3078
|
+
return;
|
|
2895
3079
|
}
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
children: multiple ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Calendar, {
|
|
2910
|
-
autoFocus: true,
|
|
2911
|
-
captionLayout: "dropdown",
|
|
2912
|
-
mode: "range",
|
|
2913
|
-
selected: localRange,
|
|
2914
|
-
onSelect: (range) => {
|
|
2915
|
-
if (!range?.from && !range?.to) {
|
|
2916
|
-
onChange(void 0);
|
|
2917
|
-
setLocalRange({
|
|
2918
|
-
from: void 0,
|
|
2919
|
-
to: void 0
|
|
2920
|
-
});
|
|
2921
|
-
return;
|
|
2922
|
-
}
|
|
2923
|
-
const hadFrom = Boolean(localRange.from);
|
|
2924
|
-
const hadTo = Boolean(localRange.to);
|
|
2925
|
-
const from = range.from?.getTime();
|
|
2926
|
-
const to = range.to?.getTime();
|
|
2927
|
-
if (from != null && to != null && from === to) {
|
|
2928
|
-
if (!hadFrom || hadTo) {
|
|
3080
|
+
if (hadFrom && !hadTo && localRange.from) {
|
|
3081
|
+
const prevFrom = localRange.from;
|
|
3082
|
+
const newDate = range.from;
|
|
3083
|
+
const [finalFrom, finalTo] = prevFrom <= newDate ? [prevFrom, newDate] : [newDate, prevFrom];
|
|
3084
|
+
setLocalRange({
|
|
3085
|
+
from: finalFrom,
|
|
3086
|
+
to: finalTo
|
|
3087
|
+
});
|
|
3088
|
+
commit([serializeCalendarDate(finalFrom), serializeCalendarDate(finalTo)]);
|
|
3089
|
+
return;
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
if (from != null && to != null && from !== to) {
|
|
2929
3093
|
setLocalRange({
|
|
2930
3094
|
from: range.from,
|
|
2931
|
-
to:
|
|
3095
|
+
to: range.to
|
|
2932
3096
|
});
|
|
3097
|
+
commit([serializeCalendarDate(range.from), serializeCalendarDate(range.to)]);
|
|
2933
3098
|
return;
|
|
2934
3099
|
}
|
|
2935
|
-
if (
|
|
2936
|
-
const prevFrom = localRange.from;
|
|
2937
|
-
const newDate = range.from;
|
|
2938
|
-
const [finalFrom, finalTo] = prevFrom <= newDate ? [prevFrom, newDate] : [newDate, prevFrom];
|
|
3100
|
+
if (range.from && !range.to) {
|
|
2939
3101
|
setLocalRange({
|
|
2940
|
-
from:
|
|
2941
|
-
to:
|
|
3102
|
+
from: range.from,
|
|
3103
|
+
to: void 0
|
|
2942
3104
|
});
|
|
2943
|
-
onChange([finalFrom.getTime().toString(), finalTo.getTime().toString()]);
|
|
2944
3105
|
return;
|
|
2945
3106
|
}
|
|
2946
3107
|
}
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
return;
|
|
2961
|
-
}
|
|
2962
|
-
}
|
|
2963
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Calendar, {
|
|
2964
|
-
captionLayout: "dropdown",
|
|
2965
|
-
mode: "single",
|
|
2966
|
-
selected: fromDate,
|
|
2967
|
-
onSelect: (date) => onChange(date ? date.getTime().toString() : void 0)
|
|
2968
|
-
})
|
|
2969
|
-
})] });
|
|
3108
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Calendar, {
|
|
3109
|
+
lang: presentation.locale,
|
|
3110
|
+
weekStartsOn: presentation.weekStartsOn,
|
|
3111
|
+
formatters: presentation.formatters,
|
|
3112
|
+
labels: presentation.labels,
|
|
3113
|
+
defaultMonth: fromDate,
|
|
3114
|
+
captionLayout: "dropdown",
|
|
3115
|
+
mode: "single",
|
|
3116
|
+
selected: fromDate,
|
|
3117
|
+
onSelect: (date) => commit(date ? serializeCalendarDate(date) : void 0)
|
|
3118
|
+
})
|
|
3119
|
+
})]
|
|
3120
|
+
});
|
|
2970
3121
|
}
|
|
2971
3122
|
|
|
2972
3123
|
//#endregion
|
|
@@ -3301,10 +3452,7 @@ function renderCell(value, type, options) {
|
|
|
3301
3452
|
className: "tabular-nums",
|
|
3302
3453
|
children: String(value)
|
|
3303
3454
|
});
|
|
3304
|
-
default: return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3305
|
-
className: "truncate max-w-48",
|
|
3306
|
-
children: String(value)
|
|
3307
|
-
});
|
|
3455
|
+
default: return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: String(value) });
|
|
3308
3456
|
}
|
|
3309
3457
|
}
|
|
3310
3458
|
/**
|
|
@@ -3390,33 +3538,38 @@ function createSelectColumn() {
|
|
|
3390
3538
|
size: 40
|
|
3391
3539
|
};
|
|
3392
3540
|
}
|
|
3541
|
+
function ActionsCell({ row, column }) {
|
|
3542
|
+
const items = column.columnDef.meta?.rowActions ?? [];
|
|
3543
|
+
const renderActionComponent = (item) => {
|
|
3544
|
+
if (!item.component) return null;
|
|
3545
|
+
return typeof item.component === "function" ? item.component(item.getContext?.(row.original)) : item.component;
|
|
3546
|
+
};
|
|
3547
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_ui.DropdownMenu, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.DropdownMenuTrigger, {
|
|
3548
|
+
asChild: true,
|
|
3549
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Button, {
|
|
3550
|
+
"aria-label": "Open menu",
|
|
3551
|
+
variant: "ghost",
|
|
3552
|
+
className: "flex size-8 p-0 data-[state=open]:bg-muted",
|
|
3553
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Ellipsis, { className: "size-4" })
|
|
3554
|
+
})
|
|
3555
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.DropdownMenuContent, {
|
|
3556
|
+
align: "end",
|
|
3557
|
+
className: "w-40",
|
|
3558
|
+
children: items.map((item, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [item.separator && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.DropdownMenuSeparator, {}), item.component ? renderActionComponent(item) : item.label && item.onClick ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.DropdownMenuItem, {
|
|
3559
|
+
className: item.variant === "destructive" ? "text-destructive" : "",
|
|
3560
|
+
onClick: () => item.onClick?.(row.original),
|
|
3561
|
+
children: item.label
|
|
3562
|
+
}) : null] }, i))
|
|
3563
|
+
})] });
|
|
3564
|
+
}
|
|
3393
3565
|
/**
|
|
3394
3566
|
* 创建操作列
|
|
3395
3567
|
*/
|
|
3396
3568
|
function createActionsColumn(items) {
|
|
3397
|
-
const renderActionComponent = (item, row) => {
|
|
3398
|
-
if (!item.component) return null;
|
|
3399
|
-
return typeof item.component === "function" ? item.component(item.getContext?.(row.original)) : item.component;
|
|
3400
|
-
};
|
|
3401
3569
|
return {
|
|
3402
3570
|
id: "actions",
|
|
3403
|
-
cell:
|
|
3404
|
-
|
|
3405
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Button, {
|
|
3406
|
-
"aria-label": "Open menu",
|
|
3407
|
-
variant: "ghost",
|
|
3408
|
-
className: "flex size-8 p-0 data-[state=open]:bg-muted",
|
|
3409
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Ellipsis, { className: "size-4" })
|
|
3410
|
-
})
|
|
3411
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.DropdownMenuContent, {
|
|
3412
|
-
align: "end",
|
|
3413
|
-
className: "w-40",
|
|
3414
|
-
children: items.map((item, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [item.separator && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.DropdownMenuSeparator, {}), item.component ? renderActionComponent(item, row) : item.label && item.onClick ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.DropdownMenuItem, {
|
|
3415
|
-
className: item.variant === "destructive" ? "text-destructive" : "",
|
|
3416
|
-
onClick: () => item.onClick?.(row.original),
|
|
3417
|
-
children: item.label
|
|
3418
|
-
}) : null] }, i))
|
|
3419
|
-
})] }),
|
|
3571
|
+
cell: ActionsCell,
|
|
3572
|
+
meta: { rowActions: items },
|
|
3420
3573
|
size: 40
|
|
3421
3574
|
};
|
|
3422
3575
|
}
|
|
@@ -3974,7 +4127,8 @@ function useDataTable(props) {
|
|
|
3974
4127
|
if (enableAdvancedFilter) return [];
|
|
3975
4128
|
return Object.entries(filterValues).reduce((filters, [key, value]) => {
|
|
3976
4129
|
if (value !== null) {
|
|
3977
|
-
const
|
|
4130
|
+
const variant = filterableColumns.find((column) => column.id === key)?.meta?.variant;
|
|
4131
|
+
const processedValue = Array.isArray(value) ? value : typeof value === "string" && (variant === "date" || variant === "dateRange") ? value.split(",").filter(Boolean) : typeof value === "string" && /[^a-zA-Z0-9]/.test(value) ? value.split(/[^a-zA-Z0-9]+/).filter(Boolean) : [value];
|
|
3978
4132
|
filters.push({
|
|
3979
4133
|
id: key,
|
|
3980
4134
|
value: processedValue
|
|
@@ -3982,7 +4136,11 @@ function useDataTable(props) {
|
|
|
3982
4136
|
}
|
|
3983
4137
|
return filters;
|
|
3984
4138
|
}, []);
|
|
3985
|
-
}, [
|
|
4139
|
+
}, [
|
|
4140
|
+
filterValues,
|
|
4141
|
+
enableAdvancedFilter,
|
|
4142
|
+
filterableColumns
|
|
4143
|
+
]);
|
|
3986
4144
|
const [columnFilters, setColumnFilters] = react.useState(initialColumnFilters);
|
|
3987
4145
|
const onColumnFiltersChange = react.useCallback((updaterOrValue) => {
|
|
3988
4146
|
if (enableAdvancedFilter) return;
|
|
@@ -4090,7 +4248,7 @@ const filterModeConfig = {
|
|
|
4090
4248
|
tooltip: "Linear-style command filters"
|
|
4091
4249
|
}
|
|
4092
4250
|
};
|
|
4093
|
-
function AutoTable({ schema, data, pageCount = 1, total, overrides, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode, search = false, onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, actionBarActions, deleteConfirmation, initialSorting, enableExport = true, showDefaultExport = true, onSelectedCountChange, onSelectedRowsChange, getSelectedRows }) {
|
|
4251
|
+
function AutoTable({ schema, data, pageCount = 1, total, overrides, classNames, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode, search = false, onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, actionBarActions, deleteConfirmation, initialSorting, enableExport = true, showDefaultExport = true, onSelectedCountChange, onSelectedRowsChange, getSelectedRows }) {
|
|
4094
4252
|
const modes = filterMode ? Array.isArray(filterMode) ? filterMode : [filterMode] : DEFAULT_MODES;
|
|
4095
4253
|
const [currentMode, setCurrentMode] = useQueryState("filterMode", parseAsStringEnum(modes).withDefault(modes[0] ?? "simple"));
|
|
4096
4254
|
const showToggle = modes.length > 1;
|
|
@@ -4252,7 +4410,10 @@ function AutoTable({ schema, data, pageCount = 1, total, overrides, enableRowSel
|
|
|
4252
4410
|
]
|
|
4253
4411
|
})]
|
|
4254
4412
|
}),
|
|
4255
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTable, {
|
|
4413
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTable, {
|
|
4414
|
+
table,
|
|
4415
|
+
classNames
|
|
4416
|
+
}),
|
|
4256
4417
|
enableRowSelection && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutoTableActionBar, {
|
|
4257
4418
|
table,
|
|
4258
4419
|
onDeleteSelected,
|
|
@@ -4272,16 +4433,16 @@ function AutoTable({ schema, data, pageCount = 1, total, overrides, enableRowSel
|
|
|
4272
4433
|
//#endregion
|
|
4273
4434
|
//#region src/components/auto-crud/form-modal.tsx
|
|
4274
4435
|
function FormModal({ open, onOpenChange, title, description, children, variant = "dialog", side = "right", className, footer }) {
|
|
4275
|
-
if (variant === "sheet") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
4436
|
+
if (variant === "sheet") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.Sheet, {
|
|
4276
4437
|
open,
|
|
4277
4438
|
onOpenChange,
|
|
4278
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
4439
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_ui.SheetContent, {
|
|
4279
4440
|
side,
|
|
4280
4441
|
className: cn("sm:max-w-lg flex flex-col p-0", className),
|
|
4281
4442
|
children: [
|
|
4282
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
4443
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_ui.SheetHeader, {
|
|
4283
4444
|
className: "flex-shrink-0 px-6 pt-6",
|
|
4284
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
4445
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.SheetTitle, { children: title }), description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.SheetDescription, { children: description })]
|
|
4285
4446
|
}),
|
|
4286
4447
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4287
4448
|
className: "flex-1 overflow-y-auto min-h-0",
|
|
@@ -4297,15 +4458,15 @@ function FormModal({ open, onOpenChange, title, description, children, variant =
|
|
|
4297
4458
|
]
|
|
4298
4459
|
})
|
|
4299
4460
|
});
|
|
4300
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
4461
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.Dialog, {
|
|
4301
4462
|
open,
|
|
4302
4463
|
onOpenChange,
|
|
4303
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
4464
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_ui.DialogContent, {
|
|
4304
4465
|
className: cn("max-w-2xl sm:max-w-2xl flex flex-col max-h-[85vh] overflow-hidden p-0", className),
|
|
4305
4466
|
children: [
|
|
4306
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
4467
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_ui.DialogHeader, {
|
|
4307
4468
|
className: "flex-shrink-0 px-6 pt-6",
|
|
4308
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
4469
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.DialogTitle, { children: title }), description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.DialogDescription, { children: description })]
|
|
4309
4470
|
}),
|
|
4310
4471
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4311
4472
|
className: "flex-1 overflow-y-auto min-h-0",
|
|
@@ -5481,6 +5642,31 @@ function CrudFormModal({ open, onOpenChange, mode, schema, initialValues, onSubm
|
|
|
5481
5642
|
});
|
|
5482
5643
|
}
|
|
5483
5644
|
|
|
5645
|
+
//#endregion
|
|
5646
|
+
//#region src/lib/row-action-dialog.tsx
|
|
5647
|
+
/** Keep custom dialogs at table level, independently of the source row's lifetime. */
|
|
5648
|
+
function useRowActionDialog() {
|
|
5649
|
+
const [dialog, setDialog] = react.useState(null);
|
|
5650
|
+
const session = react.useRef(0);
|
|
5651
|
+
return {
|
|
5652
|
+
openComponent: react.useCallback((next) => {
|
|
5653
|
+
const id = ++session.current;
|
|
5654
|
+
const dismiss = () => {
|
|
5655
|
+
if (session.current === id) setDialog(null);
|
|
5656
|
+
};
|
|
5657
|
+
setDialog(react.cloneElement(next, {
|
|
5658
|
+
key: id,
|
|
5659
|
+
open: true,
|
|
5660
|
+
onOpenChange: (open) => {
|
|
5661
|
+
if (!open) dismiss();
|
|
5662
|
+
},
|
|
5663
|
+
onDismiss: dismiss
|
|
5664
|
+
}));
|
|
5665
|
+
}, []),
|
|
5666
|
+
dialog
|
|
5667
|
+
};
|
|
5668
|
+
}
|
|
5669
|
+
|
|
5484
5670
|
//#endregion
|
|
5485
5671
|
//#region src/components/auto-crud/import-dialog.tsx
|
|
5486
5672
|
function ImportDialog({ open, onOpenChange, onImport, columns = [], title, locale = zhCN.importDialog }) {
|
|
@@ -5837,22 +6023,29 @@ function isCustomAction$1(action$1) {
|
|
|
5837
6023
|
return action$1.type === "custom";
|
|
5838
6024
|
}
|
|
5839
6025
|
function resolveActions$1(targetId, zone, ownerActions) {
|
|
5840
|
-
const
|
|
5841
|
-
|
|
5842
|
-
const
|
|
6026
|
+
const registered = targetId ? crudActions.get(targetId, zone) : [];
|
|
6027
|
+
const hiddenCustomIds = new Set(registered.flatMap(({ action: action$1 }) => isCustomAction$1(action$1) && action$1.hidden && action$1.id ? [action$1.id] : []));
|
|
6028
|
+
const isMaskedCustom = (action$1) => isCustomAction$1(action$1) && Boolean(action$1.id && hiddenCustomIds.has(action$1.id));
|
|
6029
|
+
const customOverrides = /* @__PURE__ */ new Map();
|
|
6030
|
+
for (const entry of registered) {
|
|
6031
|
+
const { action: action$1 } = entry;
|
|
6032
|
+
if (isCustomAction$1(action$1) && action$1.id && !isMaskedCustom(action$1)) customOverrides.set(action$1.id, entry);
|
|
6033
|
+
}
|
|
6034
|
+
const ownerCustomIds = new Set(ownerActions.flatMap((action$1) => isCustomAction$1(action$1) && action$1.id ? [action$1.id] : []));
|
|
6035
|
+
const baseActions = ownerActions.filter((action$1) => !action$1.hidden && !isMaskedCustom(action$1)).map((action$1) => withoutRegistryMeta(isCustomAction$1(action$1) && action$1.id ? customOverrides.get(action$1.id)?.action ?? action$1 : action$1));
|
|
6036
|
+
const isReplacedCustom = ({ action: action$1, seq: seq$1 }) => isCustomAction$1(action$1) && Boolean(action$1.id && (ownerCustomIds.has(action$1.id) || customOverrides.get(action$1.id)?.seq !== seq$1));
|
|
5843
6037
|
if (registered.length === 0) return baseActions;
|
|
5844
6038
|
const nextActions = [...baseActions];
|
|
5845
6039
|
const startCustomActions = [];
|
|
5846
6040
|
const endCustomActions = [];
|
|
6041
|
+
const groups = /* @__PURE__ */ new Map();
|
|
5847
6042
|
for (const entry of registered) {
|
|
6043
|
+
if (isMaskedCustom(entry.action)) continue;
|
|
6044
|
+
const group = groups.get(entry.ownerId) ?? [];
|
|
6045
|
+
group.push(entry);
|
|
6046
|
+
groups.set(entry.ownerId, group);
|
|
5848
6047
|
const action$1 = entry.action;
|
|
5849
|
-
if (
|
|
5850
|
-
if (isCustomAction$1(action$1)) {
|
|
5851
|
-
const custom = withoutRegistryMeta(action$1);
|
|
5852
|
-
if (custom.position === "start") startCustomActions.push(custom);
|
|
5853
|
-
else endCustomActions.push(custom);
|
|
5854
|
-
continue;
|
|
5855
|
-
}
|
|
6048
|
+
if (isCustomAction$1(action$1)) continue;
|
|
5856
6049
|
const existingIndex = nextActions.findIndex((item) => item.type === action$1.type);
|
|
5857
6050
|
if (action$1.hidden) {
|
|
5858
6051
|
if (existingIndex >= 0) nextActions.splice(existingIndex, 1);
|
|
@@ -5865,6 +6058,31 @@ function resolveActions$1(targetId, zone, ownerActions) {
|
|
|
5865
6058
|
};
|
|
5866
6059
|
else nextActions.push(builtin);
|
|
5867
6060
|
}
|
|
6061
|
+
for (const group of groups.values()) {
|
|
6062
|
+
const items = group.sort((left, right) => left.seq - right.seq).flatMap((entry) => {
|
|
6063
|
+
const { action: action$1 } = entry;
|
|
6064
|
+
if (action$1.hidden || isReplacedCustom(entry)) return [];
|
|
6065
|
+
if (isCustomAction$1(action$1)) return [withoutRegistryMeta(action$1)];
|
|
6066
|
+
const builtin = nextActions.find((item) => item.type === action$1.type);
|
|
6067
|
+
return builtin ? [builtin] : [];
|
|
6068
|
+
});
|
|
6069
|
+
const firstBuiltin = items.find((item) => !isCustomAction$1(item));
|
|
6070
|
+
if (firstBuiltin) {
|
|
6071
|
+
let cursor = nextActions.indexOf(firstBuiltin);
|
|
6072
|
+
for (const item of items) {
|
|
6073
|
+
const existing = nextActions.indexOf(item);
|
|
6074
|
+
if (existing >= cursor) cursor = existing + 1;
|
|
6075
|
+
else {
|
|
6076
|
+
if (existing >= 0) {
|
|
6077
|
+
nextActions.splice(existing, 1);
|
|
6078
|
+
cursor -= 1;
|
|
6079
|
+
}
|
|
6080
|
+
nextActions.splice(cursor, 0, item);
|
|
6081
|
+
cursor += 1;
|
|
6082
|
+
}
|
|
6083
|
+
}
|
|
6084
|
+
} else for (const custom of items) (custom.position === "start" ? startCustomActions : endCustomActions).push(custom);
|
|
6085
|
+
}
|
|
5868
6086
|
return [
|
|
5869
6087
|
...startCustomActions,
|
|
5870
6088
|
...nextActions,
|
|
@@ -6136,13 +6354,6 @@ function mergeFieldOptions(current, incoming) {
|
|
|
6136
6354
|
if ((!current || current.length === 0) && (!incoming || incoming.length === 0)) return;
|
|
6137
6355
|
return mergeFilterOptions(current, incoming ?? []);
|
|
6138
6356
|
}
|
|
6139
|
-
function mergeOptionsByField(left, right) {
|
|
6140
|
-
const keys = new Set([...Object.keys(left ?? {}), ...Object.keys(right ?? {})]);
|
|
6141
|
-
return Object.fromEntries(Array.from(keys).flatMap((key) => {
|
|
6142
|
-
const options = mergeFieldOptions(left?.[key], right?.[key]);
|
|
6143
|
-
return options ? [[key, options]] : [];
|
|
6144
|
-
}));
|
|
6145
|
-
}
|
|
6146
6357
|
function shouldResolveOptions(field, config, hiddenColumns) {
|
|
6147
6358
|
if (!config) return false;
|
|
6148
6359
|
if (hiddenColumns.has(field)) return false;
|
|
@@ -6500,6 +6711,7 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
|
|
|
6500
6711
|
const mergedSharedDynamicOptions = mergeFieldOptions(dynamicFilterLabelOptions, tableConfig?.dataSource ? void 0 : dynamicResolveOptions);
|
|
6501
6712
|
const dynamicOptions = !fieldOptions && mergedSharedDynamicOptions ? toTableOptions(mergedSharedDynamicOptions) : void 0;
|
|
6502
6713
|
const tableMeta = config.table !== false && typeof config.table === "object" ? config.table.meta : void 0;
|
|
6714
|
+
const tableClassNames = tableConfig?.classNames;
|
|
6503
6715
|
const fieldEnumMeta = tableOptions ? {
|
|
6504
6716
|
options: tableOptions,
|
|
6505
6717
|
variant: "multiSelect"
|
|
@@ -6539,13 +6751,14 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
|
|
|
6539
6751
|
enableColumnFilter: false
|
|
6540
6752
|
};
|
|
6541
6753
|
}
|
|
6542
|
-
if (fieldEnumMeta || fieldDataSourceMeta || tableMeta || filterMeta) result[key] = {
|
|
6754
|
+
if (fieldEnumMeta || fieldDataSourceMeta || tableMeta || tableClassNames !== void 0 || filterMeta) result[key] = {
|
|
6543
6755
|
...result[key],
|
|
6544
6756
|
meta: {
|
|
6545
6757
|
...result[key]?.meta ?? {},
|
|
6546
6758
|
...fieldEnumMeta ?? {},
|
|
6547
6759
|
...fieldDataSourceMeta ?? {},
|
|
6548
6760
|
...tableMeta ?? {},
|
|
6761
|
+
...tableClassNames !== void 0 ? { classNames: tableClassNames } : {},
|
|
6549
6762
|
...filterMeta ?? {}
|
|
6550
6763
|
}
|
|
6551
6764
|
};
|
|
@@ -6563,6 +6776,7 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
|
|
|
6563
6776
|
};
|
|
6564
6777
|
else if (config.table && typeof config.table === "object") {
|
|
6565
6778
|
const { meta, display,...tableProps } = config.table;
|
|
6779
|
+
delete tableProps.classNames;
|
|
6566
6780
|
delete tableProps.options;
|
|
6567
6781
|
delete tableProps.dataSource;
|
|
6568
6782
|
result[key] = {
|
|
@@ -6595,7 +6809,7 @@ function buildCapabilityTableOverrides(schema, capabilities) {
|
|
|
6595
6809
|
const override = {};
|
|
6596
6810
|
if (capabilities.filters) {
|
|
6597
6811
|
if (!capabilities.filters.enabled) override.enableColumnFilter = false;
|
|
6598
|
-
else if (filterSet) override.enableColumnFilter =
|
|
6812
|
+
else if (filterSet && !filterSet.has(key)) override.enableColumnFilter = false;
|
|
6599
6813
|
}
|
|
6600
6814
|
if (capabilities.sort) {
|
|
6601
6815
|
if (!capabilities.sort.enabled) override.enableSorting = false;
|
|
@@ -6679,7 +6893,7 @@ function buildBatchUpdateFields(schema, batchFields, fields) {
|
|
|
6679
6893
|
/**
|
|
6680
6894
|
* 渲染字段值
|
|
6681
6895
|
*/
|
|
6682
|
-
function renderFieldValue(value, type, booleanLocale, options, display = "auto") {
|
|
6896
|
+
function renderFieldValue(value, type, booleanLocale, options, display = "auto", maxItems = 5) {
|
|
6683
6897
|
if (value === null || value === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6684
6898
|
className: "text-muted-foreground",
|
|
6685
6899
|
children: "-"
|
|
@@ -6694,12 +6908,12 @@ function renderFieldValue(value, type, booleanLocale, options, display = "auto")
|
|
|
6694
6908
|
if (display === "badge" && (!options || options.length === 0)) {
|
|
6695
6909
|
if (Array.isArray(value)) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6696
6910
|
className: "flex gap-1 flex-wrap",
|
|
6697
|
-
children: [value.slice(0,
|
|
6911
|
+
children: [value.slice(0, maxItems).map((item, index$1) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Badge, {
|
|
6698
6912
|
variant: "secondary",
|
|
6699
6913
|
children: String(item)
|
|
6700
|
-
}, index$1)), value.length >
|
|
6914
|
+
}, index$1)), value.length > maxItems && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Badge, {
|
|
6701
6915
|
variant: "outline",
|
|
6702
|
-
children: ["+", value.length -
|
|
6916
|
+
children: ["+", value.length - maxItems]
|
|
6703
6917
|
})]
|
|
6704
6918
|
});
|
|
6705
6919
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Badge, {
|
|
@@ -6711,14 +6925,29 @@ function renderFieldValue(value, type, booleanLocale, options, display = "auto")
|
|
|
6711
6925
|
if ((display === "badge" || display === "auto") && options && options.length > 0) {
|
|
6712
6926
|
if (Array.isArray(value)) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6713
6927
|
className: "flex gap-1 flex-wrap",
|
|
6714
|
-
children: [value.slice(0,
|
|
6928
|
+
children: [value.slice(0, maxItems).map((v, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Badge, {
|
|
6715
6929
|
variant: "secondary",
|
|
6716
6930
|
children: getOptionLabel(v, options)
|
|
6717
|
-
}, i)), value.length >
|
|
6931
|
+
}, i)), value.length > maxItems && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Badge, {
|
|
6718
6932
|
variant: "outline",
|
|
6719
|
-
children: ["+", value.length -
|
|
6933
|
+
children: ["+", value.length - maxItems]
|
|
6720
6934
|
})]
|
|
6721
6935
|
});
|
|
6936
|
+
const tone = options.find((option) => option.value === String(value))?.badgeTone;
|
|
6937
|
+
const toneClassName = tone && {
|
|
6938
|
+
neutral: "border-border bg-muted text-muted-foreground",
|
|
6939
|
+
success: "border-emerald-200 bg-emerald-50 text-emerald-700 dark:border-emerald-800 dark:bg-emerald-950 dark:text-emerald-300",
|
|
6940
|
+
warning: "border-amber-200 bg-amber-50 text-amber-700 dark:border-amber-800 dark:bg-amber-950 dark:text-amber-300",
|
|
6941
|
+
info: "border-blue-200 bg-blue-50 text-blue-700 dark:border-blue-800 dark:bg-blue-950 dark:text-blue-300"
|
|
6942
|
+
}[tone];
|
|
6943
|
+
if (toneClassName) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Badge, {
|
|
6944
|
+
variant: "outline",
|
|
6945
|
+
className: toneClassName,
|
|
6946
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6947
|
+
"aria-hidden": "true",
|
|
6948
|
+
className: "size-1.5 shrink-0 rounded-full bg-current"
|
|
6949
|
+
}), getOptionLabel(value, options)]
|
|
6950
|
+
});
|
|
6722
6951
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Badge, {
|
|
6723
6952
|
variant: "outline",
|
|
6724
6953
|
className: "capitalize",
|
|
@@ -6735,48 +6964,81 @@ function renderFieldValue(value, type, booleanLocale, options, display = "auto")
|
|
|
6735
6964
|
});
|
|
6736
6965
|
case "array": return Array.isArray(value) ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6737
6966
|
className: "flex gap-1 flex-wrap",
|
|
6738
|
-
children: [value.slice(0,
|
|
6967
|
+
children: [value.slice(0, maxItems).map((v, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Badge, {
|
|
6739
6968
|
variant: "secondary",
|
|
6740
6969
|
children: String(v)
|
|
6741
|
-
}, i)), value.length >
|
|
6970
|
+
}, i)), value.length > maxItems && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Badge, {
|
|
6742
6971
|
variant: "outline",
|
|
6743
|
-
children: ["+", value.length -
|
|
6972
|
+
children: ["+", value.length - maxItems]
|
|
6744
6973
|
})]
|
|
6745
6974
|
}) : null;
|
|
6746
6975
|
default: return String(value);
|
|
6747
6976
|
}
|
|
6748
6977
|
}
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
*/
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
const
|
|
6755
|
-
|
|
6978
|
+
function ViewModal(props) {
|
|
6979
|
+
if (!props.open || !props.data) return null;
|
|
6980
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ViewModalContent, { ...props });
|
|
6981
|
+
}
|
|
6982
|
+
function ViewModalContent({ open, onOpenChange, variant, data, schema, fields: fieldConfig, dynamicOptions, denyFields, locale, tableOverrides, view }) {
|
|
6983
|
+
const excluded = react.useMemo(() => {
|
|
6984
|
+
const denied = new Set(denyFields ?? []);
|
|
6985
|
+
return Object.keys(schema.shape).filter((key) => {
|
|
6986
|
+
const config = fieldConfig?.[key];
|
|
6987
|
+
return denied.has(key) || config?.hidden || view?.overrides?.[key]?.hidden || isDefaultHiddenAuditField(key) && !isFieldTableExplicitlyVisible(config) && view?.overrides?.[key]?.hidden !== false;
|
|
6988
|
+
});
|
|
6989
|
+
}, [
|
|
6990
|
+
schema,
|
|
6991
|
+
fieldConfig,
|
|
6992
|
+
denyFields,
|
|
6993
|
+
view?.overrides
|
|
6994
|
+
]);
|
|
6995
|
+
const rows = react.useMemo(() => data ? [data] : [], [data]);
|
|
6996
|
+
const resolvedOptions = useDynamicResolveOptions(fieldConfig, rows, excluded);
|
|
6756
6997
|
const content = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dl", {
|
|
6757
6998
|
className: "grid gap-4 py-4",
|
|
6758
|
-
children:
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6999
|
+
children: (0, __tanstack_react_table.useReactTable)({
|
|
7000
|
+
data: rows,
|
|
7001
|
+
columns: react.useMemo(() => {
|
|
7002
|
+
const overrides = {};
|
|
7003
|
+
for (const [key, fieldSchema] of Object.entries(schema.shape).filter(([fieldKey]) => !excluded.includes(fieldKey))) {
|
|
7004
|
+
const config = fieldConfig?.[key] ?? {};
|
|
7005
|
+
const tableConfig = getTableConfig(config);
|
|
7006
|
+
const listOverride = tableOverrides?.[key];
|
|
7007
|
+
const options = getTableOptions(config) ?? resolvedOptions.optionsByField[key] ?? (tableConfig?.dataSource !== void 0 ? void 0 : dynamicOptions?.[key]);
|
|
7008
|
+
overrides[key] = {
|
|
7009
|
+
label: tableConfig?.label ?? config.label ?? listOverride?.label ?? humanize(key),
|
|
7010
|
+
index: tableConfig?.index ?? listOverride?.index,
|
|
7011
|
+
cell: ({ getValue }) => renderFieldValue(getValue(), parseZodField(fieldSchema).type, locale.boolean, options, tableConfig?.display ?? "auto", Infinity),
|
|
7012
|
+
...view?.presentation === "table" ? listOverride : void 0,
|
|
7013
|
+
hidden: false,
|
|
7014
|
+
...view?.overrides?.[key]
|
|
7015
|
+
};
|
|
7016
|
+
}
|
|
7017
|
+
return createTableSchema(schema, {
|
|
7018
|
+
overrides,
|
|
7019
|
+
exclude: excluded
|
|
7020
|
+
});
|
|
7021
|
+
}, [
|
|
7022
|
+
schema,
|
|
7023
|
+
excluded,
|
|
7024
|
+
fieldConfig,
|
|
7025
|
+
tableOverrides,
|
|
7026
|
+
view,
|
|
7027
|
+
resolvedOptions.optionsByField,
|
|
7028
|
+
dynamicOptions,
|
|
7029
|
+
locale.boolean
|
|
7030
|
+
]),
|
|
7031
|
+
getCoreRowModel: (0, __tanstack_react_table.getCoreRowModel)()
|
|
7032
|
+
}).getRowModel().rows[0]?.getAllCells().map((cell) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7033
|
+
className: "grid grid-cols-3 items-start gap-4",
|
|
7034
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", {
|
|
7035
|
+
className: "text-sm font-medium text-muted-foreground",
|
|
7036
|
+
children: cell.column.columnDef.meta?.label ?? humanize(cell.column.id)
|
|
7037
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
|
|
7038
|
+
className: "col-span-2 min-w-0 whitespace-pre-wrap break-words text-sm",
|
|
7039
|
+
children: (0, __tanstack_react_table.flexRender)(cell.column.columnDef.cell, cell.getContext())
|
|
7040
|
+
})]
|
|
7041
|
+
}, cell.id))
|
|
6780
7042
|
});
|
|
6781
7043
|
if (variant === "sheet") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Sheet, {
|
|
6782
7044
|
open,
|
|
@@ -6796,14 +7058,9 @@ function ViewModal({ open, onOpenChange, variant, data, schema, fields: fieldCon
|
|
|
6796
7058
|
/**
|
|
6797
7059
|
* 解析列表行操作
|
|
6798
7060
|
*/
|
|
6799
|
-
function resolveActions(
|
|
6800
|
-
const resolvedItems = typeof actionsOrFn === "function" ? actionsOrFn([
|
|
6801
|
-
{ type: "view" },
|
|
6802
|
-
{ type: "edit" },
|
|
6803
|
-
{ type: "copy" },
|
|
6804
|
-
{ type: "delete" }
|
|
6805
|
-
]) : actionsOrFn;
|
|
7061
|
+
function resolveActions(actions, defaults, rowActionsLocale, context) {
|
|
6806
7062
|
const getContext = (row) => ({
|
|
7063
|
+
MenuItem: __wordrhyme_ui.DropdownMenuItem,
|
|
6807
7064
|
crudId: context.crudId,
|
|
6808
7065
|
idKey: context.idKey,
|
|
6809
7066
|
row,
|
|
@@ -6811,54 +7068,13 @@ function resolveActions(actionsOrFn, defaults, rowActionsLocale, context) {
|
|
|
6811
7068
|
openView: defaults.openView,
|
|
6812
7069
|
...defaults.openEdit ? { openEdit: defaults.openEdit } : {},
|
|
6813
7070
|
...defaults.copyRow ? { copyRow: defaults.copyRow } : {},
|
|
6814
|
-
...defaults.openDelete ? { openDelete: defaults.openDelete } : {}
|
|
7071
|
+
...defaults.openDelete ? { openDelete: defaults.openDelete } : {},
|
|
7072
|
+
open: (options) => {
|
|
7073
|
+
if (options.type === "custom") context.openComponent(options.component);
|
|
7074
|
+
else handlerMap[options.type]?.(options.row);
|
|
7075
|
+
}
|
|
6815
7076
|
});
|
|
6816
|
-
const
|
|
6817
|
-
{
|
|
6818
|
-
label: rowActionsLocale.view,
|
|
6819
|
-
onClick: defaults.openView
|
|
6820
|
-
},
|
|
6821
|
-
...defaults.openEdit ? [{
|
|
6822
|
-
label: rowActionsLocale.edit,
|
|
6823
|
-
onClick: defaults.openEdit
|
|
6824
|
-
}] : [],
|
|
6825
|
-
...defaults.copyRow ? [{
|
|
6826
|
-
label: rowActionsLocale.copy,
|
|
6827
|
-
onClick: defaults.copyRow
|
|
6828
|
-
}] : [],
|
|
6829
|
-
...defaults.openDelete ? [{
|
|
6830
|
-
label: rowActionsLocale.delete,
|
|
6831
|
-
onClick: defaults.openDelete,
|
|
6832
|
-
separator: true,
|
|
6833
|
-
variant: "destructive"
|
|
6834
|
-
}] : []
|
|
6835
|
-
];
|
|
6836
|
-
if (resolvedItems === void 0) return defaultItems;
|
|
6837
|
-
const items = resolvedItems.filter((item) => !item.hidden);
|
|
6838
|
-
if (items.length === 0) return [];
|
|
6839
|
-
if (!items.some((i) => i.type !== "custom")) {
|
|
6840
|
-
const startItems = items.filter((i) => i.type === "custom" && i.position === "start").map(({ label, onClick, component, separator, variant }) => ({
|
|
6841
|
-
label,
|
|
6842
|
-
onClick,
|
|
6843
|
-
component,
|
|
6844
|
-
getContext,
|
|
6845
|
-
separator,
|
|
6846
|
-
variant
|
|
6847
|
-
}));
|
|
6848
|
-
const endItems = items.filter((i) => i.type === "custom" && i.position !== "start").map(({ label, onClick, component, separator, variant }) => ({
|
|
6849
|
-
label,
|
|
6850
|
-
onClick,
|
|
6851
|
-
component,
|
|
6852
|
-
getContext,
|
|
6853
|
-
separator,
|
|
6854
|
-
variant
|
|
6855
|
-
}));
|
|
6856
|
-
return [
|
|
6857
|
-
...startItems,
|
|
6858
|
-
...defaultItems,
|
|
6859
|
-
...endItems
|
|
6860
|
-
];
|
|
6861
|
-
}
|
|
7077
|
+
const items = actions.filter((item) => !item.hidden);
|
|
6862
7078
|
const handlerMap = {
|
|
6863
7079
|
view: defaults.openView,
|
|
6864
7080
|
edit: defaults.openEdit,
|
|
@@ -6897,7 +7113,7 @@ function resolveActions(actionsOrFn, defaults, rowActionsLocale, context) {
|
|
|
6897
7113
|
*
|
|
6898
7114
|
* 高级 CRUD 表格组件,封装了完整的增删改查流程
|
|
6899
7115
|
*/
|
|
6900
|
-
function AutoCrudTable({ id, title, description, schema, resource, fields, table: tableConfig, form: formConfig, permissions, actions: actionItems, toolbar, toolbarActions, locale: localeProp, onCreate }) {
|
|
7116
|
+
function AutoCrudTable({ id, title, description, schema, resource, fields, table: tableConfig, form: formConfig, view: viewConfig, permissions, actions: actionItems, toolbar, toolbarActions, locale: localeProp, onCreate }) {
|
|
6901
7117
|
const locale = resolveLocale(localeProp);
|
|
6902
7118
|
const resolvedSchema = resource.schema ?? schema;
|
|
6903
7119
|
const resolvedFields = react.useMemo(() => applyResourceTablePresentation(mergeFields(resource.fields, fields), resource.fields) ?? {}, [fields, resource.fields]);
|
|
@@ -6923,18 +7139,6 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
6923
7139
|
tableConfig?.overrides
|
|
6924
7140
|
]);
|
|
6925
7141
|
const dynamicResolveOptions = useDynamicResolveOptions(resolvedFields, resource.tableData.data, hiddenColumns);
|
|
6926
|
-
const sharedResolveOptions = useDynamicResolveOptions(react.useMemo(() => Object.fromEntries(Object.entries(resolvedFields).flatMap(([field, config]) => {
|
|
6927
|
-
const table = getTableConfig(config);
|
|
6928
|
-
if (table?.options === void 0 && table?.dataSource === void 0) return [];
|
|
6929
|
-
const { table: _table,...sharedConfig } = config;
|
|
6930
|
-
return [[field, sharedConfig]];
|
|
6931
|
-
})), [resolvedFields]), resource.tableData.data, hiddenColumns);
|
|
6932
|
-
const viewDynamicOptionsByField = react.useMemo(() => mergeOptionsByField(mergeOptionsByField(dynamicFilterOptions.labelOptionsByField, sharedResolveOptions.optionsByField), Object.fromEntries(Object.entries(dynamicResolveOptions.optionsByField).filter(([field]) => !getTableConfig(resolvedFields[field] ?? {})?.dataSource))), [
|
|
6933
|
-
dynamicFilterOptions.labelOptionsByField,
|
|
6934
|
-
dynamicResolveOptions.optionsByField,
|
|
6935
|
-
sharedResolveOptions.optionsByField,
|
|
6936
|
-
resolvedFields
|
|
6937
|
-
]);
|
|
6938
7142
|
const resourceIdKey = resource.idKey ?? "id";
|
|
6939
7143
|
const actionRegistryVersion = useCrudActionsVersion();
|
|
6940
7144
|
const unifiedActions = react.useMemo(() => {
|
|
@@ -7122,15 +7326,18 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
7122
7326
|
resource.handlers.openEdit,
|
|
7123
7327
|
resource.handlers.openView
|
|
7124
7328
|
]);
|
|
7329
|
+
const { openComponent, dialog: rowActionDialog } = useRowActionDialog();
|
|
7125
7330
|
const tableRowActions = react.useMemo(() => resolveActions(registryRowActions, rowActionDefaults, locale.rowActions, {
|
|
7126
7331
|
crudId: id ?? "",
|
|
7127
|
-
idKey: resourceIdKey
|
|
7332
|
+
idKey: resourceIdKey,
|
|
7333
|
+
openComponent
|
|
7128
7334
|
}), [
|
|
7129
7335
|
id,
|
|
7130
7336
|
locale.rowActions,
|
|
7131
7337
|
registryRowActions,
|
|
7132
7338
|
resourceIdKey,
|
|
7133
|
-
rowActionDefaults
|
|
7339
|
+
rowActionDefaults,
|
|
7340
|
+
openComponent
|
|
7134
7341
|
]);
|
|
7135
7342
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7136
7343
|
className: "space-y-4",
|
|
@@ -7226,6 +7433,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
7226
7433
|
pageCount: resource.tableData.pageCount,
|
|
7227
7434
|
...resource.tableData.total !== void 0 ? { total: resource.tableData.total } : {},
|
|
7228
7435
|
overrides: tableOverrides,
|
|
7436
|
+
classNames: tableConfig?.classNames,
|
|
7229
7437
|
exclude: hiddenColumns,
|
|
7230
7438
|
filterMode: tableConfig?.filterModes,
|
|
7231
7439
|
search: searchConfig,
|
|
@@ -7241,6 +7449,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
7241
7449
|
onSelectedRowsChange: handleSelectedRowsChange,
|
|
7242
7450
|
getSelectedRows: getSelectedRowsRef
|
|
7243
7451
|
}),
|
|
7452
|
+
rowActionDialog,
|
|
7244
7453
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CrudFormModal, {
|
|
7245
7454
|
open: resource.modal.createOpen || resource.modal.editOpen,
|
|
7246
7455
|
onOpenChange: (open) => !open && resource.handlers.closeModals(),
|
|
@@ -7266,9 +7475,11 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
7266
7475
|
data: resource.modal.selected,
|
|
7267
7476
|
schema: resolvedSchema,
|
|
7268
7477
|
fields: resolvedFields,
|
|
7269
|
-
dynamicOptions:
|
|
7478
|
+
dynamicOptions: dynamicFilterOptions.labelOptionsByField,
|
|
7270
7479
|
denyFields,
|
|
7271
|
-
locale
|
|
7480
|
+
locale,
|
|
7481
|
+
tableOverrides,
|
|
7482
|
+
view: viewConfig
|
|
7272
7483
|
}),
|
|
7273
7484
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.AlertDialog, {
|
|
7274
7485
|
open: resource.modal.deleteOpen,
|
|
@@ -7465,10 +7676,7 @@ function getIsDateRange(value) {
|
|
|
7465
7676
|
return value && typeof value === "object" && !Array.isArray(value);
|
|
7466
7677
|
}
|
|
7467
7678
|
function parseAsDate(timestamp) {
|
|
7468
|
-
|
|
7469
|
-
const numericTimestamp = typeof timestamp === "string" ? Number(timestamp) : timestamp;
|
|
7470
|
-
const date = new Date(numericTimestamp);
|
|
7471
|
-
return !Number.isNaN(date.getTime()) ? date : void 0;
|
|
7679
|
+
return parseCalendarDate(timestamp);
|
|
7472
7680
|
}
|
|
7473
7681
|
function parseColumnFilterValue(value) {
|
|
7474
7682
|
if (value === null || value === void 0) return [];
|
|
@@ -7479,6 +7687,9 @@ function parseColumnFilterValue(value) {
|
|
|
7479
7687
|
return [];
|
|
7480
7688
|
}
|
|
7481
7689
|
function DataTableDateFilter({ column, title, multiple }) {
|
|
7690
|
+
const formatterVersion = useDateFormatterVersion();
|
|
7691
|
+
const presentation = react.useMemo(() => calendarPresentation(), [formatterVersion]);
|
|
7692
|
+
const { formatDate: formatDate$1 } = presentation;
|
|
7482
7693
|
const columnFilterValue = column.getFilterValue();
|
|
7483
7694
|
const selectedDates = react.useMemo(() => {
|
|
7484
7695
|
if (!columnFilterValue) return multiple ? {
|
|
@@ -7552,12 +7763,12 @@ function DataTableDateFilter({ column, title, multiple }) {
|
|
|
7552
7763
|
from: nextFrom,
|
|
7553
7764
|
to: nextTo
|
|
7554
7765
|
});
|
|
7555
|
-
if (nextTo) column.setFilterValue([nextFrom
|
|
7766
|
+
if (nextTo) column.setFilterValue([serializeCalendarDate(nextFrom), serializeCalendarDate(nextTo)]);
|
|
7556
7767
|
return;
|
|
7557
7768
|
}
|
|
7558
7769
|
setLocalRange(date);
|
|
7559
|
-
if (from && to) column.setFilterValue([from, to]);
|
|
7560
|
-
} else if (!multiple && "getTime" in date) column.setFilterValue(date
|
|
7770
|
+
if (from && to) column.setFilterValue([serializeCalendarDate(new Date(from)), serializeCalendarDate(new Date(to))]);
|
|
7771
|
+
} else if (!multiple && "getTime" in date) column.setFilterValue(serializeCalendarDate(date));
|
|
7561
7772
|
}, [
|
|
7562
7773
|
column,
|
|
7563
7774
|
multiple,
|
|
@@ -7577,9 +7788,9 @@ function DataTableDateFilter({ column, title, multiple }) {
|
|
|
7577
7788
|
}, [multiple, selectedDates]);
|
|
7578
7789
|
const formatDateRange = react.useCallback((range) => {
|
|
7579
7790
|
if (!range.from && !range.to) return "";
|
|
7580
|
-
if (range.from && range.to) return `${formatDate(range.from)} - ${formatDate(range.to)}`;
|
|
7581
|
-
return formatDate(range.from ?? range.to);
|
|
7582
|
-
}, []);
|
|
7791
|
+
if (range.from && range.to) return `${formatDate$1(range.from)} - ${formatDate$1(range.to)}`;
|
|
7792
|
+
return formatDate$1(range.from ?? range.to);
|
|
7793
|
+
}, [formatDate$1]);
|
|
7583
7794
|
const label = react.useMemo(() => {
|
|
7584
7795
|
if (multiple) {
|
|
7585
7796
|
if (!getIsDateRange(selectedDates)) return null;
|
|
@@ -7595,7 +7806,7 @@ function DataTableDateFilter({ column, title, multiple }) {
|
|
|
7595
7806
|
}
|
|
7596
7807
|
if (getIsDateRange(selectedDates)) return null;
|
|
7597
7808
|
const hasSelectedDate = selectedDates.length > 0;
|
|
7598
|
-
const dateText = hasSelectedDate ? formatDate(selectedDates[0]) : "Select date";
|
|
7809
|
+
const dateText = hasSelectedDate ? formatDate$1(selectedDates[0]) : "Select date";
|
|
7599
7810
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7600
7811
|
className: "flex items-center gap-2",
|
|
7601
7812
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: title }), hasSelectedDate && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Separator, {
|
|
@@ -7607,7 +7818,8 @@ function DataTableDateFilter({ column, title, multiple }) {
|
|
|
7607
7818
|
selectedDates,
|
|
7608
7819
|
multiple,
|
|
7609
7820
|
formatDateRange,
|
|
7610
|
-
title
|
|
7821
|
+
title,
|
|
7822
|
+
formatDate$1
|
|
7611
7823
|
]);
|
|
7612
7824
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Popover, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.PopoverTrigger, {
|
|
7613
7825
|
asChild: true,
|
|
@@ -7617,7 +7829,7 @@ function DataTableDateFilter({ column, title, multiple }) {
|
|
|
7617
7829
|
className: "border-dashed font-normal",
|
|
7618
7830
|
children: [hasValue ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7619
7831
|
role: "button",
|
|
7620
|
-
"aria-label":
|
|
7832
|
+
"aria-label": presentation.clearLabel(title),
|
|
7621
7833
|
tabIndex: 0,
|
|
7622
7834
|
onClick: onReset,
|
|
7623
7835
|
className: "rounded-sm opacity-70 transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
@@ -7628,14 +7840,24 @@ function DataTableDateFilter({ column, title, multiple }) {
|
|
|
7628
7840
|
className: "w-auto p-0",
|
|
7629
7841
|
align: "start",
|
|
7630
7842
|
children: multiple ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Calendar, {
|
|
7843
|
+
lang: presentation.locale,
|
|
7844
|
+
weekStartsOn: presentation.weekStartsOn,
|
|
7845
|
+
formatters: presentation.formatters,
|
|
7846
|
+
labels: presentation.labels,
|
|
7631
7847
|
autoFocus: true,
|
|
7632
7848
|
captionLayout: "dropdown",
|
|
7633
7849
|
mode: "range",
|
|
7850
|
+
defaultMonth: localRange.from,
|
|
7634
7851
|
selected: localRange,
|
|
7635
7852
|
onSelect
|
|
7636
7853
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Calendar, {
|
|
7854
|
+
lang: presentation.locale,
|
|
7855
|
+
weekStartsOn: presentation.weekStartsOn,
|
|
7856
|
+
formatters: presentation.formatters,
|
|
7857
|
+
labels: presentation.labels,
|
|
7637
7858
|
captionLayout: "dropdown",
|
|
7638
7859
|
mode: "single",
|
|
7860
|
+
defaultMonth: !getIsDateRange(selectedDates) ? selectedDates[0] : void 0,
|
|
7639
7861
|
selected: !getIsDateRange(selectedDates) ? selectedDates[0] : void 0,
|
|
7640
7862
|
onSelect
|
|
7641
7863
|
})
|