Merge branch 'develop' into bwindels/verification-right-panel

This commit is contained in:
Travis Ralston 2020-01-16 13:23:32 -07:00
commit d1fcef1211
515 changed files with 9064 additions and 7392 deletions

View file

@ -1,6 +1,7 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -19,7 +20,7 @@ import { _t } from '../../../languageHandler';
import React from 'react';
import createReactClass from 'create-react-class';
module.exports = createReactClass({
export default createReactClass({
displayName: 'AuthFooter',
render: function() {

View file

@ -17,9 +17,9 @@ limitations under the License.
import React from 'react';
import createReactClass from 'create-react-class';
import sdk from '../../../index';
import * as sdk from '../../../index';
module.exports = createReactClass({
export default createReactClass({
displayName: 'AuthHeader',
render: function() {

View file

@ -1,6 +1,7 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -16,22 +17,21 @@ limitations under the License.
*/
import React from 'react';
import createReactClass from 'create-react-class';
import sdk from '../../../index';
import * as sdk from '../../../index';
import {replaceableComponent} from "../../../utils/replaceableComponent";
module.exports = createReactClass({
displayName: 'AuthPage',
render: function() {
@replaceableComponent("views.auth.AuthPage")
export default class AuthPage extends React.PureComponent {
render() {
const AuthFooter = sdk.getComponent('auth.AuthFooter');
return (
<div className="mx_AuthPage">
<div className="mx_AuthPage_modal">
{ this.props.children }
{this.props.children}
</div>
<AuthFooter />
</div>
);
},
});
}
}

View file

@ -24,7 +24,7 @@ const DIV_ID = 'mx_recaptcha';
/**
* A pure UI component which displays a captcha form.
*/
module.exports = createReactClass({
export default createReactClass({
displayName: 'CaptchaForm',
propTypes: {

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { COUNTRIES } from '../../../phonenumber';
import SdkConfig from "../../../SdkConfig";

View file

@ -19,7 +19,7 @@ import React from 'react';
import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
module.exports = createReactClass({
export default createReactClass({
displayName: 'CustomServerDialog',
render: function() {

View file

@ -22,7 +22,7 @@ import PropTypes from 'prop-types';
import url from 'url';
import classnames from 'classnames';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import SettingsStore from "../../../settings/SettingsStore";

View file

@ -18,7 +18,7 @@ import SdkConfig from "../../../SdkConfig";
import {getCurrentLanguage} from "../../../languageHandler";
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
import PlatformPeg from "../../../PlatformPeg";
import sdk from '../../../index';
import * as sdk from '../../../index';
import React from 'react';
function onChange(newLang) {

View file

@ -15,7 +15,7 @@ limitations under the License.
*/
import React from 'react';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils";
import SdkConfig from "../../../SdkConfig";

View file

@ -19,7 +19,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import SdkConfig from '../../../SdkConfig';
import {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils";

View file

@ -20,8 +20,8 @@ limitations under the License.
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import Email from '../../../email';
import * as sdk from '../../../index';
import * as Email from '../../../email';
import { looksValid as phoneNumberLooksValid } from '../../../phonenumber';
import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';
@ -41,7 +41,7 @@ const PASSWORD_MIN_SCORE = 3; // safely unguessable: moderate protection from of
/**
* A pure UI component which displays a registration form.
*/
module.exports = createReactClass({
export default createReactClass({
displayName: 'RegistrationForm',
propTypes: {

View file

@ -19,12 +19,12 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import Modal from '../../../Modal';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils";
import AutoDiscoveryUtils from "../../../utils/AutoDiscoveryUtils";
import SdkConfig from "../../../SdkConfig";
import { createClient } from 'matrix-js-sdk/lib/matrix';
import { createClient } from 'matrix-js-sdk/src/matrix';
import classNames from 'classnames';
/*

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
import sdk from '../../../index';
import * as sdk from '../../../index';
import classnames from 'classnames';
import {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils";
import {makeType} from "../../../utils/TypeUtils";

View file

@ -16,7 +16,7 @@ limitations under the License.
import React from 'react';
import {_t} from "../../../languageHandler";
import sdk from "../../../index";
import * as sdk from "../../../index";
import PropTypes from "prop-types";
import {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils";

View file

@ -15,12 +15,12 @@ limitations under the License.
*/
import React from 'react';
import sdk from '../../../index';
import * as sdk from '../../../index';
import SdkConfig from '../../../SdkConfig';
import AuthPage from "./AuthPage";
export default class Welcome extends React.PureComponent {
render() {
const AuthPage = sdk.getComponent("auth.AuthPage");
const EmbeddedPage = sdk.getComponent('structures.EmbeddedPage');
const LanguageSelector = sdk.getComponent('auth.LanguageSelector');

View file

@ -2,6 +2,7 @@
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2018 New Vector Ltd
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -19,12 +20,12 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import AvatarLogic from '../../../Avatar';
import * as AvatarLogic from '../../../Avatar';
import SettingsStore from "../../../settings/SettingsStore";
import AccessibleButton from '../elements/AccessibleButton';
import MatrixClientContext from "../../../contexts/MatrixClientContext";
module.exports = createReactClass({
export default createReactClass({
displayName: 'BaseAvatar',
propTypes: {

View file

@ -17,8 +17,8 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import sdk from '../../../index';
import MatrixClientPeg from '../../../MatrixClientPeg';
import * as sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
export default createReactClass({
displayName: 'GroupAvatar',

View file

@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -17,11 +18,11 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
const Avatar = require('../../../Avatar');
const sdk = require("../../../index");
const dispatcher = require("../../../dispatcher");
import * as Avatar from '../../../Avatar';
import * as sdk from "../../../index";
import dis from "../../../dispatcher";
module.exports = createReactClass({
export default createReactClass({
displayName: 'MemberAvatar',
propTypes: {
@ -55,7 +56,7 @@ module.exports = createReactClass({
},
_getState: function(props) {
if (props.member) {
if (props.member && props.member.name) {
return {
name: props.member.name,
title: props.title || props.member.userId,
@ -82,7 +83,7 @@ module.exports = createReactClass({
if (viewUserOnClick) {
onClick = () => {
dispatcher.dispatch({
dis.dispatch({
action: 'view_user',
member: this.props.member,
});

View file

@ -16,7 +16,7 @@ limitations under the License.
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
import MatrixClientPeg from '../../../MatrixClientPeg';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import {_t} from "../../../languageHandler";
import MemberAvatar from '../avatars/MemberAvatar';
import classNames from 'classnames';

View file

@ -16,13 +16,13 @@ limitations under the License.
import React from "react";
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import {ContentRepo} from "matrix-js-sdk";
import MatrixClientPeg from "../../../MatrixClientPeg";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import Modal from '../../../Modal';
import sdk from "../../../index";
import Avatar from '../../../Avatar';
import * as sdk from "../../../index";
import * as Avatar from '../../../Avatar';
import {getHttpUriForMxc} from "matrix-js-sdk/src/content-repo";
module.exports = createReactClass({
export default createReactClass({
displayName: 'RoomAvatar',
// Room may be left unset here, but if it is,
@ -82,7 +82,7 @@ module.exports = createReactClass({
getImageUrls: function(props) {
return [
ContentRepo.getHttpUriForMxc(
getHttpUriForMxc(
MatrixClientPeg.get().getHomeserverUrl(),
props.oobData.avatarUrl,
Math.floor(props.width * window.devicePixelRatio),

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import Modal from '../../../Modal';
import {Group} from 'matrix-js-sdk';

View file

@ -22,9 +22,9 @@ import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import {EventStatus} from 'matrix-js-sdk';
import MatrixClientPeg from '../../../MatrixClientPeg';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import dis from '../../../dispatcher';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import Modal from '../../../Modal';
import Resend from '../../../Resend';
@ -37,7 +37,7 @@ function canCancel(eventStatus) {
return eventStatus === EventStatus.QUEUED || eventStatus === EventStatus.NOT_SENT;
}
module.exports = createReactClass({
export default createReactClass({
displayName: 'MessageContextMenu',
propTypes: {
@ -422,7 +422,7 @@ module.exports = createReactClass({
</MenuItem>
);
if (this.props.eventTileOps && this.props.eventTileOps.getInnerText) {
if (this.props.eventTileOps) { // this event is rendered using TextualBody
quoteButton = (
<MenuItem className="mx_MessageContextMenu_field" onClick={this.onQuoteClick}>
{ _t('Quote') }

View file

@ -21,9 +21,9 @@ import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import classNames from 'classnames';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t, _td } from '../../../languageHandler';
import MatrixClientPeg from '../../../MatrixClientPeg';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import dis from '../../../dispatcher';
import DMRoomMap from '../../../utils/DMRoomMap';
import * as Rooms from '../../../Rooms';
@ -63,7 +63,7 @@ const NotifOption = ({active, onClick, src, label}) => {
);
};
module.exports = createReactClass({
export default createReactClass({
displayName: 'RoomTileContextMenu',
propTypes: {

View file

@ -17,8 +17,8 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
import MatrixClientPeg from '../../../MatrixClientPeg';
import sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import * as sdk from '../../../index';
import AccessibleButton from '../elements/AccessibleButton';
export default class StatusMessageContextMenu extends React.Component {

View file

@ -20,7 +20,7 @@ import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
import dis from '../../../dispatcher';
import TagOrderActions from '../../../actions/TagOrderActions';
import sdk from '../../../index';
import * as sdk from '../../../index';
import {MenuItem} from "../../structures/ContextMenu";
import MatrixClientContext from "../../../contexts/MatrixClientContext";

View file

@ -23,9 +23,9 @@ import LogoutDialog from "../dialogs/LogoutDialog";
import Modal from "../../../Modal";
import SdkConfig from '../../../SdkConfig';
import { getHostingLink } from '../../../utils/HostingLink';
import MatrixClientPeg from '../../../MatrixClientPeg';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import {MenuItem} from "../../structures/ContextMenu";
import sdk from "../../../index";
import * as sdk from "../../../index";
export class TopLeftMenu extends React.Component {
static propTypes = {

View file

@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -19,7 +20,7 @@ import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
module.exports = createReactClass({
export default createReactClass({
displayName: 'CreateRoomButton',
propTypes: {
onCreateRoom: PropTypes.func,

View file

@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -25,7 +26,7 @@ const Presets = {
Custom: "custom",
};
module.exports = createReactClass({
export default createReactClass({
displayName: 'CreateRoomPresets',
propTypes: {
onChange: PropTypes.func,

View file

@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -19,7 +20,7 @@ import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
module.exports = createReactClass({
export default createReactClass({
displayName: 'RoomAlias',
propTypes: {
// Specifying a homeserver will make magical things happen when you,

View file

@ -22,8 +22,8 @@ import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import { _t, _td } from '../../../languageHandler';
import sdk from '../../../index';
import MatrixClientPeg from '../../../MatrixClientPeg';
import * as sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import dis from '../../../dispatcher';
import { addressTypes, getAddressType } from '../../../UserAddress.js';
import GroupStore from '../../../stores/GroupStore';
@ -44,7 +44,7 @@ const addressTypeName = {
};
module.exports = createReactClass({
export default createReactClass({
displayName: "AddressPickerDialog",
propTypes: {

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import {SettingLevel} from "../../../settings/SettingsStore";
import SettingsStore from "../../../settings/SettingsStore";

View file

@ -24,7 +24,7 @@ import classNames from 'classnames';
import { Key } from '../../../Keyboard';
import AccessibleButton from '../elements/AccessibleButton';
import MatrixClientPeg from '../../../MatrixClientPeg';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import { _t } from "../../../languageHandler";
import MatrixClientContext from "../../../contexts/MatrixClientContext";

View file

@ -19,7 +19,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import SdkConfig from '../../../SdkConfig';
import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';

View file

@ -17,7 +17,7 @@ Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import request from 'browser-request';
import { _t } from '../../../languageHandler';

View file

@ -15,7 +15,7 @@ limitations under the License.
*/
import React from 'react';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
/*

View file

@ -16,7 +16,7 @@ limitations under the License.
import React from 'react';
import createReactClass from 'create-react-class';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
/*

View file

@ -18,7 +18,7 @@ import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import { MatrixClient } from 'matrix-js-sdk';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import { GroupMemberType } from '../../../groups';

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import {_t} from "../../../languageHandler";
import sdk from "../../../index";
import * as sdk from "../../../index";
export default class ConfirmWipeDeviceDialog extends React.Component {
static propTypes = {

View file

@ -17,10 +17,10 @@ limitations under the License.
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import dis from '../../../dispatcher';
import { _t } from '../../../languageHandler';
import MatrixClientPeg from '../../../MatrixClientPeg';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
export default createReactClass({
displayName: 'CreateGroupDialog',

View file

@ -17,11 +17,11 @@ limitations under the License.
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import SdkConfig from '../../../SdkConfig';
import withValidation from '../elements/Validation';
import { _t } from '../../../languageHandler';
import MatrixClientPeg from '../../../MatrixClientPeg';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import {Key} from "../../../Keyboard";
export default createReactClass({

View file

@ -15,7 +15,7 @@ limitations under the License.
*/
import React from 'react';
import sdk from '../../../index';
import * as sdk from '../../../index';
import dis from '../../../dispatcher';
import { _t } from '../../../languageHandler';
import Modal from '../../../Modal';

View file

@ -0,0 +1,777 @@
/*
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
import {_t} from "../../../languageHandler";
import * as sdk from "../../../index";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import {makeUserPermalink} from "../../../utils/permalinks/Permalinks";
import DMRoomMap from "../../../utils/DMRoomMap";
import {RoomMember} from "matrix-js-sdk/src/matrix";
import SdkConfig from "../../../SdkConfig";
import {getHttpUriForMxc} from "matrix-js-sdk/src/content-repo";
import * as Email from "../../../email";
import {getDefaultIdentityServerUrl, useDefaultIdentityServer} from "../../../utils/IdentityServerUtils";
import {abbreviateUrl} from "../../../utils/UrlUtils";
import dis from "../../../dispatcher";
import IdentityAuthClient from "../../../IdentityAuthClient";
import Modal from "../../../Modal";
import {humanizeTime} from "../../../utils/humanize";
// TODO: [TravisR] Make this generic for all kinds of invites
const INITIAL_ROOMS_SHOWN = 3; // Number of rooms to show at first
const INCREMENT_ROOMS_SHOWN = 5; // Number of rooms to add when 'show more' is clicked
// This is the interface that is expected by various components in this file. It is a bit
// awkward because it also matches the RoomMember class from the js-sdk with some extra support
// for 3PIDs/email addresses.
//
// XXX: We should use TypeScript interfaces instead of this weird "abstract" class.
class Member {
/**
* The display name of this Member. For users this should be their profile's display
* name or user ID if none set. For 3PIDs this should be the 3PID address (email).
*/
get name(): string { throw new Error("Member class not implemented"); }
/**
* The ID of this Member. For users this should be their user ID. For 3PIDs this should
* be the 3PID address (email).
*/
get userId(): string { throw new Error("Member class not implemented"); }
/**
* Gets the MXC URL of this Member's avatar. For users this should be their profile's
* avatar MXC URL or null if none set. For 3PIDs this should always be null.
*/
getMxcAvatarUrl(): string { throw new Error("Member class not implemented"); }
}
class DirectoryMember extends Member {
_userId: string;
_displayName: string;
_avatarUrl: string;
constructor(userDirResult: {user_id: string, display_name: string, avatar_url: string}) {
super();
this._userId = userDirResult.user_id;
this._displayName = userDirResult.display_name;
this._avatarUrl = userDirResult.avatar_url;
}
// These next class members are for the Member interface
get name(): string {
return this._displayName || this._userId;
}
get userId(): string {
return this._userId;
}
getMxcAvatarUrl(): string {
return this._avatarUrl;
}
}
class ThreepidMember extends Member {
_id: string;
constructor(id: string) {
super();
this._id = id;
}
// This is a getter that would be falsey on all other implementations. Until we have
// better type support in the react-sdk we can use this trick to determine the kind
// of 3PID we're dealing with, if any.
get isEmail(): boolean {
return this._id.includes('@');
}
// These next class members are for the Member interface
get name(): string {
return this._id;
}
get userId(): string {
return this._id;
}
getMxcAvatarUrl(): string {
return null;
}
}
class DMUserTile extends React.PureComponent {
static propTypes = {
member: PropTypes.object.isRequired, // Should be a Member (see interface above)
onRemove: PropTypes.func.isRequired, // takes 1 argument, the member being removed
};
_onRemove = (e) => {
// Stop the browser from highlighting text
e.preventDefault();
e.stopPropagation();
this.props.onRemove(this.props.member);
};
render() {
const BaseAvatar = sdk.getComponent("views.avatars.BaseAvatar");
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
const avatarSize = 20;
const avatar = this.props.member.isEmail
? <img
className='mx_DMInviteDialog_userTile_avatar mx_DMInviteDialog_userTile_threepidAvatar'
src={require("../../../../res/img/icon-email-pill-avatar.svg")}
width={avatarSize} height={avatarSize} />
: <BaseAvatar
className='mx_DMInviteDialog_userTile_avatar'
url={getHttpUriForMxc(
MatrixClientPeg.get().getHomeserverUrl(), this.props.member.getMxcAvatarUrl(),
avatarSize, avatarSize, "crop")}
name={this.props.member.name}
idName={this.props.member.userId}
width={avatarSize}
height={avatarSize} />;
return (
<span className='mx_DMInviteDialog_userTile'>
<span className='mx_DMInviteDialog_userTile_pill'>
{avatar}
<span className='mx_DMInviteDialog_userTile_name'>{this.props.member.name}</span>
</span>
<AccessibleButton
className='mx_DMInviteDialog_userTile_remove'
onClick={this._onRemove}
>
<img src={require("../../../../res/img/icon-pill-remove.svg")} alt={_t('Remove')} width={8} height={8} />
</AccessibleButton>
</span>
);
}
}
class DMRoomTile extends React.PureComponent {
static propTypes = {
member: PropTypes.object.isRequired, // Should be a Member (see interface above)
lastActiveTs: PropTypes.number,
onToggle: PropTypes.func.isRequired, // takes 1 argument, the member being toggled
highlightWord: PropTypes.string,
isSelected: PropTypes.bool,
};
_onClick = (e) => {
// Stop the browser from highlighting text
e.preventDefault();
e.stopPropagation();
this.props.onToggle(this.props.member);
};
_highlightName(str: string) {
if (!this.props.highlightWord) return str;
// We convert things to lowercase for index searching, but pull substrings from
// the submitted text to preserve case. Note: we don't need to htmlEntities the
// string because React will safely encode the text for us.
const lowerStr = str.toLowerCase();
const filterStr = this.props.highlightWord.toLowerCase();
const result = [];
let i = 0;
let ii;
while ((ii = lowerStr.indexOf(filterStr, i)) >= 0) {
// Push any text we missed (first bit/middle of text)
if (ii > i) {
// Push any text we aren't highlighting (middle of text match, or beginning of text)
result.push(<span key={i + 'begin'}>{str.substring(i, ii)}</span>);
}
i = ii; // copy over ii only if we have a match (to preserve i for end-of-text matching)
// Highlight the word the user entered
const substr = str.substring(i, filterStr.length + i);
result.push(<span className='mx_DMInviteDialog_roomTile_highlight' key={i + 'bold'}>{substr}</span>);
i += substr.length;
}
// Push any text we missed (end of text)
if (i < (str.length - 1)) {
result.push(<span key={i + 'end'}>{str.substring(i)}</span>);
}
return result;
}
render() {
const BaseAvatar = sdk.getComponent("views.avatars.BaseAvatar");
let timestamp = null;
if (this.props.lastActiveTs) {
const humanTs = humanizeTime(this.props.lastActiveTs);
timestamp = <span className='mx_DMInviteDialog_roomTile_time'>{humanTs}</span>;
}
const avatarSize = 36;
const avatar = this.props.member.isEmail
? <img
src={require("../../../../res/img/icon-email-pill-avatar.svg")}
width={avatarSize} height={avatarSize} />
: <BaseAvatar
url={getHttpUriForMxc(
MatrixClientPeg.get().getHomeserverUrl(), this.props.member.getMxcAvatarUrl(),
avatarSize, avatarSize, "crop")}
name={this.props.member.name}
idName={this.props.member.userId}
width={avatarSize}
height={avatarSize} />;
let checkmark = null;
if (this.props.isSelected) {
// To reduce flickering we put the 'selected' room tile above the real avatar
checkmark = <div className='mx_DMInviteDialog_roomTile_selected' />;
}
// To reduce flickering we put the checkmark on top of the actual avatar (prevents
// the browser from reloading the image source when the avatar remounts).
const stackedAvatar = (
<span className='mx_DMInviteDialog_roomTile_avatarStack'>
{avatar}
{checkmark}
</span>
);
return (
<div className='mx_DMInviteDialog_roomTile' onClick={this._onClick}>
{stackedAvatar}
<span className='mx_DMInviteDialog_roomTile_name'>{this._highlightName(this.props.member.name)}</span>
<span className='mx_DMInviteDialog_roomTile_userId'>{this._highlightName(this.props.member.userId)}</span>
{timestamp}
</div>
);
}
}
export default class DMInviteDialog extends React.PureComponent {
static propTypes = {
// Takes an array of user IDs/emails to invite.
onFinished: PropTypes.func.isRequired,
};
_debounceTimer: number = null;
_editorRef: any = null;
constructor() {
super();
this.state = {
targets: [], // array of Member objects (see interface above)
filterText: "",
recents: this._buildRecents(),
numRecentsShown: INITIAL_ROOMS_SHOWN,
suggestions: this._buildSuggestions(),
numSuggestionsShown: INITIAL_ROOMS_SHOWN,
serverResultsMixin: [], // { user: DirectoryMember, userId: string }[], like recents and suggestions
threepidResultsMixin: [], // { user: ThreepidMember, userId: string}[], like recents and suggestions
canUseIdentityServer: !!MatrixClientPeg.get().getIdentityServerUrl(),
tryingIdentityServer: false,
};
this._editorRef = createRef();
}
_buildRecents(): {userId: string, user: RoomMember, lastActive: number} {
const rooms = DMRoomMap.shared().getUniqueRoomsWithIndividuals();
const recents = [];
for (const userId in rooms) {
const room = rooms[userId];
const member = room.getMember(userId);
if (!member) continue; // just skip people who don't have memberships for some reason
const lastEventTs = room.timeline && room.timeline.length
? room.timeline[room.timeline.length - 1].getTs()
: 0;
if (!lastEventTs) continue; // something weird is going on with this room
recents.push({userId, user: member, lastActive: lastEventTs});
}
// Sort the recents by last active to save us time later
recents.sort((a, b) => b.lastActive - a.lastActive);
return recents;
}
_buildSuggestions(): {userId: string, user: RoomMember} {
const maxConsideredMembers = 200;
const client = MatrixClientPeg.get();
const excludedUserIds = [client.getUserId(), SdkConfig.get()['welcomeUserId']];
const joinedRooms = client.getRooms()
.filter(r => r.getMyMembership() === 'join')
.filter(r => r.getJoinedMemberCount() <= maxConsideredMembers);
// Generates { userId: {member, rooms[]} }
const memberRooms = joinedRooms.reduce((members, room) => {
// Filter out DMs (we'll handle these in the recents section)
if (DMRoomMap.shared().getUserIdForRoomId(room.roomId)) {
return members; // Do nothing
}
const joinedMembers = room.getJoinedMembers().filter(u => !excludedUserIds.includes(u.userId));
for (const member of joinedMembers) {
if (!members[member.userId]) {
members[member.userId] = {
member: member,
// Track the room size of the 'picked' member so we can use the profile of
// the smallest room (likely a DM).
pickedMemberRoomSize: room.getJoinedMemberCount(),
rooms: [],
};
}
members[member.userId].rooms.push(room);
if (room.getJoinedMemberCount() < members[member.userId].pickedMemberRoomSize) {
members[member.userId].member = member;
members[member.userId].pickedMemberRoomSize = room.getJoinedMemberCount();
}
}
return members;
}, {});
// Generates { userId: {member, numRooms, score} }
const memberScores = Object.values(memberRooms).reduce((scores, entry) => {
const numMembersTotal = entry.rooms.reduce((c, r) => c + r.getJoinedMemberCount(), 0);
const maxRange = maxConsideredMembers * entry.rooms.length;
scores[entry.member.userId] = {
member: entry.member,
numRooms: entry.rooms.length,
score: Math.max(0, Math.pow(1 - (numMembersTotal / maxRange), 5)),
};
return scores;
}, {});
const members = Object.values(memberScores);
members.sort((a, b) => {
if (a.score === b.score) {
if (a.numRooms === b.numRooms) {
return a.member.userId.localeCompare(b.member.userId);
}
return b.numRooms - a.numRooms;
}
return b.score - a.score;
});
return members.map(m => ({userId: m.member.userId, user: m.member}));
}
_startDm = () => {
this.props.onFinished(this.state.targets.map(t => t.userId));
};
_cancel = () => {
this.props.onFinished([]);
};
_updateFilter = (e) => {
const term = e.target.value;
this.setState({filterText: term});
// Debounce server lookups to reduce spam. We don't clear the existing server
// results because they might still be vaguely accurate, likewise for races which
// could happen here.
if (this._debounceTimer) {
clearTimeout(this._debounceTimer);
}
this._debounceTimer = setTimeout(async () => {
MatrixClientPeg.get().searchUserDirectory({term}).then(r => {
if (term !== this.state.filterText) {
// Discard the results - we were probably too slow on the server-side to make
// these results useful. This is a race we want to avoid because we could overwrite
// more accurate results.
return;
}
this.setState({
serverResultsMixin: r.results.map(u => ({
userId: u.user_id,
user: new DirectoryMember(u),
})),
});
}).catch(e => {
console.error("Error searching user directory:");
console.error(e);
this.setState({serverResultsMixin: []}); // clear results because it's moderately fatal
});
// Whenever we search the directory, also try to search the identity server. It's
// all debounced the same anyways.
if (!this.state.canUseIdentityServer) {
// The user doesn't have an identity server set - warn them of that.
this.setState({tryingIdentityServer: true});
return;
}
if (term.indexOf('@') > 0 && Email.looksValid(term)) {
// Start off by suggesting the plain email while we try and resolve it
// to a real account.
this.setState({
// per above: the userId is a lie here - it's just a regular identifier
threepidResultsMixin: [{user: new ThreepidMember(term), userId: term}],
});
try {
const authClient = new IdentityAuthClient();
const token = await authClient.getAccessToken();
if (term !== this.state.filterText) return; // abandon hope
const lookup = await MatrixClientPeg.get().lookupThreePid(
'email',
term,
undefined, // callback
token,
);
if (term !== this.state.filterText) return; // abandon hope
if (!lookup || !lookup.mxid) {
// We weren't able to find anyone - we're already suggesting the plain email
// as an alternative, so do nothing.
return;
}
// We append the user suggestion to give the user an option to click
// the email anyways, and so we don't cause things to jump around. In
// theory, the user would see the user pop up and think "ah yes, that
// person!"
const profile = await MatrixClientPeg.get().getProfileInfo(lookup.mxid);
if (term !== this.state.filterText || !profile) return; // abandon hope
this.setState({
threepidResultsMixin: [...this.state.threepidResultsMixin, {
user: new DirectoryMember({
user_id: lookup.mxid,
display_name: profile.displayname,
avatar_url: profile.avatar_url,
}),
userId: lookup.mxid,
}],
});
} catch (e) {
console.error("Error searching identity server:");
console.error(e);
this.setState({threepidResultsMixin: []}); // clear results because it's moderately fatal
}
}
}, 150); // 150ms debounce (human reaction time + some)
};
_showMoreRecents = () => {
this.setState({numRecentsShown: this.state.numRecentsShown + INCREMENT_ROOMS_SHOWN});
};
_showMoreSuggestions = () => {
this.setState({numSuggestionsShown: this.state.numSuggestionsShown + INCREMENT_ROOMS_SHOWN});
};
_toggleMember = (member: Member) => {
const targets = this.state.targets.map(t => t); // cheap clone for mutation
const idx = targets.indexOf(member);
if (idx >= 0) targets.splice(idx, 1);
else targets.push(member);
this.setState({targets});
};
_removeMember = (member: Member) => {
const targets = this.state.targets.map(t => t); // cheap clone for mutation
const idx = targets.indexOf(member);
if (idx >= 0) {
targets.splice(idx, 1);
this.setState({targets});
}
};
_onPaste = async (e) => {
// Prevent the text being pasted into the textarea
e.preventDefault();
// Process it as a list of addresses to add instead
const text = e.clipboardData.getData("text");
const possibleMembers = [
// If we can avoid hitting the profile endpoint, we should.
...this.state.recents,
...this.state.suggestions,
...this.state.serverResultsMixin,
...this.state.threepidResultsMixin,
];
const toAdd = [];
const failed = [];
const potentialAddresses = text.split(/[\s,]+/);
for (const address of potentialAddresses) {
const member = possibleMembers.find(m => m.userId === address);
if (member) {
toAdd.push(member.user);
continue;
}
if (address.indexOf('@') > 0 && Email.looksValid(address)) {
toAdd.push(new ThreepidMember(address));
continue;
}
if (address[0] !== '@') {
failed.push(address); // not a user ID
continue;
}
try {
const profile = await MatrixClientPeg.get().getProfileInfo(address);
const displayName = profile ? profile.displayname : null;
const avatarUrl = profile ? profile.avatar_url : null;
toAdd.push(new DirectoryMember({
user_id: address,
display_name: displayName,
avatar_url: avatarUrl,
}));
} catch (e) {
console.error("Error looking up profile for " + address);
console.error(e);
failed.push(address);
}
}
if (failed.length > 0) {
const QuestionDialog = sdk.getComponent('dialogs.QuestionDialog');
Modal.createTrackedDialog('Invite Paste Fail', '', QuestionDialog, {
title: _t('Failed to find the following users'),
description: _t(
"The following users might not exist or are invalid, and cannot be invited: %(csvNames)s",
{csvNames: failed.join(", ")},
),
button: _t('OK'),
});
}
this.setState({targets: [...this.state.targets, ...toAdd]});
};
_onClickInputArea = (e) => {
// Stop the browser from highlighting text
e.preventDefault();
e.stopPropagation();
if (this._editorRef && this._editorRef.current) {
this._editorRef.current.focus();
}
};
_onUseDefaultIdentityServerClick = (e) => {
e.preventDefault();
// Update the IS in account data. Actually using it may trigger terms.
// eslint-disable-next-line react-hooks/rules-of-hooks
useDefaultIdentityServer();
this.setState({canUseIdentityServer: true, tryingIdentityServer: false});
};
_onManageSettingsClick = (e) => {
e.preventDefault();
dis.dispatch({ action: 'view_user_settings' });
this._cancel();
};
_renderSection(kind: "recents"|"suggestions") {
let sourceMembers = kind === 'recents' ? this.state.recents : this.state.suggestions;
let showNum = kind === 'recents' ? this.state.numRecentsShown : this.state.numSuggestionsShown;
const showMoreFn = kind === 'recents' ? this._showMoreRecents.bind(this) : this._showMoreSuggestions.bind(this);
const lastActive = (m) => kind === 'recents' ? m.lastActive : null;
const sectionName = kind === 'recents' ? _t("Recent Conversations") : _t("Suggestions");
// Mix in the server results if we have any, but only if we're searching. We track the additional
// members separately because we want to filter sourceMembers but trust the mixin arrays to have
// the right members in them.
let additionalMembers = [];
const hasMixins = this.state.serverResultsMixin || this.state.threepidResultsMixin;
if (this.state.filterText && hasMixins && kind === 'suggestions') {
// We don't want to duplicate members though, so just exclude anyone we've already seen.
const notAlreadyExists = (u: Member): boolean => {
return !sourceMembers.some(m => m.userId === u.userId)
&& !additionalMembers.some(m => m.userId === u.userId);
};
const uniqueServerResults = this.state.serverResultsMixin.filter(notAlreadyExists);
additionalMembers = additionalMembers.concat(...uniqueServerResults);
const uniqueThreepidResults = this.state.threepidResultsMixin.filter(notAlreadyExists);
additionalMembers = additionalMembers.concat(...uniqueThreepidResults);
}
// Hide the section if there's nothing to filter by
if (sourceMembers.length === 0 && additionalMembers.length === 0) return null;
// Do some simple filtering on the input before going much further. If we get no results, say so.
if (this.state.filterText) {
const filterBy = this.state.filterText.toLowerCase();
sourceMembers = sourceMembers
.filter(m => m.user.name.toLowerCase().includes(filterBy) || m.userId.toLowerCase().includes(filterBy));
if (sourceMembers.length === 0 && additionalMembers.length === 0) {
return (
<div className='mx_DMInviteDialog_section'>
<h3>{sectionName}</h3>
<p>{_t("No results")}</p>
</div>
);
}
}
// Now we mix in the additional members. Again, we presume these have already been filtered. We
// also assume they are more relevant than our suggestions and prepend them to the list.
sourceMembers = [...additionalMembers, ...sourceMembers];
// If we're going to hide one member behind 'show more', just use up the space of the button
// with the member's tile instead.
if (showNum === sourceMembers.length - 1) showNum++;
// .slice() will return an incomplete array but won't error on us if we go too far
const toRender = sourceMembers.slice(0, showNum);
const hasMore = toRender.length < sourceMembers.length;
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
let showMore = null;
if (hasMore) {
showMore = (
<AccessibleButton onClick={showMoreFn} kind="link">
{_t("Show more")}
</AccessibleButton>
);
}
const tiles = toRender.map(r => (
<DMRoomTile
member={r.user}
lastActiveTs={lastActive(r)}
key={r.userId}
onToggle={this._toggleMember}
highlightWord={this.state.filterText}
isSelected={this.state.targets.some(t => t.userId === r.userId)}
/>
));
return (
<div className='mx_DMInviteDialog_section'>
<h3>{sectionName}</h3>
{tiles}
{showMore}
</div>
);
}
_renderEditor() {
const targets = this.state.targets.map(t => (
<DMUserTile member={t} onRemove={this._removeMember} key={t.userId} />
));
const input = (
<textarea
key={"input"}
rows={1}
onChange={this._updateFilter}
defaultValue={this.state.filterText}
ref={this._editorRef}
onPaste={this._onPaste}
/>
);
return (
<div className='mx_DMInviteDialog_editor' onClick={this._onClickInputArea}>
{targets}
{input}
</div>
);
}
_renderIdentityServerWarning() {
if (!this.state.tryingIdentityServer || this.state.canUseIdentityServer) {
return null;
}
const defaultIdentityServerUrl = getDefaultIdentityServerUrl();
if (defaultIdentityServerUrl) {
return (
<div className="mx_AddressPickerDialog_identityServer">{_t(
"Use an identity server to invite by email. " +
"<default>Use the default (%(defaultIdentityServerName)s)</default> " +
"or manage in <settings>Settings</settings>.",
{
defaultIdentityServerName: abbreviateUrl(defaultIdentityServerUrl),
},
{
default: sub => <a href="#" onClick={this._onUseDefaultIdentityServerClick}>{sub}</a>,
settings: sub => <a href="#" onClick={this._onManageSettingsClick}>{sub}</a>,
},
)}</div>
);
} else {
return (
<div className="mx_AddressPickerDialog_identityServer">{_t(
"Use an identity server to invite by email. " +
"Manage in <settings>Settings</settings>.",
{}, {
settings: sub => <a href="#" onClick={this._onManageSettingsClick}>{sub}</a>,
},
)}</div>
);
}
}
render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
const userId = MatrixClientPeg.get().getUserId();
return (
<BaseDialog
className='mx_DMInviteDialog'
hasCancel={true}
onFinished={this._cancel}
title={_t("Direct Messages")}
>
<div className='mx_DMInviteDialog_content'>
<p>
{_t(
"If you can't find someone, ask them for their username, or share your " +
"username (%(userId)s) or <a>profile link</a>.",
{userId},
{a: (sub) => <a href={makeUserPermalink(userId)} rel="noopener" target="_blank">{sub}</a>},
)}
</p>
<div className='mx_DMInviteDialog_addressBar'>
{this._renderEditor()}
{this._renderIdentityServerWarning()}
<AccessibleButton
kind="primary"
onClick={this._startDm}
className='mx_DMInviteDialog_goButton'
>
{_t("Go")}
</AccessibleButton>
</div>
{this._renderSection('recents')}
{this._renderSection('suggestions')}
</div>
</BaseDialog>
);
}
}

View file

@ -18,9 +18,9 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import Analytics from '../../../Analytics';
import MatrixClientPeg from '../../../MatrixClientPeg';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import * as Lifecycle from '../../../Lifecycle';
import { _t } from '../../../languageHandler';

View file

@ -19,11 +19,11 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import MatrixClientPeg from '../../../MatrixClientPeg';
import sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import * as sdk from '../../../index';
import * as FormattingUtils from '../../../utils/FormattingUtils';
import { _t } from '../../../languageHandler';
import {verificationMethods} from 'matrix-js-sdk/lib/crypto';
import {verificationMethods} from 'matrix-js-sdk/src/crypto';
import {ensureDMExists} from "../../../createRoom";
import dis from "../../../dispatcher";
import SettingsStore from '../../../settings/SettingsStore';

View file

@ -16,11 +16,10 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import { Room } from "matrix-js-sdk";
import sdk from '../../../index';
import * as sdk from '../../../index';
import SyntaxHighlight from '../elements/SyntaxHighlight';
import { _t } from '../../../languageHandler';
import { Room } from "matrix-js-sdk";
import Field from "../elements/Field";
import MatrixClientContext from "../../../contexts/MatrixClientContext";

View file

@ -28,7 +28,7 @@ limitations under the License.
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
export default createReactClass({

View file

@ -16,8 +16,8 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import MatrixClientPeg from '../../../MatrixClientPeg';
import sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
const PHASE_START = 0;

View file

@ -19,7 +19,7 @@ limitations under the License.
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import classNames from "classnames";

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import {_t} from "../../../languageHandler";
import sdk from "../../../index";
import * as sdk from "../../../index";
import dis from '../../../dispatcher';
export default class IntegrationsDisabledDialog extends React.Component {

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import {_t} from "../../../languageHandler";
import sdk from "../../../index";
import * as sdk from "../../../index";
export default class IntegrationsImpossibleDialog extends React.Component {
static propTypes = {

View file

@ -19,7 +19,7 @@ import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import AccessibleButton from '../elements/AccessibleButton';

View file

@ -18,7 +18,7 @@ import Modal from '../../../Modal';
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t, _td } from '../../../languageHandler';

View file

@ -1,5 +1,6 @@
/*
Copyright 2018, 2019 New Vector Ltd
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -16,10 +17,10 @@ limitations under the License.
import React from 'react';
import Modal from '../../../Modal';
import sdk from '../../../index';
import * as sdk from '../../../index';
import dis from '../../../dispatcher';
import { _t } from '../../../languageHandler';
import MatrixClientPeg from '../../../MatrixClientPeg';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import SettingsStore from "../../../settings/SettingsStore";
export default class LogoutDialog extends React.Component {
@ -94,10 +95,14 @@ export default class LogoutDialog extends React.Component {
// verified, so restore the backup which will give us the keys from it and
// allow us to trust it (ie. upload keys to it)
const RestoreKeyBackupDialog = sdk.getComponent('dialogs.keybackup.RestoreKeyBackupDialog');
Modal.createTrackedDialog('Restore Backup', '', RestoreKeyBackupDialog, {});
Modal.createTrackedDialog(
'Restore Backup', '', RestoreKeyBackupDialog, null, null,
/* priority = */ false, /* static = */ true,
);
} else {
Modal.createTrackedDialogAsync("Key Backup", "Key Backup",
import("../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog"),
null, null, /* priority = */ false, /* static = */ true,
);
}

View file

@ -16,9 +16,9 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import MatrixClientPeg from "../../../MatrixClientPeg";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import { _t } from '../../../languageHandler';
import sdk from "../../../index";
import * as sdk from "../../../index";
import {wantsDateSeparator} from '../../../DateUtils';
import SettingsStore from '../../../settings/SettingsStore';

View file

@ -18,7 +18,7 @@ limitations under the License.
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
export default createReactClass({

View file

@ -15,11 +15,11 @@ limitations under the License.
*/
import React, {PureComponent} from 'react';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import PropTypes from "prop-types";
import {MatrixEvent} from "matrix-js-sdk";
import MatrixClientPeg from "../../../MatrixClientPeg";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
/*
* A dialog for reporting an event.

View file

@ -17,16 +17,18 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import {Tab, TabbedView} from "../../structures/TabbedView";
import TabbedView, {Tab} from "../../structures/TabbedView";
import {_t, _td} from "../../../languageHandler";
import AdvancedRoomSettingsTab from "../settings/tabs/room/AdvancedRoomSettingsTab";
import RolesRoomSettingsTab from "../settings/tabs/room/RolesRoomSettingsTab";
import GeneralRoomSettingsTab from "../settings/tabs/room/GeneralRoomSettingsTab";
import SecurityRoomSettingsTab from "../settings/tabs/room/SecurityRoomSettingsTab";
import NotificationSettingsTab from "../settings/tabs/room/NotificationSettingsTab";
import sdk from "../../../index";
import MatrixClientPeg from "../../../MatrixClientPeg";
import BridgeSettingsTab from "../settings/tabs/room/BridgeSettingsTab";
import * as sdk from "../../../index";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import dis from "../../../dispatcher";
import SettingsStore from "../../../settings/SettingsStore";
export default class RoomSettingsDialog extends React.Component {
static propTypes = {
@ -52,6 +54,9 @@ export default class RoomSettingsDialog extends React.Component {
_getTabs() {
const tabs = [];
const featureFlag = SettingsStore.isFeatureEnabled("feature_bridge_state");
const shouldShowBridgeIcon = featureFlag &&
BridgeSettingsTab.getBridgeStateEvents(this.props.roomId).length > 0;
tabs.push(new Tab(
_td("General"),
@ -73,6 +78,15 @@ export default class RoomSettingsDialog extends React.Component {
"mx_RoomSettingsDialog_rolesIcon",
<NotificationSettingsTab roomId={this.props.roomId} />,
));
if (shouldShowBridgeIcon) {
tabs.push(new Tab(
_td("Bridge Info"),
"mx_RoomSettingsDialog_bridgesIcon",
<BridgeSettingsTab roomId={this.props.roomId} />,
));
}
tabs.push(new Tab(
_td("Advanced"),
"mx_RoomSettingsDialog_warningIcon",

View file

@ -17,8 +17,8 @@ limitations under the License.
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import MatrixClientPeg from '../../../MatrixClientPeg';
import * as sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';

View file

@ -17,9 +17,9 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import {_t} from "../../../languageHandler";
import sdk from "../../../index";
import * as sdk from "../../../index";
import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
import MatrixClientPeg from "../../../MatrixClientPeg";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import Modal from "../../../Modal";
export default class RoomUpgradeWarningDialog extends React.Component {

View file

@ -18,7 +18,7 @@ limitations under the License.
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import SdkConfig from '../../../SdkConfig';
import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';

View file

@ -18,8 +18,8 @@ limitations under the License.
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import Email from '../../../email';
import * as sdk from '../../../index';
import * as Email from '../../../email';
import AddThreepid from '../../../AddThreepid';
import { _t } from '../../../languageHandler';
import Modal from '../../../Modal';

View file

@ -18,8 +18,8 @@ limitations under the License.
import React, {createRef} from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import MatrixClientPeg from '../../../MatrixClientPeg';
import * as sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import classnames from 'classnames';
import { Key } from '../../../Keyboard';
import { _t } from '../../../languageHandler';

View file

@ -19,7 +19,7 @@ limitations under the License.
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import Modal from '../../../Modal';

View file

@ -17,7 +17,7 @@ limitations under the License.
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
import {Room, User, Group, RoomMember, MatrixEvent} from 'matrix-js-sdk';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import QRCode from 'qrcode-react';
import {RoomPermalinkCreator, makeGroupPermalink, makeUserPermalink} from "../../../utils/permalinks/Permalinks";

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import {_t} from "../../../languageHandler";
import {CommandCategories, CommandMap} from "../../../SlashCommands";
import sdk from "../../../index";
import * as sdk from "../../../index";
export default ({onFinished}) => {
const InfoDialog = sdk.getComponent('dialogs.InfoDialog');

View file

@ -16,7 +16,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import SdkConfig from '../../../SdkConfig';
import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';

View file

@ -18,10 +18,10 @@ import React from 'react';
import PropTypes from 'prop-types';
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
import {Room} from "matrix-js-sdk";
import sdk from '../../../index';
import * as sdk from '../../../index';
import {dialogTermsInteractionCallback, TermsNotSignedError} from "../../../Terms";
import classNames from 'classnames';
import ScalarMessaging from "../../../ScalarMessaging";
import * as ScalarMessaging from "../../../ScalarMessaging";
export default class TabbedIntegrationManagerDialog extends React.Component {
static propTypes = {

View file

@ -17,7 +17,7 @@ limitations under the License.
import url from 'url';
import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t, pickBestLanguage } from '../../../languageHandler';
import Matrix from 'matrix-js-sdk';

View file

@ -17,7 +17,7 @@ limitations under the License.
import React, {createRef} from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
export default createReactClass({
displayName: 'TextInputDialog',

View file

@ -18,8 +18,8 @@ limitations under the License.
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import MatrixClientPeg from '../../../MatrixClientPeg';
import * as sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler';
import SettingsStore from "../../../settings/SettingsStore";
import { markAllDevicesKnown } from '../../../cryptodevices';

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import filesize from "filesize";

View file

@ -18,7 +18,7 @@ import filesize from 'filesize';
import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import ContentMessages from '../../../ContentMessages';

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import {Tab, TabbedView} from "../../structures/TabbedView";
import TabbedView, {Tab} from "../../structures/TabbedView";
import {_t, _td} from "../../../languageHandler";
import GeneralUserSettingsTab from "../settings/tabs/user/GeneralUserSettingsTab";
import SettingsStore from "../../../settings/SettingsStore";
@ -28,7 +28,7 @@ import PreferencesUserSettingsTab from "../settings/tabs/user/PreferencesUserSet
import VoiceUserSettingsTab from "../settings/tabs/user/VoiceUserSettingsTab";
import HelpUserSettingsTab from "../settings/tabs/user/HelpUserSettingsTab";
import FlairUserSettingsTab from "../settings/tabs/user/FlairUserSettingsTab";
import sdk from "../../../index";
import * as sdk from "../../../index";
import SdkConfig from "../../../SdkConfig";
import MjolnirUserSettingsTab from "../settings/tabs/user/MjolnirUserSettingsTab";

View file

@ -18,7 +18,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import {_t} from "../../../languageHandler";
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
import sdk from "../../../index";
import * as sdk from "../../../index";
import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
import WidgetUtils from "../../../utils/WidgetUtils";

View file

@ -1,5 +1,6 @@
/*
Copyright 2018, 2019 New Vector Ltd
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -15,17 +16,17 @@ limitations under the License.
*/
import React from 'react';
import sdk from '../../../../index';
import MatrixClientPeg from '../../../../MatrixClientPeg';
import Modal from '../../../../Modal';
import * as sdk from '../../../../index';
import {MatrixClientPeg} from '../../../../MatrixClientPeg';
import { MatrixClient } from 'matrix-js-sdk';
import Modal from '../../../../Modal';
import { _t } from '../../../../languageHandler';
import {Key} from "../../../../Keyboard";
import { accessSecretStorage } from '../../../../CrossSigningManager';
const RESTORE_TYPE_PASSPHRASE = 0;
const RESTORE_TYPE_RECOVERYKEY = 1;
const RESTORE_TYPE_SECRET_STORAGE = 2;
/*
* Dialog for restoring e2e keys from a backup and the user's recovery key
@ -35,6 +36,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
super(props);
this.state = {
backupInfo: null,
backupKeyStored: null,
loading: false,
loadError: null,
restoreError: null,
@ -73,7 +75,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
onFinished: () => {
this._loadBackupStatus();
},
},
}, null, /* priority = */ false, /* static = */ true,
);
}
@ -148,6 +150,32 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
}
}
async _restoreWithSecretStorage() {
this.setState({
loading: true,
restoreError: null,
restoreType: RESTORE_TYPE_SECRET_STORAGE,
});
try {
// `accessSecretStorage` may prompt for storage access as needed.
const recoverInfo = await accessSecretStorage(async () => {
return MatrixClientPeg.get().restoreKeyBackupWithSecretStorage(
this.state.backupInfo,
);
});
this.setState({
loading: false,
recoverInfo,
});
} catch (e) {
console.log("Error restoring backup", e);
this.setState({
restoreError: e,
loading: false,
});
}
}
async _loadBackupStatus() {
this.setState({
loading: true,
@ -155,10 +183,20 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
});
try {
const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
const backupKeyStored = await MatrixClientPeg.get().isKeyBackupKeyStored();
this.setState({
backupInfo,
backupKeyStored,
});
// If the backup key is stored, we can proceed directly to restore.
if (backupKeyStored) {
return this._restoreWithSecretStorage();
}
this.setState({
loadError: null,
loading: false,
backupInfo,
});
} catch (e) {
console.log("Error loading backup status", e);

View file

@ -17,8 +17,8 @@ limitations under the License.
import React from 'react';
import PropTypes from "prop-types";
import sdk from '../../../../index';
import MatrixClientPeg from '../../../../MatrixClientPeg';
import * as sdk from '../../../../index';
import {MatrixClientPeg} from '../../../../MatrixClientPeg';
import { _t } from '../../../../languageHandler';
import { Key } from "../../../../Keyboard";

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import MatrixClientPeg from '../../../MatrixClientPeg';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import {instanceForInstanceId} from '../../../utils/DirectoryUtils';
const DEFAULT_ICON_URL = require("../../../../res/img/network-matrix.svg");

View file

@ -19,7 +19,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import AccessibleButton from "./AccessibleButton";
import sdk from "../../../index";
import * as sdk from "../../../index";
export default class AccessibleTooltipButton extends React.PureComponent {
static propTypes = {

View file

@ -19,7 +19,7 @@ import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import AccessibleButton from './AccessibleButton';
import dis from '../../../dispatcher';
import sdk from '../../../index';
import * as sdk from '../../../index';
import Analytics from '../../../Analytics';
export default createReactClass({

View file

@ -18,7 +18,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import sdk from '../../../index';
import * as sdk from '../../../index';
import classNames from 'classnames';
import { UserAddressType } from '../../../UserAddress';

View file

@ -19,8 +19,8 @@ import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import classNames from 'classnames';
import sdk from "../../../index";
import MatrixClientPeg from "../../../MatrixClientPeg";
import * as sdk from "../../../index";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import { _t } from '../../../languageHandler';
import { UserAddressType } from '../../../UserAddress.js';

View file

@ -19,10 +19,10 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import url from 'url';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import WidgetUtils from "../../../utils/WidgetUtils";
import MatrixClientPeg from "../../../MatrixClientPeg";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
export default class AppPermission extends React.Component {
static propTypes = {

View file

@ -20,12 +20,12 @@ import url from 'url';
import qs from 'querystring';
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
import MatrixClientPeg from '../../../MatrixClientPeg';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import WidgetMessaging from '../../../WidgetMessaging';
import AccessibleButton from './AccessibleButton';
import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';
import sdk from '../../../index';
import * as sdk from '../../../index';
import AppPermission from './AppPermission';
import AppWarning from './AppWarning';
import MessageSpinner from './MessageSpinner';

View file

@ -15,7 +15,7 @@ limitations under the License.
*/
import React from 'react';
import sdk from '../../../index';
import * as sdk from '../../../index';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';

View file

@ -17,11 +17,13 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import MatrixClientPeg from '../../../MatrixClientPeg';
import sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import * as sdk from '../../../index';
import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';
// XXX: This component is *not* cross-signing aware. Once everything is
// cross-signing, this component should just go away.
export default createReactClass({
displayName: 'DeviceVerifyButtons',

View file

@ -1,6 +1,7 @@
/*
Copyright 2017 Aidan Gauland
Copyright 2018 New Vector Ltd.
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -23,7 +24,7 @@ import { _t } from '../../../languageHandler';
/**
* Basic container for buttons in modal dialogs.
*/
module.exports = createReactClass({
export default createReactClass({
displayName: "DialogButtons",
propTypes: {

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
export default class DirectorySearchBox extends React.Component {

View file

@ -20,7 +20,7 @@ import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import {Key} from "../../../Keyboard";
module.exports = createReactClass({
export default createReactClass({
displayName: 'EditableText',
propTypes: {

View file

@ -16,7 +16,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
/**
* A component which wraps an EditableText, with a spinner while updates take

View file

@ -15,9 +15,9 @@ limitations under the License.
*/
import React from 'react';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import MatrixClientPeg from '../../../MatrixClientPeg';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import PlatformPeg from '../../../PlatformPeg';
import Modal from '../../../Modal';

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { debounce } from 'lodash';
// Invoke validation from user input (when typing, etc.) at most once every N ms.

View file

@ -0,0 +1,37 @@
/*
Copyright 2017 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import * as sdk from '../../../index';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
const GroupsButton = function(props) {
const ActionButton = sdk.getComponent('elements.ActionButton');
return (
<ActionButton className="mx_GroupsButton" action="toggle_my_groups"
label={_t("Communities")}
size={props.size}
tooltip={true}
/>
);
};
GroupsButton.propTypes = {
size: PropTypes.string,
};
export default GroupsButton;

View file

@ -19,15 +19,13 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
const MatrixClientPeg = require('../../../MatrixClientPeg');
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import {formatDate} from '../../../DateUtils';
const filesize = require('filesize');
const AccessibleButton = require('../../../components/views/elements/AccessibleButton');
const Modal = require('../../../Modal');
const sdk = require('../../../index');
import { _t } from '../../../languageHandler';
import filesize from "filesize";
import AccessibleButton from "./AccessibleButton";
import Modal from "../../../Modal";
import * as sdk from "../../../index";
import {Key} from "../../../Keyboard";
export default class ImageView extends React.Component {

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from "react";
import createReactClass from 'create-react-class';
module.exports = createReactClass({
export default createReactClass({
displayName: 'InlineSpinner',
render: function() {

View file

@ -18,7 +18,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import * as languageHandler from '../../../languageHandler';
import SettingsStore from "../../../settings/SettingsStore";
import { _t } from "../../../languageHandler";

View file

@ -56,14 +56,20 @@ class ItemRange {
}
export default class LazyRenderList extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
static getDerivedStateFromProps(props, state) {
const range = LazyRenderList.getVisibleRangeFromProps(props);
const intersectRange = range.expand(props.overflowMargin);
const renderRange = range.expand(props.overflowItems);
const listHasChangedSize = !!state && renderRange.totalSize() !== state.renderRange.totalSize();
const listHasChangedSize = !!state.renderRange && renderRange.totalSize() !== state.renderRange.totalSize();
// only update render Range if the list has shrunk/grown and we need to adjust padding OR
// if the new range + overflowMargin isn't contained by the old anymore
if (listHasChangedSize || !state || !state.renderRange.contains(intersectRange)) {
if (listHasChangedSize || !state.renderRange || !state.renderRange.contains(intersectRange)) {
return {renderRange};
}
return null;

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
import SettingsStore from "../../../settings/SettingsStore";

View file

@ -21,10 +21,10 @@ import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
import { formatCommaSeparatedList } from '../../../utils/FormattingUtils';
import sdk from "../../../index";
import * as sdk from "../../../index";
import {MatrixEvent} from "matrix-js-sdk";
module.exports = createReactClass({
export default createReactClass({
displayName: 'MemberEventListSummary',
propTypes: {

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import createReactClass from 'create-react-class';
module.exports = createReactClass({
export default createReactClass({
displayName: 'MessageSpinner',
render: function() {

View file

@ -1,5 +1,6 @@
/*
Copyright 2018 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -19,10 +20,10 @@ import createReactClass from 'create-react-class';
import RoomViewStore from '../../../stores/RoomViewStore';
import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
import WidgetUtils from '../../../utils/WidgetUtils';
import sdk from '../../../index';
import MatrixClientPeg from '../../../MatrixClientPeg';
import * as sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
module.exports = createReactClass({
export default createReactClass({
displayName: 'PersistentApp',
getInitialState: function() {

Some files were not shown because too many files have changed in this diff Show more