ra-core
Version:
Core components of react-admin, a frontend Framework for building admin applications on top of REST services, using ES6, React
264 lines • 10.6 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.useReferenceManyFieldController = void 0;
const react_1 = require("react");
const react_query_1 = require("@tanstack/react-query");
const get_js_1 = __importDefault(require("lodash/get.js"));
const isEqual_js_1 = __importDefault(require("lodash/isEqual.js"));
const debounce_js_1 = __importDefault(require("lodash/debounce.js"));
const util_1 = require("../../util/index.cjs");
const dataProvider_1 = require("../../dataProvider/index.cjs");
const notification_1 = require("../../notification/index.cjs");
const useListController_1 = require("../list/useListController.cjs");
const usePaginationState_1 = __importDefault(require("../usePaginationState.cjs"));
const useRecordSelection_1 = require("../list/useRecordSelection.cjs");
const useSortState_1 = __importDefault(require("../useSortState.cjs"));
const core_1 = require("../../core/index.cjs");
const record_1 = require("../record/index.cjs");
const export_1 = require("../../export/index.cjs");
/**
* Fetch reference records, and return them when available
*
* Uses dataProvider.getManyReference() internally.
*
* @example // fetch the comments related to the current post
* const { isPending, data } = useReferenceManyFieldController({
* reference: 'comments',
* target: 'post_id',
* record: { id: 123, title: 'hello, world' },
* resource: 'posts',
* });
*
* @param {Object} props
* @param {string} props.reference The linked resource name. Required.
* @param {string} props.target The target resource key. Required.
* @param {Object} props.filter The filter applied on the recorded records list
* @param {number} props.page the page number
* @param {number} props.perPage the number of item per page
* @param {Object} props.record The current resource record
* @param {string} props.resource The current resource name
* @param {Object} props.sort the sort to apply to the referenced records
* @param {string} props.source The key of the linked resource identifier
* @param {UseQuery Options} props.queryOptions `react-query` options`
*
* @returns {ListControllerResult} The reference many props
*/
const useReferenceManyFieldController = (props) => {
const { debounce = 500, reference, target, filter = defaultFilter, exporter = export_1.defaultExporter, source = 'id', page: initialPage, perPage: initialPerPage, sort: initialSort = { field: 'id', order: 'DESC' }, queryOptions = {}, } = props;
const notify = (0, notification_1.useNotify)();
const record = (0, record_1.useRecordContext)(props);
const resource = (0, core_1.useResourceContext)(props);
const dataProvider = (0, dataProvider_1.useDataProvider)();
const queryClient = (0, react_query_1.useQueryClient)();
const { meta, ...otherQueryOptions } = queryOptions;
// pagination logic
const { page, setPage, perPage, setPerPage } = (0, usePaginationState_1.default)({
page: initialPage,
perPage: initialPerPage,
});
// sort logic
const { sort, setSort: setSortState } = (0, useSortState_1.default)(initialSort);
const setSort = (0, react_1.useCallback)((sort) => {
setSortState(sort);
setPage(1);
}, [setPage, setSortState]);
// selection logic
const [selectedIds, selectionModifiers] = (0, useRecordSelection_1.useRecordSelection)({
resource: reference,
storeKey: props.storeKey ?? `${resource}.${record?.id}.${reference}`,
});
const onUnselectItems = (0, react_1.useCallback)((fromAllStoreKeys) => {
return selectionModifiers.unselect(selectedIds, fromAllStoreKeys);
}, [selectedIds, selectionModifiers]);
// filter logic
const filterRef = (0, react_1.useRef)(filter);
const [displayedFilters, setDisplayedFilters] = (0, react_1.useState)({});
const [filterValues, setFilterValues] = (0, react_1.useState)(filter);
const hideFilter = (0, react_1.useCallback)((filterName) => {
setDisplayedFilters(previousState => {
const { [filterName]: _, ...newState } = previousState;
return newState;
});
setFilterValues(previousState => {
const { [filterName]: _, ...newState } = previousState;
return newState;
});
}, [setDisplayedFilters, setFilterValues]);
const showFilter = (0, react_1.useCallback)((filterName, defaultValue) => {
setDisplayedFilters(previousState => ({
...previousState,
[filterName]: true,
}));
setFilterValues(previousState => ({
...previousState,
[filterName]: defaultValue,
}));
}, [setDisplayedFilters, setFilterValues]);
// eslint-disable-next-line react-hooks/exhaustive-deps
const debouncedSetFilters = (0, react_1.useCallback)((0, debounce_js_1.default)((filters, displayedFilters) => {
setFilterValues((0, util_1.removeEmpty)(filters));
setDisplayedFilters(displayedFilters);
setPage(1);
}, debounce), [setDisplayedFilters, setFilterValues, setPage]);
const setFilters = (0, react_1.useCallback)((filters, displayedFilters, debounce = false) => {
if (debounce) {
debouncedSetFilters(filters, displayedFilters);
}
else {
setFilterValues((0, util_1.removeEmpty)(filters));
setDisplayedFilters(displayedFilters);
setPage(1);
}
}, [setDisplayedFilters, setFilterValues, setPage, debouncedSetFilters]);
// handle filter prop change
(0, react_1.useEffect)(() => {
if (!(0, isEqual_js_1.default)(filter, filterRef.current)) {
filterRef.current = filter;
setFilterValues(filter);
}
}, [filter]);
const recordValue = (0, get_js_1.default)(record, source);
const { data, total, meta: responseMeta, pageInfo, error, isFetching, isLoading, isPaused, isPending, isPlaceholderData, refetch, } = (0, dataProvider_1.useGetManyReference)(reference, {
target,
id: recordValue,
pagination: { page, perPage },
sort,
filter: filterValues,
meta,
}, {
enabled: recordValue != null,
placeholderData: previousData => previousData,
onError: error => notify(typeof error === 'string'
? error
: error?.message ||
'ra.notification.http_error', {
type: 'error',
messageArgs: {
_: typeof error === 'string'
? error
: error?.message
? error.message
: undefined,
},
}),
...otherQueryOptions,
});
const onSelectAll = (0, util_1.useEvent)(async ({ limit = 250, queryOptions = {}, } = {}) => {
const { meta, onSuccess, onError } = queryOptions;
try {
const results = await queryClient.fetchQuery({
queryKey: [
reference,
'getManyReference',
{
target,
id: (0, get_js_1.default)(record, source),
pagination: { page: 1, perPage: limit },
sort,
filter,
meta,
},
],
queryFn: () => dataProvider.getManyReference(reference, {
target,
id: (0, get_js_1.default)(record, source),
pagination: { page: 1, perPage: limit },
sort,
filter,
meta,
}),
});
const allIds = results.data?.map(({ id }) => id) || [];
selectionModifiers.select(allIds);
if (allIds.length === limit) {
notify('ra.message.select_all_limit_reached', {
messageArgs: { max: limit },
type: 'warning',
});
}
if (onSuccess) {
onSuccess(results);
}
return results.data;
}
catch (error) {
if (onError) {
onError(error);
}
notify('ra.notification.http_error', { type: 'warning' });
}
});
const getData = (0, util_1.useEvent)(async ({ maxResults, meta: metaOverride } = {}) => {
if (recordValue == null || total === 0) {
return [];
}
const limit = maxResults ?? (total != null ? total : useListController_1.DEFAULT_MAX_RESULTS);
const { data } = await queryClient.fetchQuery({
queryKey: [
reference,
'getManyReference',
{
target,
id: recordValue,
pagination: { page: 1, perPage: limit },
sort,
filter: filterValues,
meta: metaOverride ?? meta,
},
],
queryFn: () => dataProvider.getManyReference(reference, {
target,
id: recordValue,
pagination: { page: 1, perPage: limit },
sort,
filter: filterValues,
meta: metaOverride ?? meta,
}),
});
return data;
});
return {
sort,
data,
meta: responseMeta,
defaultTitle: undefined,
displayedFilters,
error,
exporter,
filterValues,
hideFilter,
isFetching,
isLoading,
isPaused,
isPending,
isPlaceholderData,
onSelect: selectionModifiers.select,
onSelectAll,
onToggleItem: selectionModifiers.toggle,
onUnselectItems,
page,
perPage,
refetch,
resource: reference,
selectedIds,
setFilters,
setPage,
setPerPage,
hasNextPage: pageInfo
? pageInfo.hasNextPage
: total != null
? page * perPage < total
: undefined,
hasPreviousPage: pageInfo ? pageInfo.hasPreviousPage : page > 1,
setSort,
showFilter,
total,
getData,
};
};
exports.useReferenceManyFieldController = useReferenceManyFieldController;
const defaultFilter = {};
//# sourceMappingURL=useReferenceManyFieldController.js.map