@wordrhyme/auto-crud 1.3.5 → 1.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -10
- package/dist/index.cjs +100 -51
- package/dist/index.d.cts +31 -17
- package/dist/index.d.ts +15 -1
- package/dist/index.js +100 -51
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -268,7 +268,7 @@ interface AutoCrudTableProps<TSchema> {
|
|
|
268
268
|
batchFields?: (string | BatchUpdateField)[]; // 批量更新字段
|
|
269
269
|
/** @deprecated 新代码请使用 actions.batch */
|
|
270
270
|
batchActions?: BatchActionConfig<z.output<TSchema>>;
|
|
271
|
-
defaultSort?: any[]; //
|
|
271
|
+
defaultSort?: any[]; // 手动 resource 的 UI 默认排序;useAutoCrudResource 请配置 options.defaultSort
|
|
272
272
|
};
|
|
273
273
|
form?: {
|
|
274
274
|
overrides?: Record<string, any>; // 表单覆盖配置
|
|
@@ -280,11 +280,13 @@ interface AutoCrudTableProps<TSchema> {
|
|
|
280
280
|
* 旧写法 actions={[...]} 仍表示行操作;
|
|
281
281
|
* 新写法 actions={{ toolbar, row, batch }} 可集中配置三类操作。
|
|
282
282
|
*/
|
|
283
|
-
actions?:
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
283
|
+
actions?:
|
|
284
|
+
| RowActionConfig<z.output<TSchema>>
|
|
285
|
+
| {
|
|
286
|
+
toolbar?: ToolbarActionConfig;
|
|
287
|
+
row?: RowActionConfig<z.output<TSchema>>;
|
|
288
|
+
batch?: BatchActionConfig<z.output<TSchema>>;
|
|
289
|
+
};
|
|
288
290
|
/** @deprecated 新代码请使用 actions.toolbar */
|
|
289
291
|
toolbar?: ToolbarActionConfig;
|
|
290
292
|
/** @deprecated 新代码请使用 actions.toolbar */
|
|
@@ -302,6 +304,11 @@ interface AutoCrudTableProps<TSchema> {
|
|
|
302
304
|
interface UseAutoCrudResourceConfig<TData> {
|
|
303
305
|
dataSource: DataSource<TData>; // 数据源
|
|
304
306
|
schema: z.ZodType<TData>; // Zod Schema
|
|
307
|
+
options?: {
|
|
308
|
+
defaultSort?: Array<{ id: string; desc: boolean }> | false;
|
|
309
|
+
// undefined: schema 有 createdAt 时默认 createdAt desc
|
|
310
|
+
// false: 不应用默认排序
|
|
311
|
+
};
|
|
305
312
|
}
|
|
306
313
|
```
|
|
307
314
|
|
|
@@ -776,7 +783,12 @@ crudActions.register({
|
|
|
776
783
|
actions={{
|
|
777
784
|
row: [
|
|
778
785
|
{ type: 'custom', label: '分配', onClick: (row) => assign(row.id) },
|
|
779
|
-
{
|
|
786
|
+
{
|
|
787
|
+
type: 'custom',
|
|
788
|
+
label: '预览',
|
|
789
|
+
onClick: (row) => preview(row),
|
|
790
|
+
position: 'start',
|
|
791
|
+
},
|
|
780
792
|
],
|
|
781
793
|
}}
|
|
782
794
|
/>
|
|
@@ -849,7 +861,9 @@ type RowCustomActionItem<T> = ActionMeta & {
|
|
|
849
861
|
type: 'custom';
|
|
850
862
|
label?: string;
|
|
851
863
|
onClick?: (row: T) => void;
|
|
852
|
-
component?:
|
|
864
|
+
component?:
|
|
865
|
+
| React.ReactNode
|
|
866
|
+
| ((context: AutoCrudRowActionContext<T>) => React.ReactNode);
|
|
853
867
|
position?: 'start' | 'end'; // 仅无内置项时生效,默认 end
|
|
854
868
|
separator?: boolean;
|
|
855
869
|
variant?: 'default' | 'destructive';
|
|
@@ -992,7 +1006,7 @@ import {
|
|
|
992
1006
|
createSelectColumn, // 创建选择列
|
|
993
1007
|
createActionsColumn, // 创建操作列
|
|
994
1008
|
createFormSchema, // Zod Schema → Formily Schema
|
|
995
|
-
createEditFormSchema, // 创建编辑表单 Schema
|
|
1009
|
+
createEditFormSchema, // 创建编辑表单 Schema(排除平台托管字段)
|
|
996
1010
|
} from '@wordrhyme/auto-crud';
|
|
997
1011
|
```
|
|
998
1012
|
|
|
@@ -1254,7 +1268,15 @@ function CustomCrudPage() {
|
|
|
1254
1268
|
});
|
|
1255
1269
|
|
|
1256
1270
|
const formSchema = createFormSchema(taskSchema, {
|
|
1257
|
-
exclude: [
|
|
1271
|
+
exclude: [
|
|
1272
|
+
"id",
|
|
1273
|
+
"createdAt",
|
|
1274
|
+
"updatedAt",
|
|
1275
|
+
"createdBy",
|
|
1276
|
+
"createdByType",
|
|
1277
|
+
"updatedBy",
|
|
1278
|
+
"updatedByType",
|
|
1279
|
+
],
|
|
1258
1280
|
});
|
|
1259
1281
|
|
|
1260
1282
|
return (
|
package/dist/index.cjs
CHANGED
|
@@ -2062,6 +2062,12 @@ function DataTableSortList({ table, disabled,...props }) {
|
|
|
2062
2062
|
window.addEventListener("keydown", onKeyDown);
|
|
2063
2063
|
return () => window.removeEventListener("keydown", onKeyDown);
|
|
2064
2064
|
}, []);
|
|
2065
|
+
const onTriggerKeyDown = react.useCallback((event) => {
|
|
2066
|
+
if (REMOVE_SORT_SHORTCUTS.includes(event.key.toLowerCase()) && sorting.length > 0) {
|
|
2067
|
+
event.preventDefault();
|
|
2068
|
+
onSortingReset();
|
|
2069
|
+
}
|
|
2070
|
+
}, [sorting.length, onSortingReset]);
|
|
2065
2071
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn_ui.Sortable, {
|
|
2066
2072
|
value: sorting,
|
|
2067
2073
|
onValueChange: onSortingChange,
|
|
@@ -2073,24 +2079,17 @@ function DataTableSortList({ table, disabled,...props }) {
|
|
|
2073
2079
|
asChild: true,
|
|
2074
2080
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Button, {
|
|
2075
2081
|
variant: "outline",
|
|
2076
|
-
size: "sm",
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
onSortingReset();
|
|
2082
|
-
}
|
|
2083
|
-
}, [sorting.length, onSortingReset]),
|
|
2082
|
+
size: "icon-sm",
|
|
2083
|
+
"aria-label": "Sort rows",
|
|
2084
|
+
title: "Sort rows",
|
|
2085
|
+
className: cn(sorting.length > 0 && "w-auto gap-1 px-2"),
|
|
2086
|
+
onKeyDown: onTriggerKeyDown,
|
|
2084
2087
|
disabled,
|
|
2085
|
-
children: [
|
|
2086
|
-
|
|
2087
|
-
"
|
|
2088
|
-
sorting.length
|
|
2089
|
-
|
|
2090
|
-
className: "h-[18.24px] rounded-[3.2px] px-[5.12px] font-mono font-normal text-[10.4px]",
|
|
2091
|
-
children: sorting.length
|
|
2092
|
-
})
|
|
2093
|
-
]
|
|
2088
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ArrowDownUp, { className: "text-muted-foreground" }), sorting.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Badge, {
|
|
2089
|
+
variant: "secondary",
|
|
2090
|
+
className: "h-[18.24px] rounded-[3.2px] px-[5.12px] font-mono font-normal text-[10.4px]",
|
|
2091
|
+
children: sorting.length
|
|
2092
|
+
})]
|
|
2094
2093
|
})
|
|
2095
2094
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.PopoverContent, {
|
|
2096
2095
|
"aria-labelledby": labelId,
|
|
@@ -2260,14 +2259,15 @@ function DataTableViewOptions({ table, disabled,...props }) {
|
|
|
2260
2259
|
const columns = react.useMemo(() => table.getAllColumns().filter((column) => typeof column.accessorFn !== "undefined" && column.getCanHide()), [table]);
|
|
2261
2260
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Popover, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.PopoverTrigger, {
|
|
2262
2261
|
asChild: true,
|
|
2263
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.
|
|
2262
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Button, {
|
|
2264
2263
|
"aria-label": "Toggle columns",
|
|
2264
|
+
title: "Toggle columns",
|
|
2265
2265
|
role: "combobox",
|
|
2266
2266
|
variant: "outline",
|
|
2267
|
-
size: "sm",
|
|
2268
|
-
className: "ml-auto
|
|
2267
|
+
size: "icon-sm",
|
|
2268
|
+
className: "ml-auto",
|
|
2269
2269
|
disabled,
|
|
2270
|
-
children:
|
|
2270
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Settings2, { className: "text-muted-foreground" })
|
|
2271
2271
|
})
|
|
2272
2272
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.PopoverContent, {
|
|
2273
2273
|
className: "w-44 p-0",
|
|
@@ -3974,7 +3974,7 @@ const filterModeConfig = {
|
|
|
3974
3974
|
tooltip: "Linear-style command filters"
|
|
3975
3975
|
}
|
|
3976
3976
|
};
|
|
3977
|
-
function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode
|
|
3977
|
+
function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode, search = false, onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, actionBarActions, deleteConfirmation, initialSorting, enableExport = true, showDefaultExport = true, onSelectedCountChange, onSelectedRowsChange, getSelectedRows }) {
|
|
3978
3978
|
const modes = filterMode ? Array.isArray(filterMode) ? filterMode : [filterMode] : DEFAULT_MODES;
|
|
3979
3979
|
const [currentMode, setCurrentMode] = useQueryState("filterMode", parseAsStringEnum(modes).withDefault(modes[0] ?? "simple"));
|
|
3980
3980
|
const showToggle = modes.length > 1;
|
|
@@ -4049,9 +4049,9 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
|
|
|
4049
4049
|
asChild: true,
|
|
4050
4050
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Button, {
|
|
4051
4051
|
variant: "outline",
|
|
4052
|
-
size: "sm",
|
|
4053
|
-
className: "h-8 w-8 p-0",
|
|
4052
|
+
size: "icon-sm",
|
|
4054
4053
|
"aria-label": `Switch filter mode, current: ${filterModeConfig[currentMode].label}`,
|
|
4054
|
+
title: filterModeConfig[currentMode].tooltip,
|
|
4055
4055
|
children: (() => {
|
|
4056
4056
|
const Icon = filterModeConfig[currentMode].icon;
|
|
4057
4057
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { className: "size-4 text-muted-foreground" });
|
|
@@ -4118,22 +4118,15 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
|
|
|
4118
4118
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4119
4119
|
className: "flex min-h-[40px] min-w-0 flex-1 items-start gap-2",
|
|
4120
4120
|
"data-filter-parent": true,
|
|
4121
|
-
children: [
|
|
4122
|
-
currentMode !== "simple" && searchInput,
|
|
4123
|
-
currentMode !== "simple" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTableSortList, {
|
|
4124
|
-
table,
|
|
4125
|
-
align: "start"
|
|
4126
|
-
}),
|
|
4127
|
-
filtersContent
|
|
4128
|
-
]
|
|
4121
|
+
children: [currentMode !== "simple" && searchInput, filtersContent]
|
|
4129
4122
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4130
4123
|
className: "flex items-center gap-2",
|
|
4131
4124
|
children: [
|
|
4132
|
-
|
|
4125
|
+
FilterModeSelect,
|
|
4126
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTableSortList, {
|
|
4133
4127
|
table,
|
|
4134
4128
|
align: "end"
|
|
4135
4129
|
}),
|
|
4136
|
-
FilterModeSelect,
|
|
4137
4130
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTableViewOptions, {
|
|
4138
4131
|
table,
|
|
4139
4132
|
align: "end"
|
|
@@ -4214,6 +4207,15 @@ function FormModal({ open, onOpenChange, title, description, children, variant =
|
|
|
4214
4207
|
|
|
4215
4208
|
//#endregion
|
|
4216
4209
|
//#region src/lib/schema-bridge/zod-to-formily.ts
|
|
4210
|
+
const DEFAULT_FORM_MANAGED_FIELDS = [
|
|
4211
|
+
"id",
|
|
4212
|
+
"createdAt",
|
|
4213
|
+
"updatedAt",
|
|
4214
|
+
"createdBy",
|
|
4215
|
+
"createdByType",
|
|
4216
|
+
"updatedBy",
|
|
4217
|
+
"updatedByType"
|
|
4218
|
+
];
|
|
4217
4219
|
/**
|
|
4218
4220
|
* 将字符串转为人类可读格式
|
|
4219
4221
|
*/
|
|
@@ -4296,16 +4298,12 @@ function createFormSchema(schema, options) {
|
|
|
4296
4298
|
};
|
|
4297
4299
|
}
|
|
4298
4300
|
/**
|
|
4299
|
-
* 为编辑模式创建 Form Schema
|
|
4301
|
+
* 为编辑模式创建 Form Schema(排除平台托管字段)
|
|
4300
4302
|
*/
|
|
4301
4303
|
function createEditFormSchema(schema, options) {
|
|
4302
4304
|
return createFormSchema(schema, {
|
|
4303
4305
|
...options,
|
|
4304
|
-
exclude: [
|
|
4305
|
-
"id",
|
|
4306
|
-
"createdAt",
|
|
4307
|
-
"updatedAt"
|
|
4308
|
-
]
|
|
4306
|
+
exclude: [...DEFAULT_FORM_MANAGED_FIELDS]
|
|
4309
4307
|
});
|
|
4310
4308
|
}
|
|
4311
4309
|
|
|
@@ -5639,6 +5637,15 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title, local
|
|
|
5639
5637
|
});
|
|
5640
5638
|
}
|
|
5641
5639
|
|
|
5640
|
+
//#endregion
|
|
5641
|
+
//#region src/lib/default-sorting.ts
|
|
5642
|
+
function getDefaultSortingForSchema(schema) {
|
|
5643
|
+
return Object.prototype.hasOwnProperty.call(schema.shape, "createdAt") ? [{
|
|
5644
|
+
id: "createdAt",
|
|
5645
|
+
desc: true
|
|
5646
|
+
}] : [];
|
|
5647
|
+
}
|
|
5648
|
+
|
|
5642
5649
|
//#endregion
|
|
5643
5650
|
//#region src/lib/crud-actions.ts
|
|
5644
5651
|
const entries = /* @__PURE__ */ new Map();
|
|
@@ -5788,6 +5795,29 @@ const crudActions = {
|
|
|
5788
5795
|
|
|
5789
5796
|
//#endregion
|
|
5790
5797
|
//#region src/components/auto-crud/auto-crud-table.tsx
|
|
5798
|
+
const DEFAULT_IMPORT_MANAGED_FIELDS = [
|
|
5799
|
+
"createdAt",
|
|
5800
|
+
"updatedAt",
|
|
5801
|
+
"createdBy",
|
|
5802
|
+
"createdByType",
|
|
5803
|
+
"updatedBy",
|
|
5804
|
+
"updatedByType"
|
|
5805
|
+
];
|
|
5806
|
+
const DEFAULT_HIDDEN_AUDIT_FIELDS = [
|
|
5807
|
+
"createdBy",
|
|
5808
|
+
"createdByType",
|
|
5809
|
+
"updatedBy",
|
|
5810
|
+
"updatedByType"
|
|
5811
|
+
];
|
|
5812
|
+
function isDefaultHiddenAuditField(key) {
|
|
5813
|
+
return DEFAULT_HIDDEN_AUDIT_FIELDS.includes(key);
|
|
5814
|
+
}
|
|
5815
|
+
function isFieldTableExplicitlyVisible(config) {
|
|
5816
|
+
return config?.hidden === false || config?.table !== false && typeof config?.table === "object" && config.table.hidden === false;
|
|
5817
|
+
}
|
|
5818
|
+
function isTableOverrideExplicitlyVisible(config) {
|
|
5819
|
+
return config?.hidden === false;
|
|
5820
|
+
}
|
|
5791
5821
|
let autoCrudToolbarResolver = null;
|
|
5792
5822
|
function setToolbarResolver(resolver) {
|
|
5793
5823
|
autoCrudToolbarResolver = resolver;
|
|
@@ -6239,10 +6269,18 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState) {
|
|
|
6239
6269
|
/**
|
|
6240
6270
|
* 从统一配置生成隐藏列列表
|
|
6241
6271
|
*/
|
|
6242
|
-
function buildHiddenColumns(fields, legacyHidden, denyFields) {
|
|
6243
|
-
const
|
|
6244
|
-
|
|
6245
|
-
|
|
6272
|
+
function buildHiddenColumns(fields, legacyHidden, denyFields, legacyOverrides) {
|
|
6273
|
+
const legacyHiddenSet = new Set(legacyHidden ?? []);
|
|
6274
|
+
const denySet = new Set(denyFields ?? []);
|
|
6275
|
+
const hidden = new Set([
|
|
6276
|
+
...DEFAULT_HIDDEN_AUDIT_FIELDS,
|
|
6277
|
+
...legacyHiddenSet,
|
|
6278
|
+
...denySet
|
|
6279
|
+
]);
|
|
6280
|
+
for (const key of DEFAULT_HIDDEN_AUDIT_FIELDS) if (!legacyHiddenSet.has(key) && !denySet.has(key) && isTableOverrideExplicitlyVisible(legacyOverrides?.[key])) hidden.delete(key);
|
|
6281
|
+
if (fields) for (const [key, config] of Object.entries(fields)) {
|
|
6282
|
+
if (isDefaultHiddenAuditField(key) && !legacyHiddenSet.has(key) && !denySet.has(key) && isFieldTableExplicitlyVisible(config)) hidden.delete(key);
|
|
6283
|
+
if (config.hidden) hidden.add(key);
|
|
6246
6284
|
else if (config.table === false) hidden.add(key);
|
|
6247
6285
|
else if (config.table && typeof config.table === "object" && config.table.hidden) hidden.add(key);
|
|
6248
6286
|
}
|
|
@@ -6346,7 +6384,10 @@ function ViewModal({ open, onOpenChange, variant, data, schema, fields: fieldCon
|
|
|
6346
6384
|
className: "grid gap-4 py-4",
|
|
6347
6385
|
children: Object.entries(shape).filter(([key]) => {
|
|
6348
6386
|
if (denySet.has(key)) return false;
|
|
6349
|
-
|
|
6387
|
+
const config = fieldConfig?.[key];
|
|
6388
|
+
if (config?.hidden) return false;
|
|
6389
|
+
if (isDefaultHiddenAuditField(key) && !isFieldTableExplicitlyVisible(config)) return false;
|
|
6390
|
+
return true;
|
|
6350
6391
|
}).map(([key, fieldSchema]) => {
|
|
6351
6392
|
const parsed = parseZodField(fieldSchema);
|
|
6352
6393
|
const label = fieldConfig?.[key]?.label ?? humanize(key);
|
|
@@ -6559,7 +6600,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
6559
6600
|
const resolvedToolbarActions = resolveToolbarActionsWithResolver(id, registryToolbarActions, toolbarContext);
|
|
6560
6601
|
const importColumns = react.useMemo(() => {
|
|
6561
6602
|
const shape = resolvedSchema.shape;
|
|
6562
|
-
const denySet = new Set(denyFields ?? []);
|
|
6603
|
+
const denySet = new Set([...DEFAULT_IMPORT_MANAGED_FIELDS, ...denyFields ?? []]);
|
|
6563
6604
|
return Object.keys(shape).filter((key) => !denySet.has(key));
|
|
6564
6605
|
}, [resolvedSchema, denyFields]);
|
|
6565
6606
|
const handleExport = react.useCallback(async (mode) => {
|
|
@@ -6598,15 +6639,21 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
6598
6639
|
tableConfig?.overrides,
|
|
6599
6640
|
dynamicFilterOptions
|
|
6600
6641
|
]);
|
|
6642
|
+
const defaultSort = react.useMemo(() => resource.defaultSort ?? tableConfig?.defaultSort ?? getDefaultSortingForSchema(resolvedSchema), [
|
|
6643
|
+
resource.defaultSort,
|
|
6644
|
+
resolvedSchema,
|
|
6645
|
+
tableConfig?.defaultSort
|
|
6646
|
+
]);
|
|
6601
6647
|
const formOverrides = react.useMemo(() => buildFormOverrides(resolvedFields, formConfig?.overrides, denyFields), [
|
|
6602
6648
|
resolvedFields,
|
|
6603
6649
|
formConfig?.overrides,
|
|
6604
6650
|
denyFields
|
|
6605
6651
|
]);
|
|
6606
|
-
const hiddenColumns = react.useMemo(() => buildHiddenColumns(resolvedFields, tableConfig?.hidden, denyFields), [
|
|
6652
|
+
const hiddenColumns = react.useMemo(() => buildHiddenColumns(resolvedFields, tableConfig?.hidden, denyFields, tableConfig?.overrides), [
|
|
6607
6653
|
resolvedFields,
|
|
6608
6654
|
tableConfig?.hidden,
|
|
6609
|
-
denyFields
|
|
6655
|
+
denyFields,
|
|
6656
|
+
tableConfig?.overrides
|
|
6610
6657
|
]);
|
|
6611
6658
|
const searchConfig = react.useMemo(() => {
|
|
6612
6659
|
const tableSearch = tableConfig?.search;
|
|
@@ -6754,7 +6801,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
6754
6801
|
deleteConfirmation: locale.bulkDeleteModal,
|
|
6755
6802
|
enableExport: canExport,
|
|
6756
6803
|
showDefaultExport: false,
|
|
6757
|
-
initialSorting:
|
|
6804
|
+
initialSorting: defaultSort,
|
|
6758
6805
|
onSelectedRowsChange: handleSelectedRowsChange,
|
|
6759
6806
|
getSelectedRows: getSelectedRowsRef
|
|
6760
6807
|
}),
|
|
@@ -7556,7 +7603,7 @@ function modalReducer(state, action$1) {
|
|
|
7556
7603
|
* Hook 主函数
|
|
7557
7604
|
*/
|
|
7558
7605
|
function useAutoCrudResource({ router, schema, query: queryTransform, options = {} }) {
|
|
7559
|
-
const { idKey = "id", defaultVariant = "dialog", hooks, toast: toastAdapter, exportFetcher } = options;
|
|
7606
|
+
const { idKey = "id", defaultVariant = "dialog", hooks, toast: toastAdapter, exportFetcher, defaultSort: defaultSortOption } = options;
|
|
7560
7607
|
const toast = (0, react.useMemo)(() => toastAdapter === false ? noopToastAdapter : toastAdapter ?? defaultToastAdapter, [toastAdapter]);
|
|
7561
7608
|
const hooksRef = (0, react.useRef)(hooks);
|
|
7562
7609
|
(0, react.useEffect)(() => {
|
|
@@ -7564,12 +7611,13 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
7564
7611
|
}, [hooks]);
|
|
7565
7612
|
const metadata = (router.meta?.useQuery(void 0, { staleTime: 3e4 }))?.data;
|
|
7566
7613
|
const resolvedSchema = (0, react.useMemo)(() => mergeMetadataSchema(schema, metadata?.schema), [schema, metadata?.schema]);
|
|
7614
|
+
const defaultSorting = (0, react.useMemo)(() => defaultSortOption === false ? [] : defaultSortOption ?? getDefaultSortingForSchema(resolvedSchema), [defaultSortOption, resolvedSchema]);
|
|
7567
7615
|
const metadataFields = (0, react.useMemo)(() => readMetadataFields(metadata?.fields), [metadata?.fields]);
|
|
7568
7616
|
const columns = (0, react.useMemo)(() => createTableSchema(resolvedSchema), [resolvedSchema]);
|
|
7569
7617
|
const [urlParams] = useQueryStates({
|
|
7570
7618
|
page: parseAsInteger.withDefault(1),
|
|
7571
7619
|
perPage: parseAsInteger.withDefault(10),
|
|
7572
|
-
sort: getSortingStateParser().withDefault(
|
|
7620
|
+
sort: getSortingStateParser().withDefault(defaultSorting),
|
|
7573
7621
|
joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
|
|
7574
7622
|
search: parseAsString.withDefault("")
|
|
7575
7623
|
}, { shallow: false });
|
|
@@ -7857,6 +7905,7 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
7857
7905
|
},
|
|
7858
7906
|
schema: resolvedSchema,
|
|
7859
7907
|
fields: metadataFields,
|
|
7908
|
+
defaultSort: defaultSorting,
|
|
7860
7909
|
modal,
|
|
7861
7910
|
mutations: {
|
|
7862
7911
|
isCreating: createMutation.isPending,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime5 from "react/jsx-runtime";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { JsonSchemaFormScope } from "@wordrhyme/formily-shadcn";
|
|
4
4
|
import * as _tanstack_react_table0 from "@tanstack/react-table";
|
|
@@ -9,6 +9,12 @@ import { DropdownMenuTrigger, PopoverContent } from "@wordrhyme/shadcn";
|
|
|
9
9
|
import { MultiCombobox, MultiComboboxOption, MultiComboboxProps, MultiComboboxTriggerRenderProps, Select, SelectMode, SelectOption, SelectProps, SelectSearchableDynamicProps, SelectSearchableMultipleProps, SelectSearchableProps, SelectSearchableSingleProps, SelectSimpleProps, SelectTriggerRenderProps } from "@wordrhyme/shadcn-ui";
|
|
10
10
|
import { ClassValue } from "clsx";
|
|
11
11
|
|
|
12
|
+
//#region src/lib/default-sorting.d.ts
|
|
13
|
+
type AutoCrudSorting = Array<{
|
|
14
|
+
id: string;
|
|
15
|
+
desc: boolean;
|
|
16
|
+
}>;
|
|
17
|
+
//#endregion
|
|
12
18
|
//#region src/hooks/use-auto-crud-resource.d.ts
|
|
13
19
|
/**
|
|
14
20
|
* Toast 适配器接口
|
|
@@ -103,6 +109,12 @@ interface UseAutoCrudResourceOptions<TSchema extends z.ZodObject<z.ZodRawShape>,
|
|
|
103
109
|
total: number;
|
|
104
110
|
hasMore: boolean;
|
|
105
111
|
}>;
|
|
112
|
+
/**
|
|
113
|
+
* 默认排序。
|
|
114
|
+
* - undefined: schema 有 createdAt 时默认 createdAt desc
|
|
115
|
+
* - false: 不应用默认排序
|
|
116
|
+
*/
|
|
117
|
+
defaultSort?: AutoCrudSorting | false;
|
|
106
118
|
}
|
|
107
119
|
/**
|
|
108
120
|
* 导入结果类型(与服务端保持一致)
|
|
@@ -133,6 +145,8 @@ interface UseAutoCrudResourceReturn<TSchema extends z.ZodObject<z.ZodRawShape>,
|
|
|
133
145
|
schema?: z.ZodObject<z.ZodRawShape>;
|
|
134
146
|
/** Optional field config override from host metadata. */
|
|
135
147
|
fields?: Fields;
|
|
148
|
+
/** Default sorting used by this resource's list query. */
|
|
149
|
+
defaultSort?: AutoCrudSorting;
|
|
136
150
|
modal: ModalState<TListItem>;
|
|
137
151
|
mutations: {
|
|
138
152
|
isCreating: boolean;
|
|
@@ -381,7 +395,7 @@ declare function AutoTableActionBar<TData>({
|
|
|
381
395
|
extraActions,
|
|
382
396
|
actions,
|
|
383
397
|
deleteConfirmation
|
|
384
|
-
}: AutoTableActionBarProps<TData>):
|
|
398
|
+
}: AutoTableActionBarProps<TData>): react_jsx_runtime5.JSX.Element;
|
|
385
399
|
//#endregion
|
|
386
400
|
//#region src/lib/schema-bridge/types.d.ts
|
|
387
401
|
/**
|
|
@@ -557,7 +571,7 @@ declare function AutoTable<T extends z.ZodObject<z.ZodRawShape>>({
|
|
|
557
571
|
onSelectedCountChange,
|
|
558
572
|
onSelectedRowsChange,
|
|
559
573
|
getSelectedRows
|
|
560
|
-
}: AutoTableProps<T>):
|
|
574
|
+
}: AutoTableProps<T>): react_jsx_runtime5.JSX.Element;
|
|
561
575
|
//#endregion
|
|
562
576
|
//#region src/i18n/locale.d.ts
|
|
563
577
|
/**
|
|
@@ -1037,7 +1051,7 @@ declare function AutoCrudTable<TSchema extends z.ZodObject<z.ZodRawShape>>({
|
|
|
1037
1051
|
toolbarActions,
|
|
1038
1052
|
locale: localeProp,
|
|
1039
1053
|
onCreate
|
|
1040
|
-
}: AutoCrudTableProps<TSchema>):
|
|
1054
|
+
}: AutoCrudTableProps<TSchema>): react_jsx_runtime5.JSX.Element;
|
|
1041
1055
|
//#endregion
|
|
1042
1056
|
//#region src/components/auto-crud/auto-form.d.ts
|
|
1043
1057
|
interface AutoFormProps<T extends z.ZodObject<z.ZodRawShape>> {
|
|
@@ -1076,7 +1090,7 @@ declare function AutoFormInner<T extends z.ZodObject<z.ZodRawShape>>({
|
|
|
1076
1090
|
labelAlign,
|
|
1077
1091
|
labelWidth,
|
|
1078
1092
|
showSubmitButton
|
|
1079
|
-
}: AutoFormProps<T>, ref: React.Ref<AutoFormRef>):
|
|
1093
|
+
}: AutoFormProps<T>, ref: React.Ref<AutoFormRef>): react_jsx_runtime5.JSX.Element;
|
|
1080
1094
|
declare const AutoForm: <T extends z.ZodObject<z.ZodRawShape>>(props: AutoFormProps<T> & {
|
|
1081
1095
|
ref?: React.Ref<AutoFormRef>;
|
|
1082
1096
|
}) => ReturnType<typeof AutoFormInner>;
|
|
@@ -1392,7 +1406,7 @@ declare function AutoTableSimpleFilters<TData>({
|
|
|
1392
1406
|
filters: externalFilters,
|
|
1393
1407
|
onFiltersChange,
|
|
1394
1408
|
leading
|
|
1395
|
-
}: AutoTableSimpleFiltersProps<TData>):
|
|
1409
|
+
}: AutoTableSimpleFiltersProps<TData>): react_jsx_runtime5.JSX.Element | null;
|
|
1396
1410
|
//#endregion
|
|
1397
1411
|
//#region src/components/auto-crud/form-modal.d.ts
|
|
1398
1412
|
type ModalVariant = "dialog" | "sheet";
|
|
@@ -1436,7 +1450,7 @@ declare function CrudFormModal<T extends z.ZodObject<z.ZodRawShape>>({
|
|
|
1436
1450
|
labelAlign,
|
|
1437
1451
|
labelWidth,
|
|
1438
1452
|
className
|
|
1439
|
-
}: CrudFormModalProps<T>):
|
|
1453
|
+
}: CrudFormModalProps<T>): react_jsx_runtime5.JSX.Element;
|
|
1440
1454
|
//#endregion
|
|
1441
1455
|
//#region src/components/auto-crud/import-dialog.d.ts
|
|
1442
1456
|
interface ImportDialogProps {
|
|
@@ -1458,7 +1472,7 @@ declare function ImportDialog({
|
|
|
1458
1472
|
columns,
|
|
1459
1473
|
title,
|
|
1460
1474
|
locale
|
|
1461
|
-
}: ImportDialogProps):
|
|
1475
|
+
}: ImportDialogProps): react_jsx_runtime5.JSX.Element;
|
|
1462
1476
|
//#endregion
|
|
1463
1477
|
//#region src/components/auto-crud/export-dialog.d.ts
|
|
1464
1478
|
type ExportMode = "selected" | "filtered";
|
|
@@ -1478,7 +1492,7 @@ declare function ExportDialog({
|
|
|
1478
1492
|
selectedCount,
|
|
1479
1493
|
onExport,
|
|
1480
1494
|
canExportFiltered
|
|
1481
|
-
}: ExportDialogProps):
|
|
1495
|
+
}: ExportDialogProps): react_jsx_runtime5.JSX.Element;
|
|
1482
1496
|
//#endregion
|
|
1483
1497
|
//#region src/components/data-table/data-table.d.ts
|
|
1484
1498
|
interface DataTableProps<TData> extends React$1.ComponentProps<"div"> {
|
|
@@ -1491,7 +1505,7 @@ declare function DataTable<TData>({
|
|
|
1491
1505
|
children,
|
|
1492
1506
|
className,
|
|
1493
1507
|
...props
|
|
1494
|
-
}: DataTableProps<TData>):
|
|
1508
|
+
}: DataTableProps<TData>): react_jsx_runtime5.JSX.Element;
|
|
1495
1509
|
//#endregion
|
|
1496
1510
|
//#region src/components/data-table/data-table-advanced-toolbar.d.ts
|
|
1497
1511
|
interface DataTableAdvancedToolbarProps<TData> extends React$1.ComponentProps<"div"> {
|
|
@@ -1502,7 +1516,7 @@ declare function DataTableAdvancedToolbar<TData>({
|
|
|
1502
1516
|
children,
|
|
1503
1517
|
className,
|
|
1504
1518
|
...props
|
|
1505
|
-
}: DataTableAdvancedToolbarProps<TData>):
|
|
1519
|
+
}: DataTableAdvancedToolbarProps<TData>): react_jsx_runtime5.JSX.Element;
|
|
1506
1520
|
//#endregion
|
|
1507
1521
|
//#region src/components/data-table/data-table-column-header.d.ts
|
|
1508
1522
|
interface DataTableColumnHeaderProps<TData, TValue> extends React.ComponentProps<typeof DropdownMenuTrigger> {
|
|
@@ -1514,7 +1528,7 @@ declare function DataTableColumnHeader<TData, TValue>({
|
|
|
1514
1528
|
label,
|
|
1515
1529
|
className,
|
|
1516
1530
|
...props
|
|
1517
|
-
}: DataTableColumnHeaderProps<TData, TValue>):
|
|
1531
|
+
}: DataTableColumnHeaderProps<TData, TValue>): react_jsx_runtime5.JSX.Element;
|
|
1518
1532
|
//#endregion
|
|
1519
1533
|
//#region src/components/data-table/data-table-faceted-filter.d.ts
|
|
1520
1534
|
interface DataTableFacetedFilterProps<TData, TValue> {
|
|
@@ -1528,7 +1542,7 @@ declare function DataTableFacetedFilter<TData, TValue>({
|
|
|
1528
1542
|
title,
|
|
1529
1543
|
options,
|
|
1530
1544
|
multiple
|
|
1531
|
-
}: DataTableFacetedFilterProps<TData, TValue>):
|
|
1545
|
+
}: DataTableFacetedFilterProps<TData, TValue>): react_jsx_runtime5.JSX.Element;
|
|
1532
1546
|
//#endregion
|
|
1533
1547
|
//#region src/components/data-table/data-table-pagination.d.ts
|
|
1534
1548
|
interface DataTablePaginationProps<TData> extends React.ComponentProps<"div"> {
|
|
@@ -1540,7 +1554,7 @@ declare function DataTablePagination<TData>({
|
|
|
1540
1554
|
pageSizeOptions,
|
|
1541
1555
|
className,
|
|
1542
1556
|
...props
|
|
1543
|
-
}: DataTablePaginationProps<TData>):
|
|
1557
|
+
}: DataTablePaginationProps<TData>): react_jsx_runtime5.JSX.Element;
|
|
1544
1558
|
//#endregion
|
|
1545
1559
|
//#region src/components/data-table/data-table-toolbar.d.ts
|
|
1546
1560
|
interface DataTableToolbarProps<TData> extends React$1.ComponentProps<"div"> {
|
|
@@ -1551,7 +1565,7 @@ declare function DataTableToolbar<TData>({
|
|
|
1551
1565
|
children,
|
|
1552
1566
|
className,
|
|
1553
1567
|
...props
|
|
1554
|
-
}: DataTableToolbarProps<TData>):
|
|
1568
|
+
}: DataTableToolbarProps<TData>): react_jsx_runtime5.JSX.Element;
|
|
1555
1569
|
//#endregion
|
|
1556
1570
|
//#region src/components/data-table/data-table-view-options.d.ts
|
|
1557
1571
|
interface DataTableViewOptionsProps<TData> extends React$1.ComponentProps<typeof PopoverContent> {
|
|
@@ -1562,7 +1576,7 @@ declare function DataTableViewOptions<TData>({
|
|
|
1562
1576
|
table,
|
|
1563
1577
|
disabled,
|
|
1564
1578
|
...props
|
|
1565
|
-
}: DataTableViewOptionsProps<TData>):
|
|
1579
|
+
}: DataTableViewOptionsProps<TData>): react_jsx_runtime5.JSX.Element;
|
|
1566
1580
|
//#endregion
|
|
1567
1581
|
//#region src/lib/crud-actions.d.ts
|
|
1568
1582
|
type CrudActionZone = 'toolbar' | 'row' | 'batch';
|
|
@@ -1644,7 +1658,7 @@ declare function useReadableFilters<TData>(columns: ColumnLike<TData>[], options
|
|
|
1644
1658
|
*/
|
|
1645
1659
|
declare function createFormSchema<T extends z.ZodObject<z.ZodRawShape>>(schema: T, options?: CreateFormSchemaOptions): ISchema;
|
|
1646
1660
|
/**
|
|
1647
|
-
* 为编辑模式创建 Form Schema
|
|
1661
|
+
* 为编辑模式创建 Form Schema(排除平台托管字段)
|
|
1648
1662
|
*/
|
|
1649
1663
|
declare function createEditFormSchema<T extends z.ZodObject<z.ZodRawShape>>(schema: T, options?: Omit<CreateFormSchemaOptions, 'exclude'>): ISchema;
|
|
1650
1664
|
//#endregion
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,12 @@ import { z } from "zod";
|
|
|
9
9
|
import { JsonSchemaFormScope } from "@wordrhyme/formily-shadcn";
|
|
10
10
|
import { ISchema } from "@formily/json-schema";
|
|
11
11
|
|
|
12
|
+
//#region src/lib/default-sorting.d.ts
|
|
13
|
+
type AutoCrudSorting = Array<{
|
|
14
|
+
id: string;
|
|
15
|
+
desc: boolean;
|
|
16
|
+
}>;
|
|
17
|
+
//#endregion
|
|
12
18
|
//#region src/hooks/use-auto-crud-resource.d.ts
|
|
13
19
|
/**
|
|
14
20
|
* Toast 适配器接口
|
|
@@ -103,6 +109,12 @@ interface UseAutoCrudResourceOptions<TSchema extends z.ZodObject<z.ZodRawShape>,
|
|
|
103
109
|
total: number;
|
|
104
110
|
hasMore: boolean;
|
|
105
111
|
}>;
|
|
112
|
+
/**
|
|
113
|
+
* 默认排序。
|
|
114
|
+
* - undefined: schema 有 createdAt 时默认 createdAt desc
|
|
115
|
+
* - false: 不应用默认排序
|
|
116
|
+
*/
|
|
117
|
+
defaultSort?: AutoCrudSorting | false;
|
|
106
118
|
}
|
|
107
119
|
/**
|
|
108
120
|
* 导入结果类型(与服务端保持一致)
|
|
@@ -133,6 +145,8 @@ interface UseAutoCrudResourceReturn<TSchema extends z.ZodObject<z.ZodRawShape>,
|
|
|
133
145
|
schema?: z.ZodObject<z.ZodRawShape>;
|
|
134
146
|
/** Optional field config override from host metadata. */
|
|
135
147
|
fields?: Fields;
|
|
148
|
+
/** Default sorting used by this resource's list query. */
|
|
149
|
+
defaultSort?: AutoCrudSorting;
|
|
136
150
|
modal: ModalState<TListItem>;
|
|
137
151
|
mutations: {
|
|
138
152
|
isCreating: boolean;
|
|
@@ -1644,7 +1658,7 @@ declare function useReadableFilters<TData>(columns: ColumnLike<TData>[], options
|
|
|
1644
1658
|
*/
|
|
1645
1659
|
declare function createFormSchema<T extends z.ZodObject<z.ZodRawShape>>(schema: T, options?: CreateFormSchemaOptions): ISchema;
|
|
1646
1660
|
/**
|
|
1647
|
-
* 为编辑模式创建 Form Schema
|
|
1661
|
+
* 为编辑模式创建 Form Schema(排除平台托管字段)
|
|
1648
1662
|
*/
|
|
1649
1663
|
declare function createEditFormSchema<T extends z.ZodObject<z.ZodRawShape>>(schema: T, options?: Omit<CreateFormSchemaOptions, 'exclude'>): ISchema;
|
|
1650
1664
|
//#endregion
|
package/dist/index.js
CHANGED
|
@@ -2025,6 +2025,12 @@ function DataTableSortList({ table, disabled,...props }) {
|
|
|
2025
2025
|
window.addEventListener("keydown", onKeyDown);
|
|
2026
2026
|
return () => window.removeEventListener("keydown", onKeyDown);
|
|
2027
2027
|
}, []);
|
|
2028
|
+
const onTriggerKeyDown = React.useCallback((event) => {
|
|
2029
|
+
if (REMOVE_SORT_SHORTCUTS.includes(event.key.toLowerCase()) && sorting.length > 0) {
|
|
2030
|
+
event.preventDefault();
|
|
2031
|
+
onSortingReset();
|
|
2032
|
+
}
|
|
2033
|
+
}, [sorting.length, onSortingReset]);
|
|
2028
2034
|
return /* @__PURE__ */ jsxs(Sortable, {
|
|
2029
2035
|
value: sorting,
|
|
2030
2036
|
onValueChange: onSortingChange,
|
|
@@ -2036,24 +2042,17 @@ function DataTableSortList({ table, disabled,...props }) {
|
|
|
2036
2042
|
asChild: true,
|
|
2037
2043
|
children: /* @__PURE__ */ jsxs(Button, {
|
|
2038
2044
|
variant: "outline",
|
|
2039
|
-
size: "sm",
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
onSortingReset();
|
|
2045
|
-
}
|
|
2046
|
-
}, [sorting.length, onSortingReset]),
|
|
2045
|
+
size: "icon-sm",
|
|
2046
|
+
"aria-label": "Sort rows",
|
|
2047
|
+
title: "Sort rows",
|
|
2048
|
+
className: cn(sorting.length > 0 && "w-auto gap-1 px-2"),
|
|
2049
|
+
onKeyDown: onTriggerKeyDown,
|
|
2047
2050
|
disabled,
|
|
2048
|
-
children: [
|
|
2049
|
-
|
|
2050
|
-
"
|
|
2051
|
-
sorting.length
|
|
2052
|
-
|
|
2053
|
-
className: "h-[18.24px] rounded-[3.2px] px-[5.12px] font-mono font-normal text-[10.4px]",
|
|
2054
|
-
children: sorting.length
|
|
2055
|
-
})
|
|
2056
|
-
]
|
|
2051
|
+
children: [/* @__PURE__ */ jsx(ArrowDownUp, { className: "text-muted-foreground" }), sorting.length > 0 && /* @__PURE__ */ jsx(Badge, {
|
|
2052
|
+
variant: "secondary",
|
|
2053
|
+
className: "h-[18.24px] rounded-[3.2px] px-[5.12px] font-mono font-normal text-[10.4px]",
|
|
2054
|
+
children: sorting.length
|
|
2055
|
+
})]
|
|
2057
2056
|
})
|
|
2058
2057
|
}), /* @__PURE__ */ jsxs(PopoverContent, {
|
|
2059
2058
|
"aria-labelledby": labelId,
|
|
@@ -2223,14 +2222,15 @@ function DataTableViewOptions({ table, disabled,...props }) {
|
|
|
2223
2222
|
const columns = React.useMemo(() => table.getAllColumns().filter((column) => typeof column.accessorFn !== "undefined" && column.getCanHide()), [table]);
|
|
2224
2223
|
return /* @__PURE__ */ jsxs(Popover, { children: [/* @__PURE__ */ jsx(PopoverTrigger, {
|
|
2225
2224
|
asChild: true,
|
|
2226
|
-
children: /* @__PURE__ */
|
|
2225
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
2227
2226
|
"aria-label": "Toggle columns",
|
|
2227
|
+
title: "Toggle columns",
|
|
2228
2228
|
role: "combobox",
|
|
2229
2229
|
variant: "outline",
|
|
2230
|
-
size: "sm",
|
|
2231
|
-
className: "ml-auto
|
|
2230
|
+
size: "icon-sm",
|
|
2231
|
+
className: "ml-auto",
|
|
2232
2232
|
disabled,
|
|
2233
|
-
children:
|
|
2233
|
+
children: /* @__PURE__ */ jsx(Settings2, { className: "text-muted-foreground" })
|
|
2234
2234
|
})
|
|
2235
2235
|
}), /* @__PURE__ */ jsx(PopoverContent, {
|
|
2236
2236
|
className: "w-44 p-0",
|
|
@@ -3937,7 +3937,7 @@ const filterModeConfig = {
|
|
|
3937
3937
|
tooltip: "Linear-style command filters"
|
|
3938
3938
|
}
|
|
3939
3939
|
};
|
|
3940
|
-
function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode
|
|
3940
|
+
function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode, search = false, onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, actionBarActions, deleteConfirmation, initialSorting, enableExport = true, showDefaultExport = true, onSelectedCountChange, onSelectedRowsChange, getSelectedRows }) {
|
|
3941
3941
|
const modes = filterMode ? Array.isArray(filterMode) ? filterMode : [filterMode] : DEFAULT_MODES;
|
|
3942
3942
|
const [currentMode, setCurrentMode] = useQueryState("filterMode", parseAsStringEnum(modes).withDefault(modes[0] ?? "simple"));
|
|
3943
3943
|
const showToggle = modes.length > 1;
|
|
@@ -4012,9 +4012,9 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
|
|
|
4012
4012
|
asChild: true,
|
|
4013
4013
|
children: /* @__PURE__ */ jsx(Button, {
|
|
4014
4014
|
variant: "outline",
|
|
4015
|
-
size: "sm",
|
|
4016
|
-
className: "h-8 w-8 p-0",
|
|
4015
|
+
size: "icon-sm",
|
|
4017
4016
|
"aria-label": `Switch filter mode, current: ${filterModeConfig[currentMode].label}`,
|
|
4017
|
+
title: filterModeConfig[currentMode].tooltip,
|
|
4018
4018
|
children: (() => {
|
|
4019
4019
|
const Icon = filterModeConfig[currentMode].icon;
|
|
4020
4020
|
return /* @__PURE__ */ jsx(Icon, { className: "size-4 text-muted-foreground" });
|
|
@@ -4081,22 +4081,15 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
|
|
|
4081
4081
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
4082
4082
|
className: "flex min-h-[40px] min-w-0 flex-1 items-start gap-2",
|
|
4083
4083
|
"data-filter-parent": true,
|
|
4084
|
-
children: [
|
|
4085
|
-
currentMode !== "simple" && searchInput,
|
|
4086
|
-
currentMode !== "simple" && /* @__PURE__ */ jsx(DataTableSortList, {
|
|
4087
|
-
table,
|
|
4088
|
-
align: "start"
|
|
4089
|
-
}),
|
|
4090
|
-
filtersContent
|
|
4091
|
-
]
|
|
4084
|
+
children: [currentMode !== "simple" && searchInput, filtersContent]
|
|
4092
4085
|
}), /* @__PURE__ */ jsxs("div", {
|
|
4093
4086
|
className: "flex items-center gap-2",
|
|
4094
4087
|
children: [
|
|
4095
|
-
|
|
4088
|
+
FilterModeSelect,
|
|
4089
|
+
/* @__PURE__ */ jsx(DataTableSortList, {
|
|
4096
4090
|
table,
|
|
4097
4091
|
align: "end"
|
|
4098
4092
|
}),
|
|
4099
|
-
FilterModeSelect,
|
|
4100
4093
|
/* @__PURE__ */ jsx(DataTableViewOptions, {
|
|
4101
4094
|
table,
|
|
4102
4095
|
align: "end"
|
|
@@ -4177,6 +4170,15 @@ function FormModal({ open, onOpenChange, title, description, children, variant =
|
|
|
4177
4170
|
|
|
4178
4171
|
//#endregion
|
|
4179
4172
|
//#region src/lib/schema-bridge/zod-to-formily.ts
|
|
4173
|
+
const DEFAULT_FORM_MANAGED_FIELDS = [
|
|
4174
|
+
"id",
|
|
4175
|
+
"createdAt",
|
|
4176
|
+
"updatedAt",
|
|
4177
|
+
"createdBy",
|
|
4178
|
+
"createdByType",
|
|
4179
|
+
"updatedBy",
|
|
4180
|
+
"updatedByType"
|
|
4181
|
+
];
|
|
4180
4182
|
/**
|
|
4181
4183
|
* 将字符串转为人类可读格式
|
|
4182
4184
|
*/
|
|
@@ -4259,16 +4261,12 @@ function createFormSchema(schema, options) {
|
|
|
4259
4261
|
};
|
|
4260
4262
|
}
|
|
4261
4263
|
/**
|
|
4262
|
-
* 为编辑模式创建 Form Schema
|
|
4264
|
+
* 为编辑模式创建 Form Schema(排除平台托管字段)
|
|
4263
4265
|
*/
|
|
4264
4266
|
function createEditFormSchema(schema, options) {
|
|
4265
4267
|
return createFormSchema(schema, {
|
|
4266
4268
|
...options,
|
|
4267
|
-
exclude: [
|
|
4268
|
-
"id",
|
|
4269
|
-
"createdAt",
|
|
4270
|
-
"updatedAt"
|
|
4271
|
-
]
|
|
4269
|
+
exclude: [...DEFAULT_FORM_MANAGED_FIELDS]
|
|
4272
4270
|
});
|
|
4273
4271
|
}
|
|
4274
4272
|
|
|
@@ -5602,6 +5600,15 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title, local
|
|
|
5602
5600
|
});
|
|
5603
5601
|
}
|
|
5604
5602
|
|
|
5603
|
+
//#endregion
|
|
5604
|
+
//#region src/lib/default-sorting.ts
|
|
5605
|
+
function getDefaultSortingForSchema(schema) {
|
|
5606
|
+
return Object.prototype.hasOwnProperty.call(schema.shape, "createdAt") ? [{
|
|
5607
|
+
id: "createdAt",
|
|
5608
|
+
desc: true
|
|
5609
|
+
}] : [];
|
|
5610
|
+
}
|
|
5611
|
+
|
|
5605
5612
|
//#endregion
|
|
5606
5613
|
//#region src/lib/crud-actions.ts
|
|
5607
5614
|
const entries = /* @__PURE__ */ new Map();
|
|
@@ -5751,6 +5758,29 @@ const crudActions = {
|
|
|
5751
5758
|
|
|
5752
5759
|
//#endregion
|
|
5753
5760
|
//#region src/components/auto-crud/auto-crud-table.tsx
|
|
5761
|
+
const DEFAULT_IMPORT_MANAGED_FIELDS = [
|
|
5762
|
+
"createdAt",
|
|
5763
|
+
"updatedAt",
|
|
5764
|
+
"createdBy",
|
|
5765
|
+
"createdByType",
|
|
5766
|
+
"updatedBy",
|
|
5767
|
+
"updatedByType"
|
|
5768
|
+
];
|
|
5769
|
+
const DEFAULT_HIDDEN_AUDIT_FIELDS = [
|
|
5770
|
+
"createdBy",
|
|
5771
|
+
"createdByType",
|
|
5772
|
+
"updatedBy",
|
|
5773
|
+
"updatedByType"
|
|
5774
|
+
];
|
|
5775
|
+
function isDefaultHiddenAuditField(key) {
|
|
5776
|
+
return DEFAULT_HIDDEN_AUDIT_FIELDS.includes(key);
|
|
5777
|
+
}
|
|
5778
|
+
function isFieldTableExplicitlyVisible(config) {
|
|
5779
|
+
return config?.hidden === false || config?.table !== false && typeof config?.table === "object" && config.table.hidden === false;
|
|
5780
|
+
}
|
|
5781
|
+
function isTableOverrideExplicitlyVisible(config) {
|
|
5782
|
+
return config?.hidden === false;
|
|
5783
|
+
}
|
|
5754
5784
|
let autoCrudToolbarResolver = null;
|
|
5755
5785
|
function setToolbarResolver(resolver) {
|
|
5756
5786
|
autoCrudToolbarResolver = resolver;
|
|
@@ -6202,10 +6232,18 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState) {
|
|
|
6202
6232
|
/**
|
|
6203
6233
|
* 从统一配置生成隐藏列列表
|
|
6204
6234
|
*/
|
|
6205
|
-
function buildHiddenColumns(fields, legacyHidden, denyFields) {
|
|
6206
|
-
const
|
|
6207
|
-
|
|
6208
|
-
|
|
6235
|
+
function buildHiddenColumns(fields, legacyHidden, denyFields, legacyOverrides) {
|
|
6236
|
+
const legacyHiddenSet = new Set(legacyHidden ?? []);
|
|
6237
|
+
const denySet = new Set(denyFields ?? []);
|
|
6238
|
+
const hidden = new Set([
|
|
6239
|
+
...DEFAULT_HIDDEN_AUDIT_FIELDS,
|
|
6240
|
+
...legacyHiddenSet,
|
|
6241
|
+
...denySet
|
|
6242
|
+
]);
|
|
6243
|
+
for (const key of DEFAULT_HIDDEN_AUDIT_FIELDS) if (!legacyHiddenSet.has(key) && !denySet.has(key) && isTableOverrideExplicitlyVisible(legacyOverrides?.[key])) hidden.delete(key);
|
|
6244
|
+
if (fields) for (const [key, config] of Object.entries(fields)) {
|
|
6245
|
+
if (isDefaultHiddenAuditField(key) && !legacyHiddenSet.has(key) && !denySet.has(key) && isFieldTableExplicitlyVisible(config)) hidden.delete(key);
|
|
6246
|
+
if (config.hidden) hidden.add(key);
|
|
6209
6247
|
else if (config.table === false) hidden.add(key);
|
|
6210
6248
|
else if (config.table && typeof config.table === "object" && config.table.hidden) hidden.add(key);
|
|
6211
6249
|
}
|
|
@@ -6309,7 +6347,10 @@ function ViewModal({ open, onOpenChange, variant, data, schema, fields: fieldCon
|
|
|
6309
6347
|
className: "grid gap-4 py-4",
|
|
6310
6348
|
children: Object.entries(shape).filter(([key]) => {
|
|
6311
6349
|
if (denySet.has(key)) return false;
|
|
6312
|
-
|
|
6350
|
+
const config = fieldConfig?.[key];
|
|
6351
|
+
if (config?.hidden) return false;
|
|
6352
|
+
if (isDefaultHiddenAuditField(key) && !isFieldTableExplicitlyVisible(config)) return false;
|
|
6353
|
+
return true;
|
|
6313
6354
|
}).map(([key, fieldSchema]) => {
|
|
6314
6355
|
const parsed = parseZodField(fieldSchema);
|
|
6315
6356
|
const label = fieldConfig?.[key]?.label ?? humanize(key);
|
|
@@ -6522,7 +6563,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
6522
6563
|
const resolvedToolbarActions = resolveToolbarActionsWithResolver(id, registryToolbarActions, toolbarContext);
|
|
6523
6564
|
const importColumns = React.useMemo(() => {
|
|
6524
6565
|
const shape = resolvedSchema.shape;
|
|
6525
|
-
const denySet = new Set(denyFields ?? []);
|
|
6566
|
+
const denySet = new Set([...DEFAULT_IMPORT_MANAGED_FIELDS, ...denyFields ?? []]);
|
|
6526
6567
|
return Object.keys(shape).filter((key) => !denySet.has(key));
|
|
6527
6568
|
}, [resolvedSchema, denyFields]);
|
|
6528
6569
|
const handleExport = React.useCallback(async (mode) => {
|
|
@@ -6561,15 +6602,21 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
6561
6602
|
tableConfig?.overrides,
|
|
6562
6603
|
dynamicFilterOptions
|
|
6563
6604
|
]);
|
|
6605
|
+
const defaultSort = React.useMemo(() => resource.defaultSort ?? tableConfig?.defaultSort ?? getDefaultSortingForSchema(resolvedSchema), [
|
|
6606
|
+
resource.defaultSort,
|
|
6607
|
+
resolvedSchema,
|
|
6608
|
+
tableConfig?.defaultSort
|
|
6609
|
+
]);
|
|
6564
6610
|
const formOverrides = React.useMemo(() => buildFormOverrides(resolvedFields, formConfig?.overrides, denyFields), [
|
|
6565
6611
|
resolvedFields,
|
|
6566
6612
|
formConfig?.overrides,
|
|
6567
6613
|
denyFields
|
|
6568
6614
|
]);
|
|
6569
|
-
const hiddenColumns = React.useMemo(() => buildHiddenColumns(resolvedFields, tableConfig?.hidden, denyFields), [
|
|
6615
|
+
const hiddenColumns = React.useMemo(() => buildHiddenColumns(resolvedFields, tableConfig?.hidden, denyFields, tableConfig?.overrides), [
|
|
6570
6616
|
resolvedFields,
|
|
6571
6617
|
tableConfig?.hidden,
|
|
6572
|
-
denyFields
|
|
6618
|
+
denyFields,
|
|
6619
|
+
tableConfig?.overrides
|
|
6573
6620
|
]);
|
|
6574
6621
|
const searchConfig = React.useMemo(() => {
|
|
6575
6622
|
const tableSearch = tableConfig?.search;
|
|
@@ -6717,7 +6764,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
6717
6764
|
deleteConfirmation: locale.bulkDeleteModal,
|
|
6718
6765
|
enableExport: canExport,
|
|
6719
6766
|
showDefaultExport: false,
|
|
6720
|
-
initialSorting:
|
|
6767
|
+
initialSorting: defaultSort,
|
|
6721
6768
|
onSelectedRowsChange: handleSelectedRowsChange,
|
|
6722
6769
|
getSelectedRows: getSelectedRowsRef
|
|
6723
6770
|
}),
|
|
@@ -7519,7 +7566,7 @@ function modalReducer(state, action$1) {
|
|
|
7519
7566
|
* Hook 主函数
|
|
7520
7567
|
*/
|
|
7521
7568
|
function useAutoCrudResource({ router, schema, query: queryTransform, options = {} }) {
|
|
7522
|
-
const { idKey = "id", defaultVariant = "dialog", hooks, toast: toastAdapter, exportFetcher } = options;
|
|
7569
|
+
const { idKey = "id", defaultVariant = "dialog", hooks, toast: toastAdapter, exportFetcher, defaultSort: defaultSortOption } = options;
|
|
7523
7570
|
const toast$1 = useMemo(() => toastAdapter === false ? noopToastAdapter : toastAdapter ?? defaultToastAdapter, [toastAdapter]);
|
|
7524
7571
|
const hooksRef = useRef(hooks);
|
|
7525
7572
|
useEffect(() => {
|
|
@@ -7527,12 +7574,13 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
7527
7574
|
}, [hooks]);
|
|
7528
7575
|
const metadata = (router.meta?.useQuery(void 0, { staleTime: 3e4 }))?.data;
|
|
7529
7576
|
const resolvedSchema = useMemo(() => mergeMetadataSchema(schema, metadata?.schema), [schema, metadata?.schema]);
|
|
7577
|
+
const defaultSorting = useMemo(() => defaultSortOption === false ? [] : defaultSortOption ?? getDefaultSortingForSchema(resolvedSchema), [defaultSortOption, resolvedSchema]);
|
|
7530
7578
|
const metadataFields = useMemo(() => readMetadataFields(metadata?.fields), [metadata?.fields]);
|
|
7531
7579
|
const columns = useMemo(() => createTableSchema(resolvedSchema), [resolvedSchema]);
|
|
7532
7580
|
const [urlParams] = useQueryStates({
|
|
7533
7581
|
page: parseAsInteger.withDefault(1),
|
|
7534
7582
|
perPage: parseAsInteger.withDefault(10),
|
|
7535
|
-
sort: getSortingStateParser().withDefault(
|
|
7583
|
+
sort: getSortingStateParser().withDefault(defaultSorting),
|
|
7536
7584
|
joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
|
|
7537
7585
|
search: parseAsString.withDefault("")
|
|
7538
7586
|
}, { shallow: false });
|
|
@@ -7820,6 +7868,7 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
7820
7868
|
},
|
|
7821
7869
|
schema: resolvedSchema,
|
|
7822
7870
|
fields: metadataFields,
|
|
7871
|
+
defaultSort: defaultSorting,
|
|
7823
7872
|
modal,
|
|
7824
7873
|
mutations: {
|
|
7825
7874
|
isCreating: createMutation.isPending,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordrhyme/auto-crud",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.3.
|
|
4
|
+
"version": "1.3.8",
|
|
5
5
|
"description": "Schema-first CRUD components with auto-generated tables and forms",
|
|
6
6
|
"author": "wordrhyme",
|
|
7
7
|
"license": "MIT",
|
|
@@ -62,9 +62,9 @@
|
|
|
62
62
|
"nanoid": "^5.1.6",
|
|
63
63
|
"tailwind-merge": "^3.5.0",
|
|
64
64
|
"vaul": "^1.1.2",
|
|
65
|
+
"@wordrhyme/formily-shadcn": "1.12.9",
|
|
65
66
|
"@wordrhyme/shadcn": "1.3.2",
|
|
66
|
-
"@wordrhyme/shadcn-ui": "1.32.4"
|
|
67
|
-
"@wordrhyme/formily-shadcn": "1.12.9"
|
|
67
|
+
"@wordrhyme/shadcn-ui": "1.32.4"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@tanstack/react-query": "^5.90.15",
|
|
@@ -83,9 +83,9 @@
|
|
|
83
83
|
"typescript": "^5.9.3",
|
|
84
84
|
"vitest": "^3.2.4",
|
|
85
85
|
"@internal/eslint-config": "0.3.0",
|
|
86
|
+
"@internal/prettier-config": "0.0.1",
|
|
86
87
|
"@internal/tsconfig": "0.1.0",
|
|
87
88
|
"@internal/tsdown-config": "0.1.0",
|
|
88
|
-
"@internal/prettier-config": "0.0.1",
|
|
89
89
|
"@internal/vitest-config": "0.1.0"
|
|
90
90
|
},
|
|
91
91
|
"prettier": "@internal/prettier-config",
|