UNPKG

cspace-ui

Version:
669 lines (661 loc) 23.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.searchName = exports.default = exports.BaseSearchToSelectModal = void 0; var _react = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _reactIntl = require("react-intl"); var _immutable = _interopRequireDefault(require("immutable")); var _get = _interopRequireDefault(require("lodash/get")); var _isEqual = _interopRequireDefault(require("lodash/isEqual")); var _cspaceLayout = require("cspace-layout"); var _CheckboxInput = _interopRequireDefault(require("cspace-input/lib/components/CheckboxInput")); var _SearchForm = _interopRequireDefault(require("./SearchForm")); var _Pager = _interopRequireDefault(require("./Pager")); var _AcceptSelectionButton = _interopRequireDefault(require("./AcceptSelectionButton")); var _BackButton = _interopRequireDefault(require("../navigation/BackButton")); var _CancelButton = _interopRequireDefault(require("../navigation/CancelButton")); var _SearchButton = _interopRequireDefault(require("./SearchButton")); var _SearchClearButton = _interopRequireDefault(require("./SearchClearButton")); var _SearchResultSummary = _interopRequireDefault(require("./SearchResultSummary")); var _SearchToSelectTitleBar = _interopRequireDefault(require("./SearchToSelectTitleBar")); var _SelectBar = _interopRequireDefault(require("./SelectBar")); var _SearchResultTableContainer = _interopRequireDefault(require("../../containers/search/SearchResultTableContainer")); var _searchHelpers = require("../../helpers/searchHelpers"); var _SearchToSelectModal = _interopRequireDefault(require("../../../styles/cspace-ui/SearchToSelectModal.css")); var _searchOperators = require("../../constants/searchOperators"); 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 searchName = exports.searchName = 'searchToSelect'; const messages = (0, _reactIntl.defineMessages)({ editSearch: { "id": "searchToSelectModal.editSearch", "defaultMessage": "Revise search" }, label: { "id": "searchToSelectModal.label", "defaultMessage": "Select records" } }); // FIXME: Make default page size configurable const defaultPageSize = 20; const stopPropagation = event => { event.stopPropagation(); }; const propTypes = { acceptButtonClassName: _propTypes.default.string, acceptButtonLabel: _propTypes.default.node, allowedRecordTypes: _propTypes.default.arrayOf(_propTypes.default.string), allowedServiceTypes: _propTypes.default.arrayOf(_propTypes.default.string), config: _propTypes.default.shape({ listTypes: _propTypes.default.object, recordTypes: _propTypes.default.object }), intl: _reactIntl.intlShape, isOpen: _propTypes.default.bool, keywordValue: _propTypes.default.string, defaultRecordTypeValue: _propTypes.default.string, defaultVocabularyValue: _propTypes.default.string, recordTypeValue: _propTypes.default.string, vocabularyValue: _propTypes.default.string, advancedSearchCondition: _propTypes.default.instanceOf(_immutable.default.Map), advancedSearchConditionLimitBy: _propTypes.default.instanceOf(_immutable.default.Map), advancedSearchConditionSearchTerms: _propTypes.default.instanceOf(_immutable.default.Map), preferredAdvancedSearchBooleanOp: _propTypes.default.string, preferredPageSize: _propTypes.default.number, perms: _propTypes.default.instanceOf(_immutable.default.Map), selectedItems: _propTypes.default.instanceOf(_immutable.default.Map), singleSelect: _propTypes.default.bool, titleMessage: _propTypes.default.objectOf(_propTypes.default.string), getAuthorityVocabCsid: _propTypes.default.func, buildRecordFieldOptionLists: _propTypes.default.func, deleteOptionList: _propTypes.default.func, onAdvancedSearchConditionCommit: _propTypes.default.func, onAdvancedSearchConditionLimitByCommit: _propTypes.default.func, onAdvancedSearchConditionSearchTermsCommit: _propTypes.default.func, onKeywordCommit: _propTypes.default.func, onRecordTypeCommit: _propTypes.default.func, onVocabularyCommit: _propTypes.default.func, onAccept: _propTypes.default.func, onCloseButtonClick: _propTypes.default.func, onCancelButtonClick: _propTypes.default.func, onClearButtonClick: _propTypes.default.func, onItemSelectChange: _propTypes.default.func, customizeSearchDescriptor: _propTypes.default.func, clearSearchResults: _propTypes.default.func, parentSelector: _propTypes.default.func, renderAcceptPending: _propTypes.default.func, search: _propTypes.default.func, setAllItemsSelected: _propTypes.default.func, setPreferredPageSize: _propTypes.default.func, shouldShowCheckbox: _propTypes.default.func, useNewSearch: _propTypes.default.bool }; const defaultProps = { defaultVocabularyValue: 'all', selectedItems: _immutable.default.Map(), renderAcceptPending: () => /*#__PURE__*/_react.default.createElement("p", null), shouldShowCheckbox: () => true }; class BaseSearchToSelectModal extends _react.Component { constructor() { super(); this.handleAcceptButtonClick = this.handleAcceptButtonClick.bind(this); this.handleCancelButtonClick = this.handleCancelButtonClick.bind(this); this.handleCheckboxCommit = this.handleCheckboxCommit.bind(this); this.handleCloseButtonClick = this.handleCloseButtonClick.bind(this); this.handleEditSearchLinkClick = this.handleEditSearchLinkClick.bind(this); this.handleFormSearch = this.handleFormSearch.bind(this); this.handleItemClick = this.handleItemClick.bind(this); this.handlePageChange = this.handlePageChange.bind(this); this.handlePageSizeChange = this.handlePageSizeChange.bind(this); this.handleSortChange = this.handleSortChange.bind(this); this.renderCheckbox = this.renderCheckbox.bind(this); this.renderEditSearchLink = this.renderEditSearchLink.bind(this); this.renderModalButtonBar = this.renderModalButtonBar.bind(this); this.renderSearchResultTableHeader = this.renderSearchResultTableHeader.bind(this); this.renderSearchResultTableFooter = this.renderSearchResultTableFooter.bind(this); this.state = { isSearchInitiated: false, pageNum: 0, sort: null }; } // eslint-disable-next-line camelcase UNSAFE_componentWillReceiveProps(nextProps) { const { isOpen } = this.props; const { isOpen: nextIsOpen } = nextProps; if (isOpen && !nextIsOpen) { // Closing. this.setState({ isAcceptHandlerPending: false, isSearchInitiated: false, pageNum: 0, sort: null }); } } componentDidUpdate(prevProps, prevState) { const { isOpen } = this.props; const { isOpen: prevIsOpen } = prevProps; if (prevIsOpen && !isOpen) { // Closed. const { clearSearchResults, onRecordTypeCommit } = this.props; if (clearSearchResults) { clearSearchResults(searchName); } if (onRecordTypeCommit) { onRecordTypeCommit(''); } } else if (!prevIsOpen && isOpen) { // Opened. const { config, defaultRecordTypeValue, defaultVocabularyValue, onRecordTypeCommit, onVocabularyCommit } = this.props; if (onRecordTypeCommit) { onRecordTypeCommit(defaultRecordTypeValue); if (onVocabularyCommit) { const serviceType = (0, _get.default)(config, ['recordTypes', defaultRecordTypeValue, 'serviceConfig', 'serviceType']); if (serviceType === 'authority') { onVocabularyCommit(defaultVocabularyValue); } } } } const { isSearchInitiated, pageNum, sort } = this.state; const { config, defaultVocabularyValue, recordTypeValue, vocabularyValue, advancedSearchCondition, preferredPageSize, onVocabularyCommit } = this.props; const { recordTypeValue: prevRecordTypeValue, vocabularyValue: prevVocabularyValue, advancedSearchCondition: prevAdvancedSearchCondition, preferredPageSize: prevPreferredPageSize } = prevProps; if (isSearchInitiated) { const { pageNum: prevPageNum, sort: prevSort } = prevState; if (recordTypeValue !== prevRecordTypeValue || vocabularyValue !== prevVocabularyValue || !(0, _isEqual.default)(advancedSearchCondition, prevAdvancedSearchCondition) || preferredPageSize !== prevPreferredPageSize || pageNum !== prevPageNum || sort !== prevSort) { this.search(); } } else if (recordTypeValue !== prevRecordTypeValue) { const serviceType = (0, _get.default)(config, ['recordTypes', recordTypeValue, 'serviceConfig', 'serviceType']); if (serviceType === 'authority') { onVocabularyCommit(defaultVocabularyValue); } } } handleAcceptButtonClick() { const { isSearchInitiated } = this.state; if (isSearchInitiated) { const { onAccept, selectedItems } = this.props; if (onAccept) { this.setState({ isAcceptHandlerPending: true, isSearchInitiated: false }); Promise.resolve(onAccept(selectedItems, this.getSearchDescriptor())); } } else { this.search(); } } handleCancelButtonClick(event) { const { onCancelButtonClick } = this.props; if (onCancelButtonClick) { onCancelButtonClick(event); } } handleCloseButtonClick(event) { const { onCloseButtonClick } = this.props; if (onCloseButtonClick) { onCloseButtonClick(event); } } handleEditSearchLinkClick() { const { clearSearchResults } = this.props; if (clearSearchResults) { clearSearchResults(searchName); } this.setState({ isSearchInitiated: false }); } handleFormSearch() { this.search(); } handleCheckboxCommit(path, value) { const index = parseInt(path[0], 10); this.setItemSelected(index, value); } handleItemClick(item, index) { const { selectedItems, shouldShowCheckbox } = this.props; if (shouldShowCheckbox(item)) { const itemCsid = item.get('csid'); const selected = selectedItems ? selectedItems.has(itemCsid) : false; this.setItemSelected(index, !selected); } } handlePageChange(pageNum) { this.setState({ pageNum }); } handlePageSizeChange(pageSize) { const { setPreferredPageSize } = this.props; let normalizedPageSize; if (Number.isNaN(pageSize) || pageSize < 1) { normalizedPageSize = 0; } else if (pageSize > 2500) { normalizedPageSize = 2500; } else { normalizedPageSize = pageSize; } if (setPreferredPageSize) { this.setState({ pageNum: 0 }); setPreferredPageSize(normalizedPageSize); } } handleSortChange(sort) { this.setState({ sort }); } getSearchDescriptor() { const { config, recordTypeValue: recordType, vocabularyValue: vocabulary, keywordValue: keyword, advancedSearchCondition, advancedSearchConditionLimitBy, advancedSearchConditionSearchTerms, preferredPageSize, customizeSearchDescriptor, useNewSearch } = this.props; const { pageNum, sort } = this.state; const pageSize = preferredPageSize || defaultPageSize; const searchQuery = { p: pageNum, size: pageSize }; const searchCondition = useNewSearch || typeof useNewSearch === 'undefined' ? _immutable.default.Map({ op: _searchOperators.OP_AND, value: _immutable.default.List.of(advancedSearchConditionSearchTerms, advancedSearchConditionLimitBy) }) : advancedSearchCondition; if (sort) { searchQuery.sort = sort; } const kw = keyword ? keyword.trim() : ''; if (kw) { searchQuery.kw = kw; } const fields = (0, _get.default)(config, ['recordTypes', recordType, 'fields']); const condition = (0, _searchHelpers.normalizeCondition)(fields, searchCondition); if (condition) { searchQuery.as = condition; } const searchDescriptor = _immutable.default.fromJS({ recordType, vocabulary, searchQuery }); if (customizeSearchDescriptor) { return customizeSearchDescriptor(searchDescriptor); } return searchDescriptor; } setItemSelected(index, selected) { const { config, singleSelect, setAllItemsSelected, onItemSelectChange } = this.props; if (onItemSelectChange) { const searchDescriptor = this.getSearchDescriptor(); const { listType } = (0, _searchHelpers.deriveSearchType)(config, searchName, searchDescriptor); if (singleSelect && selected) { setAllItemsSelected(config, searchName, searchDescriptor, listType, false); } onItemSelectChange(config, searchName, searchDescriptor, listType, index, selected); } } search() { const { config, search } = this.props; if (search) { const searchDescriptor = this.getSearchDescriptor(); search(config, searchName, searchDescriptor); this.setState({ isSearchInitiated: true }); } } renderCheckbox({ rowData, rowIndex }) { const { shouldShowCheckbox } = this.props; if (shouldShowCheckbox(rowData)) { const { selectedItems } = this.props; const itemCsid = rowData.get('csid'); const selected = selectedItems ? selectedItems.has(itemCsid) : false; return /*#__PURE__*/_react.default.createElement(_CheckboxInput.default, { embedded: true, name: `${rowIndex}`, value: selected, onCommit: this.handleCheckboxCommit // Prevent click on the checkbox from propagating to the row, which would cause // double-toggling of the selected state. , onClick: stopPropagation }); } return null; } renderSearchForm() { const { allowedRecordTypes, allowedServiceTypes, config, intl, keywordValue, recordTypeValue, vocabularyValue, perms, preferredAdvancedSearchBooleanOp, advancedSearchCondition, advancedSearchConditionLimitBy, advancedSearchConditionSearchTerms, getAuthorityVocabCsid, buildRecordFieldOptionLists, deleteOptionList, onAdvancedSearchConditionCommit, onAdvancedSearchConditionLimitByCommit, onAdvancedSearchConditionSearchTermsCommit, onKeywordCommit, onRecordTypeCommit, onVocabularyCommit, useNewSearch } = this.props; let recordTypeInputReadOnly = true; let recordTypeInputRootType; if (allowedServiceTypes) { // Allow the record type to be changed. recordTypeInputReadOnly = false; // Don't show the All Records option. recordTypeInputRootType = ''; } else if (allowedRecordTypes) { recordTypeInputReadOnly = allowedRecordTypes.length < 2; } return /*#__PURE__*/_react.default.createElement(_SearchForm.default, { config: config, intl: intl, recordTypeValue: recordTypeValue, vocabularyValue: vocabularyValue, keywordValue: keywordValue, advancedSearchCondition: advancedSearchCondition, advancedSearchConditionLimitBy: advancedSearchConditionLimitBy, advancedSearchConditionSearchTerms: advancedSearchConditionSearchTerms, perms: perms, preferredAdvancedSearchBooleanOp: preferredAdvancedSearchBooleanOp, recordTypeInputReadOnly: recordTypeInputReadOnly, recordTypeInputRootType: recordTypeInputRootType, recordTypeInputRecordTypes: allowedRecordTypes, recordTypeInputServiceTypes: allowedServiceTypes, getAuthorityVocabCsid: getAuthorityVocabCsid, buildRecordFieldOptionLists: buildRecordFieldOptionLists, deleteOptionList: deleteOptionList, onAdvancedSearchConditionCommit: onAdvancedSearchConditionCommit, onAdvancedSearchConditionLimitByCommit: onAdvancedSearchConditionLimitByCommit, onAdvancedSearchConditionSearchTermsCommit: onAdvancedSearchConditionSearchTermsCommit, onKeywordCommit: onKeywordCommit, onRecordTypeCommit: onRecordTypeCommit, onVocabularyCommit: onVocabularyCommit, onSearch: this.handleFormSearch, showNewSearch: useNewSearch || typeof useNewSearch === 'undefined' }); } renderEditSearchLink() { return /*#__PURE__*/_react.default.createElement("button", { type: "button", onClick: this.handleEditSearchLinkClick }, /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, messages.editSearch)); } renderSearchResultTableHeader({ searchError, searchResult }) { const { config, selectedItems, setAllItemsSelected, shouldShowCheckbox, singleSelect } = this.props; if (searchError) { return null; } const listType = (0, _searchHelpers.getListTypeFromResult)(config, searchResult); const searchDescriptor = this.getSearchDescriptor(); let selectBar; if (!singleSelect) { // If only a single selection is allowed, there's no need to show a count of selected records // or a select all checkbox. selectBar = /*#__PURE__*/_react.default.createElement(_SelectBar.default, { config: config, listType: listType, searchDescriptor: searchDescriptor, searchName: searchName, searchResult: searchResult, selectedItems: selectedItems, setAllItemsSelected: setAllItemsSelected, showCheckboxFilter: shouldShowCheckbox }); } return /*#__PURE__*/_react.default.createElement("header", null, /*#__PURE__*/_react.default.createElement(_SearchResultSummary.default, { config: config, listType: listType, searchDescriptor: searchDescriptor, renderEditLink: this.renderEditSearchLink, onPageSizeChange: this.handlePageSizeChange }), selectBar); } renderSearchResultTableFooter({ searchResult }) { const { config } = this.props; if (searchResult) { const listType = (0, _searchHelpers.getListTypeFromResult)(config, searchResult); const listTypeConfig = config.listTypes[listType]; const list = searchResult.get(listTypeConfig.listNodeName); const totalItems = parseInt(list.get('totalItems'), 10); const pageSize = parseInt(list.get('pageSize'), 10); const pageNum = parseInt(list.get('pageNum'), 10); const lastPage = Math.max(0, Number.isNaN(totalItems) ? 0 : Math.ceil(totalItems / pageSize) - 1); return /*#__PURE__*/_react.default.createElement("footer", null, /*#__PURE__*/_react.default.createElement(_Pager.default, { currentPage: pageNum, lastPage: lastPage, pageSize: pageSize, onPageChange: this.handlePageChange, onPageSizeChange: this.handlePageSizeChange })); } return null; } renderSearchResultTable() { const { config, recordTypeValue } = this.props; const searchDescriptor = this.getSearchDescriptor(); return /*#__PURE__*/_react.default.createElement(_SearchResultTableContainer.default, { config: config, linkItems: false, recordType: recordTypeValue, searchName: searchName, searchDescriptor: searchDescriptor, showCheckboxColumn: true, renderCheckbox: this.renderCheckbox, renderHeader: this.renderSearchResultTableHeader, renderFooter: this.renderSearchResultTableFooter, onItemClick: this.handleItemClick, onSortChange: this.handleSortChange }); } renderModalButtonBar() { const { acceptButtonClassName, acceptButtonLabel, selectedItems, onClearButtonClick } = this.props; const { isAcceptHandlerPending, isSearchInitiated } = this.state; const cancelButton = /*#__PURE__*/_react.default.createElement(_CancelButton.default, { disabled: isAcceptHandlerPending, onClick: this.handleCancelButtonClick }); let acceptButton; let backButton; let clearButton; if (isSearchInitiated) { acceptButton = /*#__PURE__*/_react.default.createElement(_AcceptSelectionButton.default, { className: acceptButtonClassName, disabled: isAcceptHandlerPending || !selectedItems || selectedItems.size < 1, label: acceptButtonLabel, onClick: this.handleAcceptButtonClick }); backButton = /*#__PURE__*/_react.default.createElement(_BackButton.default, { disabled: isAcceptHandlerPending, label: /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, messages.editSearch), onClick: this.handleEditSearchLinkClick }); } else { acceptButton = /*#__PURE__*/_react.default.createElement(_SearchButton.default, { disabled: isAcceptHandlerPending, type: "button", onClick: this.handleAcceptButtonClick }); clearButton = /*#__PURE__*/_react.default.createElement(_SearchClearButton.default, { onClick: onClearButtonClick }); } return /*#__PURE__*/_react.default.createElement("div", null, clearButton, backButton, cancelButton, acceptButton); } render() { const { config, intl, isOpen, recordTypeValue, parentSelector, singleSelect, titleMessage, renderAcceptPending } = this.props; const { isAcceptHandlerPending, isSearchInitiated } = this.state; let content; let title; if (isOpen) { if (isAcceptHandlerPending) { content = renderAcceptPending(); } else if (isSearchInitiated) { content = this.renderSearchResultTable(); } else { content = this.renderSearchForm(); } const searchDescriptor = this.getSearchDescriptor(); title = /*#__PURE__*/_react.default.createElement(_SearchToSelectTitleBar.default, { config: config, isSearchInitiated: isSearchInitiated, recordType: recordTypeValue, searchDescriptor: searchDescriptor, singleSelect: singleSelect, titleMessage: titleMessage }); } return /*#__PURE__*/_react.default.createElement(_cspaceLayout.Modal, { className: _SearchToSelectModal.default.common, contentLabel: intl.formatMessage(messages.label), title: title, isOpen: isOpen, showCloseButton: !isAcceptHandlerPending, closeButtonClassName: "material-icons", closeButtonLabel: "close", parentSelector: parentSelector, renderButtonBar: this.renderModalButtonBar, onCloseButtonClick: this.handleCloseButtonClick }, content); } } exports.BaseSearchToSelectModal = BaseSearchToSelectModal; BaseSearchToSelectModal.propTypes = propTypes; BaseSearchToSelectModal.defaultProps = defaultProps; var _default = exports.default = (0, _reactIntl.injectIntl)(BaseSearchToSelectModal);