decap-cms-core
Version:
Decap CMS core application, see decap-cms package for the main distribution.
178 lines (160 loc) • 5.58 kB
JavaScript
import PropTypes from 'prop-types';
import { Component } from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import styled from '@emotion/styled';
import { OrderedMap } from 'immutable';
import { translate } from 'react-polyglot';
import { connect } from 'react-redux';
import {
Dropdown,
DropdownItem,
StyledDropdownButton,
Loader,
lengths,
components,
shadows,
} from 'decap-cms-ui-default';
import { createNewEntry } from '../../actions/collections';
import {
loadUnpublishedEntries,
updateUnpublishedEntryStatus,
publishUnpublishedEntry,
deleteUnpublishedEntry,
} from '../../actions/editorialWorkflow';
import { selectCanCreateNewEntry, selectUnpublishedEntriesByStatus } from '../../reducers';
import { EDITORIAL_WORKFLOW, status } from '../../constants/publishModes';
import WorkflowList from './WorkflowList';
const WorkflowContainer = styled.div`
height: 100vh;
margin: ${lengths.pageMarginMobile};
@media (min-width: 500px) {
margin: ${lengths.pageMargin};
}
`;
const WorkflowTop = styled.div`
${components.cardTop};
`;
const WorkflowTopRow = styled.div`
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
justify-content: space-between;
span[role='button'] {
${shadows.dropDeep};
}
`;
const WorkflowTopHeading = styled.h1`
${components.cardTopHeading};
`;
const WorkflowTopDescription = styled.p`
${components.cardTopDescription};
`;
class Workflow extends Component {
static propTypes = {
collections: ImmutablePropTypes.map.isRequired,
creatableCollections: ImmutablePropTypes.list.isRequired,
isEditorialWorkflow: PropTypes.bool.isRequired,
isOpenAuthoring: PropTypes.bool,
isFetching: PropTypes.bool,
unpublishedEntries: ImmutablePropTypes.map,
loadUnpublishedEntries: PropTypes.func.isRequired,
updateUnpublishedEntryStatus: PropTypes.func.isRequired,
publishUnpublishedEntry: PropTypes.func.isRequired,
deleteUnpublishedEntry: PropTypes.func.isRequired,
t: PropTypes.func.isRequired,
};
componentDidMount() {
// Manually validate PropTypes - React 19 breaking change
PropTypes.checkPropTypes(Workflow.propTypes, this.props, 'prop', 'Workflow');
const { loadUnpublishedEntries, isEditorialWorkflow, collections } = this.props;
if (isEditorialWorkflow) {
loadUnpublishedEntries(collections);
}
}
render() {
const {
isEditorialWorkflow,
isOpenAuthoring,
isFetching,
unpublishedEntries,
updateUnpublishedEntryStatus,
publishUnpublishedEntry,
deleteUnpublishedEntry,
collections,
creatableCollections,
t,
} = this.props;
if (!isEditorialWorkflow) return null;
if (isFetching) return <Loader active>{t('workflow.workflow.loading')}</Loader>;
const reviewCount = unpublishedEntries.get('pending_review').size;
const readyCount = unpublishedEntries.get('pending_publish').size;
return (
<WorkflowContainer>
<WorkflowTop>
<WorkflowTopRow>
<WorkflowTopHeading>{t('workflow.workflow.workflowHeading')}</WorkflowTopHeading>
<Dropdown
dropdownWidth="160px"
dropdownPosition="left"
dropdownTopOverlap="40px"
renderButton={() => (
<StyledDropdownButton>{t('workflow.workflow.newPost')}</StyledDropdownButton>
)}
>
{creatableCollections.map(collection => (
<DropdownItem
key={collection.get('name')}
label={collection.get('label')}
onClick={() => createNewEntry(collection.get('name'))}
/>
))}
</Dropdown>
</WorkflowTopRow>
<WorkflowTopDescription>
{t('workflow.workflow.description', {
smart_count: reviewCount,
readyCount,
})}
</WorkflowTopDescription>
</WorkflowTop>
<WorkflowList
entries={unpublishedEntries}
handleChangeStatus={updateUnpublishedEntryStatus}
handlePublish={publishUnpublishedEntry}
handleDelete={deleteUnpublishedEntry}
isOpenAuthoring={isOpenAuthoring}
collections={collections}
/>
</WorkflowContainer>
);
}
}
function mapStateToProps(state) {
const { collections, config, globalUI } = state;
const isEditorialWorkflow = config.publish_mode === EDITORIAL_WORKFLOW;
const isOpenAuthoring = globalUI.useOpenAuthoring;
const creatableCollections = collections
.filter(collection => selectCanCreateNewEntry(state, collection.get('name')))
.toList();
const returnObj = { collections, creatableCollections, isEditorialWorkflow, isOpenAuthoring };
if (isEditorialWorkflow) {
returnObj.isFetching = state.editorialWorkflow.getIn(['pages', 'isFetching'], false);
/*
* Generates an ordered Map of the available status as keys.
* Each key containing a Sequence of available unpubhlished entries
* Eg.: OrderedMap{'draft':Seq(), 'pending_review':Seq(), 'pending_publish':Seq()}
*/
returnObj.unpublishedEntries = status.reduce((acc, currStatus) => {
const entries = selectUnpublishedEntriesByStatus(state, currStatus);
return acc.set(currStatus, entries);
}, OrderedMap());
}
return returnObj;
}
export default connect(mapStateToProps, {
loadUnpublishedEntries,
updateUnpublishedEntryStatus,
publishUnpublishedEntry,
deleteUnpublishedEntry,
})(translate()(Workflow));