mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-17 14:37:58 +00:00
Share dialog improve (#2760)
This commit is contained in:
parent
cd82bf2b67
commit
91c9ac8e80
14
frontend/package-lock.json
generated
14
frontend/package-lock.json
generated
@ -180,7 +180,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"reactstrap": {
|
"reactstrap": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "http://registry.npmjs.org/reactstrap/-/reactstrap-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/reactstrap/-/reactstrap-5.0.0.tgz",
|
||||||
"integrity": "sha512-y0eju/LAK7gbEaTFfq2iW92MF7/5Qh0tc1LgYr2mg92IX8NodGc03a+I+cp7bJ0VXHAiLy0bFL9UP89oSm4cBg==",
|
"integrity": "sha512-y0eju/LAK7gbEaTFfq2iW92MF7/5Qh0tc1LgYr2mg92IX8NodGc03a+I+cp7bJ0VXHAiLy0bFL9UP89oSm4cBg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"classnames": "^2.2.3",
|
"classnames": "^2.2.3",
|
||||||
@ -640,7 +640,7 @@
|
|||||||
},
|
},
|
||||||
"axios": {
|
"axios": {
|
||||||
"version": "0.18.0",
|
"version": "0.18.0",
|
||||||
"resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
|
||||||
"integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
|
"integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"follow-redirects": "^1.3.0",
|
"follow-redirects": "^1.3.0",
|
||||||
@ -2717,6 +2717,14 @@
|
|||||||
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
|
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"copy-to-clipboard": {
|
||||||
|
"version": "3.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.0.8.tgz",
|
||||||
|
"integrity": "sha512-c3GdeY8qxCHGezVb1EFQfHYK/8NZRemgcTIzPq7PuxjHAf/raKibn2QdhHPb/y6q74PMgH6yizaDZlRmw6QyKw==",
|
||||||
|
"requires": {
|
||||||
|
"toggle-selection": "^1.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"core-js": {
|
"core-js": {
|
||||||
"version": "1.2.7",
|
"version": "1.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
|
||||||
@ -9964,7 +9972,7 @@
|
|||||||
},
|
},
|
||||||
"react-popper": {
|
"react-popper": {
|
||||||
"version": "0.8.3",
|
"version": "0.8.3",
|
||||||
"resolved": "http://registry.npmjs.org/react-popper/-/react-popper-0.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-0.8.3.tgz",
|
||||||
"integrity": "sha1-D3MzMTfJ+wr27EB00tBYWgoEYeE=",
|
"integrity": "sha1-D3MzMTfJ+wr27EB00tBYWgoEYeE=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"popper.js": "^1.12.9",
|
"popper.js": "^1.12.9",
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
"MD5": "^1.3.0",
|
"MD5": "^1.3.0",
|
||||||
"autoprefixer": "7.1.6",
|
"autoprefixer": "7.1.6",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
|
"copy-to-clipboard": "^3.0.8",
|
||||||
"css-loader": "0.28.7",
|
"css-loader": "0.28.7",
|
||||||
"dotenv": "4.0.0",
|
"dotenv": "4.0.0",
|
||||||
"dotenv-expand": "4.2.0",
|
"dotenv-expand": "4.2.0",
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import moment from 'moment';
|
||||||
|
import copy from 'copy-to-clipboard';
|
||||||
|
import { Button, Form, FormGroup, Label, Input, InputGroup, InputGroupAddon } from 'reactstrap';
|
||||||
import { gettext, shareLinkExpireDaysMin, shareLinkExpireDaysMax } from '../../utils/constants';
|
import { gettext, shareLinkExpireDaysMin, shareLinkExpireDaysMax } from '../../utils/constants';
|
||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
import { Button, Form, FormGroup, Label, Input, InputGroup, InputGroupAddon } from 'reactstrap';
|
import SharedLinkInfo from '../../models/shared-link-info';
|
||||||
|
import toaster from '../toast';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
itemPath: PropTypes.string.isRequired,
|
itemPath: PropTypes.string.isRequired,
|
||||||
@ -21,9 +25,9 @@ class GenerateShareLink extends React.Component {
|
|||||||
password: '',
|
password: '',
|
||||||
passwdnew: '',
|
passwdnew: '',
|
||||||
expireDays: '',
|
expireDays: '',
|
||||||
token: '',
|
errorInfo: '',
|
||||||
link: '',
|
sharedLinkInfo: null,
|
||||||
errorInfo: ''
|
isNoticeMessageShow: false,
|
||||||
};
|
};
|
||||||
this.permissions = {
|
this.permissions = {
|
||||||
'can_edit': false,
|
'can_edit': false,
|
||||||
@ -41,10 +45,8 @@ class GenerateShareLink extends React.Component {
|
|||||||
let repoID = this.props.repoID;
|
let repoID = this.props.repoID;
|
||||||
seafileAPI.getShareLink(repoID, path).then((res) => {
|
seafileAPI.getShareLink(repoID, path).then((res) => {
|
||||||
if (res.data.length !== 0) {
|
if (res.data.length !== 0) {
|
||||||
this.setState({
|
let sharedLinkInfo = new SharedLinkInfo(res.data[0]);
|
||||||
link: res.data[0].link,
|
this.setState({sharedLinkInfo: sharedLinkInfo});
|
||||||
token: res.data[0].token,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -105,25 +107,36 @@ class GenerateShareLink extends React.Component {
|
|||||||
let permissions = this.permissions;
|
let permissions = this.permissions;
|
||||||
permissions = JSON.stringify(permissions);
|
permissions = JSON.stringify(permissions);
|
||||||
seafileAPI.createShareLink(repoID, itemPath, password, expireDays, permissions).then((res) => {
|
seafileAPI.createShareLink(repoID, itemPath, password, expireDays, permissions).then((res) => {
|
||||||
this.setState({
|
let sharedLinkInfo = new SharedLinkInfo(res.data);
|
||||||
link: res.data.link,
|
this.setState({sharedLinkInfo: sharedLinkInfo});
|
||||||
token: res.data.token
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onCopySharedLink = () => {
|
||||||
|
let sharedLink = this.state.sharedLinkInfo.link;
|
||||||
|
copy(sharedLink);
|
||||||
|
toaster.success(gettext('Share link is copied to the clipboard.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
onCopyDownloadLink = () => {
|
||||||
|
let downloadLink = this.state.sharedLinkInfo.link + '?dl';
|
||||||
|
copy(downloadLink);
|
||||||
|
toaster.success(gettext('Direct download link is copied to the clipboard.'));
|
||||||
|
}
|
||||||
|
|
||||||
deleteShareLink = () => {
|
deleteShareLink = () => {
|
||||||
seafileAPI.deleteShareLink(this.state.token).then(() => {
|
let sharedLinkInfo = this.state.sharedLinkInfo;
|
||||||
|
seafileAPI.deleteShareLink(sharedLinkInfo.token).then(() => {
|
||||||
this.setState({
|
this.setState({
|
||||||
link: '',
|
|
||||||
token: '',
|
|
||||||
password: '',
|
password: '',
|
||||||
passwordnew: '',
|
passwordnew: '',
|
||||||
isShowPasswordInput: false,
|
isShowPasswordInput: false,
|
||||||
expireDays: '',
|
expireDays: '',
|
||||||
isExpireChecked: false,
|
isExpireChecked: false,
|
||||||
errorInfo: '',
|
errorInfo: '',
|
||||||
|
sharedLinkInfo: null,
|
||||||
|
isNoticeMessageShow: false,
|
||||||
});
|
});
|
||||||
this.permissions = {
|
this.permissions = {
|
||||||
'can_edit': false,
|
'can_edit': false,
|
||||||
@ -216,13 +229,55 @@ class GenerateShareLink extends React.Component {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onNoticeMessageToggle = () => {
|
||||||
|
this.setState({isNoticeMessageShow: !this.state.isNoticeMessageShow});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.state.link) {
|
if (this.state.sharedLinkInfo) {
|
||||||
|
let sharedLinkInfo = this.state.sharedLinkInfo;
|
||||||
return (
|
return (
|
||||||
<Form>
|
<div>
|
||||||
<p>{this.state.link}</p>
|
<Form className="mb-4">
|
||||||
<Button onClick={this.deleteShareLink}>{gettext('Delete')}</Button>
|
<FormGroup className="mb-0">
|
||||||
</Form>
|
<dt className="text-secondary font-weight-normal">{gettext('Link:')}</dt>
|
||||||
|
<dd className="d-flex">
|
||||||
|
<span>{sharedLinkInfo.link}</span>{' '}
|
||||||
|
{sharedLinkInfo.is_expired ?
|
||||||
|
<span className="err-message">({gettext('Expired')})</span> :
|
||||||
|
<span className="far fa-copy action-icon" onClick={this.onCopySharedLink}></span>
|
||||||
|
}
|
||||||
|
</dd>
|
||||||
|
</FormGroup>
|
||||||
|
{!sharedLinkInfo.is_dir && ( //just for file
|
||||||
|
<FormGroup className="mb-0">
|
||||||
|
<dt className="text-secondary font-weight-normal">{gettext('Direct Download Link:')}</dt>
|
||||||
|
<dd className="d-flex">
|
||||||
|
<span>{sharedLinkInfo.link}?dl</span>{' '}
|
||||||
|
{sharedLinkInfo.is_expired ?
|
||||||
|
<span className="err-message">({gettext('Expired')})</span> :
|
||||||
|
<span className="far fa-copy action-icon" onClick={this.onCopyDownloadLink}></span>
|
||||||
|
}
|
||||||
|
</dd>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
{sharedLinkInfo.expire_date && (
|
||||||
|
<FormGroup className="mb-0">
|
||||||
|
<dt className="text-secondary font-weight-normal">{gettext('Expiration Date:')}</dt>
|
||||||
|
<dd>{moment(sharedLinkInfo.expire_date).format('YYYY-MM-DD hh:mm:ss')}</dd>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</Form>
|
||||||
|
{!this.state.isNoticeMessageShow ?
|
||||||
|
<Button onClick={this.onNoticeMessageToggle}>{gettext('Delete')}</Button> :
|
||||||
|
<div className="alert alert-warning">
|
||||||
|
<h4 className="alert-heading">{gettext('Are you sure you want to delete the share link?')}</h4>
|
||||||
|
<p className="mb-4">{gettext('If the share link is deleted, no one will be able to access it any more.')}</p>
|
||||||
|
<button className="btn btn-primary" onClick={this.deleteShareLink}>{gettext('Delete')}</button>{' '}
|
||||||
|
<button className="btn btn-secondary" onClick={this.onNoticeMessageToggle}>{gettext('Cancel')}</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { gettext } from '../../utils/constants';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import copy from 'copy-to-clipboard';
|
||||||
import { Button, Form, FormGroup, FormText, Label, Input, InputGroup, InputGroupAddon } from 'reactstrap';
|
import { Button, Form, FormGroup, FormText, Label, Input, InputGroup, InputGroupAddon } from 'reactstrap';
|
||||||
|
import { gettext } from '../../utils/constants';
|
||||||
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
|
import SharedUploadInfo from '../../models/shared-upload-info';
|
||||||
|
import toaster from '../toast';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
itemPath: PropTypes.string.isRequired,
|
itemPath: PropTypes.string.isRequired,
|
||||||
@ -17,8 +20,7 @@ class GenerateUploadLink extends React.Component {
|
|||||||
passwordVisible: false,
|
passwordVisible: false,
|
||||||
password: '',
|
password: '',
|
||||||
passwdnew: '',
|
passwdnew: '',
|
||||||
link: '',
|
sharedUploadInfo: null,
|
||||||
token:''
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,10 +33,8 @@ class GenerateUploadLink extends React.Component {
|
|||||||
let repoID = this.props.repoID;
|
let repoID = this.props.repoID;
|
||||||
seafileAPI.getUploadLinks(repoID, path).then((res) => {
|
seafileAPI.getUploadLinks(repoID, path).then((res) => {
|
||||||
if (res.data.length !== 0) {
|
if (res.data.length !== 0) {
|
||||||
this.setState({
|
let sharedUploadInfo = new SharedUploadInfo(res.data[0]);
|
||||||
link: res.data[0].link,
|
this.setState({sharedUploadInfo: sharedUploadInfo});
|
||||||
token: res.data[0].token,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -94,33 +94,46 @@ class GenerateUploadLink extends React.Component {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
seafileAPI.createUploadLink(repoID, path, this.state.password).then((res) => {
|
seafileAPI.createUploadLink(repoID, path, this.state.password).then((res) => {
|
||||||
this.setState({
|
let sharedUploadInfo = new SharedUploadInfo(res.data);
|
||||||
link: res.data.link,
|
this.setState({sharedUploadInfo: sharedUploadInfo});
|
||||||
token: res.data.token
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onCopyUploadLink = () => {
|
||||||
|
let uploadLink = this.state.sharedUploadInfo.link;
|
||||||
|
copy(uploadLink);
|
||||||
|
toaster.success(gettext('Upload link is copied to the clipboard.'));
|
||||||
|
}
|
||||||
|
|
||||||
deleteUploadLink = () => {
|
deleteUploadLink = () => {
|
||||||
seafileAPI.deleteUploadLink(this.state.token).then(() => {
|
let sharedUploadInfo = this.state.sharedUploadInfo
|
||||||
|
seafileAPI.deleteUploadLink(sharedUploadInfo.token).then(() => {
|
||||||
this.setState({
|
this.setState({
|
||||||
link: '',
|
|
||||||
token: '',
|
|
||||||
showPasswordInput: false,
|
showPasswordInput: false,
|
||||||
password: '',
|
password: '',
|
||||||
passwordnew: '',
|
passwordnew: '',
|
||||||
|
sharedUploadInfo: null,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.state.link) {
|
if (this.state.sharedUploadInfo) {
|
||||||
|
let sharedUploadInfo = this.state.sharedUploadInfo;
|
||||||
return (
|
return (
|
||||||
<Form>
|
<div>
|
||||||
<p>{this.state.link}</p>
|
<Form className="mb-4">
|
||||||
|
<FormGroup>
|
||||||
|
<dt className="text-secondary font-weight-normal">{gettext('Upload Link:')}</dt>
|
||||||
|
<dd className="d-flex">
|
||||||
|
<span>{sharedUploadInfo.link}</span>
|
||||||
|
<span className="far fa-copy action-icon" onClick={this.onCopyUploadLink}></span>
|
||||||
|
</dd>
|
||||||
|
</FormGroup>
|
||||||
|
</Form>
|
||||||
<Button onClick={this.deleteUploadLink}>{gettext('Delete')}</Button>
|
<Button onClick={this.deleteUploadLink}>{gettext('Delete')}</Button>
|
||||||
</Form>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
@ -11,7 +11,7 @@ const wrapperClass = css({
|
|||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
zIndex: 30
|
zIndex: 999999,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,8 +67,9 @@
|
|||||||
|
|
||||||
input.expire-input {
|
input.expire-input {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 5rem;
|
width: 4rem;
|
||||||
height: 1.5rem;
|
height: 1.5rem;
|
||||||
|
padding: 0.25rem 0.25rem;
|
||||||
margin: 0 0.25rem 0 1.25rem;
|
margin: 0 0.25rem 0 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user