UNPKG

cspace-ui

Version:
401 lines (337 loc) 10.2 kB
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { defineMessages, FormattedMessage } from 'react-intl'; import Immutable from 'immutable'; import get from 'lodash/get'; import { components as inputComponents } from 'cspace-input'; import { Modal } from 'cspace-layout'; import InvokeButton from './InvokeButton'; import InvocationEditorContainer from '../../containers/invocable/InvocationEditorContainer'; import { normalizeInvocationDescriptor } from '../../helpers/invocationHelpers'; import CancelButton from '../navigation/CancelButton'; import styles from '../../../styles/cspace-ui/InvocationModal.css'; import formatPickerStyles from '../../../styles/cspace-ui/InvocationFormatPicker.css'; import { OptionPickerInput } from '../../helpers/configContextInputs'; const { Label } = inputComponents; const messages = defineMessages({ cancel: { id: 'invocationModal.cancel', description: 'Label of the cancel button in the invocation modal.', defaultMessage: 'Cancel', }, invoke: { id: 'invocationModal.run', description: 'Label of the invoke button in the invocation modal.', defaultMessage: 'Run', }, running: { id: 'invocationModal.running', description: 'Message displayed in the invocation modal when the report/batch job is running.', defaultMessage: 'Running…', }, format: { id: 'invocationModal.format', description: 'Label of the output format picker in the invocation modal.', defaultMessage: 'Format:', }, }); const propTypes = { allowedModes: PropTypes.func, config: PropTypes.shape({ recordTypes: PropTypes.object, }).isRequired, csid: PropTypes.string, data: PropTypes.instanceOf(Immutable.Map), initialInvocationDescriptor: PropTypes.instanceOf(Immutable.Map), modeReadOnly: PropTypes.bool, invocationTargetReadOnly: PropTypes.bool, isOpen: PropTypes.bool, isRecordModified: PropTypes.bool, isRunning: PropTypes.bool, recordType: PropTypes.oneOf(['report', 'batch']), readRecord: PropTypes.func, searchCsid: PropTypes.func, onCancelButtonClick: PropTypes.func, onCloseButtonClick: PropTypes.func, onInvokeButtonClick: PropTypes.func, }; export default class InvocationModal extends Component { constructor(props) { super(props); this.handleFormatPickerCommit = this.handleFormatPickerCommit.bind(this); this.handleInvocationDescriptorCommit = this.handleInvocationDescriptorCommit.bind(this); this.handleInvokeButtonClick = this.handleInvokeButtonClick.bind(this); this.renderButtonBar = this.renderButtonBar.bind(this); const { data, initialInvocationDescriptor, } = this.props; this.state = { invocationDescriptor: normalizeInvocationDescriptor(initialInvocationDescriptor, data), }; } // eslint-disable-next-line camelcase UNSAFE_componentWillReceiveProps(nextProps) { const { data, isOpen, } = this.props; const { data: nextData, isOpen: nextIsOpen, } = nextProps; if (!isOpen && nextIsOpen) { const { initialInvocationDescriptor, } = nextProps; this.setState({ invocationDescriptor: normalizeInvocationDescriptor(initialInvocationDescriptor, nextData), }); } else if (!data && nextData) { const { invocationDescriptor } = this.state; this.setState({ invocationDescriptor: normalizeInvocationDescriptor(invocationDescriptor, nextData), }); } } componentDidUpdate(prevProps) { const { csid, isOpen, readRecord, } = this.props; const { isOpen: prevIsOpen, } = prevProps; if (csid && !prevIsOpen && isOpen) { if (readRecord) { readRecord(); } this.readInvocationItem(); } } handleFormatPickerCommit(path, value) { const { invocationDescriptor, } = this.state; this.setState({ invocationDescriptor: invocationDescriptor.set('outputMIME', value), }); } handleInvocationDescriptorCommit(invocationDescriptor) { this.setState({ invocationDescriptor, }); } handleInvokeButtonClick() { const { data, onInvokeButtonClick, } = this.props; const { invocationDescriptor, } = this.state; const mode = invocationDescriptor.get('mode'); // Translate the items map to csids. const items = invocationDescriptor.get('items') || Immutable.Map(); let csid = items.keySeq().toJS(); if (mode === 'single' || mode === 'group') { [csid] = csid; } if (onInvokeButtonClick) { onInvokeButtonClick(data, invocationDescriptor.set('csid', csid)); } } readInvocationItem() { const { config, searchCsid, } = this.props; const { invocationDescriptor, } = this.state; if (invocationDescriptor) { const invocationCsid = invocationDescriptor.get('csid'); if ( invocationCsid && typeof invocationCsid === 'string' && !invocationDescriptor.get('items') ) { searchCsid(config, invocationDescriptor.get('recordType'), invocationCsid) .then((response) => { let item = get(response, ['data', 'ns2:abstract-common-list', 'list-item']); if (item) { item = Immutable.fromJS(item); } else { item = Immutable.Map({ csid: invocationCsid, }); } this.setState((prevState) => ({ invocationDescriptor: prevState.invocationDescriptor.set( 'items', Immutable.Map({ [invocationCsid]: item }), ), })); }) .catch(() => { const item = Immutable.Map({ csid: invocationCsid, }); this.setState((prevState) => ({ invocationDescriptor: prevState.invocationDescriptor.set( 'items', Immutable.Map({ [invocationCsid]: item }), ), })); }); } } } renderFormatPicker() { const { recordType, data, } = this.props; const { invocationDescriptor, } = this.state; if (recordType === 'report') { let mimeList = []; if (data) { mimeList = data.getIn(['document', 'ns2:reports_common', 'supportsOutputMIMEList', 'outputMIME']); } const prefilter = (option) => mimeList.includes(option.value); return ( <div className={formatPickerStyles.common}> <OptionPickerInput blankable={false} label={<Label><FormattedMessage {...messages.format} /></Label>} source="reportMimeTypes" prefilter={mimeList ? prefilter : null} value={invocationDescriptor.get('outputMIME')} onCommit={this.handleFormatPickerCommit} // blankable /> </div> ); } return null; } renderButtonBar() { const { isRunning, onCancelButtonClick, recordType, } = this.props; const { invocationDescriptor, } = this.state; const mode = invocationDescriptor.get('mode'); const items = invocationDescriptor.get('items'); return ( <div> {this.renderFormatPicker()} <CancelButton disabled={isRunning} label={<FormattedMessage {...messages.cancel} />} onClick={onCancelButtonClick} /> <InvokeButton disabled={ isRunning || (mode !== 'nocontext' && (!items || items.isEmpty())) } label={<FormattedMessage {...messages.invoke} />} recordType={recordType} onClick={this.handleInvokeButtonClick} /> </div> ); } renderTitle() { const { config, data, recordType, } = this.props; if (!data) { return ' '; } const recordTypeConfig = get(config, ['recordTypes', recordType]); const titleGetter = get(recordTypeConfig, 'title'); let title = (titleGetter && titleGetter(data)); if (!title) { const recordTypeMessages = get(recordTypeConfig, ['messages', 'record']); title = <FormattedMessage {...recordTypeMessages.name} />; } return ( <h1>{title}</h1> ); } renderInvocationEditor() { const { allowedModes, config, data, modeReadOnly, invocationTargetReadOnly, isRecordModified, recordType, } = this.props; const { invocationDescriptor, } = this.state; const recordTypeConfig = get(config, ['recordTypes', recordType]); const invocableNameGetter = get(recordTypeConfig, 'invocableName'); const invocableName = invocableNameGetter && invocableNameGetter(data); return ( <InvocationEditorContainer allowedModes={allowedModes} config={config} metadata={data} invocationDescriptor={invocationDescriptor} modeReadOnly={modeReadOnly} invocationTargetReadOnly={invocationTargetReadOnly} invocableName={invocableName} isInvocationTargetModified={isRecordModified} recordType={recordType} onInvocationDescriptorCommit={this.handleInvocationDescriptorCommit} /> ); } render() { const { csid, isOpen, isRunning, onCloseButtonClick, } = this.props; if (!isOpen || !csid) { return null; } let content; if (isRunning) { content = ( <p> <FormattedMessage {...messages.running} /> </p> ); } else { content = this.renderInvocationEditor(); } return ( <Modal className={isRunning ? styles.running : styles.common} isOpen={isOpen} title={this.renderTitle()} closeButtonClassName="material-icons" closeButtonDisabled={isRunning} closeButtonLabel="close" renderButtonBar={this.renderButtonBar} onCloseButtonClick={onCloseButtonClick} > {content} </Modal> ); } } InvocationModal.propTypes = propTypes;