diff --git a/client/components/Assignments/AssignmentEditor.tsx b/client/components/Assignments/AssignmentEditor.tsx
index 24436ffee..201ec76e0 100644
--- a/client/components/Assignments/AssignmentEditor.tsx
+++ b/client/components/Assignments/AssignmentEditor.tsx
@@ -14,9 +14,9 @@ import {
Row,
SelectInput,
ColouredValueInput,
- SelectUserInput,
} from '../UI/Form';
import {ContactsPreviewList, SelectSearchContactsField} from '../Contacts';
+import {superdeskApi} from '../../superdeskApi';
export class AssignmentEditorComponent extends React.Component {
constructor(props) {
@@ -243,6 +243,7 @@ export class AssignmentEditorComponent extends React.Component {
showPriority,
className,
} = this.props;
+ const {SelectUser} = superdeskApi.components;
return (
@@ -297,15 +298,19 @@ export class AssignmentEditorComponent extends React.Component {
/>
) : (
-
+
+
+ {
+ this.onUserChange(null, user);
+ }}
+ autoFocus={false}
+ horizontalSpacing={true}
+ clearable={true}
+ />
+
+
)}
{showPriority && (
diff --git a/client/components/Assignments/EditCoverageAssignmentModal.tsx b/client/components/Assignments/EditCoverageAssignmentModal.tsx
index e00d41cc0..0367175ea 100644
--- a/client/components/Assignments/EditCoverageAssignmentModal.tsx
+++ b/client/components/Assignments/EditCoverageAssignmentModal.tsx
@@ -70,6 +70,7 @@ export class EditCoverageAssignmentModalComponent extends React.Component {
show={true}
onHide={handleHide}
fill={false}
+ removeTabIndexAttribute={true}
>
{gettext('Coverage Assignment Details')}
diff --git a/client/components/Coverages/CoverageAddAdvancedModal.tsx b/client/components/Coverages/CoverageAddAdvancedModal.tsx
index b2edfdff2..984c5bab8 100644
--- a/client/components/Coverages/CoverageAddAdvancedModal.tsx
+++ b/client/components/Coverages/CoverageAddAdvancedModal.tsx
@@ -9,7 +9,8 @@ import {getUserInterfaceLanguageFromCV} from '../../utils/users';
import {getVocabularyItemFieldTranslated} from '../../utils/vocabularies';
import Modal from '../Modal';
-import {SelectInput, SelectUserInput} from '../UI/Form';
+import {SelectInput} from '../UI/Form';
+import {superdeskApi} from '../../superdeskApi';
const isInvalid = (coverage) => coverage.user && !coverage.desk;
@@ -35,7 +36,7 @@ interface ICoverageSelector {
name: IG2ContentType['name'];
icon: string;
desk: IDesk['_id'];
- user: IUser['_id'];
+ user: IUser;
status: IPlanningNewsCoverageStatus;
popupContainer: any;
filteredDesks: Array;
@@ -218,6 +219,7 @@ export class CoverageAddAdvancedModal extends React.Component {
render() {
const language = getUserInterfaceLanguageFromCV();
+ const {SelectUser} = superdeskApi.components;
return (
{
event.stopPropagation();
this.props.close();
}}
+ removeTabIndexAttribute={true}
>
@@ -276,18 +279,25 @@ export class CoverageAddAdvancedModal extends React.Component {
-
this.onUserChange(coverage, value)}
- labelField="name"
- keyField="_id"
- users={coverage.filteredUsers}
- clearable={true}
- popupContainer={() => coverage.popupContainer}
- inline={true}
- />
- coverage.popupContainer = node} />
+
+
{
+ this.onUserChange(coverage, user);
+ }}
+ autoFocus={false}
+ horizontalSpacing={true}
+ clearable={true}
+ />
+ coverage.popupContainer = node} />
+
diff --git a/client/components/ModalWithForm/index.tsx b/client/components/ModalWithForm/index.tsx
index 3b409eea4..361092326 100644
--- a/client/components/ModalWithForm/index.tsx
+++ b/client/components/ModalWithForm/index.tsx
@@ -101,6 +101,7 @@ export class ModalWithForm extends React.Component {
fill={fill}
fullscreen={fullscreen}
white={white}
+ removeTabIndexAttribute={true}
>
{title}
diff --git a/client/components/UI/Form/SelectUserInput/SelectUserPopup.tsx b/client/components/UI/Form/SelectUserInput/SelectUserPopup.tsx
deleted file mode 100644
index 97c3a8734..000000000
--- a/client/components/UI/Form/SelectUserInput/SelectUserPopup.tsx
+++ /dev/null
@@ -1,148 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import classNames from 'classnames';
-import {get} from 'lodash';
-
-import {KEYCODES} from '../../constants';
-import {gettext, scrollListItemIfNeeded, onEventCapture} from '../../utils';
-
-import {Popup, Content} from '../../Popup';
-import {UserAvatarWithMargin} from '../../../../components/UserAvatar';
-
-import './style.scss';
-
-/**
- * @ngdoc react
- * @name SelectUserPopup
- * @description Pop-up component of SelectUserList
- */
-export class SelectUserPopup extends React.Component {
- constructor(props) {
- super(props);
- this.onKeyDown = this.onKeyDown.bind(this);
- this.handleOnChange = this.handleOnChange.bind(this);
- this.state = {activeIndex: -1};
- this.dom = {itemList: null};
- }
-
- /**
- * @ngdoc method
- * @name SelectUserPopup#onKeyDown
- * @description onKeyDown method to handle keyboard selection of options
- */
- onKeyDown(event) {
- if (event) {
- switch (event.keyCode) {
- case KEYCODES.ENTER:
- onEventCapture(event);
- this.handleEnterKey(event);
- break;
- case KEYCODES.DOWN:
- onEventCapture(event);
- this.handleDownArrowKey(event);
- break;
- case KEYCODES.UP:
- onEventCapture(event);
- this.handleUpArrowKey(event);
- break;
- }
- }
- }
-
- /**
- * @ngdoc method
- * @name SelectUserPopup#handleEnterKey
- * @description handleEnterKey method to handle enter-key press on a selected option
- */
- handleEnterKey(event) {
- this.props.onChange(this.props.users[this.state.activeIndex]);
- }
-
- /**
- * @ngdoc method
- * @name SelectUserPopup#handleDownArrowKey
- * @description handleDownArrowKey method to handle down-key press to select options
- */
- handleDownArrowKey(event) {
- if (get(this.props, 'users.length', 0) - 1 > this.state.activeIndex) {
- this.setState({activeIndex: this.state.activeIndex + 1});
- scrollListItemIfNeeded(this.state.activeIndex, this.dom.itemList);
- }
- }
-
- /**
- * @ngdoc method
- * @name SelectUserPopup#handleUpArrowKey
- * @description handleUpArrowKey method to handle up-key press to select options
- */
- handleUpArrowKey(event) {
- if (this.state.activeIndex > 0) {
- this.setState({activeIndex: this.state.activeIndex - 1});
- scrollListItemIfNeeded(this.state.activeIndex, this.dom.itemList);
- }
- }
-
- handleOnChange(user, event) {
- onEventCapture(event);
- this.props.onChange(user);
- }
-
- render() {
- const {
- onClose,
- target,
- popupContainer,
- users,
- } = this.props;
-
- return (
-
-
- this.dom.itemList = ref}
- >
- {users.length > 0 && users.map((user, index) => (
- -
-
-
- ))}
-
- {users.length === 0 && (
- -
-
-
- )}
-
-
-
- );
- }
-}
-
-SelectUserPopup.propTypes = {
- onClose: PropTypes.func,
- target: PropTypes.string,
- popupContainer: PropTypes.func,
- users: PropTypes.array,
- onChange: PropTypes.func,
-};
diff --git a/client/components/UI/Form/SelectUserInput/index.tsx b/client/components/UI/Form/SelectUserInput/index.tsx
deleted file mode 100644
index 7a6307eae..000000000
--- a/client/components/UI/Form/SelectUserInput/index.tsx
+++ /dev/null
@@ -1,173 +0,0 @@
-import React from 'react';
-
-import {IUser} from 'superdesk-api';
-import {superdeskApi} from '../../../../superdeskApi';
-import {KEYCODES} from '../../constants';
-
-import {onEventCapture} from '../../utils';
-
-import {Row, LineInput, Label, Input} from '../';
-import {UserAvatarWithMargin} from '../../../../components/UserAvatar';
-import {SelectUserPopup} from './SelectUserPopup';
-
-interface IProps {
- field: string;
- label?: string;
- placeholder?: string;
- value: any;
- users: Array;
- readOnly?: boolean;
- hideInactiveDisabled?: boolean; // defaults to `true`
- inline?: boolean;
- onChange(field: string, value?: IUser): void;
- popupContainer?(): HTMLElement;
-}
-
-interface IState {
- filteredUserList: Array;
- searchText?: string;
- openFilterList?: boolean;
-}
-
-/**
- * @ngdoc react
- * @name SelectUserInput
- * @description Component to select users from a list
- */
-export class SelectUserInput extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {
- filteredUserList: this.getUsersToDisplay(this.props.users),
- searchText: '',
- openFilterList: false,
- };
-
- this.openPopup = this.openPopup.bind(this);
- this.closePopup = this.closePopup.bind(this);
- this.filterUserList = this.filterUserList.bind(this);
- this.onUserChange = this.onUserChange.bind(this);
- }
-
- componentWillReceiveProps(nextProps) {
- this.setState({filteredUserList: this.getUsersToDisplay(nextProps.users)});
- }
-
- openPopup() {
- this.setState({openFilterList: true});
- }
-
- closePopup() {
- this.setState({openFilterList: false});
- }
-
- filterUserList(field, value) {
- if (!value) {
- this.setState({
- filteredUserList: this.getUsersToDisplay(this.props.users),
- searchText: '',
- openFilterList: true,
- });
- return;
- }
-
- const filterTextNoCase = value.toLowerCase();
- const newUserList = this.props.users.filter((user) => (
- user.display_name.toLowerCase().substr(0, value.length) === filterTextNoCase ||
- user.display_name.toLowerCase().indexOf(filterTextNoCase) >= 0
- ));
-
- this.setState({
- filteredUserList: this.getUsersToDisplay(newUserList),
- searchText: value,
- openFilterList: true,
- });
- }
-
- onUserChange(newUserId) {
- this.props.onChange(this.props.field, newUserId);
- this.setState({
- openFilterList: false,
- searchText: '',
- });
- }
-
- getUsersToDisplay(list = []) {
- if (!(this.props.hideInactiveDisabled ?? true)) {
- return list;
- } else {
- return list.filter((u) => u.is_active && u.is_enabled && !u.needs_activation);
- }
- }
-
- render() {
- const {gettext} = superdeskApi.localization;
- const {value, popupContainer, label, readOnly, inline, field} = this.props;
-
- return (
-
- {(!inline || value) && (
-
-
-
-
- {value && (
-
-
-
{value.display_name}
- {!readOnly && (
-
- )}
-
- )}
-
-
- )}
-
- {!readOnly && (!inline || !value) && (
-
-
- {
- if (event.keyCode === KEYCODES.ENTER ||
- event.keyCode === KEYCODES.DOWN) {
- onEventCapture(event);
- this.openPopup();
- }
- }
- }
- />
-
- {this.state.openFilterList && (
-
- )}
-
-
- )}
-
- );
- }
-}
diff --git a/client/components/UI/Form/SelectUserInput/style.scss b/client/components/UI/Form/SelectUserInput/style.scss
deleted file mode 100644
index cc39f1de7..000000000
--- a/client/components/UI/Form/SelectUserInput/style.scss
+++ /dev/null
@@ -1,48 +0,0 @@
-@import '~superdesk-ui-framework/app/styles/_mixins.scss';
-@import '~superdesk-ui-framework/app/styles/_variables.scss';
-
-.user-search__popup {
- margin-top: 1px;
-
- &-list {
- li {
- margin: 5px 0;
- }
-
- overflow-y: scroll;
- max-height: 250px;
- }
-
- &-item {
- margin: 5px;
- &:hover {
- background: $sd-hover;
- }
-
- button {
- width: 100%;
- text-align: left;
- }
-
- &--active {
- background: $sd-hover;
- }
- }
-
- &-item-label {
- padding-top: 5px;
- display: inline-block;
- width: 200px;
- text-align: left;
- }
-
- &-user {
- display: inline-block;
- margin: 10px 0;
- width: 100%;
-
- button {
- float: right;
- }
- }
-}
diff --git a/client/components/UI/Form/index.ts b/client/components/UI/Form/index.ts
index 03a068922..2d0a9c973 100644
--- a/client/components/UI/Form/index.ts
+++ b/client/components/UI/Form/index.ts
@@ -14,7 +14,6 @@ export {SelectInput} from './SelectInput';
export {FileInput} from './FileInput';
export {LinkInput} from './LinkInput';
export {SelectMetaTermsInput} from './SelectMetaTermsInput/index';
-export {SelectUserInput} from './SelectUserInput';
export {SelectTagInput} from './SelectTagInput';
export {Checkbox} from './Checkbox';
export {CheckboxGroup} from './CheckboxGroup';
diff --git a/client/components/fields/editor/EventRelatedPlannings/EmbeddedCoverageForm.tsx b/client/components/fields/editor/EventRelatedPlannings/EmbeddedCoverageForm.tsx
index 2d3f34494..c4910538c 100644
--- a/client/components/fields/editor/EventRelatedPlannings/EmbeddedCoverageForm.tsx
+++ b/client/components/fields/editor/EventRelatedPlannings/EmbeddedCoverageForm.tsx
@@ -14,7 +14,7 @@ import {superdeskApi, planningApi} from '../../../../superdeskApi';
import {getDesksForUser, getUsersForDesk} from '../../../../utils';
import {Select, Option} from 'superdesk-ui-framework/react';
import * as List from '../../../UI/List';
-import {Row, SelectUserInput} from '../../../UI/Form';
+import {Row} from '../../../UI/Form';
import {EditorFieldNewsCoverageStatus} from '../NewsCoverageStatus';
import * as config from 'appConfig';
import {getLanguagesForTreeSelectInput} from '../../../../selectors/vocabs';
diff --git a/client/utils/testApi.ts b/client/utils/testApi.ts
index b9e7afcde..6e2374ab8 100644
--- a/client/utils/testApi.ts
+++ b/client/utils/testApi.ts
@@ -39,6 +39,9 @@ Object.assign(superdeskApi, {
success: sinon.stub().returns(undefined),
error: sinon.stub().returns(undefined),
}
+ },
+ components: {
+ SelectUser: sinon.stub().returns('Stubbed SelectUser Component
'),
}
});
diff --git a/e2e/cypress/support/common/inputs/userSelectInput.ts b/e2e/cypress/support/common/inputs/userSelectInput.ts
index 79db95832..510d9bf26 100644
--- a/e2e/cypress/support/common/inputs/userSelectInput.ts
+++ b/e2e/cypress/support/common/inputs/userSelectInput.ts
@@ -1,5 +1,4 @@
import {Input} from './input';
-import {Popup} from '../ui';
/**
* Wrapper class for a searchable user select input field
@@ -8,22 +7,21 @@ import {Popup} from '../ui';
export class UserSelectInput extends Input {
type(value) {
cy.log('Common.SearchableSelectInput.type');
- const popup = new Popup();
- this.element
- .find('input')
- .type(value);
+ // Click on the element to open the dropdown
+ this.element.click();
- popup.waitTillOpen();
- popup.element
- .find('li')
- .first()
- .click();
- popup.waitTillClosed();
+ // Type into the input inside the dropdown panel
+ cy.get('.p-dropdown-panel input').type(value);
+
+ // Click on the first list item in the dropdown
+ cy.get('.p-dropdown-panel li').first().click();
}
expect(value) {
cy.log('Common.SearchableSelectInput.expect');
- this.element.should('contain.text', value);
+
+ // Ensure that the dropdown panel contains the expected text
+ cy.get('.p-dropdown-panel').should('contain.text', value);
}
}