UNPKG

cspace-ui

Version:
353 lines (340 loc) 13.8 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 _immutable = _interopRequireDefault(require("immutable")); var _reactIntl = require("react-intl"); var _get = _interopRequireDefault(require("lodash/get")); var _cspaceInput = require("cspace-input"); var _configHelpers = require("../../helpers/configHelpers"); var _PermissionButton = _interopRequireDefault(require("../../../styles/cspace-ui/PermissionButton.css")); var _PermissionsInput = _interopRequireDefault(require("../../../styles/cspace-ui/PermissionsInput.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 { MiniButton } = _cspaceInput.components; const { getPath, pathPropType } = _cspaceInput.helpers.pathHelpers; const permMessages = (0, _reactIntl.defineMessages)({ '': { "id": "permissionsInput.perm.none", "defaultMessage": "None" }, RL: { "id": "permissionsInput.perm.read", "defaultMessage": "Read" }, CRUL: { "id": "permissionsInput.perm.write", "defaultMessage": "Write" }, CRUDL: { "id": "permissionsInput.perm.delete", "defaultMessage": "Delete" } }); const serviceTypeMessages = (0, _reactIntl.defineMessages)({ object: { "id": "permissionsInput.serviceType.object", "defaultMessage": "Objects" }, procedure: { "id": "permissionsInput.serviceType.procedure", "defaultMessage": "Procedures" }, authority: { "id": "permissionsInput.serviceType.authority", "defaultMessage": "Authorities" }, utility: { "id": "permissionsInput.serviceType.utility", "defaultMessage": "Utility Resources" }, security: { "id": "permissionsInput.serviceType.security", "defaultMessage": "Security Resources" } }); const serviceTypes = ['object', 'procedure', 'authority', 'utility', 'security']; const propTypes = { /* eslint-disable react/no-unused-prop-types */ name: _propTypes.default.string, parentPath: pathPropType, subpath: pathPropType, /* eslint-enable react/no-unused-prop-types */ readOnly: _propTypes.default.bool, resourceNames: _propTypes.default.instanceOf(_immutable.default.List), value: _propTypes.default.oneOfType([_propTypes.default.instanceOf(_immutable.default.List), _propTypes.default.instanceOf(_immutable.default.Map)]), readPerms: _propTypes.default.func, onCommit: _propTypes.default.func }; const contextTypes = { intl: _reactIntl.intlShape, config: _propTypes.default.shape({ recordTypes: _propTypes.default.object }) }; class PermissionsInput extends _react.Component { constructor(props, context) { super(props, context); this.handleHeaderButtonClick = this.handleHeaderButtonClick.bind(this); this.handleRadioChange = this.handleRadioChange.bind(this); } componentDidMount() { const { resourceNames, readPerms } = this.props; const { config } = this.context; if (!resourceNames && readPerms) { readPerms(config); } } handleHeaderButtonClick(event) { const { servicetype: serviceType, actiongroup: actionGroup } = event.currentTarget.dataset; const { onCommit } = this.props; if (onCommit) { const stagedUpdates = {}; this.getRecordTypeConfigs().filter(recordTypeConfig => recordTypeConfig.serviceConfig.serviceType === serviceType).forEach(recordTypeConfig => { this.stageUpdate(recordTypeConfig.name, actionGroup, stagedUpdates); }); const updatedPerms = this.updatePerms(stagedUpdates); onCommit(getPath(this.props), updatedPerms); } } handleRadioChange(event) { const { value: actionGroup, checked: selected } = event.target; const { name: recordType } = event.target.dataset; const { onCommit } = this.props; if (selected && onCommit) { const stagedUpdates = this.stageUpdate(recordType, actionGroup); const updatedPerms = this.updatePerms(stagedUpdates); onCommit(getPath(this.props), updatedPerms); } } getPermsMap() { const { value } = this.props; // The services layer gives us a list of resources and action groups. Build a map of resource // names to UI permissions. let permissionsList = value; if (!permissionsList) { return undefined; } if (!_immutable.default.List.isList(permissionsList)) { permissionsList = _immutable.default.List.of(permissionsList); } const perms = {}; permissionsList.forEach(permission => { const resourceName = permission.get('resourceName'); const actionGroup = permission.get('actionGroup'); perms[resourceName] = actionGroup; }); return perms; } getRecordTypeConfigs() { const { config } = this.context; const { resourceNames } = this.props; return resourceNames.map(resourceName => (0, _configHelpers.getRecordTypeConfigByServicePath)(config, resourceName)).filter(recordTypeConfig => recordTypeConfig && !recordTypeConfig.disabled); } stageUpdate(recordType, actionGroup = '', updates = {}) { /* The updates arg is mutated by this method. */ /* eslint-disable no-param-reassign */ const { config } = this.context; const recordTypeConfig = (0, _get.default)(config, ['recordTypes', recordType]); const { deletePermType, lockable, serviceConfig } = recordTypeConfig; const { documentName, servicePath, serviceType } = serviceConfig; const resourceName = servicePath; const shouldSetSoftDeletePerm = !deletePermType || deletePermType === 'soft' || deletePermType === 'all'; const shouldSetHardDeletePerm = deletePermType === 'hard' || deletePermType === 'all'; updates[resourceName] = shouldSetHardDeletePerm ? actionGroup : actionGroup.replace('D', ''); if (shouldSetSoftDeletePerm) { const softDeleteResourceName = `/${resourceName}/*/workflow/delete`; if (!actionGroup) { updates[softDeleteResourceName] = ''; } else if (actionGroup.includes('D')) { updates[softDeleteResourceName] = 'CRUDL'; } else { updates[softDeleteResourceName] = 'RL'; } } if (lockable) { const lockResourceName = `/${resourceName}/*/workflow/lock`; if (!actionGroup) { updates[lockResourceName] = ''; } else if (actionGroup.includes('C') || actionGroup.includes('U') || actionGroup.includes('D')) { updates[lockResourceName] = 'CRUDL'; } else { updates[lockResourceName] = 'RL'; } } if (serviceType === 'authority') { // Permissions on authorities should be set on both the authorities and their items. const itemResourceName = documentName; updates[itemResourceName] = actionGroup; } if (resourceName === 'authorization/roles') { // If the authorization/roles resource can be read, allow permissions to be read and // listed. This allows the permissions list to be displayed when viewing the role. const permissionsResourceName = 'authorization/permissions'; updates[permissionsResourceName] = actionGroup && actionGroup.includes('R') ? 'RL' : ''; } // Always allow read and list on servicegroups. updates.servicegroups = 'RL'; return updates; /* eslint-enable no-param-reassign */ } updatePerms(updates) { const perms = this.getPermsMap() || {}; Object.assign(perms, updates); return _immutable.default.List(Object.keys(perms).filter(resourceName => !!perms[resourceName]).map(resourceName => _immutable.default.Map({ resourceName, actionGroup: perms[resourceName] }))); } renderHeaderButton(serviceType, actionGroup) { const { readOnly } = this.props; return /*#__PURE__*/_react.default.createElement(MiniButton, { autoWidth: true, onClick: this.handleHeaderButtonClick, "data-servicetype": serviceType, "data-actiongroup": actionGroup, disabled: readOnly }, /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, permMessages[actionGroup])); } renderRadioButton(perms, recordType, resourceName, value) { const { readOnly } = this.props; const className = readOnly ? _PermissionButton.default.readOnly : _PermissionButton.default.normal; let checked = false; if (perms) { let effectivePerms = perms[resourceName]; if (effectivePerms === 'CRUL') { // Check for soft-delete perm, and synthesize a delete perm if present. const workflowDeleteResourceName = `/${resourceName}/*/workflow/delete`; if (perms[workflowDeleteResourceName] === 'CRUDL') { effectivePerms = 'CRUDL'; } } checked = value ? effectivePerms === value : !effectivePerms; } return ( /*#__PURE__*/ // eslint-disable-next-line jsx-a11y/label-has-associated-control _react.default.createElement("label", { className: className }, /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, permMessages[value]), /*#__PURE__*/_react.default.createElement("input", { checked: checked, "data-name": recordType, type: "radio", value: value, disabled: readOnly, onChange: this.handleRadioChange }), /*#__PURE__*/_react.default.createElement("div", null)) ); } renderPermRows() { const { intl } = this.context; const perms = this.getPermsMap() || {}; const sections = []; serviceTypes.forEach(serviceType => { const rows = []; this.getRecordTypeConfigs().filter(recordTypeConfig => recordTypeConfig.serviceConfig.serviceType === serviceType).sort((recordTypeConfigA, recordTypeConfigB) => { // Primary sort by sortOrder let sortOrderA = recordTypeConfigA.sortOrder; let sortOrderB = recordTypeConfigB.sortOrder; if (typeof sortOrderA !== 'number') { sortOrderA = Number.MAX_VALUE; } if (typeof sortOrderB !== 'number') { sortOrderB = Number.MAX_VALUE; } if (sortOrderA !== sortOrderB) { return sortOrderA > sortOrderB ? 1 : -1; } // Secondary sort by label const labelA = intl.formatMessage(recordTypeConfigA.messages.record.collectionName); const labelB = intl.formatMessage(recordTypeConfigB.messages.record.collectionName); // FIXME: This should be locale aware return labelA.localeCompare(labelB); }).forEach(recordTypeConfig => { const { name } = recordTypeConfig; const resourceName = recordTypeConfig.serviceConfig.servicePath; const nameMessage = (0, _get.default)(recordTypeConfig, ['messages', 'record', 'collectionName']); const formattedName = nameMessage ? intl.formatMessage(nameMessage) : `[ ${name} ]`; rows.push( /*#__PURE__*/_react.default.createElement("div", { key: name }, /*#__PURE__*/_react.default.createElement("div", null, formattedName), /*#__PURE__*/_react.default.createElement("div", null, this.renderRadioButton(perms, name, resourceName, ''), this.renderRadioButton(perms, name, resourceName, 'RL'), this.renderRadioButton(perms, name, resourceName, 'CRUL'), this.renderRadioButton(perms, name, resourceName, 'CRUDL')))); }); sections.push( /*#__PURE__*/_react.default.createElement("section", { key: serviceType }, /*#__PURE__*/_react.default.createElement("header", null, /*#__PURE__*/_react.default.createElement("h3", null, /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, serviceTypeMessages[serviceType])), /*#__PURE__*/_react.default.createElement("ul", null, /*#__PURE__*/_react.default.createElement("li", null, this.renderHeaderButton(serviceType, '')), /*#__PURE__*/_react.default.createElement("li", null, this.renderHeaderButton(serviceType, 'RL')), /*#__PURE__*/_react.default.createElement("li", null, this.renderHeaderButton(serviceType, 'CRUL')), /*#__PURE__*/_react.default.createElement("li", null, this.renderHeaderButton(serviceType, 'CRUDL')))), rows)); }); return sections; } render() { const { readOnly, resourceNames } = this.props; if (!resourceNames) { return null; } let { value } = this.props; if (value && !_immutable.default.List.isList(value)) { value = _immutable.default.List.of(value); } const className = readOnly ? _PermissionsInput.default.readOnly : _PermissionsInput.default.common; return /*#__PURE__*/_react.default.createElement("div", { className: className }, this.renderPermRows()); } } exports.default = PermissionsInput; PermissionsInput.propTypes = propTypes; PermissionsInput.contextTypes = contextTypes;