mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-10 19:29:56 +00:00
['group' page] redesigned the toolbar & the 'group members' dialog; improved the 'manage members' dialog (#6248)
This commit is contained in:
@@ -26,9 +26,9 @@ class GroupMembers extends React.Component {
|
|||||||
<Table size="sm" className="manage-members-table">
|
<Table size="sm" className="manage-members-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th width="15%"></th>
|
<th width="10%"></th>
|
||||||
<th width="45%">{gettext('Name')}</th>
|
<th width="45%">{gettext('Name')}</th>
|
||||||
<th width="30%">{gettext('Role')}</th>
|
<th width="35%">{gettext('Role')}</th>
|
||||||
<th width="10%"></th>
|
<th width="10%"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -140,7 +140,7 @@ class Member extends React.PureComponent {
|
|||||||
|
|
||||||
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>
|
||||||
<td>{item.name}</td>
|
<td>{item.name}</td>
|
||||||
<td>
|
<td>
|
||||||
{((isOwner === false) || (isOwner === true && item.role === 'Owner')) &&
|
{((isOwner === false) || (isOwner === true && item.role === 'Owner')) &&
|
||||||
|
@@ -1,30 +1,3 @@
|
|||||||
#group-setting-popover,
|
.group-member:hover {
|
||||||
#group-members-popover {
|
background: #f5f5f5;
|
||||||
top: 42px;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
.group-member-list-header {
|
|
||||||
border-bottom: 1px solid #e3e3e5;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
margin-bottom: 0px;
|
|
||||||
}
|
|
||||||
.group-member-list {
|
|
||||||
max-height: 400px;
|
|
||||||
border-top: 0;
|
|
||||||
margin-top: 0;
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
.group-member-list .user-item {
|
|
||||||
line-height: 2rem;
|
|
||||||
}
|
|
||||||
.group-member-list .user-item:hover {
|
|
||||||
background-color: #f8f8f8;
|
|
||||||
}
|
|
||||||
.group-member-list .user-item .group-member-name {
|
|
||||||
margin: 0 5px;
|
|
||||||
max-width: 70%;
|
|
||||||
}
|
|
||||||
.group-member-list .user-item .group-member-admin {
|
|
||||||
color: #888;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,3 @@
|
|||||||
.department-group-icon {
|
|
||||||
margin-left: 0.25rem;
|
|
||||||
color:#888;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-top-op-icon { /* for cur-view-path*/
|
.group-top-op-icon { /* for cur-view-path*/
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
|
@@ -10,9 +10,9 @@ import ModalPortal from '../../components/modal-portal';
|
|||||||
import Group from '../../models/group';
|
import Group from '../../models/group';
|
||||||
import Repo from '../../models/repo';
|
import Repo from '../../models/repo';
|
||||||
import toaster from '../../components/toast';
|
import toaster from '../../components/toast';
|
||||||
import OpIcon from '../../components/op-icon';
|
|
||||||
import CommonToolbar from '../../components/toolbar/common-toolbar';
|
import CommonToolbar from '../../components/toolbar/common-toolbar';
|
||||||
import CreateRepoDialog from '../../components/dialog/create-repo-dialog';
|
import CreateRepoDialog from '../../components/dialog/create-repo-dialog';
|
||||||
|
import GroupMembersDialog from '../../components/dialog/group-members-dialog';
|
||||||
import DismissGroupDialog from '../../components/dialog/dismiss-group-dialog';
|
import DismissGroupDialog from '../../components/dialog/dismiss-group-dialog';
|
||||||
import RenameGroupDialog from '../../components/dialog/rename-group-dialog';
|
import RenameGroupDialog from '../../components/dialog/rename-group-dialog';
|
||||||
import TransferGroupDialog from '../../components/dialog/transfer-group-dialog';
|
import TransferGroupDialog from '../../components/dialog/transfer-group-dialog';
|
||||||
@@ -21,6 +21,7 @@ import ManageMembersDialog from '../../components/dialog/manage-members-dialog';
|
|||||||
import LeaveGroupDialog from '../../components/dialog/leave-group-dialog';
|
import LeaveGroupDialog from '../../components/dialog/leave-group-dialog';
|
||||||
import SharedRepoListView from '../../components/shared-repo-list-view/shared-repo-list-view';
|
import SharedRepoListView from '../../components/shared-repo-list-view/shared-repo-list-view';
|
||||||
import SortOptionsDialog from '../../components/dialog/sort-options';
|
import SortOptionsDialog from '../../components/dialog/sort-options';
|
||||||
|
import SingleDropdownToolbar from '../../components/toolbar/single-dropdown-toolbar';
|
||||||
|
|
||||||
import '../../css/group-view.css';
|
import '../../css/group-view.css';
|
||||||
|
|
||||||
@@ -63,6 +64,7 @@ class GroupView extends React.Component {
|
|||||||
showManageMembersDialog: false,
|
showManageMembersDialog: false,
|
||||||
groupMembers: [],
|
groupMembers: [],
|
||||||
isLeaveGroupDialogOpen: false,
|
isLeaveGroupDialogOpen: false,
|
||||||
|
isMembersDialogOpen: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,6 +96,7 @@ class GroupView extends React.Component {
|
|||||||
repoList: [] // empty it for the current group
|
repoList: [] // empty it for the current group
|
||||||
}, () => {
|
}, () => {
|
||||||
this.loadRepos(this.state.currentPage);
|
this.loadRepos(this.state.currentPage);
|
||||||
|
this.listGroupMembers();
|
||||||
});
|
});
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -257,12 +260,6 @@ class GroupView extends React.Component {
|
|||||||
this.setState({repoList: repoList});
|
this.setState({repoList: repoList});
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleGroupDropdown = () => {
|
|
||||||
this.setState({
|
|
||||||
showGroupDropdown: !this.state.showGroupDropdown
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
toggleDismissGroupDialog = () => {
|
toggleDismissGroupDialog = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
showDismissGroupDialog: !this.state.showDismissGroupDialog,
|
showDismissGroupDialog: !this.state.showDismissGroupDialog,
|
||||||
@@ -385,38 +382,57 @@ class GroupView extends React.Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
toggleMembersDialog = () => {
|
||||||
|
this.setState({
|
||||||
|
isMembersDialogOpen: !this.state.isMembersDialogOpen
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
getOpList = () => {
|
||||||
|
const { currentGroup, isDepartmentGroup, isStaff, isOwner } = this.state;
|
||||||
|
const opList = [];
|
||||||
|
if ((!isDepartmentGroup && canAddRepo) ||
|
||||||
|
(isDepartmentGroup && isStaff)) {
|
||||||
|
opList.push({'text': gettext('New Library'), 'onClick': this.onCreateRepoToggle});
|
||||||
|
}
|
||||||
|
opList.push({'text': gettext('Members'), 'onClick': this.toggleMembersDialog});
|
||||||
|
if (currentGroup) {
|
||||||
|
if (isStaff || isOwner) {
|
||||||
|
opList.push({'text': gettext('Rename'), 'onClick': this.toggleRenameGroupDialog});
|
||||||
|
if (isOwner) {
|
||||||
|
opList.push({'text': gettext('Transfer'), 'onClick': this.toggleTransferGroupDialog});
|
||||||
|
}
|
||||||
|
opList.push({'text': gettext('Import members'), 'onClick': this.toggleImportMembersDialog});
|
||||||
|
opList.push({'text': gettext('Manage members'), 'onClick': this.toggleManageMembersDialog});
|
||||||
|
if (isOwner) {
|
||||||
|
opList.push({'text': gettext('Delete group'), 'onClick': this.toggleDismissGroupDialog});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isOwner && !isDepartmentGroup) {
|
||||||
|
opList.push({'text': gettext('Leave group'), 'onClick': this.toggleLeaveGroupDialog});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return opList;
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { errMessage, emptyTip, currentGroup, isDepartmentGroup, isStaff } = this.state;
|
const { errMessage, emptyTip, currentGroup, isDepartmentGroup,
|
||||||
let isShowSettingIcon = false;
|
groupMembers, isMembersDialogOpen
|
||||||
if (currentGroup) { // group message is loaded
|
} = this.state;
|
||||||
if (currentGroup.parent_group_id === 0) {
|
|
||||||
isShowSettingIcon = true;
|
|
||||||
} else {
|
|
||||||
if (currentGroup.admins.indexOf(username) > -1) {
|
|
||||||
isShowSettingIcon = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let useRate = 0;
|
let useRate = 0;
|
||||||
if (isDepartmentGroup && currentGroup.group_quota) {
|
if (isDepartmentGroup && currentGroup.group_quota) {
|
||||||
useRate = currentGroup.group_quota_usage / currentGroup.group_quota * 100 + '%';
|
useRate = currentGroup.group_quota_usage / currentGroup.group_quota * 100 + '%';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const opList = this.getOpList();
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className="main-panel-north border-left-show">
|
<div className="main-panel-north border-left-show">
|
||||||
<div className="cur-view-toolbar">
|
<div className="cur-view-toolbar">
|
||||||
<span className="sf2-icon-menu side-nav-toggle hidden-md-up d-md-none" title="Side Nav Menu" onClick={this.props.onShowSidePanel}></span>
|
<span className="sf2-icon-menu side-nav-toggle d-md-none" title="Side Nav Menu" onClick={this.props.onShowSidePanel}></span>
|
||||||
<div className="operation">
|
|
||||||
{((!isDepartmentGroup && canAddRepo) || (isDepartmentGroup && isStaff)) && (
|
|
||||||
Utils.isDesktop() ? (
|
|
||||||
<button className="btn btn-secondary operation-item" title={gettext('New Library')} onClick={this.onCreateRepoToggle}>
|
|
||||||
<i className="fas fa-plus-square text-secondary mr-1"></i>{gettext('New Library')}
|
|
||||||
</button>
|
|
||||||
) : (
|
|
||||||
<span className="sf2-icon-plus mobile-toolbar-icon" title={gettext('New Library')} onClick={this.onCreateRepoToggle}></span>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<CommonToolbar onSearchedClick={this.props.onSearchedClick} />
|
<CommonToolbar onSearchedClick={this.props.onSearchedClick} />
|
||||||
</div>
|
</div>
|
||||||
@@ -425,101 +441,26 @@ class GroupView extends React.Component {
|
|||||||
<div className="cur-view-path">
|
<div className="cur-view-path">
|
||||||
{currentGroup && (
|
{currentGroup && (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className="path-container">
|
<div className="sf-heading d-flex align-items-center">
|
||||||
|
{isDepartmentGroup &&
|
||||||
|
<span className="sf3-font-department sf3-font nav-icon" title={gettext('This is a special group representing a department.')}></span>
|
||||||
|
}
|
||||||
<span>{currentGroup.name}</span>
|
<span>{currentGroup.name}</span>
|
||||||
|
<SingleDropdownToolbar opList={opList} />
|
||||||
|
</div>
|
||||||
|
<div className="path-tool">
|
||||||
{isDepartmentGroup && (
|
{isDepartmentGroup && (
|
||||||
<Fragment>
|
<>
|
||||||
<span className="department-group-icon sf3-font-department sf3-font" title={gettext('This is a special group representing a department.')}></span>
|
|
||||||
{currentGroup.group_quota > 0 &&
|
{currentGroup.group_quota > 0 &&
|
||||||
<span className="department-usage-container">
|
<div className="department-usage-container">
|
||||||
<div className="department-usage">
|
<div className="department-usage">
|
||||||
<span id="quota-bar" className="department-quota-bar"><span id="quota-usage" className="usage" style={{width: useRate}}></span></span>
|
<span id="quota-bar" className="department-quota-bar"><span id="quota-usage" className="usage" style={{width: useRate}}></span></span>
|
||||||
<span className="department-quota-info">{Utils.bytesToSize(currentGroup.group_quota_usage)} / {Utils.bytesToSize(currentGroup.group_quota)}</span>
|
<span className="department-quota-info">{Utils.bytesToSize(currentGroup.group_quota_usage)} / {Utils.bytesToSize(currentGroup.group_quota)}</span>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</div>
|
||||||
}
|
}
|
||||||
</Fragment>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
<div className="path-tool">
|
|
||||||
{ isShowSettingIcon &&
|
|
||||||
<React.Fragment>
|
|
||||||
<OpIcon
|
|
||||||
className="sf2-icon-cog1 action-icon group-top-action-icon"
|
|
||||||
title={gettext('Settings')}
|
|
||||||
op={this.toggleGroupDropdown}
|
|
||||||
/>
|
|
||||||
{this.state.showGroupDropdown &&
|
|
||||||
<div className="sf-popover" id="group-setting-popover">
|
|
||||||
<div className="sf-popover-hd sf-popover-title">
|
|
||||||
<span>{gettext('Settings')}</span>
|
|
||||||
<a href="#" className="sf-popover-close js-close sf2-icon-x1 action-icon"
|
|
||||||
role="button"
|
|
||||||
aria-label={gettext('Close')}
|
|
||||||
onClick={this.toggleGroupDropdown}></a>
|
|
||||||
</div>
|
|
||||||
<div className="sf-popover-con">
|
|
||||||
{(this.state.isStaff || this.state.isOwner) &&
|
|
||||||
<ul className="sf-popover-list">
|
|
||||||
<li><a href="#" className="sf-popover-item" onClick={this.toggleRenameGroupDialog}>{gettext('Rename')}</a></li>
|
|
||||||
{
|
|
||||||
this.state.isOwner &&
|
|
||||||
<li><a href="#" className="sf-popover-item" onClick={this.toggleTransferGroupDialog} >{gettext('Transfer')}</a></li>
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
}
|
|
||||||
{(this.state.isStaff || this.state.isOwner) &&
|
|
||||||
<ul className="sf-popover-list">
|
|
||||||
<li><a href="#" className="sf-popover-item" onClick={this.toggleImportMembersDialog} >{gettext('Import Members')}</a></li>
|
|
||||||
<li><a href="#" className="sf-popover-item" onClick={this.toggleManageMembersDialog} >{gettext('Manage Members')}</a></li>
|
|
||||||
</ul>
|
|
||||||
}
|
|
||||||
{
|
|
||||||
this.state.isOwner &&
|
|
||||||
<ul className="sf-popover-list">
|
|
||||||
<li><a href="#" className="sf-popover-item" onClick={this.toggleDismissGroupDialog}>{gettext('Delete Group')}</a></li>
|
|
||||||
</ul>
|
|
||||||
}
|
|
||||||
{/* gourp owner only can dissmiss group, admin could not quit, department member could not quit */}
|
|
||||||
{(!this.state.isOwner && !isDepartmentGroup) &&
|
|
||||||
<ul className="sf-popover-list">
|
|
||||||
<li><a href="#" className="sf-popover-item" onClick={this.toggleLeaveGroupDialog}>{gettext('Leave Group')}</a></li>
|
|
||||||
</ul>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>}
|
|
||||||
</React.Fragment>
|
|
||||||
}
|
|
||||||
<a href="#"
|
|
||||||
className="sf2-icon-user2 action-icon group-top-action-icon"
|
|
||||||
title={gettext('Members')} id="groupMembers"
|
|
||||||
onClick={() => this.toggleGroupMembersPopover('open')}>
|
|
||||||
</a>
|
|
||||||
{this.state.showGroupMembersPopover &&
|
|
||||||
<div className="sf-popover" id="group-members-popover">
|
|
||||||
<div className="sf-popover-hd sf-popover-title group-member-list-header">
|
|
||||||
<span>{gettext('Members')}</span>
|
|
||||||
<a href="#" className="sf-popover-close js-close sf2-icon-x1 action-icon"
|
|
||||||
onClick={this.toggleGroupMembersPopover}></a>
|
|
||||||
</div>
|
|
||||||
<div className="sf-popover-con">
|
|
||||||
<ul className="sf-popover-list group-member-list">
|
|
||||||
{this.state.groupMembers.map((item, index) => {
|
|
||||||
return (
|
|
||||||
<li key={index}>
|
|
||||||
<a href="#" className="sf-popover-item user-item d-flex">
|
|
||||||
<img src={item.avatar_url} alt="" className="group-member-avatar avatar"/>
|
|
||||||
<span className="txt-item ellipsis d-flex">
|
|
||||||
<span className="group-member-name ellipsis">{item.name}</span>
|
|
||||||
<span className="group-member-admin">{this.translateRole(item.role)}</span>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>}
|
|
||||||
{(!Utils.isDesktop() && this.state.repoList.length > 0) && <span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>}
|
{(!Utils.isDesktop() && this.state.repoList.length > 0) && <span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>}
|
||||||
{this.state.isSortOptionsDialogOpen &&
|
{this.state.isSortOptionsDialogOpen &&
|
||||||
<SortOptionsDialog
|
<SortOptionsDialog
|
||||||
@@ -565,12 +506,17 @@ class GroupView extends React.Component {
|
|||||||
)}
|
)}
|
||||||
{this.state.isCreateRepoDialogShow && this.state.isDepartmentGroup &&
|
{this.state.isCreateRepoDialogShow && this.state.isDepartmentGroup &&
|
||||||
<CreateRepoDialog
|
<CreateRepoDialog
|
||||||
isAdmin={this.state.isAdmin}
|
|
||||||
onCreateToggle={this.onCreateRepoToggle}
|
onCreateToggle={this.onCreateRepoToggle}
|
||||||
onCreateRepo={this.onCreateRepo}
|
onCreateRepo={this.onCreateRepo}
|
||||||
libraryType='department'
|
libraryType='department'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
{isMembersDialogOpen &&
|
||||||
|
<GroupMembersDialog
|
||||||
|
members={groupMembers}
|
||||||
|
toggleDialog={this.toggleMembersDialog}
|
||||||
|
/>
|
||||||
|
}
|
||||||
{this.state.showRenameGroupDialog &&
|
{this.state.showRenameGroupDialog &&
|
||||||
<RenameGroupDialog
|
<RenameGroupDialog
|
||||||
showRenameGroupDialog={this.state.showRenameGroupDialog}
|
showRenameGroupDialog={this.state.showRenameGroupDialog}
|
||||||
|
@@ -524,13 +524,13 @@ a, a:hover { color: #ec8000; }
|
|||||||
.department-usage-container {
|
.department-usage-container {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
margin-left: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.department-usage {
|
.department-usage {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 0 0.75rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.department-usage .department-quota-bar {
|
.department-usage .department-quota-bar {
|
||||||
|
Reference in New Issue
Block a user