diff --git a/frontend/src/components/dialog/generate-upload-link.js b/frontend/src/components/dialog/generate-upload-link.js
index 9dc019e75e..f0b09a57fd 100644
--- a/frontend/src/components/dialog/generate-upload-link.js
+++ b/frontend/src/components/dialog/generate-upload-link.js
@@ -6,7 +6,7 @@ import { Button, Form, FormGroup, Label, Input, InputGroup, InputGroupAddon, Ale
import { gettext, shareLinkPasswordMinLength, canSendShareLinkEmail } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';
-import SharedUploadInfo from '../../models/shared-upload-info';
+import UploadLink from '../../models/upload-link';
import toaster from '../toast';
import SendLink from '../send-link';
import SessionExpiredTip from '../session-expired-tip';
@@ -41,7 +41,7 @@ class GenerateUploadLink extends React.Component {
let repoID = this.props.repoID;
seafileAPI.getUploadLinks(repoID, path).then((res) => {
if (res.data.length !== 0) {
- let sharedUploadInfo = new SharedUploadInfo(res.data[0]);
+ let sharedUploadInfo = new UploadLink(res.data[0]);
this.setState({sharedUploadInfo: sharedUploadInfo});
}
}).catch((err) => {
@@ -98,7 +98,7 @@ class GenerateUploadLink extends React.Component {
let isValid = this.validateParamsInput();
if (isValid) {
seafileAPI.createUploadLink(repoID, path, password, expireDays).then((res) => {
- let sharedUploadInfo = new SharedUploadInfo(res.data);
+ let sharedUploadInfo = new UploadLink(res.data);
this.setState({sharedUploadInfo: sharedUploadInfo});
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
diff --git a/frontend/src/components/dialog/share-admin-link.js b/frontend/src/components/dialog/share-admin-link.js
new file mode 100644
index 0000000000..eea392965f
--- /dev/null
+++ b/frontend/src/components/dialog/share-admin-link.js
@@ -0,0 +1,44 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Modal, ModalHeader, ModalBody, ModalFooter, Button } from 'reactstrap';
+import copy from '@seafile/seafile-editor/dist//utils/copy-to-clipboard';
+import { gettext } from '../../utils/constants';
+import toaster from '../../components/toast';
+
+const propTypes = {
+ link: PropTypes.string.isRequired,
+ toggleDialog: PropTypes.func.isRequired
+};
+
+class ShareAdminLink extends React.Component {
+
+ constructor(props) {
+ super(props);
+ }
+
+ copyToClipboard = () => {
+ copy(this.props.link);
+ this.props.toggleDialog();
+ toaster.success(gettext('The link is copied to the clipboard.')), {duration: 2};
+ }
+
+ render() {
+ const { link, toggleDialog } = this.props;
+ return (
+
+ {gettext('Link')}
+
+ {link}
+
+
+
+
+
+
+ );
+ }
+}
+
+ShareAdminLink.propTypes = propTypes;
+
+export default ShareAdminLink;
diff --git a/frontend/src/models/shared-upload-info.js b/frontend/src/models/upload-link.js
similarity index 88%
rename from frontend/src/models/shared-upload-info.js
rename to frontend/src/models/upload-link.js
index cd7f0f9b8c..adead88785 100644
--- a/frontend/src/models/shared-upload-info.js
+++ b/frontend/src/models/upload-link.js
@@ -1,4 +1,4 @@
-class SharedUploadInfo {
+class UploadLink {
constructor(object) {
this.repo_id = object.repo_id;
@@ -17,4 +17,4 @@ class SharedUploadInfo {
}
-export default SharedUploadInfo;
+export default UploadLink;
diff --git a/frontend/src/pages/share-admin/share-links.js b/frontend/src/pages/share-admin/share-links.js
index 1e22395917..05faf00698 100644
--- a/frontend/src/pages/share-admin/share-links.js
+++ b/frontend/src/pages/share-admin/share-links.js
@@ -2,8 +2,6 @@ import React, { Component, Fragment } from 'react';
import { Link } from '@reach/router';
import moment from 'moment';
import { Dropdown, DropdownToggle, DropdownItem } from 'reactstrap';
-import { Modal, ModalHeader, ModalBody, ModalFooter, Button } from 'reactstrap';
-import copy from '@seafile/seafile-editor/dist//utils/copy-to-clipboard';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';
import { isPro, gettext, siteRoot, loginUrl, canGenerateUploadLink } from '../../utils/constants';
@@ -13,6 +11,7 @@ import Loading from '../../components/loading';
import toaster from '../../components/toast';
import EmptyTip from '../../components/empty-tip';
import ShareLinkPermissionSelect from '../../components/dialog/share-link-permission-select';
+import ShareAdminLink from '../../components/dialog/share-admin-link';
class Content extends Component {
@@ -30,37 +29,6 @@ class Content extends Component {
this.props.sortItems(sortBy, sortOrder);
}
- constructor(props) {
- super(props);
- this.state = {
- modalOpen: false,
- modalContent: ''
- };
- }
-
- // required by `Modal`, and can only set the 'open' state
- toggleModal = () => {
- this.setState({
- modalOpen: !this.state.modalOpen
- });
- }
-
- showModal = (options) => {
- this.toggleModal();
- this.setState({modalContent: options.content});
- }
-
- copyToClipboard = () => {
- copy(this.state.modalContent);
- this.setState({
- modalOpen: false
- });
- let message = gettext('Share link is copied to the clipboard.');
- toaster.success(message), {
- duration: 2
- };
- }
-
render() {
const { loading, errorMsg, items, sortBy, sortOrder } = this.props;
@@ -85,44 +53,32 @@ class Content extends Component {
// only for some columns
const columnWidths = isPro ? ['14%', '7%', '14%'] : ['21%', '14%', '20%'];
const table = (
-
-
-
- {gettext('Link')}
-
- {this.state.modalContent}
-
-
- {' '}
-
-
-
-
+
);
return items.length ? table : emptyTip;
@@ -147,7 +103,8 @@ class Item extends Component {
currentPermission: isPro ? this.getCurrentPermission() : '',
isOpIconShown: false,
isOpMenuOpen: false, // for mobile
- isPermSelectDialogOpen: false // for mobile
+ isPermSelectDialogOpen: false, // for mobile
+ isLinkDialogOpen: false
};
}
@@ -199,6 +156,12 @@ class Item extends Component {
});
}
+ toggleLinkDialog = () => {
+ this.setState({
+ isLinkDialogOpen: !this.state.isLinkDialogOpen
+ });
+ }
+
handleMouseOver = () => {
this.setState({isOpIconShown: true});
}
@@ -209,7 +172,7 @@ class Item extends Component {
viewLink = (e) => {
e.preventDefault();
- this.props.showModal({content: this.props.item.link});
+ this.toggleLinkDialog();
}
removeLink = (e) => {
@@ -217,7 +180,7 @@ class Item extends Component {
this.props.onRemoveLink(this.props.item);
}
- renderExpriedData = () => {
+ renderExpiration = () => {
let item = this.props.item;
if (!item.expire_date) {
return (
@@ -228,8 +191,7 @@ class Item extends Component {
return (
{item.is_expired ?
- {expire_date} :
- expire_date
+ {expire_date} : expire_date
}
);
@@ -252,16 +214,16 @@ class Item extends Component {
render() {
const item = this.props.item;
- const { currentPermission, isOpIconShown, isPermSelectDialogOpen } = this.state;
+ const { currentPermission, isOpIconShown, isPermSelectDialogOpen, isLinkDialogOpen } = this.state;
- let iconUrl, linkUrl;
+ let iconUrl, objUrl;
if (item.is_dir) {
let path = item.path === '/' ? '/' : item.path.slice(0, item.path.length - 1);
iconUrl = Utils.getFolderIconUrl(false);
- linkUrl = `${siteRoot}library/${item.repo_id}/${encodeURIComponent(item.repo_name)}${Utils.encodePath(path)}`;
+ objUrl = `${siteRoot}library/${item.repo_id}/${encodeURIComponent(item.repo_name)}${Utils.encodePath(path)}`;
} else {
iconUrl = Utils.getFileIconUrl(item.obj_name);
- linkUrl = `${siteRoot}lib/${item.repo_id}/file${Utils.encodePath(item.path)}`;
+ objUrl = `${siteRoot}lib/${item.repo_id}/file${Utils.encodePath(item.path)}`;
}
const desktopItem = (
@@ -269,8 +231,8 @@ class Item extends Component {
 |
{item.is_dir ?
- {item.obj_name} :
- {item.obj_name}
+ {item.obj_name} :
+ {item.obj_name}
}
|
{item.repo_name} |
@@ -286,9 +248,9 @@ class Item extends Component {
}
{item.view_cnt} |
- {this.renderExpriedData()} |
+ {this.renderExpiration()} |
-
+ {!item.is_expired && }
|
@@ -300,14 +262,14 @@ class Item extends Component {
 |
{item.is_dir ?
- {item.obj_name} :
- {item.obj_name}
+ {item.obj_name} :
+ {item.obj_name}
}
{isPro && {Utils.getShareLinkPermissionObject(currentPermission).text}}
{item.repo_name}
{item.view_cnt}({gettext('Visits')})
- {this.renderExpriedData()}({gettext('Expiration')})
+ {this.renderExpiration()}({gettext('Expiration')})
|
@@ -322,7 +284,7 @@ class Item extends Component {
{(isPro && !item.is_expired) && {gettext('Permission')}}
- {gettext('View')}
+ {!item.is_expired && {gettext('View')}}
{gettext('Remove')}
@@ -340,7 +302,17 @@ class Item extends Component {
);
- return this.props.isDesktop ? desktopItem : mobileItem;
+ return (
+
+ {this.props.isDesktop ? desktopItem : mobileItem}
+ {isLinkDialogOpen &&
+
+ }
+
+ );
}
}
diff --git a/frontend/src/pages/share-admin/upload-links.js b/frontend/src/pages/share-admin/upload-links.js
index 1924de7d83..92ea770082 100644
--- a/frontend/src/pages/share-admin/upload-links.js
+++ b/frontend/src/pages/share-admin/upload-links.js
@@ -1,84 +1,65 @@
import React, { Component, Fragment } from 'react';
import { Link } from '@reach/router';
import moment from 'moment';
-import { Modal, ModalHeader, ModalBody } from 'reactstrap';
+import { Dropdown, DropdownToggle, DropdownItem } from 'reactstrap';
import { gettext, siteRoot, loginUrl, canGenerateShareLink } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';
import toaster from '../../components/toast';
-import SharedUploadInfo from '../../models/shared-upload-info';
+import Loading from '../../components/loading';
import EmptyTip from '../../components/empty-tip';
+import UploadLink from '../../models/upload-link';
+import ShareAdminLink from '../../components/dialog/share-admin-link';
class Content extends Component {
- constructor(props) {
- super(props);
- this.state = {
- modalOpen: false,
- modalContent: ''
- };
- }
-
- // required by `Modal`, and can only set the 'open' state
- toggleModal = () => {
- this.setState({
- modalOpen: !this.state.modalOpen
- });
- }
-
- showModal = (options) => {
- this.toggleModal();
- this.setState({
- modalContent: options.content
- });
- }
-
render() {
const { loading, errorMsg, items } = this.props;
if (loading) {
- return ;
- } else if (errorMsg) {
- return {errorMsg} ;
- } else {
- const emptyTip = (
-
- {gettext('You don\'t have any upload links')}
- {gettext('You can generate an upload link from any folder. Anyone who receives this link can upload files to this folder.')}
-
- );
-
- const table = (
-
-
-
-
- {/*icon*/} |
- {gettext('Name')} |
- {gettext('Library')} |
- {gettext('Visits')} |
- {gettext('Expiration')} |
- {/*Operations*/} |
-
-
-
- {items.map((item, index) => {
- return (- );
- })}
-
-
-
-
- {gettext('Link')}
-
- {this.state.modalContent}
-
-
-
- );
-
- return items.length ? table : emptyTip;
+ return ;
}
+ if (errorMsg) {
+ return {errorMsg} ;
+ }
+
+ const emptyTip = (
+
+ {gettext('You don\'t have any upload links')}
+ {gettext('You can generate an upload link from any folder. Anyone who receives this link can upload files to this folder.')}
+
+ );
+
+ const isDesktop = Utils.isDesktop();
+ const table = (
+
+
+ {isDesktop ? (
+
+ {/*icon*/} |
+ {gettext('Name')} |
+ {gettext('Library')} |
+ {gettext('Visits')} |
+ {gettext('Expiration')} |
+ {/*Operations*/} |
+
+ ) : (
+
+ |
+ |
+ |
+
+ )}
+
+
+ {items.map((item, index) => {
+ return (- );
+ })}
+
+
+ );
+
+ return items.length ? table : emptyTip;
}
}
@@ -87,21 +68,35 @@ class Item extends Component {
constructor(props) {
super(props);
this.state = {
- showOpIcon: false,
+ isOpIconShown: false,
+ isOpMenuOpen: false, // for mobile
+ isLinkDialogOpen: false
};
}
+ toggleOpMenu = () => {
+ this.setState({
+ isOpMenuOpen: !this.state.isOpMenuOpen
+ });
+ }
+
+ toggleLinkDialog = () => {
+ this.setState({
+ isLinkDialogOpen: !this.state.isLinkDialogOpen
+ });
+ }
+
handleMouseOver = () => {
- this.setState({showOpIcon: true});
+ this.setState({isOpIconShown: true});
}
handleMouseOut = () => {
- this.setState({showOpIcon: false});
+ this.setState({isOpIconShown: false});
}
viewLink = (e) => {
e.preventDefault();
- this.props.showModal({content: this.props.item.link});
+ this.toggleLinkDialog();
}
removeLink = (e) => {
@@ -109,15 +104,7 @@ class Item extends Component {
this.props.onRemoveLink(this.props.item);
}
- getUploadParams = () => {
- let item = this.props.item;
- let iconUrl = Utils.getFolderIconUrl(false);
- let uploadUrl = `${siteRoot}library/${item.repo_id}/${item.repo_name}${Utils.encodePath(item.path)}`;
-
- return { iconUrl, uploadUrl };
- }
-
- renderExpriedData = () => {
+ renderExpiration = () => {
let item = this.props.item;
if (!item.expire_date) {
return (
@@ -128,8 +115,7 @@ class Item extends Component {
return (
{item.is_expired ?
- {expire_date} :
- expire_date
+ {expire_date} : expire_date
}
);
@@ -137,25 +123,67 @@ class Item extends Component {
render() {
let item = this.props.item;
- let { iconUrl, uploadUrl } = this.getUploadParams();
+ const { isOpIconShown, isLinkDialogOpen } = this.state;
- let iconVisibility = this.state.showOpIcon ? '' : ' invisible';
- let linkIconClassName = 'sf2-icon-link action-icon' + iconVisibility;
- let deleteIconClassName = 'sf2-icon-delete action-icon' + iconVisibility;
+ const iconUrl = Utils.getFolderIconUrl(false);
+ const repoUrl = `${siteRoot}library/${item.repo_id}/${encodeURIComponent(item.repo_name)}`;
+ const objUrl = `${repoUrl}${Utils.encodePath(item.path)}`;
- return (
+ const desktopItem = (
-  |
- {item.obj_name} |
- {item.repo_name} |
+  |
+ {item.obj_name} |
+ {item.repo_name} |
{item.view_cnt} |
- {this.renderExpriedData()} |
+ {this.renderExpiration()} |
-
-
+ {!item.is_expired && }
+
|
);
+
+ const mobileItem = (
+
+  |
+
+ {item.obj_name}
+
+ {item.repo_name}
+ {item.view_cnt}({gettext('Visits')})
+ {this.renderExpiration()}({gettext('Expiration')})
+ |
+
+
+
+
+
+
+ {!item.is_expired && {gettext('View')}}
+ {gettext('Remove')}
+
+
+
+ |
+
+ );
+ return (
+
+ {this.props.isDesktop ? desktopItem : mobileItem}
+ {isLinkDialogOpen &&
+
+ }
+
+ );
}
}
@@ -172,9 +200,8 @@ class ShareAdminUploadLinks extends Component {
componentDidMount() {
seafileAPI.listUploadLinks().then((res) => {
- // res: {data: Array(2), status: 200, statusText: "OK", headers: {…}, config: {…}, …}
let items = res.data.map(item => {
- return new SharedUploadInfo(item);
+ return new UploadLink(item);
});
this.setState({
loading: false,
@@ -209,13 +236,10 @@ class ShareAdminUploadLinks extends Component {
return uploadItem.token !== item.token;
});
this.setState({items: items});
- let message = gettext("Successfully deleted upload link.");
+ const message = gettext('Successfully deleted 1 item.');
toaster.success(message);
}).catch((error) => {
- let errMessage = Utils.getErrorMsg(error);
- if (errMessage === gettext('Error')) {
- errMessage = gettext("Failed to delete upload link.");
- }
+ const errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
}
@@ -226,7 +250,7 @@ class ShareAdminUploadLinks extends Component {
- { canGenerateShareLink && (
+ {canGenerateShareLink && (
- {gettext('Share Links')}
)}
- {gettext('Upload Links')}
@@ -234,9 +258,9 @@ class ShareAdminUploadLinks extends Component {
|