Fix upload progress not communicating processing phase in web UI (#19530)

rebase/4.0.0rc1
Eugen Rochko 2022-10-29 20:05:53 +02:00 committed by GitHub
parent a449ee8654
commit 30ef110224
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 34 additions and 13 deletions

View File

@ -25,10 +25,12 @@ export const COMPOSE_REPLY_CANCEL = 'COMPOSE_REPLY_CANCEL';
export const COMPOSE_DIRECT = 'COMPOSE_DIRECT'; export const COMPOSE_DIRECT = 'COMPOSE_DIRECT';
export const COMPOSE_MENTION = 'COMPOSE_MENTION'; export const COMPOSE_MENTION = 'COMPOSE_MENTION';
export const COMPOSE_RESET = 'COMPOSE_RESET'; export const COMPOSE_RESET = 'COMPOSE_RESET';
export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST'; export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST';
export const COMPOSE_UPLOAD_SUCCESS = 'COMPOSE_UPLOAD_SUCCESS'; export const COMPOSE_UPLOAD_SUCCESS = 'COMPOSE_UPLOAD_SUCCESS';
export const COMPOSE_UPLOAD_FAIL = 'COMPOSE_UPLOAD_FAIL'; export const COMPOSE_UPLOAD_FAIL = 'COMPOSE_UPLOAD_FAIL';
export const COMPOSE_UPLOAD_PROGRESS = 'COMPOSE_UPLOAD_PROGRESS'; export const COMPOSE_UPLOAD_PROGRESS = 'COMPOSE_UPLOAD_PROGRESS';
export const COMPOSE_UPLOAD_PROCESSING = 'COMPOSE_UPLOAD_PROCESSING';
export const COMPOSE_UPLOAD_UNDO = 'COMPOSE_UPLOAD_UNDO'; export const COMPOSE_UPLOAD_UNDO = 'COMPOSE_UPLOAD_UNDO';
export const THUMBNAIL_UPLOAD_REQUEST = 'THUMBNAIL_UPLOAD_REQUEST'; export const THUMBNAIL_UPLOAD_REQUEST = 'THUMBNAIL_UPLOAD_REQUEST';
@ -268,13 +270,16 @@ export function uploadCompose(files) {
if (status === 200) { if (status === 200) {
dispatch(uploadComposeSuccess(data, f)); dispatch(uploadComposeSuccess(data, f));
} else if (status === 202) { } else if (status === 202) {
dispatch(uploadComposeProcessing());
let tryCount = 1; let tryCount = 1;
const poll = () => { const poll = () => {
api(getState).get(`/api/v1/media/${data.id}`).then(response => { api(getState).get(`/api/v1/media/${data.id}`).then(response => {
if (response.status === 200) { if (response.status === 200) {
dispatch(uploadComposeSuccess(response.data, f)); dispatch(uploadComposeSuccess(response.data, f));
} else if (response.status === 206) { } else if (response.status === 206) {
let retryAfter = (Math.log2(tryCount) || 1) * 1000; const retryAfter = (Math.log2(tryCount) || 1) * 1000;
tryCount += 1; tryCount += 1;
setTimeout(() => poll(), retryAfter); setTimeout(() => poll(), retryAfter);
} }
@ -289,6 +294,10 @@ export function uploadCompose(files) {
}; };
}; };
export const uploadComposeProcessing = () => ({
type: COMPOSE_UPLOAD_PROCESSING,
});
export const uploadThumbnail = (id, file) => (dispatch, getState) => { export const uploadThumbnail = (id, file) => (dispatch, getState) => {
dispatch(uploadThumbnailRequest()); dispatch(uploadThumbnailRequest());

View File

@ -4,7 +4,6 @@ import UploadProgressContainer from '../containers/upload_progress_container';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
import UploadContainer from '../containers/upload_container'; import UploadContainer from '../containers/upload_container';
import SensitiveButtonContainer from '../containers/sensitive_button_container'; import SensitiveButtonContainer from '../containers/sensitive_button_container';
import { FormattedMessage } from 'react-intl';
export default class UploadForm extends ImmutablePureComponent { export default class UploadForm extends ImmutablePureComponent {
@ -17,7 +16,7 @@ export default class UploadForm extends ImmutablePureComponent {
return ( return (
<div className='compose-form__upload-wrapper'> <div className='compose-form__upload-wrapper'>
<UploadProgressContainer icon='upload' message={<FormattedMessage id='upload_progress.label' defaultMessage='Uploading…' />} /> <UploadProgressContainer />
<div className='compose-form__uploads-wrapper'> <div className='compose-form__uploads-wrapper'>
{mediaIds.map(id => ( {mediaIds.map(id => (

View File

@ -3,27 +3,35 @@ import PropTypes from 'prop-types';
import Motion from '../../ui/util/optional_motion'; import Motion from '../../ui/util/optional_motion';
import spring from 'react-motion/lib/spring'; import spring from 'react-motion/lib/spring';
import Icon from 'mastodon/components/icon'; import Icon from 'mastodon/components/icon';
import { FormattedMessage } from 'react-intl';
export default class UploadProgress extends React.PureComponent { export default class UploadProgress extends React.PureComponent {
static propTypes = { static propTypes = {
active: PropTypes.bool, active: PropTypes.bool,
progress: PropTypes.number, progress: PropTypes.number,
icon: PropTypes.string.isRequired, isProcessing: PropTypes.bool,
message: PropTypes.node.isRequired,
}; };
render () { render () {
const { active, progress, icon, message } = this.props; const { active, progress, isProcessing } = this.props;
if (!active) { if (!active) {
return null; return null;
} }
let message;
if (isProcessing) {
message = <FormattedMessage id='upload_progress.processing' defaultMessage='Processing…' />;
} else {
message = <FormattedMessage id='upload_progress.label' defaultMessage='Uploading…' />;
}
return ( return (
<div className='upload-progress'> <div className='upload-progress'>
<div className='upload-progress__icon'> <div className='upload-progress__icon'>
<Icon id={icon} /> <Icon id='upload' />
</div> </div>
<div className='upload-progress__message'> <div className='upload-progress__message'>

View File

@ -4,6 +4,7 @@ import UploadProgress from '../components/upload_progress';
const mapStateToProps = state => ({ const mapStateToProps = state => ({
active: state.getIn(['compose', 'is_uploading']), active: state.getIn(['compose', 'is_uploading']),
progress: state.getIn(['compose', 'progress']), progress: state.getIn(['compose', 'progress']),
isProcessing: state.getIn(['compose', 'is_processing']),
}); });
export default connect(mapStateToProps)(UploadProgress); export default connect(mapStateToProps)(UploadProgress);

View File

@ -14,6 +14,7 @@ import {
COMPOSE_UPLOAD_FAIL, COMPOSE_UPLOAD_FAIL,
COMPOSE_UPLOAD_UNDO, COMPOSE_UPLOAD_UNDO,
COMPOSE_UPLOAD_PROGRESS, COMPOSE_UPLOAD_PROGRESS,
COMPOSE_UPLOAD_PROCESSING,
THUMBNAIL_UPLOAD_REQUEST, THUMBNAIL_UPLOAD_REQUEST,
THUMBNAIL_UPLOAD_SUCCESS, THUMBNAIL_UPLOAD_SUCCESS,
THUMBNAIL_UPLOAD_FAIL, THUMBNAIL_UPLOAD_FAIL,
@ -136,6 +137,7 @@ function appendMedia(state, media, file) {
} }
map.update('media_attachments', list => list.push(media)); map.update('media_attachments', list => list.push(media));
map.set('is_uploading', false); map.set('is_uploading', false);
map.set('is_processing', false);
map.set('resetFileKey', Math.floor((Math.random() * 0x10000))); map.set('resetFileKey', Math.floor((Math.random() * 0x10000)));
map.set('idempotencyKey', uuid()); map.set('idempotencyKey', uuid());
map.update('pending_media_attachments', n => n - 1); map.update('pending_media_attachments', n => n - 1);
@ -354,10 +356,12 @@ export default function compose(state = initialState, action) {
return state.set('is_changing_upload', false); return state.set('is_changing_upload', false);
case COMPOSE_UPLOAD_REQUEST: case COMPOSE_UPLOAD_REQUEST:
return state.set('is_uploading', true).update('pending_media_attachments', n => n + 1); return state.set('is_uploading', true).update('pending_media_attachments', n => n + 1);
case COMPOSE_UPLOAD_PROCESSING:
return state.set('is_processing', true);
case COMPOSE_UPLOAD_SUCCESS: case COMPOSE_UPLOAD_SUCCESS:
return appendMedia(state, fromJS(action.media), action.file); return appendMedia(state, fromJS(action.media), action.file);
case COMPOSE_UPLOAD_FAIL: case COMPOSE_UPLOAD_FAIL:
return state.set('is_uploading', false).update('pending_media_attachments', n => n - 1); return state.set('is_uploading', false).set('is_processing', false).update('pending_media_attachments', n => n - 1);
case COMPOSE_UPLOAD_UNDO: case COMPOSE_UPLOAD_UNDO:
return removeMedia(state, action.media_id); return removeMedia(state, action.media_id);
case COMPOSE_UPLOAD_PROGRESS: case COMPOSE_UPLOAD_PROGRESS: