mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-12 21:30:39 +00:00
Single selector (#5791)
* [single selector] added a new 'single selector' to replace the 'role editor' * [sys admin - group - member] replaced the old 'role selector' with the new 'single selector' * [sys admin - orgs] replaced the old 'role selector' with the new 'single selector' * [sys admin, org admin] replaced different selectors with the new 'single selector' for users & orgs * [share link perm selector] replaced it with the new 'single selector'
This commit is contained in:
@@ -4,7 +4,7 @@ import { Table } from 'reactstrap';
|
|||||||
import { Utils } from '../utils/utils';
|
import { Utils } from '../utils/utils';
|
||||||
import { gettext } from '../utils/constants';
|
import { gettext } from '../utils/constants';
|
||||||
import { seafileAPI } from '../utils/seafile-api';
|
import { seafileAPI } from '../utils/seafile-api';
|
||||||
import RoleEditor from './select-editor/role-editor';
|
import RoleSelector from './single-selector';
|
||||||
import toaster from './toast';
|
import toaster from './toast';
|
||||||
import OpIcon from './op-icon';
|
import OpIcon from './op-icon';
|
||||||
|
|
||||||
@@ -70,14 +70,17 @@ class Member extends React.PureComponent {
|
|||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.roles = ['Admin', 'Member'];
|
this.roleOptions = [
|
||||||
|
{ value: 'Admin', text: gettext('Admin'), isSelected: false },
|
||||||
|
{ value: 'Member', text: gettext('Member'), isSelected: false }
|
||||||
|
];
|
||||||
this.state = ({
|
this.state = ({
|
||||||
highlight: false,
|
highlight: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeUserRole = (role) => {
|
onChangeUserRole = (roleOption) => {
|
||||||
let isAdmin = role === 'Admin' ? 'True' : 'False';
|
let isAdmin = roleOption.value === 'Admin' ? 'True' : 'False';
|
||||||
seafileAPI.setGroupAdmin(this.props.groupID, this.props.item.email, isAdmin).then((res) => {
|
seafileAPI.setGroupAdmin(this.props.groupID, this.props.item.email, isAdmin).then((res) => {
|
||||||
this.props.changeMember(res.data);
|
this.props.changeMember(res.data);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
@@ -124,8 +127,17 @@ class Member extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { highlight } = this.state;
|
||||||
const { item, isOwner } = this.props;
|
const { item, isOwner } = this.props;
|
||||||
const deleteAuthority = (item.role !== 'Owner' && isOwner === true) || (item.role === 'Member' && isOwner === false);
|
const deleteAuthority = (item.role !== 'Owner' && isOwner === true) || (item.role === 'Member' && isOwner === false);
|
||||||
|
|
||||||
|
const { role: curRole } = item;
|
||||||
|
this.roleOptions = this.roleOptions.map(item => {
|
||||||
|
item.isSelected = item.value == curRole;
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
const currentSelectedOption = this.roleOptions.filter(item => item.isSelected)[0];
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<tr onMouseOver={this.handleMouseOver} onMouseLeave={this.handleMouseLeave} className={this.state.highlight ? 'tr-highlight' : ''} tabIndex="0" onFocus={this.handleMouseOver}>
|
<tr onMouseOver={this.handleMouseOver} onMouseLeave={this.handleMouseLeave} className={this.state.highlight ? 'tr-highlight' : ''} tabIndex="0" onFocus={this.handleMouseOver}>
|
||||||
<th scope="row"><img className="avatar" src={item.avatar_url} alt=""/></th>
|
<th scope="row"><img className="avatar" src={item.avatar_url} alt=""/></th>
|
||||||
@@ -135,12 +147,11 @@ class Member extends React.PureComponent {
|
|||||||
<span className="group-admin">{this.translateRole(item.role)}</span>
|
<span className="group-admin">{this.translateRole(item.role)}</span>
|
||||||
}
|
}
|
||||||
{(isOwner === true && item.role !== 'Owner') &&
|
{(isOwner === true && item.role !== 'Owner') &&
|
||||||
<RoleEditor
|
<RoleSelector
|
||||||
isTextMode={true}
|
isDropdownToggleShown={highlight}
|
||||||
isEditIconShow={this.state.highlight}
|
currentSelectedOption={currentSelectedOption}
|
||||||
currentRole={item.role}
|
options={this.roleOptions}
|
||||||
roles={this.roles}
|
selectOption={this.onChangeUserRole}
|
||||||
onRoleChanged={this.onChangeUserRole}
|
|
||||||
toggleItemFreezed={this.props.toggleItemFreezed}
|
toggleItemFreezed={this.props.toggleItemFreezed}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
@@ -1,44 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { gettext } from '../../utils/constants';
|
|
||||||
import SelectEditor from './select-editor';
|
|
||||||
|
|
||||||
const propTypes = {
|
|
||||||
isTextMode: PropTypes.bool.isRequired,
|
|
||||||
isEditIconShow: PropTypes.bool.isRequired,
|
|
||||||
roles: PropTypes.array.isRequired,
|
|
||||||
currentRole: PropTypes.string.isRequired,
|
|
||||||
onRoleChanged: PropTypes.func.isRequired,
|
|
||||||
toggleItemFreezed: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
class RoleEditor extends React.Component {
|
|
||||||
|
|
||||||
translateRole = (role) => {
|
|
||||||
if (role === 'Admin') {
|
|
||||||
return gettext('Admin');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (role === 'Member') {
|
|
||||||
return gettext('Member');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<SelectEditor
|
|
||||||
isTextMode={this.props.isTextMode}
|
|
||||||
isEditIconShow={this.props.isEditIconShow}
|
|
||||||
options={this.props.roles}
|
|
||||||
currentOption={this.props.currentRole}
|
|
||||||
onOptionChanged={this.props.onRoleChanged}
|
|
||||||
translateOption={this.translateRole}
|
|
||||||
toggleItemFreezed={this.props.toggleItemFreezed}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RoleEditor.propTypes = propTypes;
|
|
||||||
|
|
||||||
export default RoleEditor;
|
|
@@ -1,36 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { Utils } from '../../utils/utils';
|
|
||||||
import SelectEditor from './select-editor';
|
|
||||||
|
|
||||||
const propTypes = {
|
|
||||||
isTextMode: PropTypes.bool.isRequired,
|
|
||||||
isEditIconShow: PropTypes.bool.isRequired,
|
|
||||||
permissionOptions: PropTypes.array.isRequired,
|
|
||||||
currentPermission: PropTypes.string.isRequired,
|
|
||||||
onPermissionChanged: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
class ShareLinkPermissionEditor extends React.Component {
|
|
||||||
|
|
||||||
translatePermission = (permission) => {
|
|
||||||
return Utils.getShareLinkPermissionObject(permission).text;
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<SelectEditor
|
|
||||||
isTextMode={this.props.isTextMode}
|
|
||||||
isEditIconShow={this.props.isEditIconShow}
|
|
||||||
options={this.props.permissionOptions}
|
|
||||||
currentOption={this.props.currentPermission}
|
|
||||||
onOptionChanged={this.props.onPermissionChanged}
|
|
||||||
translateOption={this.translatePermission}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ShareLinkPermissionEditor.propTypes = propTypes;
|
|
||||||
|
|
||||||
export default ShareLinkPermissionEditor;
|
|
@@ -1,43 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { gettext } from '../../utils/constants';
|
|
||||||
import SelectEditor from './select-editor';
|
|
||||||
|
|
||||||
const propTypes = {
|
|
||||||
isTextMode: PropTypes.bool.isRequired,
|
|
||||||
isEditIconShow: PropTypes.bool.isRequired,
|
|
||||||
roleOptions: PropTypes.array.isRequired,
|
|
||||||
currentRole: PropTypes.string.isRequired,
|
|
||||||
onRoleChanged: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
class SysAdminGroupRoleEditor extends React.Component {
|
|
||||||
|
|
||||||
translateRoles = (role) => {
|
|
||||||
switch (role) {
|
|
||||||
case 'Member':
|
|
||||||
return gettext('Member');
|
|
||||||
case 'Admin':
|
|
||||||
return gettext('Admin');
|
|
||||||
default:
|
|
||||||
return role;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<SelectEditor
|
|
||||||
isTextMode={this.props.isTextMode}
|
|
||||||
isEditIconShow={this.props.isEditIconShow}
|
|
||||||
options={this.props.roleOptions}
|
|
||||||
currentOption={this.props.currentRole}
|
|
||||||
onOptionChanged={this.props.onRoleChanged}
|
|
||||||
translateOption={this.translateRoles}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SysAdminGroupRoleEditor.propTypes = propTypes;
|
|
||||||
|
|
||||||
export default SysAdminGroupRoleEditor;
|
|
@@ -1,41 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { gettext } from '../../utils/constants';
|
|
||||||
import SelectEditor from './select-editor';
|
|
||||||
|
|
||||||
const propTypes = {
|
|
||||||
isTextMode: PropTypes.bool.isRequired,
|
|
||||||
isEditIconShow: PropTypes.bool.isRequired,
|
|
||||||
statusOptions: PropTypes.array.isRequired,
|
|
||||||
currentStatus: PropTypes.string.isRequired,
|
|
||||||
onStatusChanged: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
class SysAdminUserStatusEditor extends React.Component {
|
|
||||||
|
|
||||||
translateStatus = (status) => {
|
|
||||||
switch (status) {
|
|
||||||
case 'active':
|
|
||||||
return gettext('Active');
|
|
||||||
case 'inactive':
|
|
||||||
return gettext('Inactive');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<SelectEditor
|
|
||||||
isTextMode={this.props.isTextMode}
|
|
||||||
isEditIconShow={this.props.isEditIconShow}
|
|
||||||
options={this.props.statusOptions}
|
|
||||||
currentOption={this.props.currentStatus}
|
|
||||||
onOptionChanged={this.props.onStatusChanged}
|
|
||||||
translateOption={this.translateStatus}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SysAdminUserStatusEditor.propTypes = propTypes;
|
|
||||||
|
|
||||||
export default SysAdminUserStatusEditor;
|
|
@@ -1,43 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { gettext } from '../../utils/constants';
|
|
||||||
import SelectEditor from './select-editor';
|
|
||||||
|
|
||||||
const propTypes = {
|
|
||||||
isTextMode: PropTypes.bool.isRequired,
|
|
||||||
isEditIconShow: PropTypes.bool.isRequired,
|
|
||||||
statusArray: PropTypes.array.isRequired,
|
|
||||||
currentStatus: PropTypes.string.isRequired,
|
|
||||||
onStatusChanged: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
class UserStatusEditor extends React.Component {
|
|
||||||
|
|
||||||
translateStatus = (userStatus) => {
|
|
||||||
if (userStatus === 'active') {
|
|
||||||
return gettext('Active');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userStatus === 'inactive') {
|
|
||||||
return gettext('Inactive');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<SelectEditor
|
|
||||||
isTextMode={this.props.isTextMode}
|
|
||||||
isEditIconShow={this.props.isEditIconShow}
|
|
||||||
options={this.props.statusArray}
|
|
||||||
currentOption={this.props.currentStatus}
|
|
||||||
onOptionChanged={this.props.onStatusChanged}
|
|
||||||
translateOption={this.translateStatus}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
UserStatusEditor.propTypes = propTypes;
|
|
||||||
|
|
||||||
export default UserStatusEditor;
|
|
@@ -4,7 +4,7 @@ import moment from 'moment';
|
|||||||
import copy from 'copy-to-clipboard';
|
import copy from 'copy-to-clipboard';
|
||||||
import { Button } from 'reactstrap';
|
import { Button } from 'reactstrap';
|
||||||
import { isPro, gettext, shareLinkExpireDaysMin, shareLinkExpireDaysMax, shareLinkExpireDaysDefault, canSendShareLinkEmail } from '../../utils/constants';
|
import { isPro, gettext, shareLinkExpireDaysMin, shareLinkExpireDaysMax, shareLinkExpireDaysDefault, canSendShareLinkEmail } from '../../utils/constants';
|
||||||
import ShareLinkPermissionEditor from '../../components/select-editor/share-link-permission-editor';
|
import Selector from '../../components/single-selector';
|
||||||
import CommonOperationConfirmationDialog from '../../components/dialog/common-operation-confirmation-dialog';
|
import CommonOperationConfirmationDialog from '../../components/dialog/common-operation-confirmation-dialog';
|
||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
@@ -119,9 +119,9 @@ class LinkDetails extends React.Component {
|
|||||||
this.setState({isOpIconShown: false});
|
this.setState({isOpIconShown: false});
|
||||||
};
|
};
|
||||||
|
|
||||||
changePerm = (permission) => {
|
changePerm = (permOption) => {
|
||||||
const { sharedLinkInfo } = this.props;
|
const { sharedLinkInfo } = this.props;
|
||||||
const { permissionDetails } = Utils.getShareLinkPermissionObject(permission);
|
const { permissionDetails } = Utils.getShareLinkPermissionObject(permOption.value);
|
||||||
seafileAPI.updateShareLink(sharedLinkInfo.token, JSON.stringify(permissionDetails)).then((res) => {
|
seafileAPI.updateShareLink(sharedLinkInfo.token, JSON.stringify(permissionDetails)).then((res) => {
|
||||||
this.props.updateLink(new ShareLink(res.data));
|
this.props.updateLink(new ShareLink(res.data));
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
@@ -152,6 +152,15 @@ class LinkDetails extends React.Component {
|
|||||||
const { sharedLinkInfo, permissionOptions } = this.props;
|
const { sharedLinkInfo, permissionOptions } = this.props;
|
||||||
const { isOpIconShown } = this.state;
|
const { isOpIconShown } = this.state;
|
||||||
const currentPermission = Utils.getShareLinkPermissionStr(sharedLinkInfo.permissions);
|
const currentPermission = Utils.getShareLinkPermissionStr(sharedLinkInfo.permissions);
|
||||||
|
this.permOptions = permissionOptions.map(item => {
|
||||||
|
return {
|
||||||
|
value: item,
|
||||||
|
text: Utils.getShareLinkPermissionObject(item).text,
|
||||||
|
isSelected: item == currentPermission
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const currentSelectedPermOption = this.permOptions.filter(item => item.isSelected)[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<button className="fa fa-arrow-left back-icon border-0 bg-transparent text-secondary p-0" onClick={this.goBack} title={gettext('Back')} aria-label={gettext('Back')}></button>
|
<button className="fa fa-arrow-left back-icon border-0 bg-transparent text-secondary p-0" onClick={this.goBack} title={gettext('Back')} aria-label={gettext('Back')}></button>
|
||||||
@@ -231,12 +240,11 @@ class LinkDetails extends React.Component {
|
|||||||
<>
|
<>
|
||||||
<dt className="text-secondary font-weight-normal">{gettext('Permission:')}</dt>
|
<dt className="text-secondary font-weight-normal">{gettext('Permission:')}</dt>
|
||||||
<dd style={{width:'250px'}} onMouseEnter={this.handleMouseOver} onMouseLeave={this.handleMouseOut}>
|
<dd style={{width:'250px'}} onMouseEnter={this.handleMouseOver} onMouseLeave={this.handleMouseOut}>
|
||||||
<ShareLinkPermissionEditor
|
<Selector
|
||||||
isTextMode={true}
|
isDropdownToggleShown={isOpIconShown && !sharedLinkInfo.is_expired}
|
||||||
isEditIconShow={isOpIconShown && !sharedLinkInfo.is_expired}
|
currentSelectedOption={currentSelectedPermOption}
|
||||||
currentPermission={currentPermission}
|
options={this.permOptions}
|
||||||
permissionOptions={permissionOptions}
|
selectOption={this.changePerm}
|
||||||
onPermissionChanged={this.changePerm}
|
|
||||||
/>
|
/>
|
||||||
</dd>
|
</dd>
|
||||||
</>
|
</>
|
||||||
|
@@ -4,7 +4,6 @@ import moment from 'moment';
|
|||||||
import copy from 'copy-to-clipboard';
|
import copy from 'copy-to-clipboard';
|
||||||
import toaster from '../toast';
|
import toaster from '../toast';
|
||||||
import { isPro, gettext } from '../../utils/constants';
|
import { isPro, gettext } from '../../utils/constants';
|
||||||
import ShareLinkPermissionEditor from '../../components/select-editor/share-link-permission-editor';
|
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
import CommonOperationConfirmationDialog from '../../components/dialog/common-operation-confirmation-dialog';
|
import CommonOperationConfirmationDialog from '../../components/dialog/common-operation-confirmation-dialog';
|
||||||
|
|
||||||
@@ -105,15 +104,7 @@ class LinkItem extends React.Component {
|
|||||||
{this.cutLink(link)}
|
{this.cutLink(link)}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{(isPro && permissions) && (
|
{(isPro && permissions) && Utils.getShareLinkPermissionObject(currentPermission).text}
|
||||||
<ShareLinkPermissionEditor
|
|
||||||
isTextMode={true}
|
|
||||||
isEditIconShow={false}
|
|
||||||
currentPermission={currentPermission}
|
|
||||||
permissionOptions={permissionOptions}
|
|
||||||
onPermissionChanged={() => {}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{expire_date ? moment(expire_date).format('YYYY-MM-DD HH:mm') : '--'}
|
{expire_date ? moment(expire_date).format('YYYY-MM-DD HH:mm') : '--'}
|
||||||
|
89
frontend/src/components/single-selector.js
Normal file
89
frontend/src/components/single-selector.js
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import '../css/single-selector.css';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
isDropdownToggleShown: PropTypes.bool.isRequired,
|
||||||
|
currentSelectedOption: PropTypes.object.isRequired,
|
||||||
|
options: PropTypes.array.isRequired,
|
||||||
|
selectOption: PropTypes.func.isRequired,
|
||||||
|
toggleItemFreezed: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
class Selector extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isPopoverOpen: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
document.addEventListener('click', this.handleOutsideClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
document.removeEventListener('click', this.handleOutsideClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOutsideClick = (e) => {
|
||||||
|
const { isPopoverOpen } = this.state;
|
||||||
|
if (isPopoverOpen && !this.selector.contains(e.target)) {
|
||||||
|
this.togglePopover();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
togglePopover = () => {
|
||||||
|
this.setState({
|
||||||
|
isPopoverOpen: !this.state.isPopoverOpen
|
||||||
|
}, () => {
|
||||||
|
if (this.props.toggleItemFreezed) {
|
||||||
|
this.props.toggleItemFreezed(this.state.isPopoverOpen);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onToggleClick = (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
this.togglePopover();
|
||||||
|
};
|
||||||
|
|
||||||
|
selectItem = (e, targetItem) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
this.props.selectOption(targetItem);
|
||||||
|
this.togglePopover();
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { isPopoverOpen } = this.state;
|
||||||
|
const { currentSelectedOption, options, isDropdownToggleShown } = this.props;
|
||||||
|
return (
|
||||||
|
<div className="sf-single-selector position-relative">
|
||||||
|
<span className="cur-option" onClick={this.onToggleClick}>
|
||||||
|
{currentSelectedOption.text}
|
||||||
|
{isDropdownToggleShown && <i className="fas fa-caret-down ml-2 toggle-icon"></i>}
|
||||||
|
</span>
|
||||||
|
{isPopoverOpen && (
|
||||||
|
<div className="options-container position-absolute rounded shadow mt-1" ref={ref => this.selector = ref}>
|
||||||
|
<ul className="option-list list-unstyled p-3 o-auto">
|
||||||
|
{options.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<li key={index} className="option-item h-6 p-1 rounded d-flex justify-content-between align-items-center" onClick={(e) => {this.selectItem(e, item);}}>
|
||||||
|
<span className="option-item-text flex-shrink-0 mr-3">{item.text}</span>
|
||||||
|
<i className={`sf2-icon-tick text-gray font-weight-bold ${item.isSelected ? '' : 'invisible'}`}></i>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Selector.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default Selector;
|
31
frontend/src/css/single-selector.css
Normal file
31
frontend/src/css/single-selector.css
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
.sf-single-selector .cur-option {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sf-single-selector .cur-option .toggle-icon {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sf-single-selector .options-container {
|
||||||
|
min-width: 165px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e8e8e8;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sf-single-selector .option-list {
|
||||||
|
min-height: 4rem;
|
||||||
|
max-height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sf-single-selector .option-item {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sf-single-selector .option-item:hover {
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sf-single-selector .option-item-text {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
@@ -10,6 +10,7 @@ const propTypes = {
|
|||||||
toggleDelete: PropTypes.func.isRequired,
|
toggleDelete: PropTypes.func.isRequired,
|
||||||
toggleRevokeAdmin: PropTypes.func.isRequired,
|
toggleRevokeAdmin: PropTypes.func.isRequired,
|
||||||
orgAdminUsers: PropTypes.array.isRequired,
|
orgAdminUsers: PropTypes.array.isRequired,
|
||||||
|
changeStatus: PropTypes.func.isRequired,
|
||||||
initOrgAdmin: PropTypes.func.isRequired
|
initOrgAdmin: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -34,6 +35,10 @@ class OrgAdminList extends React.Component {
|
|||||||
this.setState({isItemFreezed: false});
|
this.setState({isItemFreezed: false});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
toggleItemFreezed = (isFreezed) => {
|
||||||
|
this.setState({ isItemFreezed: isFreezed });
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let orgAdminUsers = this.props.orgAdminUsers;
|
let orgAdminUsers = this.props.orgAdminUsers;
|
||||||
|
|
||||||
@@ -50,17 +55,19 @@ class OrgAdminList extends React.Component {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{orgAdminUsers.map(item => {
|
{orgAdminUsers.map((item, index) => {
|
||||||
return (
|
return (
|
||||||
<UserItem
|
<UserItem
|
||||||
key={item.index}
|
key={index}
|
||||||
user={item}
|
user={item}
|
||||||
currentTab="admins"
|
currentTab="admins"
|
||||||
isItemFreezed={this.state.isItemFreezed}
|
isItemFreezed={this.state.isItemFreezed}
|
||||||
toggleDelete={this.props.toggleDelete}
|
toggleDelete={this.props.toggleDelete}
|
||||||
toggleRevokeAdmin={this.props.toggleRevokeAdmin}
|
toggleRevokeAdmin={this.props.toggleRevokeAdmin}
|
||||||
|
changeStatus={this.props.changeStatus}
|
||||||
onFreezedItem={this.onFreezedItem}
|
onFreezedItem={this.onFreezedItem}
|
||||||
onUnfreezedItem={this.onUnfreezedItem}
|
onUnfreezedItem={this.onUnfreezedItem}
|
||||||
|
toggleItemFreezed={this.toggleItemFreezed}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
@@ -7,7 +7,7 @@ import { Utils } from '../../utils/utils';
|
|||||||
import toaster from '../../components/toast';
|
import toaster from '../../components/toast';
|
||||||
import MainPanelTopbar from './main-panel-topbar';
|
import MainPanelTopbar from './main-panel-topbar';
|
||||||
import ModalPortal from '../../components/modal-portal';
|
import ModalPortal from '../../components/modal-portal';
|
||||||
import RoleEditor from '../../components/select-editor/role-editor';
|
import RoleSelector from '../../components/single-selector';
|
||||||
import AddDepartDialog from '../../components/dialog/org-add-department-dialog';
|
import AddDepartDialog from '../../components/dialog/org-add-department-dialog';
|
||||||
import AddMemberDialog from '../../components/dialog/org-add-member-dialog';
|
import AddMemberDialog from '../../components/dialog/org-add-member-dialog';
|
||||||
import DeleteMemberDialog from '../../components/dialog/org-delete-member-dialog';
|
import DeleteMemberDialog from '../../components/dialog/org-delete-member-dialog';
|
||||||
@@ -396,10 +396,12 @@ class MemberItem extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
highlight: false,
|
highlight: false
|
||||||
showRoleMenu: false,
|
|
||||||
};
|
};
|
||||||
this.roles = ['Admin', 'Member'];
|
this.roleOptions = [
|
||||||
|
{ value: 'Admin', text: gettext('Admin'), isSelected: false },
|
||||||
|
{ value: 'Member', text: gettext('Member'), isSelected: false }
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseEnter = () => {
|
onMouseEnter = () => {
|
||||||
@@ -412,12 +414,8 @@ class MemberItem extends React.Component {
|
|||||||
this.setState({ highlight: false });
|
this.setState({ highlight: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleMemberRoleMenu = () => {
|
onChangeUserRole = (roleOption) => {
|
||||||
this.setState({ showRoleMenu: !this.state.showRoleMenu });
|
let isAdmin = roleOption.value === 'Admin' ? true : false;
|
||||||
};
|
|
||||||
|
|
||||||
onChangeUserRole = (role) => {
|
|
||||||
let isAdmin = role === 'Admin' ? true : false;
|
|
||||||
seafileAPI.orgAdminSetGroupMemberRole(orgID, this.props.groupID, this.props.member.email, isAdmin).then((res) => {
|
seafileAPI.orgAdminSetGroupMemberRole(orgID, this.props.groupID, this.props.member.email, isAdmin).then((res) => {
|
||||||
this.props.onMemberChanged();
|
this.props.onMemberChanged();
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
@@ -434,25 +432,29 @@ class MemberItem extends React.Component {
|
|||||||
const highlight = this.state.highlight;
|
const highlight = this.state.highlight;
|
||||||
let memberLink = serviceURL + '/org/useradmin/info/' + member.email + '/';
|
let memberLink = serviceURL + '/org/useradmin/info/' + member.email + '/';
|
||||||
if (member.role === 'Owner') return null;
|
if (member.role === 'Owner') return null;
|
||||||
|
|
||||||
|
this.roleOptions = this.roleOptions.map(item => {
|
||||||
|
item.isSelected = item.value == member.role;
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
const currentSelectedOption = this.roleOptions.filter(item => item.isSelected)[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr className={highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
<tr className={highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
||||||
<td><img src={member.avatar_url} alt="member-header" width="24" className="avatar"/></td>
|
<td><img src={member.avatar_url} alt="member-header" width="24" className="avatar"/></td>
|
||||||
<td><a href={memberLink}>{member.name}</a></td>
|
<td><a href={memberLink}>{member.name}</a></td>
|
||||||
<td>
|
<td>
|
||||||
<RoleEditor
|
<RoleSelector
|
||||||
isTextMode={true}
|
isDropdownToggleShown={highlight}
|
||||||
isEditIconShow={highlight}
|
currentSelectedOption={currentSelectedOption}
|
||||||
currentRole={member.role}
|
options={this.roleOptions}
|
||||||
roles={this.roles}
|
selectOption={this.onChangeUserRole}
|
||||||
onRoleChanged={this.onChangeUserRole}
|
|
||||||
toggleItemFreezed={this.props.toggleItemFreezed}
|
toggleItemFreezed={this.props.toggleItemFreezed}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
{!this.props.isItemFreezed ?
|
|
||||||
<td className="cursor-pointer text-center" onClick={this.props.showDeleteMemberDialog.bind(this, member)}>
|
<td className="cursor-pointer text-center" onClick={this.props.showDeleteMemberDialog.bind(this, member)}>
|
||||||
<span className={`sf2-icon-x3 action-icon ${highlight ? '' : 'vh'}`} title="Delete"></span>
|
<span className={`sf2-icon-x3 action-icon ${highlight ? '' : 'vh'}`} title="Delete"></span>
|
||||||
</td> : <td></td>
|
</td>
|
||||||
}
|
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,7 @@ import { gettext, siteRoot, orgID, username } from '../../utils/constants';
|
|||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
import toaster from '../../components/toast';
|
import toaster from '../../components/toast';
|
||||||
import UserStatusEditor from '../../components/select-editor/user-status-editor';
|
import Selector from '../../components/single-selector';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
user: PropTypes.object,
|
user: PropTypes.object,
|
||||||
@@ -15,6 +15,7 @@ const propTypes = {
|
|||||||
toggleDelete: PropTypes.func.isRequired,
|
toggleDelete: PropTypes.func.isRequired,
|
||||||
onFreezedItem: PropTypes.func.isRequired,
|
onFreezedItem: PropTypes.func.isRequired,
|
||||||
onUnfreezedItem: PropTypes.func.isRequired,
|
onUnfreezedItem: PropTypes.func.isRequired,
|
||||||
|
toggleItemFreezed: PropTypes.func.isRequired,
|
||||||
changeStatus: PropTypes.func.isRequired,
|
changeStatus: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -25,11 +26,8 @@ class UserItem extends React.Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
highlight: false,
|
highlight: false,
|
||||||
showMenu: false,
|
showMenu: false,
|
||||||
currentStatus: this.props.user.is_active ? 'active' : 'inactive',
|
|
||||||
isItemMenuShow: false
|
isItemMenuShow: false
|
||||||
};
|
};
|
||||||
|
|
||||||
this.statusArray = ['active', 'inactive'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseEnter = () => {
|
onMouseEnter = () => {
|
||||||
@@ -78,8 +76,8 @@ class UserItem extends React.Component {
|
|||||||
this.props.toggleRevokeAdmin(email);
|
this.props.toggleRevokeAdmin(email);
|
||||||
};
|
};
|
||||||
|
|
||||||
changeStatus = (value) => {
|
changeStatus = (statusOption) => {
|
||||||
const isActive = value == 'active';
|
const isActive = statusOption.value == 'active';
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
toaster.notify(gettext('It may take some time, please wait.'));
|
toaster.notify(gettext('It may take some time, please wait.'));
|
||||||
}
|
}
|
||||||
@@ -119,23 +117,44 @@ class UserItem extends React.Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
translateStatus = (status) => {
|
||||||
|
switch (status) {
|
||||||
|
case 'active':
|
||||||
|
return gettext('Active');
|
||||||
|
case 'inactive':
|
||||||
|
return gettext('Inactive');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { highlight } = this.state;
|
||||||
let { user, currentTab } = this.props;
|
let { user, currentTab } = this.props;
|
||||||
let href = siteRoot + 'org/useradmin/info/' + encodeURIComponent(user.email) + '/';
|
let href = siteRoot + 'org/useradmin/info/' + encodeURIComponent(user.email) + '/';
|
||||||
let isOperationMenuShow = (user.email !== username) && this.state.showMenu;
|
let isOperationMenuShow = (user.email !== username) && this.state.showMenu;
|
||||||
let isEditIconShow = isOperationMenuShow;
|
|
||||||
|
// for 'user status'
|
||||||
|
const curStatus = user.is_active ? 'active' : 'inactive';
|
||||||
|
this.statusOptions = ['active', 'inactive'].map(item => {
|
||||||
|
return {
|
||||||
|
value: item,
|
||||||
|
text: this.translateStatus(item),
|
||||||
|
isSelected: item == curStatus
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const currentSelectedStatusOption = this.statusOptions.filter(item => item.isSelected)[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
||||||
<td>
|
<td>
|
||||||
<a href={href}>{user.name}</a>
|
<a href={href}>{user.name}</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<UserStatusEditor
|
<Selector
|
||||||
isTextMode={true}
|
isDropdownToggleShown={highlight}
|
||||||
isEditIconShow={isEditIconShow}
|
currentSelectedOption={currentSelectedStatusOption}
|
||||||
currentStatus={user.is_active ? 'active' : 'inactive'}
|
options={this.statusOptions}
|
||||||
statusArray={this.statusArray}
|
selectOption={this.changeStatus}
|
||||||
onStatusChanged={this.changeStatus}
|
toggleItemFreezed={this.props.toggleItemFreezed}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>{`${Utils.formatSize({bytes: user.quota_usage})} / ${this.getQuotaTotal(user.quota_total)}`}</td>
|
<td>{`${Utils.formatSize({bytes: user.quota_usage})} / ${this.getQuotaTotal(user.quota_total)}`}</td>
|
||||||
|
@@ -75,6 +75,22 @@ class OrgUsers extends Component {
|
|||||||
this.toggleAddOrgAdmin();
|
this.toggleAddOrgAdmin();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
changeStatus = (email, isActive) => {
|
||||||
|
seafileAPI.orgAdminChangeOrgUserStatus(orgID, email, isActive).then(res => {
|
||||||
|
let users = this.state.orgAdminUsers.map(item => {
|
||||||
|
if (item.email == email) {
|
||||||
|
item['is_active']= res.data['is_active'];
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
this.setState({orgAdminUsers: users});
|
||||||
|
toaster.success(gettext('Edit succeeded.'));
|
||||||
|
}).catch(error => {
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const topBtn = 'btn btn-secondary operation-item';
|
const topBtn = 'btn btn-secondary operation-item';
|
||||||
let topbarChildren;
|
let topbarChildren;
|
||||||
@@ -103,6 +119,7 @@ class OrgUsers extends Component {
|
|||||||
toggleRevokeAdmin={this.toggleRevokeAdmin}
|
toggleRevokeAdmin={this.toggleRevokeAdmin}
|
||||||
orgAdminUsers={this.state.orgAdminUsers}
|
orgAdminUsers={this.state.orgAdminUsers}
|
||||||
initOrgAdmin={this.initOrgAdmin}
|
initOrgAdmin={this.initOrgAdmin}
|
||||||
|
changeStatus={this.changeStatus}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -10,7 +10,7 @@ const propTypes = {
|
|||||||
orgUsers: PropTypes.array.isRequired,
|
orgUsers: PropTypes.array.isRequired,
|
||||||
page: PropTypes.number.isRequired,
|
page: PropTypes.number.isRequired,
|
||||||
pageNext: PropTypes.bool.isRequired,
|
pageNext: PropTypes.bool.isRequired,
|
||||||
sortByQuotaUsage: PropTypes.string.isRequired,
|
sortByQuotaUsage: PropTypes.func.isRequired,
|
||||||
sortOrder: PropTypes.string.isRequired,
|
sortOrder: PropTypes.string.isRequired,
|
||||||
sortBy: PropTypes.string.isRequired,
|
sortBy: PropTypes.string.isRequired,
|
||||||
};
|
};
|
||||||
@@ -32,6 +32,10 @@ class OrgUsersList extends React.Component {
|
|||||||
this.setState({isItemFreezed: false});
|
this.setState({isItemFreezed: false});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
toggleItemFreezed = (isFreezed) => {
|
||||||
|
this.setState({ isItemFreezed: isFreezed });
|
||||||
|
};
|
||||||
|
|
||||||
onChangePageNum = (e, num) => {
|
onChangePageNum = (e, num) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let page = this.props.page;
|
let page = this.props.page;
|
||||||
@@ -86,6 +90,7 @@ class OrgUsersList extends React.Component {
|
|||||||
changeStatus={this.props.changeStatus}
|
changeStatus={this.props.changeStatus}
|
||||||
onFreezedItem={this.onFreezedItem}
|
onFreezedItem={this.onFreezedItem}
|
||||||
onUnfreezedItem={this.onUnfreezedItem}
|
onUnfreezedItem={this.onUnfreezedItem}
|
||||||
|
toggleItemFreezed={this.toggleItemFreezed}
|
||||||
/>
|
/>
|
||||||
);})}
|
);})}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@@ -7,7 +7,6 @@ import { seafileAPI } from '../../utils/seafile-api';
|
|||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
import { isPro, gettext, siteRoot, canGenerateUploadLink } from '../../utils/constants';
|
import { isPro, gettext, siteRoot, canGenerateUploadLink } from '../../utils/constants';
|
||||||
import ShareLink from '../../models/share-link';
|
import ShareLink from '../../models/share-link';
|
||||||
import ShareLinkPermissionEditor from '../../components/select-editor/share-link-permission-editor';
|
|
||||||
import Loading from '../../components/loading';
|
import Loading from '../../components/loading';
|
||||||
import toaster from '../../components/toast';
|
import toaster from '../../components/toast';
|
||||||
import EmptyTip from '../../components/empty-tip';
|
import EmptyTip from '../../components/empty-tip';
|
||||||
@@ -16,6 +15,7 @@ import ShareAdminLink from '../../components/dialog/share-admin-link';
|
|||||||
import SortOptionsDialog from '../../components/dialog/sort-options';
|
import SortOptionsDialog from '../../components/dialog/sort-options';
|
||||||
import CommonOperationConfirmationDialog from '../../components/dialog/common-operation-confirmation-dialog';
|
import CommonOperationConfirmationDialog from '../../components/dialog/common-operation-confirmation-dialog';
|
||||||
import TopToolbar from '../../components/toolbar/top-toolbar';
|
import TopToolbar from '../../components/toolbar/top-toolbar';
|
||||||
|
import Selector from '../../components/single-selector';
|
||||||
|
|
||||||
const contentPropTypes = {
|
const contentPropTypes = {
|
||||||
loading: PropTypes.bool.isRequired,
|
loading: PropTypes.bool.isRequired,
|
||||||
@@ -29,6 +29,17 @@ const contentPropTypes = {
|
|||||||
|
|
||||||
class Content extends Component {
|
class Content extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isItemFreezed: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleItemFreezed = (isFreezed) => {
|
||||||
|
this.setState({ isItemFreezed: isFreezed });
|
||||||
|
};
|
||||||
|
|
||||||
sortByName = (e) => {
|
sortByName = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const sortBy = 'name';
|
const sortBy = 'name';
|
||||||
@@ -67,7 +78,7 @@ class Content extends Component {
|
|||||||
// only for some columns
|
// only for some columns
|
||||||
const columnWidths = isPro ? ['14%', '7%', '14%'] : ['21%', '14%', '20%'];
|
const columnWidths = isPro ? ['14%', '7%', '14%'] : ['21%', '14%', '20%'];
|
||||||
const table = (
|
const table = (
|
||||||
<table className={`table-hover ${isDesktop ? '': 'table-thead-hidden'}`}>
|
<table className={`${isDesktop ? '': 'table-thead-hidden'}`}>
|
||||||
<thead>
|
<thead>
|
||||||
{isDesktop ? (
|
{isDesktop ? (
|
||||||
<tr>
|
<tr>
|
||||||
@@ -89,7 +100,15 @@ class Content extends Component {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{items.map((item, index) => {
|
{items.map((item, index) => {
|
||||||
return (<Item key={index} isDesktop={isDesktop} item={item} onRemoveLink={this.props.onRemoveLink} />);
|
return (<Item
|
||||||
|
key={index}
|
||||||
|
isDesktop={isDesktop}
|
||||||
|
item={item}
|
||||||
|
onRemoveLink={this.props.onRemoveLink}
|
||||||
|
isItemFreezed={this.state.isItemFreezed}
|
||||||
|
toggleItemFreezed={this.toggleItemFreezed}
|
||||||
|
/>
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -105,7 +124,9 @@ Content.propTypes = contentPropTypes;
|
|||||||
const itemPropTypes = {
|
const itemPropTypes = {
|
||||||
item: PropTypes.object.isRequired,
|
item: PropTypes.object.isRequired,
|
||||||
isDesktop: PropTypes.bool.isRequired,
|
isDesktop: PropTypes.bool.isRequired,
|
||||||
onRemoveLink: PropTypes.func.isRequired
|
onRemoveLink: PropTypes.func.isRequired,
|
||||||
|
isItemFreezed: PropTypes.bool.isRequired,
|
||||||
|
toggleItemFreezed: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
class Item extends Component {
|
class Item extends Component {
|
||||||
@@ -114,6 +135,7 @@ class Item extends Component {
|
|||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
highlight: false,
|
||||||
isOpIconShown: false,
|
isOpIconShown: false,
|
||||||
isOpMenuOpen: false, // for mobile
|
isOpMenuOpen: false, // for mobile
|
||||||
isPermSelectDialogOpen: false, // for mobile
|
isPermSelectDialogOpen: false, // for mobile
|
||||||
@@ -159,12 +181,22 @@ class Item extends Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
handleMouseOver = () => {
|
handleMouseEnter = () => {
|
||||||
this.setState({isOpIconShown: true});
|
if (!this.props.isItemFreezed) {
|
||||||
|
this.setState({
|
||||||
|
isOpIconShown: true,
|
||||||
|
highlight: true
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleMouseOut = () => {
|
handleMouseLeave = () => {
|
||||||
this.setState({isOpIconShown: false});
|
if (!this.props.isItemFreezed) {
|
||||||
|
this.setState({
|
||||||
|
isOpIconShown: false,
|
||||||
|
highlight: false
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
viewLink = (e) => {
|
viewLink = (e) => {
|
||||||
@@ -187,6 +219,11 @@ class Item extends Component {
|
|||||||
return (<span className={item.is_expired ? 'error' : ''} title={expire_time}>{expire_date}</span>);
|
return (<span className={item.is_expired ? 'error' : ''} title={expire_time}>{expire_date}</span>);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// for 'selector' in desktop
|
||||||
|
changePermission = (permOption) => {
|
||||||
|
this.changePerm(permOption.value);
|
||||||
|
};
|
||||||
|
|
||||||
changePerm = (permission) => {
|
changePerm = (permission) => {
|
||||||
const item = this.props.item;
|
const item = this.props.item;
|
||||||
const permissionDetails = Utils.getShareLinkPermissionObject(permission).permissionDetails;
|
const permissionDetails = Utils.getShareLinkPermissionObject(permission).permissionDetails;
|
||||||
@@ -205,6 +242,14 @@ class Item extends Component {
|
|||||||
render() {
|
render() {
|
||||||
const item = this.props.item;
|
const item = this.props.item;
|
||||||
const { currentPermission, permissionOptions , isOpIconShown, isPermSelectDialogOpen, isLinkDialogOpen } = this.state;
|
const { currentPermission, permissionOptions , isOpIconShown, isPermSelectDialogOpen, isLinkDialogOpen } = this.state;
|
||||||
|
this.permOptions = permissionOptions.map(item => {
|
||||||
|
return {
|
||||||
|
value: item,
|
||||||
|
text: Utils.getShareLinkPermissionObject(item).text,
|
||||||
|
isSelected: item == currentPermission
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const currentSelectedPermOption = this.permOptions.filter(item => item.isSelected)[0] || {};
|
||||||
|
|
||||||
let iconUrl, objUrl;
|
let iconUrl, objUrl;
|
||||||
if (item.is_dir) {
|
if (item.is_dir) {
|
||||||
@@ -218,7 +263,7 @@ class Item extends Component {
|
|||||||
|
|
||||||
const deletedTip = item.obj_id === '' ? <span style={{color:'red'}}>{gettext('(deleted)')}</span> : null;
|
const deletedTip = item.obj_id === '' ? <span style={{color:'red'}}>{gettext('(deleted)')}</span> : null;
|
||||||
const desktopItem = (
|
const desktopItem = (
|
||||||
<tr onMouseEnter={this.handleMouseOver} onMouseLeave={this.handleMouseOut} onFocus={this.handleMouseOver}>
|
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} onFocus={this.handleMouseEnter}>
|
||||||
<td><img src={iconUrl} width="24" alt="" /></td>
|
<td><img src={iconUrl} width="24" alt="" /></td>
|
||||||
<td>
|
<td>
|
||||||
{item.is_dir ?
|
{item.is_dir ?
|
||||||
@@ -230,12 +275,12 @@ class Item extends Component {
|
|||||||
<td><Link to={`${siteRoot}library/${item.repo_id}/${encodeURIComponent(item.repo_name)}/`}>{item.repo_name}</Link></td>
|
<td><Link to={`${siteRoot}library/${item.repo_id}/${encodeURIComponent(item.repo_name)}/`}>{item.repo_name}</Link></td>
|
||||||
{isPro &&
|
{isPro &&
|
||||||
<td>
|
<td>
|
||||||
<ShareLinkPermissionEditor
|
<Selector
|
||||||
isTextMode={true}
|
isDropdownToggleShown={isOpIconShown && !item.is_expired}
|
||||||
isEditIconShow={isOpIconShown && !item.is_expired}
|
currentSelectedOption={currentSelectedPermOption}
|
||||||
currentPermission={currentPermission}
|
options={this.permOptions}
|
||||||
permissionOptions={permissionOptions}
|
selectOption={this.changePermission}
|
||||||
onPermissionChanged={this.changePerm}
|
toggleItemFreezed={this.props.toggleItemFreezed}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
}
|
}
|
||||||
|
@@ -2,8 +2,9 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { seafileAPI } from '../../../utils/seafile-api';
|
import { seafileAPI } from '../../../utils/seafile-api';
|
||||||
import { Utils } from '../../../utils/utils';
|
import { Utils } from '../../../utils/utils';
|
||||||
|
import { gettext } from '../../../utils/constants';
|
||||||
import toaster from '../../../components/toast';
|
import toaster from '../../../components/toast';
|
||||||
import RoleEditor from '../../../components/select-editor/role-editor';
|
import RoleSelector from '../../../components/single-selector';
|
||||||
import UserLink from '../user-link';
|
import UserLink from '../user-link';
|
||||||
|
|
||||||
const MemberItemPropTypes = {
|
const MemberItemPropTypes = {
|
||||||
@@ -20,10 +21,12 @@ class MemberItem extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
highlight: false,
|
highlight: false
|
||||||
showRoleMenu: false,
|
|
||||||
};
|
};
|
||||||
this.roles = ['Admin', 'Member'];
|
this.roleOptions = [
|
||||||
|
{ value: 'Admin', text: gettext('Admin'), isSelected: false },
|
||||||
|
{ value: 'Member', text: gettext('Member'), isSelected: false }
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseEnter = () => {
|
onMouseEnter = () => {
|
||||||
@@ -36,12 +39,8 @@ class MemberItem extends React.Component {
|
|||||||
this.setState({ highlight: false });
|
this.setState({ highlight: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleMemberRoleMenu = () => {
|
onChangeUserRole = (roleOption) => {
|
||||||
this.setState({ showRoleMenu: !this.state.showRoleMenu });
|
let isAdmin = roleOption.value === 'Admin' ? true : false;
|
||||||
};
|
|
||||||
|
|
||||||
onChangeUserRole = (role) => {
|
|
||||||
let isAdmin = role === 'Admin' ? true : false;
|
|
||||||
seafileAPI.sysAdminUpdateGroupMemberRole(this.props.groupID, this.props.member.email, isAdmin).then((res) => {
|
seafileAPI.sysAdminUpdateGroupMemberRole(this.props.groupID, this.props.member.email, isAdmin).then((res) => {
|
||||||
this.props.onMemberChanged();
|
this.props.onMemberChanged();
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
@@ -57,25 +56,27 @@ class MemberItem extends React.Component {
|
|||||||
const member = this.props.member;
|
const member = this.props.member;
|
||||||
const highlight = this.state.highlight;
|
const highlight = this.state.highlight;
|
||||||
if (member.role === 'Owner') return null;
|
if (member.role === 'Owner') return null;
|
||||||
|
this.roleOptions = this.roleOptions.map(item => {
|
||||||
|
item.isSelected = item.value == member.role;
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
const currentSelectedOption = this.roleOptions.filter(item => item.isSelected)[0];
|
||||||
return (
|
return (
|
||||||
<tr className={highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
<tr className={highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
||||||
<td><img src={member.avatar_url} alt="member-header" width="24" className="avatar"/></td>
|
<td><img src={member.avatar_url} alt="member-header" width="24" className="avatar"/></td>
|
||||||
<td><UserLink email={member.email} name={member.name} /></td>
|
<td><UserLink email={member.email} name={member.name} /></td>
|
||||||
<td>
|
<td>
|
||||||
<RoleEditor
|
<RoleSelector
|
||||||
isTextMode={true}
|
isDropdownToggleShown={highlight}
|
||||||
isEditIconShow={highlight}
|
currentSelectedOption={currentSelectedOption}
|
||||||
currentRole={member.role}
|
options={this.roleOptions}
|
||||||
roles={this.roles}
|
selectOption={this.onChangeUserRole}
|
||||||
onRoleChanged={this.onChangeUserRole}
|
|
||||||
toggleItemFreezed={this.props.toggleItemFreezed}
|
toggleItemFreezed={this.props.toggleItemFreezed}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
{!this.props.isItemFreezed ?
|
|
||||||
<td className="cursor-pointer text-center" onClick={this.props.showDeleteMemberDialog.bind(this, member)}>
|
<td className="cursor-pointer text-center" onClick={this.props.showDeleteMemberDialog.bind(this, member)}>
|
||||||
<span className={`sf2-icon-x3 action-icon ${highlight ? '' : 'vh'}`} title="Delete"></span>
|
<span className={`sf2-icon-x3 action-icon ${highlight ? '' : 'vh'}`} title="Delete"></span>
|
||||||
</td> : <td></td>
|
</td>
|
||||||
}
|
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@ import Loading from '../../../components/loading';
|
|||||||
import Paginator from '../../../components/paginator';
|
import Paginator from '../../../components/paginator';
|
||||||
import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog';
|
import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog';
|
||||||
import SysAdminGroupAddMemberDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-group-add-member-dialog';
|
import SysAdminGroupAddMemberDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-group-add-member-dialog';
|
||||||
import SysAdminGroupRoleEditor from '../../../components/select-editor/sysadmin-group-role-editor';
|
import RoleSelector from '../../../components/single-selector';
|
||||||
import MainPanelTopbar from '../main-panel-topbar';
|
import MainPanelTopbar from '../main-panel-topbar';
|
||||||
import UserLink from '../user-link';
|
import UserLink from '../user-link';
|
||||||
import GroupNav from './group-nav';
|
import GroupNav from './group-nav';
|
||||||
@@ -19,8 +19,15 @@ class Content extends Component {
|
|||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isItemFreezed: false
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleItemFreezed = (isFreezed) => {
|
||||||
|
this.setState({ isItemFreezed: isFreezed });
|
||||||
|
};
|
||||||
|
|
||||||
getPreviousPageList = () => {
|
getPreviousPageList = () => {
|
||||||
this.props.getListByPage(this.props.pageInfo.current_page - 1);
|
this.props.getListByPage(this.props.pageInfo.current_page - 1);
|
||||||
};
|
};
|
||||||
@@ -43,7 +50,7 @@ class Content extends Component {
|
|||||||
);
|
);
|
||||||
const table = (
|
const table = (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<table className="table-hover">
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th width="5%">{/* icon */}</th>
|
<th width="5%">{/* icon */}</th>
|
||||||
@@ -57,6 +64,8 @@ class Content extends Component {
|
|||||||
return (<Item
|
return (<Item
|
||||||
key={index}
|
key={index}
|
||||||
item={item}
|
item={item}
|
||||||
|
isItemFreezed={this.state.isItemFreezed}
|
||||||
|
toggleItemFreezed={this.toggleItemFreezed}
|
||||||
removeMember={this.props.removeMember}
|
removeMember={this.props.removeMember}
|
||||||
updateMemberRole={this.props.updateMemberRole}
|
updateMemberRole={this.props.updateMemberRole}
|
||||||
/>);
|
/>);
|
||||||
@@ -96,18 +105,24 @@ class Item extends Component {
|
|||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
this.roleOptions = [
|
||||||
|
{ value: 'Admin', text: gettext('Admin'), isSelected: false },
|
||||||
|
{ value: 'Member', text: gettext('Member'), isSelected: false }
|
||||||
|
];
|
||||||
this.state = {
|
this.state = {
|
||||||
isOpIconShown: false,
|
highlighted: false,
|
||||||
isDeleteDialogOpen: false
|
isDeleteDialogOpen: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseEnter = () => {
|
handleMouseEnter = () => {
|
||||||
this.setState({isOpIconShown: true});
|
if (this.props.isItemFreezed) return;
|
||||||
|
this.setState({highlighted: true});
|
||||||
};
|
};
|
||||||
|
|
||||||
handleMouseLeave = () => {
|
handleMouseLeave = () => {
|
||||||
this.setState({isOpIconShown: false});
|
if (this.props.isItemFreezed) return;
|
||||||
|
this.setState({highlighted: false});
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleDeleteDialog = (e) => {
|
toggleDeleteDialog = (e) => {
|
||||||
@@ -123,37 +138,44 @@ class Item extends Component {
|
|||||||
this.toggleDeleteDialog();
|
this.toggleDeleteDialog();
|
||||||
};
|
};
|
||||||
|
|
||||||
updateMemberRole = (role) => {
|
updateMemberRole = (roleOption) => {
|
||||||
this.props.updateMemberRole(this.props.item.email, role);
|
this.props.updateMemberRole(this.props.item.email, roleOption.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { isOpIconShown, isDeleteDialogOpen } = this.state;
|
let { highlighted, isDeleteDialogOpen } = this.state;
|
||||||
let { item } = this.props;
|
let { item } = this.props;
|
||||||
|
|
||||||
let itemName = '<span class="op-target">' + Utils.HTMLescape(item.name) + '</span>';
|
let itemName = '<span class="op-target">' + Utils.HTMLescape(item.name) + '</span>';
|
||||||
let dialogMsg = gettext('Are you sure you want to remove {placeholder} ?').replace('{placeholder}', itemName);
|
let dialogMsg = gettext('Are you sure you want to remove {placeholder} ?').replace('{placeholder}', itemName);
|
||||||
|
|
||||||
|
const { role: curRole } = item;
|
||||||
|
this.roleOptions = this.roleOptions.map(item => {
|
||||||
|
item.isSelected = item.value == curRole;
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
const currentSelectedOption = this.roleOptions.filter(item => item.isSelected)[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<tr onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
<tr className={highlighted ? 'tr-highlight' : ''} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
||||||
<td><img src={item.avatar_url} alt="" className="rounded-circle" width="24" /></td>
|
<td><img src={item.avatar_url} alt="" className="rounded-circle" width="24" /></td>
|
||||||
<td><UserLink email={item.email} name={item.name} /></td>
|
<td><UserLink email={item.email} name={item.name} /></td>
|
||||||
<td>
|
<td>
|
||||||
{item.role == 'Owner' ?
|
{item.role == 'Owner' ?
|
||||||
gettext('Owner') :
|
gettext('Owner') :
|
||||||
<SysAdminGroupRoleEditor
|
<RoleSelector
|
||||||
isTextMode={true}
|
isDropdownToggleShown={highlighted}
|
||||||
isEditIconShow={isOpIconShown}
|
currentSelectedOption={currentSelectedOption}
|
||||||
roleOptions={['Member', 'Admin']}
|
options={this.roleOptions}
|
||||||
currentRole={item.role}
|
selectOption={this.updateMemberRole}
|
||||||
onRoleChanged={this.updateMemberRole}
|
toggleItemFreezed={this.props.toggleItemFreezed}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{item.role != 'Owner' &&
|
{item.role != 'Owner' &&
|
||||||
<a href="#" className={`action-icon sf2-icon-x3 ${isOpIconShown ? '' : 'invisible'}`} title={gettext('Remove')} onClick={this.toggleDeleteDialog}></a>
|
<a href="#" className={`action-icon sf2-icon-x3 ${highlighted ? '' : 'invisible'}`} title={gettext('Remove')} onClick={this.toggleDeleteDialog}></a>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -175,6 +197,8 @@ Item.propTypes = {
|
|||||||
item: PropTypes.object.isRequired,
|
item: PropTypes.object.isRequired,
|
||||||
removeMember: PropTypes.func.isRequired,
|
removeMember: PropTypes.func.isRequired,
|
||||||
updateMemberRole: PropTypes.func.isRequired,
|
updateMemberRole: PropTypes.func.isRequired,
|
||||||
|
isItemFreezed: PropTypes.bool.isRequired,
|
||||||
|
toggleItemFreezed: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
class GroupMembers extends Component {
|
class GroupMembers extends Component {
|
||||||
|
@@ -8,7 +8,7 @@ import { gettext, username } from '../../../utils/constants';
|
|||||||
import toaster from '../../../components/toast';
|
import toaster from '../../../components/toast';
|
||||||
import EmptyTip from '../../../components/empty-tip';
|
import EmptyTip from '../../../components/empty-tip';
|
||||||
import Loading from '../../../components/loading';
|
import Loading from '../../../components/loading';
|
||||||
import SysAdminUserStatusEditor from '../../../components/select-editor/sysadmin-user-status-editor';
|
import Selector from '../../../components/single-selector';
|
||||||
import SysAdminUserMembershipEditor from '../../../components/select-editor/sysadmin-user-membership-editor';
|
import SysAdminUserMembershipEditor from '../../../components/select-editor/sysadmin-user-membership-editor';
|
||||||
import SysAdminAddUserDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-add-user-dialog';
|
import SysAdminAddUserDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-add-user-dialog';
|
||||||
import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog';
|
import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog';
|
||||||
@@ -26,6 +26,10 @@ class Content extends Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleItemFreezed = (isFreezed) => {
|
||||||
|
this.setState({ isItemFreezed: isFreezed });
|
||||||
|
};
|
||||||
|
|
||||||
onFreezedItem = () => {
|
onFreezedItem = () => {
|
||||||
this.setState({isItemFreezed: true});
|
this.setState({isItemFreezed: true});
|
||||||
};
|
};
|
||||||
@@ -67,6 +71,7 @@ class Content extends Component {
|
|||||||
isItemFreezed={this.state.isItemFreezed}
|
isItemFreezed={this.state.isItemFreezed}
|
||||||
onFreezedItem={this.onFreezedItem}
|
onFreezedItem={this.onFreezedItem}
|
||||||
onUnfreezedItem={this.onUnfreezedItem}
|
onUnfreezedItem={this.onUnfreezedItem}
|
||||||
|
toggleItemFreezed={this.toggleItemFreezed}
|
||||||
updateStatus={this.props.updateStatus}
|
updateStatus={this.props.updateStatus}
|
||||||
updateMembership={this.props.updateMembership}
|
updateMembership={this.props.updateMembership}
|
||||||
deleteUser={this.props.deleteUser}
|
deleteUser={this.props.deleteUser}
|
||||||
@@ -154,8 +159,8 @@ class Item extends Component {
|
|||||||
this.setState({isResetPasswordDialogOpen: !this.state.isResetPasswordDialogOpen});
|
this.setState({isResetPasswordDialogOpen: !this.state.isResetPasswordDialogOpen});
|
||||||
};
|
};
|
||||||
|
|
||||||
updateStatus= (statusValue) => {
|
updateStatus= (statusOption) => {
|
||||||
this.props.updateStatus(this.props.item.email, statusValue);
|
this.props.updateStatus(this.props.item.email, statusOption.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
updateMembership= (membershipValue) => {
|
updateMembership= (membershipValue) => {
|
||||||
@@ -190,25 +195,45 @@ class Item extends Component {
|
|||||||
return translateResult;
|
return translateResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
translateStatus = (status) => {
|
||||||
|
switch (status) {
|
||||||
|
case 'active':
|
||||||
|
return gettext('Active');
|
||||||
|
case 'inactive':
|
||||||
|
return gettext('Inactive');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { item } = this.props;
|
const { item } = this.props;
|
||||||
const { isOpIconShown, isDeleteDialogOpen, isResetPasswordDialogOpen } = this.state;
|
const { highlight, isOpIconShown, isDeleteDialogOpen, isResetPasswordDialogOpen } = this.state;
|
||||||
|
|
||||||
const itemName = '<span class="op-target">' + Utils.HTMLescape(item.name) + '</span>';
|
const itemName = '<span class="op-target">' + Utils.HTMLescape(item.name) + '</span>';
|
||||||
let deleteDialogMsg = gettext('Are you sure you want to delete {placeholder} ?').replace('{placeholder}', itemName);
|
let deleteDialogMsg = gettext('Are you sure you want to delete {placeholder} ?').replace('{placeholder}', itemName);
|
||||||
let resetPasswordDialogMsg = gettext('Are you sure you want to reset the password of {placeholder} ?').replace('{placeholder}', itemName);
|
let resetPasswordDialogMsg = gettext('Are you sure you want to reset the password of {placeholder} ?').replace('{placeholder}', itemName);
|
||||||
|
|
||||||
|
// for 'user status'
|
||||||
|
const curStatus = item.active ? 'active' : 'inactive';
|
||||||
|
this.statusOptions = ['active', 'inactive'].map(item => {
|
||||||
|
return {
|
||||||
|
value: item,
|
||||||
|
text: this.translateStatus(item),
|
||||||
|
isSelected: item == curStatus
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const currentSelectedStatusOption = this.statusOptions.filter(item => item.isSelected)[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
||||||
<td><UserLink email={item.email} name={item.name} /></td>
|
<td><UserLink email={item.email} name={item.name} /></td>
|
||||||
<td>
|
<td>
|
||||||
<SysAdminUserStatusEditor
|
<Selector
|
||||||
isTextMode={true}
|
isDropdownToggleShown={highlight}
|
||||||
isEditIconShow={isOpIconShown}
|
currentSelectedOption={currentSelectedStatusOption}
|
||||||
currentStatus={item.active ? 'active' : 'inactive'}
|
options={this.statusOptions}
|
||||||
statusOptions={['active', 'inactive']}
|
selectOption={this.updateStatus}
|
||||||
onStatusChanged={this.updateStatus}
|
toggleItemFreezed={this.props.toggleItemFreezed}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@@ -264,6 +289,7 @@ Item.propTypes = {
|
|||||||
isItemFreezed: PropTypes.bool.isRequired,
|
isItemFreezed: PropTypes.bool.isRequired,
|
||||||
onFreezedItem: PropTypes.func.isRequired,
|
onFreezedItem: PropTypes.func.isRequired,
|
||||||
onUnfreezedItem: PropTypes.func.isRequired,
|
onUnfreezedItem: PropTypes.func.isRequired,
|
||||||
|
toggleItemFreezed: PropTypes.func.isRequired,
|
||||||
updateStatus: PropTypes.func.isRequired,
|
updateStatus: PropTypes.func.isRequired,
|
||||||
updateMembership: PropTypes.func.isRequired,
|
updateMembership: PropTypes.func.isRequired,
|
||||||
deleteUser: PropTypes.func.isRequired,
|
deleteUser: PropTypes.func.isRequired,
|
||||||
|
@@ -8,7 +8,7 @@ import EmptyTip from '../../../components/empty-tip';
|
|||||||
import Loading from '../../../components/loading';
|
import Loading from '../../../components/loading';
|
||||||
import Paginator from '../../../components/paginator';
|
import Paginator from '../../../components/paginator';
|
||||||
import { seafileAPI } from '../../../utils/seafile-api';
|
import { seafileAPI } from '../../../utils/seafile-api';
|
||||||
import SysAdminUserRoleEditor from '../../../components/select-editor/sysadmin-user-role-editor';
|
import RoleSelector from '../../../components/single-selector';
|
||||||
import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog';
|
import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog';
|
||||||
import UserLink from '../user-link';
|
import UserLink from '../user-link';
|
||||||
import toaster from '../../../components/toast';
|
import toaster from '../../../components/toast';
|
||||||
@@ -17,6 +17,17 @@ const { availableRoles } = window.sysadmin.pageOptions;
|
|||||||
|
|
||||||
class Content extends Component {
|
class Content extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isItemFreezed: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleItemFreezed = (isFreezed) => {
|
||||||
|
this.setState({ isItemFreezed: isFreezed });
|
||||||
|
};
|
||||||
|
|
||||||
getPreviousPage = () => {
|
getPreviousPage = () => {
|
||||||
this.props.getListByPage(this.props.currentPage - 1);
|
this.props.getListByPage(this.props.currentPage - 1);
|
||||||
};
|
};
|
||||||
@@ -39,7 +50,7 @@ class Content extends Component {
|
|||||||
);
|
);
|
||||||
const table = (
|
const table = (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<table className="table-hover">
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th width="20%">{gettext('Name')}</th>
|
<th width="20%">{gettext('Name')}</th>
|
||||||
@@ -57,6 +68,8 @@ class Content extends Component {
|
|||||||
item={item}
|
item={item}
|
||||||
updateRole={this.props.updateRole}
|
updateRole={this.props.updateRole}
|
||||||
deleteOrg={this.props.deleteOrg}
|
deleteOrg={this.props.deleteOrg}
|
||||||
|
isItemFreezed={this.state.isItemFreezed}
|
||||||
|
toggleItemFreezed={this.toggleItemFreezed}
|
||||||
/>);
|
/>);
|
||||||
})}
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -81,7 +94,6 @@ class Content extends Component {
|
|||||||
Content.propTypes = {
|
Content.propTypes = {
|
||||||
loading: PropTypes.bool.isRequired,
|
loading: PropTypes.bool.isRequired,
|
||||||
errorMsg: PropTypes.string.isRequired,
|
errorMsg: PropTypes.string.isRequired,
|
||||||
item: PropTypes.object.isRequired,
|
|
||||||
getListByPage: PropTypes.func.isRequired,
|
getListByPage: PropTypes.func.isRequired,
|
||||||
currentPage: PropTypes.number,
|
currentPage: PropTypes.number,
|
||||||
items: PropTypes.array.isRequired,
|
items: PropTypes.array.isRequired,
|
||||||
@@ -97,18 +109,20 @@ class Item extends Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
isOpIconShown: false,
|
highlighted: false,
|
||||||
isDeleteDialogOpen: false,
|
isDeleteDialogOpen: false,
|
||||||
deleteDialogMsg: '',
|
deleteDialogMsg: '',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseEnter = () => {
|
handleMouseEnter = () => {
|
||||||
this.setState({isOpIconShown: true});
|
if (this.props.isItemFreezed) return;
|
||||||
|
this.setState({highlighted: true});
|
||||||
};
|
};
|
||||||
|
|
||||||
handleMouseLeave = () => {
|
handleMouseLeave = () => {
|
||||||
this.setState({isOpIconShown: false});
|
if (this.props.isItemFreezed) return;
|
||||||
|
this.setState({highlighted: false});
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleDeleteDialog = (e) => {
|
toggleDeleteDialog = (e) => {
|
||||||
@@ -135,8 +149,19 @@ class Item extends Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
updateRole = (role) => {
|
translateRole = (role) => {
|
||||||
this.props.updateRole(this.props.item.org_id, role);
|
switch (role) {
|
||||||
|
case 'default':
|
||||||
|
return gettext('Default');
|
||||||
|
case 'guest':
|
||||||
|
return gettext('Guest');
|
||||||
|
default:
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
updateRole = (roleOption) => {
|
||||||
|
this.props.updateRole(this.props.item.org_id, roleOption.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
deleteOrg = () => {
|
deleteOrg = () => {
|
||||||
@@ -146,28 +171,38 @@ class Item extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { item } = this.props;
|
const { item } = this.props;
|
||||||
const { isOpIconShown, isDeleteDialogOpen, deleteDialogMsg } = this.state;
|
const { highlighted, isDeleteDialogOpen, deleteDialogMsg } = this.state;
|
||||||
|
|
||||||
|
const { role: curRole } = item;
|
||||||
|
this.roleOptions = availableRoles.map(item => {
|
||||||
|
return {
|
||||||
|
value: item,
|
||||||
|
text: this.translateRole(item),
|
||||||
|
isSelected: item == curRole
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const currentSelectedOption = this.roleOptions.filter(item => item.isSelected)[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<tr onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
<tr className={highlighted ? 'tr-highlight' : ''} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
||||||
<td><Link to={`${siteRoot}sys/organizations/${item.org_id}/info/`}>{item.org_name}</Link></td>
|
<td><Link to={`${siteRoot}sys/organizations/${item.org_id}/info/`}>{item.org_name}</Link></td>
|
||||||
<td>
|
<td>
|
||||||
<UserLink email={item.creator_email} name={item.creator_name} />
|
<UserLink email={item.creator_email} name={item.creator_name} />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<SysAdminUserRoleEditor
|
<RoleSelector
|
||||||
isTextMode={true}
|
isDropdownToggleShown={highlighted}
|
||||||
isEditIconShow={isOpIconShown}
|
currentSelectedOption={currentSelectedOption}
|
||||||
currentRole={item.role}
|
options={this.roleOptions}
|
||||||
roleOptions={availableRoles}
|
selectOption={this.updateRole}
|
||||||
onRoleChanged={this.updateRole}
|
toggleItemFreezed={this.props.toggleItemFreezed}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>{`${Utils.bytesToSize(item.quota_usage)} / ${item.quota > 0 ? Utils.bytesToSize(item.quota) : '--'}`}</td>
|
<td>{`${Utils.bytesToSize(item.quota_usage)} / ${item.quota > 0 ? Utils.bytesToSize(item.quota) : '--'}`}</td>
|
||||||
<td>{moment(item.ctime).format('YYYY-MM-DD HH:mm:ss')}</td>
|
<td>{moment(item.ctime).format('YYYY-MM-DD HH:mm:ss')}</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="#" className={`action-icon sf2-icon-delete ${isOpIconShown ? '' : 'invisible'}`} title={gettext('Delete')} onClick={this.toggleDeleteDialog}></a>
|
<a href="#" className={`action-icon sf2-icon-delete ${highlighted ? '' : 'invisible'}`} title={gettext('Delete')} onClick={this.toggleDeleteDialog}></a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{isDeleteDialogOpen &&
|
{isDeleteDialogOpen &&
|
||||||
@@ -188,6 +223,8 @@ Item.propTypes = {
|
|||||||
item: PropTypes.object.isRequired,
|
item: PropTypes.object.isRequired,
|
||||||
updateRole: PropTypes.func.isRequired,
|
updateRole: PropTypes.func.isRequired,
|
||||||
deleteOrg: PropTypes.func.isRequired,
|
deleteOrg: PropTypes.func.isRequired,
|
||||||
|
isItemFreezed: PropTypes.bool.isRequired,
|
||||||
|
toggleItemFreezed: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Content;
|
export default Content;
|
||||||
|
@@ -9,9 +9,7 @@ import toaster from '../../../components/toast';
|
|||||||
import EmptyTip from '../../../components/empty-tip';
|
import EmptyTip from '../../../components/empty-tip';
|
||||||
import Loading from '../../../components/loading';
|
import Loading from '../../../components/loading';
|
||||||
import Paginator from '../../../components/paginator';
|
import Paginator from '../../../components/paginator';
|
||||||
import SysAdminUserStatusEditor from '../../../components/select-editor/sysadmin-user-status-editor';
|
import Selector from '../../../components/single-selector';
|
||||||
import SysAdminUserRoleEditor from '../../../components/select-editor/sysadmin-user-role-editor';
|
|
||||||
import SelectEditor from '../../../components/select-editor/select-editor';
|
|
||||||
import OpMenu from '../../../components/dialog/op-menu';
|
import OpMenu from '../../../components/dialog/op-menu';
|
||||||
import SysAdminUserSetQuotaDialog from '../../../components/dialog/sysadmin-dialog/set-quota';
|
import SysAdminUserSetQuotaDialog from '../../../components/dialog/sysadmin-dialog/set-quota';
|
||||||
import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog';
|
import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog';
|
||||||
@@ -28,6 +26,10 @@ class Content extends Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleItemFreezed = (isFreezed) => {
|
||||||
|
this.setState({ isItemFreezed: isFreezed });
|
||||||
|
};
|
||||||
|
|
||||||
onFreezedItem = () => {
|
onFreezedItem = () => {
|
||||||
this.setState({isItemFreezed: true});
|
this.setState({isItemFreezed: true});
|
||||||
};
|
};
|
||||||
@@ -133,6 +135,7 @@ class Content extends Component {
|
|||||||
isItemFreezed={this.state.isItemFreezed}
|
isItemFreezed={this.state.isItemFreezed}
|
||||||
onFreezedItem={this.onFreezedItem}
|
onFreezedItem={this.onFreezedItem}
|
||||||
onUnfreezedItem={this.onUnfreezedItem}
|
onUnfreezedItem={this.onUnfreezedItem}
|
||||||
|
toggleItemFreezed={this.toggleItemFreezed}
|
||||||
updateUser={this.props.updateUser}
|
updateUser={this.props.updateUser}
|
||||||
deleteUser={this.props.deleteUser}
|
deleteUser={this.props.deleteUser}
|
||||||
updateAdminRole={this.props.updateAdminRole}
|
updateAdminRole={this.props.updateAdminRole}
|
||||||
@@ -247,20 +250,31 @@ class Item extends Component {
|
|||||||
this.props.onUserSelected(this.props.item);
|
this.props.onUserSelected(this.props.item);
|
||||||
};
|
};
|
||||||
|
|
||||||
updateStatus= (value) => {
|
updateStatus= (roleOption) => {
|
||||||
const isActive = value == 'active';
|
const isActive = roleOption.value == 'active';
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
toaster.notify(gettext('It may take some time, please wait.'));
|
toaster.notify(gettext('It may take some time, please wait.'));
|
||||||
}
|
}
|
||||||
this.props.updateUser(this.props.item.email, 'is_active', isActive);
|
this.props.updateUser(this.props.item.email, 'is_active', isActive);
|
||||||
};
|
};
|
||||||
|
|
||||||
updateRole = (value) => {
|
updateRole = (roleOption) => {
|
||||||
this.props.updateUser(this.props.item.email, 'role', value);
|
this.props.updateUser(this.props.item.email, 'role', roleOption.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
updateAdminRole = (value) => {
|
updateAdminRole = (roleOption) => {
|
||||||
this.props.updateAdminRole(this.props.item.email, value);
|
this.props.updateAdminRole(this.props.item.email, roleOption.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
translateRole = (role) => {
|
||||||
|
switch (role) {
|
||||||
|
case 'default':
|
||||||
|
return gettext('Default');
|
||||||
|
case 'guest':
|
||||||
|
return gettext('Guest');
|
||||||
|
default:
|
||||||
|
return role;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
translateAdminRole = (role) => {
|
translateAdminRole = (role) => {
|
||||||
@@ -278,12 +292,17 @@ class Item extends Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
updateInstitution = (value) => {
|
translateStatus = (status) => {
|
||||||
this.props.updateUser(this.props.item.email, 'institution', value);
|
switch (status) {
|
||||||
|
case 'active':
|
||||||
|
return gettext('Active');
|
||||||
|
case 'inactive':
|
||||||
|
return gettext('Inactive');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
translateInstitution = (inst) => {
|
updateInstitution = (instOption) => {
|
||||||
return inst;
|
this.props.updateUser(this.props.item.email, 'institution', instOption.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
updateQuota = (value) => {
|
updateQuota = (value) => {
|
||||||
@@ -362,6 +381,7 @@ class Item extends Component {
|
|||||||
render() {
|
render() {
|
||||||
const { item, isAdmin } = this.props;
|
const { item, isAdmin } = this.props;
|
||||||
const {
|
const {
|
||||||
|
highlight,
|
||||||
isOpIconShown,
|
isOpIconShown,
|
||||||
isSetQuotaDialogOpen,
|
isSetQuotaDialogOpen,
|
||||||
isDeleteUserDialogOpen,
|
isDeleteUserDialogOpen,
|
||||||
@@ -374,6 +394,54 @@ class Item extends Component {
|
|||||||
const resetPasswordDialogMsg = gettext('Are you sure you want to reset the password of {placeholder} ?').replace('{placeholder}', itemName);
|
const resetPasswordDialogMsg = gettext('Are you sure you want to reset the password of {placeholder} ?').replace('{placeholder}', itemName);
|
||||||
const revokeAdminDialogMsg = gettext('Are you sure you want to revoke the admin permission of {placeholder} ?').replace('{placeholder}', itemName);
|
const revokeAdminDialogMsg = gettext('Are you sure you want to revoke the admin permission of {placeholder} ?').replace('{placeholder}', itemName);
|
||||||
|
|
||||||
|
// for 'user status'
|
||||||
|
const curStatus = item.is_active ? 'active' : 'inactive';
|
||||||
|
this.statusOptions = ['active', 'inactive'].map(item => {
|
||||||
|
return {
|
||||||
|
value: item,
|
||||||
|
text: this.translateStatus(item),
|
||||||
|
isSelected: item == curStatus
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const currentSelectedStatusOption = this.statusOptions.filter(item => item.isSelected)[0];
|
||||||
|
|
||||||
|
let currentSelectedAdminRoleOption;
|
||||||
|
let currentSelectedRoleOption;
|
||||||
|
if (isAdmin) {
|
||||||
|
const { admin_role: curAdminRole } = item;
|
||||||
|
this.adminRoleOptions = availableAdminRoles.map(item => {
|
||||||
|
return {
|
||||||
|
value: item,
|
||||||
|
text: this.translateAdminRole(item),
|
||||||
|
isSelected: item == curAdminRole
|
||||||
|
};
|
||||||
|
});
|
||||||
|
currentSelectedAdminRoleOption = this.adminRoleOptions.filter(item => item.isSelected)[0];
|
||||||
|
} else {
|
||||||
|
const { role: curRole } = item;
|
||||||
|
this.roleOptions = availableRoles.map(item => {
|
||||||
|
return {
|
||||||
|
value: item,
|
||||||
|
text: this.translateRole(item),
|
||||||
|
isSelected: item == curRole
|
||||||
|
};
|
||||||
|
});
|
||||||
|
currentSelectedRoleOption = this.roleOptions.filter(item => item.isSelected)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentSelectedInstOption;
|
||||||
|
if (multiInstitution && !isAdmin) {
|
||||||
|
const { institution: curInstitution } = item;
|
||||||
|
this.instOptions = institutions.map(item => {
|
||||||
|
return {
|
||||||
|
value: item,
|
||||||
|
text: item,
|
||||||
|
isSelected: item == curInstitution
|
||||||
|
};
|
||||||
|
});
|
||||||
|
currentSelectedInstOption = this.instOptions.filter(item => item.isSelected)[0];
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
||||||
@@ -395,31 +463,31 @@ class Item extends Component {
|
|||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<SysAdminUserStatusEditor
|
<Selector
|
||||||
isTextMode={true}
|
isDropdownToggleShown={highlight}
|
||||||
isEditIconShow={isOpIconShown}
|
currentSelectedOption={currentSelectedStatusOption}
|
||||||
currentStatus={item.is_active ? 'active' : 'inactive'}
|
options={this.statusOptions}
|
||||||
statusOptions={['active', 'inactive']}
|
selectOption={this.updateStatus}
|
||||||
onStatusChanged={this.updateStatus}
|
toggleItemFreezed={this.props.toggleItemFreezed}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
{isPro &&
|
{isPro &&
|
||||||
<td>
|
<td>
|
||||||
{isAdmin ?
|
{isAdmin ?
|
||||||
<SelectEditor
|
<Selector
|
||||||
isTextMode={true}
|
isDropdownToggleShown={highlight}
|
||||||
isEditIconShow={isOpIconShown}
|
currentSelectedOption={currentSelectedAdminRoleOption}
|
||||||
options={availableAdminRoles}
|
options={this.adminRoleOptions}
|
||||||
currentOption={item.admin_role}
|
selectOption={this.updateAdminRole}
|
||||||
onOptionChanged={this.updateAdminRole}
|
toggleItemFreezed={this.props.toggleItemFreezed}
|
||||||
translateOption={this.translateAdminRole}
|
/>
|
||||||
/> :
|
:
|
||||||
<SysAdminUserRoleEditor
|
<Selector
|
||||||
isTextMode={true}
|
isDropdownToggleShown={highlight}
|
||||||
isEditIconShow={isOpIconShown}
|
currentSelectedOption={currentSelectedRoleOption}
|
||||||
currentRole={item.role}
|
options={this.roleOptions}
|
||||||
roleOptions={availableRoles}
|
selectOption={this.updateRole}
|
||||||
onRoleChanged={this.updateRole}
|
toggleItemFreezed={this.props.toggleItemFreezed}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
@@ -434,13 +502,12 @@ class Item extends Component {
|
|||||||
</td>
|
</td>
|
||||||
{(multiInstitution && !isAdmin) &&
|
{(multiInstitution && !isAdmin) &&
|
||||||
<td>
|
<td>
|
||||||
<SelectEditor
|
<Selector
|
||||||
isTextMode={true}
|
isDropdownToggleShown={highlight && institutions.length > 0}
|
||||||
isEditIconShow={isOpIconShown && institutions.length > 0}
|
currentSelectedOption={currentSelectedInstOption}
|
||||||
options={institutions}
|
options={this.instOptions}
|
||||||
currentOption={item.institution}
|
selectOption={this.updateInstitution}
|
||||||
onOptionChanged={this.updateInstitution}
|
toggleItemFreezed={this.props.toggleItemFreezed}
|
||||||
translateOption={this.translateInstitution}
|
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
}
|
}
|
||||||
@@ -508,6 +575,7 @@ Item.propTypes = {
|
|||||||
isLDAPImported: PropTypes.bool,
|
isLDAPImported: PropTypes.bool,
|
||||||
onFreezedItem: PropTypes.func,
|
onFreezedItem: PropTypes.func,
|
||||||
onUnfreezedItem: PropTypes.func,
|
onUnfreezedItem: PropTypes.func,
|
||||||
|
toggleItemFreezed: PropTypes.func.isRequired,
|
||||||
updateUser: PropTypes.func,
|
updateUser: PropTypes.func,
|
||||||
deleteUser: PropTypes.func,
|
deleteUser: PropTypes.func,
|
||||||
updateAdminRole: PropTypes.func,
|
updateAdminRole: PropTypes.func,
|
||||||
|
Reference in New Issue
Block a user