ra-core
Version:
Core components of react-admin, a frontend Framework for building admin applications on top of REST services, using ES6, React
241 lines • 9.01 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.sanitizeListRestProps = exports.getListControllerProps = exports.injectedProps = exports.DEFAULT_MAX_RESULTS = exports.useListController = void 0;
const react_1 = require("react");
const auth_1 = require("../../auth/index.cjs");
const i18n_1 = require("../../i18n/index.cjs");
const notification_1 = require("../../notification/index.cjs");
const dataProvider_1 = require("../../dataProvider/index.cjs");
const core_1 = require("../../core/index.cjs");
const useRecordSelection_1 = require("./useRecordSelection.cjs");
const useListParams_1 = require("./useListParams.cjs");
const useSelectAll_1 = require("./useSelectAll.cjs");
const export_1 = require("../../export/index.cjs");
const queryReducer_1 = require("./queryReducer.cjs");
const util_1 = require("../../util/index.cjs");
/**
* Prepare data for the List view
*
* @param {Object} props The props passed to the List component.
*
* @return {Object} controllerProps Fetched and computed data for the List view
*
* @example
*
* import { useListController } from 'react-admin';
* import ListView from './ListView';
*
* const MyList = props => {
* const controllerProps = useListController(props);
* return <ListView {...controllerProps} {...props} />;
* }
*/
const useListController = (props = {}) => {
const { debounce = 500, disableAuthentication = false, disableSyncWithLocation = false, exporter = export_1.defaultExporter, filter, filterDefaultValues, perPage = 10, queryOptions = {}, sort = defaultSort, storeKey, } = props;
const resource = (0, core_1.useResourceContext)(props);
const { meta, ...otherQueryOptions } = queryOptions;
if (!resource) {
throw new Error(`useListController requires a non-empty resource prop or context`);
}
if (filter &&
((0, react_1.isValidElement)(filter) ||
(Array.isArray(filter) && filter.some(react_1.isValidElement)))) {
throw new Error('useListController received a React element as `filter` props. If you intended to set the list filter elements, use the `filters` (with an s) prop instead. The `filter` prop is internal and should not be set by the developer.');
}
const { isPending: isPendingAuthenticated } = (0, auth_1.useAuthenticated)({
enabled: !disableAuthentication,
});
const { isPending: isPendingCanAccess } = (0, auth_1.useRequireAccess)({
action: 'list',
resource,
enabled: !disableAuthentication && !isPendingAuthenticated,
});
const translate = (0, i18n_1.useTranslate)();
const notify = (0, notification_1.useNotify)();
const dataProvider = (0, dataProvider_1.useDataProvider)();
const [query, queryModifiers] = (0, useListParams_1.useListParams)({
debounce,
disableSyncWithLocation,
filterDefaultValues,
perPage,
resource,
sort,
storeKey,
});
const [selectedIds, selectionModifiers] = (0, useRecordSelection_1.useRecordSelection)({
resource,
disableSyncWithStore: storeKey === false,
storeKey: storeKey === false ? undefined : storeKey,
});
const onUnselectItems = (0, react_1.useCallback)((fromAllStoreKeys) => {
return selectionModifiers.unselect(selectedIds, fromAllStoreKeys);
}, [selectedIds, selectionModifiers]);
const { data, pageInfo, total, meta: responseMeta, error, isLoading, isFetching, isPending, refetch, isPaused, isPlaceholderData, } = (0, dataProvider_1.useGetList)(resource, {
pagination: {
page: query.page,
perPage: query.perPage,
},
sort: { field: query.sort, order: query.order },
filter: { ...query.filter, ...filter },
meta,
}, {
enabled: (!isPendingAuthenticated && !isPendingCanAccess) ||
disableAuthentication,
placeholderData: previousData => previousData,
retry: false,
onError: error => notify(error?.message || 'ra.notification.http_error', {
type: 'error',
messageArgs: {
_: error?.message,
},
}),
...otherQueryOptions,
});
// change page if there is no data
(0, react_1.useEffect)(() => {
if (query.page <= 0 ||
(!isFetching &&
query.page > 1 &&
(data == null || data?.length === 0))) {
// Query for a page that doesn't exist, set page to 1
queryModifiers.setPage(1);
return;
}
if (total == null) {
return;
}
const totalPages = Math.ceil(total / query.perPage) || 1;
if (!isFetching && query.page > totalPages) {
// Query for a page out of bounds, set page to the last existing page
// It occurs when deleting the last element of the last page
queryModifiers.setPage(totalPages);
}
}, [isFetching, query.page, query.perPage, data, queryModifiers, total]);
const currentSort = (0, react_1.useMemo)(() => ({
field: query.sort,
order: query.order,
}), [query.sort, query.order]);
const getResourceLabel = (0, core_1.useGetResourceLabel)();
const defaultTitle = translate(`resources.${resource}.page.list`, {
_: translate('ra.page.list', {
name: getResourceLabel(resource, 2),
}),
});
const onSelectAll = (0, useSelectAll_1.useSelectAll)({
resource,
sort: { field: query.sort, order: query.order },
filter: { ...query.filter, ...filter },
disableSyncWithStore: storeKey === false,
storeKey: storeKey === false ? undefined : storeKey,
});
const getData = (0, util_1.useEvent)(async ({ maxResults, meta: metaOverride } = {}) => {
if (total === 0) {
return [];
}
const limit = maxResults ?? (total != null ? total : exports.DEFAULT_MAX_RESULTS);
const { data } = await dataProvider.getList(resource, {
sort: currentSort,
filter: filter
? { ...query.filterValues, ...filter }
: query.filterValues,
pagination: { page: 1, perPage: limit },
meta: metaOverride ?? meta,
});
return data;
});
return {
sort: currentSort,
data,
meta: responseMeta,
defaultTitle,
displayedFilters: query.displayedFilters,
error,
exporter,
filter,
filterValues: query.filterValues,
hideFilter: queryModifiers.hideFilter,
isFetching,
isLoading,
isPaused,
isPending,
isPlaceholderData,
onSelect: selectionModifiers.select,
onSelectAll,
onToggleItem: selectionModifiers.toggle,
onUnselectItems,
page: query.page,
perPage: query.perPage,
refetch,
resource,
selectedIds,
setFilters: queryModifiers.setFilters,
setPage: queryModifiers.setPage,
setPerPage: queryModifiers.setPerPage,
setSort: queryModifiers.setSort,
showFilter: queryModifiers.showFilter,
total,
getData,
hasNextPage: pageInfo
? pageInfo.hasNextPage
: total != null
? query.page * query.perPage < total
: undefined,
hasPreviousPage: pageInfo ? pageInfo.hasPreviousPage : query.page > 1,
};
};
exports.useListController = useListController;
const defaultSort = {
field: 'id',
order: queryReducer_1.SORT_ASC,
};
exports.DEFAULT_MAX_RESULTS = 1000;
exports.injectedProps = [
'sort',
'data',
'defaultTitle',
'displayedFilters',
'error',
'exporter',
'getData',
'filterValues',
'hasNextPage',
'hasPreviousPage',
'hideFilter',
'isFetching',
'isLoading',
'isPending',
'onSelect',
'onSelectAll',
'onToggleItem',
'onUnselectItems',
'page',
'perPage',
'refetch',
'refresh',
'resource',
'selectedIds',
'setFilters',
'setPage',
'setPerPage',
'setSort',
'showFilter',
'total',
'totalPages',
];
/**
* Select the props injected by the useListController hook
* to be passed to the List children need
* This is an implementation of pick()
*/
const getListControllerProps = props => exports.injectedProps.reduce((acc, key) => ({ ...acc, [key]: props[key] }), {});
exports.getListControllerProps = getListControllerProps;
/**
* Select the props not injected by the useListController hook
* to be used inside the List children to sanitize props injected by List
* This is an implementation of omit()
*/
const sanitizeListRestProps = props => Object.keys(props)
.filter(propName => !exports.injectedProps.includes(propName))
.reduce((acc, key) => ({ ...acc, [key]: props[key] }), {});
exports.sanitizeListRestProps = sanitizeListRestProps;
//# sourceMappingURL=useListController.js.map