diff --git a/frontend/config/webpack.config.dev.js b/frontend/config/webpack.config.dev.js
index bf48d405bb..e55c48c1c0 100644
--- a/frontend/config/webpack.config.dev.js
+++ b/frontend/config/webpack.config.dev.js
@@ -84,6 +84,11 @@ module.exports = {
require.resolve('react-dev-utils/webpackHotDevClient'),
paths.appSrc + "/draw/draw.js",
],
+ sharedDirView: [
+ require.resolve('./polyfills'),
+ require.resolve('react-dev-utils/webpackHotDevClient'),
+ paths.appSrc + "/shared-dir-view.js",
+ ],
sharedFileViewMarkdown: [
require.resolve('./polyfills'),
require.resolve('react-dev-utils/webpackHotDevClient'),
diff --git a/frontend/config/webpack.config.prod.js b/frontend/config/webpack.config.prod.js
index 38fe5aaffb..26e95ab6fe 100644
--- a/frontend/config/webpack.config.prod.js
+++ b/frontend/config/webpack.config.prod.js
@@ -65,6 +65,7 @@ module.exports = {
app: [require.resolve('./polyfills'), paths.appSrc + "/app.js"],
draft: [require.resolve('./polyfills'), paths.appSrc + "/draft.js"],
draw: [require.resolve('./polyfills'), paths.appSrc + "/draw/draw.js"],
+ sharedDirView: [require.resolve('./polyfills'), paths.appSrc + "/shared-dir-view.js"],
sharedFileViewMarkdown: [require.resolve('./polyfills'), paths.appSrc + "/shared-file-view-markdown.js"],
sharedFileViewText: [require.resolve('./polyfills'), paths.appSrc + "/shared-file-view-text.js"],
sharedFileViewImage: [require.resolve('./polyfills'), paths.appSrc + "/shared-file-view-image.js"],
diff --git a/frontend/src/components/dialog/share-link-zip-download-dialog.js b/frontend/src/components/dialog/share-link-zip-download-dialog.js
new file mode 100644
index 0000000000..5fe1100008
--- /dev/null
+++ b/frontend/src/components/dialog/share-link-zip-download-dialog.js
@@ -0,0 +1,127 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Modal, ModalHeader, ModalBody } from 'reactstrap';
+import { gettext, fileServerRoot } from '../../utils/constants';
+import { seafileAPI } from '../../utils/seafile-api';
+import Loading from '../loading';
+
+const propTypes = {
+ token: PropTypes.string.isRequired,
+ path: PropTypes.string.isRequired,
+ toggleDialog: PropTypes.func.isRequired
+};
+
+let interval;
+
+class ShareLinkZipDownloadDialog extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ isLoading: true,
+ errorMsg: '',
+ zipProgress: null
+ };
+ }
+
+ componentDidMount() {
+ const { token, path } = this.props;
+ seafileAPI.getShareLinkZipTask(token, path).then((res) => {
+ const zipToken = res.data['zip_token'];
+ this.setState({
+ isLoading: false,
+ errorMsg: '',
+ zipToken: zipToken
+ });
+ this.queryZipProgress();
+ interval = setInterval(this.queryZipProgress, 1000);
+ }).catch((error) => {
+ let errorMsg = '';
+ if (error.response) {
+ errorMsg = gettext('Error');
+ } else {
+ errorMsg = gettext('Please check the network.');
+ }
+ this.setState({
+ isLoading: false,
+ errorMsg: errorMsg
+ });
+ });
+ }
+
+ queryZipProgress = () => {
+ const zipToken = this.state.zipToken;
+ seafileAPI.queryZipProgress(zipToken).then((res) => {
+ const data = res.data;
+ this.setState({
+ zipProgress: data.total == 0 ? '100%' : (data.zipped/data.total*100).toFixed(2) + '%'
+ });
+ if (data['total'] == data['zipped']) {
+ clearInterval(interval);
+ this.props.toggleDialog();
+ location.href = `${fileServerRoot}zip/${zipToken}`;
+ }
+ }).catch((error) => {
+ clearInterval(interval);
+ let errorMsg = '';
+ if (error.response) {
+ errorMsg = gettext('Error');
+ } else {
+ errorMsg = gettext('Please check the network.');
+ }
+ this.setState({
+ isLoading: false,
+ errorMsg: errorMsg
+ });
+ });
+ }
+
+ cancelZipTask = () => {
+ const zipToken = this.state.zipToken;
+ seafileAPI.cancelZipTask(zipToken).then((res) => {
+ // do nothing
+ }).catch((error) => {
+ // do nothing
+ });
+ }
+
+ toggleDialog = () => {
+ const zipProgress = this.state.zipProgress;
+ if (zipProgress && zipProgress != '100%') {
+ clearInterval(interval);
+ this.cancelZipTask();
+ }
+ this.props.toggleDialog();
+ }
+
+ render() {
+ return (
+
{errorMsg}
; + } + + return{`${gettext('Packaging...')} ${zipProgress}`}
; + } +} + +ShareLinkZipDownloadDialog.propTypes = propTypes; + +export default ShareLinkZipDownloadDialog; diff --git a/frontend/src/css/shared-dir-view.css b/frontend/src/css/shared-dir-view.css new file mode 100644 index 0000000000..d3386bb0e0 --- /dev/null +++ b/frontend/src/css/shared-dir-view.css @@ -0,0 +1,28 @@ +body { + overflow: hidden; +} +#wrapper { + height: 100%; +} +.top-header { + background: #f4f4f7; + border-bottom: 1px solid #e8e8e8; + padding: 8px 16px 4px; + height: 53px; + flex-shrink: 0; +} +.title { + font-size: 1.4rem; + margin-bottom: .5rem; +} +.shared-dir-view-main { + width: calc(100% - 40px); + max-width: 950px; + padding: 15px 0; + margin: 0 auto; +} +.op-bar { + padding: 9px 10px; + background: #f2f2f2; + border-radius: 2px; +} diff --git a/frontend/src/shared-dir-view.js b/frontend/src/shared-dir-view.js new file mode 100644 index 0000000000..fe40a7f5e1 --- /dev/null +++ b/frontend/src/shared-dir-view.js @@ -0,0 +1,255 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Button } from 'reactstrap'; +import moment from 'moment'; +import Account from './components/common/account'; +import { gettext, siteRoot, mediaUrl, logoPath, logoWidth, logoHeight, siteTitle } from './utils/constants'; +import { Utils } from './utils/utils'; +import { seafileAPI } from './utils/seafile-api'; +import Loading from './components/loading'; +import toaster from './components/toast'; +import ModalPortal from './components/modal-portal'; +import ShareLinkZipDownloadDialog from './components/dialog/share-link-zip-download-dialog'; + +import './css/shared-dir-view.css'; + +let loginUser = window.app.pageOptions.name; +const { token, trafficOverLimit, dirName, sharedBy, path, canDownload } = window.shared.pageOptions; + +const showDownloadIcon = !trafficOverLimit && canDownload; + +class SharedDirView extends React.Component { + + constructor(props) { + super(props); + this.state = { + isLoading: true, + errorMsg: '', + items: [], + isZipDialogOpen: false, + zipFolderPath: '' + }; + } + + componentDidMount() { + if (trafficOverLimit) { + toaster.danger(gettext('File download is disabled: the share link traffic of owner is used up.'), { + duration: 3 + }); + } + + seafileAPI.listSharedDir(token, path).then((res) => { + const items = res.data['dirent_list']; + this.setState({ + isLoading: false, + errorMsg: '', + items: items + }); + }).catch((error) => { + let errorMsg = ''; + if (error.response) { + if (error.response.data && error.response.data['error_msg']) { + errorMsg = error.response.data['error_msg']; + } else { + errorMsg = gettext('Error'); + } + } else { + errorMsg = gettext('Please check the network.'); + } + this.setState({ + isLoading: false, + errorMsg: errorMsg + }); + }); + } + + renderPath = () => { + // path: '/', or '/g/' + if (path == '/') { + return dirName; + } + + let pathList = path.substr(0, path.length -1).split('/'); + return ( +{gettext('Shared by: ')}{sharedBy}
+{gettext('Current path: ')}{this.renderPath()}
+ {showDownloadIcon && + + } +{errorMsg}
; + } + + return ( ++ | {gettext('Name')} | +{gettext('Size')} | +{gettext('Last Update')} | +{gettext('Operations')} | +
---|