Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show reassign on auto add to workflow, types cleanup #2121

Merged
merged 11 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions client/components/Coverages/CoverageArrayInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {isEmpty} from 'lodash';

import {
EDITOR_TYPE,
IAssignmentItem,
IAssignmentPriority,
ICoverageFormProfile,
ICoverageProvider, ICoverageScheduledUpdate, IEventItem, IFile,
Expand All @@ -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 {
Expand Down Expand Up @@ -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<void>;
uploadFiles(files: Array<Array<File>>): Promise<Array<IFile>>;
notifyValidationErrors(errors: Array<string>): void;
}
Expand All @@ -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<IProps, IState> {
constructor(props) {
super(props);
Expand Down Expand Up @@ -214,6 +215,7 @@ class CoverageArrayInputComponent extends React.Component<IProps, IState> {
onChange={onChange}
addButtonText={addButtonText}
addButtonComponent={CoverageAddButton}
onRemoveAssignment={this.props.onRemoveAssignment}
addButtonProps={{
contentTypes,
defaultDesk,
Expand Down Expand Up @@ -260,4 +262,4 @@ class CoverageArrayInputComponent extends React.Component<IProps, IState> {
}
}

export const CoverageArrayInput = connect(mapStateToProps)(CoverageArrayInputComponent);
export const CoverageArrayInput = connect(mapStateToProps, mapDispatchToProps)(CoverageArrayInputComponent);
71 changes: 42 additions & 29 deletions client/components/Coverages/CoverageEditor/CoverageFormHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -21,7 +24,7 @@ interface IProps {
addNewsItemToPlanning?: IArticle;
onChange(field: string, value: any): void;
onFocus?(): void;
onRemoveAssignment?(): void;
onRemoveAssignment?(): Promise<void>;
setCoverageDefaultDesk(coverage: IPlanningCoverageItem | ICoverageScheduledUpdate): void;
showEditCoverageAssignmentModal(props: {
field: string;
Expand All @@ -32,6 +35,7 @@ interface IProps {
onChange(field: string, value: any): void;
setCoverageDefaultDesk(coverage: IPlanningCoverageItem | ICoverageScheduledUpdate): void;
}): void;
lockedItems: ILockedItems;
}

const mapDispatchToProps = (dispatch) => ({
Expand All @@ -40,6 +44,10 @@ const mapDispatchToProps = (dispatch) => ({
),
});

const mapStateToProps = (state) => ({
lockedItems: selectors.locks.getLockedItems(state),
});

export class CoverageFormHeaderComponent extends React.PureComponent<IProps> {
constructor(props) {
super(props);
Expand Down Expand Up @@ -69,15 +77,24 @@ export class CoverageFormHeaderComponent extends React.PureComponent<IProps> {
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 (
Expand All @@ -102,11 +119,9 @@ export class CoverageFormHeaderComponent extends React.PureComponent<IProps> {
<Button
id="editAssignment"
text={gettext('Assign')}
tabIndex={0}
enterKeyIsClick
className="btn btn--primary btn--small"
onClick={this.showAssignmentModal}
autoFocus
size="small"
type="primary"
/>
</ListRow>
)}
Expand All @@ -130,7 +145,7 @@ export class CoverageFormHeaderComponent extends React.PureComponent<IProps> {
<span className="sd-list-item__text-label sd-list-item__text-label--normal">
{gettext('Desk:')}
</span>
<span name={`${field}.assigned_to.desk`}>
<span key={`${field}.assigned_to.desk`}>
{get(deskAssigned, 'name', '')}
</span>
</span>
Expand All @@ -141,7 +156,7 @@ export class CoverageFormHeaderComponent extends React.PureComponent<IProps> {
<span className="sd-list-item__text-label sd-list-item__text-label--normal">
{gettext('Assignee:')}
</span>
<span name={`${field}.assigned_to.user`}>
<span key={`${field}.assigned_to.user`}>
{get(userAssigned, 'display_name', '')}
</span>
</span>
Expand Down Expand Up @@ -173,24 +188,22 @@ export class CoverageFormHeaderComponent extends React.PureComponent<IProps> {
<ListRow>
<Button
text={gettext('Reassign')}
className="btn btn--hollow btn--small"
onClick={this.showAssignmentModal}
tabIndex={0}
enterKeyIsClick
disabled={!!addNewsItemToPlanning}
autoFocus
style="hollow"
size="small"
expand
/>
</ListRow>
{!onRemoveAssignment ? null : (
{onRemoveAssignment != null && (
<ListRow>
<Button
text={gettext('Remove')}
className="btn btn--hollow btn--small"
onClick={onRemoveAssignment}
tabIndex={0}
enterKeyIsClick
disabled={!!addNewsItemToPlanning}
autoFocus
onClick={() => {
onRemoveAssignment();
}}
style="hollow"
size="small"
expand
/>
</ListRow>
)}
Expand All @@ -202,6 +215,6 @@ export class CoverageFormHeaderComponent extends React.PureComponent<IProps> {
}

export const CoverageFormHeader = connect(
null,
mapStateToProps,
mapDispatchToProps
)(CoverageFormHeaderComponent);
2 changes: 1 addition & 1 deletion client/components/Coverages/CoverageEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ interface IProps {
onDuplicateCoverage(coverage: DeepPartial<IPlanningCoverageItem>, duplicateAs?: IG2ContentType['qcode']): void;
onCancelCoverage?(): void;
onAddCoverageToWorkflow?(): void;
onRemoveAssignment?(): void;
onRemoveAssignment?(coverage: IPlanningCoverageItem): void;
popupContainer(): void;
setCoverageDefaultDesk(): void;
onPopupOpen(): void;
Expand Down
89 changes: 35 additions & 54 deletions client/components/UI/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,60 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import {KEYCODES} from './constants';
import {onEventCapture} from './utils';


/**
* @ngdoc react
* @name Button
* @description Generic Button component
*/
interface IButtonProps {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just as a note, we should replace these with the ones from the UI Framework

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do that for this ticket if you mean replacing the button

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For buttons related to this assignment

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's easy to replace these remove/reassign buttons to UI Framework ones, then it might be beneficial here (while you're editing this component anyways).
That way, PR by PR we can slowly replace these old ones with the new ones, rather than 1 big task to remove old code/components

id?: string;
className?: string;
onClick: (...args: any) => any;
icon?: string;
title?: string;
text?: string;
disabled?: boolean;
textOnly?: boolean;
hollow?: boolean;
iconOnly?: boolean;
expanded?: boolean;
color?: 'primary' | 'success' | 'warning' | 'alert' | 'highlight' | 'sd-green' | 'ui-dark' | 'default';
size?: 'small' | 'large';
tabIndex?: number;
enterKeyIsClick?: boolean;
autoFocus?: boolean;
onKeyDown?: (e: React.KeyboardEvent) => any;
refNode?: (...args: any) => any;
iconOnlyCircle?: boolean;
children?: React.ReactNode;
pullRight?: boolean;
empty?: boolean;
}

const Button = ({
disabled = false,
textOnly = false,
hollow = false,
expanded = false,
enterKeyIsClick = false,
autoFocus = false,
iconOnlyCircle = false,
pullRight = false,
empty = false,
className,
onClick,
icon,
id,
title,
text,
disabled,
textOnly,
hollow,
expanded,
color,
size,
iconOnly,
tabIndex,
enterKeyIsClick,
autoFocus,
refNode,
onKeyDown,
iconOnlyCircle,
children,
pullRight,
empty,
...props
}) => {
}: IButtonProps) => {
const handeKeyDown = (event) => {
if (event.keyCode === KEYCODES.ENTER) {
onEventCapture(event);
Expand Down Expand Up @@ -82,42 +101,4 @@ const Button = ({
);
};

Button.propTypes = {
id: PropTypes.string,
className: PropTypes.string,
onClick: PropTypes.func.isRequired,
icon: PropTypes.string,
title: PropTypes.string,
text: PropTypes.string,
disabled: PropTypes.bool,
textOnly: PropTypes.bool,
hollow: PropTypes.bool,
iconOnly: PropTypes.bool,
expanded: PropTypes.bool,
color: PropTypes.oneOf(['primary', 'success', 'warning', 'alert', 'highlight', 'sd-green', 'ui-dark', 'default']),
size: PropTypes.oneOf(['small', 'large']),
tabIndex: PropTypes.number,
enterKeyIsClick: PropTypes.bool,
autoFocus: PropTypes.bool,
onKeyDown: PropTypes.func,
refNode: PropTypes.func,
iconOnlyCircle: PropTypes.bool,
children: PropTypes.node,
pullRight: PropTypes.bool,
empty: PropTypes.bool,
};

Button.defaultProps = {
disabled: false,
textOnly: false,
hollow: false,
iconOnly: false,
expanded: false,
enterKeyIsClick: false,
autoFocus: false,
iconOnlyCircle: false,
pullRight: false,
empty: false,
};

export default Button;
28 changes: 26 additions & 2 deletions client/components/UI/Form/InputArray/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ import {Button} from '../../';
import {Row, LineInput} from '../';
import './style.scss';
import {superdeskApi} from '../../../../superdeskApi';
import {planningApis} from '../../../../api';
import {
EDITOR_TYPE,
IAssignmentItem,
IG2ContentType,
IPlanningCoverageItem,
IPlanningNewsCoverageStatus,
} from 'interfaces';
import {IDesk} from 'superdesk-api';

interface IProps {
field: string;
Expand All @@ -18,7 +27,7 @@ interface IProps {
maxCount: number;
addOnly: boolean;
originalCount: number;
element: React.ComponentClass;
element: React.ComponentClass<any>;
defaultElement: any;
readOnly: boolean;
message: any;
Expand All @@ -37,8 +46,19 @@ interface IProps {
errors: {[key: string]: any};
showErrors: boolean;
testId?: string;

onRemoveAssignment: (assignment: IAssignmentItem) => Promise<void>;
getRef?(field: string, value: any): React.RefObject<any>;
popupContainer(): HTMLElement;
onPopupOpen(): void;
onPopupClose(): void;
setCoverageDefaultDesk(coverage: IPlanningCoverageItem): void;
contentTypes: Array<IG2ContentType>;
defaultDesk: IDesk;
newsCoverageStatus: Array<IPlanningNewsCoverageStatus>;
navigation: any;
openCoverageIds: Array<string>;
preferredCoverageDesks: {[key: string]: string};
editorType: EDITOR_TYPE;
}

export class InputArray extends React.PureComponent<IProps> {
Expand Down Expand Up @@ -153,6 +173,10 @@ export class InputArray extends React.PureComponent<IProps> {
{(value || []).map((val, index) => (
<Component
{...props}
onRemoveAssignment={(val) =>
planningApis.assignments.getById(val.assigned_to.assignment_id)
.then((assignment) => this.props.onRemoveAssignment(assignment))
}
key={index}
ref={this.props.getRef == null ? null : this.props.getRef(field, val)}
testId={`${testId}[${index}]`}
Expand Down
Loading
Loading