diff --git a/frontend/src/components/dialog/manage-members-dialog.js b/frontend/src/components/dialog/manage-members-dialog.js index 3669dda140..4a06826a51 100644 --- a/frontend/src/components/dialog/manage-members-dialog.js +++ b/frontend/src/components/dialog/manage-members-dialog.js @@ -1,9 +1,8 @@ -import React, { Fragment } from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; -import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; +import { Modal, ModalHeader, ModalBody } from 'reactstrap'; import { gettext } from '../../utils/constants'; import ListAndAddGroupMembers from '../list-and-add-group-members'; -import SearchGroupMembers from '../search-group-members'; import '../../css/manage-members-dialog.css'; @@ -13,55 +12,19 @@ const propTypes = { toggleManageMembersDialog: PropTypes.func.isRequired }; -const MANAGEMENT_MODE= { - LIST_AND_ADD: 'list_and_add', - SEARCH: 'search' -}; - class ManageMembersDialog extends React.Component { - constructor(props) { - super(props); - this.state = { - currentMode: MANAGEMENT_MODE.LIST_AND_ADD - }; - } - - changeMode = () => { - this.setState({ - currentMode: this.state.currentMode == MANAGEMENT_MODE.LIST_AND_ADD ? - MANAGEMENT_MODE.SEARCH : MANAGEMENT_MODE.LIST_AND_ADD - }); - } - render() { - const { currentMode } = this.state; const { groupID, isOwner, toggleManageMembersDialog: toggle } = this.props; return ( - - {currentMode == MANAGEMENT_MODE.LIST_AND_ADD ? - gettext('Manage group members') : ( - - - {gettext('Search group members')} - - ) - } - + {gettext('Manage group members')} - {currentMode == MANAGEMENT_MODE.LIST_AND_ADD ? - : - - } + - - - ); } diff --git a/frontend/src/components/list-and-add-group-members.js b/frontend/src/components/list-and-add-group-members.js index ee607f201f..36dc362346 100644 --- a/frontend/src/components/list-and-add-group-members.js +++ b/frontend/src/components/list-and-add-group-members.js @@ -1,6 +1,6 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; -import { Button } from 'reactstrap'; +import { Button, InputGroup, InputGroupText, Input } from 'reactstrap'; import { Utils } from '../utils/utils'; import { gettext } from '../utils/constants'; import { seafileAPI } from '../utils/seafile-api'; @@ -11,8 +11,7 @@ import GroupMembers from './group-members'; const propTypes = { groupID: PropTypes.string.isRequired, - isOwner: PropTypes.bool.isRequired, - changeMode: PropTypes.func.isRequired + isOwner: PropTypes.bool.isRequired }; class ManageMembersDialog extends React.Component { @@ -28,7 +27,10 @@ class ManageMembersDialog extends React.Component { hasNextPage: false, selectedOption: null, errMessage: [], - isItemFreezed: false + isItemFreezed: false, + searchActive: false, + keyword: '', + membersFound: [] }; } @@ -130,8 +132,39 @@ class ManageMembersDialog extends React.Component { }); } + searchMembers = (e) => { + const { groupMembers } = this.state; + const keyword = e.target.value; + const value = keyword.trim().toLowerCase(); + const membersFound = groupMembers.filter(item => item.name.toLowerCase().indexOf(value) > -1); + this.setState({ keyword, membersFound }); + } + + clearSearch = () => { + this.setState({ + keyword: '', + membersFound: [] + }); + } + + onSearchInputFocus = () => { + this.setState({ + searchActive: true + }); + } + + onSearchInputBlur = () => { + this.setState({ + searchActive: false + }); + } + render() { - const { isLoading, hasNextPage, groupMembers } = this.state; + const { + isLoading, hasNextPage, groupMembers, + keyword, membersFound, + searchActive + } = this.state; return (

{gettext('Add group member')}

@@ -157,16 +190,31 @@ class ManageMembersDialog extends React.Component { }) } {groupMembers.length > 10 && - + + + + + + {keyword && ( + + + + )} + } -
+
{} : this.handleScroll}> {isLoading ? : ( - {hasNextPage && } + {(!keyword.trim() && hasNextPage) && } )}
diff --git a/frontend/src/components/search-group-members.js b/frontend/src/components/search-group-members.js deleted file mode 100644 index 5ab56caa3d..0000000000 --- a/frontend/src/components/search-group-members.js +++ /dev/null @@ -1,133 +0,0 @@ -import React, { Fragment } from 'react'; -import PropTypes from 'prop-types'; -import { Input, Button } from 'reactstrap'; -import { Utils } from '../utils/utils'; -import { gettext } from '../utils/constants'; -import { seafileAPI } from '../utils/seafile-api'; -import Loading from './loading'; -import GroupMembers from './group-members'; - -const propTypes = { - groupID: PropTypes.string.isRequired, - isOwner: PropTypes.bool.isRequired -}; - -class SearchGroupMembers extends React.Component { - - // pagination is not needed - constructor(props) { - super(props); - this.state = { - isLoading: false, - q: '', // query - groupMembers: [], - errMessage: [], - isItemFreezed: false - }; - this.isInit = true; - } - - toggleItemFreezed = (isFreezed) => { - this.setState({ - isItemFreezed: isFreezed - }); - } - - changeMember = (targetMember) => { - this.setState({ - groupMembers: this.state.groupMembers.map((item) => { - if (item.email == targetMember.email) { - item = targetMember; - } - return item; - }) - }); - } - - deleteMember = (targetMember) => { - const groupMembers = this.state.groupMembers; - groupMembers.splice(groupMembers.indexOf(targetMember), 1); - this.setState({ - groupMembers: groupMembers - }); - } - - submit = () => { - let { q } = this.state; - q = q.trim(); - if (!q) { - return; - } - this.setState({ - isLoading: true - }); - seafileAPI.searchGroupMember(this.props.groupID, q).then((res) => { - this.isInit = false; - this.setState({ - isLoading: false, - groupMembers: res.data, - errorMsg: '' - }); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - this.setState({ - isLoading: false, - errorMsg: errMessage - }); - }); - } - - onInputChange = (e) => { - this.setState({ - q: e.target.value - }); - } - - onInputKeyDown = (e) => { - if (e.key == 'Enter') { - this.submit(); - } - } - - render() { - const { isLoading, q, errorMsg, groupMembers } = this.state; - return ( - -
- - -
- {errorMsg &&

{errorMsg}

} -
- {isLoading ? : ( - - {groupMembers.length === 0 && !this.isInit &&
{gettext('No members')}
} - {groupMembers.length > 0 && ( - - )} -
- )} -
-
- ); - } -} - -SearchGroupMembers.propTypes = propTypes; - -export default SearchGroupMembers; diff --git a/frontend/src/css/manage-members-dialog.css b/frontend/src/css/manage-members-dialog.css index ed05a68336..feb68f2e06 100644 --- a/frontend/src/css/manage-members-dialog.css +++ b/frontend/src/css/manage-members-dialog.css @@ -1,6 +1,7 @@ .manage-members { + min-height: 200px; max-height: 300px; - overflow-y: scroll; + overflow-y: auto; padding: 0.5rem 0; } @@ -31,18 +32,31 @@ margin-top: 10px; } -.group-manage-members-dialog .back-icon { - color: #999999; - cursor: pointer; -} - -.group-manage-members-dialog .search-group-members-btn { +.group-manage-members-dialog .search-group-members { + color: #999; font-size: 14px; font-weight: normal; background: #f1f1f1; + border: 1px solid transparent; margin: 12px 0 0; } -.group-manage-members-dialog .search-group-members-btn:hover { - background: #dbdbdb; +.group-manage-members-dialog .search-group-members.active { + background: #fff; + border-color: #ccc; +} + +.group-manage-members-dialog .search-group-members .input-group-text, +.group-manage-members-dialog .search-group-members .input-group-input { + background: transparent; + color: inherit; + border: none; +} + +.group-manage-members-dialog .search-group-members.active .input-group-input { + color: #495057; +} + +.group-manage-members-dialog .search-group-members .input-group-input:focus { + box-shadow: none; } diff --git a/media/css/seahub_react.css b/media/css/seahub_react.css index cca5be8303..d70c3b1101 100644 --- a/media/css/seahub_react.css +++ b/media/css/seahub_react.css @@ -47,6 +47,7 @@ font-family: 'seafile-font2'; speak: none; font-weight: normal; + font-style: normal; font-variant: normal; text-transform: none; -webkit-font-smoothing: antialiased;