Revert "Merge pull request #2395 from matrix-org/dbkr/merge_develop_experimental"

This reverts commit ad47144355.
This commit is contained in:
David Baker 2019-01-03 18:55:56 +00:00 committed by Travis Ralston
parent d111fe27bb
commit f928be6f59
77 changed files with 598 additions and 3532 deletions

View file

@ -473,7 +473,7 @@ export default React.createClass({
GroupStore.registerListener(groupId, this.onGroupStoreUpdated.bind(this, firstInit));
let willDoOnboarding = false;
// XXX: This should be more fluxy - let's get the error from GroupStore .getError or something
GroupStore.on('error', (err, errorGroupId, stateKey) => {
GroupStore.on('error', (err, errorGroupId) => {
if (this._unmounted || groupId !== errorGroupId) return;
if (err.errcode === 'M_GUEST_ACCESS_FORBIDDEN' && !willDoOnboarding) {
dis.dispatch({
@ -486,13 +486,11 @@ export default React.createClass({
dis.dispatch({action: 'require_registration'});
willDoOnboarding = true;
}
if (stateKey === GroupStore.STATE_KEY.Summary) {
this.setState({
summary: null,
error: err,
editing: false,
});
}
this.setState({
summary: null,
error: err,
editing: false,
});
});
},
@ -516,6 +514,7 @@ export default React.createClass({
isUserMember: GroupStore.getGroupMembers(this.props.groupId).some(
(m) => m.userId === this._matrixClient.credentials.userId,
),
error: null,
});
// XXX: This might not work but this.props.groupIsNew unused anyway
if (this.props.groupIsNew && firstInit) {
@ -1080,7 +1079,6 @@ export default React.createClass({
},
_getJoinableNode: function() {
const InlineSpinner = sdk.getComponent('elements.InlineSpinner');
return this.state.editing ? <div>
<h3>
{ _t('Who can join this community?') }
@ -1162,7 +1160,7 @@ export default React.createClass({
if (this.state.summaryLoading && this.state.error === null || this.state.saving) {
return <Spinner />;
} else if (this.state.summary && !this.state.error) {
} else if (this.state.summary) {
const summary = this.state.summary;
let avatarNode;

View file

@ -48,8 +48,6 @@ import SettingsStore, {SettingLevel} from "../../settings/SettingsStore";
import { startAnyRegistrationFlow } from "../../Registration.js";
import { messageForSyncError } from '../../utils/ErrorUtils';
const AutoDiscovery = Matrix.AutoDiscovery;
// Disable warnings for now: we use deprecated bluebird functions
// and need to migrate, but they spam the console with warnings.
Promise.config({warnings: false});
@ -183,12 +181,6 @@ export default React.createClass({
register_is_url: null,
register_id_sid: null,
// Parameters used for setting up the login/registration views
defaultServerName: this.props.config.default_server_name,
defaultHsUrl: this.props.config.default_hs_url,
defaultIsUrl: this.props.config.default_is_url,
defaultServerDiscoveryError: null,
// When showing Modal dialogs we need to set aria-hidden on the root app element
// and disable it when there are no dialogs
hideToSRUsers: false,
@ -207,24 +199,20 @@ export default React.createClass({
};
},
getDefaultServerName: function() {
return this.state.defaultServerName;
},
getCurrentHsUrl: function() {
if (this.state.register_hs_url) {
return this.state.register_hs_url;
} else if (MatrixClientPeg.get()) {
return MatrixClientPeg.get().getHomeserverUrl();
} else if (window.localStorage && window.localStorage.getItem("mx_hs_url")) {
return window.localStorage.getItem("mx_hs_url");
} else {
return this.getDefaultHsUrl();
}
},
getDefaultHsUrl(defaultToMatrixDotOrg) {
defaultToMatrixDotOrg = typeof(defaultToMatrixDotOrg) !== 'boolean' ? true : defaultToMatrixDotOrg;
if (!this.state.defaultHsUrl && defaultToMatrixDotOrg) return "https://matrix.org";
return this.state.defaultHsUrl;
getDefaultHsUrl() {
return this.props.config.default_hs_url || "https://matrix.org";
},
getFallbackHsUrl: function() {
@ -236,13 +224,15 @@ export default React.createClass({
return this.state.register_is_url;
} else if (MatrixClientPeg.get()) {
return MatrixClientPeg.get().getIdentityServerUrl();
} else if (window.localStorage && window.localStorage.getItem("mx_is_url")) {
return window.localStorage.getItem("mx_is_url");
} else {
return this.getDefaultIsUrl();
}
},
getDefaultIsUrl() {
return this.state.defaultIsUrl || "https://vector.im";
return this.props.config.default_is_url || "https://vector.im";
},
componentWillMount: function() {
@ -292,20 +282,6 @@ export default React.createClass({
console.info(`Team token set to ${this._teamToken}`);
}
// Set up the default URLs (async)
if (this.getDefaultServerName() && !this.getDefaultHsUrl(false)) {
this.setState({loadingDefaultHomeserver: true});
this._tryDiscoverDefaultHomeserver(this.getDefaultServerName());
} else if (this.getDefaultServerName() && this.getDefaultHsUrl(false)) {
// Ideally we would somehow only communicate this to the server admins, but
// given this is at login time we can't really do much besides hope that people
// will check their settings.
this.setState({
defaultServerName: null, // To un-hide any secrets people might be keeping
defaultServerDiscoveryError: _t("Invalid configuration: Cannot supply a default homeserver URL and a default server name"),
});
}
// Set a default HS with query param `hs_url`
const paramHs = this.props.startingFragmentQueryParams.hs_url;
if (paramHs) {
@ -1434,11 +1410,6 @@ export default React.createClass({
break;
}
});
cli.on("crypto.keyBackupFailed", () => {
Modal.createTrackedDialogAsync('New Recovery Method', 'New Recovery Method',
import('../../async-components/views/dialogs/keybackup/NewRecoveryMethodDialog'),
);
});
// Fire the tinter right on startup to ensure the default theme is applied
// A later sync can/will correct the tint to be the right value for the user
@ -1765,36 +1736,6 @@ export default React.createClass({
this.setState(newState);
},
_tryDiscoverDefaultHomeserver: async function(serverName) {
try {
const discovery = await AutoDiscovery.findClientConfig(serverName);
const state = discovery["m.homeserver"].state;
if (state !== AutoDiscovery.SUCCESS) {
console.error("Failed to discover homeserver on startup:", discovery);
this.setState({
defaultServerDiscoveryError: discovery["m.homeserver"].error,
loadingDefaultHomeserver: false,
});
} else {
const hsUrl = discovery["m.homeserver"].base_url;
const isUrl = discovery["m.identity_server"].state === AutoDiscovery.SUCCESS
? discovery["m.identity_server"].base_url
: "https://vector.im";
this.setState({
defaultHsUrl: hsUrl,
defaultIsUrl: isUrl,
loadingDefaultHomeserver: false,
});
}
} catch (e) {
console.error(e);
this.setState({
defaultServerDiscoveryError: _t("Unknown error discovering homeserver"),
loadingDefaultHomeserver: false,
});
}
},
_makeRegistrationUrl: function(params) {
if (this.props.startingFragmentQueryParams.referrer) {
params.referrer = this.props.startingFragmentQueryParams.referrer;
@ -1809,7 +1750,7 @@ export default React.createClass({
render: function() {
// console.log(`Rendering MatrixChat with view ${this.state.view}`);
if (this.state.view === VIEWS.LOADING || this.state.view === VIEWS.LOGGING_IN || this.state.loadingDefaultHomeserver) {
if (this.state.view === VIEWS.LOADING || this.state.view === VIEWS.LOGGING_IN) {
const Spinner = sdk.getComponent('elements.Spinner');
return (
<div className="mx_MatrixChat_splash">
@ -1883,8 +1824,6 @@ export default React.createClass({
idSid={this.state.register_id_sid}
email={this.props.startingFragmentQueryParams.email}
referrer={this.props.startingFragmentQueryParams.referrer}
defaultServerName={this.getDefaultServerName()}
defaultServerDiscoveryError={this.state.defaultServerDiscoveryError}
defaultHsUrl={this.getDefaultHsUrl()}
defaultIsUrl={this.getDefaultIsUrl()}
brand={this.props.config.brand}
@ -1907,8 +1846,6 @@ export default React.createClass({
const ForgotPassword = sdk.getComponent('structures.login.ForgotPassword');
return (
<ForgotPassword
defaultServerName={this.getDefaultServerName()}
defaultServerDiscoveryError={this.state.defaultServerDiscoveryError}
defaultHsUrl={this.getDefaultHsUrl()}
defaultIsUrl={this.getDefaultIsUrl()}
customHsUrl={this.getCurrentHsUrl()}
@ -1925,8 +1862,6 @@ export default React.createClass({
<Login
onLoggedIn={Lifecycle.setLoggedIn}
onRegisterClick={this.onRegisterClick}
defaultServerName={this.getDefaultServerName()}
defaultServerDiscoveryError={this.state.defaultServerDiscoveryError}
defaultHsUrl={this.getDefaultHsUrl()}
defaultIsUrl={this.getDefaultIsUrl()}
customHsUrl={this.getCurrentHsUrl()}

View file

@ -269,10 +269,17 @@ const RoomSubList = React.createClass({
let incomingCall;
if (this.props.incomingCall) {
// We can assume that if we have an incoming call then it is for this list
const IncomingCallBox = sdk.getComponent("voip.IncomingCallBox");
incomingCall =
<IncomingCallBox className="mx_RoomSubList_incomingCall" incomingCall={this.props.incomingCall} />;
const self = this;
// Check if the incoming call is for this section
const incomingCallRoom = this.props.list.filter(function(room) {
return self.props.incomingCall.roomId === room.roomId;
});
if (incomingCallRoom.length === 1) {
const IncomingCallBox = sdk.getComponent("voip.IncomingCallBox");
incomingCall =
<IncomingCallBox className="mx_RoomSubList_incomingCall" incomingCall={this.props.incomingCall} />;
}
}
let addRoomButton;

View file

@ -27,7 +27,6 @@ const React = require("react");
const ReactDOM = require("react-dom");
import PropTypes from 'prop-types';
import Promise from 'bluebird';
import filesize from 'filesize';
const classNames = require("classnames");
import { _t } from '../../languageHandler';
@ -104,10 +103,6 @@ module.exports = React.createClass({
roomLoading: true,
peekLoading: false,
shouldPeek: true,
// Media limits for uploading.
mediaConfig: undefined,
// used to trigger a rerender in TimelinePanel once the members are loaded,
// so RR are rendered again (now with the members available), ...
membersLoaded: !llMembers,
@ -163,7 +158,7 @@ module.exports = React.createClass({
MatrixClientPeg.get().on("RoomState.members", this.onRoomStateMember);
MatrixClientPeg.get().on("Room.myMembership", this.onMyMembership);
MatrixClientPeg.get().on("accountData", this.onAccountData);
this._fetchMediaConfig();
// Start listening for RoomViewStore updates
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
this._onRoomViewStoreUpdate(true);
@ -171,27 +166,6 @@ module.exports = React.createClass({
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) {
if (this.unmounted) {
return;
@ -527,10 +501,6 @@ module.exports = React.createClass({
break;
case 'notifier_enabled':
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_finished':
this.forceUpdate();
@ -609,20 +579,6 @@ module.exports = React.createClass({
}
},
async onRoomRecoveryReminderFinished(backupCreated) {
// If the user cancelled the key backup dialog, it suggests they don't
// want to be reminded anymore.
if (!backupCreated) {
await SettingsStore.setValue(
"showRoomRecoveryReminder",
null,
SettingLevel.ACCOUNT,
false,
);
}
this.forceUpdate();
},
canResetTimeline: function() {
if (!this.refs.messagePanel) {
return true;
@ -977,15 +933,6 @@ module.exports = React.createClass({
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) {
dis.dispatch({action: 'focus_composer'});
@ -1537,7 +1484,6 @@ module.exports = React.createClass({
const Loader = sdk.getComponent("elements.Spinner");
const TimelinePanel = sdk.getComponent("structures.TimelinePanel");
const RoomUpgradeWarningBar = sdk.getComponent("rooms.RoomUpgradeWarningBar");
const RoomRecoveryReminder = sdk.getComponent("rooms.RoomRecoveryReminder");
if (!this.state.room) {
if (this.state.roomLoading || this.state.peekLoading) {
@ -1675,13 +1621,6 @@ module.exports = React.createClass({
this.state.room.userMayUpgradeRoom(MatrixClientPeg.get().credentials.userId)
);
const showRoomRecoveryReminder = (
SettingsStore.isFeatureEnabled("feature_keybackup") &&
SettingsStore.getValue("showRoomRecoveryReminder") &&
MatrixClientPeg.get().isRoomEncrypted(this.state.room.roomId) &&
!MatrixClientPeg.get().getKeyBackupEnabled()
);
let aux = null;
let hideCancel = false;
if (this.state.editingRoomSettings) {
@ -1696,9 +1635,6 @@ module.exports = React.createClass({
} else if (showRoomUpgradeBar) {
aux = <RoomUpgradeWarningBar room={this.state.room} />;
hideCancel = true;
} else if (showRoomRecoveryReminder) {
aux = <RoomRecoveryReminder onFinished={this.onRoomRecoveryReminderFinished} />;
hideCancel = true;
} else if (this.state.showingPinned) {
hideCancel = true; // has own cancel
aux = <PinnedEventsPanel room={this.state.room} onCancelClick={this.onPinnedClick} />;
@ -1757,7 +1693,6 @@ module.exports = React.createClass({
callState={this.state.callState}
disabled={this.props.disabled}
showApps={this.state.showApps}
uploadAllowed={this.isFileUploadAllowed}
/>;
}

View file

@ -64,7 +64,6 @@ const SIMPLE_SETTINGS = [
{ id: "urlPreviewsEnabled" },
{ id: "autoplayGifsAndVideos" },
{ id: "alwaysShowEncryptionIcons" },
{ id: "showRoomRecoveryReminder" },
{ id: "hideReadReceipts" },
{ id: "dontSendTypingNotifications" },
{ id: "alwaysShowTimestamps" },
@ -189,11 +188,9 @@ module.exports = React.createClass({
phase: "UserSettings.LOADING", // LOADING, DISPLAY
email_add_pending: false,
vectorVersion: undefined,
canSelfUpdate: null,
rejectingInvites: false,
mediaDevices: null,
ignoredUsers: [],
autoLaunchEnabled: null,
};
},
@ -212,13 +209,6 @@ module.exports = React.createClass({
}, (e) => {
console.log("Failed to fetch app version", e);
});
PlatformPeg.get().canSelfUpdate().then((canUpdate) => {
if (this._unmounted) return;
this.setState({
canSelfUpdate: canUpdate,
});
});
}
this._refreshMediaDevices();
@ -237,12 +227,11 @@ module.exports = React.createClass({
});
this._refreshFromServer();
if (PlatformPeg.get().supportsAutoLaunch()) {
PlatformPeg.get().getAutoLaunchEnabled().then(enabled => {
this.setState({
autoLaunchEnabled: enabled,
});
});
if (PlatformPeg.get().isElectron()) {
const {ipcRenderer} = require('electron');
ipcRenderer.on('settings', this._electronSettings);
ipcRenderer.send('settings_get');
}
this.setState({
@ -273,6 +262,11 @@ module.exports = React.createClass({
if (cli) {
cli.removeListener("RoomMember.membership", this._onInviteStateChange);
}
if (PlatformPeg.get().isElectron()) {
const {ipcRenderer} = require('electron');
ipcRenderer.removeListener('settings', this._electronSettings);
}
},
// `UserSettings` assumes that the client peg will not be null, so give it some
@ -291,6 +285,10 @@ module.exports = React.createClass({
});
},
_electronSettings: function(ev, settings) {
this.setState({ electron_settings: settings });
},
_refreshMediaDevices: function(stream) {
if (stream) {
// kill stream so that we don't leave it lingering around with webcam enabled etc
@ -945,7 +943,7 @@ module.exports = React.createClass({
_renderCheckUpdate: function() {
const platform = PlatformPeg.get();
if (this.state.canSelfUpdate) {
if ('canSelfUpdate' in platform && platform.canSelfUpdate() && 'startUpdateCheck' in platform) {
return <div>
<h3>{ _t('Updates') }</h3>
<div className="mx_UserSettings_section">
@ -990,7 +988,8 @@ module.exports = React.createClass({
},
_renderElectronSettings: function() {
if (!PlatformPeg.get().supportsAutoLaunch()) return;
const settings = this.state.electron_settings;
if (!settings) return;
// TODO: This should probably be a granular setting, but it only applies to electron
// and ends up being get/set outside of matrix anyways (local system setting).
@ -1000,7 +999,7 @@ module.exports = React.createClass({
<div className="mx_UserSettings_toggle">
<input type="checkbox"
name="auto-launch"
defaultChecked={this.state.autoLaunchEnabled}
defaultChecked={settings['auto-launch']}
onChange={this._onAutoLaunchChanged}
/>
<label htmlFor="auto-launch">{ _t('Start automatically after system login') }</label>
@ -1010,11 +1009,8 @@ module.exports = React.createClass({
},
_onAutoLaunchChanged: function(e) {
PlatformPeg.get().setAutoLaunchEnabled(e.target.checked).then(() => {
this.setState({
autoLaunchEnabled: e.target.checked,
});
});
const {ipcRenderer} = require('electron');
ipcRenderer.send('settings_set', 'auto-launch', e.target.checked);
},
_mapWebRtcDevicesToSpans: function(devices) {
@ -1373,7 +1369,7 @@ module.exports = React.createClass({
{ this._renderBulkOptions() }
{ this._renderBugReport() }
{ this._renderElectronSettings() }
{ PlatformPeg.get().isElectron() && this._renderElectronSettings() }
{ this._renderAnalyticsControl() }

View file

@ -36,14 +36,6 @@ module.exports = React.createClass({
onLoginClick: PropTypes.func,
onRegisterClick: PropTypes.func,
onComplete: PropTypes.func.isRequired,
// The default server name to use when the user hasn't specified
// one. This is used when displaying the defaultHsUrl in the UI.
defaultServerName: PropTypes.string,
// An error passed along from higher up explaining that something
// went wrong when finding the defaultHsUrl.
defaultServerDiscoveryError: PropTypes.string,
},
getInitialState: function() {
@ -53,7 +45,6 @@ module.exports = React.createClass({
progress: null,
password: null,
password2: null,
errorText: null,
};
},
@ -90,13 +81,6 @@ module.exports = React.createClass({
onSubmitForm: function(ev) {
ev.preventDefault();
// Don't allow the user to register if there's a discovery error
// Without this, the user could end up registering on the wrong homeserver.
if (this.props.defaultServerDiscoveryError) {
this.setState({errorText: this.props.defaultServerDiscoveryError});
return;
}
if (!this.state.email) {
this.showErrorDialog(_t('The email address linked to your account must be entered.'));
} else if (!this.state.password || !this.state.password2) {
@ -216,12 +200,6 @@ module.exports = React.createClass({
);
}
let errorText = null;
const err = this.state.errorText || this.props.defaultServerDiscoveryError;
if (err) {
errorText = <div className="mx_Login_error">{ err }</div>;
}
const LanguageSelector = sdk.getComponent('structures.login.LanguageSelector');
resetPasswordJsx = (
@ -252,7 +230,6 @@ module.exports = React.createClass({
<input className="mx_Login_submit" type="submit" value={_t('Send Reset Email')} />
</form>
{ serverConfigSection }
{ errorText }
<a className="mx_Login_create" onClick={this.props.onLoginClick} href="#">
{ _t('Return to login screen') }
</a>

View file

@ -26,17 +26,10 @@ import Login from '../../../Login';
import SdkConfig from '../../../SdkConfig';
import SettingsStore from "../../../settings/SettingsStore";
import { messageForResourceLimitError } from '../../../utils/ErrorUtils';
import { AutoDiscovery } from "matrix-js-sdk";
// For validating phone numbers without country codes
const PHONE_NUMBER_REGEX = /^[0-9()\-\s]*$/;
// These are used in several places, and come from the js-sdk's autodiscovery
// stuff. We define them here so that they'll be picked up by i18n.
_td("Invalid homeserver discovery response");
_td("Invalid identity server discovery response");
_td("General failure");
/**
* A wire component which glues together login UI components and Login logic
*/
@ -57,14 +50,6 @@ module.exports = React.createClass({
// different home server without confusing users.
fallbackHsUrl: PropTypes.string,
// The default server name to use when the user hasn't specified
// one. This is used when displaying the defaultHsUrl in the UI.
defaultServerName: PropTypes.string,
// An error passed along from higher up explaining that something
// went wrong when finding the defaultHsUrl.
defaultServerDiscoveryError: PropTypes.string,
defaultDeviceDisplayName: PropTypes.string,
// login shouldn't know or care how registration is done.
@ -89,12 +74,6 @@ module.exports = React.createClass({
phoneCountry: null,
phoneNumber: "",
currentFlow: "m.login.password",
// .well-known discovery
discoveredHsUrl: "",
discoveredIsUrl: "",
discoveryError: "",
findingHomeserver: false,
};
},
@ -126,10 +105,6 @@ module.exports = React.createClass({
},
onPasswordLogin: function(username, phoneCountry, phoneNumber, password) {
// Prevent people from submitting their password when homeserver
// discovery went wrong
if (this.state.discoveryError || this.props.defaultServerDiscoveryError) return;
this.setState({
busy: true,
errorText: null,
@ -246,22 +221,6 @@ module.exports = React.createClass({
this.setState({ username: username });
},
onUsernameBlur: function(username) {
this.setState({ username: username });
if (username[0] === "@") {
const serverName = username.split(':').slice(1).join(':');
try {
// we have to append 'https://' to make the URL constructor happy
// otherwise we get things like 'protocol: matrix.org, pathname: 8448'
const url = new URL("https://" + serverName);
this._tryWellKnownDiscovery(url.hostname);
} catch (e) {
console.error("Problem parsing URL or unhandled error doing .well-known discovery:", e);
this.setState({discoveryError: _t("Failed to perform homeserver discovery")});
}
}
},
onPhoneCountryChanged: function(phoneCountry) {
this.setState({ phoneCountry: phoneCountry });
},
@ -297,59 +256,6 @@ module.exports = React.createClass({
});
},
_tryWellKnownDiscovery: async function(serverName) {
if (!serverName.trim()) {
// Nothing to discover
this.setState({discoveryError: "", discoveredHsUrl: "", discoveredIsUrl: "", findingHomeserver: false});
return;
}
this.setState({findingHomeserver: true});
try {
const discovery = await AutoDiscovery.findClientConfig(serverName);
const state = discovery["m.homeserver"].state;
if (state !== AutoDiscovery.SUCCESS && state !== AutoDiscovery.PROMPT) {
this.setState({
discoveredHsUrl: "",
discoveredIsUrl: "",
discoveryError: discovery["m.homeserver"].error,
findingHomeserver: false,
});
} else if (state === AutoDiscovery.PROMPT) {
this.setState({
discoveredHsUrl: "",
discoveredIsUrl: "",
discoveryError: "",
findingHomeserver: false,
});
} else if (state === AutoDiscovery.SUCCESS) {
this.setState({
discoveredHsUrl: discovery["m.homeserver"].base_url,
discoveredIsUrl:
discovery["m.identity_server"].state === AutoDiscovery.SUCCESS
? discovery["m.identity_server"].base_url
: "",
discoveryError: "",
findingHomeserver: false,
});
} else {
console.warn("Unknown state for m.homeserver in discovery response: ", discovery);
this.setState({
discoveredHsUrl: "",
discoveredIsUrl: "",
discoveryError: _t("Unknown failure discovering homeserver"),
findingHomeserver: false,
});
}
} catch (e) {
console.error(e);
this.setState({
findingHomeserver: false,
discoveryError: _t("Unknown error discovering homeserver"),
});
}
},
_initLoginLogic: function(hsUrl, isUrl) {
const self = this;
hsUrl = hsUrl || this.state.enteredHomeserverUrl;
@ -487,14 +393,11 @@ module.exports = React.createClass({
initialPhoneCountry={this.state.phoneCountry}
initialPhoneNumber={this.state.phoneNumber}
onUsernameChanged={this.onUsernameChanged}
onUsernameBlur={this.onUsernameBlur}
onPhoneCountryChanged={this.onPhoneCountryChanged}
onPhoneNumberChanged={this.onPhoneNumberChanged}
onForgotPasswordClick={this.props.onForgotPasswordClick}
loginIncorrect={this.state.loginIncorrect}
hsUrl={this.state.enteredHomeserverUrl}
hsName={this.props.defaultServerName}
disableSubmit={this.state.findingHomeserver}
/>
);
},
@ -513,8 +416,6 @@ module.exports = React.createClass({
const ServerConfig = sdk.getComponent("login.ServerConfig");
const loader = this.state.busy ? <div className="mx_Login_loader"><Loader /></div> : null;
const errorText = this.props.defaultServerDiscoveryError || this.state.discoveryError || this.state.errorText;
let loginAsGuestJsx;
if (this.props.enableGuest) {
loginAsGuestJsx =
@ -529,8 +430,8 @@ module.exports = React.createClass({
if (!SdkConfig.get()['disable_custom_urls']) {
serverConfig = <ServerConfig ref="serverConfig"
withToggleButton={true}
customHsUrl={this.state.discoveredHsUrl || this.props.customHsUrl}
customIsUrl={this.state.discoveredIsUrl || this.props.customIsUrl}
customHsUrl={this.props.customHsUrl}
customIsUrl={this.props.customIsUrl}
defaultHsUrl={this.props.defaultHsUrl}
defaultIsUrl={this.props.defaultIsUrl}
onServerConfigChange={this.onServerConfigChange}
@ -542,16 +443,16 @@ module.exports = React.createClass({
if (theme !== "status") {
header = <h2>{ _t('Sign in') } { loader }</h2>;
} else {
if (!errorText) {
if (!this.state.errorText) {
header = <h2>{ _t('Sign in to get started') } { loader }</h2>;
}
}
let errorTextSection;
if (errorText) {
if (this.state.errorText) {
errorTextSection = (
<div className="mx_Login_error">
{ errorText }
{ this.state.errorText }
</div>
);
}

View file

@ -57,14 +57,6 @@ module.exports = React.createClass({
}),
teamSelected: PropTypes.object,
// The default server name to use when the user hasn't specified
// one. This is used when displaying the defaultHsUrl in the UI.
defaultServerName: PropTypes.string,
// An error passed along from higher up explaining that something
// went wrong when finding the defaultHsUrl.
defaultServerDiscoveryError: PropTypes.string,
defaultDeviceDisplayName: PropTypes.string,
// registration shouldn't know or care how login is done.
@ -178,12 +170,6 @@ module.exports = React.createClass({
},
onFormSubmit: function(formVals) {
// Don't allow the user to register if there's a discovery error
// Without this, the user could end up registering on the wrong homeserver.
if (this.props.defaultServerDiscoveryError) {
this.setState({errorText: this.props.defaultServerDiscoveryError});
return;
}
this.setState({
errorText: "",
busy: true,
@ -342,7 +328,7 @@ module.exports = React.createClass({
errMsg = _t('A phone number is required to register on this homeserver.');
break;
case "RegistrationForm.ERR_USERNAME_INVALID":
errMsg = _t("Only use lower case letters, numbers and '=_-./'");
errMsg = _t('User names may only contain letters, numbers, dots, hyphens and underscores.');
break;
case "RegistrationForm.ERR_USERNAME_BLANK":
errMsg = _t('You need to enter a user name.');
@ -455,13 +441,12 @@ module.exports = React.createClass({
let header;
let errorText;
// FIXME: remove hardcoded Status team tweaks at some point
const err = this.state.errorText || this.props.defaultServerDiscoveryError;
if (theme === 'status' && err) {
header = <div className="mx_Login_error">{ err }</div>;
if (theme === 'status' && this.state.errorText) {
header = <div className="mx_Login_error">{ this.state.errorText }</div>;
} else {
header = <h2>{ _t('Create an account') }</h2>;
if (err) {
errorText = <div className="mx_Login_error">{ err }</div>;
if (this.state.errorText) {
errorText = <div className="mx_Login_error">{ this.state.errorText }</div>;
}
}

View file

@ -23,7 +23,6 @@ import MatrixClientPeg from '../../../MatrixClientPeg';
import Promise from 'bluebird';
import { addressTypes, getAddressType } from '../../../UserAddress.js';
import GroupStore from '../../../stores/GroupStore';
import * as Email from "../../../email";
const TRUNCATE_QUERY_LIST = 40;
const QUERY_USER_DIRECTORY_DEBOUNCE_MS = 200;
@ -420,10 +419,6 @@ module.exports = React.createClass({
// a perfectly valid address if there are close matches.
const addrType = getAddressType(query);
if (this.props.validAddressTypes.includes(addrType)) {
if (addrType === 'email' && !Email.looksValid(query)) {
this.setState({searchError: _t("That doesn't look like a valid email address")});
return;
}
suggestedList.unshift({
addressType: addrType,
address: query,

View file

@ -57,7 +57,8 @@ export default React.createClass({
className: PropTypes.string,
// Title for the dialog.
title: PropTypes.node.isRequired,
// (could probably actually be something more complicated than a string if desired)
title: PropTypes.string.isRequired,
// children should be the content of the dialog
children: PropTypes.node,

View file

@ -35,10 +35,19 @@ export default class DeactivateAccountDialog extends React.Component {
this._onPasswordFieldChange = this._onPasswordFieldChange.bind(this);
this._onEraseFieldChange = this._onEraseFieldChange.bind(this);
const deactivationPreferences =
MatrixClientPeg.get().getAccountData('im.riot.account_deactivation_preferences');
const shouldErase = (
deactivationPreferences &&
deactivationPreferences.getContent() &&
deactivationPreferences.getContent().shouldErase
) || false;
this.state = {
confirmButtonEnabled: false,
busy: false,
shouldErase: false,
shouldErase,
errStr: null,
};
}
@ -58,6 +67,36 @@ export default class DeactivateAccountDialog extends React.Component {
async _onOk() {
this.setState({busy: true});
// Before we deactivate the account insert an event into
// the user's account data indicating that they wish to be
// erased from the homeserver.
//
// We do this because the API for erasing after deactivation
// might not be supported by the connected homeserver. Leaving
// an indication in account data is only best-effort, and
// in the worse case, the HS maintainer would have to run a
// script to erase deactivated accounts that have shouldErase
// set to true in im.riot.account_deactivation_preferences.
//
// Note: The preferences are scoped to Riot, hence the
// "im.riot..." event type.
//
// Note: This may have already been set on previous attempts
// where, for example, the user entered the wrong password.
// This is fine because the UI always indicates the preference
// prior to us calling `deactivateAccount`.
try {
await MatrixClientPeg.get().setAccountData('im.riot.account_deactivation_preferences', {
shouldErase: this.state.shouldErase,
});
} catch (err) {
this.setState({
busy: false,
errStr: _t('Failed to indicate account erasure'),
});
return;
}
try {
// This assumes that the HS requires password UI auth
// for this endpoint. In reality it could be any UI auth.

View file

@ -23,7 +23,6 @@ import MatrixClientPeg from '../../../MatrixClientPeg';
import classnames from 'classnames';
import { KeyCode } from '../../../Keyboard';
import { _t } from '../../../languageHandler';
import { SAFE_LOCALPART_REGEX } from '../../../Registration';
// The amount of time to wait for further changes to the input username before
// sending a request to the server
@ -111,11 +110,12 @@ export default React.createClass({
},
_doUsernameCheck: function() {
// We do a quick check ahead of the username availability API to ensure the
// user ID roughly looks okay from a Matrix perspective.
if (!SAFE_LOCALPART_REGEX.test(this.state.username)) {
// XXX: SPEC-1
// Check if username is valid
// Naive impl copied from https://github.com/matrix-org/matrix-react-sdk/blob/66c3a6d9ca695780eb6b662e242e88323053ff33/src/components/views/login/RegistrationForm.js#L190
if (encodeURIComponent(this.state.username) !== this.state.username) {
this.setState({
usernameError: _t("Only use lower case letters, numbers and '=_-./'"),
usernameError: _t('User names may only contain letters, numbers, dots, hyphens and underscores.'),
});
return Promise.reject();
}
@ -210,6 +210,7 @@ export default React.createClass({
render: function() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const InteractiveAuth = sdk.getComponent('structures.InteractiveAuth');
const Spinner = sdk.getComponent('elements.Spinner');
let auth;
if (this.state.doingUIAuth) {
@ -229,8 +230,9 @@ export default React.createClass({
});
let usernameIndicator = null;
let usernameBusyIndicator = null;
if (this.state.usernameBusy) {
usernameIndicator = <div>{_t("Checking...")}</div>;
usernameBusyIndicator = <Spinner w="24" h="24" />;
} else {
const usernameAvailable = this.state.username &&
this.state.usernameCheckSupport && !this.state.usernameError;
@ -268,6 +270,7 @@ export default React.createClass({
size="30"
className={inputClasses}
/>
{ usernameBusyIndicator }
</div>
{ usernameIndicator }
<p>

View file

@ -22,6 +22,7 @@ import qs from 'querystring';
import React from 'react';
import PropTypes from 'prop-types';
import MatrixClientPeg from '../../../MatrixClientPeg';
import PlatformPeg from '../../../PlatformPeg';
import ScalarAuthClient from '../../../ScalarAuthClient';
import WidgetMessaging from '../../../WidgetMessaging';
import TintableSvgButton from './TintableSvgButton';
@ -48,6 +49,7 @@ export default class AppTile extends React.Component {
this.state = this._getNewState(props);
this._onAction = this._onAction.bind(this);
this._onMessage = this._onMessage.bind(this);
this._onLoaded = this._onLoaded.bind(this);
this._onEditClick = this._onEditClick.bind(this);
this._onDeleteClick = this._onDeleteClick.bind(this);
@ -141,6 +143,10 @@ export default class AppTile extends React.Component {
}
componentDidMount() {
// Legacy Jitsi widget messaging -- TODO replace this with standard widget
// postMessaging API
window.addEventListener('message', this._onMessage, false);
// Widget action listeners
this.dispatcherRef = dis.register(this._onAction);
}
@ -149,6 +155,9 @@ export default class AppTile extends React.Component {
// Widget action listeners
dis.unregister(this.dispatcherRef);
// Jitsi listener
window.removeEventListener('message', this._onMessage);
// if it's not remaining on screen, get rid of the PersistedElement container
if (!ActiveWidgetStore.getWidgetPersistence(this.props.id)) {
ActiveWidgetStore.destroyPersistentWidget();
@ -224,6 +233,32 @@ export default class AppTile extends React.Component {
}
}
// Legacy Jitsi widget messaging
// TODO -- This should be replaced with the new widget postMessaging API
_onMessage(event) {
if (this.props.type !== 'jitsi') {
return;
}
if (!event.origin) {
event.origin = event.originalEvent.origin;
}
const widgetUrlObj = url.parse(this.state.widgetUrl);
const eventOrigin = url.parse(event.origin);
if (
eventOrigin.protocol !== widgetUrlObj.protocol ||
eventOrigin.host !== widgetUrlObj.host
) {
return;
}
if (event.data.widgetAction === 'jitsi_iframe_loaded') {
const iframe = this.refs.appFrame.contentWindow
.document.querySelector('iframe[id^="jitsiConferenceFrame"]');
PlatformPeg.get().setupScreenSharingForIframe(iframe);
}
}
_canUserModify() {
// User widgets should always be modifiable by their creator
if (this.props.userWidget && MatrixClientPeg.get().credentials.userId === this.props.creatorUserId) {
@ -509,7 +544,7 @@ export default class AppTile extends React.Component {
// Additional iframe feature pemissions
// (see - https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-permissions-in-cross-origin-iframes and https://wicg.github.io/feature-policy/)
const iframeFeatures = "microphone; camera; encrypted-media; autoplay;";
const iframeFeatures = "microphone; camera; encrypted-media;";
const appTileBodyClass = 'mx_AppTileBody' + (this.props.miniMode ? '_mini ' : ' ');

View file

@ -29,7 +29,6 @@ var TintableSvg = React.createClass({
width: PropTypes.string.isRequired,
height: PropTypes.string.isRequired,
className: PropTypes.string,
forceColors: PropTypes.arrayOf(PropTypes.string),
},
statics: {
@ -51,12 +50,6 @@ var TintableSvg = React.createClass({
delete TintableSvg.mounts[this.id];
},
componentDidUpdate: function(prevProps, prevState) {
if (prevProps.forceColors !== this.props.forceColors) {
this.calcAndApplyFixups(this.refs.svgContainer);
}
},
tint: function() {
// TODO: only bother running this if the global tint settings have changed
// since we loaded!
@ -64,13 +57,8 @@ var TintableSvg = React.createClass({
},
onLoad: function(event) {
this.calcAndApplyFixups(event.target);
},
calcAndApplyFixups: function(target) {
if (!target) return;
// console.log("TintableSvg.calcAndApplyFixups for " + this.props.src);
this.fixups = Tinter.calcSvgFixups([target], this.props.forceColors);
// console.log("TintableSvg.onLoad for " + this.props.src);
this.fixups = Tinter.calcSvgFixups([event.target]);
Tinter.applySvgFixups(this.fixups);
},
@ -83,7 +71,6 @@ var TintableSvg = React.createClass({
height={this.props.height}
onLoad={this.onLoad}
tabIndex="-1"
ref="svgContainer"
/>
);
},

View file

@ -37,9 +37,7 @@ export default React.createClass({
getInitialState: function() {
return {
members: null,
membersError: null,
invitedMembers: null,
invitedMembersError: null,
truncateAt: INITIAL_LOAD_NUM_MEMBERS,
};
},
@ -57,19 +55,6 @@ export default React.createClass({
GroupStore.registerListener(groupId, () => {
this._fetchMembers();
});
GroupStore.on('error', (err, errorGroupId, stateKey) => {
if (this._unmounted || groupId !== errorGroupId) return;
if (stateKey === GroupStore.STATE_KEY.GroupMembers) {
this.setState({
membersError: err,
});
}
if (stateKey === GroupStore.STATE_KEY.GroupInvitedMembers) {
this.setState({
invitedMembersError: err,
});
}
});
},
_fetchMembers: function() {
@ -103,11 +88,7 @@ export default React.createClass({
this.setState({ searchQuery: ev.target.value });
},
makeGroupMemberTiles: function(query, memberList, memberListError) {
if (memberListError) {
return <div className="warning">{ _t("Failed to load group members") }</div>;
}
makeGroupMemberTiles: function(query, memberList) {
const GroupMemberTile = sdk.getComponent("groups.GroupMemberTile");
const TruncatedList = sdk.getComponent("elements.TruncatedList");
query = (query || "").toLowerCase();
@ -185,25 +166,13 @@ export default React.createClass({
);
const joined = this.state.members ? <div className="mx_MemberList_joined">
{
this.makeGroupMemberTiles(
this.state.searchQuery,
this.state.members,
this.state.membersError,
)
}
{ this.makeGroupMemberTiles(this.state.searchQuery, this.state.members) }
</div> : <div />;
const invited = (this.state.invitedMembers && this.state.invitedMembers.length > 0) ?
<div className="mx_MemberList_invited">
<h2>{_t("Invited")}</h2>
{
this.makeGroupMemberTiles(
this.state.searchQuery,
this.state.invitedMembers,
this.state.invitedMembersError,
)
}
<h2>{ _t("Invited") }</h2>
{ this.makeGroupMemberTiles(this.state.searchQuery, this.state.invitedMembers) }
</div> : <div />;
let inviteButton;

View file

@ -30,7 +30,6 @@ class PasswordLogin extends React.Component {
static defaultProps = {
onError: function() {},
onUsernameChanged: function() {},
onUsernameBlur: function() {},
onPasswordChanged: function() {},
onPhoneCountryChanged: function() {},
onPhoneNumberChanged: function() {},
@ -40,8 +39,6 @@ class PasswordLogin extends React.Component {
initialPassword: "",
loginIncorrect: false,
hsDomain: "",
hsName: null,
disableSubmit: false,
}
constructor(props) {
@ -56,7 +53,6 @@ class PasswordLogin extends React.Component {
this.onSubmitForm = this.onSubmitForm.bind(this);
this.onUsernameChanged = this.onUsernameChanged.bind(this);
this.onUsernameBlur = this.onUsernameBlur.bind(this);
this.onLoginTypeChange = this.onLoginTypeChange.bind(this);
this.onPhoneCountryChanged = this.onPhoneCountryChanged.bind(this);
this.onPhoneNumberChanged = this.onPhoneNumberChanged.bind(this);
@ -128,10 +124,6 @@ class PasswordLogin extends React.Component {
this.props.onUsernameChanged(ev.target.value);
}
onUsernameBlur(ev) {
this.props.onUsernameBlur(this.state.username);
}
onLoginTypeChange(loginType) {
this.props.onError(null); // send a null error to clear any error messages
this.setState({
@ -175,7 +167,6 @@ class PasswordLogin extends React.Component {
type="text"
name="username" // make it a little easier for browser's remember-password
onChange={this.onUsernameChanged}
onBlur={this.onUsernameBlur}
placeholder="joe@example.com"
value={this.state.username}
autoFocus
@ -191,7 +182,6 @@ class PasswordLogin extends React.Component {
type="text"
name="username" // make it a little easier for browser's remember-password
onChange={this.onUsernameChanged}
onBlur={this.onUsernameBlur}
placeholder={SdkConfig.get().disable_custom_urls ?
_t("Username on %(hs)s", {
hs: this.props.hsUrl.replace(/^https?:\/\//, ''),
@ -252,15 +242,13 @@ class PasswordLogin extends React.Component {
);
}
let matrixIdText = _t('Matrix ID');
if (this.props.hsName) {
matrixIdText = _t('%(serverName)s Matrix ID', {serverName: this.props.hsName});
} else {
let matrixIdText = '';
if (this.props.hsUrl) {
try {
const parsedHsUrl = new URL(this.props.hsUrl);
matrixIdText = _t('%(serverName)s Matrix ID', {serverName: parsedHsUrl.hostname});
} catch (e) {
// ignore
// pass
}
}
@ -292,8 +280,6 @@ class PasswordLogin extends React.Component {
);
}
const disableSubmit = this.props.disableSubmit || matrixIdText === '';
return (
<div>
<form onSubmit={this.onSubmitForm}>
@ -307,7 +293,7 @@ class PasswordLogin extends React.Component {
/>
<br />
{ forgotPasswordJsx }
<input className="mx_Login_submit" type="submit" value={_t('Sign in')} disabled={disableSubmit} />
<input className="mx_Login_submit" type="submit" value={_t('Sign in')} disabled={matrixIdText === ''} />
</form>
</div>
);
@ -331,8 +317,6 @@ PasswordLogin.propTypes = {
onPhoneNumberChanged: PropTypes.func,
onPasswordChanged: PropTypes.func,
loginIncorrect: PropTypes.bool,
hsName: PropTypes.string,
disableSubmit: PropTypes.bool,
};
module.exports = PasswordLogin;

View file

@ -25,7 +25,7 @@ import { looksValid as phoneNumberLooksValid } from '../../../phonenumber';
import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';
import SdkConfig from '../../../SdkConfig';
import { SAFE_LOCALPART_REGEX } from '../../../Registration';
import SettingsStore from "../../../settings/SettingsStore";
const FIELD_EMAIL = 'field_email';
const FIELD_PHONE_COUNTRY = 'field_phone_country';
@ -194,8 +194,9 @@ module.exports = React.createClass({
} else this.markFieldValid(field_id, phoneNumberValid, "RegistrationForm.ERR_PHONE_NUMBER_INVALID");
break;
case FIELD_USERNAME:
const username = this.refs.username.value.trim();
if (!SAFE_LOCALPART_REGEX.test(username)) {
// XXX: SPEC-1
var username = this.refs.username.value.trim();
if (encodeURIComponent(username) != username) {
this.markFieldValid(
field_id,
false,

View file

@ -70,23 +70,6 @@ module.exports = React.createClass({
};
},
componentWillReceiveProps: function(newProps) {
if (newProps.customHsUrl === this.state.hs_url &&
newProps.customIsUrl === this.state.is_url) return;
this.setState({
hs_url: newProps.customHsUrl,
is_url: newProps.customIsUrl,
configVisible: !newProps.withToggleButton ||
(newProps.customHsUrl !== newProps.defaultHsUrl) ||
(newProps.customIsUrl !== newProps.defaultIsUrl),
});
this.props.onServerConfigChange({
hsUrl: newProps.customHsUrl,
isUrl: newProps.customIsUrl,
});
},
onHomeserverChanged: function(ev) {
this.setState({hs_url: ev.target.value}, function() {
this._hsTimeoutId = this._waitThenInvoke(this._hsTimeoutId, function() {

View file

@ -130,7 +130,7 @@ module.exports = React.createClass({
},
isAliasValid: function(alias) {
// XXX: FIXME https://github.com/matrix-org/matrix-doc/issues/668
// XXX: FIXME SPEC-1
return (alias.match(/^#([^\/:,]+?):(.+)$/) && encodeURI(alias) === alias);
},

View file

@ -41,7 +41,6 @@ import withMatrixClient from '../../../wrappers/withMatrixClient';
import AccessibleButton from '../elements/AccessibleButton';
import RoomViewStore from '../../../stores/RoomViewStore';
import SdkConfig from '../../../SdkConfig';
import MultiInviter from "../../../utils/MultiInviter";
module.exports = withMatrixClient(React.createClass({
displayName: 'MemberInfo',
@ -715,18 +714,12 @@ module.exports = withMatrixClient(React.createClass({
const roomId = member && member.roomId ? member.roomId : RoomViewStore.getRoomId();
const onInviteUserButton = async() => {
try {
// We use a MultiInviter to re-use the invite logic, even though
// we're only inviting one user.
const inviter = new MultiInviter(roomId);
await inviter.invite([member.userId]).then(() => {
if (inviter.getCompletionState(userId) !== "invited")
throw new Error(inviter.getErrorText(userId));
});
await cli.invite(roomId, member.userId);
} catch (err) {
const ErrorDialog = sdk.getComponent('dialogs.ErrorDialog');
Modal.createTrackedDialog('Failed to invite', '', ErrorDialog, {
title: _t('Failed to invite'),
description: ((err && err.message) ? err.message : _t("Operation failed")),
description: ((err && err.message) ? err.message : "Operation failed"),
});
}
};

View file

@ -139,8 +139,7 @@ export default class MessageComposer extends React.Component {
}
onUploadFileSelected(files) {
const tfiles = files.target.files;
this.uploadFiles(tfiles);
this.uploadFiles(files.target.files);
}
uploadFiles(files) {
@ -148,21 +147,10 @@ export default class MessageComposer extends React.Component {
const TintableSvg = sdk.getComponent("elements.TintableSvg");
const fileList = [];
const acceptedFiles = [];
const failedFiles = [];
for (let i=0; i<files.length; i++) {
const fileAcceptedOrError = this.props.uploadAllowed(files[i]);
if (fileAcceptedOrError === true) {
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>);
}
fileList.push(<li key={i}>
<TintableSvg key={i} src="img/files.svg" width="16" height="16" /> { files[i].name || _t('Attachment') }
</li>);
}
const isQuoting = Boolean(RoomViewStore.getQuotingEvent());
@ -173,47 +161,23 @@ export default class MessageComposer extends React.Component {
}</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, {
title: _t('Upload Files'),
description: (
<div>
{ acceptedFilesPart }
{ failedFilesPart }
<p>{ _t('Are you sure you want to upload the following files?') }</p>
<ul style={{listStyle: 'none', textAlign: 'left'}}>
{ fileList }
</ul>
{ replyToWarning }
</div>
),
hasCancelButton: acceptedFiles.length > 0,
button: buttonText,
onFinished: (shouldUpload) => {
if (shouldUpload) {
// MessageComposer shouldn't have to rely on its parent passing in a callback to upload a file
if (fileList) {
for (let i=0; i<fileList.length; i++) {
this.props.uploadFile(fileList[i]);
if (files) {
for (let i=0; i<files.length; i++) {
this.props.uploadFile(files[i]);
}
}
}
@ -495,9 +459,6 @@ MessageComposer.propTypes = {
// callback when a file to upload is chosen
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
showApps: PropTypes.bool
showApps: PropTypes.bool,
};

View file

@ -83,7 +83,6 @@ module.exports = React.createClass({
isLoadingLeftRooms: false,
totalRoomCount: null,
lists: {},
incomingCallTag: null,
incomingCall: null,
selectedTags: [],
};
@ -200,13 +199,11 @@ module.exports = React.createClass({
if (call && call.call_state === 'ringing') {
this.setState({
incomingCall: call,
incomingCallTag: this.getTagNameForRoomId(payload.room_id),
});
this._repositionIncomingCallBox(undefined, true);
} else {
this.setState({
incomingCall: null,
incomingCallTag: null,
});
}
break;
@ -371,26 +368,6 @@ module.exports = React.createClass({
// this._lastRefreshRoomListTs = Date.now();
},
getTagNameForRoomId: function(roomId) {
const lists = RoomListStore.getRoomLists();
for (const tagName of Object.keys(lists)) {
for (const room of lists[tagName]) {
// Should be impossible, but guard anyways.
if (!room) {
continue;
}
const myUserId = MatrixClientPeg.get().getUserId();
if (HIDE_CONFERENCE_CHANS && Rooms.isConfCallRoom(room, myUserId, this.props.ConferenceHandler)) {
continue;
}
if (room.roomId === roomId) return tagName;
}
}
return null;
},
getRoomLists: function() {
const lists = RoomListStore.getRoomLists();
@ -604,12 +581,6 @@ module.exports = React.createClass({
},
render: function() {
const incomingCallIfTaggedAs = (tagName) => {
if (!this.state.incomingCall) return null;
if (this.state.incomingCallTag !== tagName) return null;
return this.state.incomingCall;
};
let subLists = [
{
list: [],
@ -622,7 +593,6 @@ module.exports = React.createClass({
list: this.state.lists['im.vector.fake.invite'],
label: _t('Invites'),
order: "recent",
incomingCall: incomingCallIfTaggedAs('im.vector.fake.invite'),
isInvite: true,
},
{
@ -630,7 +600,6 @@ module.exports = React.createClass({
label: _t('Favourites'),
tagName: "m.favourite",
order: "manual",
incomingCall: incomingCallIfTaggedAs('m.favourite'),
},
{
list: this.state.lists['im.vector.fake.direct'],
@ -638,7 +607,6 @@ module.exports = React.createClass({
tagName: "im.vector.fake.direct",
headerItems: this._getHeaderItems('im.vector.fake.direct'),
order: "recent",
incomingCall: incomingCallIfTaggedAs('im.vector.fake.direct'),
onAddRoom: () => {dis.dispatch({action: 'view_create_chat'})},
},
{
@ -646,7 +614,6 @@ module.exports = React.createClass({
label: _t('Rooms'),
headerItems: this._getHeaderItems('im.vector.fake.recent'),
order: "recent",
incomingCall: incomingCallIfTaggedAs('im.vector.fake.recent'),
onAddRoom: () => {dis.dispatch({action: 'view_create_room'})},
},
];
@ -660,7 +627,6 @@ module.exports = React.createClass({
label: labelForTagName(tagName),
tagName: tagName,
order: "manual",
incomingCall: incomingCallIfTaggedAs(tagName),
};
});
subLists = subLists.concat(tagSubLists);
@ -670,13 +636,11 @@ module.exports = React.createClass({
label: _t('Low priority'),
tagName: "m.lowpriority",
order: "recent",
incomingCall: incomingCallIfTaggedAs('m.lowpriority'),
},
{
list: this.state.lists['im.vector.fake.archived'],
label: _t('Historical'),
order: "recent",
incomingCall: incomingCallIfTaggedAs('im.vector.fake.archived'),
startAsHidden: true,
showSpinner: this.state.isLoadingLeftRooms,
onHeaderClick: this.onArchivedHeaderClick,
@ -686,7 +650,6 @@ module.exports = React.createClass({
label: _t('System Alerts'),
tagName: "m.lowpriority",
order: "recent",
incomingCall: incomingCallIfTaggedAs('m.server_notice'),
},
]);

View file

@ -1,85 +0,0 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import PropTypes from "prop-types";
import sdk from "../../../index";
import { _t } from "../../../languageHandler";
import Modal from "../../../Modal";
export default class RoomRecoveryReminder extends React.PureComponent {
static propTypes = {
onFinished: PropTypes.func.isRequired,
}
showKeyBackupDialog = () => {
Modal.createTrackedDialogAsync("Key Backup", "Key Backup",
import("../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog"),
{
onFinished: this.props.onFinished,
},
);
}
onDontAskAgainClick = () => {
// When you choose "Don't ask again" from the room reminder, we show a
// dialog to confirm the choice.
Modal.createTrackedDialogAsync("Ignore Recovery Reminder", "Ignore Recovery Reminder",
import("../../../async-components/views/dialogs/keybackup/IgnoreRecoveryReminderDialog"),
{
onDontAskAgain: () => {
// Report false to the caller, who should prevent the
// reminder from appearing in the future.
this.props.onFinished(false);
},
onSetup: () => {
this.showKeyBackupDialog();
},
},
);
}
onSetupClick = () => {
this.showKeyBackupDialog();
}
render() {
const AccessibleButton = sdk.getComponent("views.elements.AccessibleButton");
return (
<div className="mx_RoomRecoveryReminder">
<div className="mx_RoomRecoveryReminder_header">{_t(
"Secure Message Recovery",
)}</div>
<div className="mx_RoomRecoveryReminder_body">{_t(
"If you log out or use another device, you'll lose your " +
"secure message history. To prevent this, set up Secure " +
"Message Recovery.",
)}</div>
<div className="mx_RoomRecoveryReminder_buttons">
<AccessibleButton className="mx_RoomRecoveryReminder_button mx_RoomRecoveryReminder_secondary"
onClick={this.onDontAskAgainClick}>
{ _t("Don't ask again") }
</AccessibleButton>
<AccessibleButton className="mx_RoomRecoveryReminder_button"
onClick={this.onSetupClick}>
{ _t("Set up") }
</AccessibleButton>
</div>
</div>
);
}
}

View file

@ -154,7 +154,6 @@ export default class KeyBackupPanel extends React.Component {
}
let backupSigStatuses = this.state.backupSigStatus.sigs.map((sig, i) => {
const deviceName = sig.device.getDisplayName() || sig.device.deviceId;
const sigStatusSubstitutions = {
validity: sub =>
<span className={sig.valid ? 'mx_KeyBackupPanel_sigValid' : 'mx_KeyBackupPanel_sigInvalid'}>
@ -164,7 +163,7 @@ export default class KeyBackupPanel extends React.Component {
<span className={sig.device.isVerified() ? 'mx_KeyBackupPanel_deviceVerified' : 'mx_KeyBackupPanel_deviceNotVerified'}>
{sub}
</span>,
device: sub => <span className="mx_KeyBackupPanel_deviceName">{deviceName}</span>,
device: sub => <span className="mx_KeyBackupPanel_deviceName">{sig.device.getDisplayName()}</span>,
};
let sigStatus;
if (sig.device.getFingerprint() === MatrixClientPeg.get().getDeviceEd25519Key()) {
@ -175,7 +174,7 @@ export default class KeyBackupPanel extends React.Component {
} else if (sig.valid && sig.device.isVerified()) {
sigStatus = _t(
"Backup has a <validity>valid</validity> signature from " +
"<verify>verified</verify> device <device></device>",
"<verify>verified</verify> device <device>x</device>",
{}, sigStatusSubstitutions,
);
} else if (sig.valid && !sig.device.isVerified()) {

View file

@ -483,11 +483,8 @@ module.exports = React.createClass({
// The default push rules displayed by Vector UI
'.m.rule.contains_display_name': 'vector',
'.m.rule.contains_user_name': 'vector',
'.m.rule.roomnotif': 'vector',
'.m.rule.room_one_to_one': 'vector',
'.m.rule.encrypted_room_one_to_one': 'vector',
'.m.rule.message': 'vector',
'.m.rule.encrypted': 'vector',
'.m.rule.invite_for_me': 'vector',
//'.m.rule.member_event': 'vector',
'.m.rule.call': 'vector',
@ -537,12 +534,9 @@ module.exports = React.createClass({
const vectorRuleIds = [
'.m.rule.contains_display_name',
'.m.rule.contains_user_name',
'.m.rule.roomnotif',
'_keywords',
'.m.rule.room_one_to_one',
'.m.rule.encrypted_room_one_to_one',
'.m.rule.message',
'.m.rule.encrypted',
'.m.rule.invite_for_me',
//'im.vector.rule.member_event',
'.m.rule.call',