@wordrhyme/auto-crud 1.0.0 → 1.0.1
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 +251 -119
- package/dist/index.d.cts +35 -21
- package/dist/index.d.ts +35 -21
- package/dist/index.js +251 -119
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1450,7 +1450,12 @@ function DataTableFilterList({ table, debounceMs = DEBOUNCE_MS$2, throttleMs = T
|
|
|
1450
1450
|
const [open, setOpen] = react.useState(false);
|
|
1451
1451
|
const addButtonRef = react.useRef(null);
|
|
1452
1452
|
const columns = react.useMemo(() => {
|
|
1453
|
-
return table.getAllColumns().filter((column) =>
|
|
1453
|
+
return table.getAllColumns().filter((column) => {
|
|
1454
|
+
if (!column.getCanFilter()) return false;
|
|
1455
|
+
const modes = column.columnDef.meta?.modes;
|
|
1456
|
+
if (modes && !modes.includes("advanced")) return false;
|
|
1457
|
+
return true;
|
|
1458
|
+
});
|
|
1454
1459
|
}, [table]);
|
|
1455
1460
|
const [filters, setFilters] = useReadableFilters(columns, { debounceMs });
|
|
1456
1461
|
const debouncedSetFilters = useDebouncedCallback(setFilters, debounceMs);
|
|
@@ -1932,7 +1937,12 @@ const REMOVE_FILTER_SHORTCUTS = ["backspace", "delete"];
|
|
|
1932
1937
|
function DataTableFilterMenu({ table, debounceMs = DEBOUNCE_MS$1, throttleMs = THROTTLE_MS$1, shallow = true, disabled,...props }) {
|
|
1933
1938
|
const id = react.useId();
|
|
1934
1939
|
const columns = react.useMemo(() => {
|
|
1935
|
-
return table.getAllColumns().filter((column) =>
|
|
1940
|
+
return table.getAllColumns().filter((column) => {
|
|
1941
|
+
if (!column.columnDef.enableColumnFilter) return false;
|
|
1942
|
+
const modes = column.columnDef.meta?.modes;
|
|
1943
|
+
if (modes && !modes.includes("command")) return false;
|
|
1944
|
+
return true;
|
|
1945
|
+
});
|
|
1936
1946
|
}, [table]);
|
|
1937
1947
|
const [open, setOpen] = react.useState(false);
|
|
1938
1948
|
const [selectedColumn, setSelectedColumn] = react.useState(null);
|
|
@@ -2689,7 +2699,7 @@ function DataTableViewOptions({ table, disabled,...props }) {
|
|
|
2689
2699
|
//#endregion
|
|
2690
2700
|
//#region src/components/auto-crud/auto-table-simple-filters.tsx
|
|
2691
2701
|
function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilters, onFiltersChange }) {
|
|
2692
|
-
const columns = react.useMemo(() => table.getAllColumns().filter((col) => col.
|
|
2702
|
+
const columns = react.useMemo(() => table.getAllColumns().filter((col) => col.getCanFilter()), [table]);
|
|
2693
2703
|
const queryStateOptions = table.options.meta?.queryStateOptions;
|
|
2694
2704
|
const [queryFilters, setQueryFilters] = useReadableFilters(columns, {
|
|
2695
2705
|
...queryStateOptions,
|
|
@@ -2709,9 +2719,10 @@ function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilte
|
|
|
2709
2719
|
react.useEffect(() => {
|
|
2710
2720
|
setMounted(true);
|
|
2711
2721
|
}, []);
|
|
2712
|
-
const
|
|
2713
|
-
|
|
2714
|
-
|
|
2722
|
+
const filterMap = react.useMemo(() => new Map(filters.map((f) => [f.id, f])), [filters]);
|
|
2723
|
+
const getFilterValue = react.useCallback((columnId) => {
|
|
2724
|
+
return filterMap.get(columnId)?.value;
|
|
2725
|
+
}, [filterMap]);
|
|
2715
2726
|
const updateFilter = react.useCallback((columnId, value) => {
|
|
2716
2727
|
const column = columns.find((c) => c.id === columnId);
|
|
2717
2728
|
if (!column) return;
|
|
@@ -2734,7 +2745,14 @@ function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilte
|
|
|
2734
2745
|
setFilters
|
|
2735
2746
|
]);
|
|
2736
2747
|
const hasFilters = filters.length > 0;
|
|
2737
|
-
const filterColumns = react.useMemo(() => columns.filter((col) =>
|
|
2748
|
+
const filterColumns = react.useMemo(() => columns.filter((col) => {
|
|
2749
|
+
const meta = col.columnDef.meta;
|
|
2750
|
+
const enableFilter = col.columnDef.enableColumnFilter !== false;
|
|
2751
|
+
if (!meta?.variant || !enableFilter) return false;
|
|
2752
|
+
const modes = meta.modes;
|
|
2753
|
+
if (modes && !modes.includes("simple")) return false;
|
|
2754
|
+
return true;
|
|
2755
|
+
}), [columns]);
|
|
2738
2756
|
const [expanded, setExpanded] = react.useState(false);
|
|
2739
2757
|
const [visibleCount, setVisibleCount] = react.useState(null);
|
|
2740
2758
|
const containerRef = react.useRef(null);
|
|
@@ -2874,7 +2892,7 @@ function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilte
|
|
|
2874
2892
|
}
|
|
2875
2893
|
function SimpleFacetedFilter({ title, options, multiple, value, onChange }) {
|
|
2876
2894
|
const [open, setOpen] = react.useState(false);
|
|
2877
|
-
const selectedValues = new Set(value);
|
|
2895
|
+
const selectedValues = react.useMemo(() => new Set(value), [value]);
|
|
2878
2896
|
const onItemSelect = (option, isSelected) => {
|
|
2879
2897
|
if (multiple) {
|
|
2880
2898
|
const newValues = new Set(selectedValues);
|
|
@@ -2905,6 +2923,12 @@ function SimpleFacetedFilter({ title, options, multiple, value, onChange }) {
|
|
|
2905
2923
|
tabIndex: 0,
|
|
2906
2924
|
className: "rounded-sm opacity-70 hover:opacity-100",
|
|
2907
2925
|
onClick: onReset,
|
|
2926
|
+
onKeyDown: (e) => {
|
|
2927
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
2928
|
+
e.preventDefault();
|
|
2929
|
+
onReset(e);
|
|
2930
|
+
}
|
|
2931
|
+
},
|
|
2908
2932
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.XCircle, {})
|
|
2909
2933
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.PlusCircle, {}),
|
|
2910
2934
|
title,
|
|
@@ -3012,6 +3036,12 @@ function SimpleSliderFilter({ title, range, unit, value, onChange }) {
|
|
|
3012
3036
|
tabIndex: 0,
|
|
3013
3037
|
className: "rounded-sm opacity-70 hover:opacity-100",
|
|
3014
3038
|
onClick: onReset,
|
|
3039
|
+
onKeyDown: (e) => {
|
|
3040
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
3041
|
+
e.preventDefault();
|
|
3042
|
+
onReset(e);
|
|
3043
|
+
}
|
|
3044
|
+
},
|
|
3015
3045
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.XCircle, {})
|
|
3016
3046
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.PlusCircle, {}),
|
|
3017
3047
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: title }),
|
|
@@ -3135,6 +3165,12 @@ function SimpleDateFilter({ title, multiple, value, onChange }) {
|
|
|
3135
3165
|
tabIndex: 0,
|
|
3136
3166
|
className: "rounded-sm opacity-70 hover:opacity-100",
|
|
3137
3167
|
onClick: onReset,
|
|
3168
|
+
onKeyDown: (e) => {
|
|
3169
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
3170
|
+
e.preventDefault();
|
|
3171
|
+
onReset(e);
|
|
3172
|
+
}
|
|
3173
|
+
},
|
|
3138
3174
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.XCircle, {})
|
|
3139
3175
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.CalendarIcon, {}),
|
|
3140
3176
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: title }),
|
|
@@ -3747,33 +3783,47 @@ function inferFilterVariantByFieldName(fieldName) {
|
|
|
3747
3783
|
|
|
3748
3784
|
//#endregion
|
|
3749
3785
|
//#region src/lib/schema-bridge/zod-to-columns.tsx
|
|
3786
|
+
const parsedFieldCache = /* @__PURE__ */ new WeakMap();
|
|
3787
|
+
const baseTableSchemaCache = /* @__PURE__ */ new WeakMap();
|
|
3750
3788
|
/**
|
|
3751
3789
|
* 解析 Zod 字段类型
|
|
3752
3790
|
*/
|
|
3753
3791
|
function parseZodField(schema) {
|
|
3792
|
+
const cached = parsedFieldCache.get(schema);
|
|
3793
|
+
if (cached) return cached;
|
|
3794
|
+
const finalize = (result) => {
|
|
3795
|
+
parsedFieldCache.set(schema, result);
|
|
3796
|
+
return result;
|
|
3797
|
+
};
|
|
3754
3798
|
const def = schema._zod?.def ?? schema._def;
|
|
3755
|
-
const testNull = schema.safeParse(null);
|
|
3756
|
-
const required = !schema.safeParse(void 0).success && !testNull.success;
|
|
3757
3799
|
const typeName = def?.typeName;
|
|
3758
|
-
|
|
3800
|
+
const isOptional = def?.type === "optional" || typeName === "ZodOptional";
|
|
3801
|
+
const isNullable = def?.type === "nullable" || typeName === "ZodNullable";
|
|
3802
|
+
if (isOptional || isNullable) {
|
|
3759
3803
|
const innerType = def?.innerType;
|
|
3760
|
-
if (innerType) return {
|
|
3804
|
+
if (innerType) return finalize({
|
|
3761
3805
|
...parseZodField(innerType),
|
|
3762
3806
|
required: false
|
|
3763
|
-
};
|
|
3807
|
+
});
|
|
3808
|
+
}
|
|
3809
|
+
let required;
|
|
3810
|
+
if (isOptional || isNullable) required = false;
|
|
3811
|
+
else {
|
|
3812
|
+
const testNull = schema.safeParse(null);
|
|
3813
|
+
required = !schema.safeParse(void 0).success && !testNull.success;
|
|
3764
3814
|
}
|
|
3765
|
-
if (def?.type === "boolean") return {
|
|
3815
|
+
if (def?.type === "boolean") return finalize({
|
|
3766
3816
|
type: "boolean",
|
|
3767
3817
|
required
|
|
3768
|
-
};
|
|
3769
|
-
if (def?.type === "number") return {
|
|
3818
|
+
});
|
|
3819
|
+
if (def?.type === "number") return finalize({
|
|
3770
3820
|
type: "number",
|
|
3771
3821
|
required
|
|
3772
|
-
};
|
|
3773
|
-
if (def?.type === "date") return {
|
|
3822
|
+
});
|
|
3823
|
+
if (def?.type === "date") return finalize({
|
|
3774
3824
|
type: "date",
|
|
3775
3825
|
required
|
|
3776
|
-
};
|
|
3826
|
+
});
|
|
3777
3827
|
if (def?.type === "enum") {
|
|
3778
3828
|
let enumValues$1;
|
|
3779
3829
|
if (def?.entries) {
|
|
@@ -3784,20 +3834,20 @@ function parseZodField(schema) {
|
|
|
3784
3834
|
const values = def.values;
|
|
3785
3835
|
if (Array.isArray(values)) enumValues$1 = values.map(String);
|
|
3786
3836
|
}
|
|
3787
|
-
if (enumValues$1 && enumValues$1.length > 0) return {
|
|
3837
|
+
if (enumValues$1 && enumValues$1.length > 0) return finalize({
|
|
3788
3838
|
type: "enum",
|
|
3789
3839
|
required,
|
|
3790
3840
|
enumValues: enumValues$1
|
|
3791
|
-
};
|
|
3841
|
+
});
|
|
3792
3842
|
}
|
|
3793
|
-
if (def?.type === "string") return {
|
|
3843
|
+
if (def?.type === "string") return finalize({
|
|
3794
3844
|
type: "string",
|
|
3795
3845
|
required
|
|
3796
|
-
};
|
|
3797
|
-
if (typeName === "ZodBoolean") return {
|
|
3846
|
+
});
|
|
3847
|
+
if (typeName === "ZodBoolean") return finalize({
|
|
3798
3848
|
type: "boolean",
|
|
3799
3849
|
required
|
|
3800
|
-
};
|
|
3850
|
+
});
|
|
3801
3851
|
let enumValues;
|
|
3802
3852
|
if (def?.entries) {
|
|
3803
3853
|
const entries = def.entries;
|
|
@@ -3807,51 +3857,51 @@ function parseZodField(schema) {
|
|
|
3807
3857
|
const values = def.values;
|
|
3808
3858
|
if (Array.isArray(values)) enumValues = values.map(String);
|
|
3809
3859
|
}
|
|
3810
|
-
if (enumValues && Array.isArray(enumValues) && enumValues.length > 0) return {
|
|
3860
|
+
if (enumValues && Array.isArray(enumValues) && enumValues.length > 0) return finalize({
|
|
3811
3861
|
type: "enum",
|
|
3812
3862
|
required,
|
|
3813
3863
|
enumValues
|
|
3814
|
-
};
|
|
3815
|
-
if (typeName === "ZodNumber") return {
|
|
3864
|
+
});
|
|
3865
|
+
if (typeName === "ZodNumber") return finalize({
|
|
3816
3866
|
type: "number",
|
|
3817
3867
|
required
|
|
3818
|
-
};
|
|
3819
|
-
if (typeName === "ZodDate") return {
|
|
3868
|
+
});
|
|
3869
|
+
if (typeName === "ZodDate") return finalize({
|
|
3820
3870
|
type: "date",
|
|
3821
3871
|
required
|
|
3822
|
-
};
|
|
3823
|
-
if (typeName === "ZodArray") return {
|
|
3872
|
+
});
|
|
3873
|
+
if (typeName === "ZodArray") return finalize({
|
|
3824
3874
|
type: "array",
|
|
3825
3875
|
required
|
|
3826
|
-
};
|
|
3827
|
-
if (typeName === "ZodObject") return {
|
|
3876
|
+
});
|
|
3877
|
+
if (typeName === "ZodObject") return finalize({
|
|
3828
3878
|
type: "object",
|
|
3829
3879
|
required
|
|
3830
|
-
};
|
|
3880
|
+
});
|
|
3831
3881
|
const testString = schema.safeParse("test");
|
|
3832
3882
|
const testNumber = schema.safeParse(123);
|
|
3833
3883
|
const testBoolean = schema.safeParse(true);
|
|
3834
3884
|
const testDate = schema.safeParse(17040672e5);
|
|
3835
|
-
if (testBoolean.success && !testString.success && !testNumber.success) return {
|
|
3885
|
+
if (testBoolean.success && !testString.success && !testNumber.success) return finalize({
|
|
3836
3886
|
type: "boolean",
|
|
3837
3887
|
required
|
|
3838
|
-
};
|
|
3839
|
-
if (testDate.success && !testString.success) return {
|
|
3888
|
+
});
|
|
3889
|
+
if (testDate.success && !testString.success) return finalize({
|
|
3840
3890
|
type: "date",
|
|
3841
3891
|
required
|
|
3842
|
-
};
|
|
3843
|
-
if (testNumber.success && !testString.success) return {
|
|
3892
|
+
});
|
|
3893
|
+
if (testNumber.success && !testString.success) return finalize({
|
|
3844
3894
|
type: "number",
|
|
3845
3895
|
required
|
|
3846
|
-
};
|
|
3847
|
-
if (schema.safeParse([]).success && !testString.success) return {
|
|
3896
|
+
});
|
|
3897
|
+
if (schema.safeParse([]).success && !testString.success) return finalize({
|
|
3848
3898
|
type: "array",
|
|
3849
3899
|
required
|
|
3850
|
-
};
|
|
3851
|
-
return {
|
|
3900
|
+
});
|
|
3901
|
+
return finalize({
|
|
3852
3902
|
type: "string",
|
|
3853
3903
|
required
|
|
3854
|
-
};
|
|
3904
|
+
});
|
|
3855
3905
|
}
|
|
3856
3906
|
/**
|
|
3857
3907
|
* 渲染单元格内容
|
|
@@ -3893,9 +3943,14 @@ function renderCell(value, type) {
|
|
|
3893
3943
|
* 从 Zod Schema 创建 Table Schema (ColumnDef 数组)
|
|
3894
3944
|
*/
|
|
3895
3945
|
function createTableSchema(schema, options) {
|
|
3946
|
+
const { overrides, exclude = [] } = options ?? {};
|
|
3947
|
+
const canCache = !(!!overrides && Object.keys(overrides).length > 0) && exclude.length === 0;
|
|
3948
|
+
if (canCache) {
|
|
3949
|
+
const cached = baseTableSchemaCache.get(schema);
|
|
3950
|
+
if (cached) return [...cached];
|
|
3951
|
+
}
|
|
3896
3952
|
const shape = schema.shape;
|
|
3897
3953
|
const columns = [];
|
|
3898
|
-
const { overrides, exclude = [] } = options ?? {};
|
|
3899
3954
|
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
3900
3955
|
if (exclude.includes(key)) continue;
|
|
3901
3956
|
const override = overrides?.[key];
|
|
@@ -3930,6 +3985,7 @@ function createTableSchema(schema, options) {
|
|
|
3930
3985
|
...restOverride
|
|
3931
3986
|
});
|
|
3932
3987
|
}
|
|
3988
|
+
if (canCache) baseTableSchemaCache.set(schema, columns);
|
|
3933
3989
|
return columns;
|
|
3934
3990
|
}
|
|
3935
3991
|
/**
|
|
@@ -4446,6 +4502,13 @@ function useDataTable(props) {
|
|
|
4446
4502
|
filterableColumns,
|
|
4447
4503
|
enableAdvancedFilter
|
|
4448
4504
|
]);
|
|
4505
|
+
const getCoreRowModelFn = react.useMemo(() => (0, __tanstack_react_table.getCoreRowModel)(), []);
|
|
4506
|
+
const getFilteredRowModelFn = react.useMemo(() => (0, __tanstack_react_table.getFilteredRowModel)(), []);
|
|
4507
|
+
const getPaginationRowModelFn = react.useMemo(() => (0, __tanstack_react_table.getPaginationRowModel)(), []);
|
|
4508
|
+
const getSortedRowModelFn = react.useMemo(() => (0, __tanstack_react_table.getSortedRowModel)(), []);
|
|
4509
|
+
const getFacetedRowModelFn = react.useMemo(() => (0, __tanstack_react_table.getFacetedRowModel)(), []);
|
|
4510
|
+
const getFacetedUniqueValuesFn = react.useMemo(() => (0, __tanstack_react_table.getFacetedUniqueValues)(), []);
|
|
4511
|
+
const getFacetedMinMaxValuesFn = react.useMemo(() => (0, __tanstack_react_table.getFacetedMinMaxValues)(), []);
|
|
4449
4512
|
const table = (0, __tanstack_react_table.useReactTable)({
|
|
4450
4513
|
...tableProps,
|
|
4451
4514
|
columns,
|
|
@@ -4468,13 +4531,13 @@ function useDataTable(props) {
|
|
|
4468
4531
|
onSortingChange,
|
|
4469
4532
|
onColumnFiltersChange,
|
|
4470
4533
|
onColumnVisibilityChange: setColumnVisibility,
|
|
4471
|
-
getCoreRowModel:
|
|
4472
|
-
getFilteredRowModel:
|
|
4473
|
-
getPaginationRowModel:
|
|
4474
|
-
getSortedRowModel:
|
|
4475
|
-
getFacetedRowModel:
|
|
4476
|
-
getFacetedUniqueValues:
|
|
4477
|
-
getFacetedMinMaxValues:
|
|
4534
|
+
getCoreRowModel: getCoreRowModelFn,
|
|
4535
|
+
getFilteredRowModel: getFilteredRowModelFn,
|
|
4536
|
+
getPaginationRowModel: getPaginationRowModelFn,
|
|
4537
|
+
getSortedRowModel: getSortedRowModelFn,
|
|
4538
|
+
getFacetedRowModel: getFacetedRowModelFn,
|
|
4539
|
+
getFacetedUniqueValues: getFacetedUniqueValuesFn,
|
|
4540
|
+
getFacetedMinMaxValues: getFacetedMinMaxValuesFn,
|
|
4478
4541
|
manualPagination: true,
|
|
4479
4542
|
manualSorting: true,
|
|
4480
4543
|
manualFiltering: true,
|
|
@@ -4505,6 +4568,11 @@ function useDataTable(props) {
|
|
|
4505
4568
|
|
|
4506
4569
|
//#endregion
|
|
4507
4570
|
//#region src/components/auto-crud/auto-table.tsx
|
|
4571
|
+
const DEFAULT_MODES = [
|
|
4572
|
+
"simple",
|
|
4573
|
+
"advanced",
|
|
4574
|
+
"command"
|
|
4575
|
+
];
|
|
4508
4576
|
/** 过滤模式配置 */
|
|
4509
4577
|
const filterModeConfig = {
|
|
4510
4578
|
simple: {
|
|
@@ -4524,11 +4592,7 @@ const filterModeConfig = {
|
|
|
4524
4592
|
}
|
|
4525
4593
|
};
|
|
4526
4594
|
function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode = "simple", onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, initialSorting, enableExport = true, onSelectedCountChange, getSelectedRows }) {
|
|
4527
|
-
const modes = filterMode ? Array.isArray(filterMode) ? filterMode : [filterMode] :
|
|
4528
|
-
"simple",
|
|
4529
|
-
"advanced",
|
|
4530
|
-
"command"
|
|
4531
|
-
];
|
|
4595
|
+
const modes = filterMode ? Array.isArray(filterMode) ? filterMode : [filterMode] : DEFAULT_MODES;
|
|
4532
4596
|
const [currentMode, setCurrentMode] = useQueryState("filterMode", parseAsStringEnum(modes).withDefault(modes[0] ?? "simple"));
|
|
4533
4597
|
const showToggle = modes.length > 1;
|
|
4534
4598
|
const { table, shallow, debounceMs, throttleMs } = useDataTable({
|
|
@@ -4550,13 +4614,18 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
|
|
|
4550
4614
|
]),
|
|
4551
4615
|
pageCount,
|
|
4552
4616
|
enableAdvancedFilter: true,
|
|
4553
|
-
initialState: {
|
|
4617
|
+
initialState: (0, react.useMemo)(() => ({
|
|
4554
4618
|
sorting: initialSorting,
|
|
4555
4619
|
columnPinning: pinnedColumns ?? {
|
|
4556
4620
|
left: enableRowSelection ? ["select"] : [],
|
|
4557
4621
|
right: actions ? ["actions"] : []
|
|
4558
4622
|
}
|
|
4559
|
-
},
|
|
4623
|
+
}), [
|
|
4624
|
+
initialSorting,
|
|
4625
|
+
pinnedColumns,
|
|
4626
|
+
enableRowSelection,
|
|
4627
|
+
actions
|
|
4628
|
+
]),
|
|
4560
4629
|
shallow: false,
|
|
4561
4630
|
clearOnDefault: true
|
|
4562
4631
|
});
|
|
@@ -4597,7 +4666,7 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
|
|
|
4597
4666
|
})
|
|
4598
4667
|
})
|
|
4599
4668
|
})] }) : null;
|
|
4600
|
-
const
|
|
4669
|
+
const filtersContent = (0, react.useMemo)(() => {
|
|
4601
4670
|
switch (currentMode) {
|
|
4602
4671
|
case "simple": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutoTableSimpleFilters, {
|
|
4603
4672
|
table,
|
|
@@ -4617,7 +4686,13 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
|
|
|
4617
4686
|
align: "start"
|
|
4618
4687
|
});
|
|
4619
4688
|
}
|
|
4620
|
-
}
|
|
4689
|
+
}, [
|
|
4690
|
+
currentMode,
|
|
4691
|
+
table,
|
|
4692
|
+
shallow,
|
|
4693
|
+
debounceMs,
|
|
4694
|
+
throttleMs
|
|
4695
|
+
]);
|
|
4621
4696
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4622
4697
|
className: "space-y-4",
|
|
4623
4698
|
children: [
|
|
@@ -4629,7 +4704,7 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
|
|
|
4629
4704
|
children: [currentMode !== "simple" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTableSortList, {
|
|
4630
4705
|
table,
|
|
4631
4706
|
align: "start"
|
|
4632
|
-
}),
|
|
4707
|
+
}), filtersContent]
|
|
4633
4708
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4634
4709
|
className: "flex items-center gap-2",
|
|
4635
4710
|
children: [
|
|
@@ -5218,26 +5293,51 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title = "导
|
|
|
5218
5293
|
function buildTableOverrides(fields, legacyOverrides) {
|
|
5219
5294
|
const result = { ...legacyOverrides };
|
|
5220
5295
|
if (fields) for (const [key, config] of Object.entries(fields)) {
|
|
5296
|
+
const tableMeta = config.table !== false && typeof config.table === "object" ? config.table.meta : void 0;
|
|
5221
5297
|
let filterMeta;
|
|
5222
|
-
if (config.filter && config.filter
|
|
5223
|
-
|
|
5224
|
-
|
|
5298
|
+
if (config.filter && typeof config.filter === "object") {
|
|
5299
|
+
if (config.filter.enabled !== false && config.filter.hidden !== true) {
|
|
5300
|
+
const { enabled: _, hidden: __,...filterProps } = config.filter;
|
|
5301
|
+
if (Object.keys(filterProps).length > 0) filterMeta = filterProps;
|
|
5302
|
+
}
|
|
5303
|
+
}
|
|
5304
|
+
if (config.filter === false) result[key] = {
|
|
5305
|
+
...result[key],
|
|
5306
|
+
enableColumnFilter: false
|
|
5307
|
+
};
|
|
5308
|
+
else if (config.filter && typeof config.filter === "object") {
|
|
5309
|
+
if (config.filter.enabled === false || config.filter.hidden === true) result[key] = {
|
|
5310
|
+
...result[key],
|
|
5311
|
+
enableColumnFilter: false
|
|
5312
|
+
};
|
|
5225
5313
|
}
|
|
5226
|
-
result[key] = {
|
|
5314
|
+
if (tableMeta || filterMeta) result[key] = {
|
|
5227
5315
|
...result[key],
|
|
5228
|
-
|
|
5229
|
-
...config.hidden && { hidden: true },
|
|
5230
|
-
...config.table,
|
|
5231
|
-
...filterMeta && { meta: {
|
|
5316
|
+
meta: {
|
|
5232
5317
|
...result[key]?.meta ?? {},
|
|
5233
|
-
...
|
|
5234
|
-
...filterMeta
|
|
5235
|
-
}
|
|
5318
|
+
...tableMeta ?? {},
|
|
5319
|
+
...filterMeta ?? {}
|
|
5320
|
+
}
|
|
5236
5321
|
};
|
|
5237
|
-
if (config.
|
|
5322
|
+
if (config.label) result[key] = {
|
|
5238
5323
|
...result[key],
|
|
5239
|
-
|
|
5324
|
+
label: config.label
|
|
5325
|
+
};
|
|
5326
|
+
if (config.hidden) result[key] = {
|
|
5327
|
+
...result[key],
|
|
5328
|
+
hidden: true
|
|
5329
|
+
};
|
|
5330
|
+
if (config.table === false) result[key] = {
|
|
5331
|
+
...result[key],
|
|
5332
|
+
hidden: true
|
|
5240
5333
|
};
|
|
5334
|
+
else if (config.table && typeof config.table === "object") {
|
|
5335
|
+
const { meta,...tableProps } = config.table;
|
|
5336
|
+
result[key] = {
|
|
5337
|
+
...result[key],
|
|
5338
|
+
...tableProps
|
|
5339
|
+
};
|
|
5340
|
+
}
|
|
5241
5341
|
}
|
|
5242
5342
|
return result;
|
|
5243
5343
|
}
|
|
@@ -5251,12 +5351,24 @@ function buildFormOverrides(fields, legacyOverrides, denyFields) {
|
|
|
5251
5351
|
...result[field],
|
|
5252
5352
|
"x-hidden": true
|
|
5253
5353
|
};
|
|
5254
|
-
if (fields) for (const [key, config] of Object.entries(fields))
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5354
|
+
if (fields) for (const [key, config] of Object.entries(fields)) {
|
|
5355
|
+
if (config.label) result[key] = {
|
|
5356
|
+
...result[key],
|
|
5357
|
+
title: config.label
|
|
5358
|
+
};
|
|
5359
|
+
if (config.hidden) result[key] = {
|
|
5360
|
+
...result[key],
|
|
5361
|
+
"x-hidden": true
|
|
5362
|
+
};
|
|
5363
|
+
if (config.form === false) result[key] = {
|
|
5364
|
+
...result[key],
|
|
5365
|
+
"x-hidden": true
|
|
5366
|
+
};
|
|
5367
|
+
else if (config.form && typeof config.form === "object") result[key] = {
|
|
5368
|
+
...result[key],
|
|
5369
|
+
...config.form
|
|
5370
|
+
};
|
|
5371
|
+
}
|
|
5260
5372
|
return result;
|
|
5261
5373
|
}
|
|
5262
5374
|
/**
|
|
@@ -5265,7 +5377,9 @@ function buildFormOverrides(fields, legacyOverrides, denyFields) {
|
|
|
5265
5377
|
function buildHiddenColumns(fields, legacyHidden, denyFields) {
|
|
5266
5378
|
const hidden = new Set([...legacyHidden ?? [], ...denyFields ?? []]);
|
|
5267
5379
|
if (fields) {
|
|
5268
|
-
for (const [key, config] of Object.entries(fields)) if (config.hidden
|
|
5380
|
+
for (const [key, config] of Object.entries(fields)) if (config.hidden) hidden.add(key);
|
|
5381
|
+
else if (config.table === false) hidden.add(key);
|
|
5382
|
+
else if (config.table && typeof config.table === "object" && config.table.hidden) hidden.add(key);
|
|
5269
5383
|
}
|
|
5270
5384
|
return Array.from(hidden);
|
|
5271
5385
|
}
|
|
@@ -5431,10 +5545,22 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
|
|
|
5431
5545
|
setExporting(false);
|
|
5432
5546
|
}
|
|
5433
5547
|
}, [selectedCount, handleExport]);
|
|
5434
|
-
const tableOverrides = buildTableOverrides(fields, tableConfig?.overrides);
|
|
5435
|
-
const formOverrides = buildFormOverrides(fields, formConfig?.overrides, denyFields)
|
|
5436
|
-
|
|
5437
|
-
|
|
5548
|
+
const tableOverrides = react.useMemo(() => buildTableOverrides(fields, tableConfig?.overrides), [fields, tableConfig?.overrides]);
|
|
5549
|
+
const formOverrides = react.useMemo(() => buildFormOverrides(fields, formConfig?.overrides, denyFields), [
|
|
5550
|
+
fields,
|
|
5551
|
+
formConfig?.overrides,
|
|
5552
|
+
denyFields
|
|
5553
|
+
]);
|
|
5554
|
+
const hiddenColumns = react.useMemo(() => buildHiddenColumns(fields, tableConfig?.hidden, denyFields), [
|
|
5555
|
+
fields,
|
|
5556
|
+
tableConfig?.hidden,
|
|
5557
|
+
denyFields
|
|
5558
|
+
]);
|
|
5559
|
+
const batchFields = react.useMemo(() => buildBatchUpdateFields(schema, tableConfig?.batchFields, fields), [
|
|
5560
|
+
schema,
|
|
5561
|
+
tableConfig?.batchFields,
|
|
5562
|
+
fields
|
|
5563
|
+
]);
|
|
5438
5564
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5439
5565
|
className: "space-y-4",
|
|
5440
5566
|
children: [
|
|
@@ -6166,6 +6292,8 @@ function DataTableToolbarFilter({ column }) {
|
|
|
6166
6292
|
const columnMeta = column.columnDef.meta;
|
|
6167
6293
|
return react.useCallback(() => {
|
|
6168
6294
|
if (!columnMeta?.variant) return null;
|
|
6295
|
+
const modes = columnMeta.modes;
|
|
6296
|
+
if (modes && !modes.includes("advanced")) return null;
|
|
6169
6297
|
switch (columnMeta.variant) {
|
|
6170
6298
|
case "text": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__pixpilot_shadcn.Input, {
|
|
6171
6299
|
placeholder: columnMeta.placeholder ?? columnMeta.label,
|
|
@@ -6287,6 +6415,10 @@ function modalReducer(state, action) {
|
|
|
6287
6415
|
function useAutoCrudResource({ router, schema, query: queryTransform, options = {} }) {
|
|
6288
6416
|
const { idKey = "id", defaultVariant = "dialog", hooks, toast: toastAdapter, exportFetcher } = options;
|
|
6289
6417
|
const toast = (0, react.useMemo)(() => toastAdapter === false ? noopToastAdapter : toastAdapter ?? defaultToastAdapter, [toastAdapter]);
|
|
6418
|
+
const hooksRef = (0, react.useRef)(hooks);
|
|
6419
|
+
(0, react.useEffect)(() => {
|
|
6420
|
+
hooksRef.current = hooks;
|
|
6421
|
+
}, [hooks]);
|
|
6290
6422
|
const columns = (0, react.useMemo)(() => createTableSchema(schema), [schema]);
|
|
6291
6423
|
const [urlParams] = useQueryStates({
|
|
6292
6424
|
page: parseAsInteger.withDefault(1),
|
|
@@ -6350,15 +6482,16 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
6350
6482
|
payload: variant
|
|
6351
6483
|
}), []);
|
|
6352
6484
|
const submitCreate = (0, react.useCallback)(async (values) => {
|
|
6485
|
+
const currentHooks = hooksRef.current;
|
|
6353
6486
|
try {
|
|
6354
|
-
if (
|
|
6355
|
-
const result = await
|
|
6487
|
+
if (currentHooks?.beforeCreate) {
|
|
6488
|
+
const result = await currentHooks.beforeCreate(values);
|
|
6356
6489
|
if (typeof result === "boolean") {
|
|
6357
6490
|
if (result) {
|
|
6358
6491
|
toast.success("创建成功");
|
|
6359
6492
|
closeModals();
|
|
6360
6493
|
listQuery.refetch();
|
|
6361
|
-
|
|
6494
|
+
currentHooks?.onSuccess?.("create", values);
|
|
6362
6495
|
}
|
|
6363
6496
|
return;
|
|
6364
6497
|
}
|
|
@@ -6369,36 +6502,36 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
6369
6502
|
toast.success("创建成功");
|
|
6370
6503
|
closeModals();
|
|
6371
6504
|
listQuery.refetch();
|
|
6372
|
-
|
|
6505
|
+
currentHooks?.onSuccess?.("create", data);
|
|
6373
6506
|
},
|
|
6374
6507
|
onError: (error) => {
|
|
6375
6508
|
const err = error;
|
|
6376
6509
|
toast.error(`创建失败: ${err.message}`);
|
|
6377
|
-
|
|
6510
|
+
currentHooks?.onError?.("create", err);
|
|
6378
6511
|
}
|
|
6379
6512
|
});
|
|
6380
6513
|
} catch (error) {
|
|
6381
6514
|
const err = error;
|
|
6382
6515
|
toast.error(`创建失败: ${err.message}`);
|
|
6383
|
-
|
|
6516
|
+
currentHooks?.onError?.("create", err);
|
|
6384
6517
|
}
|
|
6385
6518
|
}, [
|
|
6386
6519
|
createMutation,
|
|
6387
6520
|
closeModals,
|
|
6388
|
-
listQuery
|
|
6389
|
-
hooks
|
|
6521
|
+
listQuery
|
|
6390
6522
|
]);
|
|
6391
6523
|
const submitUpdate = (0, react.useCallback)(async (values) => {
|
|
6524
|
+
const currentHooks = hooksRef.current;
|
|
6392
6525
|
if (!modal.selected) return;
|
|
6393
6526
|
try {
|
|
6394
|
-
if (
|
|
6395
|
-
const result = await
|
|
6527
|
+
if (currentHooks?.beforeUpdate) {
|
|
6528
|
+
const result = await currentHooks.beforeUpdate(values, modal.selected);
|
|
6396
6529
|
if (typeof result === "boolean") {
|
|
6397
6530
|
if (result) {
|
|
6398
6531
|
toast.success("更新成功");
|
|
6399
6532
|
closeModals();
|
|
6400
6533
|
listQuery.refetch();
|
|
6401
|
-
|
|
6534
|
+
currentHooks?.onSuccess?.("update", values);
|
|
6402
6535
|
}
|
|
6403
6536
|
return;
|
|
6404
6537
|
}
|
|
@@ -6413,38 +6546,38 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
6413
6546
|
toast.success("更新成功");
|
|
6414
6547
|
closeModals();
|
|
6415
6548
|
listQuery.refetch();
|
|
6416
|
-
|
|
6549
|
+
currentHooks?.onSuccess?.("update", data);
|
|
6417
6550
|
},
|
|
6418
6551
|
onError: (error) => {
|
|
6419
6552
|
const err = error;
|
|
6420
6553
|
toast.error(`更新失败: ${err.message}`);
|
|
6421
|
-
|
|
6554
|
+
currentHooks?.onError?.("update", err);
|
|
6422
6555
|
}
|
|
6423
6556
|
});
|
|
6424
6557
|
} catch (error) {
|
|
6425
6558
|
const err = error;
|
|
6426
6559
|
toast.error(`更新失败: ${err.message}`);
|
|
6427
|
-
|
|
6560
|
+
currentHooks?.onError?.("update", err);
|
|
6428
6561
|
}
|
|
6429
6562
|
}, [
|
|
6430
6563
|
modal.selected,
|
|
6431
6564
|
idKey,
|
|
6432
6565
|
updateMutation,
|
|
6433
6566
|
closeModals,
|
|
6434
|
-
listQuery
|
|
6435
|
-
hooks
|
|
6567
|
+
listQuery
|
|
6436
6568
|
]);
|
|
6437
6569
|
const confirmDelete = (0, react.useCallback)(async () => {
|
|
6570
|
+
const currentHooks = hooksRef.current;
|
|
6438
6571
|
if (!modal.selected) return;
|
|
6439
6572
|
try {
|
|
6440
|
-
if (
|
|
6441
|
-
const result = await
|
|
6573
|
+
if (currentHooks?.beforeDelete) {
|
|
6574
|
+
const result = await currentHooks.beforeDelete(modal.selected);
|
|
6442
6575
|
if (typeof result === "boolean") {
|
|
6443
6576
|
if (result) {
|
|
6444
6577
|
toast.success("删除成功");
|
|
6445
6578
|
closeModals();
|
|
6446
6579
|
listQuery.refetch();
|
|
6447
|
-
|
|
6580
|
+
currentHooks?.onSuccess?.("delete", modal.selected);
|
|
6448
6581
|
}
|
|
6449
6582
|
return;
|
|
6450
6583
|
}
|
|
@@ -6455,28 +6588,28 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
6455
6588
|
toast.success("删除成功");
|
|
6456
6589
|
closeModals();
|
|
6457
6590
|
listQuery.refetch();
|
|
6458
|
-
|
|
6591
|
+
currentHooks?.onSuccess?.("delete", data);
|
|
6459
6592
|
},
|
|
6460
6593
|
onError: (error) => {
|
|
6461
6594
|
const err = error;
|
|
6462
6595
|
toast.error(`删除失败: ${err.message}`);
|
|
6463
|
-
|
|
6596
|
+
currentHooks?.onError?.("delete", err);
|
|
6464
6597
|
}
|
|
6465
6598
|
});
|
|
6466
6599
|
} catch (error) {
|
|
6467
6600
|
const err = error;
|
|
6468
6601
|
toast.error(`删除失败: ${err.message}`);
|
|
6469
|
-
|
|
6602
|
+
currentHooks?.onError?.("delete", err);
|
|
6470
6603
|
}
|
|
6471
6604
|
}, [
|
|
6472
6605
|
modal.selected,
|
|
6473
6606
|
idKey,
|
|
6474
6607
|
deleteMutation,
|
|
6475
6608
|
closeModals,
|
|
6476
|
-
listQuery
|
|
6477
|
-
hooks
|
|
6609
|
+
listQuery
|
|
6478
6610
|
]);
|
|
6479
6611
|
const deleteMany = (0, react.useCallback)((rows) => {
|
|
6612
|
+
const currentHooks = hooksRef.current;
|
|
6480
6613
|
if (!deleteManyMutation) {
|
|
6481
6614
|
toast.error("批量删除功能未启用");
|
|
6482
6615
|
return;
|
|
@@ -6486,21 +6619,21 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
6486
6619
|
onSuccess: (data) => {
|
|
6487
6620
|
toast.success(`成功删除 ${ids.length} 条记录`);
|
|
6488
6621
|
listQuery.refetch();
|
|
6489
|
-
|
|
6622
|
+
currentHooks?.onSuccess?.("delete", data);
|
|
6490
6623
|
},
|
|
6491
6624
|
onError: (error) => {
|
|
6492
6625
|
const err = error;
|
|
6493
6626
|
toast.error(`批量删除失败: ${err.message}`);
|
|
6494
|
-
|
|
6627
|
+
currentHooks?.onError?.("delete", err);
|
|
6495
6628
|
}
|
|
6496
6629
|
});
|
|
6497
6630
|
}, [
|
|
6498
6631
|
deleteManyMutation,
|
|
6499
6632
|
idKey,
|
|
6500
|
-
listQuery
|
|
6501
|
-
hooks
|
|
6633
|
+
listQuery
|
|
6502
6634
|
]);
|
|
6503
6635
|
const updateMany = (0, react.useCallback)((rows, data) => {
|
|
6636
|
+
const currentHooks = hooksRef.current;
|
|
6504
6637
|
if (!updateManyMutation) {
|
|
6505
6638
|
toast.error("批量更新功能未启用");
|
|
6506
6639
|
return;
|
|
@@ -6513,19 +6646,18 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
6513
6646
|
onSuccess: (result) => {
|
|
6514
6647
|
toast.success(`成功更新 ${ids.length} 条记录`);
|
|
6515
6648
|
listQuery.refetch();
|
|
6516
|
-
|
|
6649
|
+
currentHooks?.onSuccess?.("update", result);
|
|
6517
6650
|
},
|
|
6518
6651
|
onError: (error) => {
|
|
6519
6652
|
const err = error;
|
|
6520
6653
|
toast.error(`批量更新失败: ${err.message}`);
|
|
6521
|
-
|
|
6654
|
+
currentHooks?.onError?.("update", err);
|
|
6522
6655
|
}
|
|
6523
6656
|
});
|
|
6524
6657
|
}, [
|
|
6525
6658
|
updateManyMutation,
|
|
6526
6659
|
idKey,
|
|
6527
|
-
listQuery
|
|
6528
|
-
hooks
|
|
6660
|
+
listQuery
|
|
6529
6661
|
]);
|
|
6530
6662
|
const copyRow = (0, react.useCallback)((row) => {
|
|
6531
6663
|
dispatch({
|