diff --git a/frontend/src/components/dialog/my-deleted-repos.js b/frontend/src/components/dialog/my-deleted-repos.js
new file mode 100644
index 0000000000..01e2bb6760
--- /dev/null
+++ b/frontend/src/components/dialog/my-deleted-repos.js
@@ -0,0 +1,165 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { Modal, ModalHeader, ModalBody } from 'reactstrap';
+import moment from 'moment';
+import { gettext, lang, trashReposExpireDays } from '../../utils/constants';
+import { seafileAPI } from '../../utils/seafile-api';
+import { Utils } from '../../utils/utils';
+import toaster from '../../components/toast';
+import Loading from '../../components/loading';
+import EmptyTip from '../../components/empty-tip';
+
+import '../../css/my-deleted-repos.css';
+
+moment.locale(lang);
+
+class MyLibsDeleted extends Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ deletedRepoList: [],
+ isLoading: true,
+ };
+ }
+
+ componentDidMount() {
+ seafileAPI.listDeletedRepo().then(res => {
+ this.setState({
+ deletedRepoList: res.data,
+ isLoading: false,
+ });
+ }).catch(error => {
+ let errMessage = Utils.getErrorMsg(error);
+ toaster.danger(errMessage);
+ });
+ }
+
+ refreshDeletedRepoList = (repoID) => {
+ let deletedRepoList = this.state.deletedRepoList.filter(item => {
+ return item.repo_id !== repoID;
+ });
+ this.setState({ deletedRepoList: deletedRepoList });
+ };
+
+ render() {
+ const { deletedRepoList: repos } = this.state;
+ return (
+
+
+ {gettext('Deleted Libraries')}
+
+
+ {this.state.isLoading && }
+ {(!this.state.isLoading && repos.length === 0) &&
+
+ {gettext('No deleted libraries')}
+ {gettext('You have not deleted any libraries in the last {placeholder} days. A deleted library will be cleaned automatically after this period.').replace('{placeholder}', trashReposExpireDays)}
+
+ }
+ {repos.length !== 0 &&
+
+
{gettext('Tip: libraries deleted {placeholder} days ago will be cleaned automatically.').replace('{placeholder}', trashReposExpireDays)}
+
+
+
+ {/* img*/} |
+ {gettext('Name')} |
+ {gettext('Deleted Time')} |
+ |
+
+
+
+ {repos.map((item) => {
+ return (
+
+ );
+ })}
+
+
+
+ }
+
+
+ );
+ }
+}
+
+class DeletedRepoItem extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ hideRestoreMenu: true,
+ highlight: false,
+ };
+ }
+
+ onMouseEnter = () => {
+ this.setState({
+ hideRestoreMenu: false,
+ highlight: true,
+ });
+ };
+
+ onMouseLeave = () => {
+ this.setState({
+ hideRestoreMenu: true,
+ highlight: false,
+ });
+ };
+
+ restoreDeletedRepo = (e) => {
+ e.preventDefault();
+ let repoID = this.props.repo.repo_id;
+ let repoName = this.props.repo.repo_name;
+ seafileAPI.restoreDeletedRepo(repoID).then(res => {
+ let message = gettext('Successfully restored the library {library_name}.').replace('{library_name}', repoName);
+ toaster.success(message);
+ this.props.refreshDeletedRepoList(repoID);
+ }).catch(error => {
+ const errMessage = Utils.getErrorMsg(error);
+ toaster.danger(errMessage);
+ });
+ };
+
+ render() {
+ let localTime = moment.utc(this.props.repo.del_time).toDate();
+ localTime = moment(localTime).fromNow();
+ let iconUrl = Utils.getLibIconUrl(this.props.repo);
+
+ return (
+
+  |
+ {this.props.repo.repo_name} |
+ {localTime} |
+
+
+
+ |
+
+ );
+ }
+}
+
+DeletedRepoItem.propTypes = {
+ repo: PropTypes.object.isRequired,
+ refreshDeletedRepoList: PropTypes.func.isRequired,
+};
+
+MyLibsDeleted.propTypes = {
+ toggleDialog: PropTypes.func.isRequired
+};
+
+export default MyLibsDeleted;
diff --git a/frontend/src/components/empty-tip.js b/frontend/src/components/empty-tip.js
index ffb8bff656..6398cb9a3f 100644
--- a/frontend/src/components/empty-tip.js
+++ b/frontend/src/components/empty-tip.js
@@ -5,13 +5,15 @@ import { mediaUrl } from '../utils/constants';
const propTypes = {
forDialog: PropTypes.bool,
children: PropTypes.any,
+ className: PropTypes.string
};
class EmptyTip extends React.Component {
render() {
+ const { className } = this.props;
return (
-
+

{this.props.children}
diff --git a/frontend/src/css/my-deleted-repos.css b/frontend/src/css/my-deleted-repos.css
new file mode 100644
index 0000000000..67257c6720
--- /dev/null
+++ b/frontend/src/css/my-deleted-repos.css
@@ -0,0 +1,35 @@
+.my-deleted-repos-dialog {
+ max-width: 720px;
+}
+
+.my-deleted-repos-container {
+ min-height: 200px;
+ max-height: 500px;
+ overflow: auto;
+}
+
+.my-deleted-repos-empty-tip {
+ text-align: center;
+ margin: 20px 0;
+}
+
+.my-deleted-repos-empty-tip .empty-explanation {
+ color: #666;
+ font-size: .875rem;
+ margin: 0;
+}
+
+@media (min-width: 768px) {
+ .my-deleted-repos-empty-tip {
+ margin: 104px 0 216px;
+ }
+
+ .my-deleted-repos-empty-tip .empty-explanation {
+ margin: 0 7rem;
+ }
+}
+
+.my-deleted-repos-tip {
+ font-size: .8125rem;
+ color: #9c9c9c;
+}
diff --git a/frontend/src/pages/my-libs/my-libs.js b/frontend/src/pages/my-libs/my-libs.js
index 850af0a3b0..bbc393c83b 100644
--- a/frontend/src/pages/my-libs/my-libs.js
+++ b/frontend/src/pages/my-libs/my-libs.js
@@ -1,9 +1,7 @@
import React, { Component, Fragment } from 'react';
import cookie from 'react-cookies';
-import { navigate } from '@gatsbyjs/reach-router';
-import { DropdownToggle, Dropdown, DropdownMenu, DropdownItem } from 'reactstrap';
import { seafileAPI } from '../../utils/seafile-api';
-import { gettext, siteRoot } from '../../utils/constants';
+import { gettext } from '../../utils/constants';
import { Utils } from '../../utils/utils';
import toaster from '../../components/toast';
import Repo from '../../models/repo';
@@ -14,6 +12,7 @@ import SortOptionsDialog from '../../components/dialog/sort-options';
import SingleDropdownToolbar from '../../components/toolbar/single-dropdown-toolbar';
import ModalPortal from '../../components/modal-portal';
import CreateRepoDialog from '../../components/dialog/create-repo-dialog';
+import DeletedReposDialog from '../../components/dialog/my-deleted-repos';
class MyLibraries extends Component {
constructor(props) {
@@ -22,8 +21,8 @@ class MyLibraries extends Component {
errorMsg: '',
isLoading: true,
repoList: [],
+ isDeletedReposDialogOpen: false,
isCreateRepoDialogOpen: false,
- isDropdownMenuOpen: false,
isSortOptionsDialogOpen: false,
sortBy: cookie.load('seafile-repo-dir-sort-by') || 'name', // 'name' or 'time' or 'size'
sortOrder: cookie.load('seafile-repo-dir-sort-order') || 'asc', // 'asc' or 'desc'
@@ -129,24 +128,13 @@ class MyLibraries extends Component {
this.setState({ isCreateRepoDialogOpen: !this.state.isCreateRepoDialogOpen });
};
- toggleDropdownMenu = () => {
+ toggleDeletedReposDialog = () => {
this.setState({
- isDropdownMenuOpen: !this.state.isDropdownMenuOpen
+ isDeletedReposDialogOpen: !this.state.isDeletedReposDialogOpen
});
};
- visitDeleted = () => {
- navigate(`${siteRoot}my-libs/deleted/`);
- };
-
- visitDeletedviaKey = (e) => {
- if (e.key == 'Enter' || e.key == 'Space') {
- this.visiteDeleted();
- }
- };
-
render() {
- const { isDropdownMenuOpen } = this.state;
return (
@@ -155,25 +143,14 @@ class MyLibraries extends Component {
{gettext('My Libraries')}
{(!Utils.isDesktop() && this.state.repoList.length > 0) && }
-
-
-
-
- {gettext('Deleted Libraries')}
-
-
@@ -211,6 +188,13 @@ class MyLibraries extends Component {
/>
)}
+ {this.state.isDeletedReposDialogOpen && (
+
+
+
+ )}
);