diff --git a/client/actions/assignments/api.ts b/client/actions/assignments/api.ts index bec65419c..8d00b041d 100644 --- a/client/actions/assignments/api.ts +++ b/client/actions/assignments/api.ts @@ -10,7 +10,7 @@ import * as actions from '../'; import {ASSIGNMENTS, ALL_DESKS, SORT_DIRECTION} from '../../constants'; import planningUtils from '../../utils/planning'; import {getErrorMessage, isExistingItem, gettext} from '../../utils'; -import planning from '../planning'; +import planningActions from '../planning/api'; import {assignmentsViewRequiresArchiveItems} from '../../components/Assignments/AssignmentItem/fields'; const setBaseQuery = ({must = []}) => ({ @@ -415,7 +415,7 @@ const receiveAssignmentHistory = (items) => ({ * @param {object} assignment - The Assignment to load items for */ const loadPlanningAndEvent = (assignment) => (dispatch) => - dispatch(planning.api.fetchById(assignment.planning_item)); + dispatch(planningActions.fetchById(assignment.planning_item)); /** * Loads the Archive items that are linked to the provided Assignment list diff --git a/client/components/Assignments/AssignmentPreviewContainer/index.tsx b/client/components/Assignments/AssignmentPreviewContainer/index.tsx index 16d944a5e..791d81ab4 100644 --- a/client/components/Assignments/AssignmentPreviewContainer/index.tsx +++ b/client/components/Assignments/AssignmentPreviewContainer/index.tsx @@ -16,6 +16,8 @@ import { import {superdeskApi} from '../../../superdeskApi'; import * as selectors from '../../../selectors'; import * as actions from '../../../actions'; +import planningActions from '../../../actions/planning/api'; + import {assignmentUtils, eventUtils, planningUtils, getFileDownloadURL} from '../../../utils'; import {ASSIGNMENTS, WORKSPACE} from '../../../constants'; @@ -262,7 +264,7 @@ const mapDispatchToProps = (dispatch) => ({ removeAssignment: (assignment) => dispatch(actions.assignments.ui.showRemoveAssignmentModal(assignment)), openArchivePreview: (assignment) => dispatch(actions.assignments.ui.openArchivePreview(assignment)), fetchEventFiles: (event) => dispatch(actions.events.api.fetchEventFiles(event)), - fetchPlanningFiles: (planning) => dispatch(actions.planning.api.fetchPlanningFiles(planning)), + fetchPlanningFiles: (planning) => dispatch(planningActions.fetchPlanningFiles(planning)), }); export const AssignmentPreviewContainer = connect( diff --git a/client/components/Coverages/CoverageArrayInput.tsx b/client/components/Coverages/CoverageArrayInput.tsx index 82cf285a0..cac903e8e 100644 --- a/client/components/Coverages/CoverageArrayInput.tsx +++ b/client/components/Coverages/CoverageArrayInput.tsx @@ -4,6 +4,7 @@ import {isEmpty} from 'lodash'; import { EDITOR_TYPE, + IAssignmentItem, IAssignmentPriority, ICoverageFormProfile, ICoverageProvider, ICoverageScheduledUpdate, IEventItem, IFile, @@ -22,6 +23,7 @@ import * as selectors from '../../selectors'; import {InputArray} from '../UI/Form'; import {CoverageEditor} from './CoverageEditor'; import {CoverageAddButton} from './CoverageAddButton'; +import * as actions from '../../actions'; interface IProps { @@ -78,12 +80,7 @@ interface IProps { scheduledUpdate?: ICoverageScheduledUpdate, scheduledUpdateIndex?: number ): void; - onRemoveAssignment( - coverage: IPlanningCoverageItem, - index: number, - scheduledUpdate?: ICoverageScheduledUpdate, - scheduledUpdateIndex?: number - ): void; + onRemoveAssignment(assignemnt: IAssignmentItem): Promise; uploadFiles(files: Array>): Promise>; notifyValidationErrors(errors: Array): void; } @@ -106,6 +103,10 @@ const mapStateToProps = (state) => ({ defaultDesk: selectors.general.defaultDesk(state), }); +const mapDispatchToProps = (dispatch) => ({ + onRemoveAssignment: (assignment) => dispatch(actions.assignments.ui.showRemoveAssignmentModal(assignment)), +}); + class CoverageArrayInputComponent extends React.Component { constructor(props) { super(props); @@ -214,6 +215,7 @@ class CoverageArrayInputComponent extends React.Component { onChange={onChange} addButtonText={addButtonText} addButtonComponent={CoverageAddButton} + onRemoveAssignment={this.props.onRemoveAssignment} addButtonProps={{ contentTypes, defaultDesk, @@ -260,4 +262,4 @@ class CoverageArrayInputComponent extends React.Component { } } -export const CoverageArrayInput = connect(mapStateToProps)(CoverageArrayInputComponent); +export const CoverageArrayInput = connect(mapStateToProps, mapDispatchToProps)(CoverageArrayInputComponent); diff --git a/client/components/Coverages/CoverageEditor/CoverageFormHeader.tsx b/client/components/Coverages/CoverageEditor/CoverageFormHeader.tsx index 26c534fb3..11b971be9 100644 --- a/client/components/Coverages/CoverageEditor/CoverageFormHeader.tsx +++ b/client/components/Coverages/CoverageEditor/CoverageFormHeader.tsx @@ -2,15 +2,18 @@ import React from 'react'; import {connect} from 'react-redux'; import {get} from 'lodash'; -import {IPlanningCoverageItem, ICoverageScheduledUpdate} from '../../../interfaces'; +import {IPlanningCoverageItem, ICoverageScheduledUpdate, ILockedItems} from '../../../interfaces'; import {IArticle, IDesk, IUser} from 'superdesk-api'; -import {getCreator, getItemInArrayById, gettext, planningUtils, onEventCapture} from '../../../utils'; +import {getCreator, getItemInArrayById, gettext, onEventCapture} from '../../../utils'; import {Item, Border, Column, Row as ListRow} from '../../UI/List'; -import {Button} from '../../UI'; import {UserAvatar} from '../../../components/UserAvatar'; import {StateLabel} from '../../StateLabel'; import * as actions from '../../../actions'; +import {ASSIGNMENTS} from '../../../constants/assignments'; +import * as selectors from '../../../selectors'; +import {planningUtils} from '../../../utils'; +import {Button} from 'superdesk-ui-framework/react'; interface IProps { field: string; @@ -21,7 +24,7 @@ interface IProps { addNewsItemToPlanning?: IArticle; onChange(field: string, value: any): void; onFocus?(): void; - onRemoveAssignment?(): void; + onRemoveAssignment?(): Promise; setCoverageDefaultDesk(coverage: IPlanningCoverageItem | ICoverageScheduledUpdate): void; showEditCoverageAssignmentModal(props: { field: string; @@ -32,6 +35,7 @@ interface IProps { onChange(field: string, value: any): void; setCoverageDefaultDesk(coverage: IPlanningCoverageItem | ICoverageScheduledUpdate): void; }): void; + lockedItems: ILockedItems; } const mapDispatchToProps = (dispatch) => ({ @@ -40,6 +44,10 @@ const mapDispatchToProps = (dispatch) => ({ ), }); +const mapStateToProps = (state) => ({ + lockedItems: selectors.locks.getLockedItems(state), +}); + export class CoverageFormHeaderComponent extends React.PureComponent { constructor(props) { super(props); @@ -69,15 +77,24 @@ export class CoverageFormHeaderComponent extends React.PureComponent { addNewsItemToPlanning, onRemoveAssignment, readOnly, + lockedItems, } = this.props; const userAssigned = getCreator(value, 'assigned_to.user', users); - const deskAssigned = getItemInArrayById(desks, get(value, 'assigned_to.desk')); - const coverageProvider = get(value, 'assigned_to.coverage_provider'); - const assignmentState = get(value, 'assigned_to.state'); - const cancelled = get(value, 'workflow_status') === 'cancelled'; - const canEditAssignment = planningUtils.isCoverageDraft(value) || - (!!addNewsItemToPlanning && !get(value, 'coverage_id') && !get(value, 'scheduled_update_id')); + const deskAssigned = getItemInArrayById(desks, value.assigned_to?.desk); + const coverageProvider = value.assigned_to?.coverage_provider; + const assignmentState = value.assigned_to?.state; + const cancelled = value.workflow_status === ASSIGNMENTS.WORKFLOW_STATE.CANCELLED; + + /* + Check if: + 1. This view is rendered from AddToPlanning action + 2. There's an already scheduled update for the coverage + */ + const isAssignmentLocked = lockedItems?.assignment + && value.assigned_to?.assignment_id in lockedItems.assignment; + const canEditAssignment = addNewsItemToPlanning == null && !isAssignmentLocked + && !((value as ICoverageScheduledUpdate).scheduled_update_id); if (!deskAssigned && (!userAssigned || !coverageProvider)) { return ( @@ -102,11 +119,9 @@ export class CoverageFormHeaderComponent extends React.PureComponent {