cspace-ui
Version:
CollectionSpace user interface for browsers
253 lines (198 loc) • 7.02 kB
JSX
import React from 'react';
import PropTypes from 'prop-types';
import { defineMessages, intlShape, FormattedMessage } from 'react-intl';
import { Link } from 'react-router-dom';
import Immutable from 'immutable';
import TitleBar from '../sections/TitleBar';
import { canCreate } from '../../helpers/permissionHelpers';
import { isLocked } from '../../helpers/workflowStateHelpers';
import styles from '../../../styles/cspace-ui/CreatePage.css';
import panelStyles from '../../../styles/cspace-ui/CreatePagePanel.css';
const serviceTypes = ['object', 'procedure', 'authority'];
const messages = defineMessages({
title: {
id: 'createPage.title',
defaultMessage: 'Create New',
},
object: {
id: 'createPage.object',
defaultMessage: 'Objects',
},
procedure: {
id: 'createPage.procedure',
defaultMessage: 'Procedures',
},
authority: {
id: 'createPage.authority',
defaultMessage: 'Authorities',
},
});
const getRecordTypesByServiceType = (recordTypes, perms, intl) => {
const recordTypesByServiceType = {};
serviceTypes.forEach((serviceType) => {
const recordTypeNames = Object.keys(recordTypes)
.filter((recordTypeName) => {
const recordTypeConfig = recordTypes[recordTypeName];
return (
recordTypeConfig.serviceConfig.serviceType === serviceType &&
!recordTypeConfig.disabled &&
canCreate(recordTypeName, perms)
);
})
.sort((nameA, nameB) => {
const configA = recordTypes[nameA];
const configB = recordTypes[nameB];
// Primary sort by sortOrder
let sortOrderA = configA.sortOrder;
let sortOrderB = configB.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(configA.messages.record.name);
const labelB = intl.formatMessage(configB.messages.record.name);
// FIXME: This should be locale aware
return labelA.localeCompare(labelB);
});
recordTypesByServiceType[serviceType] = recordTypeNames;
});
return recordTypesByServiceType;
};
const getVocabularies = (recordTypeConfig, intl, getAuthorityVocabWorkflowState) => {
const recordTypeName = recordTypeConfig.name;
const { vocabularies } = recordTypeConfig;
let vocabularyNames;
if (vocabularies) {
vocabularyNames = Object.keys(vocabularies)
.filter((vocabularyName) => {
// Filter out vocabularies that don't exist in the services layer, vocabularies that are
// locked, and vocabularies that are disabled. Always include the 'all' vocabulary.
const workflowState = getAuthorityVocabWorkflowState(recordTypeName, vocabularyName);
return (
vocabularyName !== 'all' &&
workflowState && // Empty workflow state means vocab doesn't exist.
!isLocked(workflowState) &&
!vocabularies[vocabularyName].disabled
);
})
.sort((nameA, nameB) => {
const configA = vocabularies[nameA];
const configB = vocabularies[nameB];
// Primary sort by sortOrder
let sortOrderA = configA.sortOrder;
let sortOrderB = configB.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(configA.messages.name);
const labelB = intl.formatMessage(configB.messages.name);
// FIXME: This should be locale aware
return labelA.localeCompare(labelB);
});
}
return vocabularyNames;
};
const contextTypes = {
config: PropTypes.object,
};
const propTypes = {
intl: intlShape,
perms: PropTypes.instanceOf(Immutable.Map),
getAuthorityVocabWorkflowState: PropTypes.func,
};
const defaultProps = {
getAuthorityVocabWorkflowState: () => null,
};
export default function CreatePage(props, context) {
const {
intl,
perms,
getAuthorityVocabWorkflowState,
} = props;
const {
config,
} = context;
const {
recordTypes,
} = config;
const itemsByServiceType = {};
const lists = [];
if (recordTypes) {
const recordTypesByServiceType = getRecordTypesByServiceType(recordTypes, perms, intl);
serviceTypes.forEach((serviceType) => {
itemsByServiceType[serviceType] = recordTypesByServiceType[serviceType].map((recordType) => {
const recordTypeConfig = recordTypes[recordType];
const vocabularies = getVocabularies(
recordTypeConfig, intl, getAuthorityVocabWorkflowState
);
let vocabularyList;
if (vocabularies && vocabularies.length > 0) {
const vocabularyItems = vocabularies.map(vocabulary =>
<li key={vocabulary}>
<Link id={`${recordType}/${vocabulary}`} to={`/record/${recordType}/${vocabulary}`}>
<FormattedMessage {...recordTypeConfig.vocabularies[vocabulary].messages.name} />
</Link>
</li>
);
vocabularyList = <ul>{vocabularyItems}</ul>;
}
if (recordTypeConfig.vocabularies && !vocabularyList) {
// The record type is an authority, but no vocabularies are enabled. Don't render
// anything.
return null;
}
const recordDisplayName = <FormattedMessage {...recordTypeConfig.messages.record.name} />;
let recordLink;
if (vocabularyList) {
recordLink = <h3 id={recordType}>{recordDisplayName}</h3>;
} else {
recordLink = <Link id={recordType} to={`/record/${recordType}`}>{recordDisplayName}</Link>;
}
return (
<li key={recordType}>
{recordLink}
{vocabularyList}
</li>
);
});
});
serviceTypes.forEach((serviceType) => {
const items = itemsByServiceType[serviceType].filter(item => !!item);
if (items && items.length > 0) {
lists.push(
<div className={panelStyles[serviceType]} key={serviceType}>
<h2><FormattedMessage {...messages[serviceType]} /></h2>
<ul>
{items}
</ul>
</div>
);
}
});
}
const title = <FormattedMessage {...messages.title} />;
return (
<div className={styles.common}>
<TitleBar title={title} updateDocumentTitle />
<div>
{lists}
</div>
</div>
);
}
CreatePage.propTypes = propTypes;
CreatePage.defaultProps = defaultProps;
CreatePage.contextTypes = contextTypes;