1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-21 19:37:28 +00:00

Upload link page redesign (#6000)

* ['upload link' page] redesigned it(added the 'total status' bar, 'uploaded' icon & etc)

* ['upload link' page] redesigned it(separated the statuses from the operations for file items, and etc.)
This commit is contained in:
llj
2024-03-29 21:21:58 +08:00
committed by GitHub
parent 569f7a2d4a
commit 2326fcdb43
7 changed files with 125 additions and 34 deletions

View File

@@ -73,11 +73,45 @@
color: #666666; color: #666666;
} }
.upload-operation .saving {
color: #ee8204;
word-wrap: break-word;
}
.disabled-link { .disabled-link {
color: #999999; color: #999999;
} }
#upload-link-total-progress-container {
margin: 20px -32px 0;
border: 1px solid #eee;
border-width: 1px 0;
font-size: 14px;
height: 36px;
}
.file-upload-item .upload-success-icon {
width: 16px;
height: 16px;
padding: 4px;
color: #fff;
background: #47b881;
border-radius: 100%;
font-size: 8px;
line-height: 1.1;
font-weight: bolder;
}
.file-upload-item .upload-success-msg {
color: #47b881;
}
.file-upload-item .upload-failure-icon {
width: 16px;
height: 16px;
padding: 4px;
color: #fff;
background: #ec4c47;
border-radius: 100%;
font-size: 8px;
text-align: center;
}
.file-upload-item .upload-failure-msg {
color: #ec4c47;
}

View File

@@ -25,9 +25,6 @@ body {
color: #f25041; color: #f25041;
font-size: 48px; font-size: 48px;
} }
#upload-link-panel .tip-list-item {
list-style: decimal inside none;
}
#upload-link-drop-zone { #upload-link-drop-zone {
background: rgba(255, 152, 0, 0.1); background: rgba(255, 152, 0, 0.1);
border: 2px dashed #ff9800; border: 2px dashed #ff9800;

View File

