Move upload verification logic to RoomView.
Improve upload dialog ux
This commit is contained in:
parent
736b76bbb0
commit
541f1d71fb
2 changed files with 47 additions and 33 deletions
|
@ -26,6 +26,7 @@ const React = require("react");
|
||||||
const ReactDOM = require("react-dom");
|
const ReactDOM = require("react-dom");
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
|
import filesize from 'filesize';
|
||||||
const classNames = require("classnames");
|
const classNames = require("classnames");
|
||||||
import { _t } from '../../languageHandler';
|
import { _t } from '../../languageHandler';
|
||||||
|
|
||||||
|
@ -49,8 +50,6 @@ import SettingsStore, {SettingLevel} from "../../settings/SettingsStore";
|
||||||
const DEBUG = false;
|
const DEBUG = false;
|
||||||
let debuglog = function() {};
|
let debuglog = function() {};
|
||||||
|
|
||||||
let mediaLimitCache = null;
|
|
||||||
|
|
||||||
const BROWSER_SUPPORTS_SANDBOX = 'sandbox' in document.createElement('iframe');
|
const BROWSER_SUPPORTS_SANDBOX = 'sandbox' in document.createElement('iframe');
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
@ -96,9 +95,9 @@ module.exports = React.createClass({
|
||||||
roomLoading: true,
|
roomLoading: true,
|
||||||
peekLoading: false,
|
peekLoading: false,
|
||||||
shouldPeek: true,
|
shouldPeek: true,
|
||||||
|
|
||||||
// Media limits for uploading, this may change.
|
// Media limits for uploading.
|
||||||
mediaLimits: {},
|
mediaConfig: undefined,
|
||||||
|
|
||||||
// The event to be scrolled to initially
|
// The event to be scrolled to initially
|
||||||
initialEventId: null,
|
initialEventId: null,
|
||||||
|
@ -152,24 +151,31 @@ module.exports = React.createClass({
|
||||||
MatrixClientPeg.get().on("RoomState.members", this.onRoomStateMember);
|
MatrixClientPeg.get().on("RoomState.members", this.onRoomStateMember);
|
||||||
MatrixClientPeg.get().on("RoomMember.membership", this.onRoomMemberMembership);
|
MatrixClientPeg.get().on("RoomMember.membership", this.onRoomMemberMembership);
|
||||||
MatrixClientPeg.get().on("accountData", this.onAccountData);
|
MatrixClientPeg.get().on("accountData", this.onAccountData);
|
||||||
this._fetchMediaLimits();
|
this._fetchMediaConfig();
|
||||||
// Start listening for RoomViewStore updates
|
// Start listening for RoomViewStore updates
|
||||||
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
|
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
|
||||||
this._onRoomViewStoreUpdate(true);
|
this._onRoomViewStoreUpdate(true);
|
||||||
},
|
},
|
||||||
|
|
||||||
_fetchMediaLimits: function(invalidateCache: boolean = false) {
|
_fetchMediaConfig: function(invalidateCache: boolean = false) {
|
||||||
let limits;
|
/// NOTE: Using global here so we don't make repeated requests for the
|
||||||
if(invalidateCache || mediaLimitCache == null) {
|
/// config every time we swap room.
|
||||||
MatrixClientPeg.get().getMediaLimits().then((_limits) => {
|
if(global.mediaConfig !== undefined && !invalidateCache) {
|
||||||
limits = _limits;
|
this.setState({mediaConfig: global.mediaConfig});
|
||||||
}).catch(() => {
|
return;
|
||||||
// Media repo can't or won't report limits, so provide an empty object (no limits).
|
|
||||||
limits = {};
|
|
||||||
});
|
|
||||||
mediaLimitCache = limits;
|
|
||||||
}
|
}
|
||||||
this.state.mediaLimits = limits;
|
console.log("[Media Config] Fetching");
|
||||||
|
MatrixClientPeg.get().getMediaConfig().then((config) => {
|
||||||
|
console.log("[Media Config] Fetched config:", config);
|
||||||
|
return config;
|
||||||
|
}).catch(() => {
|
||||||
|
// Media repo can't or won't report limits, so provide an empty object (no limits).
|
||||||
|
console.log("[Media Config] Could not fetch config, so not limiting uploads.");
|
||||||
|
return {};
|
||||||
|
}).then((config) => {
|
||||||
|
global.mediaConfig = config;
|
||||||
|
this.setState({mediaConfig: config});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_onRoomViewStoreUpdate: function(initial) {
|
_onRoomViewStoreUpdate: function(initial) {
|
||||||
|
@ -501,8 +507,8 @@ module.exports = React.createClass({
|
||||||
case 'notifier_enabled':
|
case 'notifier_enabled':
|
||||||
case 'upload_failed':
|
case 'upload_failed':
|
||||||
// 413: File was too big or upset the server in some way.
|
// 413: File was too big or upset the server in some way.
|
||||||
if(payload.data.error.http_status === 413) {
|
if(payload.error.http_status === 413) {
|
||||||
this._fetchMediaLimits(true);
|
this._fetchMediaConfig(true);
|
||||||
}
|
}
|
||||||
case 'upload_started':
|
case 'upload_started':
|
||||||
case 'upload_finished':
|
case 'upload_finished':
|
||||||
|
@ -935,6 +941,15 @@ module.exports = React.createClass({
|
||||||
this.setState({ draggingFile: false });
|
this.setState({ draggingFile: false });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isFileUploadAllowed(file) {
|
||||||
|
if (this.state.mediaConfig !== undefined &&
|
||||||
|
this.state.mediaConfig["m.upload.size"] !== undefined &&
|
||||||
|
file.size > this.state.mediaConfig["m.upload.size"]) {
|
||||||
|
return _t("File is too big. Maximum file size is %(fileSize)s", {fileSize: filesize(this.state.mediaConfig["m.upload.size"])});
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
uploadFile: async function(file) {
|
uploadFile: async function(file) {
|
||||||
dis.dispatch({action: 'focus_composer'});
|
dis.dispatch({action: 'focus_composer'});
|
||||||
|
|
||||||
|
@ -1677,7 +1692,7 @@ module.exports = React.createClass({
|
||||||
callState={this.state.callState}
|
callState={this.state.callState}
|
||||||
disabled={this.props.disabled}
|
disabled={this.props.disabled}
|
||||||
showApps={this.state.showApps}
|
showApps={this.state.showApps}
|
||||||
mediaLimits={this.state.mediaLimits}
|
uploadAllowed={this.isFileUploadAllowed}
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import filesize from 'filesize';
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import CallHandler from '../../../CallHandler';
|
import CallHandler from '../../../CallHandler';
|
||||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||||
|
@ -102,15 +101,6 @@ export default class MessageComposer extends React.Component {
|
||||||
this.uploadFiles(tfiles);
|
this.uploadFiles(tfiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
isFileUploadAllowed(file) {
|
|
||||||
if (this.props.mediaLimits !== undefined &&
|
|
||||||
this.props.mediaLimits.upload_size !== undefined &&
|
|
||||||
file.size > this.props.mediaLimits.upload_size) {
|
|
||||||
return _t("File is too big. Maximum file size is %(fileSize)s", {fileSize: filesize(this.mediaLimits.upload_size)});
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadFiles(files) {
|
uploadFiles(files) {
|
||||||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
||||||
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
||||||
|
@ -120,7 +110,7 @@ export default class MessageComposer extends React.Component {
|
||||||
const failedFiles = [];
|
const failedFiles = [];
|
||||||
|
|
||||||
for (let i=0; i<files.length; i++) {
|
for (let i=0; i<files.length; i++) {
|
||||||
const fileAcceptedOrError = this.isFileUploadAllowed(files[i]);
|
const fileAcceptedOrError = this.props.uploadAllowed(files[i]);
|
||||||
if (fileAcceptedOrError === true) {
|
if (fileAcceptedOrError === true) {
|
||||||
acceptedFiles.push(<li key={i}>
|
acceptedFiles.push(<li key={i}>
|
||||||
<TintableSvg key={i} src="img/files.svg" width="16" height="16" /> { files[i].name || _t('Attachment') }
|
<TintableSvg key={i} src="img/files.svg" width="16" height="16" /> { files[i].name || _t('Attachment') }
|
||||||
|
@ -128,7 +118,7 @@ export default class MessageComposer extends React.Component {
|
||||||
fileList.push(files[i]);
|
fileList.push(files[i]);
|
||||||
} else {
|
} else {
|
||||||
failedFiles.push(<li key={i}>
|
failedFiles.push(<li key={i}>
|
||||||
<TintableSvg key={i} src="img/files.svg" width="16" height="16" /> { files[i].name || _t('Attachment') } <b>{ _t('Reason') + ": " + fileAcceptedOrError}</b>
|
<TintableSvg key={i} src="img/files.svg" width="16" height="16" /> { files[i].name || _t('Attachment') } <p>{ _t('Reason') + ": " + fileAcceptedOrError}</p>
|
||||||
</li>);
|
</li>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,6 +148,12 @@ export default class MessageComposer extends React.Component {
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
let buttonText;
|
||||||
|
if (acceptedFiles.length > 0 && failedFiles.length > 0) {
|
||||||
|
buttonText = "Upload selected"
|
||||||
|
} else if (failedFiles.length > 0) {
|
||||||
|
buttonText = "Close"
|
||||||
|
}
|
||||||
|
|
||||||
Modal.createTrackedDialog('Upload Files confirmation', '', QuestionDialog, {
|
Modal.createTrackedDialog('Upload Files confirmation', '', QuestionDialog, {
|
||||||
title: _t('Upload Files'),
|
title: _t('Upload Files'),
|
||||||
|
@ -168,6 +164,8 @@ export default class MessageComposer extends React.Component {
|
||||||
{ replyToWarning }
|
{ replyToWarning }
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
|
hasCancelButton: acceptedFiles.length > 0,
|
||||||
|
button: buttonText,
|
||||||
onFinished: (shouldUpload) => {
|
onFinished: (shouldUpload) => {
|
||||||
if (shouldUpload) {
|
if (shouldUpload) {
|
||||||
// MessageComposer shouldn't have to rely on its parent passing in a callback to upload a file
|
// MessageComposer shouldn't have to rely on its parent passing in a callback to upload a file
|
||||||
|
@ -425,7 +423,8 @@ MessageComposer.propTypes = {
|
||||||
// callback when a file to upload is chosen
|
// callback when a file to upload is chosen
|
||||||
uploadFile: PropTypes.func.isRequired,
|
uploadFile: PropTypes.func.isRequired,
|
||||||
|
|
||||||
mediaLimits: PropTypes.object,
|
// function to test whether a file should be allowed to be uploaded.
|
||||||
|
uploadAllowed: PropTypes.func.isRequired,
|
||||||
|
|
||||||
// string representing the current room app drawer state
|
// string representing the current room app drawer state
|
||||||
showApps: PropTypes.bool
|
showApps: PropTypes.bool
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue