mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-24 04:48:03 +00:00
Library view more menu (#7806)
* [library view] added the 'More' menu('more' operations for the current library) * add monitored field when get repo info --------- Co-authored-by: lian <imwhatiam123@gmail.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Modal, ModalBody, ModalFooter, Alert } from 'reactstrap';
|
import { Button, Modal, ModalBody, ModalFooter, Alert } from 'reactstrap';
|
||||||
import { gettext, repoPasswordMinLength } from '../../utils/constants';
|
import { gettext, repoPasswordMinLength } from '../../utils/constants';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
@@ -137,6 +137,7 @@ class ChangeRepoPasswordDialog extends React.Component {
|
|||||||
</form>
|
</form>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
|
<Button color="secondary" onClick={this.props.toggleDialog}>{gettext('Cancel')}</Button>
|
||||||
<button className="btn btn-primary" disabled={this.state.submitBtnDisabled} onClick={this.formSubmit}>{gettext('Submit')}</button>
|
<button className="btn btn-primary" disabled={this.state.submitBtnDisabled} onClick={this.formSubmit}>{gettext('Submit')}</button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
76
frontend/src/components/dialog/rename-repo.js
Normal file
76
frontend/src/components/dialog/rename-repo.js
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { gettext } from '../../utils/constants';
|
||||||
|
import { validateName } from '../../utils/utils';
|
||||||
|
import { Button, Input, Label, Modal, ModalBody, ModalFooter, Alert } from 'reactstrap';
|
||||||
|
import SeahubModalHeader from '@/components/common/seahub-modal-header';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
renameRepo: PropTypes.func.isRequired,
|
||||||
|
toggleDialog: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
class Rename extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
name: props.name,
|
||||||
|
errMessage: '',
|
||||||
|
isSubmitBtnActive: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange = (e) => {
|
||||||
|
if (!e.target.value.trim()) {
|
||||||
|
this.setState({ isSubmitBtnActive: false });
|
||||||
|
} else {
|
||||||
|
this.setState({ isSubmitBtnActive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ name: e.target.value });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleSubmit = () => {
|
||||||
|
let name = this.state.name.trim();
|
||||||
|
let { isValid, errMessage } = validateName(name);
|
||||||
|
if (!isValid) {
|
||||||
|
this.setState({ errMessage });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.props.renameRepo(name);
|
||||||
|
this.toggle();
|
||||||
|
};
|
||||||
|
|
||||||
|
handleKeyDown = (e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
this.handleSubmit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
toggle = () => {
|
||||||
|
this.props.toggleDialog();
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Modal isOpen={true} toggle={this.toggle}>
|
||||||
|
<SeahubModalHeader toggle={this.toggle}>{gettext('Rename Library')}</SeahubModalHeader>
|
||||||
|
<ModalBody>
|
||||||
|
<Label for="repo-name">{gettext('Name')}</Label>
|
||||||
|
<Input id="repo-name" onKeyDown={this.handleKeyDown} value={this.state.name} onChange={this.handleChange} />
|
||||||
|
{this.state.errMessage && <Alert color="danger" className="mt-2">{this.state.errMessage}</Alert>}
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter>
|
||||||
|
<Button color="secondary" onClick={this.toggle}>{gettext('Cancel')}</Button>
|
||||||
|
<Button color="primary" onClick={this.handleSubmit} disabled={!this.state.isSubmitBtnActive}>{gettext('Submit')}</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rename.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default Rename;
|
@@ -1,20 +1,20 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Button, Modal, ModalBody, ModalFooter, TabContent, TabPane } from 'reactstrap';
|
import { Button, Modal, ModalBody, ModalFooter, TabContent, TabPane } from 'reactstrap';
|
||||||
import SeahubModalHeader from '../common/seahub-modal-header';
|
|
||||||
import makeAnimated from 'react-select/animated';
|
import makeAnimated from 'react-select/animated';
|
||||||
|
import toaster from '../toast';
|
||||||
import { userAPI } from '../../utils/user-api';
|
import { userAPI } from '../../utils/user-api';
|
||||||
import { gettext, isPro } from '../../utils/constants';
|
import { gettext, isPro } from '../../utils/constants';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
import toaster from '../toast';
|
|
||||||
import { SeahubSelect } from '../common/select';
|
import { SeahubSelect } from '../common/select';
|
||||||
|
import SeahubModalHeader from '../common/seahub-modal-header';
|
||||||
|
|
||||||
import '../../css/repo-office-suite-dialog.css';
|
import '../../css/repo-office-suite-dialog.css';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
itemName: PropTypes.string.isRequired,
|
|
||||||
toggleDialog: PropTypes.func.isRequired,
|
|
||||||
submit: PropTypes.func.isRequired,
|
|
||||||
repoID: PropTypes.string.isRequired,
|
repoID: PropTypes.string.isRequired,
|
||||||
|
repoName: PropTypes.string.isRequired,
|
||||||
|
toggleDialog: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
class OfficeSuiteDialog extends React.Component {
|
class OfficeSuiteDialog extends React.Component {
|
||||||
@@ -32,8 +32,21 @@ class OfficeSuiteDialog extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
submit = () => {
|
submit = () => {
|
||||||
let suite_id = this.state.selectedOption.value;
|
const { repoID } = this.props;
|
||||||
this.props.submit(suite_id);
|
const { selectedOption } = this.state;
|
||||||
|
if (!selectedOption) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { value: suiteID } = selectedOption;
|
||||||
|
userAPI.setOfficeSuite(repoID, suiteID).then(res => {
|
||||||
|
const message = gettext('Successfully changed the office suite.');
|
||||||
|
toaster.success(message);
|
||||||
|
}).catch(error => {
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
});
|
||||||
|
this.props.toggleDialog();
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@@ -72,7 +85,7 @@ class OfficeSuiteDialog extends React.Component {
|
|||||||
maxMenuHeight={200}
|
maxMenuHeight={200}
|
||||||
hideSelectedOptions={true}
|
hideSelectedOptions={true}
|
||||||
components={makeAnimated()}
|
components={makeAnimated()}
|
||||||
placeholder={gettext('Select a office suite')}
|
placeholder={gettext('Select an office suite')}
|
||||||
options={this.options}
|
options={this.options}
|
||||||
onChange={this.handleSelectChange}
|
onChange={this.handleSelectChange}
|
||||||
value={this.state.selectedOption}
|
value={this.state.selectedOption}
|
||||||
@@ -86,7 +99,7 @@ class OfficeSuiteDialog extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { itemName: repoName } = this.props;
|
const { repoName } = this.props;
|
||||||
let title = gettext('{library_name} Office Suite');
|
let title = gettext('{library_name} Office Suite');
|
||||||
title = title.replace('{library_name}', '<span class="op-target text-truncate mx-1">' + Utils.HTMLescape(repoName) + '</span>');
|
title = title.replace('{library_name}', '<span class="op-target text-truncate mx-1">' + Utils.HTMLescape(repoName) + '</span>');
|
||||||
return (
|
return (
|
||||||
|
@@ -66,6 +66,7 @@ class TransferDialog extends React.Component {
|
|||||||
const { activeTab, reshare, selectedOption, selectedUsers } = this.state;
|
const { activeTab, reshare, selectedOption, selectedUsers } = this.state;
|
||||||
const email = activeTab === TRANS_DEPART ? selectedOption.value : selectedUsers[0].email;
|
const email = activeTab === TRANS_DEPART ? selectedOption.value : selectedUsers[0].email;
|
||||||
this.props.onTransferRepo(email, reshare);
|
this.props.onTransferRepo(email, reshare);
|
||||||
|
this.props.toggleDialog();
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@@ -33,6 +33,7 @@ const propTypes = {
|
|||||||
getMenuContainerSize: PropTypes.func,
|
getMenuContainerSize: PropTypes.func,
|
||||||
updateDirent: PropTypes.func,
|
updateDirent: PropTypes.func,
|
||||||
updateTreeNode: PropTypes.func,
|
updateTreeNode: PropTypes.func,
|
||||||
|
updateRepoInfo: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
class DirColumnNav extends React.Component {
|
class DirColumnNav extends React.Component {
|
||||||
@@ -76,7 +77,7 @@ class DirColumnNav extends React.Component {
|
|||||||
/>
|
/>
|
||||||
<DirViews repoID={repoID} currentPath={currentPath} userPerm={userPerm} currentRepoInfo={currentRepoInfo} />
|
<DirViews repoID={repoID} currentPath={currentPath} userPerm={userPerm} currentRepoInfo={currentRepoInfo} />
|
||||||
<DirTags repoID={repoID} currentPath={currentPath} userPerm={userPerm} currentRepoInfo={currentRepoInfo} />
|
<DirTags repoID={repoID} currentPath={currentPath} userPerm={userPerm} currentRepoInfo={currentRepoInfo} />
|
||||||
<DirOthers repoID={repoID} userPerm={userPerm} currentRepoInfo={currentRepoInfo} />
|
<DirOthers repoID={repoID} userPerm={userPerm} currentRepoInfo={currentRepoInfo} updateRepoInfo={this.props.updateRepoInfo} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@@ -86,6 +86,7 @@ const propTypes = {
|
|||||||
updateCurrentPath: PropTypes.func,
|
updateCurrentPath: PropTypes.func,
|
||||||
toggleShowDirentToolbar: PropTypes.func,
|
toggleShowDirentToolbar: PropTypes.func,
|
||||||
updateTreeNode: PropTypes.func,
|
updateTreeNode: PropTypes.func,
|
||||||
|
updateRepoInfo: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
class DirColumnView extends React.Component {
|
class DirColumnView extends React.Component {
|
||||||
@@ -177,6 +178,7 @@ class DirColumnView extends React.Component {
|
|||||||
navRate={navRate}
|
navRate={navRate}
|
||||||
inResizing={inResizing}
|
inResizing={inResizing}
|
||||||
currentRepoInfo={this.props.currentRepoInfo}
|
currentRepoInfo={this.props.currentRepoInfo}
|
||||||
|
updateRepoInfo={this.props.updateRepoInfo}
|
||||||
onItemMove={this.props.onItemMove}
|
onItemMove={this.props.onItemMove}
|
||||||
onItemCopy={this.props.onItemCopy}
|
onItemCopy={this.props.onItemCopy}
|
||||||
selectedDirentList={this.props.selectedDirentList}
|
selectedDirentList={this.props.selectedDirentList}
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dir-others .dir-others-item[aria-expanded="true"], /* for 'More' */
|
||||||
.dir-others .dir-others-item:hover {
|
.dir-others .dir-others-item:hover {
|
||||||
background-color: #f0f0f0;
|
background-color: #f0f0f0;
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useEffect, useCallback } from 'react';
|
import React, { useState, useEffect, useCallback } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { gettext } from '../../../utils/constants';
|
import { gettext, username } from '../../../utils/constants';
|
||||||
import { Utils } from '../../../utils/utils';
|
import { Utils } from '../../../utils/utils';
|
||||||
import TreeSection from '../../tree-section';
|
import TreeSection from '../../tree-section';
|
||||||
import TrashDialog from '../../dialog/trash-dialog';
|
import TrashDialog from '../../dialog/trash-dialog';
|
||||||
@@ -9,13 +9,14 @@ import RepoHistoryDialog from '../../dialog/repo-history';
|
|||||||
import { eventBus } from '../../common/event-bus';
|
import { eventBus } from '../../common/event-bus';
|
||||||
import { EVENT_BUS_TYPE } from '../../common/event-bus-type';
|
import { EVENT_BUS_TYPE } from '../../common/event-bus-type';
|
||||||
import { TAB } from '../../../constants/repo-setting-tabs';
|
import { TAB } from '../../../constants/repo-setting-tabs';
|
||||||
|
import LibraryMoreOperations from './library-more-operations';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
const DirOthers = ({ userPerm, repoID, currentRepoInfo }) => {
|
const DirOthers = ({ userPerm, repoID, currentRepoInfo, updateRepoInfo }) => {
|
||||||
|
const { owner_email, is_admin, repo_name: repoName } = currentRepoInfo;
|
||||||
|
|
||||||
const showSettings = currentRepoInfo.is_admin; // repo owner, department admin, shared with 'Admin' permission
|
const showSettings = is_admin; // repo owner, department admin, shared with 'Admin' permission
|
||||||
const repoName = currentRepoInfo.repo_name;
|
|
||||||
let [isSettingsDialogOpen, setSettingsDialogOpen] = useState(false);
|
let [isSettingsDialogOpen, setSettingsDialogOpen] = useState(false);
|
||||||
let [activeTab, setActiveTab] = useState(TAB.HISTORY_SETTING);
|
let [activeTab, setActiveTab] = useState(TAB.HISTORY_SETTING);
|
||||||
let [showMigrateTip, setShowMigrateTip] = useState(false);
|
let [showMigrateTip, setShowMigrateTip] = useState(false);
|
||||||
@@ -51,6 +52,9 @@ const DirOthers = ({ userPerm, repoID, currentRepoInfo }) => {
|
|||||||
setRepoHistoryDialogOpen(!isRepoHistoryDialogOpen);
|
setRepoHistoryDialogOpen(!isRepoHistoryDialogOpen);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isDesktop = Utils.isDesktop();
|
||||||
|
const isRepoOwner = owner_email == username;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TreeSection title={gettext('Others')} className="dir-others">
|
<TreeSection title={gettext('Others')} className="dir-others">
|
||||||
{showSettings && (
|
{showSettings && (
|
||||||
@@ -65,12 +69,18 @@ const DirOthers = ({ userPerm, repoID, currentRepoInfo }) => {
|
|||||||
<span className="dir-others-item-text">{gettext('Trash')}</span>
|
<span className="dir-others-item-text">{gettext('Trash')}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{Utils.isDesktop() && (
|
{isDesktop && (
|
||||||
<div className='dir-others-item text-nowrap' title={gettext('History')} onClick={toggleRepoHistoryDialog}>
|
<div className='dir-others-item text-nowrap' title={gettext('History')} onClick={toggleRepoHistoryDialog}>
|
||||||
<span className="sf3-font-history sf3-font"></span>
|
<span className="sf3-font-history sf3-font"></span>
|
||||||
<span className="dir-others-item-text">{gettext('History')}</span>
|
<span className="dir-others-item-text">{gettext('History')}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{isDesktop && isRepoOwner && (
|
||||||
|
<LibraryMoreOperations
|
||||||
|
repo={currentRepoInfo}
|
||||||
|
updateRepoInfo={updateRepoInfo}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{showTrashDialog && (
|
{showTrashDialog && (
|
||||||
<TrashDialog
|
<TrashDialog
|
||||||
repoID={repoID}
|
repoID={repoID}
|
||||||
@@ -105,6 +115,7 @@ DirOthers.propTypes = {
|
|||||||
userPerm: PropTypes.string,
|
userPerm: PropTypes.string,
|
||||||
repoID: PropTypes.string,
|
repoID: PropTypes.string,
|
||||||
currentRepoInfo: PropTypes.object.isRequired,
|
currentRepoInfo: PropTypes.object.isRequired,
|
||||||
|
updateRepoInfo: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DirOthers;
|
export default DirOthers;
|
||||||
|
@@ -0,0 +1,278 @@
|
|||||||
|
import React, { Fragment } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { navigate } from '@gatsbyjs/reach-router';
|
||||||
|
import { Utils } from '../../../utils/utils';
|
||||||
|
import { seafileAPI } from '../../../utils/seafile-api';
|
||||||
|
import { gettext, siteRoot } from '../../../utils/constants';
|
||||||
|
import ModalPortal from '../../../components/modal-portal';
|
||||||
|
import toaster from '../../../components/toast';
|
||||||
|
import RenameRepoDialog from '../../../components/dialog/rename-repo';
|
||||||
|
import TransferDialog from '../../../components/dialog/transfer-dialog';
|
||||||
|
import ChangeRepoPasswordDialog from '../../../components/dialog/change-repo-password-dialog';
|
||||||
|
import ResetEncryptedRepoPasswordDialog from '../../../components/dialog/reset-encrypted-repo-password-dialog';
|
||||||
|
import LabelRepoStateDialog from '../../../components/dialog/label-repo-state-dialog';
|
||||||
|
import LibSubFolderPermissionDialog from '../../../components/dialog/lib-sub-folder-permission-dialog';
|
||||||
|
import RepoAPITokenDialog from '../../../components/dialog/repo-api-token-dialog';
|
||||||
|
import RepoShareAdminDialog from '../../../components/dialog/repo-share-admin-dialog';
|
||||||
|
import OfficeSuiteDialog from '../../../components/dialog/repo-office-suite-dialog';
|
||||||
|
import { userAPI } from '../../../utils/user-api';
|
||||||
|
import MylibRepoMenu from '../../../pages/my-libs/mylib-repo-menu';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
repo: PropTypes.object.isRequired,
|
||||||
|
updateRepoInfo: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
class LibraryMoreOperations extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isRenameRepoDialogOpen: false,
|
||||||
|
isTransferDialogOpen: false,
|
||||||
|
isChangePasswordDialogOpen: false,
|
||||||
|
isResetPasswordDialogOpen: false,
|
||||||
|
isLabelRepoStateDialogOpen: false,
|
||||||
|
isFolderPermissionDialogOpen: false,
|
||||||
|
isAPITokenDialogOpen: false,
|
||||||
|
isRepoShareAdminDialogOpen: false,
|
||||||
|
isOfficeSuiteDialogOpen: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onMenuItemClick = (item) => {
|
||||||
|
switch (item) {
|
||||||
|
case 'Rename':
|
||||||
|
this.onRenameToggle();
|
||||||
|
break;
|
||||||
|
case 'Transfer':
|
||||||
|
this.onTransferToggle();
|
||||||
|
break;
|
||||||
|
case 'Folder Permission':
|
||||||
|
this.onFolderPermissionToggle();
|
||||||
|
break;
|
||||||
|
case 'Share Admin':
|
||||||
|
this.toggleRepoShareAdminDialog();
|
||||||
|
break;
|
||||||
|
case 'Change Password':
|
||||||
|
this.onChangePasswordToggle();
|
||||||
|
break;
|
||||||
|
case 'Reset Password':
|
||||||
|
this.onResetPasswordToggle();
|
||||||
|
break;
|
||||||
|
case 'Watch File Changes':
|
||||||
|
this.watchFileChanges();
|
||||||
|
break;
|
||||||
|
case 'Unwatch File Changes':
|
||||||
|
this.unwatchFileChanges();
|
||||||
|
break;
|
||||||
|
case 'API Token':
|
||||||
|
this.onAPITokenToggle();
|
||||||
|
break;
|
||||||
|
case 'Label Current State':
|
||||||
|
this.onLabelToggle();
|
||||||
|
break;
|
||||||
|
case 'Office Suite':
|
||||||
|
this.onOfficeSuiteToggle();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watchFileChanges = () => {
|
||||||
|
const { repo } = this.props;
|
||||||
|
seafileAPI.monitorRepo(repo.repo_id).then(() => {
|
||||||
|
this.props.updateRepoInfo({ 'monitored': true });
|
||||||
|
const message = gettext('Successfully watched the library.');
|
||||||
|
toaster.success(message);
|
||||||
|
}).catch(error => {
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
unwatchFileChanges = () => {
|
||||||
|
const { repo } = this.props;
|
||||||
|
seafileAPI.unMonitorRepo(repo.repo_id).then(() => {
|
||||||
|
this.props.updateRepoInfo({ 'monitored': false });
|
||||||
|
const message = gettext('Successfully unwatched the library.');
|
||||||
|
toaster.success(message);
|
||||||
|
}).catch(error => {
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onRenameToggle = () => {
|
||||||
|
this.setState({ isRenameRepoDialogOpen: !this.state.isRenameRepoDialogOpen });
|
||||||
|
};
|
||||||
|
|
||||||
|
onTransferToggle = () => {
|
||||||
|
this.setState({ isTransferDialogOpen: !this.state.isTransferDialogOpen });
|
||||||
|
};
|
||||||
|
|
||||||
|
onChangePasswordToggle = () => {
|
||||||
|
this.setState({ isChangePasswordDialogOpen: !this.state.isChangePasswordDialogOpen });
|
||||||
|
};
|
||||||
|
|
||||||
|
onResetPasswordToggle = () => {
|
||||||
|
this.setState({ isResetPasswordDialogOpen: !this.state.isResetPasswordDialogOpen });
|
||||||
|
};
|
||||||
|
|
||||||
|
onLabelToggle = () => {
|
||||||
|
this.setState({ isLabelRepoStateDialogOpen: !this.state.isLabelRepoStateDialogOpen });
|
||||||
|
};
|
||||||
|
|
||||||
|
onFolderPermissionToggle = () => {
|
||||||
|
this.setState({ isFolderPermissionDialogOpen: !this.state.isFolderPermissionDialogOpen });
|
||||||
|
};
|
||||||
|
|
||||||
|
onAPITokenToggle = () => {
|
||||||
|
this.setState({ isAPITokenDialogOpen: !this.state.isAPITokenDialogOpen });
|
||||||
|
};
|
||||||
|
|
||||||
|
onOfficeSuiteToggle = () => {
|
||||||
|
this.setState({ isOfficeSuiteDialogOpen: !this.state.isOfficeSuiteDialogOpen });
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleRepoShareAdminDialog = () => {
|
||||||
|
this.setState({ isRepoShareAdminDialogOpen: !this.state.isRepoShareAdminDialogOpen });
|
||||||
|
};
|
||||||
|
|
||||||
|
renameRepo = (newName) => {
|
||||||
|
const { repo } = this.props;
|
||||||
|
const { repo_id: repoID } = repo;
|
||||||
|
seafileAPI.renameRepo(repoID, newName).then((res) => {
|
||||||
|
this.props.updateRepoInfo({ 'repo_name': newName });
|
||||||
|
const message = gettext('Successfully renamed the library.');
|
||||||
|
toaster.success(message);
|
||||||
|
}).catch(error => {
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onTransferRepo = (email, reshare) => {
|
||||||
|
const { repo } = this.props;
|
||||||
|
const { repo_id: repoID } = repo;
|
||||||
|
userAPI.transferRepo(repoID, email, reshare).then(res => {
|
||||||
|
const message = gettext('Successfully transferred the library.');
|
||||||
|
toaster.success(message);
|
||||||
|
navigate(siteRoot);
|
||||||
|
}).catch(error => {
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { repo } = this.props;
|
||||||
|
const {
|
||||||
|
isRenameRepoDialogOpen, isTransferDialogOpen
|
||||||
|
} = this.state;
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<MylibRepoMenu
|
||||||
|
isPC={true}
|
||||||
|
isLibView={true}
|
||||||
|
repo={repo}
|
||||||
|
onMenuItemClick={this.onMenuItemClick}
|
||||||
|
>
|
||||||
|
<>
|
||||||
|
<span className="sf3-font-more sf3-font"></span>
|
||||||
|
<span className="dir-others-item-text">{gettext('More')}</span>
|
||||||
|
</>
|
||||||
|
</MylibRepoMenu>
|
||||||
|
{isRenameRepoDialogOpen && (
|
||||||
|
<ModalPortal>
|
||||||
|
<RenameRepoDialog
|
||||||
|
name={repo.repo_name}
|
||||||
|
renameRepo={this.renameRepo}
|
||||||
|
toggleDialog={this.onRenameToggle}
|
||||||
|
/>
|
||||||
|
</ModalPortal>
|
||||||
|
)}
|
||||||
|
{isTransferDialogOpen && (
|
||||||
|
<ModalPortal>
|
||||||
|
<TransferDialog
|
||||||
|
itemName={repo.repo_name}
|
||||||
|
onTransferRepo={this.onTransferRepo}
|
||||||
|
toggleDialog={this.onTransferToggle}
|
||||||
|
/>
|
||||||
|
</ModalPortal>
|
||||||
|
)}
|
||||||
|
{this.state.isChangePasswordDialogOpen && (
|
||||||
|
<ModalPortal>
|
||||||
|
<ChangeRepoPasswordDialog
|
||||||
|
repoID={repo.repo_id}
|
||||||
|
repoName={repo.repo_name}
|
||||||
|
toggleDialog={this.onChangePasswordToggle}
|
||||||
|
/>
|
||||||
|
</ModalPortal>
|
||||||
|
)}
|
||||||
|
{this.state.isResetPasswordDialogOpen && (
|
||||||
|
<ModalPortal>
|
||||||
|
<ResetEncryptedRepoPasswordDialog
|
||||||
|
repoID={repo.repo_id}
|
||||||
|
toggleDialog={this.onResetPasswordToggle}
|
||||||
|
/>
|
||||||
|
</ModalPortal>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{this.state.isLabelRepoStateDialogOpen && (
|
||||||
|
<ModalPortal>
|
||||||
|
<LabelRepoStateDialog
|
||||||
|
repoID={repo.repo_id}
|
||||||
|
repoName={repo.repo_name}
|
||||||
|
toggleDialog={this.onLabelToggle}
|
||||||
|
/>
|
||||||
|
</ModalPortal>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{this.state.isFolderPermissionDialogOpen && (
|
||||||
|
<ModalPortal>
|
||||||
|
<LibSubFolderPermissionDialog
|
||||||
|
toggleDialog={this.onFolderPermissionToggle}
|
||||||
|
repoID={repo.repo_id}
|
||||||
|
repoName={repo.repo_name}
|
||||||
|
/>
|
||||||
|
</ModalPortal>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{this.state.isAPITokenDialogOpen && (
|
||||||
|
<ModalPortal>
|
||||||
|
<RepoAPITokenDialog
|
||||||
|
repo={repo}
|
||||||
|
onRepoAPITokenToggle={this.onAPITokenToggle}
|
||||||
|
/>
|
||||||
|
</ModalPortal>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{this.state.isRepoShareAdminDialogOpen && (
|
||||||
|
<ModalPortal>
|
||||||
|
<RepoShareAdminDialog
|
||||||
|
repo={repo}
|
||||||
|
toggleDialog={this.toggleRepoShareAdminDialog}
|
||||||
|
/>
|
||||||
|
</ModalPortal>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{this.state.isOfficeSuiteDialogOpen && (
|
||||||
|
<ModalPortal>
|
||||||
|
<OfficeSuiteDialog
|
||||||
|
repoID={repo.repo_id}
|
||||||
|
repoName={repo.repo_name}
|
||||||
|
toggleDialog={this.onOfficeSuiteToggle}
|
||||||
|
/>
|
||||||
|
</ModalPortal>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LibraryMoreOperations.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default LibraryMoreOperations;
|
@@ -245,7 +245,6 @@ class SharedRepoListItem extends React.Component {
|
|||||||
toaster.danger(gettext('Failed. Please check the network.'), { duration: 3 });
|
toaster.danger(gettext('Failed. Please check the network.'), { duration: 3 });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.onTransferToggle();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
onRenameConfirm = (name) => {
|
onRenameConfirm = (name) => {
|
||||||
|
@@ -24,6 +24,7 @@ class RepoInfo {
|
|||||||
this.last_modified = object.last_modified;
|
this.last_modified = object.last_modified;
|
||||||
this.status = object.status;
|
this.status = object.status;
|
||||||
this.enable_onlyoffice = object.enable_onlyoffice;
|
this.enable_onlyoffice = object.enable_onlyoffice;
|
||||||
|
this.monitored = object.monitored;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2274,6 +2274,12 @@ class LibContentView extends React.Component {
|
|||||||
this.props.eventBus.dispatch(EVENT_BUS_TYPE.TAGS_CHANGED, tags);
|
this.props.eventBus.dispatch(EVENT_BUS_TYPE.TAGS_CHANGED, tags);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
updateRepoInfo = (updatedData) => {
|
||||||
|
this.setState({
|
||||||
|
currentRepoInfo: { ...this.state.currentRepoInfo, ...updatedData }
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { repoID } = this.props;
|
const { repoID } = this.props;
|
||||||
let { currentRepoInfo, userPerm, isCopyMoveProgressDialogShow, isDeleteFolderDialogOpen, errorMsg,
|
let { currentRepoInfo, userPerm, isCopyMoveProgressDialogShow, isDeleteFolderDialogOpen, errorMsg,
|
||||||
@@ -2464,6 +2470,7 @@ class LibContentView extends React.Component {
|
|||||||
path={this.state.path}
|
path={this.state.path}
|
||||||
repoID={this.props.repoID}
|
repoID={this.props.repoID}
|
||||||
currentRepoInfo={this.state.currentRepoInfo}
|
currentRepoInfo={this.state.currentRepoInfo}
|
||||||
|
updateRepoInfo={this.updateRepoInfo}
|
||||||
isGroupOwnedRepo={this.state.isGroupOwnedRepo}
|
isGroupOwnedRepo={this.state.isGroupOwnedRepo}
|
||||||
userPerm={userPerm}
|
userPerm={userPerm}
|
||||||
enableDirPrivateShare={enableDirPrivateShare}
|
enableDirPrivateShare={enableDirPrivateShare}
|
||||||
|
@@ -273,22 +273,6 @@ class MylibRepoListItem extends React.Component {
|
|||||||
toaster.danger(gettext('Failed. Please check the network.'), { duration: 3 });
|
toaster.danger(gettext('Failed. Please check the network.'), { duration: 3 });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.onTransferToggle();
|
|
||||||
};
|
|
||||||
|
|
||||||
onOfficeSuiteChange = (suiteID) => {
|
|
||||||
let repoID = this.props.repo.repo_id;
|
|
||||||
userAPI.setOfficeSuite(repoID, suiteID).then(res => {
|
|
||||||
let message = gettext('Successfully change office suite.');
|
|
||||||
toaster.success(message);
|
|
||||||
}).catch(error => {
|
|
||||||
if (error.response) {
|
|
||||||
toaster.danger(error.response.data.error_msg || gettext('Error'), { duration: 3 });
|
|
||||||
} else {
|
|
||||||
toaster.danger(gettext('Failed. Please check the network.'), { duration: 3 });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.onOfficeSuiteToggle();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
onDeleteRepo = (repo) => {
|
onDeleteRepo = (repo) => {
|
||||||
@@ -578,8 +562,7 @@ class MylibRepoListItem extends React.Component {
|
|||||||
<ModalPortal>
|
<ModalPortal>
|
||||||
<OfficeSuiteDialog
|
<OfficeSuiteDialog
|
||||||
repoID={repo.repo_id}
|
repoID={repo.repo_id}
|
||||||
itemName={repo.repo_name}
|
repoName={repo.repo_name}
|
||||||
submit={this.onOfficeSuiteChange}
|
|
||||||
toggleDialog={this.onOfficeSuiteToggle}
|
toggleDialog={this.onOfficeSuiteToggle}
|
||||||
/>
|
/>
|
||||||
</ModalPortal>
|
</ModalPortal>
|
||||||
|
@@ -9,8 +9,8 @@ const propTypes = {
|
|||||||
isPC: PropTypes.bool,
|
isPC: PropTypes.bool,
|
||||||
repo: PropTypes.object.isRequired,
|
repo: PropTypes.object.isRequired,
|
||||||
isStarred: PropTypes.bool,
|
isStarred: PropTypes.bool,
|
||||||
onFreezedItem: PropTypes.func.isRequired,
|
onFreezedItem: PropTypes.func,
|
||||||
onUnfreezedItem: PropTypes.func.isRequired,
|
onUnfreezedItem: PropTypes.func,
|
||||||
onMenuItemClick: PropTypes.func.isRequired,
|
onMenuItemClick: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ class MylibRepoMenu extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMenuItemClick = (e) => {
|
onMenuItemClick = (e) => {
|
||||||
let operation = Utils.getEventData(e, 'toggle');
|
const operation = Utils.getEventData(e, 'toggle');
|
||||||
this.props.onMenuItemClick(operation);
|
this.props.onMenuItemClick(operation);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -46,6 +46,12 @@ class MylibRepoMenu extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
toggleOperationMenu = (e) => {
|
toggleOperationMenu = (e) => {
|
||||||
|
const { isLibView } = this.props;
|
||||||
|
if (isLibView) {
|
||||||
|
this.setState({ isItemMenuShow: !this.state.isItemMenuShow });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let dataset = e.target ? e.target.dataset : null;
|
let dataset = e.target ? e.target.dataset : null;
|
||||||
if (dataset && dataset.toggle && dataset.toggle === 'Rename') {
|
if (dataset && dataset.toggle && dataset.toggle === 'Rename') {
|
||||||
this.setState({ isItemMenuShow: !this.state.isItemMenuShow });
|
this.setState({ isItemMenuShow: !this.state.isItemMenuShow });
|
||||||
@@ -175,9 +181,6 @@ class MylibRepoMenu extends React.Component {
|
|||||||
case 'Advanced':
|
case 'Advanced':
|
||||||
translateResult = gettext('Advanced');
|
translateResult = gettext('Advanced');
|
||||||
break;
|
break;
|
||||||
case 'SeaTable integration':
|
|
||||||
translateResult = gettext('SeaTable integration');
|
|
||||||
break;
|
|
||||||
case 'Office Suite':
|
case 'Office Suite':
|
||||||
translateResult = gettext('Office Suite');
|
translateResult = gettext('Office Suite');
|
||||||
break;
|
break;
|
||||||
@@ -192,22 +195,31 @@ class MylibRepoMenu extends React.Component {
|
|||||||
let operations = this.generatorOperations();
|
let operations = this.generatorOperations();
|
||||||
const advancedOperations = this.getAdvancedOperations();
|
const advancedOperations = this.getAdvancedOperations();
|
||||||
|
|
||||||
|
const { children, isLibView } = this.props;
|
||||||
|
|
||||||
// pc menu
|
// pc menu
|
||||||
if (this.props.isPC) {
|
if (this.props.isPC) {
|
||||||
return (
|
return (
|
||||||
<Dropdown isOpen={this.state.isItemMenuShow} toggle={this.toggleOperationMenu}>
|
<Dropdown
|
||||||
|
isOpen={this.state.isItemMenuShow}
|
||||||
|
toggle={this.toggleOperationMenu}
|
||||||
|
direction={isLibView ? 'end' : 'down'}
|
||||||
|
className={isLibView ? 'd-block' : ''}
|
||||||
|
>
|
||||||
<DropdownToggle
|
<DropdownToggle
|
||||||
tag="i"
|
tag={isLibView ? 'div' : 'span'}
|
||||||
|
className={isLibView ? 'dir-others-item' : ''}
|
||||||
role="button"
|
role="button"
|
||||||
tabIndex="0"
|
tabIndex="0"
|
||||||
className="sf-dropdown-toggle sf3-font-more sf3-font"
|
title={isLibView ? gettext('More') : gettext('More operations')}
|
||||||
title={gettext('More operations')}
|
|
||||||
aria-label={gettext('More operations')}
|
aria-label={gettext('More operations')}
|
||||||
onClick={this.onDropdownToggleClick}
|
onClick={this.onDropdownToggleClick}
|
||||||
onKeyDown={this.onDropdownToggleKeyDown}
|
onKeyDown={this.onDropdownToggleKeyDown}
|
||||||
data-toggle="dropdown"
|
data-toggle="dropdown"
|
||||||
/>
|
>
|
||||||
<DropdownMenu onMouseMove={this.onDropDownMouseMove}>
|
{children || <i className="sf-dropdown-toggle sf3-font-more sf3-font"></i>}
|
||||||
|
</DropdownToggle>
|
||||||
|
<DropdownMenu onMouseMove={this.onDropDownMouseMove} container={isLibView ? 'body' : ''}>
|
||||||
{operations.map((item, index) => {
|
{operations.map((item, index) => {
|
||||||
if (item == 'Divider') {
|
if (item == 'Divider') {
|
||||||
return <DropdownItem key={index} divider />;
|
return <DropdownItem key={index} divider />;
|
||||||
|
@@ -223,7 +223,6 @@ class RepoItem extends React.Component {
|
|||||||
let errMessage = Utils.getErrorMsg(error);
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
toaster.danger(errMessage);
|
toaster.danger(errMessage);
|
||||||
});
|
});
|
||||||
this.toggleTransfer();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@@ -180,7 +180,6 @@ class Item extends Component {
|
|||||||
let errMessage = Utils.getErrorMsg(error);
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
toaster.danger(errMessage);
|
toaster.danger(errMessage);
|
||||||
});
|
});
|
||||||
this.toggleTransferDialog();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
handleMouseOver = () => {
|
handleMouseOver = () => {
|
||||||
|
@@ -138,8 +138,7 @@ class Item extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
transferRepo = (owner, reshare) => {
|
transferRepo = (owner, reshare) => {
|
||||||
this.props.transferRepo(this.props.item.id, owner.email, reshare);
|
this.props.transferRepo(this.props.item.id, owner, reshare);
|
||||||
this.toggleTransferDialog();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
renderRepoName = () => {
|
renderRepoName = () => {
|
||||||
|
@@ -395,6 +395,12 @@ class RepoView(APIView):
|
|||||||
has_been_shared_out = False
|
has_been_shared_out = False
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
|
|
||||||
|
monitored = False
|
||||||
|
monitored_repos = UserMonitoredRepos.objects.filter(email=username,
|
||||||
|
repo_id=repo_id)
|
||||||
|
if monitored_repos:
|
||||||
|
monitored = True
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
"repo_id": repo.id,
|
"repo_id": repo.id,
|
||||||
"repo_name": repo.name,
|
"repo_name": repo.name,
|
||||||
@@ -416,7 +422,8 @@ class RepoView(APIView):
|
|||||||
"lib_need_decrypt": lib_need_decrypt,
|
"lib_need_decrypt": lib_need_decrypt,
|
||||||
"last_modified": timestamp_to_isoformat_timestr(repo.last_modify),
|
"last_modified": timestamp_to_isoformat_timestr(repo.last_modify),
|
||||||
"status": normalize_repo_status_code(repo.status),
|
"status": normalize_repo_status_code(repo.status),
|
||||||
"enable_onlyoffice": enable_onlyoffice
|
"enable_onlyoffice": enable_onlyoffice,
|
||||||
|
"monitored": monitored,
|
||||||
}
|
}
|
||||||
|
|
||||||
return Response(result)
|
return Response(result)
|
||||||
@@ -542,6 +549,7 @@ class RepoShareInfoView(APIView):
|
|||||||
|
|
||||||
return Response(result)
|
return Response(result)
|
||||||
|
|
||||||
|
|
||||||
class RepoImageRotateView(APIView):
|
class RepoImageRotateView(APIView):
|
||||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||||
permission_classes = (IsAuthenticated, )
|
permission_classes = (IsAuthenticated, )
|
||||||
|
Reference in New Issue
Block a user