@@ -302,8 +302,10 @@ class FileUploader extends React.Component {
// start uploading // start uploading
onUploadStart = () => { onUploadStart = () => {
/*
const message = gettext('File upload started'); const message = gettext('File upload started');
toaster.notify(message); toaster.notify(message);
*/
}; };
onProgress = () => { onProgress = () => {
@@ -421,10 +423,12 @@ class FileUploader extends React.Component {
}; };
onComplete = () => { onComplete = () => {
/*
if (!this.error) { if (!this.error) {
const message = gettext('All files uploaded'); const message = gettext('All files uploaded');
toaster.success(message); toaster.success(message);
} }
*/
this.error = false; // reset it this.error = false; // reset it
this.notifiedFolders = []; this.notifiedFolders = [];

View File

@@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Utils } from '../../utils/utils'; import { Utils } from '../../utils/utils';
import { gettext, maxUploadFileSize } from '../../utils/constants'; import { gettext } from '../../utils/constants';
const propTypes = { const propTypes = {
file: PropTypes.object, file: PropTypes.object,
@@ -10,15 +10,20 @@ const propTypes = {
class ForbidUploadListItem extends React.Component { class ForbidUploadListItem extends React.Component {
render() { render() {
let { file } = this.props; const { file } = this.props;
let msg = gettext('Please upload files less than {placeholder}').replace('{placeholder}', Utils.bytesToSize(maxUploadFileSize * 1000 * 1000));
return ( return (
<tr className="file-upload-item"> <tr className="file-upload-item">
<td className="upload-name"> <td className="upload-name">
<div className="ellipsis">{file.name}</div> <div className="ellipsis">{file.name}</div>
</td> </td>
<td>{Utils.bytesToSize(file.size)}</td>
<td colSpan={3} className="error">{msg}</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> </tr>
); );
} }

View File

@@ -47,10 +47,7 @@ class SharedUploadLink extends React.Component {
</div> </div>
) : ( ) : (
<Fragment> <Fragment>
<ol className="small text-gray"> {maxUploadFileSize && <p className="small text-gray m-0">{gettext('File size should be smaller than {max_size_placeholder}.').replace('{max_size_placeholder}', Utils.bytesToSize(maxUploadFileSize * 1000 * 1000))}</p>}
<li className="tip-list-item">{gettext('Folder upload is limited to Chrome, Firefox 50+, and Microsoft Edge.')}</li>
{maxUploadFileSize && <li className="tip-list-item">{gettext('File size should be smaller than {max_size_placeholder}.').replace('{max_size_placeholder}', Utils.bytesToSize(maxUploadFileSize * 1000 * 1000))}</li>}
</ol>
<div id="upload-link-drop-zone" className="text-center mt-2 mb-4"> <div id="upload-link-drop-zone" className="text-center mt-2 mb-4">
<span className="sf3-font sf3-font-upload upload-icon"></span> <span className="sf3-font sf3-font-upload upload-icon"></span>
<p className="small text-gray mb-0">{gettext('Drag and drop files or folders here.')}</p> <p className="small text-gray mb-0">{gettext('Drag and drop files or folders here.')}</p>

View File

@@ -105,17 +105,37 @@ class UploadListItem extends React.Component {
)} )}
</Fragment> </Fragment>
} }
{(resumableFile.size < (100 * 1000 * 1000)) && {(resumableFile.size < (100 * 1000 * 1000)) && (
<>
<div className="progress-container d-flex align-items-center"> <div className="progress-container d-flex align-items-center">
<div className="progress"> <div className="progress">
<div className="progress-bar" role="progressbar" style={{width: `${progress}%`}} aria-valuenow={progress} aria-valuemin="0" aria-valuemax="100"></div> <div className="progress-bar" role="progressbar" style={{width: `${progress}%`}} aria-valuenow={progress} aria-valuemin="0" aria-valuemax="100"></div>
</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> </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 && ( {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>
<td className="upload-operation"> <td className="upload-operation">
@@ -126,12 +146,6 @@ class UploadListItem extends React.Component {
{this.state.uploadState === UPLOAD_ERROR && ( {this.state.uploadState === UPLOAD_ERROR && (
<a href="#" onClick={this.onUploadRetry} role="button">{gettext('Retry')}</a> <a href="#" onClick={this.onUploadRetry} role="button">{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>
)}
</Fragment> </Fragment>
</td> </td>
</tr> </tr>

View File

@@ -1,11 +1,14 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Button, ButtonDropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap'; import { Button, ButtonDropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
import { Utils } from '../../utils/utils';
import { gettext } from '../../utils/constants'; import { gettext } from '../../utils/constants';
import UploadListItem from './upload-list-item'; import UploadListItem from './upload-list-item';
import ForbidUploadListItem from './forbid-upload-list-item'; import ForbidUploadListItem from './forbid-upload-list-item';
const propTypes = { const propTypes = {
totalProgress: PropTypes.number.isRequired,
uploadBitrate: PropTypes.number.isRequired,
uploadFileList: PropTypes.array.isRequired, uploadFileList: PropTypes.array.isRequired,
forbidUploadFileList: PropTypes.array.isRequired, forbidUploadFileList: PropTypes.array.isRequired,
onCancelAllUploading: PropTypes.func.isRequired, onCancelAllUploading: PropTypes.func.isRequired,
@@ -44,7 +47,18 @@ class UploadProgressDialog extends React.Component {
}; };
render() { render() {
let { allFilesUploaded } = this.props; const { totalProgress, allFilesUploaded, uploadBitrate, uploadFileList, forbidUploadFileList } = this.props;
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 filesFailedMsg;
if (totalProgress == 100) {
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 ( return (
<Fragment> <Fragment>
<div className="text-center"> <div className="text-center">
@@ -61,13 +75,39 @@ class UploadProgressDialog extends React.Component {
{gettext('Cancel All')} {gettext('Cancel All')}
</Button> </Button>
</div> </div>
<div className="mt-4 mh-2"> {totalProgress > 0 && (
<div id="upload-link-total-progress-container" className="d-flex align-items-center px-6">
{totalProgress < 100 && (
<>
<span>{gettext('File Uploading...')}</span>
<div className="upload-progress flex-fill mx-2">
<div className="progress-container d-flex align-items-center">
<div className="progress w-100">
<div className="progress-bar" role="progressbar" style={{width: `${totalProgress}%`}} aria-valuenow={totalProgress} aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
</div>
<span>{`${totalProgress}% (${Utils.formatBitRate(uploadBitrate)})`}</span>
</>
)}
{totalProgress == 100 && (
<>
{filesFailedMsg ?
<p className="m-0 mr-auto error">{filesFailedMsg}</p> :
<p className="m-0 mr-auto">{gettext('All files uploaded')}</p>
}
</>
)}
{uploadFileList.length > 0 && <span className="ml-4">{filesUploadedMsg}</span>}
</div>
)}
<div className="mh-2">
<table className="table-thead-hidden"> <table className="table-thead-hidden">
<thead> <thead>
<tr> <tr>
<th width="35%">{gettext('name')}</th> <th width="40%">{gettext('name')}</th>
<th width="15%">{gettext('size')}</th> <th width="15%">{gettext('size')}</th>
<th width="35%">{gettext('progress')}</th> <th width="30%">{gettext('progress')}</th>
<th width="15%">{gettext('state')}</th> <th width="15%">{gettext('state')}</th>
</tr> </tr>
</thead> </thead>