ra-core
Version:
Core components of react-admin, a frontend Framework for building admin applications on top of REST services, using ES6, React
334 lines • 13.6 kB
JavaScript
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getNumberOrDefault = exports.getQuery = exports.hasCustomParams = exports.parseQueryFromLocation = exports.useListParams = void 0;
var react_1 = require("react");
var query_string_1 = require("query-string");
var debounce_1 = __importDefault(require("lodash/debounce"));
var react_router_dom_1 = require("react-router-dom");
var store_1 = require("../../store");
var queryReducer_1 = __importStar(require("./queryReducer"));
var removeEmpty_1 = __importDefault(require("../../util/removeEmpty"));
var hooks_1 = require("../../util/hooks");
/**
* Get the list parameters (page, sort, filters) and modifiers.
*
* These parameters are merged from 3 sources:
* - the query string from the URL
* - the params stored in the state (from previous navigation)
* - the options passed to the hook (including the filter defaultValues)
*
* @returns {Array} A tuple [parameters, modifiers].
* Destructure as [
* { page, perPage, sort, order, filter, filterValues, displayedFilters, requestSignature },
* { setFilters, hideFilter, showFilter, setPage, setPerPage, setSort }
* ]
*
* @example
*
* const [listParams, listParamsActions] = useListParams({
* resource: 'posts',
* location: location // From react-router. Injected to your component by react-admin inside a List
* filterDefaultValues: {
* published: true
* },
* sort: {
* field: 'published_at',
* order: 'DESC'
* },
* perPage: 25
* });
*
* const {
* page,
* perPage,
* sort,
* order,
* filter,
* filterValues,
* displayedFilters,
* requestSignature
* } = listParams;
*
* const {
* setFilters,
* hideFilter,
* showFilter,
* setPage,
* setPerPage,
* setSort,
* } = listParamsActions;
*/
var useListParams = function (_a) {
var _b = _a.debounce, debounce = _b === void 0 ? 500 : _b, _c = _a.disableSyncWithLocation, disableSyncWithLocation = _c === void 0 ? false : _c, filterDefaultValues = _a.filterDefaultValues, _d = _a.perPage, perPage = _d === void 0 ? 10 : _d, resource = _a.resource, _e = _a.sort, sort = _e === void 0 ? defaultSort : _e, _f = _a.storeKey, storeKey = _f === void 0 ? disableSyncWithLocation ? false : "".concat(resource, ".listParams") : _f;
var location = (0, react_router_dom_1.useLocation)();
var navigate = (0, react_router_dom_1.useNavigate)();
var _g = (0, react_1.useState)(defaultParams), localParams = _g[0], setLocalParams = _g[1];
// As we can't conditionally call a hook, if the storeKey is false,
// we'll ignore the params variable later on and won't call setParams either.
var _h = (0, store_1.useStore)(storeKey || "".concat(resource, ".listParams"), defaultParams), params = _h[0], setParams = _h[1];
var tempParams = (0, react_1.useRef)();
var isMounted = (0, hooks_1.useIsMounted)();
var requestSignature = [
location.search,
resource,
storeKey,
JSON.stringify(!storeKey ? localParams : params),
JSON.stringify(filterDefaultValues),
JSON.stringify(sort),
perPage,
disableSyncWithLocation,
];
var queryFromLocation = disableSyncWithLocation
? {}
: (0, exports.parseQueryFromLocation)(location);
var query = (0, react_1.useMemo)(function () {
return (0, exports.getQuery)({
queryFromLocation: queryFromLocation,
params: !storeKey ? localParams : params,
filterDefaultValues: filterDefaultValues,
sort: sort,
perPage: perPage,
});
}, requestSignature // eslint-disable-line react-hooks/exhaustive-deps
);
// if the location includes params (for example from a link like
// the categories products on the demo), we need to persist them in the
// store as well so that we don't lose them after a redirection back
// to the list
(0, react_1.useEffect)(function () {
if (Object.keys(queryFromLocation).length > 0) {
setParams(query);
}
}, [location.search]); // eslint-disable-line
var changeParams = (0, react_1.useCallback)(function (action) {
// do not change params if the component is already unmounted
// this is necessary because changeParams can be debounced, and therefore
// executed after the component is unmounted
if (!isMounted.current)
return;
if (!tempParams.current) {
// no other changeParams action dispatched this tick
tempParams.current = (0, queryReducer_1.default)(query, action);
// schedule side effects for next tick
setTimeout(function () {
if (!tempParams.current) {
// the side effects were already processed by another changeParams
return;
}
if (disableSyncWithLocation && !storeKey) {
setLocalParams(tempParams.current);
}
else if (disableSyncWithLocation && !!storeKey) {
setParams(tempParams.current);
}
else {
// the useEffect above will apply the changes to the params in the store
navigate({
search: "?".concat((0, query_string_1.stringify)(__assign(__assign({}, tempParams.current), { filter: JSON.stringify(tempParams.current.filter), displayedFilters: JSON.stringify(tempParams.current.displayedFilters) }))),
}, {
state: {
_scrollToTop: action.type === queryReducer_1.SET_PAGE,
},
});
}
tempParams.current = undefined;
}, 0);
}
else {
// side effects already scheduled, just change the params
tempParams.current = (0, queryReducer_1.default)(tempParams.current, action);
}
}, __spreadArray(__spreadArray([], requestSignature, true), [navigate], false));
var setSort = (0, react_1.useCallback)(function (sort) {
return changeParams({
type: queryReducer_1.SET_SORT,
payload: sort,
});
}, [changeParams]);
var setPage = (0, react_1.useCallback)(function (newPage) { return changeParams({ type: queryReducer_1.SET_PAGE, payload: newPage }); }, [changeParams]);
var setPerPage = (0, react_1.useCallback)(function (newPerPage) {
return changeParams({ type: queryReducer_1.SET_PER_PAGE, payload: newPerPage });
}, [changeParams]);
var filterValues = query.filter || emptyObject;
var displayedFilterValues = query.displayedFilters || emptyObject;
var debouncedSetFilters = (0, debounce_1.default)(function (filter, displayedFilters) {
changeParams({
type: queryReducer_1.SET_FILTER,
payload: {
filter: (0, removeEmpty_1.default)(filter),
displayedFilters: displayedFilters,
},
});
}, debounce);
var setFilters = (0, react_1.useCallback)(function (filter, displayedFilters, debounce) {
if (displayedFilters === void 0) { displayedFilters = undefined; }
if (debounce === void 0) { debounce = false; }
return debounce
? debouncedSetFilters(filter, displayedFilters)
: changeParams({
type: queryReducer_1.SET_FILTER,
payload: {
filter: (0, removeEmpty_1.default)(filter),
displayedFilters: displayedFilters,
},
});
}, [changeParams] // eslint-disable-line react-hooks/exhaustive-deps
);
var hideFilter = (0, react_1.useCallback)(function (filterName) {
changeParams({
type: queryReducer_1.HIDE_FILTER,
payload: filterName,
});
}, [changeParams]);
var showFilter = (0, react_1.useCallback)(function (filterName, defaultValue) {
changeParams({
type: queryReducer_1.SHOW_FILTER,
payload: {
filterName: filterName,
defaultValue: defaultValue,
},
});
}, [changeParams]);
return [
__assign(__assign({ filterValues: filterValues, requestSignature: requestSignature }, query), { displayedFilters: displayedFilterValues }),
{
changeParams: changeParams,
setPage: setPage,
setPerPage: setPerPage,
setSort: setSort,
setFilters: setFilters,
hideFilter: hideFilter,
showFilter: showFilter,
},
];
};
exports.useListParams = useListParams;
var parseObject = function (query, field) {
if (query[field] && typeof query[field] === 'string') {
try {
query[field] = JSON.parse(query[field]);
}
catch (err) {
delete query[field];
}
}
};
var parseQueryFromLocation = function (_a) {
var search = _a.search;
var query = (0, query_string_1.parse)(search);
parseObject(query, 'filter');
parseObject(query, 'displayedFilters');
return query;
};
exports.parseQueryFromLocation = parseQueryFromLocation;
/**
* Check if user has already set custom sort, page, or filters for this list
*
* User params come from the store as the params props. By default,
* this object is:
*
* { filter: {}, order: null, page: 1, perPage: null, sort: null }
*
* To check if the user has custom params, we must compare the params
* to these initial values.
*
* @param {Object} params
*/
var hasCustomParams = function (params) {
return (params &&
params.filter &&
(Object.keys(params.filter).length > 0 ||
params.order != null ||
params.page !== 1 ||
params.perPage != null ||
params.sort != null));
};
exports.hasCustomParams = hasCustomParams;
/**
* Merge list params from 3 different sources:
* - the query string
* - the params stored in the state (from previous navigation)
* - the props passed to the List component (including the filter defaultValues)
*/
var getQuery = function (_a) {
var queryFromLocation = _a.queryFromLocation, params = _a.params, filterDefaultValues = _a.filterDefaultValues, sort = _a.sort, perPage = _a.perPage;
var query = Object.keys(queryFromLocation).length > 0
? queryFromLocation
: (0, exports.hasCustomParams)(params)
? __assign({}, params) : { filter: filterDefaultValues || {} };
if (!query.sort) {
query.sort = sort.field;
query.order = sort.order;
}
if (query.perPage == null) {
query.perPage = perPage;
}
if (query.page == null) {
query.page = 1;
}
return __assign(__assign({}, query), { page: (0, exports.getNumberOrDefault)(query.page, 1), perPage: (0, exports.getNumberOrDefault)(query.perPage, 10) });
};
exports.getQuery = getQuery;
var getNumberOrDefault = function (possibleNumber, defaultValue) {
if (typeof possibleNumber === 'undefined') {
return defaultValue;
}
var parsedNumber = typeof possibleNumber === 'string'
? parseInt(possibleNumber, 10)
: possibleNumber;
return isNaN(parsedNumber) ? defaultValue : parsedNumber;
};
exports.getNumberOrDefault = getNumberOrDefault;
var emptyObject = {};
var defaultSort = {
field: 'id',
order: queryReducer_1.SORT_ASC,
};
var defaultParams = {};
//# sourceMappingURL=useListParams.js.map
;