1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-02 15:38:15 +00:00

add context menu for libraries list (#6909)

* add context menu for libraries list

* support context menu on grid mode

* optimize code

---------

Co-authored-by: zhouwenxuan <aries@Mac.local>
This commit is contained in:
Aries
2024-10-18 10:54:58 +08:00
committed by GitHub
parent 675e2572da
commit b723b6436e
10 changed files with 419 additions and 33 deletions

View File

@@ -31,3 +31,27 @@ export function showMenu(opts = {}, target) {
export function hideMenu(opts = {}, target) { export function hideMenu(opts = {}, target) {
dispatchGlobalEvent(MENU_HIDE, assign({}, opts, { type: MENU_HIDE }), target); dispatchGlobalEvent(MENU_HIDE, assign({}, opts, { type: MENU_HIDE }), target);
} }
export function handleContextClick(event, id, menuList, currentObject = null) {
event.preventDefault();
event.stopPropagation();
let x = event.clientX || (event.touches && event.touches[0].pageX);
let y = event.clientY || (event.touches && event.touches[0].pageY);
hideMenu();
let showMenuConfig = {
id: id,
position: { x, y },
target: event.target,
currentObject: currentObject,
menuList: menuList,
};
if (menuList.length === 0) {
return;
}
showMenu(showMenuConfig);
}

View File

@@ -32,7 +32,8 @@ const propTypes = {
onItemUnshare: PropTypes.func.isRequired, onItemUnshare: PropTypes.func.isRequired,
onItemRename: PropTypes.func, onItemRename: PropTypes.func,
onItemDelete: PropTypes.func, onItemDelete: PropTypes.func,
onMonitorRepo: PropTypes.func onMonitorRepo: PropTypes.func,
onContextMenu: PropTypes.func.isRequired,
}; };
class SharedRepoListItem extends React.Component { class SharedRepoListItem extends React.Component {
@@ -157,7 +158,7 @@ class SharedRepoListItem extends React.Component {
}; };
onMenuItemClick = (e) => { onMenuItemClick = (e) => {
let operation = e.target.dataset.toggle; let operation = e.target.dataset.toggle || e.target.dataset.operation;
switch (operation) { switch (operation) {
case 'Rename': case 'Rename':
this.onItemRenameToggle(); this.onItemRenameToggle();
@@ -616,6 +617,10 @@ class SharedRepoListItem extends React.Component {
} }
}; };
handleContextMenu = (e) => {
this.props.onContextMenu(e, this.props.repo);
};
renderPCUI = () => { renderPCUI = () => {
const { isStarred } = this.state; const { isStarred } = this.state;
let { iconUrl, iconTitle, libPath } = this.getRepoComputeParams(); let { iconUrl, iconTitle, libPath } = this.getRepoComputeParams();
@@ -627,6 +632,7 @@ class SharedRepoListItem extends React.Component {
onMouseOver={this.onMouseOver} onMouseOver={this.onMouseOver}
onMouseLeave={this.onMouseLeave} onMouseLeave={this.onMouseLeave}
onFocus={this.onMouseEnter} onFocus={this.onMouseEnter}
onContextMenu={this.handleContextMenu}
> >
<td className="text-center"> <td className="text-center">
<i <i
@@ -659,6 +665,7 @@ class SharedRepoListItem extends React.Component {
onMouseEnter={this.onMouseEnter} onMouseEnter={this.onMouseEnter}
onMouseLeave={this.onMouseLeave} onMouseLeave={this.onMouseLeave}
onFocus={this.onMouseEnter} onFocus={this.onMouseEnter}
onContextMenu={this.handleContextMenu}
> >
<div className="d-flex align-items-center text-truncate"> <div className="d-flex align-items-center text-truncate">
<img src={iconUrl} title={iconTitle} alt={iconTitle} width="36" className="mr-2" /> <img src={iconUrl} title={iconTitle} alt={iconTitle} width="36" className="mr-2" />

View File

@@ -7,6 +7,8 @@ import toaster from '../toast';
import LibsMobileThead from '../libs-mobile-thead'; import LibsMobileThead from '../libs-mobile-thead';
import Loading from '../loading'; import Loading from '../loading';
import { LIST_MODE } from '../dir-view-mode/constants'; import { LIST_MODE } from '../dir-view-mode/constants';
import ContextMenu from '../context-menu/context-menu';
import { hideMenu, handleContextClick } from '../context-menu/actions';
const propTypes = { const propTypes = {
currentViewMode: PropTypes.string, currentViewMode: PropTypes.string,
@@ -33,6 +35,7 @@ class SharedRepoListView extends React.Component {
this.state = { this.state = {
isItemFreezed: false, isItemFreezed: false,
}; };
this.repoItems = [];
} }
sortByName = (e) => { sortByName = (e) => {
@@ -86,13 +89,41 @@ class SharedRepoListView extends React.Component {
this.props.onItemRename(repo, newName); this.props.onItemRename(repo, newName);
}; };
setRepoItemRef = (index) => item => {
this.repoItems[index] = item;
};
getRepoIndex = (repo) => {
return this.props.repoList.findIndex(item => {
return item.repo_id === repo.repo_id;
});
};
onMenuItemClick = (operation, currentObject, event) => {
const index = this.getRepoIndex(currentObject);
if (this.repoItems[index]) {
this.repoItems[index].onMenuItemClick(event);
}
hideMenu();
};
onContextMenu = (event, repo) => {
event.preventDefault();
const { libraryType, currentGroup } = this.props;
const isPublic = libraryType === 'public';
const id = isPublic ? 'shared-repo-item-menu' : `shared-repo-item-menu-${currentGroup.id}`;
const menuList = Utils.getSharedRepoOperationList(repo, currentGroup, isPublic);
handleContextClick(event, id, menuList, repo);
};
renderRepoListView = () => { renderRepoListView = () => {
const { currentViewMode = LIST_MODE } = this.props; const { currentViewMode = LIST_MODE } = this.props;
return ( return (
<Fragment> <Fragment>
{this.props.repoList.map(repo => { {this.props.repoList.map((repo, index) => {
return ( return (
<SharedRepoListItem <SharedRepoListItem
ref={this.setRepoItemRef(index)}
key={repo.repo_id} key={repo.repo_id}
repo={repo} repo={repo}
libraryType={this.props.libraryType} libraryType={this.props.libraryType}
@@ -105,6 +136,7 @@ class SharedRepoListView extends React.Component {
onItemRename={this.props.onItemRename} onItemRename={this.props.onItemRename}
onMonitorRepo={this.props.onMonitorRepo} onMonitorRepo={this.props.onMonitorRepo}
currentViewMode={currentViewMode} currentViewMode={currentViewMode}
onContextMenu={this.onContextMenu}
/> />
); );
})} })}
@@ -113,10 +145,11 @@ class SharedRepoListView extends React.Component {
}; };
renderPCUI = () => { renderPCUI = () => {
const { theadHidden = false, currentViewMode = LIST_MODE } = this.props; const { theadHidden = false, currentViewMode = LIST_MODE, currentGroup, libraryType } = this.props;
const { sortByName, sortByTime, sortBySize, sortIcon } = this.getSortMetaData(); const { sortByName, sortByTime, sortBySize, sortIcon } = this.getSortMetaData();
return currentViewMode == LIST_MODE ? ( const content = currentViewMode == LIST_MODE ? (
<>
<table className={theadHidden ? 'table-thead-hidden' : ''}> <table className={theadHidden ? 'table-thead-hidden' : ''}>
<thead> <thead>
<tr> <tr>
@@ -133,11 +166,22 @@ class SharedRepoListView extends React.Component {
{this.renderRepoListView()} {this.renderRepoListView()}
</tbody> </tbody>
</table> </table>
</>
) : ( ) : (
<div className="d-flex justify-content-between flex-wrap"> <div className="d-flex justify-content-between flex-wrap">
{this.renderRepoListView()} {this.renderRepoListView()}
</div> </div>
); );
return (
<>
{content}
<ContextMenu
id={`${libraryType === 'public' ? 'shared-repo-item-menu' : `shared-repo-item-menu-${currentGroup.id}`}`}
onMenuItemClick={this.onMenuItemClick}
/>;
</>
);
}; };
renderMobileUI = () => { renderMobileUI = () => {

View File

@@ -129,6 +129,7 @@ class GroupItem extends React.Component {
{group.repos.length === 0 ? {group.repos.length === 0 ?
emptyTip : emptyTip :
<SharedRepoListView <SharedRepoListView
key={`group-${group.id}`}
inAllLibs={inAllLibs} inAllLibs={inAllLibs}
theadHidden={true} theadHidden={true}
isShowRepoOwner={false} isShowRepoOwner={false}

View File

@@ -34,6 +34,7 @@ const propTypes = {
onDeleteRepo: PropTypes.func.isRequired, onDeleteRepo: PropTypes.func.isRequired,
onTransferRepo: PropTypes.func.isRequired, onTransferRepo: PropTypes.func.isRequired,
onMonitorRepo: PropTypes.func.isRequired, onMonitorRepo: PropTypes.func.isRequired,
onContextMenu: PropTypes.func.isRequired,
}; };
class MylibRepoListItem extends React.Component { class MylibRepoListItem extends React.Component {
@@ -303,6 +304,10 @@ class MylibRepoListItem extends React.Component {
}); });
}; };
handleContextMenu = (event) => {
this.props.onContextMenu(event, this.props.repo);
};
renderPCUI = () => { renderPCUI = () => {
const { isStarred } = this.state; const { isStarred } = this.state;
const { repo, currentViewMode = LIST_MODE } = this.props; const { repo, currentViewMode = LIST_MODE } = this.props;
@@ -311,7 +316,7 @@ class MylibRepoListItem extends React.Component {
let iconTitle = Utils.getLibIconTitle(repo); let iconTitle = Utils.getLibIconTitle(repo);
let repoURL = `${siteRoot}library/${repo.repo_id}/${Utils.encodePath(repo.repo_name)}/`; let repoURL = `${siteRoot}library/${repo.repo_id}/${Utils.encodePath(repo.repo_name)}/`;
return currentViewMode == LIST_MODE ? ( return currentViewMode == LIST_MODE ? (
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave} onFocus={this.onFocus}> <tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave} onFocus={this.onFocus} onContextMenu={this.handleContextMenu}>
<td className="text-center"> <td className="text-center">
<i <i
role="button" role="button"
@@ -366,6 +371,7 @@ class MylibRepoListItem extends React.Component {
onMouseEnter={this.onMouseEnter} onMouseEnter={this.onMouseEnter}
onMouseLeave={this.onMouseLeave} onMouseLeave={this.onMouseLeave}
onFocus={this.onFocus} onFocus={this.onFocus}
onContextMenu={this.handleContextMenu}
> >
<div className="d-flex align-items-center text-truncate"> <div className="d-flex align-items-center text-truncate">
<img src={iconUrl} title={iconTitle} alt={iconTitle} width="36" className="mr-2" /> <img src={iconUrl} title={iconTitle} alt={iconTitle} width="36" className="mr-2" />

View File

@@ -5,6 +5,9 @@ import { gettext, storages } from '../../utils/constants';
import MylibRepoListItem from './mylib-repo-list-item'; import MylibRepoListItem from './mylib-repo-list-item';
import LibsMobileThead from '../../components/libs-mobile-thead'; import LibsMobileThead from '../../components/libs-mobile-thead';
import { LIST_MODE } from '../../components/dir-view-mode/constants'; import { LIST_MODE } from '../../components/dir-view-mode/constants';
import ContextMenu from '../../components/context-menu/context-menu';
import { Utils } from '../../utils/utils';
import { hideMenu, handleContextClick } from '../../components/context-menu/actions';
const propTypes = { const propTypes = {
sortBy: PropTypes.string.isRequired, sortBy: PropTypes.string.isRequired,
@@ -26,6 +29,7 @@ class MylibRepoListView extends React.Component {
this.state = { this.state = {
isItemFreezed: false, isItemFreezed: false,
}; };
this.repoItems = [];
} }
onFreezedItem = () => { onFreezedItem = () => {
@@ -57,12 +61,37 @@ class MylibRepoListView extends React.Component {
this.props.sortRepoList(sortBy, sortOrder); this.props.sortRepoList(sortBy, sortOrder);
}; };
onContextMenu = (event, repo) => {
event.preventDefault();
const id = 'mylib-repo-item-menu';
const menuList = Utils.getRepoOperationList(repo);
handleContextClick(event, id, menuList, repo);
};
setRepoItemRef = (index) => item => {
this.repoItems[index] = item;
};
getRepoIndex = (repo) => {
return this.props.repoList.findIndex(item => {
return item.repo_id === repo.repo_id;
});
};
onMenuItemClick = (operation, currentObject) => {
const index = this.getRepoIndex(currentObject);
this.repoItems[index].onMenuItemClick(operation);
hideMenu();
};
renderRepoListView = () => { renderRepoListView = () => {
return ( return (
<Fragment> <Fragment>
{this.props.repoList.map(item => { {this.props.repoList.map((item, index) => {
return ( return (
<MylibRepoListItem <MylibRepoListItem
ref={this.setRepoItemRef(index)}
key={item.repo_id} key={item.repo_id}
repo={item} repo={item}
isItemFreezed={this.state.isItemFreezed} isItemFreezed={this.state.isItemFreezed}
@@ -73,6 +102,7 @@ class MylibRepoListView extends React.Component {
onTransferRepo={this.props.onTransferRepo} onTransferRepo={this.props.onTransferRepo}
onMonitorRepo={this.props.onMonitorRepo} onMonitorRepo={this.props.onMonitorRepo}
currentViewMode={this.props.currentViewMode} currentViewMode={this.props.currentViewMode}
onContextMenu={this.onContextMenu}
/> />
); );
})} })}
@@ -130,6 +160,10 @@ class MylibRepoListView extends React.Component {
<MediaQuery query="(max-width: 767.8px)"> <MediaQuery query="(max-width: 767.8px)">
{this.renderMobileUI()} {this.renderMobileUI()}
</MediaQuery> </MediaQuery>
<ContextMenu
id="mylib-repo-item-menu"
onMenuItemClick={this.onMenuItemClick}
/>
</Fragment> </Fragment>
); );
} }

View File

@@ -17,6 +17,8 @@ import ShareDialog from '../../components/dialog/share-dialog';
import SortOptionsDialog from '../../components/dialog/sort-options'; import SortOptionsDialog from '../../components/dialog/sort-options';
import RepoMonitoredIcon from '../../components/repo-monitored-icon'; import RepoMonitoredIcon from '../../components/repo-monitored-icon';
import { GRID_MODE, LIST_MODE } from '../../components/dir-view-mode/constants'; import { GRID_MODE, LIST_MODE } from '../../components/dir-view-mode/constants';
import ContextMenu from '../../components/context-menu/context-menu';
import { hideMenu, handleContextClick } from '../../components/context-menu/actions';
class Content extends Component { class Content extends Component {
@@ -25,6 +27,7 @@ class Content extends Component {
this.state = { this.state = {
isItemFreezed: false isItemFreezed: false
}; };
this.libItems = [];
} }
freezeItem = (freezed) => { freezeItem = (freezed) => {
@@ -54,6 +57,30 @@ class Content extends Component {
this.props.sortItems(sortBy, sortOrder); this.props.sortItems(sortBy, sortOrder);
}; };
onContextMenu = (event, repo) => {
event.preventDefault();
const id = 'shared-libs-item-menu';
const menuList = Utils.getSharedLibsOperationList(repo);
handleContextClick(event, id, menuList, repo);
};
setLibItemRef = (index) => item => {
this.libItems[index] = item;
};
getLibIndex = (lib) => {
return this.props.items.findIndex(item => {
return item.repo_id === lib.repo_id;
});
};
onMenuItemClick = (operation, currentObject, event) => {
const index = this.getLibIndex(currentObject);
this.libItems[index].onMenuItemClick(operation, event);
hideMenu();
};
render() { render() {
const { loading, errorMsg, items, sortBy, sortOrder, theadHidden, inAllLibs, currentViewMode } = this.props; const { loading, errorMsg, items, sortBy, sortOrder, theadHidden, inAllLibs, currentViewMode } = this.props;
@@ -95,6 +122,7 @@ class Content extends Component {
<> <>
{items.map((item, index) => { {items.map((item, index) => {
return <Item return <Item
ref={this.setLibItemRef(index)}
key={index} key={index}
data={item} data={item}
isDesktop={isDesktop} isDesktop={isDesktop}
@@ -102,24 +130,35 @@ class Content extends Component {
freezeItem={this.freezeItem} freezeItem={this.freezeItem}
onMonitorRepo={this.props.onMonitorRepo} onMonitorRepo={this.props.onMonitorRepo}
currentViewMode={currentViewMode} currentViewMode={currentViewMode}
onContextMenu={this.onContextMenu}
/>; />;
})} })}
</> </>
); );
const content = currentViewMode == LIST_MODE ? ( const content = currentViewMode == LIST_MODE ? (
<>
<table className={(isDesktop && !theadHidden) ? '' : 'table-thead-hidden'}> <table className={(isDesktop && !theadHidden) ? '' : 'table-thead-hidden'}>
{isDesktop ? desktopThead : <LibsMobileThead inAllLibs={inAllLibs} />} {isDesktop ? desktopThead : <LibsMobileThead inAllLibs={inAllLibs} />}
<tbody> <tbody>
{itemsContent} {itemsContent}
</tbody> </tbody>
</table> </table>
</>
) : ( ) : (
<div className="d-flex justify-content-between flex-wrap"> <div className="d-flex justify-content-between flex-wrap">
{itemsContent} {itemsContent}
</div> </div>
); );
return items.length ? content : emptyTip; return items.length ? (
<>
{content}
<ContextMenu
id="shared-libs-item-menu"
onMenuItemClick={this.onMenuItemClick}
/>
</>
) : emptyTip;
} }
} }
} }
@@ -265,6 +304,29 @@ class Item extends Component {
}); });
}; };
handleContextMenu = (event) => {
this.props.onContextMenu(event, this.props.data);
};
onMenuItemClick = (operation, event) => {
switch (operation) {
case 'Share':
this.share(event);
break;
case 'Unshare':
this.leaveShare(event);
break;
case 'Watch File Changes':
this.watchFileChanges();
break;
case 'Unwatch File Changes':
this.unwatchFileChanges();
break;
default:
break;
}
};
render() { render() {
if (this.state.unshared) { if (this.state.unshared) {
return null; return null;
@@ -288,7 +350,7 @@ class Item extends Component {
return ( return (
<Fragment> <Fragment>
{currentViewMode == LIST_MODE ? ( {currentViewMode == LIST_MODE ? (
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut} onFocus={this.handleMouseOver}> <tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut} onFocus={this.handleMouseOver} onContextMenu={this.handleContextMenu}>
<td className="text-center"> <td className="text-center">
<i <i
role="button" role="button"
@@ -339,6 +401,7 @@ class Item extends Component {
onMouseOver={this.handleMouseOver} onMouseOver={this.handleMouseOver}
onMouseOut={this.handleMouseOut} onMouseOut={this.handleMouseOut}
onFocus={this.handleMouseOver} onFocus={this.handleMouseOver}
onContextMenu={this.handleContextMenu}
> >
<div className="d-flex align-items-center text-truncate"> <div className="d-flex align-items-center text-truncate">
<img src={data.icon_url} title={data.icon_title} alt={data.icon_title} width="36" className="mr-2" /> <img src={data.icon_url} title={data.icon_title} alt={data.icon_title} width="36" className="mr-2" />
@@ -459,7 +522,8 @@ Item.propTypes = {
data: PropTypes.object.isRequired, data: PropTypes.object.isRequired,
isItemFreezed: PropTypes.bool.isRequired, isItemFreezed: PropTypes.bool.isRequired,
freezeItem: PropTypes.func.isRequired, freezeItem: PropTypes.func.isRequired,
onMonitorRepo: PropTypes.func.isRequired onMonitorRepo: PropTypes.func.isRequired,
onContextMenu: PropTypes.func.isRequired,
}; };
class SharedLibraries extends Component { class SharedLibraries extends Component {

View File

@@ -138,6 +138,7 @@ class PublicSharedView extends React.Component {
{(!this.state.isLoading && this.state.repoList.length === 0) && emptyTip} {(!this.state.isLoading && this.state.repoList.length === 0) && emptyTip}
{(!this.state.isLoading && this.state.repoList.length > 0) && {(!this.state.isLoading && this.state.repoList.length > 0) &&
<SharedRepoListView <SharedRepoListView
key='public-shared-view'
libraryType={this.state.libraryType} libraryType={this.state.libraryType}
repoList={this.state.repoList} repoList={this.state.repoList}
sortBy={this.state.sortBy} sortBy={this.state.sortBy}

View File

@@ -135,6 +135,63 @@ const TextTranslation = {
key: 'Export sdoc', key: 'Export sdoc',
value: gettext('Export as zip') value: gettext('Export as zip')
}, },
// repo operations
'TRANSFER': {
key: 'Transfer',
value: gettext('Transfer')
},
'FOLDER_PERMISSION': {
key: 'Folder Permission',
value: gettext('Folder Permission')
},
'SHARE_ADMIN': {
key: 'Share Admin',
value: gettext('Share Admin')
},
'CHANGE_PASSWORD': {
key: 'Change Password',
value: gettext('Change Password')
},
'RESET_PASSWORD': {
key: 'Reset Password',
value: gettext('Reset Password')
},
'UNWATCH_FILE_CHANGES': {
key: 'Unwatch File Changes',
value: gettext('Unwatch File Changes')
},
'WATCH_FILE_CHANGES': {
key: 'Watch File Changes',
value: gettext('Watch File Changes')
},
'HISTORY_SETTING': {
key: 'History Setting',
value: gettext('History Setting')
},
'ADVANCED': {
key: 'advanced',
value: gettext('Advanced')
},
// advanced operations
'API_TOKEN': {
key: 'API Token',
value: gettext('API Token')
},
'LABEL_CURRENT_STATE': {
key: 'Label Current State',
value: gettext('Label Current State')
},
'OLD_FILES_AUTO_DELETE': {
key: 'Old Files Auto Delete',
value: gettext('Old Files Auto Delete')
},
'UNSHARE': {
key: 'Unshare',
value: gettext('Unshare')
},
}; };
export default TextTranslation; export default TextTranslation;

View File

@@ -1,4 +1,4 @@
import { mediaUrl, gettext, serviceURL, siteRoot, isPro, fileAuditEnabled, canGenerateShareLink, canGenerateUploadLink, shareLinkPasswordMinLength, username, folderPermEnabled, onlyofficeConverterExtensions, enableOnlyoffice, enableSeadoc, enableFileTags } from './constants'; import { mediaUrl, gettext, serviceURL, siteRoot, isPro, fileAuditEnabled, canGenerateShareLink, canGenerateUploadLink, shareLinkPasswordMinLength, username, folderPermEnabled, onlyofficeConverterExtensions, enableOnlyoffice, enableSeadoc, enableFileTags, enableRepoSnapshotLabel, enableRepoAutoDel, enableResetEncryptedRepoPassword, isEmailConfigured, isSystemStaff } from './constants';
import TextTranslation from './text-translation'; import TextTranslation from './text-translation';
import React from 'react'; import React from 'react';
import toaster from '../components/toast'; import toaster from '../components/toast';
@@ -716,6 +716,154 @@ export const Utils = {
return operationListGetter(isRepoOwner, currentRepoInfo, dirent, isContextmenu); return operationListGetter(isRepoOwner, currentRepoInfo, dirent, isContextmenu);
}, },
getRepoOperationList: function (repo) {
const showResetPasswordMenuItem = isPro && repo.encrypted && enableResetEncryptedRepoPassword && isEmailConfigured;
const operations = [];
const DIVIDER = 'Divider';
const { SHARE, DELETE, RENAME, TRANSFER, FOLDER_PERMISSION, SHARE_ADMIN, CHANGE_PASSWORD, RESET_PASSWORD, UNWATCH_FILE_CHANGES, WATCH_FILE_CHANGES, HISTORY_SETTING, ADVANCED } = TextTranslation;
operations.push(SHARE, DELETE, DIVIDER, RENAME, TRANSFER);
if (folderPermEnabled) {
operations.push(FOLDER_PERMISSION);
}
operations.push(SHARE_ADMIN, DIVIDER);
if (repo.encrypted) {
operations.push(CHANGE_PASSWORD);
}
if (showResetPasswordMenuItem) {
operations.push(RESET_PASSWORD);
}
if (isPro) {
const monitorOp = repo.monitored ? UNWATCH_FILE_CHANGES : WATCH_FILE_CHANGES;
operations.push(monitorOp);
}
operations.push(DIVIDER, HISTORY_SETTING);
const subOpList = Utils.getAdvancedOperations();
operations.push({ ...ADVANCED, subOpList });
// Remove adjacent excess 'Divider'
return operations.filter((op, i, arr) => !(op === DIVIDER && arr[i + 1] === DIVIDER));
},
getAdvancedOperations: function () {
const operations = [];
const { API_TOKEN, LABEL_CURRENT_STATE, OLD_FILES_AUTO_DELETE } = TextTranslation;
operations.push(API_TOKEN);
if (enableRepoSnapshotLabel) {
operations.push(LABEL_CURRENT_STATE);
}
if (enableRepoAutoDel) {
operations.push(OLD_FILES_AUTO_DELETE);
}
return operations;
},
getSharedLibsOperationList: function (lib) {
const { SHARE, UNSHARE, WATCH_FILE_CHANGES, UNWATCH_FILE_CHANGES } = TextTranslation;
const operations = [];
if (isPro && lib.is_admin) {
operations.push(SHARE);
}
operations.push(UNSHARE);
const monitorOp = lib.monitored ? UNWATCH_FILE_CHANGES : WATCH_FILE_CHANGES;
operations.push(monitorOp);
return operations;
},
getPublicSharedRepoOperationList: function (repo) {
const { UNSHARE } = TextTranslation;
const operations = [];
const isRepoOwner = repo.owner_email === username;
if (isSystemStaff || isRepoOwner) {
operations.push(UNSHARE);
}
return operations;
},
getSharedRepoOperationList: function (repo, currentGroup, isPublic) {
const operations = [];
const { SHARE, UNSHARE, DELETE, RENAME, FOLDER_PERMISSION, SHARE_ADMIN, UNWATCH_FILE_CHANGES, WATCH_FILE_CHANGES, HISTORY_SETTING, ADVANCED, CHANGE_PASSWORD, RESET_PASSWORD } = TextTranslation;
const isStaff = currentGroup && currentGroup.admins && currentGroup.admins.indexOf(username) > -1;
const isRepoOwner = repo.owner_email === username;
const isAdmin = repo.is_admin;
const DIVIDER = 'Divider';
if (isPublic) {
if (isSystemStaff || isRepoOwner) {
operations.push(UNSHARE);
}
return operations;
}
if (isPro) {
if (repo.owner_email.indexOf('@seafile_group') !== -1) {
// is group admin
if (isStaff) {
if (repo.owner_email === `${currentGroup.id}@seafile_group`) {
operations.push(SHARE, DELETE, RENAME);
if (folderPermEnabled) {
operations.push(FOLDER_PERMISSION);
}
operations.push(SHARE_ADMIN, DIVIDER);
if (repo.encrypted) {
operations.push(CHANGE_PASSWORD);
}
if (repo.encrypted && enableResetEncryptedRepoPassword && isEmailConfigured) {
operations.push(RESET_PASSWORD);
}
if (repo.permission === 'r' || repo.permission === 'rw') {
const monitorOp = repo.monitored ? UNWATCH_FILE_CHANGES : WATCH_FILE_CHANGES;
operations.push(monitorOp);
}
operations.push(DIVIDER, HISTORY_SETTING);
if (Utils.isDesktop()) {
const subOpList = Utils.getAdvancedOperations();
operations.push({ ...ADVANCED, subOpList });
}
return operations;
} else {
operations.push(UNSHARE);
}
}
} else {
if (isRepoOwner || isAdmin) {
operations.push(SHARE);
}
if (isStaff || isRepoOwner || isAdmin) {
operations.push(UNSHARE);
}
}
if (repo.permission === 'r' || repo.permission === 'rw') {
const monitorOp = repo.monitored ? UNWATCH_FILE_CHANGES : WATCH_FILE_CHANGES;
operations.push(monitorOp);
}
} else {
if (isRepoOwner) {
operations.push(SHARE);
}
if (isStaff || isRepoOwner) {
operations.push(UNSHARE);
}
}
return operations;
},
sharePerms: function (permission) { sharePerms: function (permission) {
var title; var title;
switch (permission) { switch (permission) {