diff --git a/frontend/src/css/my-deleted-repos.css b/frontend/src/components/dialog/my-deleted-repos-dialog/index.css
similarity index 63%
rename from frontend/src/css/my-deleted-repos.css
rename to frontend/src/components/dialog/my-deleted-repos-dialog/index.css
index 53eb9c26fb..c1724f11a4 100644
--- a/frontend/src/css/my-deleted-repos.css
+++ b/frontend/src/components/dialog/my-deleted-repos-dialog/index.css
@@ -1,11 +1,15 @@
.my-deleted-repos-dialog {
max-width: 720px;
+ height: calc(100% - 56px);
+ overflow: hidden;
}
-.my-deleted-repos-container {
- min-height: 200px;
- max-height: 500px;
- overflow: auto;
+.my-deleted-repos-dialog .modal-content {
+ height: 100%;
+}
+
+.my-deleted-repos-dialog .my-deleted-repos-container {
+ overflow-y: scroll;
}
.my-deleted-repos-empty-tip {
@@ -25,5 +29,5 @@
.my-deleted-repos-tip {
font-size: .8125rem;
- color: #9c9c9c;
+ color: #666;
}
diff --git a/frontend/src/components/dialog/my-deleted-repos-dialog/index.js b/frontend/src/components/dialog/my-deleted-repos-dialog/index.js
new file mode 100644
index 0000000000..56fcaff43c
--- /dev/null
+++ b/frontend/src/components/dialog/my-deleted-repos-dialog/index.js
@@ -0,0 +1,65 @@
+import React, { useCallback, useEffect, useState } from 'react';
+import PropTypes from 'prop-types';
+import { Modal, ModalHeader, ModalBody } from 'reactstrap';
+import { gettext, trashReposExpireDays } from '../../../utils/constants';
+import { seafileAPI } from '../../../utils/seafile-api';
+import { Utils } from '../../../utils/utils';
+import toaster from '../../toast';
+import Loading from '../../loading';
+import EmptyTip from '../../empty-tip';
+import Repos from './repos';
+
+import './index.css';
+
+const MyDeletedReposDialog = ({ toggleDialog }) => {
+
+ const [isLoading, setLoading] = useState(true);
+ const [deletedRepoList, setDeletedRepoList] = useState([]);
+
+ useEffect(() => {
+ seafileAPI.listDeletedRepo().then(res => {
+ setDeletedRepoList(res.data);
+ setLoading(false);
+ }).catch(error => {
+ const errMessage = Utils.getErrorMsg(error);
+ toaster.danger(errMessage);
+ });
+ }, []);
+
+ const filterRestoredRepo = useCallback((restoredRepoID) => {
+ const newDeletedRepoList = deletedRepoList.filter(item => {
+ return item.repo_id !== restoredRepoID;
+ });
+ setDeletedRepoList(newDeletedRepoList);
+ }, [deletedRepoList]);
+
+ return (
+
+ {gettext('Deleted Libraries')}
+
+ {isLoading ? (
+
+ ) : (
+ <>
+ {deletedRepoList.length === 0 ? (
+
+ ) : (
+
+ )}
+ >
+ )}
+
+
+ );
+
+};
+
+MyDeletedReposDialog.propTypes = {
+ toggleDialog: PropTypes.func.isRequired
+};
+
+export default MyDeletedReposDialog;
diff --git a/frontend/src/components/dialog/my-deleted-repos-dialog/repo-item.js b/frontend/src/components/dialog/my-deleted-repos-dialog/repo-item.js
new file mode 100644
index 0000000000..ee635bc579
--- /dev/null
+++ b/frontend/src/components/dialog/my-deleted-repos-dialog/repo-item.js
@@ -0,0 +1,71 @@
+import React, { useCallback, useMemo, useState } from 'react';
+import PropTypes from 'prop-types';
+import dayjs from 'dayjs';
+import relativeTime from 'dayjs/plugin/relativeTime';
+import { seafileAPI } from '../../../utils/seafile-api';
+import { gettext, lang } from '../../../utils/constants';
+import toaster from '../../toast';
+import { Utils } from '../../../utils/utils';
+
+dayjs.locale(lang);
+dayjs.extend(relativeTime);
+
+const RepoItem = ({ repo, filterRestoredRepo }) => {
+ const repoID = useMemo(() => repo.repo_id, [repo]);
+ const repoName = useMemo(() => repo.repo_name, [repo]);
+ const localTime = useMemo(() => {
+ const timeDate = dayjs.utc(repo.del_time).toDate();
+ return dayjs(timeDate).fromNow();
+ }, [repo]);
+ const iconUrl = useMemo(() => Utils.getLibIconUrl(repo), [repo]);
+
+ const [highlight, setHighlight] = useState(false);
+
+ const onMouseEnter = useCallback(() => {
+ setHighlight(true);
+ }, []);
+
+ const onMouseLeave = useCallback(() => {
+ setHighlight(false);
+ }, []);
+
+ const restoreDeletedRepo = useCallback((event) => {
+ event.preventDefault();
+ seafileAPI.restoreDeletedRepo(repoID).then(res => {
+ const message = gettext('Successfully restored the library {library_name}.').replace('{library_name}', repoName);
+ toaster.success(message);
+ filterRestoredRepo(repoID);
+ }).catch(error => {
+ const errMessage = Utils.getErrorMsg(error);
+ toaster.danger(errMessage);
+ });
+ }, [repoID, repoName, filterRestoredRepo]);
+
+ return (
+
+  |
+ {repoName} |
+ {localTime} |
+
+
+
+ |
+
+ );
+
+};
+
+RepoItem.propTypes = {
+ repo: PropTypes.object.isRequired,
+ filterRestoredRepo: PropTypes.func.isRequired,
+};
+
+export default RepoItem;
diff --git a/frontend/src/components/dialog/my-deleted-repos-dialog/repos.js b/frontend/src/components/dialog/my-deleted-repos-dialog/repos.js
new file mode 100644
index 0000000000..e50daafe49
--- /dev/null
+++ b/frontend/src/components/dialog/my-deleted-repos-dialog/repos.js
@@ -0,0 +1,54 @@
+import React, { useState, useEffect, useRef } from 'react';
+import PropTypes from 'prop-types';
+import RepoItem from './repo-item';
+import { gettext, trashReposExpireDays } from '../../../utils/constants';
+
+const Repos = ({ repos, filterRestoredRepo }) => {
+ const [containerWidth, setContainerWidth] = useState(0);
+
+ const containerRef = useRef(null);
+
+ useEffect(() => {
+ const container = containerRef.current;
+ const handleResize = () => {
+ if (!container) return;
+ setContainerWidth(container.offsetWidth);
+ };
+ const resizeObserver = new ResizeObserver(handleResize);
+ container && resizeObserver.observe(container);
+
+ return () => {
+ container && resizeObserver.unobserve(container);
+ };
+ }, []);
+
+ return (
+
+
{gettext('Tip: libraries deleted {placeholder} days ago will be cleaned automatically.').replace('{placeholder}', trashReposExpireDays)}
+
+
+
+ {/* img*/} |
+ {gettext('Name')} |
+ {gettext('Deleted Time')} |
+ |
+
+
+
+ {repos.map((repo) => {
+ return (
+
+ );
+ })}
+
+
+
+ );
+};
+
+Repos.propTypes = {
+ repos: PropTypes.array,
+ filterRestoredRepo: PropTypes.func,
+};
+
+export default Repos;
diff --git a/frontend/src/components/dialog/my-deleted-repos.js b/frontend/src/components/dialog/my-deleted-repos.js
deleted file mode 100644
index c68d8388c8..0000000000
--- a/frontend/src/components/dialog/my-deleted-repos.js
+++ /dev/null
@@ -1,168 +0,0 @@
-import React, { Component } from 'react';
-import PropTypes from 'prop-types';
-import { Modal, ModalHeader, ModalBody } from 'reactstrap';
-import dayjs from 'dayjs';
-import relativeTime from 'dayjs/plugin/relativeTime';
-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';
-
-dayjs.locale(lang);
-dayjs.extend(relativeTime);
-
-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) &&
-
- }
- {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 = dayjs.utc(this.props.repo.del_time).toDate();
- localTime = dayjs(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/pages/my-libs/my-libs.js b/frontend/src/pages/my-libs/my-libs.js
index 17d59549c1..4b74b3e67a 100644
--- a/frontend/src/pages/my-libs/my-libs.js
+++ b/frontend/src/pages/my-libs/my-libs.js
@@ -14,7 +14,7 @@ import ReposSortMenu from '../../components/sort-menu';
import SingleDropdownToolbar from '../../components/toolbar/single-dropdown-toolbar';
import SortOptionsDialog from '../../components/dialog/sort-options';
import CreateRepoDialog from '../../components/dialog/create-repo-dialog';
-import DeletedReposDialog from '../../components/dialog/my-deleted-repos';
+import DeletedReposDialog from '../../components/dialog/my-deleted-repos-dialog';
import { LIST_MODE } from '../../components/dir-view-mode/constants';
import MylibRepoListView from './mylib-repo-list-view';