cspace-ui
Version:
CollectionSpace user interface for browsers
645 lines (638 loc) • 22.4 kB
JavaScript
"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"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
const searchName = exports.searchName = 'searchToSelect';
const messages = (0, _reactIntl.defineMessages)({
editSearch: {
"id": "searchToSelectModal.editSearch",
"defaultMessage": "Revise search"
},
label: {
"id": "searchToSelectModal.label",
"defaultMessage": "Select records"
}
});
const listType = 'common';
// 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),
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,
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
};
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,
preferredPageSize,
customizeSearchDescriptor
} = this.props;
const {
pageNum,
sort
} = this.state;
const pageSize = preferredPageSize || defaultPageSize;
const searchQuery = {
p: pageNum,
size: pageSize
};
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, advancedSearchCondition);
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();
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,
getAuthorityVocabCsid,
buildRecordFieldOptionLists,
deleteOptionList,
onAdvancedSearchConditionCommit,
onKeywordCommit,
onRecordTypeCommit,
onVocabularyCommit
} = 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,
perms: perms,
preferredAdvancedSearchBooleanOp: preferredAdvancedSearchBooleanOp,
recordTypeInputReadOnly: recordTypeInputReadOnly,
recordTypeInputRootType: recordTypeInputRootType,
recordTypeInputRecordTypes: allowedRecordTypes,
recordTypeInputServiceTypes: allowedServiceTypes,
getAuthorityVocabCsid: getAuthorityVocabCsid,
buildRecordFieldOptionLists: buildRecordFieldOptionLists,
deleteOptionList: deleteOptionList,
onAdvancedSearchConditionCommit: onAdvancedSearchConditionCommit,
onKeywordCommit: onKeywordCommit,
onRecordTypeCommit: onRecordTypeCommit,
onVocabularyCommit: onVocabularyCommit,
onSearch: this.handleFormSearch
});
}
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 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,
searchError: searchError,
searchResult: searchResult,
renderEditLink: this.renderEditSearchLink,
onPageSizeChange: this.handlePageSizeChange
}), selectBar);
}
renderSearchResultTableFooter({
searchResult
}) {
const {
config
} = this.props;
if (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,
listType: listType,
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);