mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-16 21:24:59 +08:00
Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
commit
35ef2cde61
@ -377,9 +377,9 @@ class ContentMessages {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (error) {
|
if (error) {
|
||||||
dis.dispatch({action: 'upload_failed', upload: upload});
|
dis.dispatch({action: 'upload_failed', upload, error});
|
||||||
} else {
|
} else {
|
||||||
dis.dispatch({action: 'upload_finished', upload: upload});
|
dis.dispatch({action: 'upload_finished', upload});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,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';
|
||||||
|
|
||||||
@ -101,6 +102,10 @@ module.exports = React.createClass({
|
|||||||
roomLoading: true,
|
roomLoading: true,
|
||||||
peekLoading: false,
|
peekLoading: false,
|
||||||
shouldPeek: true,
|
shouldPeek: true,
|
||||||
|
|
||||||
|
// Media limits for uploading.
|
||||||
|
mediaConfig: undefined,
|
||||||
|
|
||||||
// used to trigger a rerender in TimelinePanel once the members are loaded,
|
// used to trigger a rerender in TimelinePanel once the members are loaded,
|
||||||
// so RR are rendered again (now with the members available), ...
|
// so RR are rendered again (now with the members available), ...
|
||||||
membersLoaded: !llMembers,
|
membersLoaded: !llMembers,
|
||||||
@ -156,7 +161,7 @@ module.exports = React.createClass({
|
|||||||
MatrixClientPeg.get().on("RoomState.members", this.onRoomStateMember);
|
MatrixClientPeg.get().on("RoomState.members", this.onRoomStateMember);
|
||||||
MatrixClientPeg.get().on("Room.myMembership", this.onMyMembership);
|
MatrixClientPeg.get().on("Room.myMembership", this.onMyMembership);
|
||||||
MatrixClientPeg.get().on("accountData", this.onAccountData);
|
MatrixClientPeg.get().on("accountData", this.onAccountData);
|
||||||
|
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);
|
||||||
@ -164,6 +169,27 @@ module.exports = React.createClass({
|
|||||||
WidgetEchoStore.on('update', this._onWidgetEchoStoreUpdate);
|
WidgetEchoStore.on('update', this._onWidgetEchoStoreUpdate);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_fetchMediaConfig: function(invalidateCache: boolean = false) {
|
||||||
|
/// NOTE: Using global here so we don't make repeated requests for the
|
||||||
|
/// config every time we swap room.
|
||||||
|
if(global.mediaConfig !== undefined && !invalidateCache) {
|
||||||
|
this.setState({mediaConfig: global.mediaConfig});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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) {
|
||||||
if (this.unmounted) {
|
if (this.unmounted) {
|
||||||
return;
|
return;
|
||||||
@ -499,6 +525,10 @@ module.exports = React.createClass({
|
|||||||
break;
|
break;
|
||||||
case 'notifier_enabled':
|
case 'notifier_enabled':
|
||||||
case 'upload_failed':
|
case 'upload_failed':
|
||||||
|
// 413: File was too big or upset the server in some way.
|
||||||
|
if(payload.error.http_status === 413) {
|
||||||
|
this._fetchMediaConfig(true);
|
||||||
|
}
|
||||||
case 'upload_started':
|
case 'upload_started':
|
||||||
case 'upload_finished':
|
case 'upload_finished':
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
@ -931,6 +961,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'});
|
||||||
|
|
||||||
@ -1687,6 +1726,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}
|
||||||
|
uploadAllowed={this.isFileUploadAllowed}
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +139,8 @@ export default class MessageComposer extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onUploadFileSelected(files) {
|
onUploadFileSelected(files) {
|
||||||
this.uploadFiles(files.target.files);
|
const tfiles = files.target.files;
|
||||||
|
this.uploadFiles(tfiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadFiles(files) {
|
uploadFiles(files) {
|
||||||
@ -147,10 +148,21 @@ export default class MessageComposer extends React.Component {
|
|||||||
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
||||||
|
|
||||||
const fileList = [];
|
const fileList = [];
|
||||||
|
const acceptedFiles = [];
|
||||||
|
const failedFiles = [];
|
||||||
|
|
||||||
for (let i=0; i<files.length; i++) {
|
for (let i=0; i<files.length; i++) {
|
||||||
fileList.push(<li key={i}>
|
const fileAcceptedOrError = this.props.uploadAllowed(files[i]);
|
||||||
<TintableSvg key={i} src="img/files.svg" width="16" height="16" /> { files[i].name || _t('Attachment') }
|
if (fileAcceptedOrError === true) {
|
||||||
</li>);
|
acceptedFiles.push(<li key={i}>
|
||||||
|
<TintableSvg key={i} src="img/files.svg" width="16" height="16" /> { files[i].name || _t('Attachment') }
|
||||||
|
</li>);
|
||||||
|
fileList.push(files[i]);
|
||||||
|
} else {
|
||||||
|
failedFiles.push(<li key={i}>
|
||||||
|
<TintableSvg key={i} src="img/files.svg" width="16" height="16" /> { files[i].name || _t('Attachment') } <p>{ _t('Reason') + ": " + fileAcceptedOrError}</p>
|
||||||
|
</li>);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isQuoting = Boolean(RoomViewStore.getQuotingEvent());
|
const isQuoting = Boolean(RoomViewStore.getQuotingEvent());
|
||||||
@ -161,23 +173,47 @@ export default class MessageComposer extends React.Component {
|
|||||||
}</p>;
|
}</p>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const acceptedFilesPart = acceptedFiles.length === 0 ? null : (
|
||||||
|
<div>
|
||||||
|
<p>{ _t('Are you sure you want to upload the following files?') }</p>
|
||||||
|
<ul style={{listStyle: 'none', textAlign: 'left'}}>
|
||||||
|
{ acceptedFiles }
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const failedFilesPart = failedFiles.length === 0 ? null : (
|
||||||
|
<div>
|
||||||
|
<p>{ _t('The following files cannot be uploaded:') }</p>
|
||||||
|
<ul style={{listStyle: 'none', textAlign: 'left'}}>
|
||||||
|
{ failedFiles }
|
||||||
|
</ul>
|
||||||
|
</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'),
|
||||||
description: (
|
description: (
|
||||||
<div>
|
<div>
|
||||||
<p>{ _t('Are you sure you want to upload the following files?') }</p>
|
{ acceptedFilesPart }
|
||||||
<ul style={{listStyle: 'none', textAlign: 'left'}}>
|
{ failedFilesPart }
|
||||||
{ fileList }
|
|
||||||
</ul>
|
|
||||||
{ 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
|
||||||
if (files) {
|
if (fileList) {
|
||||||
for (let i=0; i<files.length; i++) {
|
for (let i=0; i<fileList.length; i++) {
|
||||||
this.props.uploadFile(files[i]);
|
this.props.uploadFile(fileList[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -459,6 +495,9 @@ 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,
|
||||||
|
|
||||||
|
// 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
|
||||||
};
|
};
|
||||||
|
@ -1351,5 +1351,12 @@
|
|||||||
"Import": "Import",
|
"Import": "Import",
|
||||||
"Failed to set direct chat tag": "Failed to set direct chat tag",
|
"Failed to set direct chat tag": "Failed to set direct chat tag",
|
||||||
"Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room",
|
"Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room",
|
||||||
"Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room"
|
"Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room",
|
||||||
|
"File is too big. Maximum file size is %(fileSize)s": "File is too big. Maximum file size is %(fileSize)s",
|
||||||
|
"Reason": "Reason",
|
||||||
|
"The following files cannot be uploaded:": "The following files cannot be uploaded:",
|
||||||
|
"You've previously used Riot on %(host)s with lazy loading of members enabled. In this version lazy loading is disabled. As the local cache is not compatible between these two settings, Riot needs to resync your account.": "You've previously used Riot on %(host)s with lazy loading of members enabled. In this version lazy loading is disabled. As the local cache is not compatible between these two settings, Riot needs to resync your account.",
|
||||||
|
"If the other version of Riot is still open in another tab, please close it as using Riot on the same host with both lazy loading enabled and disabled simultaneously will cause issues.": "If the other version of Riot is still open in another tab, please close it as using Riot on the same host with both lazy loading enabled and disabled simultaneously will cause issues.",
|
||||||
|
"Incompatible local cache": "Incompatible local cache",
|
||||||
|
"Clear cache and resync": "Clear cache and resync"
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user