cspace-ui
Version:
CollectionSpace user interface for browsers
362 lines (356 loc) • 15.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SelectExportRelateToggleBar = SelectExportRelateToggleBar;
exports.default = void 0;
var _react = _interopRequireWildcard(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _reactRedux = require("react-redux");
var _reactRouterDom = require("react-router-dom");
var _immutable = _interopRequireDefault(require("immutable"));
var _qs = _interopRequireDefault(require("qs"));
var _get = _interopRequireDefault(require("lodash/get"));
var _reactIntl = require("react-intl");
var _classnames = _interopRequireDefault(require("classnames"));
var _searchNames = require("../../../constants/searchNames");
var _SearchResultTitleBar = _interopRequireDefault(require("../../search/SearchResultTitleBar"));
var _SearchResultFooter = _interopRequireDefault(require("../../search/SearchResultFooter"));
var _SearchTable = _interopRequireDefault(require("../../search/table/SearchTable"));
var _SearchResultGrid = _interopRequireDefault(require("../../search/grid/SearchResultGrid"));
var _SearchList = _interopRequireDefault(require("../../search/list/SearchList"));
var _SearchResultSidebar = _interopRequireDefault(require("../../search/SearchResultSidebar"));
var _SearchResultSummary = _interopRequireDefault(require("../../search/SearchResultSummary"));
var _SortBy = _interopRequireDefault(require("../../search/SortBy"));
var _ToggleButtons = require("../../search/header/ToggleButtons");
var _ConfigProvider = require("../../config/ConfigProvider");
var _SearchResults = _interopRequireDefault(require("../../../../styles/cspace-ui/SearchResults.css"));
var _ButtonBar = _interopRequireDefault(require("../../../../styles/cspace-ui/ButtonBar.css"));
var _prefs = require("../../../actions/prefs");
var _search = require("../../../actions/search");
var _reducers = require("../../../reducers");
var _SelectBar = _interopRequireDefault(require("../../search/SelectBar"));
var _RelateResults = _interopRequireDefault(require("../../search/RelateResults"));
var _ExportResults = _interopRequireDefault(require("../../search/ExportResults"));
var _searchHelpers = require("../../../helpers/searchHelpers");
var _searchPage = require("../../../actions/searchPage");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
const selectBarPropTypes = {
toggleBar: _propTypes.default.object,
searchResult: _propTypes.default.instanceOf(_immutable.default.Map),
config: _propTypes.default.object,
searchDescriptor: _propTypes.default.instanceOf(_immutable.default.Map)
};
function SelectExportRelateToggleBar({
toggleBar,
searchResult,
config,
searchDescriptor
}) {
if (!searchResult) {
return null;
}
const selectedItems = (0, _reactRedux.useSelector)(state => (0, _reducers.getSearchSelectedItems)(state, _searchNames.SEARCH_RESULT_PAGE_SEARCH_NAME));
const perms = (0, _reactRedux.useSelector)(state => (0, _reducers.getUserPerms)(state));
const dispatch = (0, _reactRedux.useDispatch)();
// button bar (relate/export)
const exportButton = /*#__PURE__*/_react.default.createElement(_ExportResults.default, {
config: config,
selectedItems: selectedItems,
searchDescriptor: searchDescriptor
});
const relateButton = /*#__PURE__*/_react.default.createElement(_RelateResults.default, {
config: config,
selectedItems: selectedItems,
searchDescriptor: searchDescriptor,
perms: perms,
disabled: false,
key: "relate"
});
const buttonBar = /*#__PURE__*/_react.default.createElement("div", {
className: _ButtonBar.default.common
}, relateButton, exportButton);
const listType = (0, _searchHelpers.getListTypeFromResult)(config, searchResult);
return /*#__PURE__*/_react.default.createElement(_SelectBar.default, {
config: config,
listType: listType,
searchDescriptor: searchDescriptor,
searchName: _searchNames.SEARCH_RESULT_PAGE_SEARCH_NAME,
searchResult: searchResult,
selectedItems: selectedItems,
setAllItemsSelected: (...args) => dispatch((0, _search.setAllResultItemsSelected)(...args))
}, buttonBar, toggleBar);
}
// memoize?
const getSearchDescriptor = (query, props) => {
const {
match
} = props;
const {
params
} = match;
const {
view,
...queryWithoutView
} = query;
const searchQuery = {
...queryWithoutView,
p: parseInt(query.p, 10) - 1,
size: parseInt(query.size, 10)
};
const advancedSearchCondition = query.as;
if (advancedSearchCondition) {
searchQuery.as = JSON.parse(advancedSearchCondition);
}
const searchDescriptor = {
searchQuery
};
['recordType', 'vocabulary', 'csid', 'subresource'].forEach(param => {
const value = params[param];
if (typeof value !== 'undefined') {
searchDescriptor[param] = value;
}
});
return _immutable.default.fromJS(searchDescriptor);
};
function setPreferredPageSize(props, dispatch) {
const {
location
} = props;
const {
search: searchFromLoc
} = location;
const query = _qs.default.parse(searchFromLoc.substring(1));
dispatch((0, _prefs.setSearchResultPagePageSize)(parseInt(query.size, 10)));
}
function normalizeQuery(props, config) {
const {
location,
preferredPageSize
} = props;
const {
search: searchFromLoc
} = location;
const query = _qs.default.parse(searchFromLoc.substring(1));
const {
normalizedQuery
} = (0, _searchHelpers.normalizeSearchQueryParams)(query, preferredPageSize, config.defaultSearchPageSize);
return normalizedQuery;
}
/**
* Gets the current view which we want to display. We prioritize
* query parameters first, then the last view a user was on (in redux),
* and finally fall back to the table view.
*/
const currentView = props => {
const {
history,
location
} = props;
const {
search: searchFromLoc
} = location;
const preferred = (0, _reactRedux.useSelector)(state => (0, _reducers.getSearchResultPageView)(state));
let current;
const query = _qs.default.parse(searchFromLoc.substring(1));
if (query) {
current = query.view;
const hasCurrent = current && (current === _searchNames.SEARCH_RESULT_GRID_VIEW || current === _searchNames.SEARCH_RESULT_LIST_VIEW || current === _searchNames.SEARCH_RESULT_TABLE_VIEW);
// update the query parameter to include our view
if (preferred && !hasCurrent) {
query.view = preferred;
history.push({
pathname: location.pathname,
search: `?${_qs.default.stringify(query)}`,
state: location.state
});
}
}
return current || preferred || _searchNames.SEARCH_RESULT_TABLE_VIEW;
};
const messages = (0, _reactIntl.defineMessages)({
table: {
"id": "search.result.view.table",
"defaultMessage": "Switch to table view"
},
detailList: {
"id": "search.result.view.detailList",
"defaultMessage": "Switch to detail list view"
},
grid: {
"id": "search.result.view.grid",
"defaultMessage": "Switch to grid view"
}
});
/**
* The page for displaying Search Results. Before rendering it first executes the search based on
* the query parameters provided by encapsulating them in a search descriptor and calling the search
* action in redux.
*
* Currently this is more for the new search views on CollectionObjects which includes a grid and
* detail based view compared to the older table based view. Ideally this be the only component for
* displaying search results but we first would need to make sure we only display the views which
* are supported for a given procedure or authority.
*
* @param {*} props
* @returns the SearchResults page component
*/
function SearchResults(props) {
const config = (0, _ConfigProvider.useConfig)();
const dispatch = (0, _reactRedux.useDispatch)();
const history = (0, _reactRouterDom.useHistory)();
const {
intl,
location
} = props;
const normalizedQuery = normalizeQuery(props, config);
const searchDescriptor = getSearchDescriptor(normalizedQuery, props);
const searchResults = (0, _reactRedux.useSelector)(state => (0, _reducers.getSearchResult)(state, _searchNames.SEARCH_RESULT_PAGE_SEARCH_NAME, searchDescriptor));
const isSidebarOpen = (0, _reactRedux.useSelector)(state => (0, _reducers.isSearchResultSidebarOpen)(state));
const display = currentView(props);
(0, _react.useEffect)(() => {
setPreferredPageSize(props, dispatch);
dispatch((0, _search.search)(config, _searchNames.SEARCH_RESULT_PAGE_SEARCH_NAME, searchDescriptor));
}, [searchDescriptor.toString()]);
const handlePageSizeChange = (0, _searchHelpers.createPageSizeChangeHandler)({
history,
location,
dispatch,
setPreferredPageSize: _prefs.setSearchResultPagePageSize
});
const handleEditSearchLinkClick = () => {
// Transfer the search descriptor from this search to the search page. If this search
// originated from the search page, the original descriptor will be in the location state.
// Otherwise, build it from the URL params. If present, the search descriptor from the
// originating search page will be more complete than one constructed from the URL; for
// example, it will contain fields that are blank, which will have been removed from the
// URL, to reduce the size.
const origin = (0, _get.default)(location.state, 'originSearchPage');
const conditionalSearchDescriptor = origin ? _immutable.default.fromJS(origin.searchDescriptor) : getSearchDescriptor(normalizedQuery, props);
const searchQuery = conditionalSearchDescriptor.get('searchQuery');
(0, _reactRedux.batch)(() => {
dispatch((0, _prefs.setSearchPageRecordType)(conditionalSearchDescriptor.get('recordType')));
dispatch((0, _prefs.setSearchPageVocabulary)(conditionalSearchDescriptor.get('vocabulary')));
dispatch((0, _searchPage.setSearchPageKeyword)(searchQuery.get('kw')));
dispatch((0, _searchPage.setSearchPageAdvanced)(searchQuery.get('as')));
dispatch((0, _searchPage.setSearchPageAdvancedLimitBy)((0, _searchHelpers.extractAdvancedSearchGroupedTerms)(searchQuery.get('as')).limitBy));
dispatch((0, _searchPage.setSearchPageAdvancedSearchTerms)((0, _searchHelpers.extractAdvancedSearchGroupedTerms)(searchQuery.get('as')).searchTerms));
});
};
const handleSortChange = (0, _searchHelpers.createSortByHandler)({
history,
location
});
const handleSortDirChange = (0, _searchHelpers.createSortDirHandler)({
history,
location
});
const renderSortBy = () => /*#__PURE__*/_react.default.createElement(_SortBy.default, {
onSortChange: handleSortChange,
onSortDirChange: handleSortDirChange,
sort: normalizedQuery === null || normalizedQuery === void 0 ? void 0 : normalizedQuery.sort,
recordType: searchDescriptor.get('recordType')
});
const gridLabel = intl.formatMessage(messages.grid);
const tableLabel = intl.formatMessage(messages.table);
const detailListLabel = intl.formatMessage(messages.detailList);
const toggles = [{
key: _searchNames.SEARCH_RESULT_TABLE_VIEW,
label: tableLabel,
icon: 'format_list_bulleted'
}, {
key: _searchNames.SEARCH_RESULT_GRID_VIEW,
label: gridLabel,
icon: 'grid_view'
}, {
key: _searchNames.SEARCH_RESULT_LIST_VIEW,
label: detailListLabel,
icon: 'vertical_split',
class: _SearchResults.default.detailList
}];
const updatePageView = key => {
if (history && location) {
const {
search: searchFromLoc
} = location;
const query = _qs.default.parse(searchFromLoc.substring(1));
query.view = key;
const queryString = _qs.default.stringify(query);
history.push({
pathname: location.pathname,
search: `?${queryString}`,
state: location.state
});
}
dispatch((0, _prefs.setSearchResultPageView)(key));
};
const displayToggles = /*#__PURE__*/_react.default.createElement(_ToggleButtons.ToggleButtonContainer, {
items: toggles,
renderButton: item => /*#__PURE__*/_react.default.createElement(_ToggleButtons.ToggleButton, {
icon: item.icon,
key: item.key,
name: item.key,
title: item.label,
className: (0, _classnames.default)(_SearchResults.default.toggle, item.class),
onClick: () => updatePageView(item.key)
})
});
let searchDisplay;
if (display === _searchNames.SEARCH_RESULT_GRID_VIEW) {
searchDisplay = /*#__PURE__*/_react.default.createElement(_SearchResultGrid.default, {
searchDescriptor: searchDescriptor
});
} else if (display === _searchNames.SEARCH_RESULT_LIST_VIEW) {
searchDisplay = /*#__PURE__*/_react.default.createElement(_SearchList.default, {
searchDescriptor: searchDescriptor
});
} else {
searchDisplay = /*#__PURE__*/_react.default.createElement(_SearchTable.default, {
searchDescriptor: searchDescriptor
});
}
const handleBatchInvokeComplete = () => {
dispatch((0, _search.search)(config, _searchNames.SEARCH_RESULT_PAGE_SEARCH_NAME, searchDescriptor));
};
const sidebar = /*#__PURE__*/_react.default.createElement(_SearchResultSidebar.default, {
config: config,
history: history,
isOpen: isSidebarOpen,
onInvokeComplete: handleBatchInvokeComplete,
recordType: searchDescriptor.get('recordType')
});
return /*#__PURE__*/_react.default.createElement("main", {
className: _SearchResults.default.common
}, /*#__PURE__*/_react.default.createElement(_SearchResultTitleBar.default, {
config: config,
searchDescriptor: searchDescriptor,
searchName: _searchNames.SEARCH_RESULT_PAGE_SEARCH_NAME,
updateDocumentTitle: true
}), /*#__PURE__*/_react.default.createElement("div", {
className: isSidebarOpen ? _SearchResults.default.body : _SearchResults.default.full
}, /*#__PURE__*/_react.default.createElement("div", {
className: _SearchResults.default.results
}, /*#__PURE__*/_react.default.createElement("header", null, /*#__PURE__*/_react.default.createElement(_SearchResultSummary.default, {
config: config,
searchName: _searchNames.SEARCH_RESULT_PAGE_SEARCH_NAME,
searchDescriptor: searchDescriptor,
onPageSizeChange: handlePageSizeChange,
onEditSearchLinkClick: handleEditSearchLinkClick,
renderSortBy: () => renderSortBy()
}), /*#__PURE__*/_react.default.createElement(SelectExportRelateToggleBar, {
toggleBar: displayToggles,
searchResult: searchResults,
config: config,
searchDescriptor: searchDescriptor
})), searchDisplay, /*#__PURE__*/_react.default.createElement(_SearchResultFooter.default, {
searchDescriptor: searchDescriptor
})), sidebar));
}
const searchResultsPropTypes = {
intl: _reactIntl.intlShape,
location: _propTypes.default.object.isRequired
};
SearchResults.propTypes = searchResultsPropTypes;
SelectExportRelateToggleBar.propTypes = selectBarPropTypes;
var _default = exports.default = (0, _reactIntl.injectIntl)(SearchResults);