@wordrhyme/auto-crud 1.1.1 → 1.1.3
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 +209 -48
- package/dist/index.d.cts +50 -19
- package/dist/index.d.ts +34 -3
- package/dist/index.js +209 -49
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -59,6 +59,8 @@ let __pixpilot_formily_shadcn = require("@pixpilot/formily-shadcn");
|
|
|
59
59
|
__pixpilot_formily_shadcn = __toESM(__pixpilot_formily_shadcn);
|
|
60
60
|
let __formily_react = require("@formily/react");
|
|
61
61
|
__formily_react = __toESM(__formily_react);
|
|
62
|
+
let __pixpilot_shadcn_ui = require("@pixpilot/shadcn-ui");
|
|
63
|
+
__pixpilot_shadcn_ui = __toESM(__pixpilot_shadcn_ui);
|
|
62
64
|
let sonner = require("sonner");
|
|
63
65
|
sonner = __toESM(sonner);
|
|
64
66
|
|
|
@@ -2705,8 +2707,17 @@ function DataTableViewOptions({ table, disabled,...props }) {
|
|
|
2705
2707
|
|
|
2706
2708
|
//#endregion
|
|
2707
2709
|
//#region src/components/auto-crud/auto-table-simple-filters.tsx
|
|
2708
|
-
function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilters, onFiltersChange }) {
|
|
2709
|
-
const columns = react.useMemo(() => table.getAllColumns().filter((col) => col.getCanFilter()),
|
|
2710
|
+
function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilters, onFiltersChange, leading }) {
|
|
2711
|
+
const columns = react.useMemo(() => table.getAllColumns().filter((col) => col.getCanFilter()).sort((a, b) => {
|
|
2712
|
+
const readOrder = (column) => {
|
|
2713
|
+
const metaIndex = column.columnDef.meta?.index;
|
|
2714
|
+
const columnIndex = column.columnDef.index;
|
|
2715
|
+
return typeof metaIndex === "number" ? metaIndex : typeof columnIndex === "number" ? columnIndex : 1e4;
|
|
2716
|
+
};
|
|
2717
|
+
const orderDiff = readOrder(a) - readOrder(b);
|
|
2718
|
+
if (orderDiff !== 0) return orderDiff;
|
|
2719
|
+
return a.getIndex() - b.getIndex();
|
|
2720
|
+
}), [table]);
|
|
2710
2721
|
const queryStateOptions = table.options.meta?.queryStateOptions;
|
|
2711
2722
|
const [queryFilters, setQueryFilters] = useReadableFilters(columns, {
|
|
2712
2723
|
...queryStateOptions,
|
|
@@ -2823,8 +2834,9 @@ function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilte
|
|
|
2823
2834
|
if (!mounted) return null;
|
|
2824
2835
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2825
2836
|
ref: containerRef,
|
|
2826
|
-
className: "flex flex-wrap items-center gap-2 min-w-0",
|
|
2837
|
+
className: "flex flex-1 flex-wrap items-center gap-2 min-w-0",
|
|
2827
2838
|
children: [
|
|
2839
|
+
leading,
|
|
2828
2840
|
filterColumns.map((column, index) => {
|
|
2829
2841
|
const meta = column.columnDef.meta;
|
|
2830
2842
|
const value = getFilterValue(column.id);
|
|
@@ -3957,7 +3969,7 @@ function createTableSchema(schema, options) {
|
|
|
3957
3969
|
if (cached) return [...cached];
|
|
3958
3970
|
}
|
|
3959
3971
|
const shape = schema.shape;
|
|
3960
|
-
const
|
|
3972
|
+
const columnEntries = [];
|
|
3961
3973
|
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
3962
3974
|
if (exclude.includes(key)) continue;
|
|
3963
3975
|
const override = overrides?.[key];
|
|
@@ -3978,20 +3990,31 @@ function createTableSchema(schema, options) {
|
|
|
3978
3990
|
options: override?.meta?.options ?? autoOptions
|
|
3979
3991
|
};
|
|
3980
3992
|
const { meta: _ignoredMeta,...restOverride } = override ?? {};
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
+
const sourceIndex = columnEntries.length;
|
|
3994
|
+
const order = typeof restOverride.index === "number" ? restOverride.index : typeof meta.index === "number" ? meta.index : 1e4 + sourceIndex;
|
|
3995
|
+
columnEntries.push({
|
|
3996
|
+
order,
|
|
3997
|
+
sourceIndex,
|
|
3998
|
+
column: {
|
|
3999
|
+
id: key,
|
|
4000
|
+
accessorKey: key,
|
|
4001
|
+
header: ({ column }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTableColumnHeader, {
|
|
4002
|
+
column,
|
|
4003
|
+
label
|
|
4004
|
+
}),
|
|
4005
|
+
cell: ({ row }) => renderCell(row.getValue(key), parsed.type),
|
|
4006
|
+
enableColumnFilter: true,
|
|
4007
|
+
enableSorting: true,
|
|
4008
|
+
meta,
|
|
4009
|
+
...restOverride
|
|
4010
|
+
}
|
|
3993
4011
|
});
|
|
3994
4012
|
}
|
|
4013
|
+
const columns = columnEntries.sort((a, b) => {
|
|
4014
|
+
const orderDiff = a.order - b.order;
|
|
4015
|
+
if (orderDiff !== 0) return orderDiff;
|
|
4016
|
+
return a.sourceIndex - b.sourceIndex;
|
|
4017
|
+
}).map((entry) => entry.column);
|
|
3995
4018
|
if (canCache) baseTableSchemaCache.set(schema, columns);
|
|
3996
4019
|
return columns;
|
|
3997
4020
|
}
|
|
@@ -4318,12 +4341,12 @@ function AutoTableActionBar({ table, onDeleteSelected, onUpdateSelected, batchUp
|
|
|
4318
4341
|
if (action.component) return renderComponent(action.component);
|
|
4319
4342
|
if (action.type === "batchUpdate") return renderBatchUpdate(action.type);
|
|
4320
4343
|
if (action.type === "export") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ActionBarItem, {
|
|
4321
|
-
onClick: () => action.onClick ? action.onClick(selectedRows, actionContext) : onExport(),
|
|
4344
|
+
onClick: (event) => action.onClick ? action.onClick(selectedRows, actionContext, event) : onExport(),
|
|
4322
4345
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Download, {}), action.label ?? "Export"]
|
|
4323
4346
|
}, "export");
|
|
4324
4347
|
if (action.type === "delete") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ActionBarItem, {
|
|
4325
4348
|
variant: "destructive",
|
|
4326
|
-
onClick: () => action.onClick ? action.onClick(selectedRows, actionContext) : onDelete(),
|
|
4349
|
+
onClick: (event) => action.onClick ? action.onClick(selectedRows, actionContext, event) : onDelete(),
|
|
4327
4350
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Trash2, {}), action.label ?? "Delete"]
|
|
4328
4351
|
}, "delete");
|
|
4329
4352
|
return null;
|
|
@@ -4345,7 +4368,7 @@ function AutoTableActionBar({ table, onDeleteSelected, onUpdateSelected, batchUp
|
|
|
4345
4368
|
if (!action.label || !action.onClick) return null;
|
|
4346
4369
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionBarItem, {
|
|
4347
4370
|
variant: action.variant === "destructive" ? "destructive" : "secondary",
|
|
4348
|
-
onClick: () => action.onClick?.(selectedRows, actionContext),
|
|
4371
|
+
onClick: (event) => action.onClick?.(selectedRows, actionContext, event),
|
|
4349
4372
|
children: action.label
|
|
4350
4373
|
}, `custom-${index}`);
|
|
4351
4374
|
}, [
|
|
@@ -4663,10 +4686,19 @@ const filterModeConfig = {
|
|
|
4663
4686
|
tooltip: "Linear-style command filters"
|
|
4664
4687
|
}
|
|
4665
4688
|
};
|
|
4666
|
-
function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode = "simple", onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, actionBarActions, initialSorting, enableExport = true, showDefaultExport = true, onSelectedCountChange, getSelectedRows }) {
|
|
4689
|
+
function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode = "simple", search = false, onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, actionBarActions, initialSorting, enableExport = true, showDefaultExport = true, onSelectedCountChange, getSelectedRows }) {
|
|
4667
4690
|
const modes = filterMode ? Array.isArray(filterMode) ? filterMode : [filterMode] : DEFAULT_MODES;
|
|
4668
4691
|
const [currentMode, setCurrentMode] = useQueryState("filterMode", parseAsStringEnum(modes).withDefault(modes[0] ?? "simple"));
|
|
4669
4692
|
const showToggle = modes.length > 1;
|
|
4693
|
+
const [searchValue, setSearchValue] = useUrlState("search", parseAsString.withDefault(""), {
|
|
4694
|
+
shallow: false,
|
|
4695
|
+
clearOnDefault: true
|
|
4696
|
+
});
|
|
4697
|
+
const [, setSearchPage] = useUrlState("page", parseAsInteger.withDefault(1), {
|
|
4698
|
+
shallow: false,
|
|
4699
|
+
clearOnDefault: true
|
|
4700
|
+
});
|
|
4701
|
+
const searchConfig = search && typeof search === "object" ? search : {};
|
|
4670
4702
|
const { table, shallow, debounceMs, throttleMs } = useDataTable({
|
|
4671
4703
|
data,
|
|
4672
4704
|
columns: (0, react.useMemo)(() => {
|
|
@@ -4738,11 +4770,21 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
|
|
|
4738
4770
|
})
|
|
4739
4771
|
})
|
|
4740
4772
|
})] }) : null;
|
|
4773
|
+
const searchInput = search ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__pixpilot_shadcn.Input, {
|
|
4774
|
+
value: searchValue,
|
|
4775
|
+
onChange: (event) => {
|
|
4776
|
+
setSearchValue(event.target.value);
|
|
4777
|
+
setSearchPage(1);
|
|
4778
|
+
},
|
|
4779
|
+
placeholder: searchConfig.placeholder ?? "搜索",
|
|
4780
|
+
className: "h-8 w-48 shrink-0"
|
|
4781
|
+
}) : null;
|
|
4741
4782
|
const filtersContent = (0, react.useMemo)(() => {
|
|
4742
4783
|
switch (currentMode) {
|
|
4743
4784
|
case "simple": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutoTableSimpleFilters, {
|
|
4744
4785
|
table,
|
|
4745
|
-
shallow
|
|
4786
|
+
shallow,
|
|
4787
|
+
leading: searchInput
|
|
4746
4788
|
});
|
|
4747
4789
|
case "command": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTableFilterMenu, {
|
|
4748
4790
|
table,
|
|
@@ -4762,6 +4804,7 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
|
|
|
4762
4804
|
currentMode,
|
|
4763
4805
|
table,
|
|
4764
4806
|
shallow,
|
|
4807
|
+
searchInput,
|
|
4765
4808
|
debounceMs,
|
|
4766
4809
|
throttleMs
|
|
4767
4810
|
]);
|
|
@@ -4773,10 +4816,14 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
|
|
|
4773
4816
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4774
4817
|
className: "flex flex-1 items-start gap-2 min-h-[40px]",
|
|
4775
4818
|
"data-filter-parent": true,
|
|
4776
|
-
children: [
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4819
|
+
children: [
|
|
4820
|
+
currentMode !== "simple" && searchInput,
|
|
4821
|
+
currentMode !== "simple" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTableSortList, {
|
|
4822
|
+
table,
|
|
4823
|
+
align: "start"
|
|
4824
|
+
}),
|
|
4825
|
+
filtersContent
|
|
4826
|
+
]
|
|
4780
4827
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4781
4828
|
className: "flex items-center gap-2",
|
|
4782
4829
|
children: [
|
|
@@ -4965,10 +5012,44 @@ function createEditFormSchema(schema, options) {
|
|
|
4965
5012
|
|
|
4966
5013
|
//#endregion
|
|
4967
5014
|
//#region src/components/auto-crud/auto-form.tsx
|
|
5015
|
+
const COMBOBOX_LIST_CLASS = "[&_[cmdk-list]]:max-h-[360px]";
|
|
4968
5016
|
const FormilySwitch = (0, __formily_react.connect)(__pixpilot_shadcn.Switch, (0, __formily_react.mapProps)({
|
|
4969
5017
|
value: "checked",
|
|
4970
5018
|
onInput: "onCheckedChange"
|
|
4971
5019
|
}));
|
|
5020
|
+
const FormilyCombobox = (0, __formily_react.connect)(AutoCrudCombobox, (0, __formily_react.mapProps)({ dataSource: "options" }));
|
|
5021
|
+
function AutoCrudCombobox({ options = [], filter, className,...props }) {
|
|
5022
|
+
const resolvedFilter = (0, react.useMemo)(() => {
|
|
5023
|
+
if (typeof filter === "function") return filter;
|
|
5024
|
+
return createComboboxFilter(options);
|
|
5025
|
+
}, [filter, options]);
|
|
5026
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__pixpilot_shadcn_ui.Combobox, {
|
|
5027
|
+
...props,
|
|
5028
|
+
options,
|
|
5029
|
+
filter: resolvedFilter,
|
|
5030
|
+
className: (0, __pixpilot_shadcn.cn)(COMBOBOX_LIST_CLASS, className)
|
|
5031
|
+
});
|
|
5032
|
+
}
|
|
5033
|
+
function createComboboxFilter(options) {
|
|
5034
|
+
const searchTextByValue = new Map(options.map((option) => [option.value, collectSearchText(option.value, option.label, option.searchText, option.keywords).toLocaleLowerCase()]));
|
|
5035
|
+
return (value, search, keywords) => {
|
|
5036
|
+
const query = search.trim().toLocaleLowerCase();
|
|
5037
|
+
if (!query) return 1;
|
|
5038
|
+
const searchText = collectSearchText(searchTextByValue.get(value), keywords).toLocaleLowerCase();
|
|
5039
|
+
if (searchText === query) return 2;
|
|
5040
|
+
return searchText.includes(query) ? 1 : 0;
|
|
5041
|
+
};
|
|
5042
|
+
}
|
|
5043
|
+
function collectSearchText(...parts) {
|
|
5044
|
+
const texts = [];
|
|
5045
|
+
for (const part of parts) {
|
|
5046
|
+
if (!part) continue;
|
|
5047
|
+
if (Array.isArray(part)) texts.push(...part.map(String));
|
|
5048
|
+
else if (typeof part === "object") texts.push(...Object.values(part).filter(Boolean).map(String));
|
|
5049
|
+
else texts.push(String(part));
|
|
5050
|
+
}
|
|
5051
|
+
return texts.join(" ");
|
|
5052
|
+
}
|
|
4972
5053
|
function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, overrides, mode = "create", loading = false, gridColumns = 1, labelAlign = "top", labelWidth, showSubmitButton = true }, ref) {
|
|
4973
5054
|
const form = (0, react.useMemo)(() => (0, __formily_core.createForm)({ initialValues }), [JSON.stringify(initialValues)]);
|
|
4974
5055
|
const formSchema = (0, react.useMemo)(() => createEditFormSchema(zodSchema, {
|
|
@@ -4993,10 +5074,16 @@ function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, overrides,
|
|
|
4993
5074
|
form,
|
|
4994
5075
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__pixpilot_formily_shadcn.JsonSchemaField, {
|
|
4995
5076
|
schema: formSchema,
|
|
4996
|
-
components: { fields: {
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5077
|
+
components: { fields: {
|
|
5078
|
+
Combobox: {
|
|
5079
|
+
component: FormilyCombobox,
|
|
5080
|
+
decorator: "FormItem"
|
|
5081
|
+
},
|
|
5082
|
+
Switch: {
|
|
5083
|
+
component: FormilySwitch,
|
|
5084
|
+
decorator: "FormItem"
|
|
5085
|
+
}
|
|
5086
|
+
} }
|
|
5000
5087
|
}), showSubmitButton && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5001
5088
|
className: "flex justify-end gap-2 mt-6",
|
|
5002
5089
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__pixpilot_shadcn.Button, {
|
|
@@ -6088,6 +6175,11 @@ function resolveActions(actionsOrFn, defaults, rowActionsLocale) {
|
|
|
6088
6175
|
*/
|
|
6089
6176
|
function AutoCrudTable({ title, description, schema, resource, fields, table: tableConfig, form: formConfig, permissions, actions: actionItems, toolbarActions, locale: localeProp, onCreate }) {
|
|
6090
6177
|
const locale = resolveLocale(localeProp);
|
|
6178
|
+
const resolvedSchema = resource.schema ?? schema;
|
|
6179
|
+
const resolvedFields = react.useMemo(() => ({
|
|
6180
|
+
...fields,
|
|
6181
|
+
...resource.fields
|
|
6182
|
+
}), [fields, resource.fields]);
|
|
6091
6183
|
const can = {
|
|
6092
6184
|
create: permissions?.can?.create ?? true,
|
|
6093
6185
|
update: permissions?.can?.update ?? true,
|
|
@@ -6103,10 +6195,10 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
|
|
|
6103
6195
|
const [exporting, setExporting] = react.useState(false);
|
|
6104
6196
|
const getSelectedRowsRef = react.useRef(null);
|
|
6105
6197
|
const importColumns = react.useMemo(() => {
|
|
6106
|
-
const shape =
|
|
6198
|
+
const shape = resolvedSchema.shape;
|
|
6107
6199
|
const denySet = new Set(denyFields ?? []);
|
|
6108
6200
|
return Object.keys(shape).filter((key) => !denySet.has(key));
|
|
6109
|
-
}, [
|
|
6201
|
+
}, [resolvedSchema, denyFields]);
|
|
6110
6202
|
const handleExport = react.useCallback(async (mode) => {
|
|
6111
6203
|
const filename = title ?? "export";
|
|
6112
6204
|
const excludeColumns = denyFields;
|
|
@@ -6138,21 +6230,34 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
|
|
|
6138
6230
|
setExporting(false);
|
|
6139
6231
|
}
|
|
6140
6232
|
}, [selectedCount, handleExport]);
|
|
6141
|
-
const tableOverrides = react.useMemo(() => buildTableOverrides(
|
|
6142
|
-
const formOverrides = react.useMemo(() => buildFormOverrides(
|
|
6143
|
-
|
|
6233
|
+
const tableOverrides = react.useMemo(() => buildTableOverrides(resolvedFields, tableConfig?.overrides), [resolvedFields, tableConfig?.overrides]);
|
|
6234
|
+
const formOverrides = react.useMemo(() => buildFormOverrides(resolvedFields, formConfig?.overrides, denyFields), [
|
|
6235
|
+
resolvedFields,
|
|
6144
6236
|
formConfig?.overrides,
|
|
6145
6237
|
denyFields
|
|
6146
6238
|
]);
|
|
6147
|
-
const hiddenColumns = react.useMemo(() => buildHiddenColumns(
|
|
6148
|
-
|
|
6239
|
+
const hiddenColumns = react.useMemo(() => buildHiddenColumns(resolvedFields, tableConfig?.hidden, denyFields), [
|
|
6240
|
+
resolvedFields,
|
|
6149
6241
|
tableConfig?.hidden,
|
|
6150
6242
|
denyFields
|
|
6151
6243
|
]);
|
|
6152
|
-
const
|
|
6153
|
-
|
|
6244
|
+
const searchConfig = react.useMemo(() => {
|
|
6245
|
+
const tableSearch = tableConfig?.search;
|
|
6246
|
+
if (tableSearch === false) return false;
|
|
6247
|
+
if (tableSearch && typeof tableSearch === "object") return tableSearch;
|
|
6248
|
+
return Object.values(resolvedFields).some((field) => field?.search === true) ? true : false;
|
|
6249
|
+
}, [resolvedFields, tableConfig?.search]);
|
|
6250
|
+
const batchFields = react.useMemo(() => buildBatchUpdateFields(resolvedSchema, tableConfig?.batchFields, resolvedFields), [
|
|
6251
|
+
resolvedSchema,
|
|
6154
6252
|
tableConfig?.batchFields,
|
|
6155
|
-
|
|
6253
|
+
resolvedFields
|
|
6254
|
+
]);
|
|
6255
|
+
const formInitialValues = react.useMemo(() => {
|
|
6256
|
+
return resource.modal.createOpen ? resource.modal.copySource ?? void 0 : resource.modal.selected ?? void 0;
|
|
6257
|
+
}, [
|
|
6258
|
+
resource.modal.createOpen,
|
|
6259
|
+
resource.modal.copySource,
|
|
6260
|
+
resource.modal.selected
|
|
6156
6261
|
]);
|
|
6157
6262
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6158
6263
|
className: "space-y-4",
|
|
@@ -6233,11 +6338,12 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
|
|
|
6233
6338
|
}),
|
|
6234
6339
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutoTable, {
|
|
6235
6340
|
data: resource.tableData.data,
|
|
6236
|
-
schema,
|
|
6341
|
+
schema: resolvedSchema,
|
|
6237
6342
|
pageCount: resource.tableData.pageCount,
|
|
6238
6343
|
overrides: tableOverrides,
|
|
6239
6344
|
exclude: hiddenColumns,
|
|
6240
6345
|
filterMode: tableConfig?.filterModes,
|
|
6346
|
+
search: searchConfig,
|
|
6241
6347
|
actions: resolveActions(actionItems, {
|
|
6242
6348
|
openView: resource.handlers.openView,
|
|
6243
6349
|
openEdit: can.update ? resource.handlers.openEdit : void 0,
|
|
@@ -6258,8 +6364,8 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
|
|
|
6258
6364
|
open: resource.modal.createOpen || resource.modal.editOpen,
|
|
6259
6365
|
onOpenChange: (open) => !open && resource.handlers.closeModals(),
|
|
6260
6366
|
mode: resource.modal.createOpen ? "create" : "edit",
|
|
6261
|
-
schema,
|
|
6262
|
-
initialValues:
|
|
6367
|
+
schema: resolvedSchema,
|
|
6368
|
+
initialValues: formInitialValues,
|
|
6263
6369
|
onSubmit: (values) => {
|
|
6264
6370
|
if (resource.modal.createOpen) resource.handlers.submitCreate(values);
|
|
6265
6371
|
else resource.handlers.submitUpdate(values);
|
|
@@ -6276,8 +6382,8 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
|
|
|
6276
6382
|
onOpenChange: (open) => !open && resource.handlers.closeModals(),
|
|
6277
6383
|
variant: resource.modal.variant,
|
|
6278
6384
|
data: resource.modal.selected,
|
|
6279
|
-
schema,
|
|
6280
|
-
fields,
|
|
6385
|
+
schema: resolvedSchema,
|
|
6386
|
+
fields: resolvedFields,
|
|
6281
6387
|
denyFields,
|
|
6282
6388
|
locale
|
|
6283
6389
|
}),
|
|
@@ -6996,6 +7102,53 @@ const noopToastAdapter = {
|
|
|
6996
7102
|
info: () => {},
|
|
6997
7103
|
warning: () => {}
|
|
6998
7104
|
};
|
|
7105
|
+
function isRecord(value) {
|
|
7106
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7107
|
+
}
|
|
7108
|
+
function isJsonSchemaObject(value) {
|
|
7109
|
+
return isRecord(value) && isRecord(value.properties);
|
|
7110
|
+
}
|
|
7111
|
+
function readJsonSchemaType(property) {
|
|
7112
|
+
return Array.isArray(property.type) ? property.type.find((item) => item !== "null") : property.type;
|
|
7113
|
+
}
|
|
7114
|
+
function jsonPropertyToZod(property, required) {
|
|
7115
|
+
const enumValues = property.enum?.filter((value) => typeof value === "string");
|
|
7116
|
+
let schema;
|
|
7117
|
+
if (enumValues && enumValues.length > 0) schema = zod.z.enum(enumValues);
|
|
7118
|
+
else switch (readJsonSchemaType(property)) {
|
|
7119
|
+
case "number":
|
|
7120
|
+
case "integer":
|
|
7121
|
+
schema = zod.z.number();
|
|
7122
|
+
break;
|
|
7123
|
+
case "boolean":
|
|
7124
|
+
schema = zod.z.boolean();
|
|
7125
|
+
break;
|
|
7126
|
+
case "array":
|
|
7127
|
+
schema = zod.z.array(zod.z.unknown());
|
|
7128
|
+
break;
|
|
7129
|
+
case "object":
|
|
7130
|
+
schema = zod.z.record(zod.z.string(), zod.z.unknown());
|
|
7131
|
+
break;
|
|
7132
|
+
case "string":
|
|
7133
|
+
schema = property.format === "date" || property.format === "date-time" ? zod.z.coerce.date() : zod.z.string();
|
|
7134
|
+
break;
|
|
7135
|
+
default: schema = zod.z.unknown();
|
|
7136
|
+
}
|
|
7137
|
+
return required ? schema : schema.optional();
|
|
7138
|
+
}
|
|
7139
|
+
function mergeMetadataSchema(baseSchema, metadataSchema) {
|
|
7140
|
+
if (!isJsonSchemaObject(metadataSchema)) return baseSchema;
|
|
7141
|
+
const required = new Set(Array.isArray(metadataSchema.required) ? metadataSchema.required.filter((field) => typeof field === "string") : []);
|
|
7142
|
+
const extensionShape = {};
|
|
7143
|
+
for (const [field, property] of Object.entries(metadataSchema.properties ?? {})) {
|
|
7144
|
+
if (field in baseSchema.shape) continue;
|
|
7145
|
+
extensionShape[field] = jsonPropertyToZod(property, required.has(field));
|
|
7146
|
+
}
|
|
7147
|
+
return Object.keys(extensionShape).length > 0 ? baseSchema.extend(extensionShape) : baseSchema;
|
|
7148
|
+
}
|
|
7149
|
+
function readMetadataFields(fields) {
|
|
7150
|
+
return isRecord(fields) ? fields : void 0;
|
|
7151
|
+
}
|
|
6999
7152
|
/**
|
|
7000
7153
|
* Modal 状态 Reducer
|
|
7001
7154
|
*/
|
|
@@ -7054,12 +7207,16 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
7054
7207
|
(0, react.useEffect)(() => {
|
|
7055
7208
|
hooksRef.current = hooks;
|
|
7056
7209
|
}, [hooks]);
|
|
7057
|
-
const
|
|
7210
|
+
const metadata = (router.meta?.useQuery(void 0, { staleTime: 3e4 }))?.data;
|
|
7211
|
+
const resolvedSchema = (0, react.useMemo)(() => mergeMetadataSchema(schema, metadata?.schema), [schema, metadata?.schema]);
|
|
7212
|
+
const metadataFields = (0, react.useMemo)(() => readMetadataFields(metadata?.fields), [metadata?.fields]);
|
|
7213
|
+
const columns = (0, react.useMemo)(() => createTableSchema(resolvedSchema), [resolvedSchema]);
|
|
7058
7214
|
const [urlParams] = useQueryStates({
|
|
7059
7215
|
page: parseAsInteger.withDefault(1),
|
|
7060
7216
|
perPage: parseAsInteger.withDefault(10),
|
|
7061
7217
|
sort: getSortingStateParser().withDefault([]),
|
|
7062
|
-
joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and")
|
|
7218
|
+
joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
|
|
7219
|
+
search: parseAsString.withDefault("")
|
|
7063
7220
|
}, { shallow: false });
|
|
7064
7221
|
const [filters] = useReadableFilters(columns, { shallow: false });
|
|
7065
7222
|
const queryInput = (0, react.useMemo)(() => {
|
|
@@ -7068,7 +7225,8 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
7068
7225
|
perPage: urlParams.perPage,
|
|
7069
7226
|
sort: urlParams.sort,
|
|
7070
7227
|
filters,
|
|
7071
|
-
joinOperator: urlParams.joinOperator
|
|
7228
|
+
joinOperator: urlParams.joinOperator,
|
|
7229
|
+
...urlParams.search.trim() ? { search: urlParams.search.trim() } : {}
|
|
7072
7230
|
};
|
|
7073
7231
|
return queryTransform ? queryTransform(autoParams) : autoParams;
|
|
7074
7232
|
}, [
|
|
@@ -7080,6 +7238,7 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
7080
7238
|
placeholderData: keepPreviousData,
|
|
7081
7239
|
staleTime: 0
|
|
7082
7240
|
});
|
|
7241
|
+
const tableRows = listQuery.data?.data ?? [];
|
|
7083
7242
|
const createMutation = router.create.useMutation();
|
|
7084
7243
|
const updateMutation = router.update.useMutation();
|
|
7085
7244
|
const deleteMutation = router.delete.useMutation();
|
|
@@ -7332,11 +7491,13 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
7332
7491
|
const canExport = !!(exportFetcher || exportQuery);
|
|
7333
7492
|
return {
|
|
7334
7493
|
tableData: {
|
|
7335
|
-
data:
|
|
7494
|
+
data: tableRows,
|
|
7336
7495
|
pageCount: listQuery.data?.pageCount ?? 0,
|
|
7337
7496
|
isLoading: listQuery.isLoading,
|
|
7338
7497
|
isFetching: listQuery.isFetching
|
|
7339
7498
|
},
|
|
7499
|
+
schema: resolvedSchema,
|
|
7500
|
+
fields: metadataFields,
|
|
7340
7501
|
modal,
|
|
7341
7502
|
mutations: {
|
|
7342
7503
|
isCreating: createMutation.isPending,
|