1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-02 15:38:15 +00:00

[dir view] redesigned the 'file upload' dialog (#6006)

* [dir view] redesigned the 'file upload' dialog

* [dir view] 'file upload' dialog: fixup & improvements
This commit is contained in:
llj
2024-04-03 22:14:31 +08:00
committed by GitHub
parent 8bf135ca96
commit 29081f204b
6 changed files with 121 additions and 82 deletions

View File

@@ -46,7 +46,6 @@ class FileUploader extends React.Component {
isUploadRemindDialogShow: false,
currentResumableFile: null,
uploadBitrate: 0,
allFilesUploaded: false,
};
this.uploadInput = React.createRef();
@@ -159,11 +158,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;
@@ -439,11 +433,9 @@ class FileUploader extends React.Component {
this.notifiedFolders = [];
// reset upload link loaded
this.isUploadLinkLoaded = false;
this.setState({allFilesUploaded: true});
};
onPause = () => {
};
onError = (message) => {
@@ -536,8 +528,7 @@ class FileUploader extends React.Component {
if (!this.resumable.isUploading()) {
this.setState({
totalProgress: '100',
allFilesUploaded: true,
totalProgress: 100,
});
this.loaded = 0;
}
@@ -557,8 +548,7 @@ class FileUploader extends React.Component {
this.loaded = 0;
this.setState({
allFilesUploaded: true,
totalProgress: '100',
totalProgress: 100,
uploadFileList: uploadFileList
});
// reset upload link loaded
@@ -709,12 +699,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)) &&
<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>
{(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>
</div>
}
{this.state.uploadState === UPLOAD_UPLOADING && (
<>
{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 && (
<p className="progress-text mb-0">{gettext('Saving...')}</p>
)}
</>
)}
</Fragment>
}
{this.state.uploadState === UPLOAD_UPLOADED && (
<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="message err-message ml-0" dangerouslySetInnerHTML={{__html: error}}></div>
<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 ellipsis">
<td className="upload-operation">
<Fragment>
{this.state.uploadState === UPLOAD_UPLOADING && (
<a href="#" onClick={this.onUploadCancel}>{gettext('Cancel')}</a>
<a href="#" onClick={this.onUploadCancel} role="button">{gettext('Cancel')}</a>
)}
{this.state.uploadState === UPLOAD_ERROR && (
<a href="#" onClick={this.onUploadRetry}>{gettext('Retry')}</a>
)}
{this.state.uploadState === UPLOAD_ISSAVING && (
<span className="saving">{gettext('Saving...')}</span>
)}
{this.state.uploadState === UPLOAD_UPLOADED && (
<span className="uploaded">{gettext('Uploaded')}</span>
<a href="#" onClick={this.onUploadRetry} role="button">{gettext('Retry')}</a>
)}
</Fragment>
</td>

View File

@@ -16,7 +16,6 @@ const propTypes = {
onUploadCancel: PropTypes.func.isRequired,
onUploadRetry: PropTypes.func.isRequired,
onUploadRetryAll: PropTypes.func.isRequired,
allFilesUploaded: PropTypes.bool.isRequired,
};
class UploadProgressDialog extends React.Component {
@@ -43,52 +42,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>
</>
) : (
<>
{filesFailedMsg ?
<p className="m-0 error">{filesFailedMsg}</p> :
<p className="m-0">{gettext('All files uploaded')}</p>
}
</>
)}
</div>
<div className="uploader-options">
{totalProgress === 100 || allFilesUploaded ? uploadedOptions : uploadingOptions}
<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

@@ -25,25 +25,36 @@
.uploader-list-header {
background-color: #f0f0f0;
padding: 0.375rem 0.625rem;
padding: 0.625rem;
font-size: 1rem;
line-height: 1.5;
color: #322;
display: flex;
justify-content: space-between;
min-height: 2.25rem;
border-bottom: 1px solid #ddd;
}
.uploader-list-header .uploader-options span{
.uploader-list-header .progress {
height: 5px;
margin-top: 8px;
width: 475px;
}
.uploader-list-header .upload-dialog-op-container {
line-height: 1;
}
.uploader-list-header .upload-dialog-op {
display: inline-block;
margin-left: 0.25rem;
margin: 3px 0 0 4px;
font-size: 18px;
line-height: 1;
color: #b8b8b8;
cursor: pointer;
}
.uploader-list-content {
padding: 0rem 1rem 1.25rem;
padding: 0 1rem 1.25rem;
background-color: #fff;
overflow: auto;
}

View File

@@ -93,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() && (