@wordrhyme/auto-crud 1.12.0 → 1.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +101 -36
- package/dist/index.js +101 -36
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -4172,6 +4172,14 @@ function inferFilterVariantByFieldName(fieldName) {
|
|
|
4172
4172
|
//#region src/lib/schema-bridge/zod-to-columns.tsx
|
|
4173
4173
|
const parsedFieldCache = /* @__PURE__ */ new WeakMap();
|
|
4174
4174
|
const baseTableSchemaCache = /* @__PURE__ */ new WeakMap();
|
|
4175
|
+
/** Cache generated value cells; custom cells keep observing every table state update. */
|
|
4176
|
+
function memoCell(render) {
|
|
4177
|
+
const ValueCell = react.memo(function ValueCell$1(context) {
|
|
4178
|
+
useDateFormatterVersion();
|
|
4179
|
+
return render(context);
|
|
4180
|
+
});
|
|
4181
|
+
return (context) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueCell, { ...context });
|
|
4182
|
+
}
|
|
4175
4183
|
/**
|
|
4176
4184
|
* 解析 Zod 字段类型
|
|
4177
4185
|
*/
|
|
@@ -4392,7 +4400,7 @@ function createTableSchema(schema, options) {
|
|
|
4392
4400
|
column,
|
|
4393
4401
|
label
|
|
4394
4402
|
}),
|
|
4395
|
-
cell: ({ row }) => renderCell(row.getValue(key), parsed.type, meta.options),
|
|
4403
|
+
cell: memoCell(({ row }) => renderCell(row.getValue(key), parsed.type, meta.options)),
|
|
4396
4404
|
enableColumnFilter: true,
|
|
4397
4405
|
enableSorting: true,
|
|
4398
4406
|
meta,
|
|
@@ -5388,6 +5396,37 @@ function AutoTable({ schema, data, getRowId, expandedRow, defaultExpanded = fals
|
|
|
5388
5396
|
debounceMs,
|
|
5389
5397
|
throttleMs
|
|
5390
5398
|
]);
|
|
5399
|
+
const state = table.getState();
|
|
5400
|
+
const tableContent = (0, react.useMemo)(() => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTable, {
|
|
5401
|
+
pagination,
|
|
5402
|
+
table,
|
|
5403
|
+
classNames,
|
|
5404
|
+
expandedRow
|
|
5405
|
+
}), [
|
|
5406
|
+
table,
|
|
5407
|
+
data,
|
|
5408
|
+
columns,
|
|
5409
|
+
getRowId,
|
|
5410
|
+
pageCount,
|
|
5411
|
+
total,
|
|
5412
|
+
stableInitialState,
|
|
5413
|
+
pagination,
|
|
5414
|
+
classNames,
|
|
5415
|
+
expandedRow,
|
|
5416
|
+
state.columnFilters,
|
|
5417
|
+
state.columnOrder,
|
|
5418
|
+
state.columnPinning,
|
|
5419
|
+
state.columnSizing,
|
|
5420
|
+
state.columnSizingInfo,
|
|
5421
|
+
state.columnVisibility,
|
|
5422
|
+
state.expanded,
|
|
5423
|
+
state.globalFilter,
|
|
5424
|
+
state.grouping,
|
|
5425
|
+
state.pagination,
|
|
5426
|
+
state.rowPinning,
|
|
5427
|
+
state.rowSelection,
|
|
5428
|
+
state.sorting
|
|
5429
|
+
]);
|
|
5391
5430
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5392
5431
|
className: "space-y-4",
|
|
5393
5432
|
children: [
|
|
@@ -5415,12 +5454,7 @@ function AutoTable({ schema, data, getRowId, expandedRow, defaultExpanded = fals
|
|
|
5415
5454
|
]
|
|
5416
5455
|
})]
|
|
5417
5456
|
}),
|
|
5418
|
-
|
|
5419
|
-
pagination,
|
|
5420
|
-
table,
|
|
5421
|
-
classNames,
|
|
5422
|
-
expandedRow
|
|
5423
|
-
}),
|
|
5457
|
+
tableContent,
|
|
5424
5458
|
enableRowSelection && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutoTableActionBar, {
|
|
5425
5459
|
table,
|
|
5426
5460
|
onDeleteSelected,
|
|
@@ -7167,7 +7201,7 @@ function useDynamicFilterOptions(fields) {
|
|
|
7167
7201
|
react.useEffect(() => () => {
|
|
7168
7202
|
for (const field of Object.keys(controllersRef.current)) clearFieldRequest(field);
|
|
7169
7203
|
}, [clearFieldRequest]);
|
|
7170
|
-
return {
|
|
7204
|
+
return react.useMemo(() => ({
|
|
7171
7205
|
hasMoreByField,
|
|
7172
7206
|
labelOptionsByField,
|
|
7173
7207
|
loadingByField,
|
|
@@ -7177,7 +7211,17 @@ function useDynamicFilterOptions(fields) {
|
|
|
7177
7211
|
searchableByField,
|
|
7178
7212
|
loadMore: (field) => loadFieldOptions(field, true),
|
|
7179
7213
|
setSearchValue
|
|
7180
|
-
}
|
|
7214
|
+
}), [
|
|
7215
|
+
hasMoreByField,
|
|
7216
|
+
labelOptionsByField,
|
|
7217
|
+
loadingByField,
|
|
7218
|
+
optionsByField,
|
|
7219
|
+
registeredByField,
|
|
7220
|
+
searchValues,
|
|
7221
|
+
searchableByField,
|
|
7222
|
+
loadFieldOptions,
|
|
7223
|
+
setSearchValue
|
|
7224
|
+
]);
|
|
7181
7225
|
}
|
|
7182
7226
|
function rowHasResolveValue(row, field, value) {
|
|
7183
7227
|
const rowValue = row[field];
|
|
@@ -7288,15 +7332,22 @@ function useDynamicResolveOptions(fields, rows, hiddenColumns) {
|
|
|
7288
7332
|
rows,
|
|
7289
7333
|
sourceEntries
|
|
7290
7334
|
]);
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
const
|
|
7294
|
-
const
|
|
7295
|
-
|
|
7296
|
-
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7335
|
+
return react.useMemo(() => {
|
|
7336
|
+
const displayOptionsByField = { ...optionsByField };
|
|
7337
|
+
for (const field of Object.keys(fields ?? {}).filter((key) => !hiddenColumns.includes(key))) {
|
|
7338
|
+
const projectedOptions = rows.flatMap((row) => {
|
|
7339
|
+
const option = readCrudReferenceOption(row, field, row[field]);
|
|
7340
|
+
return option ? [option] : [];
|
|
7341
|
+
});
|
|
7342
|
+
if (projectedOptions.length > 0) displayOptionsByField[field] = mergeFilterOptions(projectedOptions, optionsByField[field] ?? []);
|
|
7343
|
+
}
|
|
7344
|
+
return { optionsByField: displayOptionsByField };
|
|
7345
|
+
}, [
|
|
7346
|
+
optionsByField,
|
|
7347
|
+
fields,
|
|
7348
|
+
hiddenColumns,
|
|
7349
|
+
rows
|
|
7350
|
+
]);
|
|
7300
7351
|
}
|
|
7301
7352
|
function getOptionLabel(value, options) {
|
|
7302
7353
|
const stringValue = String(value);
|
|
@@ -7404,7 +7455,7 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
|
|
|
7404
7455
|
const options = tableConfig?.dataSource ? mergeFieldOptions(dynamicResolveOptions, presentationOptions) : presentationOptions ?? mergedSharedDynamicOptions;
|
|
7405
7456
|
result[key] = {
|
|
7406
7457
|
...result[key],
|
|
7407
|
-
cell: ({ row, getValue }) => {
|
|
7458
|
+
cell: memoCell(({ row, getValue }) => {
|
|
7408
7459
|
const value = getValue();
|
|
7409
7460
|
return config.format?.(value, {
|
|
7410
7461
|
row: row.original,
|
|
@@ -7413,7 +7464,7 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
|
|
|
7413
7464
|
true: "true",
|
|
7414
7465
|
false: "false"
|
|
7415
7466
|
}, options, display ?? "auto");
|
|
7416
|
-
}
|
|
7467
|
+
})
|
|
7417
7468
|
};
|
|
7418
7469
|
}
|
|
7419
7470
|
}
|
|
@@ -7742,10 +7793,14 @@ function resolveActions(actions, defaults, rowActionsLocale, context) {
|
|
|
7742
7793
|
* 高级 CRUD 表格组件,封装了完整的增删改查流程
|
|
7743
7794
|
*/
|
|
7744
7795
|
function AutoCrudTable({ id, title, description, schema, resource, fields, table: tableConfig, form: formConfig, view: viewConfig, permissions, actions: actionItems, toolbar, toolbarActions, locale: localeProp, onCreate, onExport }) {
|
|
7745
|
-
const locale = resolveLocale(localeProp);
|
|
7796
|
+
const locale = react.useMemo(() => resolveLocale(localeProp), [localeProp]);
|
|
7746
7797
|
const getPagination = react.useCallback(() => id ? tablePagination.get(id) : void 0, [id]);
|
|
7747
7798
|
const registeredPagination = react.useSyncExternalStore(tablePagination.subscribe, getPagination, getPagination);
|
|
7748
7799
|
const pagination = tableConfig?.pagination ?? registeredPagination;
|
|
7800
|
+
const paginationOptions = react.useMemo(() => pagination ? {
|
|
7801
|
+
pageJumpLabel: locale.pagination?.pageJump,
|
|
7802
|
+
...pagination
|
|
7803
|
+
} : void 0, [pagination, locale.pagination?.pageJump]);
|
|
7749
7804
|
const resolvedSchema = resource.schema ?? schema;
|
|
7750
7805
|
const resolvedFields = react.useMemo(() => applyResourceTablePresentation(mergeFields(resource.fields, fields), resource.fields) ?? {}, [fields, resource.fields]);
|
|
7751
7806
|
const can = {
|
|
@@ -7777,6 +7832,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
7777
7832
|
denyFields,
|
|
7778
7833
|
tableConfig?.overrides
|
|
7779
7834
|
]);
|
|
7835
|
+
const excludedColumns = react.useMemo(() => hiddenColumns.filter((key) => !filterOnly.includes(key)), [hiddenColumns, filterOnly]);
|
|
7780
7836
|
const dynamicResolveOptions = useDynamicResolveOptions(resolvedFields, resource.tableData.data, hiddenColumns);
|
|
7781
7837
|
const resourceIdKey = resource.idKey ?? "id";
|
|
7782
7838
|
const actionRegistryVersion = useCrudActionsVersion();
|
|
@@ -7968,13 +8024,13 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
7968
8024
|
const { type } = parseZodField(resolvedSchema.shape[key]);
|
|
7969
8025
|
formattedOverrides[key] = {
|
|
7970
8026
|
...override,
|
|
7971
|
-
cell: (context) => {
|
|
8027
|
+
cell: memoCell((context) => {
|
|
7972
8028
|
const value = context.getValue();
|
|
7973
8029
|
return config.format?.(value, {
|
|
7974
8030
|
row: context.row.original,
|
|
7975
8031
|
target: "display"
|
|
7976
8032
|
}) ?? renderCell(value, type, context.column.columnDef.meta?.options);
|
|
7977
|
-
}
|
|
8033
|
+
})
|
|
7978
8034
|
};
|
|
7979
8035
|
}
|
|
7980
8036
|
}
|
|
@@ -8136,17 +8192,14 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
8136
8192
|
data: resource.tableData.data,
|
|
8137
8193
|
schema: resolvedSchema,
|
|
8138
8194
|
pageCount: resource.tableData.pageCount,
|
|
8139
|
-
pagination:
|
|
8140
|
-
pageJumpLabel: locale.pagination?.pageJump,
|
|
8141
|
-
...pagination
|
|
8142
|
-
} : void 0,
|
|
8195
|
+
pagination: paginationOptions,
|
|
8143
8196
|
...resource.tableData.total !== void 0 ? { total: resource.tableData.total } : {},
|
|
8144
8197
|
getRowId: tableConfig?.getRowId,
|
|
8145
8198
|
expandedRow: tableConfig?.expandedRow,
|
|
8146
8199
|
defaultExpanded: tableConfig?.defaultExpanded,
|
|
8147
8200
|
overrides: tableOverrides,
|
|
8148
8201
|
classNames: tableConfig?.classNames,
|
|
8149
|
-
exclude:
|
|
8202
|
+
exclude: excludedColumns,
|
|
8150
8203
|
filterOnly,
|
|
8151
8204
|
filterMode: tableConfig?.filterModes,
|
|
8152
8205
|
search: searchConfig,
|
|
@@ -8990,7 +9043,8 @@ function useAutoCrudResource({ router, schema, query: queryTransform, fields, op
|
|
|
8990
9043
|
(0, react.useEffect)(() => {
|
|
8991
9044
|
hooksRef.current = hooks;
|
|
8992
9045
|
}, [hooks]);
|
|
8993
|
-
const
|
|
9046
|
+
const metadataQuery = router.meta?.useQuery(void 0, { staleTime: 3e4 });
|
|
9047
|
+
const metadata = metadataQuery?.data;
|
|
8994
9048
|
const resolvedSchema = (0, react.useMemo)(() => mergeMetadataSchema(schema, metadata?.schema), [schema, metadata?.schema]);
|
|
8995
9049
|
const defaultSorting = (0, react.useMemo)(() => defaultSortOption === false ? [] : defaultSortOption ?? getDefaultSortingForSchema(resolvedSchema), [defaultSortOption, resolvedSchema]);
|
|
8996
9050
|
const metadataFields = (0, react.useMemo)(() => readMetadataFields(metadata?.fields), [metadata?.fields]);
|
|
@@ -9011,6 +9065,10 @@ function useAutoCrudResource({ router, schema, query: queryTransform, fields, op
|
|
|
9011
9065
|
search: parseAsString.withDefault("")
|
|
9012
9066
|
}, { shallow: false });
|
|
9013
9067
|
const [filters] = useReadableFilters(columns, { shallow: false });
|
|
9068
|
+
const metadataPending = Boolean(metadataQuery?.isPending);
|
|
9069
|
+
const [filtersReady, setFiltersReady] = (0, react.useState)(!metadataPending);
|
|
9070
|
+
(0, react.useEffect)(() => setFiltersReady(!metadataPending), [metadataPending]);
|
|
9071
|
+
const listReady = !metadataPending && filtersReady;
|
|
9014
9072
|
const queryInput = (0, react.useMemo)(() => {
|
|
9015
9073
|
const autoParams = {
|
|
9016
9074
|
page: urlParams.page,
|
|
@@ -9026,11 +9084,17 @@ function useAutoCrudResource({ router, schema, query: queryTransform, fields, op
|
|
|
9026
9084
|
filters,
|
|
9027
9085
|
queryTransform
|
|
9028
9086
|
]);
|
|
9087
|
+
const hasReadyListData = (0, react.useRef)(false);
|
|
9029
9088
|
const listQuery = router.list.useQuery(queryInput, {
|
|
9030
|
-
|
|
9089
|
+
enabled: listReady,
|
|
9090
|
+
placeholderData: hasReadyListData.current ? __tanstack_react_query.keepPreviousData : void 0,
|
|
9031
9091
|
staleTime: 0
|
|
9032
9092
|
});
|
|
9033
|
-
|
|
9093
|
+
(0, react.useEffect)(() => {
|
|
9094
|
+
if (listReady && listQuery.data !== void 0) hasReadyListData.current = true;
|
|
9095
|
+
}, [listReady, listQuery.data]);
|
|
9096
|
+
const listData = listReady ? listQuery.data : void 0;
|
|
9097
|
+
const tableRows = listData?.data ?? [];
|
|
9034
9098
|
const createMutation = router.create.useMutation();
|
|
9035
9099
|
const updateMutation = router.update.useMutation();
|
|
9036
9100
|
const deleteMutation = router.delete.useMutation();
|
|
@@ -9288,16 +9352,17 @@ function useAutoCrudResource({ router, schema, query: queryTransform, fields, op
|
|
|
9288
9352
|
]);
|
|
9289
9353
|
const canExport = !!(exportFetcher || exportQuery);
|
|
9290
9354
|
const refresh = (0, react.useCallback)(async () => {
|
|
9355
|
+
if (!listReady) return;
|
|
9291
9356
|
return listQuery.refetch();
|
|
9292
|
-
}, [listQuery]);
|
|
9357
|
+
}, [listQuery, listReady]);
|
|
9293
9358
|
return {
|
|
9294
9359
|
idKey,
|
|
9295
9360
|
tableData: {
|
|
9296
9361
|
data: tableRows,
|
|
9297
|
-
pageCount:
|
|
9298
|
-
...typeof
|
|
9299
|
-
isLoading: listQuery.isLoading,
|
|
9300
|
-
isFetching: listQuery.isFetching
|
|
9362
|
+
pageCount: listData?.pageCount ?? 0,
|
|
9363
|
+
...typeof listData?.total === "number" ? { total: listData.total } : {},
|
|
9364
|
+
isLoading: !listReady || listQuery.isLoading,
|
|
9365
|
+
isFetching: !listReady || listQuery.isFetching
|
|
9301
9366
|
},
|
|
9302
9367
|
schema: resolvedSchema,
|
|
9303
9368
|
fields: metadataFields,
|
package/dist/index.js
CHANGED
|
@@ -4157,6 +4157,14 @@ function inferFilterVariantByFieldName(fieldName) {
|
|
|
4157
4157
|
//#region src/lib/schema-bridge/zod-to-columns.tsx
|
|
4158
4158
|
const parsedFieldCache = /* @__PURE__ */ new WeakMap();
|
|
4159
4159
|
const baseTableSchemaCache = /* @__PURE__ */ new WeakMap();
|
|
4160
|
+
/** Cache generated value cells; custom cells keep observing every table state update. */
|
|
4161
|
+
function memoCell(render) {
|
|
4162
|
+
const ValueCell = React.memo(function ValueCell$1(context) {
|
|
4163
|
+
useDateFormatterVersion();
|
|
4164
|
+
return render(context);
|
|
4165
|
+
});
|
|
4166
|
+
return (context) => /* @__PURE__ */ jsx(ValueCell, { ...context });
|
|
4167
|
+
}
|
|
4160
4168
|
/**
|
|
4161
4169
|
* 解析 Zod 字段类型
|
|
4162
4170
|
*/
|
|
@@ -4377,7 +4385,7 @@ function createTableSchema(schema, options) {
|
|
|
4377
4385
|
column,
|
|
4378
4386
|
label
|
|
4379
4387
|
}),
|
|
4380
|
-
cell: ({ row }) => renderCell(row.getValue(key), parsed.type, meta.options),
|
|
4388
|
+
cell: memoCell(({ row }) => renderCell(row.getValue(key), parsed.type, meta.options)),
|
|
4381
4389
|
enableColumnFilter: true,
|
|
4382
4390
|
enableSorting: true,
|
|
4383
4391
|
meta,
|
|
@@ -5373,6 +5381,37 @@ function AutoTable({ schema, data, getRowId, expandedRow, defaultExpanded = fals
|
|
|
5373
5381
|
debounceMs,
|
|
5374
5382
|
throttleMs
|
|
5375
5383
|
]);
|
|
5384
|
+
const state = table.getState();
|
|
5385
|
+
const tableContent = useMemo(() => /* @__PURE__ */ jsx(DataTable, {
|
|
5386
|
+
pagination,
|
|
5387
|
+
table,
|
|
5388
|
+
classNames,
|
|
5389
|
+
expandedRow
|
|
5390
|
+
}), [
|
|
5391
|
+
table,
|
|
5392
|
+
data,
|
|
5393
|
+
columns,
|
|
5394
|
+
getRowId,
|
|
5395
|
+
pageCount,
|
|
5396
|
+
total,
|
|
5397
|
+
stableInitialState,
|
|
5398
|
+
pagination,
|
|
5399
|
+
classNames,
|
|
5400
|
+
expandedRow,
|
|
5401
|
+
state.columnFilters,
|
|
5402
|
+
state.columnOrder,
|
|
5403
|
+
state.columnPinning,
|
|
5404
|
+
state.columnSizing,
|
|
5405
|
+
state.columnSizingInfo,
|
|
5406
|
+
state.columnVisibility,
|
|
5407
|
+
state.expanded,
|
|
5408
|
+
state.globalFilter,
|
|
5409
|
+
state.grouping,
|
|
5410
|
+
state.pagination,
|
|
5411
|
+
state.rowPinning,
|
|
5412
|
+
state.rowSelection,
|
|
5413
|
+
state.sorting
|
|
5414
|
+
]);
|
|
5376
5415
|
return /* @__PURE__ */ jsxs("div", {
|
|
5377
5416
|
className: "space-y-4",
|
|
5378
5417
|
children: [
|
|
@@ -5400,12 +5439,7 @@ function AutoTable({ schema, data, getRowId, expandedRow, defaultExpanded = fals
|
|
|
5400
5439
|
]
|
|
5401
5440
|
})]
|
|
5402
5441
|
}),
|
|
5403
|
-
|
|
5404
|
-
pagination,
|
|
5405
|
-
table,
|
|
5406
|
-
classNames,
|
|
5407
|
-
expandedRow
|
|
5408
|
-
}),
|
|
5442
|
+
tableContent,
|
|
5409
5443
|
enableRowSelection && /* @__PURE__ */ jsx(AutoTableActionBar, {
|
|
5410
5444
|
table,
|
|
5411
5445
|
onDeleteSelected,
|
|
@@ -7152,7 +7186,7 @@ function useDynamicFilterOptions(fields) {
|
|
|
7152
7186
|
React.useEffect(() => () => {
|
|
7153
7187
|
for (const field of Object.keys(controllersRef.current)) clearFieldRequest(field);
|
|
7154
7188
|
}, [clearFieldRequest]);
|
|
7155
|
-
return {
|
|
7189
|
+
return React.useMemo(() => ({
|
|
7156
7190
|
hasMoreByField,
|
|
7157
7191
|
labelOptionsByField,
|
|
7158
7192
|
loadingByField,
|
|
@@ -7162,7 +7196,17 @@ function useDynamicFilterOptions(fields) {
|
|
|
7162
7196
|
searchableByField,
|
|
7163
7197
|
loadMore: (field) => loadFieldOptions(field, true),
|
|
7164
7198
|
setSearchValue
|
|
7165
|
-
}
|
|
7199
|
+
}), [
|
|
7200
|
+
hasMoreByField,
|
|
7201
|
+
labelOptionsByField,
|
|
7202
|
+
loadingByField,
|
|
7203
|
+
optionsByField,
|
|
7204
|
+
registeredByField,
|
|
7205
|
+
searchValues,
|
|
7206
|
+
searchableByField,
|
|
7207
|
+
loadFieldOptions,
|
|
7208
|
+
setSearchValue
|
|
7209
|
+
]);
|
|
7166
7210
|
}
|
|
7167
7211
|
function rowHasResolveValue(row, field, value) {
|
|
7168
7212
|
const rowValue = row[field];
|
|
@@ -7273,15 +7317,22 @@ function useDynamicResolveOptions(fields, rows, hiddenColumns) {
|
|
|
7273
7317
|
rows,
|
|
7274
7318
|
sourceEntries
|
|
7275
7319
|
]);
|
|
7276
|
-
|
|
7277
|
-
|
|
7278
|
-
const
|
|
7279
|
-
const
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7320
|
+
return React.useMemo(() => {
|
|
7321
|
+
const displayOptionsByField = { ...optionsByField };
|
|
7322
|
+
for (const field of Object.keys(fields ?? {}).filter((key) => !hiddenColumns.includes(key))) {
|
|
7323
|
+
const projectedOptions = rows.flatMap((row) => {
|
|
7324
|
+
const option = readCrudReferenceOption(row, field, row[field]);
|
|
7325
|
+
return option ? [option] : [];
|
|
7326
|
+
});
|
|
7327
|
+
if (projectedOptions.length > 0) displayOptionsByField[field] = mergeFilterOptions(projectedOptions, optionsByField[field] ?? []);
|
|
7328
|
+
}
|
|
7329
|
+
return { optionsByField: displayOptionsByField };
|
|
7330
|
+
}, [
|
|
7331
|
+
optionsByField,
|
|
7332
|
+
fields,
|
|
7333
|
+
hiddenColumns,
|
|
7334
|
+
rows
|
|
7335
|
+
]);
|
|
7285
7336
|
}
|
|
7286
7337
|
function getOptionLabel(value, options) {
|
|
7287
7338
|
const stringValue = String(value);
|
|
@@ -7389,7 +7440,7 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
|
|
|
7389
7440
|
const options = tableConfig?.dataSource ? mergeFieldOptions(dynamicResolveOptions, presentationOptions) : presentationOptions ?? mergedSharedDynamicOptions;
|
|
7390
7441
|
result[key] = {
|
|
7391
7442
|
...result[key],
|
|
7392
|
-
cell: ({ row, getValue }) => {
|
|
7443
|
+
cell: memoCell(({ row, getValue }) => {
|
|
7393
7444
|
const value = getValue();
|
|
7394
7445
|
return config.format?.(value, {
|
|
7395
7446
|
row: row.original,
|
|
@@ -7398,7 +7449,7 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
|
|
|
7398
7449
|
true: "true",
|
|
7399
7450
|
false: "false"
|
|
7400
7451
|
}, options, display ?? "auto");
|
|
7401
|
-
}
|
|
7452
|
+
})
|
|
7402
7453
|
};
|
|
7403
7454
|
}
|
|
7404
7455
|
}
|
|
@@ -7727,10 +7778,14 @@ function resolveActions(actions, defaults, rowActionsLocale, context) {
|
|
|
7727
7778
|
* 高级 CRUD 表格组件,封装了完整的增删改查流程
|
|
7728
7779
|
*/
|
|
7729
7780
|
function AutoCrudTable({ id, title, description, schema, resource, fields, table: tableConfig, form: formConfig, view: viewConfig, permissions, actions: actionItems, toolbar, toolbarActions, locale: localeProp, onCreate, onExport }) {
|
|
7730
|
-
const locale = resolveLocale(localeProp);
|
|
7781
|
+
const locale = React.useMemo(() => resolveLocale(localeProp), [localeProp]);
|
|
7731
7782
|
const getPagination = React.useCallback(() => id ? tablePagination.get(id) : void 0, [id]);
|
|
7732
7783
|
const registeredPagination = React.useSyncExternalStore(tablePagination.subscribe, getPagination, getPagination);
|
|
7733
7784
|
const pagination = tableConfig?.pagination ?? registeredPagination;
|
|
7785
|
+
const paginationOptions = React.useMemo(() => pagination ? {
|
|
7786
|
+
pageJumpLabel: locale.pagination?.pageJump,
|
|
7787
|
+
...pagination
|
|
7788
|
+
} : void 0, [pagination, locale.pagination?.pageJump]);
|
|
7734
7789
|
const resolvedSchema = resource.schema ?? schema;
|
|
7735
7790
|
const resolvedFields = React.useMemo(() => applyResourceTablePresentation(mergeFields(resource.fields, fields), resource.fields) ?? {}, [fields, resource.fields]);
|
|
7736
7791
|
const can = {
|
|
@@ -7762,6 +7817,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
7762
7817
|
denyFields,
|
|
7763
7818
|
tableConfig?.overrides
|
|
7764
7819
|
]);
|
|
7820
|
+
const excludedColumns = React.useMemo(() => hiddenColumns.filter((key) => !filterOnly.includes(key)), [hiddenColumns, filterOnly]);
|
|
7765
7821
|
const dynamicResolveOptions = useDynamicResolveOptions(resolvedFields, resource.tableData.data, hiddenColumns);
|
|
7766
7822
|
const resourceIdKey = resource.idKey ?? "id";
|
|
7767
7823
|
const actionRegistryVersion = useCrudActionsVersion();
|
|
@@ -7953,13 +8009,13 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
7953
8009
|
const { type } = parseZodField(resolvedSchema.shape[key]);
|
|
7954
8010
|
formattedOverrides[key] = {
|
|
7955
8011
|
...override,
|
|
7956
|
-
cell: (context) => {
|
|
8012
|
+
cell: memoCell((context) => {
|
|
7957
8013
|
const value = context.getValue();
|
|
7958
8014
|
return config.format?.(value, {
|
|
7959
8015
|
row: context.row.original,
|
|
7960
8016
|
target: "display"
|
|
7961
8017
|
}) ?? renderCell(value, type, context.column.columnDef.meta?.options);
|
|
7962
|
-
}
|
|
8018
|
+
})
|
|
7963
8019
|
};
|
|
7964
8020
|
}
|
|
7965
8021
|
}
|
|
@@ -8121,17 +8177,14 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
8121
8177
|
data: resource.tableData.data,
|
|
8122
8178
|
schema: resolvedSchema,
|
|
8123
8179
|
pageCount: resource.tableData.pageCount,
|
|
8124
|
-
pagination:
|
|
8125
|
-
pageJumpLabel: locale.pagination?.pageJump,
|
|
8126
|
-
...pagination
|
|
8127
|
-
} : void 0,
|
|
8180
|
+
pagination: paginationOptions,
|
|
8128
8181
|
...resource.tableData.total !== void 0 ? { total: resource.tableData.total } : {},
|
|
8129
8182
|
getRowId: tableConfig?.getRowId,
|
|
8130
8183
|
expandedRow: tableConfig?.expandedRow,
|
|
8131
8184
|
defaultExpanded: tableConfig?.defaultExpanded,
|
|
8132
8185
|
overrides: tableOverrides,
|
|
8133
8186
|
classNames: tableConfig?.classNames,
|
|
8134
|
-
exclude:
|
|
8187
|
+
exclude: excludedColumns,
|
|
8135
8188
|
filterOnly,
|
|
8136
8189
|
filterMode: tableConfig?.filterModes,
|
|
8137
8190
|
search: searchConfig,
|
|
@@ -8975,7 +9028,8 @@ function useAutoCrudResource({ router, schema, query: queryTransform, fields, op
|
|
|
8975
9028
|
useEffect(() => {
|
|
8976
9029
|
hooksRef.current = hooks;
|
|
8977
9030
|
}, [hooks]);
|
|
8978
|
-
const
|
|
9031
|
+
const metadataQuery = router.meta?.useQuery(void 0, { staleTime: 3e4 });
|
|
9032
|
+
const metadata = metadataQuery?.data;
|
|
8979
9033
|
const resolvedSchema = useMemo(() => mergeMetadataSchema(schema, metadata?.schema), [schema, metadata?.schema]);
|
|
8980
9034
|
const defaultSorting = useMemo(() => defaultSortOption === false ? [] : defaultSortOption ?? getDefaultSortingForSchema(resolvedSchema), [defaultSortOption, resolvedSchema]);
|
|
8981
9035
|
const metadataFields = useMemo(() => readMetadataFields(metadata?.fields), [metadata?.fields]);
|
|
@@ -8996,6 +9050,10 @@ function useAutoCrudResource({ router, schema, query: queryTransform, fields, op
|
|
|
8996
9050
|
search: parseAsString.withDefault("")
|
|
8997
9051
|
}, { shallow: false });
|
|
8998
9052
|
const [filters] = useReadableFilters(columns, { shallow: false });
|
|
9053
|
+
const metadataPending = Boolean(metadataQuery?.isPending);
|
|
9054
|
+
const [filtersReady, setFiltersReady] = useState(!metadataPending);
|
|
9055
|
+
useEffect(() => setFiltersReady(!metadataPending), [metadataPending]);
|
|
9056
|
+
const listReady = !metadataPending && filtersReady;
|
|
8999
9057
|
const queryInput = useMemo(() => {
|
|
9000
9058
|
const autoParams = {
|
|
9001
9059
|
page: urlParams.page,
|
|
@@ -9011,11 +9069,17 @@ function useAutoCrudResource({ router, schema, query: queryTransform, fields, op
|
|
|
9011
9069
|
filters,
|
|
9012
9070
|
queryTransform
|
|
9013
9071
|
]);
|
|
9072
|
+
const hasReadyListData = useRef(false);
|
|
9014
9073
|
const listQuery = router.list.useQuery(queryInput, {
|
|
9015
|
-
|
|
9074
|
+
enabled: listReady,
|
|
9075
|
+
placeholderData: hasReadyListData.current ? keepPreviousData : void 0,
|
|
9016
9076
|
staleTime: 0
|
|
9017
9077
|
});
|
|
9018
|
-
|
|
9078
|
+
useEffect(() => {
|
|
9079
|
+
if (listReady && listQuery.data !== void 0) hasReadyListData.current = true;
|
|
9080
|
+
}, [listReady, listQuery.data]);
|
|
9081
|
+
const listData = listReady ? listQuery.data : void 0;
|
|
9082
|
+
const tableRows = listData?.data ?? [];
|
|
9019
9083
|
const createMutation = router.create.useMutation();
|
|
9020
9084
|
const updateMutation = router.update.useMutation();
|
|
9021
9085
|
const deleteMutation = router.delete.useMutation();
|
|
@@ -9273,16 +9337,17 @@ function useAutoCrudResource({ router, schema, query: queryTransform, fields, op
|
|
|
9273
9337
|
]);
|
|
9274
9338
|
const canExport = !!(exportFetcher || exportQuery);
|
|
9275
9339
|
const refresh = useCallback(async () => {
|
|
9340
|
+
if (!listReady) return;
|
|
9276
9341
|
return listQuery.refetch();
|
|
9277
|
-
}, [listQuery]);
|
|
9342
|
+
}, [listQuery, listReady]);
|
|
9278
9343
|
return {
|
|
9279
9344
|
idKey,
|
|
9280
9345
|
tableData: {
|
|
9281
9346
|
data: tableRows,
|
|
9282
|
-
pageCount:
|
|
9283
|
-
...typeof
|
|
9284
|
-
isLoading: listQuery.isLoading,
|
|
9285
|
-
isFetching: listQuery.isFetching
|
|
9347
|
+
pageCount: listData?.pageCount ?? 0,
|
|
9348
|
+
...typeof listData?.total === "number" ? { total: listData.total } : {},
|
|
9349
|
+
isLoading: !listReady || listQuery.isLoading,
|
|
9350
|
+
isFetching: !listReady || listQuery.isFetching
|
|
9286
9351
|
},
|
|
9287
9352
|
schema: resolvedSchema,
|
|
9288
9353
|
fields: metadataFields,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordrhyme/auto-crud",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.12.
|
|
4
|
+
"version": "1.12.2",
|
|
5
5
|
"description": "Schema-first CRUD components with auto-generated tables and forms",
|
|
6
6
|
"author": "wordrhyme",
|
|
7
7
|
"license": "MIT",
|
|
@@ -94,11 +94,11 @@
|
|
|
94
94
|
"tsdown": "^0.15.12",
|
|
95
95
|
"typescript": "^5.9.3",
|
|
96
96
|
"vitest": "^3.2.4",
|
|
97
|
-
"@internal/eslint-config": "0.3.0",
|
|
98
97
|
"@internal/prettier-config": "0.0.1",
|
|
99
|
-
"@internal/tsdown-config": "0.1.0",
|
|
100
98
|
"@internal/tsconfig": "0.1.0",
|
|
101
|
-
"@internal/
|
|
99
|
+
"@internal/eslint-config": "0.3.0",
|
|
100
|
+
"@internal/vitest-config": "0.1.0",
|
|
101
|
+
"@internal/tsdown-config": "0.1.0"
|
|
102
102
|
},
|
|
103
103
|
"prettier": "@internal/prettier-config",
|
|
104
104
|
"scripts": {
|