mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-21 11:27:18 +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:
@@ -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;
|
||||||
|
}
|
||||||
|
@@ -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;
|
||||||
|
@@ -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 = [];
|
||||||
|
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -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>
|
||||||
|
@@ -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">
|
<div className="progress-container d-flex align-items-center">
|
||||||
<div className="progress-bar" role="progressbar" style={{width: `${progress}%`}} aria-valuenow={progress} aria-valuemin="0" aria-valuemax="100"></div>
|
<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>
|
||||||
</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>
|
||||||
|
@@ -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>
|
||||||
|
Reference in New Issue
Block a user