UNPKG

cspace-ui

Version:
593 lines (580 loc) 21 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _reactRouter = require("react-router"); var _immutable = _interopRequireDefault(require("immutable")); var _get = _interopRequireDefault(require("lodash/get")); var _Dock = _interopRequireDefault(require("../sections/Dock")); var _RecordButtonBar = _interopRequireDefault(require("./RecordButtonBar")); var _RecordHeader = _interopRequireDefault(require("./RecordHeader")); var _ConfirmRecordNavigationModal = _interopRequireDefault(require("./ConfirmRecordNavigationModal")); var _ConfirmRecordDeleteModal = _interopRequireDefault(require("./ConfirmRecordDeleteModal")); var _LockRecordModal = _interopRequireDefault(require("./LockRecordModal")); var _HierarchyReparentNotifier = _interopRequireDefault(require("./HierarchyReparentNotifier")); var _RecordFormContainer = _interopRequireDefault(require("../../containers/record/RecordFormContainer")); var _permissionHelpers = require("../../helpers/permissionHelpers"); var _recordDataHelpers = require("../../helpers/recordDataHelpers"); var _workflowStateHelpers = require("../../helpers/workflowStateHelpers"); var _RecordEditor = _interopRequireDefault(require("../../../styles/cspace-ui/RecordEditor.css")); var _modalNames = require("../../constants/modalNames"); 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 propTypes = { config: _propTypes.default.shape({ recordTypes: _propTypes.default.object, termDeprecationEnabled: _propTypes.default.bool }), recordType: _propTypes.default.string.isRequired, vocabulary: _propTypes.default.string, csid: _propTypes.default.string, cloneCsid: _propTypes.default.string, data: _propTypes.default.instanceOf(_immutable.default.Map), dockTop: _propTypes.default.number, formName: _propTypes.default.string, perms: _propTypes.default.instanceOf(_immutable.default.Map), roleNames: _propTypes.default.instanceOf(_immutable.default.List), subrecordData: _propTypes.default.instanceOf(_immutable.default.Map), validationErrors: _propTypes.default.instanceOf(_immutable.default.Map), vocabularyWorkflowState: _propTypes.default.string, isModified: _propTypes.default.bool, isReadPending: _propTypes.default.bool, isSavePending: _propTypes.default.bool, isSidebarOpen: _propTypes.default.bool, isHardDelete: _propTypes.default.bool, // The workflow state of the related subject (aka primary) record when we're in a secondary tab. relatedSubjectWorkflowState: _propTypes.default.string, openModalName: _propTypes.default.string, checkDeletable: _propTypes.default.func, checkForRelations: _propTypes.default.func, checkForUses: _propTypes.default.func, checkForRoleUses: _propTypes.default.func, createNewRecord: _propTypes.default.func, readRecord: _propTypes.default.func, onRecordCreated: _propTypes.default.func, onRecordSaved: _propTypes.default.func, onSaveCancelled: _propTypes.default.func, closeModal: _propTypes.default.func, openModal: _propTypes.default.func, deleteRecord: _propTypes.default.func, save: _propTypes.default.func, saveWithTransition: _propTypes.default.func, revert: _propTypes.default.func, clone: _propTypes.default.func, transitionRecord: _propTypes.default.func, removeNotification: _propTypes.default.func, removeValidationNotification: _propTypes.default.func, setForm: _propTypes.default.func, validateRecordData: _propTypes.default.func, onRecordReadComplete: _propTypes.default.func, onRecordDeleted: _propTypes.default.func, onRecordTransitioned: _propTypes.default.func, onRunButtonClick: _propTypes.default.func }; const defaultProps = { data: _immutable.default.Map(), isSidebarOpen: true }; class RecordEditor extends _react.Component { constructor() { super(); // Confirm delete modal button handlers. this.handleConfirmDeleteButtonClick = this.handleConfirmDeleteButtonClick.bind(this); // Confirm navigation modal button handlers. this.handleConfirmNavigationSaveButtonClick = this.handleConfirmNavigationSaveButtonClick.bind(this); this.handleConfirmNavigationRevertButtonClick = this.handleConfirmNavigationRevertButtonClick.bind(this); // Lock modal button handlers. this.handleSaveOnlyButtonClick = this.handleSaveOnlyButtonClick.bind(this); this.handleSaveLockButtonClick = this.handleSaveLockButtonClick.bind(this); // Shared modal handlers. this.handleModalCancelButtonClick = this.handleModalCancelButtonClick.bind(this); // Button bar handlers. this.handleDeprecateButtonClick = this.handleDeprecateButtonClick.bind(this); this.handleSaveButtonClick = this.handleSaveButtonClick.bind(this); this.handleSaveButtonErrorBadgeClick = this.handleSaveButtonErrorBadgeClick.bind(this); this.handleRevertButtonClick = this.handleRevertButtonClick.bind(this); this.handleCloneButtonClick = this.handleCloneButtonClick.bind(this); this.handleDeleteButtonClick = this.handleDeleteButtonClick.bind(this); this.handleRecordFormSelectorCommit = this.handleRecordFormSelectorCommit.bind(this); this.handleUndeprecateButtonClick = this.handleUndeprecateButtonClick.bind(this); } componentDidMount() { this.initRecord(); } componentDidUpdate(prevProps) { const { recordType, vocabulary, csid, cloneCsid, data } = this.props; const { recordType: prevRecordType, vocabulary: prevVocabulary, csid: prevCsid, cloneCsid: prevCloneCsid, data: prevData } = prevProps; if (recordType !== prevRecordType || vocabulary !== prevVocabulary || csid !== prevCsid || cloneCsid !== prevCloneCsid // DRYD-859: Re-init when data is reset but other props stay the same. || prevData.size > 0 && data.size === 0) { this.initRecord(); } } componentWillUnmount() { const { removeNotification, removeValidationNotification } = this.props; if (removeValidationNotification) { removeValidationNotification(); } if (removeNotification) { removeNotification(_HierarchyReparentNotifier.default.notificationID); } } handleModalCancelButtonClick(event) { const { closeModal, onSaveCancelled } = this.props; if (closeModal) { event.stopPropagation(); closeModal(false); } if (onSaveCancelled) { onSaveCancelled(); } } handleUndeprecateButtonClick() { const { transitionRecord, onRecordTransitioned } = this.props; const transitionName = 'undeprecate'; if (transitionRecord) { transitionRecord(transitionName).then(() => { if (onRecordTransitioned) { onRecordTransitioned(transitionName); } }); } } handleDeprecateButtonClick() { const { transitionRecord, onRecordTransitioned } = this.props; const transitionName = 'deprecate'; if (transitionRecord) { transitionRecord(transitionName).then(() => { if (onRecordTransitioned) { onRecordTransitioned(transitionName); } }); } } handleConfirmDeleteButtonClick() { this.delete(); } handleConfirmNavigationSaveButtonClick() { const { closeModal, onRecordCreated } = this.props; // Wrap the onRecordCreated callback in a function that sets isNavigating to true. This lets // the callback know that we're already navigating away, so it should not do any navigation // of its own. const callback = onRecordCreated ? newRecordCsid => { onRecordCreated(newRecordCsid, true); } : undefined; const saveCalled = this.save(callback); if (saveCalled && closeModal) { closeModal(true); } } handleConfirmNavigationRevertButtonClick() { const { closeModal, revert } = this.props; if (revert) { revert(); } if (closeModal) { closeModal(true); } } handleCloneButtonClick() { const { clone, csid } = this.props; if (clone) { clone(csid); } } handleDeleteButtonClick() { const { openModal } = this.props; if (openModal) { openModal(_modalNames.MODAL_CONFIRM_RECORD_DELETE); } } handleRevertButtonClick() { const { revert } = this.props; if (revert) { revert(); } } handleSaveButtonClick() { const { onRecordCreated } = this.props; this.save(onRecordCreated); } handleSaveButtonErrorBadgeClick() { const { validateRecordData } = this.props; if (validateRecordData) { validateRecordData(); } } handleSaveOnlyButtonClick() { const { save, closeModal, onRecordCreated } = this.props; if (save) { save(onRecordCreated).then(() => { if (closeModal) { closeModal(true); } }); } } handleSaveLockButtonClick() { const { saveWithTransition, closeModal, onRecordCreated } = this.props; if (saveWithTransition) { saveWithTransition('lock', onRecordCreated).then(() => { if (closeModal) { closeModal(true); } }); } } handleRecordFormSelectorCommit(path, value) { const { setForm } = this.props; if (setForm) { setForm(value); } } initRecord() { const { csid, cloneCsid, createNewRecord, readRecord, removeValidationNotification, onRecordReadComplete } = this.props; if (removeValidationNotification) { removeValidationNotification(); } if (csid) { if (readRecord) { readRecord().then(() => { if (onRecordReadComplete) { onRecordReadComplete(); } }); } } else if (createNewRecord) { createNewRecord(cloneCsid); } } save(onRecordCreated) { const { config, data, recordType, openModal, save, saveWithTransition, onRecordSaved } = this.props; const recordTypeConfig = config.recordTypes[recordType]; const { lockOnSave } = recordTypeConfig; if (lockOnSave === 'prompt' && openModal) { openModal(_modalNames.MODAL_LOCK_RECORD); return false; } let savePromise; if (lockOnSave === true && saveWithTransition) { savePromise = saveWithTransition('lock', onRecordCreated); } else if (save) { savePromise = save(onRecordCreated); } if (savePromise) { savePromise.then(() => { if (recordTypeConfig.onRecordSaved) { // TODO: Pass in the post-save data (which could have been modified due to services layer // event handlers) instead of the pre-save data. The save action would need to resolve // with the data instead of a csid. recordTypeConfig.onRecordSaved({ data, recordEditor: this }); } if (onRecordSaved) { onRecordSaved(); } }); } return true; } delete() { const { closeModal, isHardDelete, deleteRecord, onRecordDeleted, transitionRecord, onRecordTransitioned } = this.props; if (isHardDelete) { if (deleteRecord) { deleteRecord().then(() => { if (closeModal) { closeModal(true); } if (onRecordDeleted) { onRecordDeleted(); } }); } } else { const transitionName = 'delete'; if (transitionRecord) { transitionRecord(transitionName).then(() => { if (closeModal) { closeModal(true); } if (onRecordTransitioned) { onRecordTransitioned(transitionName); } }); } } } renderConfirmNavigationModal() { const { isModified, isSavePending, openModalName, validationErrors } = this.props; return /*#__PURE__*/_react.default.createElement(_ConfirmRecordNavigationModal.default, { isOpen: openModalName === _modalNames.MODAL_CONFIRM_RECORD_NAVIGATION, isModified: isModified, isSavePending: isSavePending, validationErrors: validationErrors, onCancelButtonClick: this.handleModalCancelButtonClick, onCloseButtonClick: this.handleModalCancelButtonClick, onSaveButtonClick: this.handleConfirmNavigationSaveButtonClick, onSaveButtonErrorBadgeClick: this.handleSaveButtonErrorBadgeClick, onRevertButtonClick: this.handleConfirmNavigationRevertButtonClick }); } renderConfirmRecordDeleteModal() { const { config, csid, data, isSavePending, openModalName, recordType, vocabulary, checkForRelations, checkForUses, checkForRoleUses } = this.props; return /*#__PURE__*/_react.default.createElement(_ConfirmRecordDeleteModal.default, { config: config, csid: csid, data: data, isOpen: openModalName === _modalNames.MODAL_CONFIRM_RECORD_DELETE, isSavePending: isSavePending, recordType: recordType, vocabulary: vocabulary, checkForRelations: checkForRelations, checkForUses: checkForUses, checkForRoleUses: checkForRoleUses, onCancelButtonClick: this.handleModalCancelButtonClick, onCloseButtonClick: this.handleModalCancelButtonClick, onDeleteButtonClick: this.handleConfirmDeleteButtonClick }); } renderLockRecordModal() { const { config, csid, isSavePending, openModalName, recordType } = this.props; const recordTypeConfig = config.recordTypes[recordType]; const { lockOnSave } = recordTypeConfig; if (lockOnSave !== 'prompt') { return null; } return /*#__PURE__*/_react.default.createElement(_LockRecordModal.default, { csid: csid, isOpen: openModalName === _modalNames.MODAL_LOCK_RECORD, isSavePending: isSavePending, onCancelButtonClick: this.handleModalCancelButtonClick, onCloseButtonClick: this.handleModalCancelButtonClick, onSaveOnlyButtonClick: this.handleSaveOnlyButtonClick, onSaveLockButtonClick: this.handleSaveLockButtonClick }); } render() { const { config, csid, data, dockTop, formName, isModified, isReadPending, isSavePending, isSidebarOpen, perms, recordType, relatedSubjectWorkflowState, roleNames, subrecordData, validationErrors, vocabulary, vocabularyWorkflowState, checkDeletable, onRunButtonClick } = this.props; const recordTypeConfig = config.recordTypes[recordType]; if (!data || !recordTypeConfig) { return null; } const serviceType = (0, _get.default)(recordTypeConfig, ['serviceConfig', 'serviceType']); const selectedFormName = formName || recordTypeConfig.defaultForm || 'default'; const relatedSubjectLocked = (0, _workflowStateHelpers.isLocked)(relatedSubjectWorkflowState); const vocabularyLocked = (0, _workflowStateHelpers.isLocked)(vocabularyWorkflowState); const immutable = (0, _recordDataHelpers.isRecordImmutable)(data); const readOnly = isReadPending || immutable || !(csid ? (0, _permissionHelpers.canUpdate)(recordType, perms) : (0, _permissionHelpers.canCreate)(recordType, perms)); const isRunnable = !!onRunButtonClick; const isCloneable = // The record must be saved. !!csid && !vocabularyLocked // If we're editing an object record in a secondary tab, and the primary record is locked, // a new cloned record would not be able to be related to the primary, so the clone // button should not appear. && !relatedSubjectLocked // We must have permission to create a new record of the type. && (0, _permissionHelpers.canCreate)(recordType, perms) // FIXME: Prevent cloning seeded authroles, since they may contain permissions that are not // normally creatable via the UI. Instead of hardcoding this, should be able to configure a // normalizeCloneData function that will clean up cloned data for a record type, and/or // a cloneable function that will determine if a record is cloneable based on its data. && !(recordType === 'authrole' && data.getIn(['ns2:role', 'permsProtection']) === 'immutable'); const isDeletable = (checkDeletable ? checkDeletable(data) : true) && !!csid && !immutable && !vocabularyLocked // Security resources don't have soft-delete, so also need to check hard delete. && ((0, _permissionHelpers.canSoftDelete)(recordType, perms) || (0, _permissionHelpers.canDelete)(recordType, perms)); const isDeprecatable = !!csid && config.termDeprecationEnabled && serviceType === 'authority' && !(0, _recordDataHelpers.isRecordDeprecated)(data); const isUndeprecatable = !!csid && config.termDeprecationEnabled && serviceType === 'authority' && (0, _recordDataHelpers.isRecordDeprecated)(data); const className = isSidebarOpen ? _RecordEditor.default.normal : _RecordEditor.default.full; return /*#__PURE__*/_react.default.createElement("form", { className: className, autoComplete: "off" }, /*#__PURE__*/_react.default.createElement(_Dock.default, { dockTop: dockTop, isSidebarOpen: isSidebarOpen }, /*#__PURE__*/_react.default.createElement(_RecordHeader.default, { config: config, data: data, formName: selectedFormName, isRunnable: isRunnable, isCloneable: isCloneable, isDeletable: isDeletable, isDeprecatable: isDeprecatable, isUndeprecatable: isUndeprecatable, isModified: isModified, isReadPending: isReadPending, isSavePending: isSavePending, readOnly: readOnly, recordType: recordType, validationErrors: validationErrors, onCloneButtonClick: this.handleCloneButtonClick, onCommit: this.handleRecordFormSelectorCommit, onDeprecateButtonClick: this.handleDeprecateButtonClick, onDeleteButtonClick: this.handleDeleteButtonClick, onSaveButtonClick: this.handleSaveButtonClick, onSaveButtonErrorBadgeClick: this.handleSaveButtonErrorBadgeClick, onRevertButtonClick: this.handleRevertButtonClick, onUndeprecateButtonClick: this.handleUndeprecateButtonClick, onRunButtonClick: onRunButtonClick })), /*#__PURE__*/_react.default.createElement(_RecordFormContainer.default, { config: config, csid: csid, data: data, formName: selectedFormName, readOnly: readOnly, recordType: recordType, recordTypeConfig: recordTypeConfig, roleNames: roleNames, subrecordData: subrecordData, vocabulary: vocabulary }), /*#__PURE__*/_react.default.createElement("footer", null, /*#__PURE__*/_react.default.createElement(_RecordButtonBar.default, { isRunnable: isRunnable, isCloneable: isCloneable, isDeletable: isDeletable, isDeprecatable: isDeprecatable, isUndeprecatable: isUndeprecatable, isModified: isModified, isReadPending: isReadPending, isSavePending: isSavePending, readOnly: readOnly, validationErrors: validationErrors, onSaveButtonClick: this.handleSaveButtonClick, onSaveButtonErrorBadgeClick: this.handleSaveButtonErrorBadgeClick, onRevertButtonClick: this.handleRevertButtonClick, onCloneButtonClick: this.handleCloneButtonClick, onDeleteButtonClick: this.handleDeleteButtonClick, onRunButtonClick: onRunButtonClick })), /*#__PURE__*/_react.default.createElement(_reactRouter.Prompt, { when: isModified && !isSavePending, message: _modalNames.MODAL_CONFIRM_RECORD_NAVIGATION }), this.renderConfirmNavigationModal(), this.renderConfirmRecordDeleteModal(), this.renderLockRecordModal()); } } exports.default = RecordEditor; RecordEditor.propTypes = propTypes; RecordEditor.defaultProps = defaultProps;