mirror of
https://github.com/element-hq/element-web
synced 2024-11-28 12:28:50 +03:00
Merge branch 'develop' into travis/react-warnings/3-componentCannotDidMount
This commit is contained in:
commit
07030a9466
102 changed files with 640 additions and 294 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -1,3 +1,14 @@
|
||||||
|
Changes in [2.3.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v2.3.1) (2020-04-01)
|
||||||
|
===================================================================================================
|
||||||
|
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.3.0...v2.3.1)
|
||||||
|
|
||||||
|
* Fix jitsi popout URL
|
||||||
|
[\#4327](https://github.com/matrix-org/matrix-react-sdk/pull/4327)
|
||||||
|
* Remove underscore from Jitsi conference names
|
||||||
|
[\#4324](https://github.com/matrix-org/matrix-react-sdk/pull/4324)
|
||||||
|
* Fix popout support for jitsi widgets
|
||||||
|
[\#4322](https://github.com/matrix-org/matrix-react-sdk/pull/4322)
|
||||||
|
|
||||||
Changes in [2.3.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v2.3.0) (2020-03-30)
|
Changes in [2.3.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v2.3.0) (2020-03-30)
|
||||||
===================================================================================================
|
===================================================================================================
|
||||||
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.3.0-rc.1...v2.3.0)
|
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.3.0-rc.1...v2.3.0)
|
||||||
|
|
|
@ -51,6 +51,17 @@ Settings are the different options a user may set or experience in the applicati
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Settings that support the config level can be set in the config file under the `settingDefaults` key (note that some settings, like the "theme" setting, are special cased in the config file):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
...
|
||||||
|
"settingDefaults": {
|
||||||
|
"settingName": true
|
||||||
|
},
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Getting values for a setting
|
### Getting values for a setting
|
||||||
|
|
||||||
After importing `SettingsStore`, simply make a call to `SettingsStore.getValue`. The `roomId` parameter should always
|
After importing `SettingsStore`, simply make a call to `SettingsStore.getValue`. The `roomId` parameter should always
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "matrix-react-sdk",
|
"name": "matrix-react-sdk",
|
||||||
"version": "2.3.0",
|
"version": "2.3.1",
|
||||||
"description": "SDK for matrix.org using React",
|
"description": "SDK for matrix.org using React",
|
||||||
"author": "matrix.org",
|
"author": "matrix.org",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -60,3 +60,14 @@ limitations under the License.
|
||||||
.mx_InteractiveAuthEntryComponents_passwordSection {
|
.mx_InteractiveAuthEntryComponents_passwordSection {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_InteractiveAuthEntryComponents_sso_buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
.mx_AccessibleButton {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -36,12 +36,20 @@ limitations under the License.
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_AccessibleButton_kind_primary_outline {
|
||||||
|
color: $button-primary-bg-color;
|
||||||
|
background-color: $button-secondary-bg-color;
|
||||||
|
border: 1px solid $button-primary-bg-color;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_AccessibleButton_kind_secondary {
|
.mx_AccessibleButton_kind_secondary {
|
||||||
color: $accent-color;
|
color: $accent-color;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_AccessibleButton_kind_primary.mx_AccessibleButton_disabled {
|
.mx_AccessibleButton_kind_primary.mx_AccessibleButton_disabled,
|
||||||
|
.mx_AccessibleButton_kind_primary_outline.mx_AccessibleButton_disabled {
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +68,14 @@ limitations under the License.
|
||||||
background-color: $button-danger-bg-color;
|
background-color: $button-danger-bg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_AccessibleButton_kind_danger.mx_AccessibleButton_disabled {
|
.mx_AccessibleButton_kind_danger_outline {
|
||||||
|
color: $button-danger-bg-color;
|
||||||
|
background-color: $button-secondary-bg-color;
|
||||||
|
border: 1px solid $button-danger-bg-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_AccessibleButton_kind_danger.mx_AccessibleButton_disabled,
|
||||||
|
.mx_AccessibleButton_kind_danger_outline.mx_AccessibleButton_disabled {
|
||||||
color: $button-danger-disabled-fg-color;
|
color: $button-danger-disabled-fg-color;
|
||||||
background-color: $button-danger-disabled-bg-color;
|
background-color: $button-danger-disabled-bg-color;
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,12 +266,31 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_AccessibleButton {
|
||||||
|
padding: 8px 18px;
|
||||||
|
|
||||||
|
&.mx_AccessibleButton_kind_primary {
|
||||||
|
color: $accent-color;
|
||||||
|
background-color: $accent-bg-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_AccessibleButton_kind_danger {
|
||||||
|
color: $notice-primary-color;
|
||||||
|
background-color: $notice-primary-bg-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_VerificationShowSas .mx_AccessibleButton,
|
||||||
.mx_UserInfo_wideButton {
|
.mx_UserInfo_wideButton {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 16px 0;
|
margin: 16px 0 8px;
|
||||||
}
|
}
|
||||||
button.mx_UserInfo_wideButton {
|
|
||||||
width: 100%; // FIXME get rid of this once we get rid of DialogButtons here
|
|
||||||
|
.mx_VerificationShowSas {
|
||||||
|
.mx_AccessibleButton + .mx_AccessibleButton {
|
||||||
|
margin: 8px 0; // space between buttons
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import * as sdk from './index';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
import IdentityAuthClient from './IdentityAuthClient';
|
import IdentityAuthClient from './IdentityAuthClient';
|
||||||
|
import {SSOAuthEntry} from "./components/views/auth/InteractiveAuthEntryComponents";
|
||||||
|
|
||||||
function getIdServerDomain() {
|
function getIdServerDomain() {
|
||||||
return MatrixClientPeg.get().idBaseUrl.split("://")[1];
|
return MatrixClientPeg.get().idBaseUrl.split("://")[1];
|
||||||
|
@ -188,11 +189,31 @@ export default class AddThreepid {
|
||||||
// pop up an interactive auth dialog
|
// pop up an interactive auth dialog
|
||||||
const InteractiveAuthDialog = sdk.getComponent("dialogs.InteractiveAuthDialog");
|
const InteractiveAuthDialog = sdk.getComponent("dialogs.InteractiveAuthDialog");
|
||||||
|
|
||||||
|
|
||||||
|
const dialogAesthetics = {
|
||||||
|
[SSOAuthEntry.PHASE_PREAUTH]: {
|
||||||
|
title: _t("Use Single Sign On to continue"),
|
||||||
|
body: _t("Confirm adding this email address by using " +
|
||||||
|
"Single Sign On to prove your identity."),
|
||||||
|
continueText: _t("Single Sign On"),
|
||||||
|
continueKind: "primary",
|
||||||
|
},
|
||||||
|
[SSOAuthEntry.PHASE_POSTAUTH]: {
|
||||||
|
title: _t("Confirm adding email"),
|
||||||
|
body: _t("Click the button below to confirm adding this email address."),
|
||||||
|
continueText: _t("Confirm"),
|
||||||
|
continueKind: "primary",
|
||||||
|
},
|
||||||
|
};
|
||||||
const { finished } = Modal.createTrackedDialog('Add Email', '', InteractiveAuthDialog, {
|
const { finished } = Modal.createTrackedDialog('Add Email', '', InteractiveAuthDialog, {
|
||||||
title: _t("Add Email Address"),
|
title: _t("Add Email Address"),
|
||||||
matrixClient: MatrixClientPeg.get(),
|
matrixClient: MatrixClientPeg.get(),
|
||||||
authData: e.data,
|
authData: e.data,
|
||||||
makeRequest: this._makeAddThreepidOnlyRequest,
|
makeRequest: this._makeAddThreepidOnlyRequest,
|
||||||
|
aestheticsForStagePhases: {
|
||||||
|
[SSOAuthEntry.LOGIN_TYPE]: dialogAesthetics,
|
||||||
|
[SSOAuthEntry.UNSTABLE_LOGIN_TYPE]: dialogAesthetics,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
return finished;
|
return finished;
|
||||||
}
|
}
|
||||||
|
@ -285,11 +306,30 @@ export default class AddThreepid {
|
||||||
// pop up an interactive auth dialog
|
// pop up an interactive auth dialog
|
||||||
const InteractiveAuthDialog = sdk.getComponent("dialogs.InteractiveAuthDialog");
|
const InteractiveAuthDialog = sdk.getComponent("dialogs.InteractiveAuthDialog");
|
||||||
|
|
||||||
|
const dialogAesthetics = {
|
||||||
|
[SSOAuthEntry.PHASE_PREAUTH]: {
|
||||||
|
title: _t("Use Single Sign On to continue"),
|
||||||
|
body: _t("Confirm adding this phone number by using " +
|
||||||
|
"Single Sign On to prove your identity."),
|
||||||
|
continueText: _t("Single Sign On"),
|
||||||
|
continueKind: "primary",
|
||||||
|
},
|
||||||
|
[SSOAuthEntry.PHASE_POSTAUTH]: {
|
||||||
|
title: _t("Confirm adding phone number"),
|
||||||
|
body: _t("Click the button below to confirm adding this phone number."),
|
||||||
|
continueText: _t("Confirm"),
|
||||||
|
continueKind: "primary",
|
||||||
|
},
|
||||||
|
};
|
||||||
const { finished } = Modal.createTrackedDialog('Add MSISDN', '', InteractiveAuthDialog, {
|
const { finished } = Modal.createTrackedDialog('Add MSISDN', '', InteractiveAuthDialog, {
|
||||||
title: _t("Add Phone Number"),
|
title: _t("Add Phone Number"),
|
||||||
matrixClient: MatrixClientPeg.get(),
|
matrixClient: MatrixClientPeg.get(),
|
||||||
authData: e.data,
|
authData: e.data,
|
||||||
makeRequest: this._makeAddThreepidOnlyRequest,
|
makeRequest: this._makeAddThreepidOnlyRequest,
|
||||||
|
aestheticsForStagePhases: {
|
||||||
|
[SSOAuthEntry.LOGIN_TYPE]: dialogAesthetics,
|
||||||
|
[SSOAuthEntry.UNSTABLE_LOGIN_TYPE]: dialogAesthetics,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
return finished;
|
return finished;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this._unmounted = false;
|
this._unmounted = false;
|
||||||
// XXX: temporary logging to try to diagnose
|
// XXX: temporary logging to try to diagnose
|
||||||
// https://github.com/vector-im/riot-web/issues/3148
|
// https://github.com/vector-im/riot-web/issues/3148
|
||||||
|
|
|
@ -24,8 +24,7 @@ import {MatrixClientPeg} from "./MatrixClientPeg";
|
||||||
import RoomViewStore from "./stores/RoomViewStore";
|
import RoomViewStore from "./stores/RoomViewStore";
|
||||||
import {IntegrationManagers} from "./integrations/IntegrationManagers";
|
import {IntegrationManagers} from "./integrations/IntegrationManagers";
|
||||||
import SettingsStore from "./settings/SettingsStore";
|
import SettingsStore from "./settings/SettingsStore";
|
||||||
import {Capability, KnownWidgetActions} from "./widgets/WidgetApi";
|
import {Capability} from "./widgets/WidgetApi";
|
||||||
import SdkConfig from "./SdkConfig";
|
|
||||||
|
|
||||||
const WIDGET_API_VERSION = '0.0.2'; // Current API version
|
const WIDGET_API_VERSION = '0.0.2'; // Current API version
|
||||||
const SUPPORTED_WIDGET_API_VERSIONS = [
|
const SUPPORTED_WIDGET_API_VERSIONS = [
|
||||||
|
@ -220,13 +219,6 @@ export default class FromWidgetPostMessageApi {
|
||||||
}
|
}
|
||||||
} else if (action === 'get_openid') {
|
} else if (action === 'get_openid') {
|
||||||
// Handled by caller
|
// Handled by caller
|
||||||
} else if (action === KnownWidgetActions.GetRiotWebConfig) {
|
|
||||||
if (ActiveWidgetStore.widgetHasCapability(widgetId, Capability.GetRiotWebConfig)) {
|
|
||||||
this.sendResponse(event, {
|
|
||||||
api: INBOUND_API_NAME,
|
|
||||||
config: SdkConfig.get(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
console.warn('Widget postMessage event unhandled');
|
console.warn('Widget postMessage event unhandled');
|
||||||
this.sendError(event, {message: 'The postMessage was unhandled'});
|
this.sendError(event, {message: 'The postMessage was unhandled'});
|
||||||
|
|
|
@ -30,8 +30,6 @@ export const DEFAULTS: ConfigOptions = {
|
||||||
jitsi: {
|
jitsi: {
|
||||||
// Default conference domain
|
// Default conference domain
|
||||||
preferredDomain: "jitsi.riot.im",
|
preferredDomain: "jitsi.riot.im",
|
||||||
// Default Jitsi Meet API location
|
|
||||||
externalApiUrl: "https://jitsi.riot.im/libs/external_api.min.js",
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -412,17 +412,20 @@ export const Commands = [
|
||||||
button: _t("Continue"),
|
button: _t("Continue"),
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
|
finished = finished.then(([useDefault]: any) => {
|
||||||
|
if (useDefault) {
|
||||||
|
useDefaultIdentityServer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new Error(_t("Use an identity server to invite by email. Manage in Settings."));
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
return reject(_t("Use an identity server to invite by email. Manage in Settings."));
|
return reject(_t("Use an identity server to invite by email. Manage in Settings."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const inviter = new MultiInviter(roomId);
|
const inviter = new MultiInviter(roomId);
|
||||||
return success(finished.then(([useDefault]: any) => {
|
return success(finished.then(() => {
|
||||||
if (useDefault) {
|
|
||||||
useDefaultIdentityServer();
|
|
||||||
} else if (useDefault === false) {
|
|
||||||
throw new Error(_t("Use an identity server to invite by email. Manage in Settings."));
|
|
||||||
}
|
|
||||||
return inviter.invite([address]);
|
return inviter.invite([address]);
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
if (inviter.getCompletionState(address) !== "invited") {
|
if (inviter.getCompletionState(address) !== "invited") {
|
||||||
|
|
|
@ -37,7 +37,7 @@ export default createReactClass({
|
||||||
return { device: null };
|
return { device: null };
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this._unmounted = false;
|
this._unmounted = false;
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ export default createReactClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
onDeviceVerificationChanged: function(userId, device) {
|
onDeviceVerificationChanged: function(userId, device) {
|
||||||
if (userId == this.props.event.getSender()) {
|
if (userId === this.props.event.getSender()) {
|
||||||
this.refreshDevice().then((dev) => {
|
this.refreshDevice().then((dev) => {
|
||||||
this.setState({ device: dev });
|
this.setState({ device: dev });
|
||||||
});
|
});
|
||||||
|
|
|
@ -30,7 +30,7 @@ import EventIndexPeg from "../../../../indexing/EventIndexPeg";
|
||||||
export default class ManageEventIndexDialog extends React.Component {
|
export default class ManageEventIndexDialog extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
onFinished: PropTypes.func.isRequired,
|
onFinished: PropTypes.func.isRequired,
|
||||||
}
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -82,7 +82,7 @@ export default class ManageEventIndexDialog extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentWillMount(): void {
|
async componentDidMount(): void {
|
||||||
let eventIndexSize = 0;
|
let eventIndexSize = 0;
|
||||||
let crawlingRoomsCount = 0;
|
let crawlingRoomsCount = 0;
|
||||||
let roomCount = 0;
|
let roomCount = 0;
|
||||||
|
@ -126,16 +126,12 @@ export default class ManageEventIndexDialog extends React.Component {
|
||||||
import("./DisableEventIndexDialog"),
|
import("./DisableEventIndexDialog"),
|
||||||
null, null, /* priority = */ false, /* static = */ true,
|
null, null, /* priority = */ false, /* static = */ true,
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
_onDone = () => {
|
|
||||||
this.props.onFinished(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
_onCrawlerSleepTimeChange = (e) => {
|
_onCrawlerSleepTimeChange = (e) => {
|
||||||
this.setState({crawlerSleepTime: e.target.value});
|
this.setState({crawlerSleepTime: e.target.value});
|
||||||
SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value);
|
SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value);
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let crawlerState;
|
let crawlerState;
|
||||||
|
|
|
@ -30,7 +30,7 @@ class CustomRoomTagPanel extends React.Component {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
this._tagStoreToken = CustomRoomTagStore.addListener(() => {
|
this._tagStoreToken = CustomRoomTagStore.addListener(() => {
|
||||||
this.setState({tags: CustomRoomTagStore.getSortedTags()});
|
this.setState({tags: CustomRoomTagStore.getSortedTags()});
|
||||||
});
|
});
|
||||||
|
|
|
@ -58,7 +58,7 @@ export default class EmbeddedPage extends React.PureComponent {
|
||||||
return sanitizeHtml(_t(s));
|
return sanitizeHtml(_t(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
this._unmounted = false;
|
this._unmounted = false;
|
||||||
|
|
||||||
if (!this.props.url) {
|
if (!this.props.url) {
|
||||||
|
|
|
@ -428,12 +428,11 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this._unmounted = false;
|
this._unmounted = false;
|
||||||
this._matrixClient = MatrixClientPeg.get();
|
this._matrixClient = MatrixClientPeg.get();
|
||||||
this._matrixClient.on("Group.myMembership", this._onGroupMyMembership);
|
this._matrixClient.on("Group.myMembership", this._onGroupMyMembership);
|
||||||
|
|
||||||
this._changeAvatarComponent = null;
|
|
||||||
this._initGroupStore(this.props.groupId, true);
|
this._initGroupStore(this.props.groupId, true);
|
||||||
|
|
||||||
this._dispatcherRef = dis.register(this._onAction);
|
this._dispatcherRef = dis.register(this._onAction);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2017 Vector Creations Ltd.
|
Copyright 2017 Vector Creations Ltd.
|
||||||
Copyright 2019 The Matrix.org Foundation C.I.C.
|
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -24,6 +24,8 @@ import getEntryComponentForLoginType from '../views/auth/InteractiveAuthEntryCom
|
||||||
|
|
||||||
import * as sdk from '../../index';
|
import * as sdk from '../../index';
|
||||||
|
|
||||||
|
export const ERROR_USER_CANCELLED = new Error("User cancelled auth session");
|
||||||
|
|
||||||
export default createReactClass({
|
export default createReactClass({
|
||||||
displayName: 'InteractiveAuth',
|
displayName: 'InteractiveAuth',
|
||||||
|
|
||||||
|
@ -47,7 +49,7 @@ export default createReactClass({
|
||||||
// @param {bool} status True if the operation requiring
|
// @param {bool} status True if the operation requiring
|
||||||
// auth was completed sucessfully, false if canceled.
|
// auth was completed sucessfully, false if canceled.
|
||||||
// @param {object} result The result of the authenticated call
|
// @param {object} result The result of the authenticated call
|
||||||
// if successful, otherwise the error object
|
// if successful, otherwise the error object.
|
||||||
// @param {object} extra Additional information about the UI Auth
|
// @param {object} extra Additional information about the UI Auth
|
||||||
// process:
|
// process:
|
||||||
// * emailSid {string} If email auth was performed, the sid of
|
// * emailSid {string} If email auth was performed, the sid of
|
||||||
|
@ -75,6 +77,15 @@ export default createReactClass({
|
||||||
// is managed by some other party and should not be managed by
|
// is managed by some other party and should not be managed by
|
||||||
// the component itself.
|
// the component itself.
|
||||||
continueIsManaged: PropTypes.bool,
|
continueIsManaged: PropTypes.bool,
|
||||||
|
|
||||||
|
// Called when the stage changes, or the stage's phase changes. First
|
||||||
|
// argument is the stage, second is the phase. Some stages do not have
|
||||||
|
// phases and will be counted as 0 (numeric).
|
||||||
|
onStagePhaseChange: PropTypes.func,
|
||||||
|
|
||||||
|
// continueText and continueKind are passed straight through to the AuthEntryComponent.
|
||||||
|
continueText: PropTypes.string,
|
||||||
|
continueKind: PropTypes.string,
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
|
@ -205,6 +216,16 @@ export default createReactClass({
|
||||||
this._authLogic.submitAuthDict(authData);
|
this._authLogic.submitAuthDict(authData);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onPhaseChange: function(newPhase) {
|
||||||
|
if (this.props.onStagePhaseChange) {
|
||||||
|
this.props.onStagePhaseChange(this.state.authStage, newPhase || 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_onStageCancel: function() {
|
||||||
|
this.props.onAuthFinished(false, ERROR_USER_CANCELLED);
|
||||||
|
},
|
||||||
|
|
||||||
_renderCurrentStage: function() {
|
_renderCurrentStage: function() {
|
||||||
const stage = this.state.authStage;
|
const stage = this.state.authStage;
|
||||||
if (!stage) {
|
if (!stage) {
|
||||||
|
@ -233,6 +254,10 @@ export default createReactClass({
|
||||||
fail={this._onAuthStageFailed}
|
fail={this._onAuthStageFailed}
|
||||||
setEmailSid={this._setEmailSid}
|
setEmailSid={this._setEmailSid}
|
||||||
showContinue={!this.props.continueIsManaged}
|
showContinue={!this.props.continueIsManaged}
|
||||||
|
onPhaseChange={this._onPhaseChange}
|
||||||
|
continueText={this.props.continueText}
|
||||||
|
continueKind={this.props.continueKind}
|
||||||
|
onCancel={this._onStageCancel}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -44,7 +44,7 @@ const LeftPanel = createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this.focusedElement = null;
|
this.focusedElement = null;
|
||||||
|
|
||||||
this._breadcrumbsWatcherRef = SettingsStore.watchSetting(
|
this._breadcrumbsWatcherRef = SettingsStore.watchSetting(
|
||||||
|
|
|
@ -22,7 +22,7 @@ import createReactClass from 'create-react-class';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { DragDropContext } from 'react-beautiful-dnd';
|
import { DragDropContext } from 'react-beautiful-dnd';
|
||||||
|
|
||||||
import { Key, isOnlyCtrlOrCmdKeyEvent } from '../../Keyboard';
|
import {Key, isOnlyCtrlOrCmdKeyEvent, isOnlyCtrlOrCmdIgnoreShiftKeyEvent} from '../../Keyboard';
|
||||||
import PageTypes from '../../PageTypes';
|
import PageTypes from '../../PageTypes';
|
||||||
import CallMediaHandler from '../../CallMediaHandler';
|
import CallMediaHandler from '../../CallMediaHandler';
|
||||||
import { fixupColorFonts } from '../../utils/FontManager';
|
import { fixupColorFonts } from '../../utils/FontManager';
|
||||||
|
@ -381,7 +381,7 @@ const LoggedInView = createReactClass({
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Key.SLASH:
|
case Key.SLASH:
|
||||||
if (ctrlCmdOnly) {
|
if (isOnlyCtrlOrCmdIgnoreShiftKeyEvent(ev)) {
|
||||||
KeyboardShortcuts.toggleDialog();
|
KeyboardShortcuts.toggleDialog();
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,7 +221,8 @@ export default createReactClass({
|
||||||
return {serverConfig: props};
|
return {serverConfig: props};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
// TODO: [REACT-WARNING] Move this to constructor
|
||||||
|
UNSAFE_componentWillMount: function() {
|
||||||
SdkConfig.put(this.props.config);
|
SdkConfig.put(this.props.config);
|
||||||
|
|
||||||
// Used by _viewRoom before getting state from sync
|
// Used by _viewRoom before getting state from sync
|
||||||
|
@ -261,9 +262,7 @@ export default createReactClass({
|
||||||
|
|
||||||
this._accountPassword = null;
|
this._accountPassword = null;
|
||||||
this._accountPasswordTimer = null;
|
this._accountPasswordTimer = null;
|
||||||
},
|
|
||||||
|
|
||||||
componentDidMount: function() {
|
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
this._themeWatcher = new ThemeWatcher();
|
this._themeWatcher = new ThemeWatcher();
|
||||||
this._themeWatcher.start();
|
this._themeWatcher.start();
|
||||||
|
|
|
@ -38,7 +38,7 @@ export default createReactClass({
|
||||||
contextType: MatrixClientContext,
|
contextType: MatrixClientContext,
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this._fetch();
|
this._fetch();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ export default class RightPanel extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
const cli = this.context;
|
const cli = this.context;
|
||||||
cli.on("RoomState.members", this.onRoomStateMember);
|
cli.on("RoomState.members", this.onRoomStateMember);
|
||||||
|
|
|
@ -56,7 +56,8 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
// TODO: [REACT-WARNING] Move this to constructor
|
||||||
|
UNSAFE_componentWillMount: function() {
|
||||||
this._unmounted = false;
|
this._unmounted = false;
|
||||||
this.nextBatch = null;
|
this.nextBatch = null;
|
||||||
this.filterTimeout = null;
|
this.filterTimeout = null;
|
||||||
|
@ -89,9 +90,7 @@ export default createReactClass({
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
|
||||||
|
|
||||||
componentDidMount: function() {
|
|
||||||
this.refreshRoomList();
|
this.refreshRoomList();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
MatrixClientPeg.get().on("sync", this.onSyncStateChange);
|
MatrixClientPeg.get().on("sync", this.onSyncStateChange);
|
||||||
MatrixClientPeg.get().on("Room.localEchoUpdated", this._onRoomLocalEchoUpdated);
|
MatrixClientPeg.get().on("Room.localEchoUpdated", this._onRoomLocalEchoUpdated);
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ export default class RoomSubList extends React.PureComponent {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'view_room':
|
case 'view_room':
|
||||||
if (this.state.hidden && !this.props.forceExpand &&
|
if (this.state.hidden && !this.props.forceExpand && payload.show_room_tile &&
|
||||||
this.props.list.some((r) => r.roomId === payload.room_id)
|
this.props.list.some((r) => r.roomId === payload.room_id)
|
||||||
) {
|
) {
|
||||||
this.toggle();
|
this.toggle();
|
||||||
|
@ -193,6 +193,7 @@ export default class RoomSubList extends React.PureComponent {
|
||||||
onRoomTileClick = (roomId, ev) => {
|
onRoomTileClick = (roomId, ev) => {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'view_room',
|
action: 'view_room',
|
||||||
|
show_room_tile: true, // to make sure the room gets scrolled into view
|
||||||
room_id: roomId,
|
room_id: roomId,
|
||||||
clear_search: (ev && (ev.key === Key.ENTER || ev.key === Key.SPACE)),
|
clear_search: (ev && (ev.key === Key.ENTER || ev.key === Key.SPACE)),
|
||||||
});
|
});
|
||||||
|
|
|
@ -44,7 +44,7 @@ const TagPanel = createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this.unmounted = false;
|
this.unmounted = false;
|
||||||
this.context.on("Group.myMembership", this._onGroupMyMembership);
|
this.context.on("Group.myMembership", this._onGroupMyMembership);
|
||||||
this.context.on("sync", this._onClientSync);
|
this.context.on("sync", this._onClientSync);
|
||||||
|
|
|
@ -35,7 +35,7 @@ export default class UserView extends React.Component {
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
if (this.props.userId) {
|
if (this.props.userId) {
|
||||||
this._loadProfileInfo();
|
this._loadProfileInfo();
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this.reset = null;
|
this.reset = null;
|
||||||
this._checkServerLiveliness(this.props.serverConfig);
|
this._checkServerLiveliness(this.props.serverConfig);
|
||||||
},
|
},
|
||||||
|
|
|
@ -113,7 +113,8 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
// TODO: [REACT-WARNING] Move this to constructor
|
||||||
|
UNSAFE_componentWillMount: function() {
|
||||||
this._unmounted = false;
|
this._unmounted = false;
|
||||||
|
|
||||||
// map from login step type to a function which will render a control
|
// map from login step type to a function which will render a control
|
||||||
|
|
|
@ -37,7 +37,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
// There is some assymetry between ChangeDisplayName and ChangeAvatar,
|
// There is some assymetry between ChangeDisplayName and ChangeAvatar,
|
||||||
// as ChangeDisplayName will auto-get the name but ChangeAvatar expects
|
// as ChangeDisplayName will auto-get the name but ChangeAvatar expects
|
||||||
// the URL to be passed to you (because it's also used for room avatars).
|
// the URL to be passed to you (because it's also used for room avatars).
|
||||||
|
|
|
@ -120,7 +120,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this._unmounted = false;
|
this._unmounted = false;
|
||||||
this._replaceClient();
|
this._replaceClient();
|
||||||
},
|
},
|
||||||
|
|
|
@ -54,7 +54,7 @@ export default class SoftLogout extends React.Component {
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
loginView: LOGIN_VIEW.LOADING,
|
loginView: LOGIN_VIEW.LOADING,
|
||||||
keyBackupNeeded: true, // assume we do while we figure it out (see componentWillMount)
|
keyBackupNeeded: true, // assume we do while we figure it out (see componentDidMount)
|
||||||
|
|
||||||
busy: false,
|
busy: false,
|
||||||
password: "",
|
password: "",
|
||||||
|
|
|
@ -60,7 +60,7 @@ export default class CountryDropdown extends React.Component {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
if (!this.props.value) {
|
if (!this.props.value) {
|
||||||
// If no value is given, we start with the default
|
// If no value is given, we start with the default
|
||||||
// country selected, but our parent component
|
// country selected, but our parent component
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2016 OpenMarket Ltd
|
Copyright 2016 OpenMarket Ltd
|
||||||
Copyright 2017 Vector Creations Ltd
|
Copyright 2017 Vector Creations Ltd
|
||||||
Copyright 2019 The Matrix.org Foundation C.I.C.
|
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -25,6 +25,7 @@ import classnames from 'classnames';
|
||||||
import * as sdk from '../../../index';
|
import * as sdk from '../../../index';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
|
|
||||||
/* This file contains a collection of components which are used by the
|
/* This file contains a collection of components which are used by the
|
||||||
* InteractiveAuth to prompt the user to enter the information needed
|
* InteractiveAuth to prompt the user to enter the information needed
|
||||||
|
@ -59,11 +60,21 @@ import SettingsStore from "../../../settings/SettingsStore";
|
||||||
* session to be failed and the process to go back to the start.
|
* session to be failed and the process to go back to the start.
|
||||||
* setEmailSid: m.login.email.identity only: a function to be called with the
|
* setEmailSid: m.login.email.identity only: a function to be called with the
|
||||||
* email sid after a token is requested.
|
* email sid after a token is requested.
|
||||||
|
* onPhaseChange: A function which is called when the stage's phase changes. If
|
||||||
|
* the stage has no phases, call this with DEFAULT_PHASE. Takes
|
||||||
|
* one argument, the phase, and is always defined/required.
|
||||||
|
* continueText: For stages which have a continue button, the text to use.
|
||||||
|
* continueKind: For stages which have a continue button, the style of button to
|
||||||
|
* use. For example, 'danger' or 'primary'.
|
||||||
|
* onCancel A function with no arguments which is called by the stage if the
|
||||||
|
* user knowingly cancelled/dismissed the authentication attempt.
|
||||||
*
|
*
|
||||||
* Each component may also provide the following functions (beyond the standard React ones):
|
* Each component may also provide the following functions (beyond the standard React ones):
|
||||||
* focus: set the input focus appropriately in the form.
|
* focus: set the input focus appropriately in the form.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export const DEFAULT_PHASE = 0;
|
||||||
|
|
||||||
export const PasswordAuthEntry = createReactClass({
|
export const PasswordAuthEntry = createReactClass({
|
||||||
displayName: 'PasswordAuthEntry',
|
displayName: 'PasswordAuthEntry',
|
||||||
|
|
||||||
|
@ -78,6 +89,11 @@ export const PasswordAuthEntry = createReactClass({
|
||||||
// is the auth logic currently waiting for something to
|
// is the auth logic currently waiting for something to
|
||||||
// happen?
|
// happen?
|
||||||
busy: PropTypes.bool,
|
busy: PropTypes.bool,
|
||||||
|
onPhaseChange: PropTypes.func.isRequired,
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
this.props.onPhaseChange(DEFAULT_PHASE);
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
|
@ -175,6 +191,11 @@ export const RecaptchaAuthEntry = createReactClass({
|
||||||
stageParams: PropTypes.object.isRequired,
|
stageParams: PropTypes.object.isRequired,
|
||||||
errorText: PropTypes.string,
|
errorText: PropTypes.string,
|
||||||
busy: PropTypes.bool,
|
busy: PropTypes.bool,
|
||||||
|
onPhaseChange: PropTypes.func.isRequired,
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
this.props.onPhaseChange(DEFAULT_PHASE);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onCaptchaResponse: function(response) {
|
_onCaptchaResponse: function(response) {
|
||||||
|
@ -236,6 +257,11 @@ export const TermsAuthEntry = createReactClass({
|
||||||
errorText: PropTypes.string,
|
errorText: PropTypes.string,
|
||||||
busy: PropTypes.bool,
|
busy: PropTypes.bool,
|
||||||
showContinue: PropTypes.bool,
|
showContinue: PropTypes.bool,
|
||||||
|
onPhaseChange: PropTypes.func.isRequired,
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
this.props.onPhaseChange(DEFAULT_PHASE);
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO: [REACT-WARNING] Move this to constructor
|
// TODO: [REACT-WARNING] Move this to constructor
|
||||||
|
@ -379,6 +405,11 @@ export const EmailIdentityAuthEntry = createReactClass({
|
||||||
stageState: PropTypes.object.isRequired,
|
stageState: PropTypes.object.isRequired,
|
||||||
fail: PropTypes.func.isRequired,
|
fail: PropTypes.func.isRequired,
|
||||||
setEmailSid: PropTypes.func.isRequired,
|
setEmailSid: PropTypes.func.isRequired,
|
||||||
|
onPhaseChange: PropTypes.func.isRequired,
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
this.props.onPhaseChange(DEFAULT_PHASE);
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
|
@ -421,6 +452,11 @@ export const MsisdnAuthEntry = createReactClass({
|
||||||
clientSecret: PropTypes.func,
|
clientSecret: PropTypes.func,
|
||||||
submitAuthDict: PropTypes.func.isRequired,
|
submitAuthDict: PropTypes.func.isRequired,
|
||||||
matrixClient: PropTypes.object,
|
matrixClient: PropTypes.object,
|
||||||
|
onPhaseChange: PropTypes.func.isRequired,
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
this.props.onPhaseChange(DEFAULT_PHASE);
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
|
@ -430,7 +466,7 @@ export const MsisdnAuthEntry = createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this._submitUrl = null;
|
this._submitUrl = null;
|
||||||
this._sid = null;
|
this._sid = null;
|
||||||
this._msisdn = null;
|
this._msisdn = null;
|
||||||
|
@ -565,6 +601,91 @@ export const MsisdnAuthEntry = createReactClass({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export class SSOAuthEntry extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
matrixClient: PropTypes.object.isRequired,
|
||||||
|
authSessionId: PropTypes.string.isRequired,
|
||||||
|
loginType: PropTypes.string.isRequired,
|
||||||
|
submitAuthDict: PropTypes.func.isRequired,
|
||||||
|
errorText: PropTypes.string,
|
||||||
|
onPhaseChange: PropTypes.func.isRequired,
|
||||||
|
continueText: PropTypes.string,
|
||||||
|
continueKind: PropTypes.string,
|
||||||
|
onCancel: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
static LOGIN_TYPE = "m.login.sso";
|
||||||
|
static UNSTABLE_LOGIN_TYPE = "org.matrix.login.sso";
|
||||||
|
|
||||||
|
static PHASE_PREAUTH = 1; // button to start SSO
|
||||||
|
static PHASE_POSTAUTH = 2; // button to confirm SSO completed
|
||||||
|
|
||||||
|
_ssoUrl: string;
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
// We actually send the user through fallback auth so we don't have to
|
||||||
|
// deal with a redirect back to us, losing application context.
|
||||||
|
this._ssoUrl = props.matrixClient.getFallbackAuthUrl(
|
||||||
|
this.props.loginType,
|
||||||
|
this.props.authSessionId,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
phase: SSOAuthEntry.PHASE_PREAUTH,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount(): void {
|
||||||
|
this.props.onPhaseChange(SSOAuthEntry.PHASE_PREAUTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
onStartAuthClick = () => {
|
||||||
|
// Note: We don't use PlatformPeg's startSsoAuth functions because we almost
|
||||||
|
// certainly will need to open the thing in a new tab to avoid losing application
|
||||||
|
// context.
|
||||||
|
|
||||||
|
window.open(this._ssoUrl, '_blank');
|
||||||
|
this.setState({phase: SSOAuthEntry.PHASE_POSTAUTH});
|
||||||
|
this.props.onPhaseChange(SSOAuthEntry.PHASE_POSTAUTH);
|
||||||
|
};
|
||||||
|
|
||||||
|
onConfirmClick = () => {
|
||||||
|
this.props.submitAuthDict({});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let continueButton = null;
|
||||||
|
const cancelButton = (
|
||||||
|
<AccessibleButton
|
||||||
|
onClick={this.props.onCancel}
|
||||||
|
kind={this.props.continueKind ? (this.props.continueKind + '_outline') : 'primary_outline'}
|
||||||
|
>{_t("Cancel")}</AccessibleButton>
|
||||||
|
);
|
||||||
|
if (this.state.phase === SSOAuthEntry.PHASE_PREAUTH) {
|
||||||
|
continueButton = (
|
||||||
|
<AccessibleButton
|
||||||
|
onClick={this.onStartAuthClick}
|
||||||
|
kind={this.props.continueKind || 'primary'}
|
||||||
|
>{this.props.continueText || _t("Single Sign On")}</AccessibleButton>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
continueButton = (
|
||||||
|
<AccessibleButton
|
||||||
|
onClick={this.onConfirmClick}
|
||||||
|
kind={this.props.continueKind || 'primary'}
|
||||||
|
>{this.props.continueText || _t("Confirm")}</AccessibleButton>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div className='mx_InteractiveAuthEntryComponents_sso_buttons'>
|
||||||
|
{cancelButton}
|
||||||
|
{continueButton}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const FallbackAuthEntry = createReactClass({
|
export const FallbackAuthEntry = createReactClass({
|
||||||
displayName: 'FallbackAuthEntry',
|
displayName: 'FallbackAuthEntry',
|
||||||
|
|
||||||
|
@ -574,6 +695,11 @@ export const FallbackAuthEntry = createReactClass({
|
||||||
loginType: PropTypes.string.isRequired,
|
loginType: PropTypes.string.isRequired,
|
||||||
submitAuthDict: PropTypes.func.isRequired,
|
submitAuthDict: PropTypes.func.isRequired,
|
||||||
errorText: PropTypes.string,
|
errorText: PropTypes.string,
|
||||||
|
onPhaseChange: PropTypes.func.isRequired,
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
this.props.onPhaseChange(DEFAULT_PHASE);
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
|
// TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
|
||||||
|
@ -599,7 +725,10 @@ export const FallbackAuthEntry = createReactClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onShowFallbackClick: function() {
|
_onShowFallbackClick: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
const url = this.props.matrixClient.getFallbackAuthUrl(
|
const url = this.props.matrixClient.getFallbackAuthUrl(
|
||||||
this.props.loginType,
|
this.props.loginType,
|
||||||
this.props.authSessionId,
|
this.props.authSessionId,
|
||||||
|
@ -628,7 +757,7 @@ export const FallbackAuthEntry = createReactClass({
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<a ref={this._fallbackButton} onClick={this._onShowFallbackClick}>{ _t("Start authentication") }</a>
|
<a href="" ref={this._fallbackButton} onClick={this._onShowFallbackClick}>{ _t("Start authentication") }</a>
|
||||||
{errorSection}
|
{errorSection}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -641,11 +770,12 @@ const AuthEntryComponents = [
|
||||||
EmailIdentityAuthEntry,
|
EmailIdentityAuthEntry,
|
||||||
MsisdnAuthEntry,
|
MsisdnAuthEntry,
|
||||||
TermsAuthEntry,
|
TermsAuthEntry,
|
||||||
|
SSOAuthEntry,
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function getEntryComponentForLoginType(loginType) {
|
export default function getEntryComponentForLoginType(loginType) {
|
||||||
for (const c of AuthEntryComponents) {
|
for (const c of AuthEntryComponents) {
|
||||||
if (c.LOGIN_TYPE == loginType) {
|
if (c.LOGIN_TYPE === loginType || c.UNSTABLE_LOGIN_TYPE === loginType) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ export default class MemberStatusMessageAvatar extends React.Component {
|
||||||
this._button = createRef();
|
this._button = createRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
if (this.props.member.userId !== MatrixClientPeg.get().getUserId()) {
|
if (this.props.member.userId !== MatrixClientPeg.get().getUserId()) {
|
||||||
throw new Error("Cannot use MemberStatusMessageAvatar on anyone but the logged in user");
|
throw new Error("Cannot use MemberStatusMessageAvatar on anyone but the logged in user");
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
MatrixClientPeg.get().on('RoomMember.powerLevel', this._checkPermissions);
|
MatrixClientPeg.get().on('RoomMember.powerLevel', this._checkPermissions);
|
||||||
this._checkPermissions();
|
this._checkPermissions();
|
||||||
},
|
},
|
||||||
|
|
|
@ -82,7 +82,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this._unmounted = false;
|
this._unmounted = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ export default class StatusMessageContextMenu extends React.Component {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
const { user } = this.props;
|
const { user } = this.props;
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -55,7 +55,8 @@ export default createReactClass({
|
||||||
askReason: false,
|
askReason: false,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
componentWillMount: function() {
|
// TODO: [REACT-WARNING] Move this to constructor
|
||||||
|
UNSAFE_componentWillMount: function() {
|
||||||
this._reasonField = null;
|
this._reasonField = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -279,6 +279,7 @@ export default class DeviceVerifyDialog extends React.Component {
|
||||||
onDone={this._onSasMatchesClick}
|
onDone={this._onSasMatchesClick}
|
||||||
isSelf={MatrixClientPeg.get().getUserId() === this.props.userId}
|
isSelf={MatrixClientPeg.get().getUserId() === this.props.userId}
|
||||||
onStartEmoji={this._onUseSasClick}
|
onStartEmoji={this._onUseSasClick}
|
||||||
|
inDialog={true}
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,8 @@ export default class IncomingSasDialog extends React.Component {
|
||||||
sas={this._showSasEvent.sas}
|
sas={this._showSasEvent.sas}
|
||||||
onCancel={this._onCancelClick}
|
onCancel={this._onCancelClick}
|
||||||
onDone={this._onSasMatchesClick}
|
onDone={this._onSasMatchesClick}
|
||||||
isSelf={this.props.verifier.userId == MatrixClientPeg.get().getUserId()}
|
isSelf={this.props.verifier.userId === MatrixClientPeg.get().getUserId()}
|
||||||
|
inDialog={true}
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2016 OpenMarket Ltd
|
Copyright 2016 OpenMarket Ltd
|
||||||
Copyright 2017 Vector Creations Ltd
|
Copyright 2017 Vector Creations Ltd
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -23,6 +24,7 @@ import * as sdk from '../../../index';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
|
|
||||||
import AccessibleButton from '../elements/AccessibleButton';
|
import AccessibleButton from '../elements/AccessibleButton';
|
||||||
|
import {ERROR_USER_CANCELLED} from "../../structures/InteractiveAuth";
|
||||||
|
|
||||||
export default createReactClass({
|
export default createReactClass({
|
||||||
displayName: 'InteractiveAuthDialog',
|
displayName: 'InteractiveAuthDialog',
|
||||||
|
@ -44,12 +46,36 @@ export default createReactClass({
|
||||||
|
|
||||||
onFinished: PropTypes.func.isRequired,
|
onFinished: PropTypes.func.isRequired,
|
||||||
|
|
||||||
|
// Optional title and body to show when not showing a particular stage
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
|
body: PropTypes.string,
|
||||||
|
|
||||||
|
// Optional title and body pairs for particular stages and phases within
|
||||||
|
// those stages. Object structure/example is:
|
||||||
|
// {
|
||||||
|
// "org.example.stage_type": {
|
||||||
|
// 1: {
|
||||||
|
// "body": "This is a body for phase 1" of org.example.stage_type,
|
||||||
|
// "title": "Title for phase 1 of org.example.stage_type"
|
||||||
|
// },
|
||||||
|
// 2: {
|
||||||
|
// "body": "This is a body for phase 2 of org.example.stage_type",
|
||||||
|
// "title": "Title for phase 2 of org.example.stage_type"
|
||||||
|
// "continueText": "Confirm identity with Example Auth",
|
||||||
|
// "continueKind": "danger"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
aestheticsForStagePhases: PropTypes.object,
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
authError: null,
|
authError: null,
|
||||||
|
|
||||||
|
// See _onUpdateStagePhase()
|
||||||
|
uiaStage: null,
|
||||||
|
uiaStagePhase: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -57,12 +83,21 @@ export default createReactClass({
|
||||||
if (success) {
|
if (success) {
|
||||||
this.props.onFinished(true, result);
|
this.props.onFinished(true, result);
|
||||||
} else {
|
} else {
|
||||||
this.setState({
|
if (result === ERROR_USER_CANCELLED) {
|
||||||
authError: result,
|
this.props.onFinished(false, null);
|
||||||
});
|
} else {
|
||||||
|
this.setState({
|
||||||
|
authError: result,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onUpdateStagePhase: function(newStage, newPhase) {
|
||||||
|
// We copy the stage and stage phase params into state for title selection in render()
|
||||||
|
this.setState({uiaStage: newStage, uiaStagePhase: newPhase});
|
||||||
|
},
|
||||||
|
|
||||||
_onDismissClick: function() {
|
_onDismissClick: function() {
|
||||||
this.props.onFinished(false);
|
this.props.onFinished(false);
|
||||||
},
|
},
|
||||||
|
@ -71,6 +106,23 @@ export default createReactClass({
|
||||||
const InteractiveAuth = sdk.getComponent("structures.InteractiveAuth");
|
const InteractiveAuth = sdk.getComponent("structures.InteractiveAuth");
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||||
|
|
||||||
|
// Let's pick a title, body, and other params text that we'll show to the user. The order
|
||||||
|
// is most specific first, so stagePhase > our props > defaults.
|
||||||
|
|
||||||
|
let title = this.state.authError ? 'Error' : (this.props.title || _t('Authentication'));
|
||||||
|
let body = this.state.authError ? null : this.props.body;
|
||||||
|
let continueText = null;
|
||||||
|
let continueKind = null;
|
||||||
|
if (!this.state.authError && this.props.aestheticsForStagePhases) {
|
||||||
|
if (this.props.aestheticsForStagePhases[this.state.uiaStage]) {
|
||||||
|
const aesthetics = this.props.aestheticsForStagePhases[this.state.uiaStage][this.state.uiaStagePhase];
|
||||||
|
if (aesthetics && aesthetics.title) title = aesthetics.title;
|
||||||
|
if (aesthetics && aesthetics.body) body = aesthetics.body;
|
||||||
|
if (aesthetics && aesthetics.continueText) continueText = aesthetics.continueText;
|
||||||
|
if (aesthetics && aesthetics.continueKind) continueKind = aesthetics.continueKind;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let content;
|
let content;
|
||||||
if (this.state.authError) {
|
if (this.state.authError) {
|
||||||
content = (
|
content = (
|
||||||
|
@ -88,11 +140,16 @@ export default createReactClass({
|
||||||
} else {
|
} else {
|
||||||
content = (
|
content = (
|
||||||
<div id='mx_Dialog_content'>
|
<div id='mx_Dialog_content'>
|
||||||
<InteractiveAuth ref={this._collectInteractiveAuth}
|
{body}
|
||||||
|
<InteractiveAuth
|
||||||
|
ref={this._collectInteractiveAuth}
|
||||||
matrixClient={this.props.matrixClient}
|
matrixClient={this.props.matrixClient}
|
||||||
authData={this.props.authData}
|
authData={this.props.authData}
|
||||||
makeRequest={this.props.makeRequest}
|
makeRequest={this.props.makeRequest}
|
||||||
onAuthFinished={this._onAuthFinished}
|
onAuthFinished={this._onAuthFinished}
|
||||||
|
onStagePhaseChange={this._onUpdateStagePhase}
|
||||||
|
continueText={continueText}
|
||||||
|
continueKind={continueKind}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -101,7 +158,7 @@ export default createReactClass({
|
||||||
return (
|
return (
|
||||||
<BaseDialog className="mx_InteractiveAuthDialog"
|
<BaseDialog className="mx_InteractiveAuthDialog"
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
title={this.state.authError ? 'Error' : (this.props.title || _t('Authentication'))}
|
title={title}
|
||||||
contentId='mx_Dialog_content'
|
contentId='mx_Dialog_content'
|
||||||
>
|
>
|
||||||
{ content }
|
{ content }
|
||||||
|
|
|
@ -36,12 +36,12 @@ export default class RoomSettingsDialog extends React.Component {
|
||||||
onFinished: PropTypes.func.isRequired,
|
onFinished: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
this._dispatcherRef = dis.register(this._onAction);
|
this._dispatcherRef = dis.register(this._onAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
dis.unregister(this._dispatcherRef);
|
if (this._dispatcherRef) dis.unregister(this._dispatcherRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onAction = (payload) => {
|
_onAction = (payload) => {
|
||||||
|
|
|
@ -30,7 +30,7 @@ export default createReactClass({
|
||||||
onFinished: PropTypes.func.isRequired,
|
onFinished: PropTypes.func.isRequired,
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: async function() {
|
componentDidMount: async function() {
|
||||||
const recommended = await this.props.room.getRecommendedVersion();
|
const recommended = await this.props.room.getRecommendedVersion();
|
||||||
this._targetVersion = recommended.version;
|
this._targetVersion = recommended.version;
|
||||||
this.setState({busy: false});
|
this.setState({busy: false});
|
||||||
|
|
|
@ -75,8 +75,8 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
console.info('SetPasswordDialog component will mount');
|
console.info('SetPasswordDialog component did mount');
|
||||||
},
|
},
|
||||||
|
|
||||||
_onPasswordChanged: function(res) {
|
_onPasswordChanged: function(res) {
|
||||||
|
|
|
@ -121,7 +121,7 @@ export default class ShareDialog extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
if (this.props.target instanceof Room) {
|
if (this.props.target instanceof Room) {
|
||||||
const permalinkCreator = new RoomPermalinkCreator(this.props.target);
|
const permalinkCreator = new RoomPermalinkCreator(this.props.target);
|
||||||
permalinkCreator.load();
|
permalinkCreator.load();
|
||||||
|
|
|
@ -87,7 +87,7 @@ export default createReactClass({
|
||||||
onSend: PropTypes.func.isRequired,
|
onSend: PropTypes.func.isRequired,
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
MatrixClientPeg.get().on("deviceVerificationChanged", this._onDeviceVerificationChanged);
|
MatrixClientPeg.get().on("deviceVerificationChanged", this._onDeviceVerificationChanged);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ export default class VerificationRequestDialog extends React.Component {
|
||||||
verificationRequestPromise={this.props.verificationRequestPromise}
|
verificationRequestPromise={this.props.verificationRequestPromise}
|
||||||
onClose={this.props.onFinished}
|
onClose={this.props.onFinished}
|
||||||
member={member}
|
member={member}
|
||||||
|
inDialog={true}
|
||||||
/>
|
/>
|
||||||
</BaseDialog>;
|
</BaseDialog>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
Copyright 2017 Vector Creations Ltd
|
Copyright 2017 Vector Creations Ltd
|
||||||
Copyright 2018 New Vector Ltd
|
Copyright 2018 New Vector Ltd
|
||||||
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
|
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -41,12 +42,30 @@ import PersistedElement from "./PersistedElement";
|
||||||
const ALLOWED_APP_URL_SCHEMES = ['https:', 'http:'];
|
const ALLOWED_APP_URL_SCHEMES = ['https:', 'http:'];
|
||||||
const ENABLE_REACT_PERF = false;
|
const ENABLE_REACT_PERF = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does template substitution on a URL (or any string). Variables will be
|
||||||
|
* passed through encodeURIComponent.
|
||||||
|
* @param {string} uriTemplate The path with template variables e.g. '/foo/$bar'.
|
||||||
|
* @param {Object} variables The key/value pairs to replace the template
|
||||||
|
* variables with. E.g. { '$bar': 'baz' }.
|
||||||
|
* @return {string} The result of replacing all template variables e.g. '/foo/baz'.
|
||||||
|
*/
|
||||||
|
function uriFromTemplate(uriTemplate, variables) {
|
||||||
|
let out = uriTemplate;
|
||||||
|
for (const [key, val] of Object.entries(variables)) {
|
||||||
|
out = out.replace(
|
||||||
|
'$' + key, encodeURIComponent(val),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
export default class AppTile extends React.Component {
|
export default class AppTile extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
// The key used for PersistedElement
|
// The key used for PersistedElement
|
||||||
this._persistKey = 'widget_' + this.props.id;
|
this._persistKey = 'widget_' + this.props.app.id;
|
||||||
|
|
||||||
this.state = this._getNewState(props);
|
this.state = this._getNewState(props);
|
||||||
|
|
||||||
|
@ -78,7 +97,7 @@ export default class AppTile extends React.Component {
|
||||||
// This is a function to make the impact of calling SettingsStore slightly less
|
// This is a function to make the impact of calling SettingsStore slightly less
|
||||||
const hasPermissionToLoad = () => {
|
const hasPermissionToLoad = () => {
|
||||||
const currentlyAllowedWidgets = SettingsStore.getValue("allowedWidgets", newProps.room.roomId);
|
const currentlyAllowedWidgets = SettingsStore.getValue("allowedWidgets", newProps.room.roomId);
|
||||||
return !!currentlyAllowedWidgets[newProps.eventId];
|
return !!currentlyAllowedWidgets[newProps.app.eventId];
|
||||||
};
|
};
|
||||||
|
|
||||||
const PersistedElement = sdk.getComponent("elements.PersistedElement");
|
const PersistedElement = sdk.getComponent("elements.PersistedElement");
|
||||||
|
@ -86,7 +105,7 @@ export default class AppTile extends React.Component {
|
||||||
initialising: true, // True while we are mangling the widget URL
|
initialising: true, // True while we are mangling the widget URL
|
||||||
// True while the iframe content is loading
|
// True while the iframe content is loading
|
||||||
loading: this.props.waitForIframeLoad && !PersistedElement.isMounted(this._persistKey),
|
loading: this.props.waitForIframeLoad && !PersistedElement.isMounted(this._persistKey),
|
||||||
widgetUrl: this._addWurlParams(newProps.url),
|
widgetUrl: this._addWurlParams(newProps.app.url),
|
||||||
// Assume that widget has permission to load if we are the user who
|
// Assume that widget has permission to load if we are the user who
|
||||||
// added it to the room, or if explicitly granted by the user
|
// added it to the room, or if explicitly granted by the user
|
||||||
hasPermissionToLoad: newProps.userId === newProps.creatorUserId || hasPermissionToLoad(),
|
hasPermissionToLoad: newProps.userId === newProps.creatorUserId || hasPermissionToLoad(),
|
||||||
|
@ -103,7 +122,7 @@ export default class AppTile extends React.Component {
|
||||||
* @return {Boolean} True if capability supported
|
* @return {Boolean} True if capability supported
|
||||||
*/
|
*/
|
||||||
_hasCapability(capability) {
|
_hasCapability(capability) {
|
||||||
return ActiveWidgetStore.widgetHasCapability(this.props.id, capability);
|
return ActiveWidgetStore.widgetHasCapability(this.props.app.id, capability);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -125,7 +144,7 @@ export default class AppTile extends React.Component {
|
||||||
|
|
||||||
const params = qs.parse(u.query);
|
const params = qs.parse(u.query);
|
||||||
// Append widget ID to query parameters
|
// Append widget ID to query parameters
|
||||||
params.widgetId = this.props.id;
|
params.widgetId = this.props.app.id;
|
||||||
// Append current / parent URL, minus the hash because that will change when
|
// Append current / parent URL, minus the hash because that will change when
|
||||||
// we view a different room (ie. may change for persistent widgets)
|
// we view a different room (ie. may change for persistent widgets)
|
||||||
params.parentUrl = window.location.href.split('#', 2)[0];
|
params.parentUrl = window.location.href.split('#', 2)[0];
|
||||||
|
@ -137,35 +156,33 @@ export default class AppTile extends React.Component {
|
||||||
|
|
||||||
isMixedContent() {
|
isMixedContent() {
|
||||||
const parentContentProtocol = window.location.protocol;
|
const parentContentProtocol = window.location.protocol;
|
||||||
const u = url.parse(this.props.url);
|
const u = url.parse(this.props.app.url);
|
||||||
const childContentProtocol = u.protocol;
|
const childContentProtocol = u.protocol;
|
||||||
if (parentContentProtocol === 'https:' && childContentProtocol !== 'https:') {
|
if (parentContentProtocol === 'https:' && childContentProtocol !== 'https:') {
|
||||||
console.warn("Refusing to load mixed-content app:",
|
console.warn("Refusing to load mixed-content app:",
|
||||||
parentContentProtocol, childContentProtocol, window.location, this.props.url);
|
parentContentProtocol, childContentProtocol, window.location, this.props.app.url);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
// Only fetch IM token on mount if we're showing and have permission to load
|
// Only fetch IM token on mount if we're showing and have permission to load
|
||||||
if (this.props.show && this.state.hasPermissionToLoad) {
|
if (this.props.show && this.state.hasPermissionToLoad) {
|
||||||
this.setScalarToken();
|
this.setScalarToken();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
// Widget action listeners
|
// Widget action listeners
|
||||||
this.dispatcherRef = dis.register(this._onAction);
|
this.dispatcherRef = dis.register(this._onAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
// Widget action listeners
|
// Widget action listeners
|
||||||
dis.unregister(this.dispatcherRef);
|
if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
|
||||||
|
|
||||||
// if it's not remaining on screen, get rid of the PersistedElement container
|
// if it's not remaining on screen, get rid of the PersistedElement container
|
||||||
if (!ActiveWidgetStore.getWidgetPersistence(this.props.id)) {
|
if (!ActiveWidgetStore.getWidgetPersistence(this.props.app.id)) {
|
||||||
ActiveWidgetStore.destroyPersistentWidget(this.props.id);
|
ActiveWidgetStore.destroyPersistentWidget(this.props.app.id);
|
||||||
const PersistedElement = sdk.getComponent("elements.PersistedElement");
|
const PersistedElement = sdk.getComponent("elements.PersistedElement");
|
||||||
PersistedElement.destroyElement(this._persistKey);
|
PersistedElement.destroyElement(this._persistKey);
|
||||||
}
|
}
|
||||||
|
@ -176,11 +193,11 @@ export default class AppTile extends React.Component {
|
||||||
* Component initialisation is only complete when this function has resolved
|
* Component initialisation is only complete when this function has resolved
|
||||||
*/
|
*/
|
||||||
setScalarToken() {
|
setScalarToken() {
|
||||||
if (!WidgetUtils.isScalarUrl(this.props.url)) {
|
if (!WidgetUtils.isScalarUrl(this.props.app.url)) {
|
||||||
console.warn('Non-scalar widget, not setting scalar token!', url);
|
console.warn('Non-scalar widget, not setting scalar token!', url);
|
||||||
this.setState({
|
this.setState({
|
||||||
error: null,
|
error: null,
|
||||||
widgetUrl: this._addWurlParams(this.props.url),
|
widgetUrl: this._addWurlParams(this.props.app.url),
|
||||||
initialising: false,
|
initialising: false,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -191,7 +208,7 @@ export default class AppTile extends React.Component {
|
||||||
console.warn("No integration manager - not setting scalar token", url);
|
console.warn("No integration manager - not setting scalar token", url);
|
||||||
this.setState({
|
this.setState({
|
||||||
error: null,
|
error: null,
|
||||||
widgetUrl: this._addWurlParams(this.props.url),
|
widgetUrl: this._addWurlParams(this.props.app.url),
|
||||||
initialising: false,
|
initialising: false,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -204,7 +221,7 @@ export default class AppTile extends React.Component {
|
||||||
console.warn('Non-scalar manager, not setting scalar token!', url);
|
console.warn('Non-scalar manager, not setting scalar token!', url);
|
||||||
this.setState({
|
this.setState({
|
||||||
error: null,
|
error: null,
|
||||||
widgetUrl: this._addWurlParams(this.props.url),
|
widgetUrl: this._addWurlParams(this.props.app.url),
|
||||||
initialising: false,
|
initialising: false,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -217,7 +234,7 @@ export default class AppTile extends React.Component {
|
||||||
this._scalarClient.getScalarToken().then((token) => {
|
this._scalarClient.getScalarToken().then((token) => {
|
||||||
// Append scalar_token as a query param if not already present
|
// Append scalar_token as a query param if not already present
|
||||||
this._scalarClient.scalarToken = token;
|
this._scalarClient.scalarToken = token;
|
||||||
const u = url.parse(this._addWurlParams(this.props.url));
|
const u = url.parse(this._addWurlParams(this.props.app.url));
|
||||||
const params = qs.parse(u.query);
|
const params = qs.parse(u.query);
|
||||||
if (!params.scalar_token) {
|
if (!params.scalar_token) {
|
||||||
params.scalar_token = encodeURIComponent(token);
|
params.scalar_token = encodeURIComponent(token);
|
||||||
|
@ -246,7 +263,7 @@ export default class AppTile extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
if (nextProps.url !== this.props.url) {
|
if (nextProps.app.url !== this.props.app.url) {
|
||||||
this._getNewState(nextProps);
|
this._getNewState(nextProps);
|
||||||
// Fetch IM token for new URL if we're showing and have permission to load
|
// Fetch IM token for new URL if we're showing and have permission to load
|
||||||
if (this.props.show && this.state.hasPermissionToLoad) {
|
if (this.props.show && this.state.hasPermissionToLoad) {
|
||||||
|
@ -280,7 +297,7 @@ export default class AppTile extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onEditClick() {
|
_onEditClick() {
|
||||||
console.log("Edit widget ID ", this.props.id);
|
console.log("Edit widget ID ", this.props.app.id);
|
||||||
if (this.props.onEditClick) {
|
if (this.props.onEditClick) {
|
||||||
this.props.onEditClick();
|
this.props.onEditClick();
|
||||||
} else {
|
} else {
|
||||||
|
@ -289,13 +306,13 @@ export default class AppTile extends React.Component {
|
||||||
IntegrationManagers.sharedInstance().openAll(
|
IntegrationManagers.sharedInstance().openAll(
|
||||||
this.props.room,
|
this.props.room,
|
||||||
'type_' + this.props.type,
|
'type_' + this.props.type,
|
||||||
this.props.id,
|
this.props.app.id,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
IntegrationManagers.sharedInstance().getPrimaryManager().open(
|
IntegrationManagers.sharedInstance().getPrimaryManager().open(
|
||||||
this.props.room,
|
this.props.room,
|
||||||
'type_' + this.props.type,
|
'type_' + this.props.type,
|
||||||
this.props.id,
|
this.props.app.id,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,7 +320,7 @@ export default class AppTile extends React.Component {
|
||||||
|
|
||||||
_onSnapshotClick() {
|
_onSnapshotClick() {
|
||||||
console.warn("Requesting widget snapshot");
|
console.warn("Requesting widget snapshot");
|
||||||
ActiveWidgetStore.getWidgetMessaging(this.props.id).getScreenshot()
|
ActiveWidgetStore.getWidgetMessaging(this.props.app.id).getScreenshot()
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error("Failed to get screenshot", err);
|
console.error("Failed to get screenshot", err);
|
||||||
})
|
})
|
||||||
|
@ -351,7 +368,7 @@ export default class AppTile extends React.Component {
|
||||||
|
|
||||||
WidgetUtils.setRoomWidget(
|
WidgetUtils.setRoomWidget(
|
||||||
this.props.room.roomId,
|
this.props.room.roomId,
|
||||||
this.props.id,
|
this.props.app.id,
|
||||||
).catch((e) => {
|
).catch((e) => {
|
||||||
console.error('Failed to delete widget', e);
|
console.error('Failed to delete widget', e);
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
|
@ -369,7 +386,7 @@ export default class AppTile extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onRevokeClicked() {
|
_onRevokeClicked() {
|
||||||
console.info("Revoke widget permissions - %s", this.props.id);
|
console.info("Revoke widget permissions - %s", this.props.app.id);
|
||||||
this._revokeWidgetPermission();
|
this._revokeWidgetPermission();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,10 +397,10 @@ export default class AppTile extends React.Component {
|
||||||
// Destroy the old widget messaging before starting it back up again. Some widgets
|
// Destroy the old widget messaging before starting it back up again. Some widgets
|
||||||
// have startup routines that run when they are loaded, so we just need to reinitialize
|
// have startup routines that run when they are loaded, so we just need to reinitialize
|
||||||
// the messaging for them.
|
// the messaging for them.
|
||||||
ActiveWidgetStore.delWidgetMessaging(this.props.id);
|
ActiveWidgetStore.delWidgetMessaging(this.props.app.id);
|
||||||
this._setupWidgetMessaging();
|
this._setupWidgetMessaging();
|
||||||
|
|
||||||
ActiveWidgetStore.setRoomId(this.props.id, this.props.room.roomId);
|
ActiveWidgetStore.setRoomId(this.props.app.id, this.props.room.roomId);
|
||||||
this.setState({loading: false});
|
this.setState({loading: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,10 +408,10 @@ export default class AppTile extends React.Component {
|
||||||
// FIXME: There's probably no reason to do this here: it should probably be done entirely
|
// FIXME: There's probably no reason to do this here: it should probably be done entirely
|
||||||
// in ActiveWidgetStore.
|
// in ActiveWidgetStore.
|
||||||
const widgetMessaging = new WidgetMessaging(
|
const widgetMessaging = new WidgetMessaging(
|
||||||
this.props.id, this.props.url, this.props.userWidget, this._appFrame.current.contentWindow);
|
this.props.app.id, this._getRenderedUrl(), this.props.userWidget, this._appFrame.current.contentWindow);
|
||||||
ActiveWidgetStore.setWidgetMessaging(this.props.id, widgetMessaging);
|
ActiveWidgetStore.setWidgetMessaging(this.props.app.id, widgetMessaging);
|
||||||
widgetMessaging.getCapabilities().then((requestedCapabilities) => {
|
widgetMessaging.getCapabilities().then((requestedCapabilities) => {
|
||||||
console.log(`Widget ${this.props.id} requested capabilities: ` + requestedCapabilities);
|
console.log(`Widget ${this.props.app.id} requested capabilities: ` + requestedCapabilities);
|
||||||
requestedCapabilities = requestedCapabilities || [];
|
requestedCapabilities = requestedCapabilities || [];
|
||||||
|
|
||||||
// Allow whitelisted capabilities
|
// Allow whitelisted capabilities
|
||||||
|
@ -406,7 +423,7 @@ export default class AppTile extends React.Component {
|
||||||
}, this.props.whitelistCapabilities);
|
}, this.props.whitelistCapabilities);
|
||||||
|
|
||||||
if (requestedWhitelistCapabilies.length > 0 ) {
|
if (requestedWhitelistCapabilies.length > 0 ) {
|
||||||
console.warn(`Widget ${this.props.id} allowing requested, whitelisted properties: ` +
|
console.warn(`Widget ${this.props.app.id} allowing requested, whitelisted properties: ` +
|
||||||
requestedWhitelistCapabilies,
|
requestedWhitelistCapabilies,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -414,7 +431,7 @@ export default class AppTile extends React.Component {
|
||||||
|
|
||||||
// TODO -- Add UI to warn about and optionally allow requested capabilities
|
// TODO -- Add UI to warn about and optionally allow requested capabilities
|
||||||
|
|
||||||
ActiveWidgetStore.setWidgetCapabilities(this.props.id, requestedWhitelistCapabilies);
|
ActiveWidgetStore.setWidgetCapabilities(this.props.app.id, requestedWhitelistCapabilies);
|
||||||
|
|
||||||
if (this.props.onCapabilityRequest) {
|
if (this.props.onCapabilityRequest) {
|
||||||
this.props.onCapabilityRequest(requestedCapabilities);
|
this.props.onCapabilityRequest(requestedCapabilities);
|
||||||
|
@ -422,16 +439,16 @@ export default class AppTile extends React.Component {
|
||||||
|
|
||||||
// We only tell Jitsi widgets that we're ready because they're realistically the only ones
|
// We only tell Jitsi widgets that we're ready because they're realistically the only ones
|
||||||
// using this custom extension to the widget API.
|
// using this custom extension to the widget API.
|
||||||
if (this.props.type === 'jitsi') {
|
if (this.props.app.type === 'jitsi') {
|
||||||
widgetMessaging.flagReadyToContinue();
|
widgetMessaging.flagReadyToContinue();
|
||||||
}
|
}
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.log(`Failed to get capabilities for widget type ${this.props.type}`, this.props.id, err);
|
console.log(`Failed to get capabilities for widget type ${this.props.app.type}`, this.props.app.id, err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onAction(payload) {
|
_onAction(payload) {
|
||||||
if (payload.widgetId === this.props.id) {
|
if (payload.widgetId === this.props.app.id) {
|
||||||
switch (payload.action) {
|
switch (payload.action) {
|
||||||
case 'm.sticker':
|
case 'm.sticker':
|
||||||
if (this._hasCapability('m.sticker')) {
|
if (this._hasCapability('m.sticker')) {
|
||||||
|
@ -460,9 +477,9 @@ export default class AppTile extends React.Component {
|
||||||
|
|
||||||
_grantWidgetPermission() {
|
_grantWidgetPermission() {
|
||||||
const roomId = this.props.room.roomId;
|
const roomId = this.props.room.roomId;
|
||||||
console.info("Granting permission for widget to load: " + this.props.eventId);
|
console.info("Granting permission for widget to load: " + this.props.app.eventId);
|
||||||
const current = SettingsStore.getValue("allowedWidgets", roomId);
|
const current = SettingsStore.getValue("allowedWidgets", roomId);
|
||||||
current[this.props.eventId] = true;
|
current[this.props.app.eventId] = true;
|
||||||
SettingsStore.setValue("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, current).then(() => {
|
SettingsStore.setValue("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, current).then(() => {
|
||||||
this.setState({hasPermissionToLoad: true});
|
this.setState({hasPermissionToLoad: true});
|
||||||
|
|
||||||
|
@ -476,14 +493,14 @@ export default class AppTile extends React.Component {
|
||||||
|
|
||||||
_revokeWidgetPermission() {
|
_revokeWidgetPermission() {
|
||||||
const roomId = this.props.room.roomId;
|
const roomId = this.props.room.roomId;
|
||||||
console.info("Revoking permission for widget to load: " + this.props.eventId);
|
console.info("Revoking permission for widget to load: " + this.props.app.eventId);
|
||||||
const current = SettingsStore.getValue("allowedWidgets", roomId);
|
const current = SettingsStore.getValue("allowedWidgets", roomId);
|
||||||
current[this.props.eventId] = false;
|
current[this.props.app.eventId] = false;
|
||||||
SettingsStore.setValue("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, current).then(() => {
|
SettingsStore.setValue("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, current).then(() => {
|
||||||
this.setState({hasPermissionToLoad: false});
|
this.setState({hasPermissionToLoad: false});
|
||||||
|
|
||||||
// Force the widget to be non-persistent (able to be deleted/forgotten)
|
// Force the widget to be non-persistent (able to be deleted/forgotten)
|
||||||
ActiveWidgetStore.destroyPersistentWidget(this.props.id);
|
ActiveWidgetStore.destroyPersistentWidget(this.props.app.id);
|
||||||
const PersistedElement = sdk.getComponent("elements.PersistedElement");
|
const PersistedElement = sdk.getComponent("elements.PersistedElement");
|
||||||
PersistedElement.destroyElement(this._persistKey);
|
PersistedElement.destroyElement(this._persistKey);
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
|
@ -494,8 +511,8 @@ export default class AppTile extends React.Component {
|
||||||
|
|
||||||
formatAppTileName() {
|
formatAppTileName() {
|
||||||
let appTileName = "No name";
|
let appTileName = "No name";
|
||||||
if (this.props.name && this.props.name.trim()) {
|
if (this.props.app.name && this.props.app.name.trim()) {
|
||||||
appTileName = this.props.name.trim();
|
appTileName = this.props.app.name.trim();
|
||||||
}
|
}
|
||||||
return appTileName;
|
return appTileName;
|
||||||
}
|
}
|
||||||
|
@ -519,20 +536,78 @@ export default class AppTile extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_getSafeUrl() {
|
/**
|
||||||
const parsedWidgetUrl = url.parse(this.state.widgetUrl, true);
|
* Replace the widget template variables in a url with their values
|
||||||
|
*
|
||||||
|
* @param {string} u The URL with template variables
|
||||||
|
*
|
||||||
|
* @returns {string} url with temlate variables replaced
|
||||||
|
*/
|
||||||
|
_templatedUrl(u) {
|
||||||
|
const myUserId = MatrixClientPeg.get().credentials.userId;
|
||||||
|
const myUser = MatrixClientPeg.get().getUser(myUserId);
|
||||||
|
const vars = Object.assign({
|
||||||
|
domain: "jitsi.riot.im", // v1 widgets have this hardcoded
|
||||||
|
}, this.props.app.data, {
|
||||||
|
'matrix_user_id': myUserId,
|
||||||
|
'matrix_room_id': this.props.room.roomId,
|
||||||
|
'matrix_display_name': myUser ? myUser.displayName : myUserId,
|
||||||
|
'matrix_avatar_url': myUser ? MatrixClientPeg.get().mxcUrlToHttp(myUser.avatarUrl) : '',
|
||||||
|
|
||||||
|
// TODO: Namespace themes through some standard
|
||||||
|
'theme': SettingsStore.getValue("theme"),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (vars.conferenceId === undefined) {
|
||||||
|
// we'll need to parse the conference ID out of the URL for v1 Jitsi widgets
|
||||||
|
const parsedUrl = new URL(this.props.app.url);
|
||||||
|
vars.conferenceId = parsedUrl.searchParams.get("confId");
|
||||||
|
}
|
||||||
|
|
||||||
|
return uriFromTemplate(u, vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the URL used in the iframe
|
||||||
|
* In cases where we supply our own UI for a widget, this is an internal
|
||||||
|
* URL different to the one used if the widget is popped out to a separate
|
||||||
|
* tab / browser
|
||||||
|
*
|
||||||
|
* @returns {string} url
|
||||||
|
*/
|
||||||
|
_getRenderedUrl() {
|
||||||
|
let url;
|
||||||
|
|
||||||
|
if (this.props.app.type === 'jitsi') {
|
||||||
|
console.log("Replacing Jitsi widget URL with local wrapper");
|
||||||
|
url = WidgetUtils.getLocalJitsiWrapperUrl({forLocalRender: true});
|
||||||
|
url = this._addWurlParams(url);
|
||||||
|
} else {
|
||||||
|
url = this._getSafeUrl(this.state.widgetUrl);
|
||||||
|
}
|
||||||
|
return this._templatedUrl(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
_getPopoutUrl() {
|
||||||
|
if (this.props.app.type === 'jitsi') {
|
||||||
|
return this._templatedUrl(
|
||||||
|
WidgetUtils.getLocalJitsiWrapperUrl({forLocalRender: false}),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// use app.url, not state.widgetUrl, because we want the one without
|
||||||
|
// the wURL params for the popped-out version.
|
||||||
|
return this._templatedUrl(this._getSafeUrl(this.props.app.url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_getSafeUrl(u) {
|
||||||
|
const parsedWidgetUrl = url.parse(u, true);
|
||||||
if (ENABLE_REACT_PERF) {
|
if (ENABLE_REACT_PERF) {
|
||||||
parsedWidgetUrl.search = null;
|
parsedWidgetUrl.search = null;
|
||||||
parsedWidgetUrl.query.react_perf = true;
|
parsedWidgetUrl.query.react_perf = true;
|
||||||
}
|
}
|
||||||
let safeWidgetUrl = '';
|
let safeWidgetUrl = '';
|
||||||
if (ALLOWED_APP_URL_SCHEMES.includes(parsedWidgetUrl.protocol) || (
|
if (ALLOWED_APP_URL_SCHEMES.includes(parsedWidgetUrl.protocol)) {
|
||||||
// Check if the widget URL is a Jitsi widget in Electron
|
|
||||||
parsedWidgetUrl.protocol === 'vector:'
|
|
||||||
&& parsedWidgetUrl.host === 'vector'
|
|
||||||
&& parsedWidgetUrl.pathname === '/webapp/jitsi.html'
|
|
||||||
&& this.props.type === 'jitsi'
|
|
||||||
)) {
|
|
||||||
safeWidgetUrl = url.format(parsedWidgetUrl);
|
safeWidgetUrl = url.format(parsedWidgetUrl);
|
||||||
}
|
}
|
||||||
return safeWidgetUrl;
|
return safeWidgetUrl;
|
||||||
|
@ -562,9 +637,9 @@ export default class AppTile extends React.Component {
|
||||||
|
|
||||||
_onPopoutWidgetClick() {
|
_onPopoutWidgetClick() {
|
||||||
// Using Object.assign workaround as the following opens in a new window instead of a new tab.
|
// Using Object.assign workaround as the following opens in a new window instead of a new tab.
|
||||||
// window.open(this._getSafeUrl(), '_blank', 'noopener=yes');
|
// window.open(this._getPopoutUrl(), '_blank', 'noopener=yes');
|
||||||
Object.assign(document.createElement('a'),
|
Object.assign(document.createElement('a'),
|
||||||
{ target: '_blank', href: this._getSafeUrl(), rel: 'noreferrer noopener'}).click();
|
{ target: '_blank', href: this._getPopoutUrl(), rel: 'noreferrer noopener'}).click();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onReloadWidgetClick() {
|
_onReloadWidgetClick() {
|
||||||
|
@ -641,7 +716,7 @@ export default class AppTile extends React.Component {
|
||||||
<iframe
|
<iframe
|
||||||
allow={iframeFeatures}
|
allow={iframeFeatures}
|
||||||
ref={this._appFrame}
|
ref={this._appFrame}
|
||||||
src={this._getSafeUrl()}
|
src={this._getRenderedUrl()}
|
||||||
allowFullScreen={true}
|
allowFullScreen={true}
|
||||||
sandbox={sandboxFlags}
|
sandbox={sandboxFlags}
|
||||||
onLoad={this._onLoaded} />
|
onLoad={this._onLoaded} />
|
||||||
|
@ -706,7 +781,7 @@ export default class AppTile extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
return <React.Fragment>
|
return <React.Fragment>
|
||||||
<div className={appTileClass} id={this.props.id}>
|
<div className={appTileClass} id={this.props.app.id}>
|
||||||
{ this.props.showMenubar &&
|
{ this.props.showMenubar &&
|
||||||
<div ref={this._menu_bar} className={menuBarClasses} onClick={this.onClickMenuBar}>
|
<div ref={this._menu_bar} className={menuBarClasses} onClick={this.onClickMenuBar}>
|
||||||
<span className="mx_AppTileMenuBarTitle" style={{pointerEvents: (this.props.handleMinimisePointerEvents ? 'all' : false)}}>
|
<span className="mx_AppTileMenuBarTitle" style={{pointerEvents: (this.props.handleMinimisePointerEvents ? 'all' : false)}}>
|
||||||
|
@ -753,12 +828,8 @@ export default class AppTile extends React.Component {
|
||||||
AppTile.displayName = 'AppTile';
|
AppTile.displayName = 'AppTile';
|
||||||
|
|
||||||
AppTile.propTypes = {
|
AppTile.propTypes = {
|
||||||
id: PropTypes.string.isRequired,
|
app: PropTypes.object.isRequired,
|
||||||
eventId: PropTypes.string, // required for room widgets
|
|
||||||
url: PropTypes.string.isRequired,
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
room: PropTypes.object.isRequired,
|
room: PropTypes.object.isRequired,
|
||||||
type: PropTypes.string.isRequired,
|
|
||||||
// Specifying 'fullWidth' as true will render the app tile to fill the width of the app drawer continer.
|
// Specifying 'fullWidth' as true will render the app tile to fill the width of the app drawer continer.
|
||||||
// This should be set to true when there is only one widget in the app drawer, otherwise it should be false.
|
// This should be set to true when there is only one widget in the app drawer, otherwise it should be false.
|
||||||
fullWidth: PropTypes.bool,
|
fullWidth: PropTypes.bool,
|
||||||
|
@ -805,7 +876,6 @@ AppTile.propTypes = {
|
||||||
};
|
};
|
||||||
|
|
||||||
AppTile.defaultProps = {
|
AppTile.defaultProps = {
|
||||||
url: "",
|
|
||||||
waitForIframeLoad: true,
|
waitForIframeLoad: true,
|
||||||
showMenubar: true,
|
showMenubar: true,
|
||||||
showTitle: true,
|
showTitle: true,
|
||||||
|
|
|
@ -38,7 +38,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
cli.on("deviceVerificationChanged", this.onDeviceVerificationChanged);
|
cli.on("deviceVerificationChanged", this.onDeviceVerificationChanged);
|
||||||
},
|
},
|
||||||
|
|
|
@ -42,7 +42,7 @@ export default class EditableTextContainer extends React.Component {
|
||||||
this._onValueChanged = this._onValueChanged.bind(this);
|
this._onValueChanged = this._onValueChanged.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
if (this.props.getInitialValue === undefined) {
|
if (this.props.getInitialValue === undefined) {
|
||||||
// use whatever was given in the initialValue property.
|
// use whatever was given in the initialValue property.
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -24,8 +24,8 @@ import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
|
|
||||||
function languageMatchesSearchQuery(query, language) {
|
function languageMatchesSearchQuery(query, language) {
|
||||||
if (language.label.toUpperCase().indexOf(query.toUpperCase()) == 0) return true;
|
if (language.label.toUpperCase().includes(query.toUpperCase())) return true;
|
||||||
if (language.value.toUpperCase() == query.toUpperCase()) return true;
|
if (language.value.toUpperCase() === query.toUpperCase()) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ export default class LanguageDropdown extends React.Component {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
languageHandler.getAllLanguagesFromJson().then((langs) => {
|
languageHandler.getAllLanguagesFromJson().then((langs) => {
|
||||||
langs.sort(function(a, b) {
|
langs.sort(function(a, b) {
|
||||||
if (a.label < b.label) return -1;
|
if (a.label < b.label) return -1;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2018 New Vector Ltd
|
Copyright 2018 New Vector Ltd
|
||||||
Copyright 2019 The Matrix.org Foundation C.I.C.
|
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -33,7 +33,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
|
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
|
||||||
ActiveWidgetStore.on('update', this._onActiveWidgetStoreUpdate);
|
ActiveWidgetStore.on('update', this._onActiveWidgetStoreUpdate);
|
||||||
},
|
},
|
||||||
|
@ -75,11 +75,7 @@ export default createReactClass({
|
||||||
const AppTile = sdk.getComponent('elements.AppTile');
|
const AppTile = sdk.getComponent('elements.AppTile');
|
||||||
return <AppTile
|
return <AppTile
|
||||||
key={app.id}
|
key={app.id}
|
||||||
id={app.id}
|
app={app}
|
||||||
eventId={app.eventId}
|
|
||||||
url={app.url}
|
|
||||||
name={app.name}
|
|
||||||
type={app.type}
|
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
room={persistentWidgetInRoom}
|
room={persistentWidgetInRoom}
|
||||||
userId={MatrixClientPeg.get().credentials.userId}
|
userId={MatrixClientPeg.get().credentials.userId}
|
||||||
|
|
|
@ -155,10 +155,10 @@ const Pill = createReactClass({
|
||||||
this.setState({resourceId, pillType, member, group, room});
|
this.setState({resourceId, pillType, member, group, room});
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
this._unmounted = false;
|
this._unmounted = false;
|
||||||
this._matrixClient = MatrixClientPeg.get();
|
this._matrixClient = MatrixClientPeg.get();
|
||||||
this.componentWillReceiveProps(this.props);
|
this.componentWillReceiveProps(this.props); // HACK: We shouldn't be calling lifecycle functions ourselves.
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
|
|
@ -62,7 +62,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
// TODO: [REACT-WARNING] Move this to class constructor
|
// TODO: [REACT-WARNING] Move this to class constructor
|
||||||
this._initStateFromProps(this.props);
|
this._initStateFromProps(this.props);
|
||||||
},
|
},
|
||||||
|
|
|
@ -184,7 +184,7 @@ export default class ReplyThread extends React.Component {
|
||||||
ref={ref} permalinkCreator={permalinkCreator} />;
|
ref={ref} permalinkCreator={permalinkCreator} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
this.unmounted = false;
|
this.unmounted = false;
|
||||||
this.room = this.context.getRoom(this.props.parentEv.getRoomId());
|
this.room = this.context.getRoom(this.props.parentEv.getRoomId());
|
||||||
this.room.on("Room.redaction", this.onRoomRedaction);
|
this.room.on("Room.redaction", this.onRoomRedaction);
|
||||||
|
|
|
@ -36,11 +36,9 @@ const TintableSvg = createReactClass({
|
||||||
idSequence: 0,
|
idSequence: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
|
||||||
this.fixups = [];
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
|
this.fixups = [];
|
||||||
|
|
||||||
this.id = TintableSvg.idSequence++;
|
this.id = TintableSvg.idSequence++;
|
||||||
TintableSvg.mounts[this.id] = this;
|
TintableSvg.mounts[this.id] = this;
|
||||||
},
|
},
|
||||||
|
|
|
@ -49,7 +49,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this._unmounted = false;
|
this._unmounted = false;
|
||||||
this._initGroupStore(this.props.groupId);
|
this._initGroupStore(this.props.groupId);
|
||||||
},
|
},
|
||||||
|
|
|
@ -47,7 +47,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this._unmounted = false;
|
this._unmounted = false;
|
||||||
this._initGroupStore(this.props.groupId);
|
this._initGroupStore(this.props.groupId);
|
||||||
},
|
},
|
||||||
|
|
|
@ -36,7 +36,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this._initGroupStore(this.props.groupId);
|
this._initGroupStore(this.props.groupId);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this._initGroupStore(this.props.groupId);
|
this._initGroupStore(this.props.groupId);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this._unmounted = false;
|
this._unmounted = false;
|
||||||
this._initGroupStore(this.props.groupId);
|
this._initGroupStore(this.props.groupId);
|
||||||
},
|
},
|
||||||
|
|
|
@ -55,7 +55,7 @@ const GroupTile = createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
FlairStore.getGroupProfileCached(this.context, this.props.groupId).then((profile) => {
|
FlairStore.getGroupProfileCached(this.context, this.props.groupId).then((profile) => {
|
||||||
this.setState({profile});
|
this.setState({profile});
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
|
|
|
@ -34,7 +34,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this.context.getJoinedGroups().then((result) => {
|
this.context.getJoinedGroups().then((result) => {
|
||||||
this.setState({groups: result.groups || [], error: null});
|
this.setState({groups: result.groups || [], error: null});
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
|
|
|
@ -67,11 +67,6 @@ export default class MImageBody extends React.Component {
|
||||||
this._image = createRef();
|
this._image = createRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
this.unmounted = false;
|
|
||||||
this.context.on('sync', this.onClientSync);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: factor this out and aplpy it to MVideoBody and MAudioBody too!
|
// FIXME: factor this out and aplpy it to MVideoBody and MAudioBody too!
|
||||||
onClientSync(syncState, prevState) {
|
onClientSync(syncState, prevState) {
|
||||||
if (this.unmounted) return;
|
if (this.unmounted) return;
|
||||||
|
@ -258,6 +253,9 @@ export default class MImageBody extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
this.unmounted = false;
|
||||||
|
this.context.on('sync', this.onClientSync);
|
||||||
|
|
||||||
const content = this.props.mxEvent.getContent();
|
const content = this.props.mxEvent.getContent();
|
||||||
if (content.file !== undefined && this.state.decryptedUrl === null) {
|
if (content.file !== undefined && this.state.decryptedUrl === null) {
|
||||||
let thumbnailPromise = Promise.resolve(null);
|
let thumbnailPromise = Promise.resolve(null);
|
||||||
|
|
|
@ -42,7 +42,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
this.unmounted = false;
|
this.unmounted = false;
|
||||||
this._updateRelatedGroups();
|
this._updateRelatedGroups();
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ import {_t} from "../../../languageHandler";
|
||||||
const MISMATCHES = ["m.key_mismatch", "m.user_error", "m.mismatched_sas"];
|
const MISMATCHES = ["m.key_mismatch", "m.user_error", "m.mismatched_sas"];
|
||||||
|
|
||||||
const EncryptionPanel = (props) => {
|
const EncryptionPanel = (props) => {
|
||||||
const {verificationRequest, verificationRequestPromise, member, onClose, layout, isRoomEncrypted} = props;
|
const {verificationRequest, verificationRequestPromise, member, onClose, layout, isRoomEncrypted, inDialog} = props;
|
||||||
const [request, setRequest] = useState(verificationRequest);
|
const [request, setRequest] = useState(verificationRequest);
|
||||||
// state to show a spinner immediately after clicking "start verification",
|
// state to show a spinner immediately after clicking "start verification",
|
||||||
// before we have a request
|
// before we have a request
|
||||||
|
@ -133,6 +133,7 @@ const EncryptionPanel = (props) => {
|
||||||
member={member}
|
member={member}
|
||||||
request={request}
|
request={request}
|
||||||
key={request.channel.transactionId}
|
key={request.channel.transactionId}
|
||||||
|
inDialog={inDialog}
|
||||||
phase={phase} />
|
phase={phase} />
|
||||||
</React.Fragment>);
|
</React.Fragment>);
|
||||||
}
|
}
|
||||||
|
@ -142,6 +143,7 @@ EncryptionPanel.propTypes = {
|
||||||
onClose: PropTypes.func.isRequired,
|
onClose: PropTypes.func.isRequired,
|
||||||
verificationRequest: PropTypes.object,
|
verificationRequest: PropTypes.object,
|
||||||
layout: PropTypes.string,
|
layout: PropTypes.string,
|
||||||
|
inDialog: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default EncryptionPanel;
|
export default EncryptionPanel;
|
||||||
|
|
|
@ -40,7 +40,7 @@ export default class HeaderButtons extends React.Component {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
this._storeToken = RightPanelStore.getSharedInstance().addListener(this.onRightPanelUpdate.bind(this));
|
this._storeToken = RightPanelStore.getSharedInstance().addListener(this.onRightPanelUpdate.bind(this));
|
||||||
this._dispatcherRef = dis.register(this.onAction.bind(this)); // used by subclasses
|
this._dispatcherRef = dis.register(this.onAction.bind(this)); // used by subclasses
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,6 +245,7 @@ export default class VerificationPanel extends React.PureComponent {
|
||||||
sas={this.state.sasEvent.sas}
|
sas={this.state.sasEvent.sas}
|
||||||
onCancel={this._onSasMismatchesClick}
|
onCancel={this._onSasMismatchesClick}
|
||||||
onDone={this._onSasMatchesClick}
|
onDone={this._onSasMatchesClick}
|
||||||
|
inDialog={this.props.inDialog}
|
||||||
/>
|
/>
|
||||||
</div>;
|
</div>;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -55,13 +55,10 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
ScalarMessaging.startListening();
|
ScalarMessaging.startListening();
|
||||||
MatrixClientPeg.get().on('RoomState.events', this.onRoomStateEvents);
|
MatrixClientPeg.get().on('RoomState.events', this.onRoomStateEvents);
|
||||||
WidgetEchoStore.on('update', this._updateApps);
|
WidgetEchoStore.on('update', this._updateApps);
|
||||||
},
|
|
||||||
|
|
||||||
componentDidMount: function() {
|
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -71,7 +68,7 @@ export default createReactClass({
|
||||||
MatrixClientPeg.get().removeListener('RoomState.events', this.onRoomStateEvents);
|
MatrixClientPeg.get().removeListener('RoomState.events', this.onRoomStateEvents);
|
||||||
}
|
}
|
||||||
WidgetEchoStore.removeListener('update', this._updateApps);
|
WidgetEchoStore.removeListener('update', this._updateApps);
|
||||||
dis.unregister(this.dispatcherRef);
|
if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillReceiveProps(newProps) {
|
componentWillReceiveProps(newProps) {
|
||||||
|
@ -160,11 +157,7 @@ export default createReactClass({
|
||||||
|
|
||||||
return (<AppTile
|
return (<AppTile
|
||||||
key={app.id}
|
key={app.id}
|
||||||
id={app.id}
|
app={app}
|
||||||
eventId={app.eventId}
|
|
||||||
url={app.url}
|
|
||||||
name={app.name}
|
|
||||||
type={app.type}
|
|
||||||
fullWidth={arr.length<2 ? true : false}
|
fullWidth={arr.length<2 ? true : false}
|
||||||
room={this.props.room}
|
room={this.props.room}
|
||||||
userId={this.props.userId}
|
userId={this.props.userId}
|
||||||
|
|
|
@ -223,7 +223,7 @@ export default class EditMessageComposer extends React.Component {
|
||||||
this.props.editState.setEditorState(caret, parts);
|
this.props.editState.setEditorState(caret, parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
this._createEditorModel();
|
this._createEditorModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,14 +30,12 @@ export default createReactClass({
|
||||||
onCancelClick: PropTypes.func.isRequired,
|
onCancelClick: PropTypes.func.isRequired,
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'panel_disable',
|
action: 'panel_disable',
|
||||||
middleDisabled: true,
|
middleDisabled: true,
|
||||||
});
|
});
|
||||||
},
|
|
||||||
|
|
||||||
componentDidMount: function() {
|
|
||||||
document.addEventListener('keydown', this._onKeyDown);
|
document.addEventListener('keydown', this._onKeyDown);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,8 @@ export default createReactClass({
|
||||||
contextType: MatrixClientContext,
|
contextType: MatrixClientContext,
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
// TODO: [REACT-WARNING] Move this to constructor
|
||||||
|
UNSAFE_componentWillMount: function() {
|
||||||
this._cancelDeviceList = null;
|
this._cancelDeviceList = null;
|
||||||
const cli = this.context;
|
const cli = this.context;
|
||||||
|
|
||||||
|
@ -98,9 +99,7 @@ export default createReactClass({
|
||||||
cli.on("accountData", this.onAccountData);
|
cli.on("accountData", this.onAccountData);
|
||||||
|
|
||||||
this._checkIgnoreState();
|
this._checkIgnoreState();
|
||||||
},
|
|
||||||
|
|
||||||
componentDidMount: function() {
|
|
||||||
this._updateStateForNewMember(this.props.member);
|
this._updateStateForNewMember(this.props.member);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,8 @@ export default createReactClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
// TODO: [REACT-WARNING] Move this to constructor
|
||||||
|
UNSAFE_componentWillMount: function() {
|
||||||
this._mounted = true;
|
this._mounted = true;
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
if (cli.hasLazyLoadMembersEnabled()) {
|
if (cli.hasLazyLoadMembersEnabled()) {
|
||||||
|
|
|
@ -49,7 +49,7 @@ export default class RoomBreadcrumbs extends React.Component {
|
||||||
this._scroller = createRef();
|
this._scroller = createRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
this._dispatcherRef = dis.register(this.onAction);
|
this._dispatcherRef = dis.register(this.onAction);
|
||||||
|
|
||||||
const storedRooms = SettingsStore.getValue("breadcrumb_rooms");
|
const storedRooms = SettingsStore.getValue("breadcrumb_rooms");
|
||||||
|
|
|
@ -290,6 +290,7 @@ export default createReactClass({
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'view_room',
|
action: 'view_room',
|
||||||
room_id: room.roomId,
|
room_id: room.roomId,
|
||||||
|
show_room_tile: true, // to make sure the room gets scrolled into view
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -34,7 +34,8 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
// TODO: [REACT-WARNING] Move this to constructor
|
||||||
|
UNSAFE_componentWillMount: function() {
|
||||||
const room = this.props.room;
|
const room = this.props.room;
|
||||||
const name = room.currentState.getStateEvents('m.room.name', '');
|
const name = room.currentState.getStateEvents('m.room.name', '');
|
||||||
const myId = MatrixClientPeg.get().credentials.userId;
|
const myId = MatrixClientPeg.get().credentials.userId;
|
||||||
|
|
|
@ -97,7 +97,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this._checkInvitedEmail();
|
this._checkInvitedEmail();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ export default class RoomRecoveryReminder extends React.PureComponent {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
this._loadBackupStatus();
|
this._loadBackupStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,6 @@ export default class RoomRecoveryReminder extends React.PureComponent {
|
||||||
loading: false,
|
loading: false,
|
||||||
error: e,
|
error: e,
|
||||||
});
|
});
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -203,7 +203,7 @@ export default createReactClass({
|
||||||
|
|
||||||
case 'view_room':
|
case 'view_room':
|
||||||
// when the room is selected make sure its tile is visible, for breadcrumbs/keyboard shortcut access
|
// when the room is selected make sure its tile is visible, for breadcrumbs/keyboard shortcut access
|
||||||
if (payload.room_id === this.props.room.roomId) {
|
if (payload.room_id === this.props.room.roomId && payload.show_room_tile) {
|
||||||
this._scrollIntoView();
|
this._scrollIntoView();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -33,7 +33,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
const room = this.props.room;
|
const room = this.props.room;
|
||||||
const topic = room.currentState.getStateEvents('m.room.topic', '');
|
const topic = room.currentState.getStateEvents('m.room.topic', '');
|
||||||
this.setState({
|
this.setState({
|
||||||
|
|
|
@ -31,7 +31,7 @@ export default createReactClass({
|
||||||
recommendation: PropTypes.object.isRequired,
|
recommendation: PropTypes.object.isRequired,
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
const tombstone = this.props.room.currentState.getStateEvents("m.room.tombstone", "");
|
const tombstone = this.props.room.currentState.getStateEvents("m.room.tombstone", "");
|
||||||
this.setState({upgraded: tombstone && tombstone.getContent().replacement_room});
|
this.setState({upgraded: tombstone && tombstone.getContent().replacement_room});
|
||||||
|
|
||||||
|
|
|
@ -240,6 +240,14 @@ export default class Stickerpicker extends React.Component {
|
||||||
// Set default name
|
// Set default name
|
||||||
stickerpickerWidget.content.name = stickerpickerWidget.name || _t("Stickerpack");
|
stickerpickerWidget.content.name = stickerpickerWidget.name || _t("Stickerpack");
|
||||||
|
|
||||||
|
// FIXME: could this use the same code as other apps?
|
||||||
|
const stickerApp = {
|
||||||
|
id: stickerpickerWidget.id,
|
||||||
|
url: stickerpickerWidget.content.url,
|
||||||
|
name: stickerpickerWidget.content.name,
|
||||||
|
type: stickerpickerWidget.content.type,
|
||||||
|
};
|
||||||
|
|
||||||
stickersContent = (
|
stickersContent = (
|
||||||
<div className='mx_Stickers_content_container'>
|
<div className='mx_Stickers_content_container'>
|
||||||
<div
|
<div
|
||||||
|
@ -253,11 +261,8 @@ export default class Stickerpicker extends React.Component {
|
||||||
>
|
>
|
||||||
<PersistedElement persistKey={PERSISTED_ELEMENT_KEY} style={{zIndex: STICKERPICKER_Z_INDEX}}>
|
<PersistedElement persistKey={PERSISTED_ELEMENT_KEY} style={{zIndex: STICKERPICKER_Z_INDEX}}>
|
||||||
<AppTile
|
<AppTile
|
||||||
id={stickerpickerWidget.id}
|
app={stickerApp}
|
||||||
url={stickerpickerWidget.content.url}
|
|
||||||
name={stickerpickerWidget.content.name}
|
|
||||||
room={this.props.room}
|
room={this.props.room}
|
||||||
type={stickerpickerWidget.content.type}
|
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
userId={MatrixClientPeg.get().credentials.userId}
|
userId={MatrixClientPeg.get().credentials.userId}
|
||||||
creatorUserId={stickerpickerWidget.sender || MatrixClientPeg.get().credentials.userId}
|
creatorUserId={stickerpickerWidget.sender || MatrixClientPeg.get().credentials.userId}
|
||||||
|
|
|
@ -51,7 +51,7 @@ export default class ThirdPartyMemberInfo extends React.Component {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount(): void {
|
componentDidMount(): void {
|
||||||
MatrixClientPeg.get().on("RoomState.events", this.onRoomStateEvents);
|
MatrixClientPeg.get().on("RoomState.events", this.onRoomStateEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
MatrixClientPeg.get().on("RoomMember.typing", this.onRoomMemberTyping);
|
MatrixClientPeg.get().on("RoomMember.typing", this.onRoomMemberTyping);
|
||||||
MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
|
MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
|
||||||
},
|
},
|
||||||
|
|
|
@ -55,7 +55,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
MatrixClientPeg.get().on("RoomState.events", this.onRoomStateEvents);
|
MatrixClientPeg.get().on("RoomState.events", this.onRoomStateEvents);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this._sessionStore = sessionStore;
|
this._sessionStore = sessionStore;
|
||||||
this._sessionStoreToken = this._sessionStore.addListener(
|
this._sessionStoreToken = this._sessionStore.addListener(
|
||||||
this._setStateFromSessionStore,
|
this._setStateFromSessionStore,
|
||||||
|
|
|
@ -23,6 +23,7 @@ import * as sdk from '../../../index';
|
||||||
import {MatrixClientPeg} from '../../../MatrixClientPeg';
|
import {MatrixClientPeg} from '../../../MatrixClientPeg';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import Modal from '../../../Modal';
|
import Modal from '../../../Modal';
|
||||||
|
import {SSOAuthEntry} from "../auth/InteractiveAuthEntryComponents";
|
||||||
|
|
||||||
export default class DevicesPanel extends React.Component {
|
export default class DevicesPanel extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -123,11 +124,29 @@ export default class DevicesPanel extends React.Component {
|
||||||
// pop up an interactive auth dialog
|
// pop up an interactive auth dialog
|
||||||
const InteractiveAuthDialog = sdk.getComponent("dialogs.InteractiveAuthDialog");
|
const InteractiveAuthDialog = sdk.getComponent("dialogs.InteractiveAuthDialog");
|
||||||
|
|
||||||
|
const dialogAesthetics = {
|
||||||
|
[SSOAuthEntry.PHASE_PREAUTH]: {
|
||||||
|
title: _t("Use Single Sign On to continue"),
|
||||||
|
body: _t("Confirm deleting these sessions by using Single Sign On to prove your identity."),
|
||||||
|
continueText: _t("Single Sign On"),
|
||||||
|
continueKind: "primary",
|
||||||
|
},
|
||||||
|
[SSOAuthEntry.PHASE_POSTAUTH]: {
|
||||||
|
title: _t("Confirm deleting these sessions"),
|
||||||
|
body: _t("Click the button below to confirm deleting these sessions."),
|
||||||
|
continueText: _t("Delete sessions"),
|
||||||
|
continueKind: "danger",
|
||||||
|
},
|
||||||
|
};
|
||||||
Modal.createTrackedDialog('Delete Device Dialog', '', InteractiveAuthDialog, {
|
Modal.createTrackedDialog('Delete Device Dialog', '', InteractiveAuthDialog, {
|
||||||
title: _t("Authentication"),
|
title: _t("Authentication"),
|
||||||
matrixClient: MatrixClientPeg.get(),
|
matrixClient: MatrixClientPeg.get(),
|
||||||
authData: error.data,
|
authData: error.data,
|
||||||
makeRequest: this._makeDeleteRequest.bind(this),
|
makeRequest: this._makeDeleteRequest.bind(this),
|
||||||
|
aestheticsForStagePhases: {
|
||||||
|
[SSOAuthEntry.LOGIN_TYPE]: dialogAesthetics,
|
||||||
|
[SSOAuthEntry.UNSTABLE_LOGIN_TYPE]: dialogAesthetics,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
console.error("Error deleting sessions", e);
|
console.error("Error deleting sessions", e);
|
||||||
|
|
|
@ -63,7 +63,7 @@ export default class EventIndexPanel extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentWillMount(): void {
|
async componentDidMount(): void {
|
||||||
this.updateState();
|
this.updateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ export default class KeyBackupPanel extends React.PureComponent {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
this._checkKeyBackupStatus();
|
this._checkKeyBackupStatus();
|
||||||
|
|
||||||
MatrixClientPeg.get().on('crypto.keyBackupStatus', this._onKeyBackupStatus);
|
MatrixClientPeg.get().on('crypto.keyBackupStatus', this._onKeyBackupStatus);
|
||||||
|
|
|
@ -87,7 +87,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this._refreshFromServer();
|
this._refreshFromServer();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ export default class HelpUserSettingsTab extends React.Component {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount(): void {
|
componentDidMount(): void {
|
||||||
PlatformPeg.get().getAppVersion().then((ver) => this.setState({vectorVersion: ver})).catch((e) => {
|
PlatformPeg.get().getAppVersion().then((ver) => this.setState({vectorVersion: ver})).catch((e) => {
|
||||||
console.error("Error getting vector version: ", e);
|
console.error("Error getting vector version: ", e);
|
||||||
});
|
});
|
||||||
|
|
|
@ -81,7 +81,7 @@ export default class PreferencesUserSettingsTab extends React.Component {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentWillMount(): void {
|
async componentDidMount(): void {
|
||||||
const platform = PlatformPeg.get();
|
const platform = PlatformPeg.get();
|
||||||
|
|
||||||
const autoLaunchSupported = await platform.supportsAutoLaunch();
|
const autoLaunchSupported = await platform.supportsAutoLaunch();
|
||||||
|
|
|
@ -33,6 +33,7 @@ export default class VerificationShowSas extends React.Component {
|
||||||
onCancel: PropTypes.func.isRequired,
|
onCancel: PropTypes.func.isRequired,
|
||||||
sas: PropTypes.object.isRequired,
|
sas: PropTypes.object.isRequired,
|
||||||
isSelf: PropTypes.bool,
|
isSelf: PropTypes.bool,
|
||||||
|
inDialog: PropTypes.bool, // whether this component is being shown in a dialog and to use DialogButtons
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -112,7 +113,7 @@ export default class VerificationShowSas extends React.Component {
|
||||||
text = _t("Cancelling…");
|
text = _t("Cancelling…");
|
||||||
}
|
}
|
||||||
confirm = <PendingActionSpinner text={text} />;
|
confirm = <PendingActionSpinner text={text} />;
|
||||||
} else {
|
} else if (this.props.inDialog) {
|
||||||
// FIXME: stop using DialogButtons here once this component is only used in the right panel verification
|
// FIXME: stop using DialogButtons here once this component is only used in the right panel verification
|
||||||
confirm = <DialogButtons
|
confirm = <DialogButtons
|
||||||
primaryButton={_t("They match")}
|
primaryButton={_t("They match")}
|
||||||
|
@ -122,6 +123,15 @@ export default class VerificationShowSas extends React.Component {
|
||||||
onCancel={this.onDontMatchClick}
|
onCancel={this.onDontMatchClick}
|
||||||
cancelButtonClass="mx_UserInfo_wideButton"
|
cancelButtonClass="mx_UserInfo_wideButton"
|
||||||
/>;
|
/>;
|
||||||
|
} else {
|
||||||
|
confirm = <React.Fragment>
|
||||||
|
<AccessibleButton onClick={this.onMatchClick} kind="primary">
|
||||||
|
{ _t("They match") }
|
||||||
|
</AccessibleButton>
|
||||||
|
<AccessibleButton onClick={this.onDontMatchClick} kind="danger">
|
||||||
|
{ _t("They don't match") }
|
||||||
|
</AccessibleButton>
|
||||||
|
</React.Fragment>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="mx_VerificationShowSas">
|
return <div className="mx_VerificationShowSas">
|
||||||
|
|
|
@ -40,7 +40,7 @@ export default createReactClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentDidMount: function() {
|
||||||
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
|
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
|
||||||
this.dispatcherRef = dis.register(this._onAction);
|
this.dispatcherRef = dis.register(this._onAction);
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
{
|
{
|
||||||
"This email address is already in use": "This email address is already in use",
|
"This email address is already in use": "This email address is already in use",
|
||||||
"This phone number is already in use": "This phone number is already in use",
|
"This phone number is already in use": "This phone number is already in use",
|
||||||
|
"Use Single Sign On to continue": "Use Single Sign On to continue",
|
||||||
|
"Confirm adding this email address by using Single Sign On to prove your identity.": "Confirm adding this email address by using Single Sign On to prove your identity.",
|
||||||
|
"Single Sign On": "Single Sign On",
|
||||||
|
"Confirm adding email": "Confirm adding email",
|
||||||
|
"Click the button below to confirm adding this email address.": "Click the button below to confirm adding this email address.",
|
||||||
|
"Confirm": "Confirm",
|
||||||
"Add Email Address": "Add Email Address",
|
"Add Email Address": "Add Email Address",
|
||||||
"Failed to verify email address: make sure you clicked the link in the email": "Failed to verify email address: make sure you clicked the link in the email",
|
"Failed to verify email address: make sure you clicked the link in the email": "Failed to verify email address: make sure you clicked the link in the email",
|
||||||
|
"Confirm adding this phone number by using Single Sign On to prove your identity.": "Confirm adding this phone number by using Single Sign On to prove your identity.",
|
||||||
|
"Confirm adding phone number": "Confirm adding phone number",
|
||||||
|
"Click the button below to confirm adding this phone number.": "Click the button below to confirm adding this phone number.",
|
||||||
"Add Phone Number": "Add Phone Number",
|
"Add Phone Number": "Add Phone Number",
|
||||||
"The platform you're on": "The platform you're on",
|
"The platform you're on": "The platform you're on",
|
||||||
"The version of Riot": "The version of Riot",
|
"The version of Riot": "The version of Riot",
|
||||||
|
@ -599,6 +608,10 @@
|
||||||
"up to date": "up to date",
|
"up to date": "up to date",
|
||||||
"Your homeserver does not support session management.": "Your homeserver does not support session management.",
|
"Your homeserver does not support session management.": "Your homeserver does not support session management.",
|
||||||
"Unable to load session list": "Unable to load session list",
|
"Unable to load session list": "Unable to load session list",
|
||||||
|
"Confirm deleting these sessions by using Single Sign On to prove your identity.": "Confirm deleting these sessions by using Single Sign On to prove your identity.",
|
||||||
|
"Confirm deleting these sessions": "Confirm deleting these sessions",
|
||||||
|
"Click the button below to confirm deleting these sessions.": "Click the button below to confirm deleting these sessions.",
|
||||||
|
"Delete sessions": "Delete sessions",
|
||||||
"Authentication": "Authentication",
|
"Authentication": "Authentication",
|
||||||
"Delete %(count)s sessions|other": "Delete %(count)s sessions",
|
"Delete %(count)s sessions|other": "Delete %(count)s sessions",
|
||||||
"Delete %(count)s sessions|one": "Delete %(count)s session",
|
"Delete %(count)s sessions|one": "Delete %(count)s session",
|
||||||
|
@ -1862,7 +1875,6 @@
|
||||||
"Use lowercase letters, numbers, dashes and underscores only": "Use lowercase letters, numbers, dashes and underscores only",
|
"Use lowercase letters, numbers, dashes and underscores only": "Use lowercase letters, numbers, dashes and underscores only",
|
||||||
"Enter username": "Enter username",
|
"Enter username": "Enter username",
|
||||||
"Email (optional)": "Email (optional)",
|
"Email (optional)": "Email (optional)",
|
||||||
"Confirm": "Confirm",
|
|
||||||
"Phone (optional)": "Phone (optional)",
|
"Phone (optional)": "Phone (optional)",
|
||||||
"Create your Matrix account on %(serverName)s": "Create your Matrix account on %(serverName)s",
|
"Create your Matrix account on %(serverName)s": "Create your Matrix account on %(serverName)s",
|
||||||
"Create your Matrix account on <underlinedServerName />": "Create your Matrix account on <underlinedServerName />",
|
"Create your Matrix account on <underlinedServerName />": "Create your Matrix account on <underlinedServerName />",
|
||||||
|
|
|
@ -109,6 +109,7 @@ export default class EventIndex extends EventEmitter {
|
||||||
roomId: room.roomId,
|
roomId: room.roomId,
|
||||||
token: token,
|
token: token,
|
||||||
direction: "b",
|
direction: "b",
|
||||||
|
fullCrawl: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const forwardCheckpoint = {
|
const forwardCheckpoint = {
|
||||||
|
|
|
@ -30,26 +30,6 @@ import ActiveWidgetStore from "../stores/ActiveWidgetStore";
|
||||||
import {IntegrationManagers} from "../integrations/IntegrationManagers";
|
import {IntegrationManagers} from "../integrations/IntegrationManagers";
|
||||||
import {Capability} from "../widgets/WidgetApi";
|
import {Capability} from "../widgets/WidgetApi";
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes a URI according to a set of template variables. Variables will be
|
|
||||||
* passed through encodeURIComponent.
|
|
||||||
* @param {string} pathTemplate The path with template variables e.g. '/foo/$bar'.
|
|
||||||
* @param {Object} variables The key/value pairs to replace the template
|
|
||||||
* variables with. E.g. { '$bar': 'baz' }.
|
|
||||||
* @return {string} The result of replacing all template variables e.g. '/foo/baz'.
|
|
||||||
*/
|
|
||||||
function encodeUri(pathTemplate, variables) {
|
|
||||||
for (const key in variables) {
|
|
||||||
if (!variables.hasOwnProperty(key)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
pathTemplate = pathTemplate.replace(
|
|
||||||
key, encodeURIComponent(variables[key]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return pathTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class WidgetUtils {
|
export default class WidgetUtils {
|
||||||
/* Returns true if user is able to send state events to modify widgets in this room
|
/* Returns true if user is able to send state events to modify widgets in this room
|
||||||
* (Does not apply to non-room-based / user widgets)
|
* (Does not apply to non-room-based / user widgets)
|
||||||
|
@ -402,18 +382,6 @@ export default class WidgetUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
static makeAppConfig(appId, app, senderUserId, roomId, eventId) {
|
static makeAppConfig(appId, app, senderUserId, roomId, eventId) {
|
||||||
const myUserId = MatrixClientPeg.get().credentials.userId;
|
|
||||||
const user = MatrixClientPeg.get().getUser(myUserId);
|
|
||||||
const params = {
|
|
||||||
'$matrix_user_id': myUserId,
|
|
||||||
'$matrix_room_id': roomId,
|
|
||||||
'$matrix_display_name': user ? user.displayName : myUserId,
|
|
||||||
'$matrix_avatar_url': user ? MatrixClientPeg.get().mxcUrlToHttp(user.avatarUrl) : '',
|
|
||||||
|
|
||||||
// TODO: Namespace themes through some standard
|
|
||||||
'$theme': SettingsStore.getValue("theme"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!senderUserId) {
|
if (!senderUserId) {
|
||||||
throw new Error("Widgets must be created by someone - provide a senderUserId");
|
throw new Error("Widgets must be created by someone - provide a senderUserId");
|
||||||
}
|
}
|
||||||
|
@ -423,32 +391,6 @@ export default class WidgetUtils {
|
||||||
app.eventId = eventId;
|
app.eventId = eventId;
|
||||||
app.name = app.name || app.type;
|
app.name = app.name || app.type;
|
||||||
|
|
||||||
if (app.type === 'jitsi') {
|
|
||||||
console.log("Replacing Jitsi widget URL with local wrapper");
|
|
||||||
if (!app.data || !app.data.conferenceId) {
|
|
||||||
// Assumed to be a v1 widget: add a data object for visibility on the wrapper
|
|
||||||
// TODO: Remove this once mobile supports v2 widgets
|
|
||||||
console.log("Replacing v1 Jitsi widget with v2 equivalent");
|
|
||||||
const parsed = new URL(app.url);
|
|
||||||
app.data = {
|
|
||||||
conferenceId: parsed.searchParams.get("confId"),
|
|
||||||
domain: "jitsi.riot.im", // v1 widgets have this hardcoded
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
app.url = WidgetUtils.getLocalJitsiWrapperUrl({forLocalRender: true});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (app.data) {
|
|
||||||
Object.keys(app.data).forEach((key) => {
|
|
||||||
params['$' + key] = app.data[key];
|
|
||||||
});
|
|
||||||
|
|
||||||
app.waitForIframeLoad = (app.data.waitForIframeLoad === 'false' ? false : true);
|
|
||||||
}
|
|
||||||
|
|
||||||
app.url = encodeUri(app.url, params);
|
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,7 +404,6 @@ export default class WidgetUtils {
|
||||||
// widgets from at all, but it probably makes sense for sanity.
|
// widgets from at all, but it probably makes sense for sanity.
|
||||||
if (appType === 'jitsi') {
|
if (appType === 'jitsi') {
|
||||||
capWhitelist.push(Capability.AlwaysOnScreen);
|
capWhitelist.push(Capability.AlwaysOnScreen);
|
||||||
capWhitelist.push(Capability.GetRiotWebConfig);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return capWhitelist;
|
return capWhitelist;
|
||||||
|
|
|
@ -99,7 +99,7 @@ export async function legacyVerifyUser(user) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
const verificationRequestPromise = cli.beginKeyVerification(user.userId);
|
const verificationRequestPromise = cli.requestVerification(user.userId);
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: "set_right_panel_phase",
|
action: "set_right_panel_phase",
|
||||||
phase: RIGHT_PANEL_PHASES.EncryptionPanel,
|
phase: RIGHT_PANEL_PHASES.EncryptionPanel,
|
||||||
|
|
|
@ -23,7 +23,6 @@ export enum Capability {
|
||||||
Screenshot = "m.capability.screenshot",
|
Screenshot = "m.capability.screenshot",
|
||||||
Sticker = "m.sticker",
|
Sticker = "m.sticker",
|
||||||
AlwaysOnScreen = "m.always_on_screen",
|
AlwaysOnScreen = "m.always_on_screen",
|
||||||
GetRiotWebConfig = "im.vector.web.riot_config",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum KnownWidgetActions {
|
export enum KnownWidgetActions {
|
||||||
|
@ -34,7 +33,6 @@ export enum KnownWidgetActions {
|
||||||
UpdateVisibility = "visibility",
|
UpdateVisibility = "visibility",
|
||||||
ReceiveOpenIDCredentials = "openid_credentials",
|
ReceiveOpenIDCredentials = "openid_credentials",
|
||||||
SetAlwaysOnScreen = "set_always_on_screen",
|
SetAlwaysOnScreen = "set_always_on_screen",
|
||||||
GetRiotWebConfig = "im.vector.web.riot_config",
|
|
||||||
ClientReady = "im.vector.ready",
|
ClientReady = "im.vector.ready",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,12 +155,4 @@ export class WidgetApi {
|
||||||
resolve(); // SetAlwaysOnScreen is currently fire-and-forget, but that could change.
|
resolve(); // SetAlwaysOnScreen is currently fire-and-forget, but that could change.
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getRiotConfig(): Promise<any> {
|
|
||||||
return new Promise<any>(resolve => {
|
|
||||||
this.callAction(KnownWidgetActions.GetRiotWebConfig, {}, response => {
|
|
||||||
resolve(response.response.config);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue