1
0
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:
llj
2024-04-07 22:16:08 +08:00
committed by GitHub
parent 4d33c2aca3
commit 48c0d96df8
6 changed files with 106 additions and 79 deletions

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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>
);
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -84,10 +84,6 @@
color: #666666;
}
.disabled-link {
color: #999999;
}
#upload-link-total-progress-container {
margin: 20px -32px 0;
border: 1px solid #eee;