diff --git a/frontend/src/components/dialog/trash-dialog.js b/frontend/src/components/dialog/trash-dialog.js
deleted file mode 100644
index 2819d4e64e..0000000000
--- a/frontend/src/components/dialog/trash-dialog.js
+++ /dev/null
@@ -1,484 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { navigate } from '@gatsbyjs/reach-router';
-import { Modal, ModalHeader, ModalBody } from 'reactstrap';
-import dayjs from 'dayjs';
-import { Utils, isMobile } from '../../utils/utils';
-import { gettext, siteRoot, enableUserCleanTrash, username } from '../../utils/constants';
-import { seafileAPI } from '../../utils/seafile-api';
-import { repotrashAPI } from '../../utils/repo-trash-api';
-import ModalPortal from '../../components/modal-portal';
-import toaster from '../../components/toast';
-import CleanTrash from '../../components/dialog/clean-trash';
-import Paginator from '../paginator';
-import Loading from '../../components/loading';
-import EmptyTip from '../../components/empty-tip';
-
-import '../../css/toolbar.css';
-import '../../css/search.css';
-import '../../css/trash-dialog.css';
-
-const propTypes = {
- repoID: PropTypes.string.isRequired,
- currentRepoInfo: PropTypes.object.isRequired,
- showTrashDialog: PropTypes.bool.isRequired,
- toggleTrashDialog: PropTypes.func.isRequired
-};
-
-class TrashDialog extends React.Component {
-
- constructor(props) {
- super(props);
- this.state = {
- isLoading: true,
- errorMsg: '',
- items: [],
- scanStat: null,
- more: false,
- isCleanTrashDialogOpen: false,
- trashType: 0,
- isOldTrashDialogOpen: false,
- currentPage: 1,
- perPage: 100,
- hasNextPage: false
- };
- }
-
- componentDidMount() {
- this.getItems2();
- }
-
- getItems2 = (page) => {
- repotrashAPI.getRepoFolderTrash2(this.props.repoID, page, this.state.perPage).then((res) => {
- const { items, total_count } = res.data;
- if (!page) {
- page = 1;
- }
- this.setState({
- currentPage: page,
- hasNextPage: total_count - page * this.state.perPage > 0,
- isLoading: false,
- items: items,
- more: false
- });
- });
- };
-
- onSearchedClick = (selectedItem) => {
- if (selectedItem.is_dir === true) {
- let url = siteRoot + 'library/' + selectedItem.repo_id + '/' + selectedItem.repo_name + selectedItem.path;
- navigate(url, { replace: true });
- } else {
- let url = siteRoot + 'lib/' + selectedItem.repo_id + '/file' + Utils.encodePath(selectedItem.path);
- let newWindow = window.open('about:blank');
- newWindow.location.href = url;
- }
- };
-
- resetPerPage = (perPage) => {
- this.setState({
- perPage: perPage
- }, () => {
- this.getItems2(1);
- });
- };
- cleanTrash = () => {
- this.toggleCleanTrashDialog();
- };
-
- toggleCleanTrashDialog = () => {
- this.setState({
- isCleanTrashDialogOpen: !this.state.isCleanTrashDialogOpen
- });
- };
-
- refreshTrash2 = () => {
- this.setState({
- isLoading: true,
- errorMsg: '',
- items: [],
- scanStat: null,
- more: false,
- showFolder: false
- });
- this.getItems2();
- };
-
- renderFolder = (commitID, baseDir, folderPath) => {
- this.setState({
- showFolder: true,
- commitID: commitID,
- baseDir: baseDir,
- folderPath: folderPath,
- folderItems: [],
- isLoading: true
- });
-
- seafileAPI.listCommitDir(this.props.repoID, commitID, `${baseDir.substr(0, baseDir.length - 1)}${folderPath}`).then((res) => {
- this.setState({
- isLoading: false,
- folderItems: res.data.dirent_list
- });
- }).catch((error) => {
- if (error.response) {
- if (error.response.status == 403) {
- this.setState({
- isLoading: false,
- errorMsg: gettext('Permission denied')
- });
- } else {
- this.setState({
- isLoading: false,
- errorMsg: gettext('Error')
- });
- }
- } else {
- this.setState({
- isLoading: false,
- errorMsg: gettext('Please check the network.')
- });
- }
- });
- };
-
-
- clickFolderPath = (folderPath, e) => {
- e.preventDefault();
- const { commitID, baseDir } = this.state;
- this.renderFolder(commitID, baseDir, folderPath);
- };
-
- clickRoot = (e) => {
- e.preventDefault();
- this.refreshTrash2();
- };
-
- renderFolderPath = () => {
- const pathList = this.state.folderPath.split('/');
- const repoFolderName = this.props.currentRepoInfo.repo_name;
-
- return (
-
- {repoFolderName}
- /
- {pathList.map((item, index) => {
- if (index > 0 && index != pathList.length - 1) {
- return (
-
- {pathList[index]}
- /
-
- );
- }
- return null;
- }
- )}
- {pathList[pathList.length - 1]}
-
- );
- };
-
- render() {
- const { showTrashDialog, toggleTrashDialog } = this.props;
- const { isCleanTrashDialogOpen, showFolder, isLoading, items } = this.state;
- const isRepoAdmin = this.props.currentRepoInfo.owner_email === username || this.props.currentRepoInfo.is_admin;
- const repoFolderName = this.props.currentRepoInfo.repo_name;
- const oldTrashUrl = siteRoot + 'repo/' + this.props.repoID + '/trash/';
- let title = gettext('{placeholder} Trash');
- title = title.replace('{placeholder}', '' + Utils.HTMLescape(repoFolderName) + '');
-
- return (
-
-
- {gettext('Visit old version page')}
- {(enableUserCleanTrash && !showFolder && isRepoAdmin) &&
-
- }
-
- >
- }
- >
-
-
-
- {isLoading && }
- {!isLoading && items.length === 0 &&
-
- }
- {!isLoading && items.length > 0 &&
-
-
- {gettext('Current path: ')}
- {showFolder ?
- this.renderFolderPath() :
- {repoFolderName}
- }
-
-
-
- }
- {isCleanTrashDialogOpen &&
-
-
-
- }
-
-
- );
- }
-}
-
-class Content extends React.Component {
-
- constructor(props) {
- super(props);
- this.theadData = [
- { width: '5%', text: gettext('Name') },
- { width: '20%', text: '' },
- { width: '40%', text: gettext('Original path') },
- { width: '12%', text: gettext('Delete Time') },
- { width: '13%', text: gettext('Size') },
- { width: '10%', text: '' }
- ];
- }
-
- getPreviousPage = () => {
- this.props.getListByPage(this.props.currentPage - 1);
- };
-
- getNextPage = () => {
- this.props.getListByPage(this.props.currentPage + 1);
- };
-
- render() {
- const { items, showFolder, commitID, baseDir, folderPath, folderItems } = this.props.data;
- const { curPerPage, currentPage, hasNextPage } = this.props;
- return (
-
-
-
-
- {this.theadData.map((item, index) => {
- return {item.text} | ;
- })}
-
-
-
- {showFolder ?
- folderItems.map((item, index) => {
- return ;
- }) :
- items.map((item, index) => {
- return ;
- })}
-
-
-
-
- );
- }
-}
-
-Content.propTypes = {
- data: PropTypes.object.isRequired,
- getMore: PropTypes.func,
- renderFolder: PropTypes.func.isRequired,
- repoID: PropTypes.string.isRequired,
- getListByPage: PropTypes.func.isRequired,
- resetPerPage: PropTypes.func.isRequired,
- currentPage: PropTypes.number.isRequired,
- curPerPage: PropTypes.number.isRequired,
- hasNextPage: PropTypes.bool.isRequired,
-};
-
-
-class Item extends React.Component {
-
- constructor(props) {
- super(props);
- this.state = {
- restored: false,
- isIconShown: false
- };
- }
-
- handleMouseOver = () => {
- this.setState({ isIconShown: true });
- };
-
- handleMouseOut = () => {
- this.setState({ isIconShown: false });
- };
-
- restoreItem = (e) => {
- e.preventDefault();
- const item = this.props.item;
- const { commit_id, parent_dir, obj_name } = item;
- const path = parent_dir + obj_name;
- const request = item.is_dir ?
- seafileAPI.restoreFolder(this.props.repoID, commit_id, path) :
- seafileAPI.restoreFile(this.props.repoID, commit_id, path);
- request.then((res) => {
- this.setState({
- restored: true
- });
- toaster.success(gettext('Restored 1 item'));
- }).catch((error) => {
- let errorMsg = '';
- if (error.response) {
- errorMsg = error.response.data.error_msg || gettext('Error');
- } else {
- errorMsg = gettext('Please check the network.');
- }
- toaster.danger(errorMsg);
- });
- };
-
- renderFolder = (e) => {
- e.preventDefault();
- const item = this.props.item;
- this.props.renderFolder(item.commit_id, item.parent_dir, Utils.joinPath('/', item.obj_name));
- };
-
- render() {
- const item = this.props.item;
- const { restored, isIconShown } = this.state;
-
- if (restored) {
- return null;
- }
-
- return item.is_dir ? (
-
- }) |
- {item.obj_name} |
- {item.parent_dir} |
- {dayjs(item.deleted_time).format('YYYY-MM-DD')} |
- |
-
- {gettext('Restore')}
- |
-
- ) : (
-
- }) |
- {item.obj_name} |
- {item.parent_dir} |
- {dayjs(item.deleted_time).format('YYYY-MM-DD')} |
- {Utils.bytesToSize(item.size)} |
-
- {gettext('Restore')}
- |
-
- );
- }
-}
-
-Item.propTypes = {
- item: PropTypes.object.isRequired,
- renderFolder: PropTypes.func.isRequired,
- repoID: PropTypes.string.isRequired
-};
-
-class FolderItem extends React.Component {
-
- constructor(props) {
- super(props);
- this.state = {
- isIconShown: false
- };
- }
-
- handleMouseOver = () => {
- this.setState({ isIconShown: true });
- };
-
- handleMouseOut = () => {
- this.setState({ isIconShown: false });
- };
-
- renderFolder = (e) => {
- e.preventDefault();
- const item = this.props.item;
- const { commitID, baseDir, folderPath } = this.props;
- this.props.renderFolder(commitID, baseDir, Utils.joinPath(folderPath, item.name));
- };
-
- render() {
- const item = this.props.item;
- const { commitID, baseDir, folderPath } = this.props;
-
- return item.type == 'dir' ? (
-
- }) |
- {item.name} |
- {item.parent_dir} |
- |
- |
- |
-
- ) : (
-
-
-
- |
-
- {item.name}
- |
- {item.parent_dir} |
- |
- {Utils.bytesToSize(item.size)} |
- |
-
- );
- }
-}
-
-FolderItem.propTypes = {
- item: PropTypes.object.isRequired,
- commitID: PropTypes.string.isRequired,
- repoID: PropTypes.string.isRequired,
- baseDir: PropTypes.string.isRequired,
- folderPath: PropTypes.string.isRequired,
- renderFolder: PropTypes.func.isRequired,
-};
-
-TrashDialog.propTypes = propTypes;
-
-export default TrashDialog;
diff --git a/frontend/src/css/trash-dialog.css b/frontend/src/components/dialog/trash-dialog/index.css
similarity index 87%
rename from frontend/src/css/trash-dialog.css
rename to frontend/src/components/dialog/trash-dialog/index.css
index 1cc1dff4c4..4dde219b99 100644
--- a/frontend/src/css/trash-dialog.css
+++ b/frontend/src/components/dialog/trash-dialog/index.css
@@ -1,5 +1,12 @@
.trash-dialog {
max-width: 1100px;
+ height: calc(100% - 56px);
+ overflow: hidden;
+}
+
+.trash-dialog .modal-content {
+ height: 100%;
+ overflow: hidden;
}
.trash-dialog .modal-header {
diff --git a/frontend/src/components/dialog/trash-dialog/index.js b/frontend/src/components/dialog/trash-dialog/index.js
new file mode 100644
index 0000000000..9305c90152
--- /dev/null
+++ b/frontend/src/components/dialog/trash-dialog/index.js
@@ -0,0 +1,255 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { navigate } from '@gatsbyjs/reach-router';
+import { Modal, ModalHeader, ModalBody } from 'reactstrap';
+import { Utils } from '../../../utils/utils';
+import { gettext, siteRoot, enableUserCleanTrash, username } from '../../../utils/constants';
+import { seafileAPI } from '../../../utils/seafile-api';
+import { repoTrashAPI } from '../../../utils/repo-trash-api';
+import ModalPortal from '../../modal-portal';
+import Table from './table';
+import CleanTrash from '../clean-trash';
+import Paginator from '../../paginator';
+import Loading from '../../loading';
+import EmptyTip from '../../empty-tip';
+
+import '../../../css/toolbar.css';
+import '../../../css/search.css';
+import './index.css';
+
+class TrashDialog extends React.Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ isLoading: true,
+ errorMsg: '',
+ items: [],
+ scanStat: null,
+ more: false,
+ isCleanTrashDialogOpen: false,
+ trashType: 0,
+ isOldTrashDialogOpen: false,
+ currentPage: 1,
+ perPage: 100,
+ hasNextPage: false
+ };
+ }
+
+ componentDidMount() {
+ this.getFolderTrash();
+ }
+
+ getFolderTrash = (page) => {
+ repoTrashAPI.getRepoFolderTrash(this.props.repoID, page, this.state.perPage).then((res) => {
+ const { items, total_count } = res.data;
+ if (!page) {
+ page = 1;
+ }
+ this.setState({
+ currentPage: page,
+ hasNextPage: total_count - page * this.state.perPage > 0,
+ isLoading: false,
+ items: items,
+ more: false
+ });
+ });
+ };
+
+ onSearchedClick = (selectedItem) => {
+ if (selectedItem.is_dir === true) {
+ let url = siteRoot + 'library/' + selectedItem.repo_id + '/' + selectedItem.repo_name + selectedItem.path;
+ navigate(url, { replace: true });
+ } else {
+ let url = siteRoot + 'lib/' + selectedItem.repo_id + '/file' + Utils.encodePath(selectedItem.path);
+ let newWindow = window.open('about:blank');
+ newWindow.location.href = url;
+ }
+ };
+
+ getPreviousPage = () => {
+ this.getFolderTrash(this.state.currentPage - 1);
+ };
+
+ getNextPage = () => {
+ this.getFolderTrash(this.state.currentPage + 1);
+ };
+
+ resetPerPage = (perPage) => {
+ this.setState({
+ perPage: perPage
+ }, () => {
+ this.getFolderTrash(1);
+ });
+ };
+
+ cleanTrash = () => {
+ this.toggleCleanTrashDialog();
+ };
+
+ toggleCleanTrashDialog = () => {
+ this.setState({
+ isCleanTrashDialogOpen: !this.state.isCleanTrashDialogOpen
+ });
+ };
+
+ refreshTrash2 = () => {
+ this.setState({
+ isLoading: true,
+ errorMsg: '',
+ items: [],
+ scanStat: null,
+ more: false,
+ showFolder: false
+ });
+ this.getFolderTrash();
+ };
+
+ renderFolder = (commitID, baseDir, folderPath) => {
+ this.setState({
+ showFolder: true,
+ commitID: commitID,
+ baseDir: baseDir,
+ folderPath: folderPath,
+ folderItems: [],
+ isLoading: true
+ });
+
+ seafileAPI.listCommitDir(this.props.repoID, commitID, `${baseDir.substr(0, baseDir.length - 1)}${folderPath}`).then((res) => {
+ this.setState({
+ isLoading: false,
+ folderItems: res.data.dirent_list
+ });
+ }).catch((error) => {
+ if (error.response) {
+ if (error.response.status == 403) {
+ this.setState({
+ isLoading: false,
+ errorMsg: gettext('Permission denied')
+ });
+ } else {
+ this.setState({
+ isLoading: false,
+ errorMsg: gettext('Error')
+ });
+ }
+ } else {
+ this.setState({
+ isLoading: false,
+ errorMsg: gettext('Please check the network.')
+ });
+ }
+ });
+ };
+
+
+ clickFolderPath = (folderPath, e) => {
+ e.preventDefault();
+ const { commitID, baseDir } = this.state;
+ this.renderFolder(commitID, baseDir, folderPath);
+ };
+
+ clickRoot = (e) => {
+ e.preventDefault();
+ this.refreshTrash2();
+ };
+
+ renderFolderPath = () => {
+ const pathList = this.state.folderPath.split('/');
+ const repoFolderName = this.props.currentRepoInfo.repo_name;
+
+ return (
+
+ {repoFolderName}
+ /
+ {pathList.map((item, index) => {
+ if (index > 0 && index != pathList.length - 1) {
+ return (
+
+ {pathList[index]}
+ /
+
+ );
+ }
+ return null;
+ }
+ )}
+ {pathList[pathList.length - 1]}
+
+ );
+ };
+
+ render() {
+ const { showTrashDialog, toggleTrashDialog, repoID } = this.props;
+ const { isCleanTrashDialogOpen, showFolder, isLoading, items, perPage, currentPage, hasNextPage } = this.state;
+ const isRepoAdmin = this.props.currentRepoInfo.owner_email === username || this.props.currentRepoInfo.is_admin;
+ const repoFolderName = this.props.currentRepoInfo.repo_name;
+ const oldTrashUrl = siteRoot + 'repo/' + this.props.repoID + '/trash/';
+ let title = gettext('{placeholder} Trash');
+ title = title.replace('{placeholder}', '' + Utils.HTMLescape(repoFolderName) + '');
+
+ return (
+ <>
+
+
+ {gettext('Visit old version page')}
+ {(enableUserCleanTrash && !showFolder && isRepoAdmin) &&
+
+ }
+
+ >
+ }
+ >
+
+
+
+ {isLoading && }
+ {!isLoading && items.length === 0 &&
+
+ }
+ {!isLoading && items.length > 0 &&
+
+
+ {gettext('Current path: ')}
+ {showFolder ?
+ this.renderFolderPath() :
+ {repoFolderName}
+ }
+
+
+
+
+ }
+
+
+ {isCleanTrashDialogOpen && (
+
+
+
+ )}
+ >
+ );
+ }
+}
+
+TrashDialog.propTypes = {
+ repoID: PropTypes.string.isRequired,
+ currentRepoInfo: PropTypes.object.isRequired,
+ showTrashDialog: PropTypes.bool.isRequired,
+ toggleTrashDialog: PropTypes.func.isRequired
+};
+
+export default TrashDialog;
diff --git a/frontend/src/components/dialog/trash-dialog/table/file-records/file-record.js b/frontend/src/components/dialog/trash-dialog/table/file-records/file-record.js
new file mode 100644
index 0000000000..d12465b041
--- /dev/null
+++ b/frontend/src/components/dialog/trash-dialog/table/file-records/file-record.js
@@ -0,0 +1,101 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import dayjs from 'dayjs';
+import { Utils, isMobile } from '../../../../../utils/utils';
+import { gettext, siteRoot } from '../../../../../utils/constants';
+import { seafileAPI } from '../../../../../utils/seafile-api';
+import toaster from '../../../../toast';
+
+class FileRecord extends React.Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ restored: false,
+ isIconShown: false
+ };
+ }
+
+ handleMouseOver = () => {
+ this.setState({ isIconShown: true });
+ };
+
+ handleMouseOut = () => {
+ this.setState({ isIconShown: false });
+ };
+
+ restoreItem = (e) => {
+ e.preventDefault();
+ const { record } = this.props;
+ const { commit_id, parent_dir, obj_name, is_dir } = record;
+ const path = parent_dir + obj_name;
+ const request = is_dir ?
+ seafileAPI.restoreFolder(this.props.repoID, commit_id, path) :
+ seafileAPI.restoreFile(this.props.repoID, commit_id, path);
+ request.then((res) => {
+ this.setState({
+ restored: true
+ });
+ toaster.success(gettext('Restored 1 item'));
+ }).catch((error) => {
+ let errorMsg = '';
+ if (error.response) {
+ errorMsg = error.response.data.error_msg || gettext('Error');
+ } else {
+ errorMsg = gettext('Please check the network.');
+ }
+ toaster.danger(errorMsg);
+ });
+ };
+
+ renderFolder = (e) => {
+ e.preventDefault();
+ const { record } = this.props;
+ this.props.renderFolder(record.commit_id, record.parent_dir, Utils.joinPath('/', record.obj_name));
+ };
+
+ render() {
+ const { record } = this.props;
+ const { restored, isIconShown } = this.state;
+
+ if (restored) return null;
+
+ return record.is_dir ? (
+
+ }) |
+ {record.obj_name} |
+ {record.parent_dir} |
+ {dayjs(record.deleted_time).format('YYYY-MM-DD')} |
+ |
+
+ {gettext('Restore')}
+ |
+
+ ) : (
+
+ }) |
+
+
+ {record.obj_name}
+
+ |
+ {record.parent_dir} |
+
+ {dayjs(record.deleted_time).format('YYYY-MM-DD')}
+ |
+ {Utils.bytesToSize(record.size)} |
+
+ {gettext('Restore')}
+ |
+
+ );
+ }
+}
+
+FileRecord.propTypes = {
+ record: PropTypes.object.isRequired,
+ repoID: PropTypes.string.isRequired,
+ renderFolder: PropTypes.func.isRequired,
+};
+
+export default FileRecord;
diff --git a/frontend/src/components/dialog/trash-dialog/table/file-records/index.js b/frontend/src/components/dialog/trash-dialog/table/file-records/index.js
new file mode 100644
index 0000000000..4a7d4c3d5d
--- /dev/null
+++ b/frontend/src/components/dialog/trash-dialog/table/file-records/index.js
@@ -0,0 +1,23 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import FileRecord from './file-record';
+
+const FileRecords = ({ records, repoID, renderFolder }) => {
+ if (!Array.isArray(records) || records.length === 0) return null;
+ return records.map((record, index) => {
+ return (
+
+ );
+ });
+};
+
+FileRecords.propTypes = {
+ records: PropTypes.array,
+};
+
+export default FileRecords;
diff --git a/frontend/src/components/dialog/trash-dialog/table/folder-records/folder-record.js b/frontend/src/components/dialog/trash-dialog/table/folder-records/folder-record.js
new file mode 100644
index 0000000000..193b50ebff
--- /dev/null
+++ b/frontend/src/components/dialog/trash-dialog/table/folder-records/folder-record.js
@@ -0,0 +1,69 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Utils } from '../../../../../utils/utils';
+import { gettext, siteRoot } from '../../../../../utils/constants';
+
+class FolderRecord extends React.Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ isIconShown: false
+ };
+ }
+
+ handleMouseOver = () => {
+ this.setState({ isIconShown: true });
+ };
+
+ handleMouseOut = () => {
+ this.setState({ isIconShown: false });
+ };
+
+ renderFolder = (e) => {
+ e.preventDefault();
+ const { commitID, baseDir, folderPath, record } = this.props;
+ this.props.renderFolder(commitID, baseDir, Utils.joinPath(folderPath, record.name));
+ };
+
+ render() {
+ const { commitID, baseDir, folderPath, record } = this.props;
+
+ return record.type == 'dir' ? (
+
+ }) |
+ {record.name} |
+ {record.parent_dir} |
+ |
+ |
+ |
+
+ ) : (
+
+
+
+ |
+
+
+ {record.name}
+
+ |
+ {record.parent_dir} |
+ |
+ {Utils.bytesToSize(record.size)} |
+ |
+
+ );
+ }
+}
+
+FolderRecord.propTypes = {
+ record: PropTypes.object.isRequired,
+ commitID: PropTypes.string.isRequired,
+ repoID: PropTypes.string.isRequired,
+ baseDir: PropTypes.string.isRequired,
+ folderPath: PropTypes.string.isRequired,
+ renderFolder: PropTypes.func.isRequired,
+};
+
+export default FolderRecord;
diff --git a/frontend/src/components/dialog/trash-dialog/table/folder-records/index.js b/frontend/src/components/dialog/trash-dialog/table/folder-records/index.js
new file mode 100644
index 0000000000..c5e25f5ca7
--- /dev/null
+++ b/frontend/src/components/dialog/trash-dialog/table/folder-records/index.js
@@ -0,0 +1,26 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import FolderRecord from './folder-record';
+
+const FolderRecords = ({ records, repoID, commitID, baseDir, folderPath, renderFolder }) => {
+ if (!Array.isArray(records) || records.length === 0) return null;
+ return records.map((record, index) => {
+ return (
+
+ );
+ });
+};
+
+FolderRecords.propTypes = {
+ records: PropTypes.array,
+};
+
+export default FolderRecords;
diff --git a/frontend/src/components/dialog/trash-dialog/table/index.js b/frontend/src/components/dialog/trash-dialog/table/index.js
new file mode 100644
index 0000000000..61b538d6a3
--- /dev/null
+++ b/frontend/src/components/dialog/trash-dialog/table/index.js
@@ -0,0 +1,59 @@
+import React, { useState, useEffect, useRef } from 'react';
+import PropTypes from 'prop-types';
+import { gettext } from '../../../../utils/constants';
+import FolderRecords from './folder-records';
+import FileRecords from './file-records';
+
+const Table = ({ repoID, renderFolder, data }) => {
+ 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);
+ };
+ }, []);
+
+ const { items, showFolder, commitID, baseDir, folderPath, folderItems } = data;
+
+ return (
+
+
+
+
+ {/* icon */} |
+ {gettext('Name')} |
+ {gettext('Original path')} |
+ {gettext('Delete Time')} |
+ {gettext('Size')} |
+ {/* op */} |
+
+
+
+ {showFolder ? (
+
+ ) : (
+
+ )}
+
+
+
+ );
+};
+
+Table.propTypes = {
+ repoID: PropTypes.string.isRequired,
+ data: PropTypes.object.isRequired,
+ renderFolder: PropTypes.func.isRequired,
+};
+
+export default Table;
diff --git a/frontend/src/utils/repo-trash-api.js b/frontend/src/utils/repo-trash-api.js
index d29f1fc286..aa10150184 100644
--- a/frontend/src/utils/repo-trash-api.js
+++ b/frontend/src/utils/repo-trash-api.js
@@ -34,7 +34,7 @@ class RepotrashAPI {
return this;
}
- getRepoFolderTrash2(repoID, page, per_page) {
+ getRepoFolderTrash(repoID, page, per_page) {
const url = this.server + '/api/v2.1/repos/' + repoID + '/trash2/';
let params = {
page: page || 1,
@@ -44,8 +44,8 @@ class RepotrashAPI {
}
}
-let repotrashAPI = new RepotrashAPI();
+let repoTrashAPI = new RepotrashAPI();
let xcsrfHeaders = cookie.load('sfcsrftoken');
-repotrashAPI.initForSeahubUsage({ siteRoot, xcsrfHeaders });
+repoTrashAPI.initForSeahubUsage({ siteRoot, xcsrfHeaders });
-export { repotrashAPI };
+export { repoTrashAPI };