mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-01 15:09:14 +00:00
[shared dir view] redesigned the 'file upload' dialog (#6010)
This commit is contained in:
@@ -16,6 +16,7 @@ const propTypes = {
|
||||
onUploadCancel: PropTypes.func.isRequired,
|
||||
onUploadRetry: PropTypes.func.isRequired,
|
||||
onUploadRetryAll: PropTypes.func.isRequired,
|
||||
isUploading : PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
class UploadProgressDialog extends React.Component {
|
||||
|
@@ -44,7 +44,6 @@ class FileUploader extends React.Component {
|
||||
isUploadRemindDialogShow: false,
|
||||
currentResumableFile: null,
|
||||
uploadBitrate: 0,
|
||||
allFilesUploaded: false,
|
||||
};
|
||||
|
||||
this.uploadInput = React.createRef();
|
||||
@@ -157,11 +156,6 @@ class FileUploader extends React.Component {
|
||||
|
||||
onChunkingComplete = (resumableFile) => {
|
||||
|
||||
let allFilesUploaded = this.state.allFilesUploaded;
|
||||
if (allFilesUploaded === true) {
|
||||
this.setState({allFilesUploaded: false});
|
||||
}
|
||||
|
||||
//get parent_dir relative_path
|
||||
let path = this.props.path === '/' ? '/' : this.props.path + '/';
|
||||
let fileName = resumableFile.fileName;
|
||||
@@ -436,7 +430,6 @@ class FileUploader extends React.Component {
|
||||
this.notifiedFolders = [];
|
||||
// reset upload link loaded
|
||||
this.isUploadLinkLoaded = false;
|
||||
this.setState({allFilesUploaded: true});
|
||||
};
|
||||
|
||||
onPause = () => {
|
||||
@@ -533,8 +526,7 @@ class FileUploader extends React.Component {
|
||||
|
||||
if (!this.resumable.isUploading()) {
|
||||
this.setState({
|
||||
totalProgress: '100',
|
||||
allFilesUploaded: true,
|
||||
totalProgress: 100
|
||||
});
|
||||
this.loaded = 0;
|
||||
}
|
||||
@@ -554,8 +546,7 @@ class FileUploader extends React.Component {
|
||||
this.loaded = 0;
|
||||
|
||||
this.setState({
|
||||
allFilesUploaded: true,
|
||||
totalProgress: '100',
|
||||
totalProgress: 100,
|
||||
uploadFileList: uploadFileList
|
||||
});
|
||||
// reset upload link loaded
|
||||
@@ -683,12 +674,12 @@ class FileUploader extends React.Component {
|
||||
forbidUploadFileList={this.state.forbidUploadFileList}
|
||||
totalProgress={this.state.totalProgress}
|
||||
uploadBitrate={this.state.uploadBitrate}
|
||||
allFilesUploaded={this.state.allFilesUploaded}
|
||||
onCloseUploadDialog={this.onCloseUploadDialog}
|
||||
onCancelAllUploading={this.onCancelAllUploading}
|
||||
onUploadCancel={this.onUploadCancel}
|
||||
onUploadRetry={this.onUploadRetry}
|
||||
onUploadRetryAll={this.onUploadRetryAll}
|
||||
isUploading={this.resumable.isUploading()}
|
||||
/>
|
||||
}
|
||||
</Fragment>
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { gettext, maxUploadFileSize } from '../../utils/constants';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import { gettext } from '../../utils/constants';
|
||||
|
||||
const propTypes = {
|
||||
file: PropTypes.object,
|
||||
@@ -9,15 +10,20 @@ const propTypes = {
|
||||
class ForbidUploadListItem extends React.Component {
|
||||
|
||||
render() {
|
||||
let { file } = this.props;
|
||||
let msg = gettext('Please upload files less than {placeholder}M').replace('{placeholder}', maxUploadFileSize);
|
||||
const { file } = this.props;
|
||||
return (
|
||||
<tr className="file-upload-item">
|
||||
<td className="upload-name">
|
||||
<div className="ellipsis" title={file.name}>{file.name}</div>
|
||||
</td>
|
||||
|
||||
<td colSpan={3} className="error">{msg}</td>
|
||||
<td>{Utils.bytesToSize(file.size)}</td>
|
||||
<td>
|
||||
<div className="d-flex align-items-center">
|
||||
<span className="upload-failure-icon fas fa-exclamation mr-2"></span>
|
||||
<span className="upload-failure-msg">{gettext('File too large')}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
@@ -73,18 +73,15 @@ class UploadListItem extends React.Component {
|
||||
let progress = Math.round(resumableFile.progress() * 100);
|
||||
let error = resumableFile.error;
|
||||
|
||||
const fileName = resumableFile.newFileName;
|
||||
const size = this.formatFileSize(resumableFile.size);
|
||||
|
||||
return (
|
||||
<tr className="file-upload-item">
|
||||
<td className="upload-name">
|
||||
<div className="ellipsis" title={fileName}>{fileName}</div>
|
||||
<div className="ellipsis">{resumableFile.newFileName}</div>
|
||||
</td>
|
||||
<td className="ellipsis">
|
||||
<span className="file-size" title={size}>{size}</span>
|
||||
<td>
|
||||
<span className="file-size">{this.formatFileSize(resumableFile.size)}</span>
|
||||
</td>
|
||||
<td className="upload-progress ellipsis">
|
||||
<td className="upload-progress">
|
||||
{(this.state.uploadState === UPLOAD_UPLOADING || this.state.uploadState === UPLOAD_ISSAVING) &&
|
||||
<Fragment>
|
||||
{resumableFile.size >= (100 * 1000 * 1000) &&
|
||||
@@ -96,7 +93,7 @@ class UploadListItem extends React.Component {
|
||||
</div>
|
||||
{(resumableFile.remainingTime === -1) && <div className="progress-text">{gettext('Preparing to upload...')}</div>}
|
||||
{(resumableFile.remainingTime > 0) && <div className="progress-text">{gettext('Remaining')}{' '}{Utils.formatTime(resumableFile.remainingTime)}</div>}
|
||||
{(resumableFile.remainingTime === 0) && <div className="progress-text">{gettext('Indexing...')}</div>}
|
||||
{(resumableFile.remainingTime === 0) && <div className="progress-text">{gettext('Saving...')}</div>}
|
||||
</div>
|
||||
)}
|
||||
{!resumableFile.isUploading() && (
|
||||
@@ -108,32 +105,46 @@ class UploadListItem extends React.Component {
|
||||
)}
|
||||
</Fragment>
|
||||
}
|
||||
{(resumableFile.size < (100 * 1000 * 1000)) &&
|
||||
{(resumableFile.size < (100 * 1000 * 1000)) && (
|
||||
<>
|
||||
<div className="progress-container d-flex align-items-center">
|
||||
<div className="progress">
|
||||
<div className="progress-bar" role="progressbar" style={{width: `${progress}%`}} aria-valuenow={progress} aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</Fragment>
|
||||
}
|
||||
{this.state.uploadState === UPLOAD_ERROR && (
|
||||
<div className="message err-message ml-0" dangerouslySetInnerHTML={{__html: error}}></div>
|
||||
)}
|
||||
</td>
|
||||
<td className="upload-operation ellipsis">
|
||||
<Fragment>
|
||||
{this.state.uploadState === UPLOAD_UPLOADING && (
|
||||
<a href="#" onClick={this.onUploadCancel}>{gettext('Cancel')}</a>
|
||||
)}
|
||||
{this.state.uploadState === UPLOAD_ERROR && (
|
||||
<a href="#" onClick={this.onUploadRetry}>{gettext('Retry')}</a>
|
||||
<>
|
||||
{progress == 0 && <p className="progress-text mb-0">{gettext('Waiting...')}</p>}
|
||||
{progress > 0 && <p className="progress-text mb-0">{`${gettext('Uploading...')} ${progress}%`}</p>}
|
||||
</>
|
||||
)}
|
||||
{this.state.uploadState === UPLOAD_ISSAVING && (
|
||||
<span className="saving">{gettext('Saving...')}</span>
|
||||
<p className="progress-text mb-0">{gettext('Saving...')}</p>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Fragment>
|
||||
}
|
||||
{this.state.uploadState === UPLOAD_UPLOADED && (
|
||||
<span className="uploaded">{gettext('Uploaded')}</span>
|
||||
<div className="d-flex align-items-center">
|
||||
<span className="upload-success-icon sf2-icon-tick mr-2"></span>
|
||||
<span className="upload-success-msg">{gettext('Uploaded')}</span>
|
||||
</div>
|
||||
)}
|
||||
{this.state.uploadState === UPLOAD_ERROR && (
|
||||
<div className="d-flex align-items-center">
|
||||
<span className="upload-failure-icon fas fa-exclamation mr-2"></span>
|
||||
<span className="upload-failure-msg" dangerouslySetInnerHTML={{__html: error}}></span>
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
<td className="upload-operation">
|
||||
<Fragment>
|
||||
{this.state.uploadState === UPLOAD_UPLOADING && (
|
||||
<a href="#" onClick={this.onUploadCancel} role="button">{gettext('Cancel')}</a>
|
||||
)}
|
||||
{this.state.uploadState === UPLOAD_ERROR && (
|
||||
<a href="#" onClick={this.onUploadRetry} role="button">{gettext('Retry')}</a>
|
||||
)}
|
||||
</Fragment>
|
||||
</td>
|
||||
|
@@ -16,7 +16,7 @@ const propTypes = {
|
||||
onUploadCancel: PropTypes.func.isRequired,
|
||||
onUploadRetry: PropTypes.func.isRequired,
|
||||
onUploadRetryAll: PropTypes.func.isRequired,
|
||||
allFilesUploaded: PropTypes.bool.isRequired,
|
||||
isUploading : PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
class UploadProgressDialog extends React.Component {
|
||||
@@ -43,52 +43,74 @@ class UploadProgressDialog extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { totalProgress, retryFileList, uploadBitrate, uploadFileList, forbidUploadFileList, isUploading } = this.props;
|
||||
|
||||
let uploadBitrate = Utils.formatBitRate(this.props.uploadBitrate);
|
||||
let uploadedMessage = gettext('File Upload');
|
||||
let uploadingMessage = gettext('File Uploading...') + ' ' + this.props.totalProgress + '% (' + uploadBitrate + ')';
|
||||
const filesUploadedMsg = gettext('{uploaded_files_num}/{all_files_num} Files')
|
||||
.replace('{uploaded_files_num}', uploadFileList.filter(file => file.isSaved).length)
|
||||
.replace('{all_files_num}', uploadFileList.length);
|
||||
|
||||
let uploadingOptions = (<span className="sf2-icon-minus" onClick={this.onMinimizeUpload}></span>);
|
||||
|
||||
let uploadedOptions = (
|
||||
<Fragment>
|
||||
<span className="sf2-icon-minus" onClick={this.onMinimizeUpload}></span>
|
||||
<span className="sf2-icon-x1" onClick={this.onCloseUpload}></span>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
let { totalProgress, allFilesUploaded, retryFileList } = this.props;
|
||||
let filesFailedMsg;
|
||||
if (!isUploading) {
|
||||
const failedNum = uploadFileList.filter(file => file.error).length + forbidUploadFileList.length;
|
||||
if (failedNum > 0) {
|
||||
filesFailedMsg = gettext('{failed_files_num} file(s) failed to upload')
|
||||
.replace('{failed_files_num}', failedNum);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="uploader-list-view mw-100" style={{height: this.state.isMinimized ? '2.25rem' : '20rem'}}>
|
||||
<div className="uploader-list-header">
|
||||
<div className="title">
|
||||
{totalProgress === 100 ? uploadedMessage : uploadingMessage}
|
||||
<div className="uploader-list-view mw-100" style={{height: this.state.isMinimized ? document.querySelector('.uploader-list-header').offsetHeight : '20rem'}}>
|
||||
<div className="uploader-list-header flex-shrink-0">
|
||||
<div>
|
||||
{isUploading ? (
|
||||
<>
|
||||
<span>{gettext('File Uploading...')}</span>
|
||||
<span className="ml-2">{`${totalProgress}% (${Utils.formatBitRate(uploadBitrate)})`}</span>
|
||||
<div className="progress">
|
||||
<div className="progress-bar" role="progressbar" style={{width: `${totalProgress}%`}} aria-valuenow={totalProgress} aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<div className="uploader-options">
|
||||
{totalProgress === 100 || allFilesUploaded ? uploadedOptions : uploadingOptions}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{filesFailedMsg ?
|
||||
<p className="m-0 error">{filesFailedMsg}</p> :
|
||||
<p className="m-0">{gettext('All files uploaded')}</p>
|
||||
}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="upload-dialog-op-container">
|
||||
<span className="sf2-icon-minus upload-dialog-op" onClick={this.onMinimizeUpload}></span>
|
||||
{!isUploading && <span className="sf2-icon-x1 upload-dialog-op" onClick={this.onCloseUpload}></span>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="uploader-list-content">
|
||||
<div className="text-right mt-2">
|
||||
{retryFileList.length > 0 ?
|
||||
<span className="cursor-pointer" onClick={this.props.onUploadRetryAll}>{gettext('Retry All')}</span>
|
||||
:
|
||||
<span className="cursor-pointer disabled-link">{gettext('Retry All')}</span>
|
||||
}
|
||||
{!allFilesUploaded ?
|
||||
<span className="cursor-pointer ml-3" onClick={this.onCancelAllUploading}>{gettext('Cancel All')}</span>
|
||||
:
|
||||
<span className="cursor-pointer ml-3 disabled-link" >{gettext('Cancel All')}</span>
|
||||
}
|
||||
<div className="d-flex justify-content-between align-items-center border-bottom">
|
||||
{uploadFileList.length > 0 && <span>{filesUploadedMsg}</span>}
|
||||
<div className="ml-auto">
|
||||
<button
|
||||
className="btn btn-lg border-0 background-transparent px-0"
|
||||
onClick={this.props.onUploadRetryAll}
|
||||
disabled={retryFileList.length == 0}
|
||||
>
|
||||
{gettext('Retry All')}
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-lg border-0 background-transparent px-0 ml-3"
|
||||
onClick={this.props.onCancelAllUploading}
|
||||
disabled={!isUploading}
|
||||
>
|
||||
{gettext('Cancel All')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<table className="table-thead-hidden">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="30%">{gettext('name')}</th>
|
||||
<th width="20%">{gettext('size')}</th>
|
||||
<th width="40%">{gettext('name')}</th>
|
||||
<th width="15%">{gettext('size')}</th>
|
||||
<th width="30%">{gettext('progress')}</th>
|
||||
<th width="20%">{gettext('state')}</th>
|
||||
<th width="15%">{gettext('state')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@@ -84,10 +84,6 @@
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.disabled-link {
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
#upload-link-total-progress-container {
|
||||
margin: 20px -32px 0;
|
||||
border: 1px solid #eee;
|
||||
|
Reference in New Issue
Block a user