You've already forked matrix-react-sdk
							
							
				mirror of
				https://github.com/matrix-org/matrix-react-sdk.git
				synced 2025-11-04 11:51:45 +03:00 
			
		
		
		
	Merge branch 'develop' into travis/moar-jitsi
This commit is contained in:
		@@ -89,7 +89,6 @@
 | 
			
		||||
    "qrcode-react": "^0.1.16",
 | 
			
		||||
    "qs": "^6.6.0",
 | 
			
		||||
    "react": "^16.9.0",
 | 
			
		||||
    "react-addons-css-transition-group": "15.6.2",
 | 
			
		||||
    "react-beautiful-dnd": "^4.0.1",
 | 
			
		||||
    "react-dom": "^16.9.0",
 | 
			
		||||
    "react-focus-lock": "^2.2.1",
 | 
			
		||||
 
 | 
			
		||||
@@ -94,6 +94,7 @@
 | 
			
		||||
@import "./views/elements/_AccessibleButton.scss";
 | 
			
		||||
@import "./views/elements/_AddressSelector.scss";
 | 
			
		||||
@import "./views/elements/_AddressTile.scss";
 | 
			
		||||
@import "./views/elements/_ButtonPlaceholder.scss";
 | 
			
		||||
@import "./views/elements/_DirectorySearchBox.scss";
 | 
			
		||||
@import "./views/elements/_Dropdown.scss";
 | 
			
		||||
@import "./views/elements/_EditableItemList.scss";
 | 
			
		||||
@@ -133,6 +134,7 @@
 | 
			
		||||
@import "./views/messages/_MNoticeBody.scss";
 | 
			
		||||
@import "./views/messages/_MStickerBody.scss";
 | 
			
		||||
@import "./views/messages/_MTextBody.scss";
 | 
			
		||||
@import "./views/messages/_MVideoBody.scss";
 | 
			
		||||
@import "./views/messages/_MessageActionBar.scss";
 | 
			
		||||
@import "./views/messages/_MessageTimestamp.scss";
 | 
			
		||||
@import "./views/messages/_MjolnirBody.scss";
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,7 @@ limitations under the License.
 | 
			
		||||
.mx_CompleteSecurity_actionRow {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: flex-end;
 | 
			
		||||
    margin-top: $font-28px;
 | 
			
		||||
 | 
			
		||||
    .mx_AccessibleButton {
 | 
			
		||||
        margin-inline-start: 18px;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								res/css/views/elements/_ButtonPlaceholder.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								res/css/views/elements/_ButtonPlaceholder.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
/*
 | 
			
		||||
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.
 | 
			
		||||
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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
.mx_ButtonPlaceholder {
 | 
			
		||||
    font-size: $font-14px;
 | 
			
		||||
    font-weight: 600;
 | 
			
		||||
    padding: 7px 18px;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    color: $authpage-secondary-color;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								res/css/views/messages/_MVideoBody.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								res/css/views/messages/_MVideoBody.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
/*
 | 
			
		||||
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.
 | 
			
		||||
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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
span.mx_MVideoBody {
 | 
			
		||||
    video.mx_MVideoBody {
 | 
			
		||||
        max-width: 100%;
 | 
			
		||||
        height: auto;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -34,6 +34,10 @@ limitations under the License.
 | 
			
		||||
        background-color: $reaction-row-button-selected-bg-color;
 | 
			
		||||
        border-color: $reaction-row-button-selected-border-color;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ignore mouse events for all children, treat it as one entire hoverable entity
 | 
			
		||||
    * {
 | 
			
		||||
        pointer-events: none;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .mx_ReactionsRowButton_content {
 | 
			
		||||
@@ -43,3 +47,4 @@ limitations under the License.
 | 
			
		||||
        text-overflow: ellipsis;
 | 
			
		||||
        padding-right: 4px;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,7 @@ limitations under the License.
 | 
			
		||||
        outline: none;
 | 
			
		||||
        overflow-x: hidden;
 | 
			
		||||
 | 
			
		||||
        &.mx_BasicMessageComposer_input_shouldShowPillAvatar {
 | 
			
		||||
            span.mx_UserPill, span.mx_RoomPill {
 | 
			
		||||
                padding-left: 21px;
 | 
			
		||||
                position: relative;
 | 
			
		||||
@@ -68,6 +69,7 @@ limitations under the License.
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .mx_BasicMessageComposer_AutoCompleteWrapper {
 | 
			
		||||
        position: relative;
 | 
			
		||||
 
 | 
			
		||||
@@ -188,4 +188,8 @@ export default class BasePlatform {
 | 
			
		||||
        const callbackUrl = this.getSSOCallbackUrl(mxClient.getHomeserverUrl(), mxClient.getIdentityServerUrl());
 | 
			
		||||
        window.location.href = mxClient.getSsoLoginUrl(callbackUrl.toString(), loginType); // redirect to SSO
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onKeyDown(ev: KeyboardEvent): boolean {
 | 
			
		||||
        return false; // no shortcuts implemented
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -43,6 +43,8 @@ export const Key = {
 | 
			
		||||
    BACKTICK: "`",
 | 
			
		||||
    SPACE: " ",
 | 
			
		||||
    SLASH: "/",
 | 
			
		||||
    SQUARE_BRACKET_LEFT: "[",
 | 
			
		||||
    SQUARE_BRACKET_RIGHT: "]",
 | 
			
		||||
    A: "a",
 | 
			
		||||
    B: "b",
 | 
			
		||||
    C: "c",
 | 
			
		||||
 
 | 
			
		||||
@@ -172,6 +172,7 @@ Request:
 | 
			
		||||
Response:
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        // TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
 | 
			
		||||
        type: "im.vector.modular.widgets",
 | 
			
		||||
        state_key: "wid1",
 | 
			
		||||
        content: {
 | 
			
		||||
@@ -190,6 +191,7 @@ Example:
 | 
			
		||||
    room_id: "!foo:bar",
 | 
			
		||||
    response: [
 | 
			
		||||
        {
 | 
			
		||||
            // TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
 | 
			
		||||
            type: "im.vector.modular.widgets",
 | 
			
		||||
            state_key: "wid1",
 | 
			
		||||
            content: {
 | 
			
		||||
 
 | 
			
		||||
@@ -351,7 +351,7 @@ export const Commands = [
 | 
			
		||||
                return success(cli.setRoomTopic(roomId, args));
 | 
			
		||||
            }
 | 
			
		||||
            const room = cli.getRoom(roomId);
 | 
			
		||||
            if (!room) return reject('Bad room ID: ' + roomId);
 | 
			
		||||
            if (!room) return reject(_t("Failed to set topic"));
 | 
			
		||||
 | 
			
		||||
            const topicEvents = room.currentState.getStateEvents('m.room.topic', '');
 | 
			
		||||
            const topic = topicEvents && topicEvents.getContent().topic;
 | 
			
		||||
@@ -722,9 +722,10 @@ export const Commands = [
 | 
			
		||||
                    if (!isNaN(powerLevel)) {
 | 
			
		||||
                        const cli = MatrixClientPeg.get();
 | 
			
		||||
                        const room = cli.getRoom(roomId);
 | 
			
		||||
                        if (!room) return reject('Bad room ID: ' + roomId);
 | 
			
		||||
                        if (!room) return reject(_t("Command failed"));
 | 
			
		||||
 | 
			
		||||
                        const powerLevelEvent = room.currentState.getStateEvents('m.room.power_levels', '');
 | 
			
		||||
                        if (!powerLevelEvent.getContent().users[args]) return reject(_t("Could not find user in room"));
 | 
			
		||||
                        return success(cli.setPowerLevel(roomId, userId, powerLevel, powerLevelEvent));
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
@@ -743,9 +744,10 @@ export const Commands = [
 | 
			
		||||
                if (matches) {
 | 
			
		||||
                    const cli = MatrixClientPeg.get();
 | 
			
		||||
                    const room = cli.getRoom(roomId);
 | 
			
		||||
                    if (!room) return reject('Bad room ID: ' + roomId);
 | 
			
		||||
                    if (!room) return reject(_t("Command failed"));
 | 
			
		||||
 | 
			
		||||
                    const powerLevelEvent = room.currentState.getStateEvents('m.room.power_levels', '');
 | 
			
		||||
                    if (!powerLevelEvent.getContent().users[args]) return reject(_t("Could not find user in room"));
 | 
			
		||||
                    return success(cli.setPowerLevel(roomId, args, undefined, powerLevelEvent));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -915,7 +917,7 @@ export const Commands = [
 | 
			
		||||
    // Command definitions for autocompletion ONLY:
 | 
			
		||||
    // /me is special because its not handled by SlashCommands.js and is instead done inside the Composer classes
 | 
			
		||||
    new Command({
 | 
			
		||||
        command: 'me',
 | 
			
		||||
        command: "me",
 | 
			
		||||
        args: '<message>',
 | 
			
		||||
        description: _td('Displays action'),
 | 
			
		||||
        category: CommandCategories.messages,
 | 
			
		||||
@@ -932,16 +934,7 @@ Commands.forEach(cmd => {
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Process the given text for /commands and return a bound method to perform them.
 | 
			
		||||
 * @param {string} roomId The room in which the command was performed.
 | 
			
		||||
 * @param {string} input The raw text input by the user.
 | 
			
		||||
 * @return {null|function(): Object} Function returning an object with the property 'error' if there was an error
 | 
			
		||||
 * processing the command, or 'promise' if a request was sent out.
 | 
			
		||||
 * Returns null if the input didn't match a command.
 | 
			
		||||
 */
 | 
			
		||||
export function getCommand(roomId, input) {
 | 
			
		||||
export function parseCommandString(input) {
 | 
			
		||||
    // trim any trailing whitespace, as it can confuse the parser for
 | 
			
		||||
    // IRC-style commands
 | 
			
		||||
    input = input.replace(/\s+$/, '');
 | 
			
		||||
@@ -957,6 +950,20 @@ export function getCommand(roomId, input) {
 | 
			
		||||
        cmd = input;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {cmd, args};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Process the given text for /commands and return a bound method to perform them.
 | 
			
		||||
 * @param {string} roomId The room in which the command was performed.
 | 
			
		||||
 * @param {string} input The raw text input by the user.
 | 
			
		||||
 * @return {null|function(): Object} Function returning an object with the property 'error' if there was an error
 | 
			
		||||
 * processing the command, or 'promise' if a request was sent out.
 | 
			
		||||
 * Returns null if the input didn't match a command.
 | 
			
		||||
 */
 | 
			
		||||
export function getCommand(roomId, input) {
 | 
			
		||||
    const {cmd, args} = parseCommandString(input);
 | 
			
		||||
 | 
			
		||||
    if (CommandMap.has(cmd)) {
 | 
			
		||||
        return () => CommandMap.get(cmd).run(roomId, args, cmd);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -603,6 +603,7 @@ const stateHandlers = {
 | 
			
		||||
    'm.room.guest_access': textForGuestAccessEvent,
 | 
			
		||||
    'm.room.related_groups': textForRelatedGroupsEvent,
 | 
			
		||||
 | 
			
		||||
    // TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
 | 
			
		||||
    'im.vector.modular.widgets': textForWidgetEvent,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -70,6 +70,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
 | 
			
		||||
        this._recoveryKey = null;
 | 
			
		||||
        this._recoveryKeyNode = null;
 | 
			
		||||
        this._setZxcvbnResultTimeout = null;
 | 
			
		||||
        this._backupKey = null;
 | 
			
		||||
 | 
			
		||||
        this.state = {
 | 
			
		||||
            phase: PHASE_LOADING,
 | 
			
		||||
@@ -243,7 +244,15 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
 | 
			
		||||
                    createSecretStorageKey: async () => this._recoveryKey,
 | 
			
		||||
                    keyBackupInfo: this.state.backupInfo,
 | 
			
		||||
                    setupNewKeyBackup: !this.state.backupInfo && this.state.useKeyBackup,
 | 
			
		||||
                    getKeyBackupPassphrase: promptForBackupPassphrase,
 | 
			
		||||
                    getKeyBackupPassphrase: () => {
 | 
			
		||||
                        // We may already have the backup key if we earlier went
 | 
			
		||||
                        // through the restore backup path, so pass it along
 | 
			
		||||
                        // rather than prompting again.
 | 
			
		||||
                        if (this._backupKey) {
 | 
			
		||||
                            return this._backupKey;
 | 
			
		||||
                        }
 | 
			
		||||
                        return promptForBackupPassphrase();
 | 
			
		||||
                    },
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            this.setState({
 | 
			
		||||
@@ -272,10 +281,18 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _restoreBackup = async () => {
 | 
			
		||||
        // It's possible we'll need the backup key later on for bootstrapping,
 | 
			
		||||
        // so let's stash it here, rather than prompting for it twice.
 | 
			
		||||
        const keyCallback = k => this._backupKey = k;
 | 
			
		||||
 | 
			
		||||
        const RestoreKeyBackupDialog = sdk.getComponent('dialogs.keybackup.RestoreKeyBackupDialog');
 | 
			
		||||
        const { finished } = Modal.createTrackedDialog(
 | 
			
		||||
            'Restore Backup', '', RestoreKeyBackupDialog, {showSummary: false}, null,
 | 
			
		||||
            /* priority = */ false, /* static = */ false,
 | 
			
		||||
            'Restore Backup', '', RestoreKeyBackupDialog,
 | 
			
		||||
            {
 | 
			
		||||
                showSummary: false,
 | 
			
		||||
                keyCallback,
 | 
			
		||||
            },
 | 
			
		||||
            null, /* priority = */ false, /* static = */ false,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        await finished;
 | 
			
		||||
 
 | 
			
		||||
@@ -100,6 +100,8 @@ export default class EmojiProvider extends AutocompleteProvider {
 | 
			
		||||
 | 
			
		||||
            // then sort by score (Infinity if matchedString not in shortname)
 | 
			
		||||
            sorters.push((c) => score(matchedString, c.shortname));
 | 
			
		||||
            // then sort by max score of all shortcodes, trim off the `:`
 | 
			
		||||
            sorters.push((c) => Math.min(...c.emoji.shortcodes.map(s => score(matchedString.substring(1), s))));
 | 
			
		||||
            // If the matchedString is not empty, sort by length of shortname. Example:
 | 
			
		||||
            //  matchedString = ":bookmark"
 | 
			
		||||
            //  completions = [":bookmark:", ":bookmark_tabs:", ...]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2015, 2016 OpenMarket Ltd
 | 
			
		||||
Copyright 2017 Vector Creations Ltd
 | 
			
		||||
Copyright 2017, 2018 New Vector Ltd
 | 
			
		||||
Copyright 2017, 2018, 2020 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.
 | 
			
		||||
@@ -16,10 +16,10 @@ See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import { MatrixClient } from 'matrix-js-sdk';
 | 
			
		||||
import React, {createRef} from 'react';
 | 
			
		||||
import createReactClass from 'create-react-class';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import * as React from 'react';
 | 
			
		||||
import * as PropTypes from 'prop-types';
 | 
			
		||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
 | 
			
		||||
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
 | 
			
		||||
import { DragDropContext } from 'react-beautiful-dnd';
 | 
			
		||||
 | 
			
		||||
import {Key, isOnlyCtrlOrCmdKeyEvent, isOnlyCtrlOrCmdIgnoreShiftKeyEvent} from '../../Keyboard';
 | 
			
		||||
@@ -29,7 +29,7 @@ import { fixupColorFonts } from '../../utils/FontManager';
 | 
			
		||||
import * as sdk from '../../index';
 | 
			
		||||
import dis from '../../dispatcher';
 | 
			
		||||
import sessionStore from '../../stores/SessionStore';
 | 
			
		||||
import {MatrixClientPeg} from '../../MatrixClientPeg';
 | 
			
		||||
import {MatrixClientPeg, MatrixClientCreds} from '../../MatrixClientPeg';
 | 
			
		||||
import SettingsStore from "../../settings/SettingsStore";
 | 
			
		||||
import RoomListStore from "../../stores/RoomListStore";
 | 
			
		||||
 | 
			
		||||
@@ -40,6 +40,8 @@ import {Resizer, CollapseDistributor} from '../../resizer';
 | 
			
		||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
 | 
			
		||||
import * as KeyboardShortcuts from "../../accessibility/KeyboardShortcuts";
 | 
			
		||||
import HomePage from "./HomePage";
 | 
			
		||||
import ResizeNotifier from "../../utils/ResizeNotifier";
 | 
			
		||||
import PlatformPeg from "../../PlatformPeg";
 | 
			
		||||
// We need to fetch each pinned message individually (if we don't already have it)
 | 
			
		||||
// so each pinned message may trigger a request. Limit the number per room for sanity.
 | 
			
		||||
// NB. this is just for server notices rather than pinned messages in general.
 | 
			
		||||
@@ -52,6 +54,52 @@ function canElementReceiveInput(el) {
 | 
			
		||||
        !!el.getAttribute("contenteditable");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IProps {
 | 
			
		||||
    matrixClient: MatrixClient;
 | 
			
		||||
    onRegistered: (credentials: MatrixClientCreds) => Promise<MatrixClient>;
 | 
			
		||||
    viaServers?: string[];
 | 
			
		||||
    hideToSRUsers: boolean;
 | 
			
		||||
    resizeNotifier: ResizeNotifier;
 | 
			
		||||
    middleDisabled: boolean;
 | 
			
		||||
    initialEventPixelOffset: number;
 | 
			
		||||
    leftDisabled: boolean;
 | 
			
		||||
    rightDisabled: boolean;
 | 
			
		||||
    showCookieBar: boolean;
 | 
			
		||||
    hasNewVersion: boolean;
 | 
			
		||||
    userHasGeneratedPassword: boolean;
 | 
			
		||||
    showNotifierToolbar: boolean;
 | 
			
		||||
    page_type: string;
 | 
			
		||||
    autoJoin: boolean;
 | 
			
		||||
    thirdPartyInvite?: object;
 | 
			
		||||
    roomOobData?: object;
 | 
			
		||||
    currentRoomId: string;
 | 
			
		||||
    ConferenceHandler?: object;
 | 
			
		||||
    collapseLhs: boolean;
 | 
			
		||||
    checkingForUpdate: boolean;
 | 
			
		||||
    config: {
 | 
			
		||||
        piwik: {
 | 
			
		||||
            policyUrl: string;
 | 
			
		||||
        },
 | 
			
		||||
        [key: string]: any,
 | 
			
		||||
    };
 | 
			
		||||
    currentUserId?: string;
 | 
			
		||||
    currentGroupId?: string;
 | 
			
		||||
    currentGroupIsNew?: boolean;
 | 
			
		||||
    version?: string;
 | 
			
		||||
    newVersion?: string;
 | 
			
		||||
    newVersionReleaseNotes?: string;
 | 
			
		||||
}
 | 
			
		||||
interface IState {
 | 
			
		||||
    mouseDown?: {
 | 
			
		||||
        x: number;
 | 
			
		||||
        y: number;
 | 
			
		||||
    };
 | 
			
		||||
    syncErrorData: any;
 | 
			
		||||
    useCompactLayout: boolean;
 | 
			
		||||
    serverNoticeEvents: MatrixEvent[];
 | 
			
		||||
    userHasGeneratedPassword: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This is what our MatrixChat shows when we are logged in. The precise view is
 | 
			
		||||
 * determined by the page_type property.
 | 
			
		||||
@@ -61,10 +109,10 @@ function canElementReceiveInput(el) {
 | 
			
		||||
 *
 | 
			
		||||
 * Components mounted below us can access the matrix client via the react context.
 | 
			
		||||
 */
 | 
			
		||||
const LoggedInView = createReactClass({
 | 
			
		||||
    displayName: 'LoggedInView',
 | 
			
		||||
class LoggedInView extends React.PureComponent<IProps, IState> {
 | 
			
		||||
    static displayName = 'LoggedInView';
 | 
			
		||||
 | 
			
		||||
    propTypes: {
 | 
			
		||||
    static propTypes = {
 | 
			
		||||
        matrixClient: PropTypes.instanceOf(MatrixClient).isRequired,
 | 
			
		||||
        page_type: PropTypes.string.isRequired,
 | 
			
		||||
        onRoomCreated: PropTypes.func,
 | 
			
		||||
@@ -77,25 +125,28 @@ const LoggedInView = createReactClass({
 | 
			
		||||
        viaServers: PropTypes.arrayOf(PropTypes.string),
 | 
			
		||||
 | 
			
		||||
        // and lots and lots of other stuff.
 | 
			
		||||
    },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    getInitialState: function() {
 | 
			
		||||
        return {
 | 
			
		||||
    protected readonly _matrixClient: MatrixClient;
 | 
			
		||||
    protected readonly _roomView: React.RefObject<any>;
 | 
			
		||||
    protected readonly _resizeContainer: React.RefObject<ResizeHandle>;
 | 
			
		||||
    protected readonly _sessionStore: sessionStore;
 | 
			
		||||
    protected readonly _sessionStoreToken: { remove: () => void };
 | 
			
		||||
    protected resizer: Resizer;
 | 
			
		||||
 | 
			
		||||
    constructor(props, context) {
 | 
			
		||||
        super(props, context);
 | 
			
		||||
 | 
			
		||||
        this.state = {
 | 
			
		||||
            mouseDown: undefined,
 | 
			
		||||
            syncErrorData: undefined,
 | 
			
		||||
            userHasGeneratedPassword: false,
 | 
			
		||||
            // use compact timeline view
 | 
			
		||||
            useCompactLayout: SettingsStore.getValue('useCompactLayout'),
 | 
			
		||||
            // any currently active server notice events
 | 
			
		||||
            serverNoticeEvents: [],
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    componentDidMount: function() {
 | 
			
		||||
        this.resizer = this._createResizer();
 | 
			
		||||
        this.resizer.attach();
 | 
			
		||||
        this._loadResizerPreferences();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
 | 
			
		||||
    UNSAFE_componentWillMount: function() {
 | 
			
		||||
        // stash the MatrixClient in case we log out before we are unmounted
 | 
			
		||||
        this._matrixClient = this.props.matrixClient;
 | 
			
		||||
 | 
			
		||||
@@ -117,22 +168,29 @@ const LoggedInView = createReactClass({
 | 
			
		||||
 | 
			
		||||
        fixupColorFonts();
 | 
			
		||||
 | 
			
		||||
        this._roomView = createRef();
 | 
			
		||||
    },
 | 
			
		||||
        this._roomView = React.createRef();
 | 
			
		||||
        this._resizeContainer = React.createRef();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentDidUpdate(prevProps) {
 | 
			
		||||
    componentDidMount() {
 | 
			
		||||
        this.resizer = this._createResizer();
 | 
			
		||||
        this.resizer.attach();
 | 
			
		||||
        this._loadResizerPreferences();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentDidUpdate(prevProps, prevState) {
 | 
			
		||||
        // attempt to guess when a banner was opened or closed
 | 
			
		||||
        if (
 | 
			
		||||
            (prevProps.showCookieBar !== this.props.showCookieBar) ||
 | 
			
		||||
            (prevProps.hasNewVersion !== this.props.hasNewVersion) ||
 | 
			
		||||
            (prevProps.userHasGeneratedPassword !== this.props.userHasGeneratedPassword) ||
 | 
			
		||||
            (prevState.userHasGeneratedPassword !== this.state.userHasGeneratedPassword) ||
 | 
			
		||||
            (prevProps.showNotifierToolbar !== this.props.showNotifierToolbar)
 | 
			
		||||
        ) {
 | 
			
		||||
            this.props.resizeNotifier.notifyBannersChanged();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentWillUnmount: function() {
 | 
			
		||||
    componentWillUnmount() {
 | 
			
		||||
        document.removeEventListener('keydown', this._onNativeKeyDown, false);
 | 
			
		||||
        this._matrixClient.removeListener("accountData", this.onAccountData);
 | 
			
		||||
        this._matrixClient.removeListener("sync", this.onSync);
 | 
			
		||||
@@ -141,7 +199,7 @@ const LoggedInView = createReactClass({
 | 
			
		||||
            this._sessionStoreToken.remove();
 | 
			
		||||
        }
 | 
			
		||||
        this.resizer.detach();
 | 
			
		||||
    },
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Child components assume that the client peg will not be null, so give them some
 | 
			
		||||
    // sort of assurance here by only allowing a re-render if the client is truthy.
 | 
			
		||||
@@ -149,22 +207,22 @@ const LoggedInView = createReactClass({
 | 
			
		||||
    // This is required because `LoggedInView` maintains its own state and if this state
 | 
			
		||||
    // updates after the client peg has been made null (during logout), then it will
 | 
			
		||||
    // attempt to re-render and the children will throw errors.
 | 
			
		||||
    shouldComponentUpdate: function() {
 | 
			
		||||
    shouldComponentUpdate() {
 | 
			
		||||
        return Boolean(MatrixClientPeg.get());
 | 
			
		||||
    },
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    canResetTimelineInRoom: function(roomId) {
 | 
			
		||||
    canResetTimelineInRoom = (roomId) => {
 | 
			
		||||
        if (!this._roomView.current) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return this._roomView.current.canResetTimeline();
 | 
			
		||||
    },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    _setStateFromSessionStore() {
 | 
			
		||||
    _setStateFromSessionStore = () => {
 | 
			
		||||
        this.setState({
 | 
			
		||||
            userHasGeneratedPassword: Boolean(this._sessionStore.getCachedPassword()),
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    _createResizer() {
 | 
			
		||||
        const classNames = {
 | 
			
		||||
@@ -188,24 +246,22 @@ const LoggedInView = createReactClass({
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
        const resizer = new Resizer(
 | 
			
		||||
            this.resizeContainer,
 | 
			
		||||
            this._resizeContainer.current,
 | 
			
		||||
            CollapseDistributor,
 | 
			
		||||
            collapseConfig);
 | 
			
		||||
        resizer.setClassNames(classNames);
 | 
			
		||||
        return resizer;
 | 
			
		||||
    },
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _loadResizerPreferences() {
 | 
			
		||||
        let lhsSize = window.localStorage.getItem("mx_lhs_size");
 | 
			
		||||
        if (lhsSize !== null) {
 | 
			
		||||
            lhsSize = parseInt(lhsSize, 10);
 | 
			
		||||
        } else {
 | 
			
		||||
        let lhsSize = parseInt(window.localStorage.getItem("mx_lhs_size"), 10);
 | 
			
		||||
        if (isNaN(lhsSize)) {
 | 
			
		||||
            lhsSize = 350;
 | 
			
		||||
        }
 | 
			
		||||
        this.resizer.forHandleAt(0).resize(lhsSize);
 | 
			
		||||
    },
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onAccountData: function(event) {
 | 
			
		||||
    onAccountData = (event) => {
 | 
			
		||||
        if (event.getType() === "im.vector.web.settings") {
 | 
			
		||||
            this.setState({
 | 
			
		||||
                useCompactLayout: event.getContent().useCompactLayout,
 | 
			
		||||
@@ -214,9 +270,9 @@ const LoggedInView = createReactClass({
 | 
			
		||||
        if (event.getType() === "m.ignored_user_list") {
 | 
			
		||||
            dis.dispatch({action: "ignore_state_changed"});
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    onSync: function(syncState, oldSyncState, data) {
 | 
			
		||||
    onSync = (syncState, oldSyncState, data) => {
 | 
			
		||||
        const oldErrCode = (
 | 
			
		||||
            this.state.syncErrorData &&
 | 
			
		||||
            this.state.syncErrorData.error &&
 | 
			
		||||
@@ -238,16 +294,16 @@ const LoggedInView = createReactClass({
 | 
			
		||||
        if (oldSyncState === 'PREPARED' && syncState === 'SYNCING') {
 | 
			
		||||
            this._updateServerNoticeEvents();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    onRoomStateEvents: function(ev, state) {
 | 
			
		||||
    onRoomStateEvents = (ev, state) => {
 | 
			
		||||
        const roomLists = RoomListStore.getRoomLists();
 | 
			
		||||
        if (roomLists['m.server_notice'] && roomLists['m.server_notice'].some(r => r.roomId === ev.getRoomId())) {
 | 
			
		||||
            this._updateServerNoticeEvents();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    _updateServerNoticeEvents: async function() {
 | 
			
		||||
    _updateServerNoticeEvents = async () => {
 | 
			
		||||
        const roomLists = RoomListStore.getRoomLists();
 | 
			
		||||
        if (!roomLists['m.server_notice']) return [];
 | 
			
		||||
 | 
			
		||||
@@ -260,16 +316,16 @@ const LoggedInView = createReactClass({
 | 
			
		||||
            const pinnedEventIds = pinStateEvent.getContent().pinned.slice(0, MAX_PINNED_NOTICES_PER_ROOM);
 | 
			
		||||
            for (const eventId of pinnedEventIds) {
 | 
			
		||||
                const timeline = await this._matrixClient.getEventTimeline(room.getUnfilteredTimelineSet(), eventId, 0);
 | 
			
		||||
                const ev = timeline.getEvents().find(ev => ev.getId() === eventId);
 | 
			
		||||
                if (ev) pinnedEvents.push(ev);
 | 
			
		||||
                const event = timeline.getEvents().find(ev => ev.getId() === eventId);
 | 
			
		||||
                if (event) pinnedEvents.push(event);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        this.setState({
 | 
			
		||||
            serverNoticeEvents: pinnedEvents,
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    _onPaste: function(ev) {
 | 
			
		||||
    _onPaste = (ev) => {
 | 
			
		||||
        let canReceiveInput = false;
 | 
			
		||||
        let element = ev.target;
 | 
			
		||||
        // test for all parents because the target can be a child of a contenteditable element
 | 
			
		||||
@@ -283,7 +339,7 @@ const LoggedInView = createReactClass({
 | 
			
		||||
            // so dispatch synchronously before paste happens
 | 
			
		||||
            dis.dispatch({action: 'focus_composer'}, true);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
    SOME HACKERY BELOW:
 | 
			
		||||
@@ -307,22 +363,22 @@ const LoggedInView = createReactClass({
 | 
			
		||||
    We also listen with a native listener on the document to get keydown events when no element is focused.
 | 
			
		||||
    Bubbling is irrelevant here as the target is the body element.
 | 
			
		||||
    */
 | 
			
		||||
    _onReactKeyDown: function(ev) {
 | 
			
		||||
    _onReactKeyDown = (ev) => {
 | 
			
		||||
        // events caught while bubbling up on the root element
 | 
			
		||||
        // of this component, so something must be focused.
 | 
			
		||||
        this._onKeyDown(ev);
 | 
			
		||||
    },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    _onNativeKeyDown: function(ev) {
 | 
			
		||||
    _onNativeKeyDown = (ev) => {
 | 
			
		||||
        // only pass this if there is no focused element.
 | 
			
		||||
        // if there is, _onKeyDown will be called by the
 | 
			
		||||
        // react keydown handler that respects the react bubbling order.
 | 
			
		||||
        if (ev.target === document.body) {
 | 
			
		||||
            this._onKeyDown(ev);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    _onKeyDown: function(ev) {
 | 
			
		||||
    _onKeyDown = (ev) => {
 | 
			
		||||
            /*
 | 
			
		||||
            // Remove this for now as ctrl+alt = alt-gr so this breaks keyboards which rely on alt-gr for numbers
 | 
			
		||||
            // Will need to find a better meta key if anyone actually cares about using this.
 | 
			
		||||
@@ -407,6 +463,11 @@ const LoggedInView = createReactClass({
 | 
			
		||||
                    });
 | 
			
		||||
                    handled = true;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            default:
 | 
			
		||||
                // if we do not have a handler for it, pass it to the platform which might
 | 
			
		||||
                handled = PlatformPeg.get().onKeyDown(ev);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (handled) {
 | 
			
		||||
@@ -432,19 +493,19 @@ const LoggedInView = createReactClass({
 | 
			
		||||
                // that would prevent typing in the now-focussed composer
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * dispatch a page-up/page-down/etc to the appropriate component
 | 
			
		||||
     * @param {Object} ev The key event
 | 
			
		||||
     */
 | 
			
		||||
    _onScrollKeyPressed: function(ev) {
 | 
			
		||||
    _onScrollKeyPressed = (ev) => {
 | 
			
		||||
        if (this._roomView.current) {
 | 
			
		||||
            this._roomView.current.handleScrollKey(ev);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    _onDragEnd: function(result) {
 | 
			
		||||
    _onDragEnd = (result) => {
 | 
			
		||||
        // Dragged to an invalid destination, not onto a droppable
 | 
			
		||||
        if (!result.destination) {
 | 
			
		||||
            return;
 | 
			
		||||
@@ -467,9 +528,9 @@ const LoggedInView = createReactClass({
 | 
			
		||||
        } else if (dest.startsWith('room-sub-list-droppable_')) {
 | 
			
		||||
            this._onRoomTileEndDrag(result);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    _onRoomTileEndDrag: function(result) {
 | 
			
		||||
    _onRoomTileEndDrag = (result) => {
 | 
			
		||||
        let newTag = result.destination.droppableId.split('_')[1];
 | 
			
		||||
        let prevTag = result.source.droppableId.split('_')[1];
 | 
			
		||||
        if (newTag === 'undefined') newTag = undefined;
 | 
			
		||||
@@ -486,9 +547,9 @@ const LoggedInView = createReactClass({
 | 
			
		||||
            prevTag, newTag,
 | 
			
		||||
            oldIndex, newIndex,
 | 
			
		||||
        ), true);
 | 
			
		||||
    },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    _onMouseDown: function(ev) {
 | 
			
		||||
    _onMouseDown = (ev) => {
 | 
			
		||||
        // When the panels are disabled, clicking on them results in a mouse event
 | 
			
		||||
        // which bubbles to certain elements in the tree. When this happens, close
 | 
			
		||||
        // any settings page that is currently open (user/room/group).
 | 
			
		||||
@@ -507,9 +568,9 @@ const LoggedInView = createReactClass({
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    _onMouseUp: function(ev) {
 | 
			
		||||
    _onMouseUp = (ev) => {
 | 
			
		||||
        if (!this.state.mouseDown) return;
 | 
			
		||||
 | 
			
		||||
        const deltaX = ev.pageX - this.state.mouseDown.x;
 | 
			
		||||
@@ -528,13 +589,9 @@ const LoggedInView = createReactClass({
 | 
			
		||||
        // Always clear the mouseDown state to ensure we don't accidentally
 | 
			
		||||
        // use stale values due to the mouseDown checks.
 | 
			
		||||
        this.setState({mouseDown: null});
 | 
			
		||||
    },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    _setResizeContainerRef(div) {
 | 
			
		||||
        this.resizeContainer = div;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    render: function() {
 | 
			
		||||
    render() {
 | 
			
		||||
        const LeftPanel = sdk.getComponent('structures.LeftPanel');
 | 
			
		||||
        const RoomView = sdk.getComponent('structures.RoomView');
 | 
			
		||||
        const UserView = sdk.getComponent('structures.UserView');
 | 
			
		||||
@@ -647,7 +704,7 @@ const LoggedInView = createReactClass({
 | 
			
		||||
                    { topBar }
 | 
			
		||||
                    <ToastContainer />
 | 
			
		||||
                    <DragDropContext onDragEnd={this._onDragEnd}>
 | 
			
		||||
                        <div ref={this._setResizeContainerRef} className={bodyClasses}>
 | 
			
		||||
                        <div ref={this._resizeContainer} className={bodyClasses}>
 | 
			
		||||
                            <LeftPanel
 | 
			
		||||
                                resizeNotifier={this.props.resizeNotifier}
 | 
			
		||||
                                collapsed={this.props.collapseLhs || false}
 | 
			
		||||
@@ -660,7 +717,7 @@ const LoggedInView = createReactClass({
 | 
			
		||||
                </div>
 | 
			
		||||
            </MatrixClientContext.Provider>
 | 
			
		||||
        );
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default LoggedInView;
 | 
			
		||||
@@ -49,7 +49,6 @@ import RoomViewStore from '../../stores/RoomViewStore';
 | 
			
		||||
import RoomScrollStateStore from '../../stores/RoomScrollStateStore';
 | 
			
		||||
import WidgetEchoStore from '../../stores/WidgetEchoStore';
 | 
			
		||||
import SettingsStore, {SettingLevel} from "../../settings/SettingsStore";
 | 
			
		||||
import WidgetUtils from '../../utils/WidgetUtils';
 | 
			
		||||
import AccessibleButton from "../views/elements/AccessibleButton";
 | 
			
		||||
import RightPanelStore from "../../stores/RightPanelStore";
 | 
			
		||||
import {haveTileForEvent} from "../views/rooms/EventTile";
 | 
			
		||||
@@ -406,13 +405,9 @@ export default createReactClass({
 | 
			
		||||
        const hideWidgetDrawer = localStorage.getItem(
 | 
			
		||||
            room.roomId + "_hide_widget_drawer");
 | 
			
		||||
 | 
			
		||||
        if (hideWidgetDrawer === "true") {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const widgets = WidgetEchoStore.getEchoedRoomWidgets(room.roomId, WidgetUtils.getRoomWidgets(room));
 | 
			
		||||
 | 
			
		||||
        return widgets.length > 0 || WidgetEchoStore.roomHasPendingWidgets(room.roomId, WidgetUtils.getRoomWidgets(room));
 | 
			
		||||
        // This is confusing, but it means to say that we default to the tray being
 | 
			
		||||
        // hidden unless the user clicked to open it.
 | 
			
		||||
        return hideWidgetDrawer === "false";
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    componentDidMount: function() {
 | 
			
		||||
 
 | 
			
		||||
@@ -108,14 +108,13 @@ export default class SetupEncryptionBody extends React.Component {
 | 
			
		||||
                member={MatrixClientPeg.get().getUser(this.state.verificationRequest.otherUserId)}
 | 
			
		||||
            />;
 | 
			
		||||
        } else if (phase === PHASE_INTRO) {
 | 
			
		||||
            const InlineSpinner = sdk.getComponent('elements.InlineSpinner');
 | 
			
		||||
            const ButtonPlaceholder = sdk.getComponent("elements.ButtonPlaceholder");
 | 
			
		||||
            return (
 | 
			
		||||
                <div>
 | 
			
		||||
                    <p>{_t(
 | 
			
		||||
                        "Open an existing session & use it to verify this one, " +
 | 
			
		||||
                        "Use an existing session to verify this one, " +
 | 
			
		||||
                        "granting it access to encrypted messages.",
 | 
			
		||||
                    )}</p>
 | 
			
		||||
                    <p className="mx_CompleteSecurity_waiting"><InlineSpinner />{_t("Waiting…")}</p>
 | 
			
		||||
                    <p>{_t(
 | 
			
		||||
                        "If you can’t access one, <button>use your recovery key or passphrase.</button>",
 | 
			
		||||
                    {}, {
 | 
			
		||||
@@ -133,6 +132,7 @@ export default class SetupEncryptionBody extends React.Component {
 | 
			
		||||
                        >
 | 
			
		||||
                            {_t("Skip")}
 | 
			
		||||
                        </AccessibleButton>
 | 
			
		||||
                        <ButtonPlaceholder>{_t("Use your other device to continue…")}</ButtonPlaceholder>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            );
 | 
			
		||||
 
 | 
			
		||||
@@ -66,7 +66,7 @@ export default createReactClass({
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!this.state.isPublic && SettingsStore.isFeatureEnabled("feature_cross_signing")) {
 | 
			
		||||
            createOpts.encryption = this.state.isEncrypted;
 | 
			
		||||
            opts.encryption = this.state.isEncrypted;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return opts;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								src/components/views/elements/ButtonPlaceholder.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/components/views/elements/ButtonPlaceholder.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
/*
 | 
			
		||||
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.
 | 
			
		||||
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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
export default function ButtonPlaceholder(props) {
 | 
			
		||||
    return <div class="mx_ButtonPlaceholder">{props.children}</div>;
 | 
			
		||||
}
 | 
			
		||||
@@ -81,12 +81,14 @@ export default createReactClass({
 | 
			
		||||
        const hideWidgetKey = this.props.room.roomId + '_hide_widget_drawer';
 | 
			
		||||
        switch (action.action) {
 | 
			
		||||
            case 'appsDrawer':
 | 
			
		||||
                // Note: these booleans are awkward because localstorage is fundamentally
 | 
			
		||||
                // string-based. We also do exact equality on the strings later on.
 | 
			
		||||
                if (action.show) {
 | 
			
		||||
                    localStorage.removeItem(hideWidgetKey);
 | 
			
		||||
                    localStorage.setItem(hideWidgetKey, "false");
 | 
			
		||||
                } else {
 | 
			
		||||
                    // Store hidden state of widget
 | 
			
		||||
                    // Don't show if previously hidden
 | 
			
		||||
                    localStorage.setItem(hideWidgetKey, true);
 | 
			
		||||
                    localStorage.setItem(hideWidgetKey, "true");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                break;
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,7 @@ import EMOTICON_REGEX from 'emojibase-regex/emoticon';
 | 
			
		||||
import * as sdk from '../../../index';
 | 
			
		||||
import {Key} from "../../../Keyboard";
 | 
			
		||||
import {EMOTICON_TO_EMOJI} from "../../../emoji";
 | 
			
		||||
import {CommandCategories, CommandMap, parseCommandString} from "../../../SlashCommands";
 | 
			
		||||
 | 
			
		||||
const REGEX_EMOTICON_WHITESPACE = new RegExp('(?:^|\\s)(' + EMOTICON_REGEX.source + ')\\s$');
 | 
			
		||||
 | 
			
		||||
@@ -84,6 +85,7 @@ export default class BasicMessageEditor extends React.Component {
 | 
			
		||||
        super(props);
 | 
			
		||||
        this.state = {
 | 
			
		||||
            autoComplete: null,
 | 
			
		||||
            showPillAvatar: SettingsStore.getValue("Pill.shouldShowPillAvatar"),
 | 
			
		||||
        };
 | 
			
		||||
        this._editorRef = null;
 | 
			
		||||
        this._autocompleteRef = null;
 | 
			
		||||
@@ -92,6 +94,7 @@ export default class BasicMessageEditor extends React.Component {
 | 
			
		||||
        this._isIMEComposing = false;
 | 
			
		||||
        this._hasTextSelected = false;
 | 
			
		||||
        this._emoticonSettingHandle = null;
 | 
			
		||||
        this._shouldShowPillAvatarSettingHandle = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentDidUpdate(prevProps) {
 | 
			
		||||
@@ -162,7 +165,16 @@ export default class BasicMessageEditor extends React.Component {
 | 
			
		||||
        }
 | 
			
		||||
        this.setState({autoComplete: this.props.model.autoComplete});
 | 
			
		||||
        this.historyManager.tryPush(this.props.model, selection, inputType, diff);
 | 
			
		||||
        TypingStore.sharedInstance().setSelfTyping(this.props.room.roomId, !this.props.model.isEmpty);
 | 
			
		||||
 | 
			
		||||
        let isTyping = !this.props.model.isEmpty;
 | 
			
		||||
        // If the user is entering a command, only consider them typing if it is one which sends a message into the room
 | 
			
		||||
        if (isTyping && this.props.model.parts[0].type === "command") {
 | 
			
		||||
            const {cmd} = parseCommandString(this.props.model.parts[0].text);
 | 
			
		||||
            if (!CommandMap.has(cmd) || CommandMap.get(cmd).category !== CommandCategories.messages) {
 | 
			
		||||
                isTyping = false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        TypingStore.sharedInstance().setSelfTyping(this.props.room.roomId, isTyping);
 | 
			
		||||
 | 
			
		||||
        if (this.props.onChange) {
 | 
			
		||||
            this.props.onChange();
 | 
			
		||||
@@ -508,10 +520,15 @@ export default class BasicMessageEditor extends React.Component {
 | 
			
		||||
        this.setState({completionIndex});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _configureEmoticonAutoReplace() {
 | 
			
		||||
    _configureEmoticonAutoReplace = () => {
 | 
			
		||||
        const shouldReplace = SettingsStore.getValue('MessageComposerInput.autoReplaceEmoji');
 | 
			
		||||
        this.props.model.setTransformCallback(shouldReplace ? this._replaceEmoticon : null);
 | 
			
		||||
    }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    _configureShouldShowPillAvatar = () => {
 | 
			
		||||
        const showPillAvatar = SettingsStore.getValue("Pill.shouldShowPillAvatar");
 | 
			
		||||
        this.setState({ showPillAvatar });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    componentWillUnmount() {
 | 
			
		||||
        document.removeEventListener("selectionchange", this._onSelectionChange);
 | 
			
		||||
@@ -519,15 +536,17 @@ export default class BasicMessageEditor extends React.Component {
 | 
			
		||||
        this._editorRef.removeEventListener("compositionstart", this._onCompositionStart, true);
 | 
			
		||||
        this._editorRef.removeEventListener("compositionend", this._onCompositionEnd, true);
 | 
			
		||||
        SettingsStore.unwatchSetting(this._emoticonSettingHandle);
 | 
			
		||||
        SettingsStore.unwatchSetting(this._shouldShowPillAvatarSettingHandle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentDidMount() {
 | 
			
		||||
        const model = this.props.model;
 | 
			
		||||
        model.setUpdateCallback(this._updateEditorState);
 | 
			
		||||
        this._emoticonSettingHandle = SettingsStore.watchSetting('MessageComposerInput.autoReplaceEmoji', null, () => {
 | 
			
		||||
            this._configureEmoticonAutoReplace();
 | 
			
		||||
        });
 | 
			
		||||
        this._emoticonSettingHandle = SettingsStore.watchSetting('MessageComposerInput.autoReplaceEmoji', null,
 | 
			
		||||
            this._configureEmoticonAutoReplace);
 | 
			
		||||
        this._configureEmoticonAutoReplace();
 | 
			
		||||
        this._shouldShowPillAvatarSettingHandle = SettingsStore.watchSetting("Pill.shouldShowPillAvatar", null,
 | 
			
		||||
            this._configureShouldShowPillAvatar);
 | 
			
		||||
        const partCreator = model.partCreator;
 | 
			
		||||
        // TODO: does this allow us to get rid of EditorStateTransfer?
 | 
			
		||||
        // not really, but we could not serialize the parts, and just change the autoCompleter
 | 
			
		||||
@@ -605,9 +624,12 @@ export default class BasicMessageEditor extends React.Component {
 | 
			
		||||
                />
 | 
			
		||||
            </div>);
 | 
			
		||||
        }
 | 
			
		||||
        const classes = classNames("mx_BasicMessageComposer", {
 | 
			
		||||
        const wrapperClasses = classNames("mx_BasicMessageComposer", {
 | 
			
		||||
            "mx_BasicMessageComposer_input_error": this.state.showVisualBell,
 | 
			
		||||
        });
 | 
			
		||||
        const classes = classNames("mx_BasicMessageComposer_input", {
 | 
			
		||||
            "mx_BasicMessageComposer_input_shouldShowPillAvatar": this.state.showPillAvatar,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        const MessageComposerFormatBar = sdk.getComponent('rooms.MessageComposerFormatBar');
 | 
			
		||||
        const shortcuts = {
 | 
			
		||||
@@ -618,11 +640,11 @@ export default class BasicMessageEditor extends React.Component {
 | 
			
		||||
 | 
			
		||||
        const {completionIndex} = this.state;
 | 
			
		||||
 | 
			
		||||
        return (<div className={classes}>
 | 
			
		||||
        return (<div className={wrapperClasses}>
 | 
			
		||||
            { autoComplete }
 | 
			
		||||
            <MessageComposerFormatBar ref={ref => this._formatBarRef = ref} onAction={this._onFormatAction} shortcuts={shortcuts} />
 | 
			
		||||
            <div
 | 
			
		||||
                className="mx_BasicMessageComposer_input"
 | 
			
		||||
                className={classes}
 | 
			
		||||
                contentEditable="true"
 | 
			
		||||
                tabIndex="0"
 | 
			
		||||
                onBlur={this._onBlur}
 | 
			
		||||
 
 | 
			
		||||
@@ -59,6 +59,7 @@ const stateEventTileTypes = {
 | 
			
		||||
    'm.room.power_levels': 'messages.TextualEvent',
 | 
			
		||||
    'm.room.pinned_events': 'messages.TextualEvent',
 | 
			
		||||
    'm.room.server_acl': 'messages.TextualEvent',
 | 
			
		||||
    // TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
 | 
			
		||||
    'im.vector.modular.widgets': 'messages.TextualEvent',
 | 
			
		||||
    'm.room.tombstone': 'messages.TextualEvent',
 | 
			
		||||
    'm.room.join_rules': 'messages.TextualEvent',
 | 
			
		||||
 
 | 
			
		||||
@@ -139,7 +139,7 @@ export default class DevicesPanel extends React.Component {
 | 
			
		||||
                    body: _t("Click the button below to confirm deleting these sessions.", {
 | 
			
		||||
                        count: numDevices,
 | 
			
		||||
                    }),
 | 
			
		||||
                    continueText: _t("Delete sessions"),
 | 
			
		||||
                    continueText: _t("Delete sessions", {count: numDevices}),
 | 
			
		||||
                    continueKind: "danger",
 | 
			
		||||
                },
 | 
			
		||||
            };
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,7 @@ const plEventsToLabels = {
 | 
			
		||||
    "m.room.tombstone": _td("Upgrade the room"),
 | 
			
		||||
    "m.room.encryption": _td("Enable room encryption"),
 | 
			
		||||
 | 
			
		||||
    // TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
 | 
			
		||||
    "im.vector.modular.widgets": _td("Modify widgets"),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -47,6 +48,7 @@ const plEventsToShow = {
 | 
			
		||||
    "m.room.tombstone": {isState: true},
 | 
			
		||||
    "m.room.encryption": {isState: true},
 | 
			
		||||
 | 
			
		||||
    // TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
 | 
			
		||||
    "im.vector.modular.widgets": {isState: true},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -20,8 +20,8 @@ import { _t } from '../../../languageHandler';
 | 
			
		||||
import AccessibleButton from "../elements/AccessibleButton";
 | 
			
		||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
 | 
			
		||||
import VerificationQRCode from "../elements/crypto/VerificationQRCode";
 | 
			
		||||
import {VerificationRequest} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
 | 
			
		||||
import Spinner from "../elements/Spinner";
 | 
			
		||||
import {SCAN_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode";
 | 
			
		||||
 | 
			
		||||
@replaceableComponent("views.verification.VerificationQREmojiOptions")
 | 
			
		||||
export default class VerificationQREmojiOptions extends React.Component {
 | 
			
		||||
@@ -31,31 +31,17 @@ export default class VerificationQREmojiOptions extends React.Component {
 | 
			
		||||
        onStartEmoji: PropTypes.func.isRequired,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    constructor(props) {
 | 
			
		||||
        super(props);
 | 
			
		||||
 | 
			
		||||
        this.state = {
 | 
			
		||||
            qrProps: null,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        this._prepareQrCode(props.request);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async _prepareQrCode(request: VerificationRequest) {
 | 
			
		||||
        try {
 | 
			
		||||
            const props = await VerificationQRCode.getPropsForRequest(request);
 | 
			
		||||
            this.setState({qrProps: props});
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            console.error(e);
 | 
			
		||||
            // We just won't show a QR code
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
        let qrCode = <div className='mx_VerificationQREmojiOptions_noQR'><Spinner /></div>;
 | 
			
		||||
        if (this.state.qrProps) {
 | 
			
		||||
            qrCode = <VerificationQRCode {...this.state.qrProps} />;
 | 
			
		||||
        const {request} = this.props;
 | 
			
		||||
        const showQR = request.otherPartySupportsMethod(SCAN_QR_CODE_METHOD);
 | 
			
		||||
 | 
			
		||||
        let qrCode;
 | 
			
		||||
        if (showQR) {
 | 
			
		||||
            qrCode = <VerificationQRCode qrCodeData={request.qrCodeData} />;
 | 
			
		||||
        } else {
 | 
			
		||||
            qrCode = <div className='mx_VerificationQREmojiOptions_noQR'><Spinner /></div>;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
            <div>
 | 
			
		||||
                {_t("Verify this session by completing one of the following:")}
 | 
			
		||||
 
 | 
			
		||||
@@ -132,12 +132,12 @@ export default class VerificationShowSas extends React.Component {
 | 
			
		||||
            />;
 | 
			
		||||
        } 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>
 | 
			
		||||
                <AccessibleButton onClick={this.onMatchClick} kind="primary">
 | 
			
		||||
                    { _t("They match") }
 | 
			
		||||
                </AccessibleButton>
 | 
			
		||||
            </React.Fragment>;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -177,6 +177,7 @@
 | 
			
		||||
    "Changes your avatar in this current room only": "Changes your avatar in this current room only",
 | 
			
		||||
    "Changes your avatar in all rooms": "Changes your avatar in all rooms",
 | 
			
		||||
    "Gets or sets the room topic": "Gets or sets the room topic",
 | 
			
		||||
    "Failed to set topic": "Failed to set topic",
 | 
			
		||||
    "This room has no topic.": "This room has no topic.",
 | 
			
		||||
    "Sets the room name": "Sets the room name",
 | 
			
		||||
    "Invites user with given id to current room": "Invites user with given id to current room",
 | 
			
		||||
@@ -196,6 +197,8 @@
 | 
			
		||||
    "Unignored user": "Unignored user",
 | 
			
		||||
    "You are no longer ignoring %(userId)s": "You are no longer ignoring %(userId)s",
 | 
			
		||||
    "Define the power level of a user": "Define the power level of a user",
 | 
			
		||||
    "Command failed": "Command failed",
 | 
			
		||||
    "Could not find user in room": "Could not find user in room",
 | 
			
		||||
    "Deops user with given id": "Deops user with given id",
 | 
			
		||||
    "Opens the Developer Tools dialog": "Opens the Developer Tools dialog",
 | 
			
		||||
    "Adds a custom widget by URL to the room": "Adds a custom widget by URL to the room",
 | 
			
		||||
@@ -618,7 +621,8 @@
 | 
			
		||||
    "Confirm deleting these sessions": "Confirm deleting these sessions",
 | 
			
		||||
    "Click the button below to confirm deleting these sessions.|other": "Click the button below to confirm deleting these sessions.",
 | 
			
		||||
    "Click the button below to confirm deleting these sessions.|one": "Click the button below to confirm deleting this session.",
 | 
			
		||||
    "Delete sessions": "Delete sessions",
 | 
			
		||||
    "Delete sessions|other": "Delete sessions",
 | 
			
		||||
    "Delete sessions|one": "Delete session",
 | 
			
		||||
    "Authentication": "Authentication",
 | 
			
		||||
    "Delete %(count)s sessions|other": "Delete %(count)s sessions",
 | 
			
		||||
    "Delete %(count)s sessions|one": "Delete %(count)s session",
 | 
			
		||||
@@ -2111,9 +2115,9 @@
 | 
			
		||||
    "You can now close this window or <a>log in</a> to your new account.": "You can now close this window or <a>log in</a> to your new account.",
 | 
			
		||||
    "Registration Successful": "Registration Successful",
 | 
			
		||||
    "Create your account": "Create your account",
 | 
			
		||||
    "Open an existing session & use it to verify this one, granting it access to encrypted messages.": "Open an existing session & use it to verify this one, granting it access to encrypted messages.",
 | 
			
		||||
    "Waiting…": "Waiting…",
 | 
			
		||||
    "Use an existing session to verify this one, granting it access to encrypted messages.": "Use an existing session to verify this one, granting it access to encrypted messages.",
 | 
			
		||||
    "If you can’t access one, <button>use your recovery key or passphrase.</button>": "If you can’t access one, <button>use your recovery key or passphrase.</button>",
 | 
			
		||||
    "Use your other device to continue…": "Use your other device to continue…",
 | 
			
		||||
    "Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.": "Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.",
 | 
			
		||||
    "Your new session is now verified. Other users will see it as trusted.": "Your new session is now verified. Other users will see it as trusted.",
 | 
			
		||||
    "Without completing security on this session, it won’t have access to encrypted messages.": "Without completing security on this session, it won’t have access to encrypted messages.",
 | 
			
		||||
 
 | 
			
		||||
@@ -64,6 +64,7 @@ class ActiveWidgetStore extends EventEmitter {
 | 
			
		||||
        // Everything else relies on views listening for events and calling setters
 | 
			
		||||
        // on this class which is terrible. This store should just listen for events
 | 
			
		||||
        // and keep itself up to date.
 | 
			
		||||
        // TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
 | 
			
		||||
        if (ev.getType() !== 'im.vector.modular.widgets') return;
 | 
			
		||||
 | 
			
		||||
        if (ev.getStateKey() === this._persistentWidgetId) {
 | 
			
		||||
 
 | 
			
		||||
@@ -68,6 +68,7 @@ export default class WidgetUtils {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
 | 
			
		||||
        return room.currentState.maySendStateEvent('im.vector.modular.widgets', me);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -182,6 +183,7 @@ export default class WidgetUtils {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const room = MatrixClientPeg.get().getRoom(roomId);
 | 
			
		||||
            // TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
 | 
			
		||||
            const startingWidgetEvents = room.currentState.getStateEvents('im.vector.modular.widgets');
 | 
			
		||||
            if (eventsInIntendedState(startingWidgetEvents)) {
 | 
			
		||||
                resolve();
 | 
			
		||||
@@ -191,6 +193,7 @@ export default class WidgetUtils {
 | 
			
		||||
            function onRoomStateEvents(ev) {
 | 
			
		||||
                if (ev.getRoomId() !== roomId) return;
 | 
			
		||||
 | 
			
		||||
                // TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
 | 
			
		||||
                const currentWidgetEvents = room.currentState.getStateEvents('im.vector.modular.widgets');
 | 
			
		||||
 | 
			
		||||
                if (eventsInIntendedState(currentWidgetEvents)) {
 | 
			
		||||
@@ -272,8 +275,7 @@ export default class WidgetUtils {
 | 
			
		||||
        WidgetEchoStore.setRoomWidgetEcho(roomId, widgetId, content);
 | 
			
		||||
 | 
			
		||||
        const client = MatrixClientPeg.get();
 | 
			
		||||
        // TODO - Room widgets need to be moved to 'm.widget' state events
 | 
			
		||||
        // https://docs.google.com/document/d/1uPF7XWY_dXTKVKV7jZQ2KmsI19wn9-kFRgQ1tFQP7wQ/edit?usp=sharing
 | 
			
		||||
        // TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
 | 
			
		||||
        return client.sendStateEvent(roomId, "im.vector.modular.widgets", content, widgetId).then(() => {
 | 
			
		||||
            return WidgetUtils.waitForRoomWidget(widgetId, roomId, addingWidget);
 | 
			
		||||
        }).finally(() => {
 | 
			
		||||
@@ -287,6 +289,7 @@ export default class WidgetUtils {
 | 
			
		||||
     * @return {[object]} Array containing current / active room widgets
 | 
			
		||||
     */
 | 
			
		||||
    static getRoomWidgets(room: Room) {
 | 
			
		||||
        // TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
 | 
			
		||||
        const appsStateEvents = room.currentState.getStateEvents('im.vector.modular.widgets');
 | 
			
		||||
        if (!appsStateEvents) {
 | 
			
		||||
            return [];
 | 
			
		||||
 
 | 
			
		||||
@@ -61,15 +61,18 @@ function UntrustedDeviceDialog(props) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function verifyDevice(user, device) {
 | 
			
		||||
    const cli = MatrixClientPeg.get();
 | 
			
		||||
    // if cross-signing is not explicitly disabled, check if it should be enabled first.
 | 
			
		||||
    if (cli.getCryptoTrustCrossSignedDevices()) {
 | 
			
		||||
        if (!await enable4SIfNeeded()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    Modal.createTrackedDialog("Verification warning", "unverified session", UntrustedDeviceDialog, {
 | 
			
		||||
        user,
 | 
			
		||||
        device,
 | 
			
		||||
        onFinished: async (action) => {
 | 
			
		||||
            if (action === "sas") {
 | 
			
		||||
                const cli = MatrixClientPeg.get();
 | 
			
		||||
                const verificationRequestPromise = cli.legacyDeviceVerification(
 | 
			
		||||
                    user.userId,
 | 
			
		||||
                    device.deviceId,
 | 
			
		||||
@@ -95,10 +98,13 @@ export async function verifyDevice(user, device) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function legacyVerifyUser(user) {
 | 
			
		||||
    const cli = MatrixClientPeg.get();
 | 
			
		||||
    // if cross-signing is not explicitly disabled, check if it should be enabled first.
 | 
			
		||||
    if (cli.getCryptoTrustCrossSignedDevices()) {
 | 
			
		||||
        if (!await enable4SIfNeeded()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    const cli = MatrixClientPeg.get();
 | 
			
		||||
    }
 | 
			
		||||
    const verificationRequestPromise = cli.requestVerification(user.userId);
 | 
			
		||||
    dis.dispatch({
 | 
			
		||||
        action: "set_right_panel_phase",
 | 
			
		||||
 
 | 
			
		||||
@@ -177,6 +177,7 @@ describe.skip('RoomSettings', () => {
 | 
			
		||||
                        'm.room.history_visibility': 50,
 | 
			
		||||
                        'm.room.power_levels': 50,
 | 
			
		||||
                        'm.room.topic': 50,
 | 
			
		||||
                        // TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
 | 
			
		||||
                        'im.vector.modular.widgets': 50,
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										234
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										234
									
								
								yarn.lock
									
									
									
									
									
								
							@@ -1496,11 +1496,6 @@ abab@^2.0.0:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a"
 | 
			
		||||
  integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==
 | 
			
		||||
 | 
			
		||||
abbrev@1:
 | 
			
		||||
  version "1.1.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
 | 
			
		||||
  integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
 | 
			
		||||
 | 
			
		||||
acorn-globals@^4.1.0:
 | 
			
		||||
  version "4.3.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7"
 | 
			
		||||
@@ -1634,19 +1629,11 @@ anymatch@~3.1.1:
 | 
			
		||||
    normalize-path "^3.0.0"
 | 
			
		||||
    picomatch "^2.0.4"
 | 
			
		||||
 | 
			
		||||
aproba@^1.0.3, aproba@^1.1.1:
 | 
			
		||||
aproba@^1.1.1:
 | 
			
		||||
  version "1.2.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
 | 
			
		||||
  integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
 | 
			
		||||
 | 
			
		||||
are-we-there-yet@~1.1.2:
 | 
			
		||||
  version "1.1.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
 | 
			
		||||
  integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    delegates "^1.0.0"
 | 
			
		||||
    readable-stream "^2.0.6"
 | 
			
		||||
 | 
			
		||||
argparse@^1.0.7:
 | 
			
		||||
  version "1.0.10"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
 | 
			
		||||
@@ -2283,11 +2270,6 @@ ccount@^1.0.0:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.0.5.tgz#ac82a944905a65ce204eb03023157edf29425c17"
 | 
			
		||||
  integrity sha512-MOli1W+nfbPLlKEhInaxhRdp7KVLFxLN5ykwzHgLsLI3H3gs5jjFAK4Eoj3OzzcxCtumDaI8onoVDeQyWaNTkw==
 | 
			
		||||
 | 
			
		||||
chain-function@^1.0.0:
 | 
			
		||||
  version "1.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/chain-function/-/chain-function-1.0.1.tgz#c63045e5b4b663fb86f1c6e186adaf1de402a1cc"
 | 
			
		||||
  integrity sha512-SxltgMwL9uCko5/ZCLiyG2B7R9fY4pDZUw7hJ4MhirdjBLosoDqkWABi3XMucddHdLiFJMb7PD2MZifZriuMTg==
 | 
			
		||||
 | 
			
		||||
chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2:
 | 
			
		||||
  version "2.4.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
 | 
			
		||||
@@ -2553,11 +2535,6 @@ console-browserify@^1.1.0:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336"
 | 
			
		||||
  integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==
 | 
			
		||||
 | 
			
		||||
console-control-strings@^1.0.0, console-control-strings@~1.1.0:
 | 
			
		||||
  version "1.1.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
 | 
			
		||||
  integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
 | 
			
		||||
 | 
			
		||||
constants-browserify@^1.0.0:
 | 
			
		||||
  version "1.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
 | 
			
		||||
@@ -2803,7 +2780,7 @@ debug@^2.2.0, debug@^2.3.3:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    ms "2.0.0"
 | 
			
		||||
 | 
			
		||||
debug@^3.1.0, debug@^3.2.6:
 | 
			
		||||
debug@^3.1.0:
 | 
			
		||||
  version "3.2.6"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
 | 
			
		||||
  integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
 | 
			
		||||
@@ -2879,11 +2856,6 @@ delayed-stream@~1.0.0:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
 | 
			
		||||
  integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
 | 
			
		||||
 | 
			
		||||
delegates@^1.0.0:
 | 
			
		||||
  version "1.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
 | 
			
		||||
  integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
 | 
			
		||||
 | 
			
		||||
des.js@^1.0.0:
 | 
			
		||||
  version "1.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843"
 | 
			
		||||
@@ -2897,11 +2869,6 @@ detect-file@^1.0.0:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
 | 
			
		||||
  integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=
 | 
			
		||||
 | 
			
		||||
detect-libc@^1.0.2:
 | 
			
		||||
  version "1.0.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
 | 
			
		||||
  integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
 | 
			
		||||
 | 
			
		||||
detect-newline@^2.1.0:
 | 
			
		||||
  version "2.1.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2"
 | 
			
		||||
@@ -2975,13 +2942,6 @@ doctrine@^3.0.0:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    esutils "^2.0.2"
 | 
			
		||||
 | 
			
		||||
dom-helpers@^3.2.0:
 | 
			
		||||
  version "3.4.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8"
 | 
			
		||||
  integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/runtime" "^7.1.2"
 | 
			
		||||
 | 
			
		||||
dom-serializer@0, dom-serializer@^0.2.1:
 | 
			
		||||
  version "0.2.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51"
 | 
			
		||||
@@ -3916,13 +3876,6 @@ from2@^2.1.0:
 | 
			
		||||
    inherits "^2.0.1"
 | 
			
		||||
    readable-stream "^2.0.0"
 | 
			
		||||
 | 
			
		||||
fs-minipass@^1.2.5:
 | 
			
		||||
  version "1.2.7"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7"
 | 
			
		||||
  integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    minipass "^2.6.0"
 | 
			
		||||
 | 
			
		||||
fs-readdir-recursive@^1.1.0:
 | 
			
		||||
  version "1.1.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27"
 | 
			
		||||
@@ -3985,20 +3938,6 @@ fuse.js@^2.2.0:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-2.7.4.tgz#96e420fde7ef011ac49c258a621314fe576536f9"
 | 
			
		||||
  integrity sha1-luQg/efvARrEnCWKYhMU/ldlNvk=
 | 
			
		||||
 | 
			
		||||
gauge@~2.7.3:
 | 
			
		||||
  version "2.7.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
 | 
			
		||||
  integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=
 | 
			
		||||
  dependencies:
 | 
			
		||||
    aproba "^1.0.3"
 | 
			
		||||
    console-control-strings "^1.0.0"
 | 
			
		||||
    has-unicode "^2.0.0"
 | 
			
		||||
    object-assign "^4.1.0"
 | 
			
		||||
    signal-exit "^3.0.0"
 | 
			
		||||
    string-width "^1.0.1"
 | 
			
		||||
    strip-ansi "^3.0.1"
 | 
			
		||||
    wide-align "^1.1.0"
 | 
			
		||||
 | 
			
		||||
gensync@^1.0.0-beta.1:
 | 
			
		||||
  version "1.0.0-beta.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
 | 
			
		||||
@@ -4196,11 +4135,6 @@ has-symbols@^1.0.0, has-symbols@^1.0.1:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
 | 
			
		||||
  integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
 | 
			
		||||
 | 
			
		||||
has-unicode@^2.0.0:
 | 
			
		||||
  version "2.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
 | 
			
		||||
  integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
 | 
			
		||||
 | 
			
		||||
has-value@^0.3.1:
 | 
			
		||||
  version "0.3.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
 | 
			
		||||
@@ -4388,7 +4322,7 @@ humanize-ms@^1.2.1:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    ms "^2.0.0"
 | 
			
		||||
 | 
			
		||||
iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
 | 
			
		||||
iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@~0.4.13:
 | 
			
		||||
  version "0.4.24"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
 | 
			
		||||
  integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
 | 
			
		||||
@@ -4405,13 +4339,6 @@ iferr@^0.1.5:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501"
 | 
			
		||||
  integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE=
 | 
			
		||||
 | 
			
		||||
ignore-walk@^3.0.1:
 | 
			
		||||
  version "3.0.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37"
 | 
			
		||||
  integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    minimatch "^3.0.4"
 | 
			
		||||
 | 
			
		||||
ignore@^4.0.3, ignore@^4.0.6:
 | 
			
		||||
  version "4.0.6"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
 | 
			
		||||
@@ -5975,21 +5902,6 @@ minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5, "minimist@~ 1.2.0":
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
 | 
			
		||||
  integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
 | 
			
		||||
 | 
			
		||||
minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0:
 | 
			
		||||
  version "2.9.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6"
 | 
			
		||||
  integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    safe-buffer "^5.1.2"
 | 
			
		||||
    yallist "^3.0.0"
 | 
			
		||||
 | 
			
		||||
minizlib@^1.2.1:
 | 
			
		||||
  version "1.3.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d"
 | 
			
		||||
  integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    minipass "^2.9.0"
 | 
			
		||||
 | 
			
		||||
mississippi@^3.0.0:
 | 
			
		||||
  version "3.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022"
 | 
			
		||||
@@ -6014,7 +5926,7 @@ mixin-deep@^1.2.0:
 | 
			
		||||
    for-in "^1.0.2"
 | 
			
		||||
    is-extendable "^1.0.1"
 | 
			
		||||
 | 
			
		||||
mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3:
 | 
			
		||||
mkdirp@^0.5.1, mkdirp@^0.5.3:
 | 
			
		||||
  version "0.5.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
 | 
			
		||||
  integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
 | 
			
		||||
@@ -6091,15 +6003,6 @@ nearley@^2.7.10:
 | 
			
		||||
    randexp "0.4.6"
 | 
			
		||||
    semver "^5.4.1"
 | 
			
		||||
 | 
			
		||||
needle@^2.2.1:
 | 
			
		||||
  version "2.4.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.1.tgz#14af48732463d7475696f937626b1b993247a56a"
 | 
			
		||||
  integrity sha512-x/gi6ijr4B7fwl6WYL9FwlCvRQKGlUNvnceho8wxkwXqN8jvVmmmATTmZPRRG7b/yC1eode26C2HO9jl78Du9g==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    debug "^3.2.6"
 | 
			
		||||
    iconv-lite "^0.4.4"
 | 
			
		||||
    sax "^1.2.4"
 | 
			
		||||
 | 
			
		||||
neo-async@^2.5.0, neo-async@^2.6.1:
 | 
			
		||||
  version "2.6.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c"
 | 
			
		||||
@@ -6177,35 +6080,11 @@ node-notifier@^5.4.2:
 | 
			
		||||
    shellwords "^0.1.1"
 | 
			
		||||
    which "^1.3.0"
 | 
			
		||||
 | 
			
		||||
node-pre-gyp@*:
 | 
			
		||||
  version "0.14.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83"
 | 
			
		||||
  integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    detect-libc "^1.0.2"
 | 
			
		||||
    mkdirp "^0.5.1"
 | 
			
		||||
    needle "^2.2.1"
 | 
			
		||||
    nopt "^4.0.1"
 | 
			
		||||
    npm-packlist "^1.1.6"
 | 
			
		||||
    npmlog "^4.0.2"
 | 
			
		||||
    rc "^1.2.7"
 | 
			
		||||
    rimraf "^2.6.1"
 | 
			
		||||
    semver "^5.3.0"
 | 
			
		||||
    tar "^4.4.2"
 | 
			
		||||
 | 
			
		||||
node-releases@^1.1.53:
 | 
			
		||||
  version "1.1.53"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.53.tgz#2d821bfa499ed7c5dffc5e2f28c88e78a08ee3f4"
 | 
			
		||||
  integrity sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ==
 | 
			
		||||
 | 
			
		||||
nopt@^4.0.1:
 | 
			
		||||
  version "4.0.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48"
 | 
			
		||||
  integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    abbrev "1"
 | 
			
		||||
    osenv "^0.1.4"
 | 
			
		||||
 | 
			
		||||
normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
 | 
			
		||||
  version "2.5.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
 | 
			
		||||
@@ -6238,27 +6117,6 @@ normalize-selector@^0.2.0:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/normalize-selector/-/normalize-selector-0.2.0.tgz#d0b145eb691189c63a78d201dc4fdb1293ef0c03"
 | 
			
		||||
  integrity sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=
 | 
			
		||||
 | 
			
		||||
npm-bundled@^1.0.1:
 | 
			
		||||
  version "1.1.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b"
 | 
			
		||||
  integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    npm-normalize-package-bin "^1.0.1"
 | 
			
		||||
 | 
			
		||||
npm-normalize-package-bin@^1.0.1:
 | 
			
		||||
  version "1.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2"
 | 
			
		||||
  integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==
 | 
			
		||||
 | 
			
		||||
npm-packlist@^1.1.6:
 | 
			
		||||
  version "1.4.8"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e"
 | 
			
		||||
  integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    ignore-walk "^3.0.1"
 | 
			
		||||
    npm-bundled "^1.0.1"
 | 
			
		||||
    npm-normalize-package-bin "^1.0.1"
 | 
			
		||||
 | 
			
		||||
npm-run-path@^2.0.0:
 | 
			
		||||
  version "2.0.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
 | 
			
		||||
@@ -6266,16 +6124,6 @@ npm-run-path@^2.0.0:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    path-key "^2.0.0"
 | 
			
		||||
 | 
			
		||||
npmlog@^4.0.2:
 | 
			
		||||
  version "4.1.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
 | 
			
		||||
  integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    are-we-there-yet "~1.1.2"
 | 
			
		||||
    console-control-strings "~1.1.0"
 | 
			
		||||
    gauge "~2.7.3"
 | 
			
		||||
    set-blocking "~2.0.0"
 | 
			
		||||
 | 
			
		||||
nth-check@~1.0.1:
 | 
			
		||||
  version "1.0.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c"
 | 
			
		||||
@@ -6425,11 +6273,6 @@ os-browserify@^0.3.0:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
 | 
			
		||||
  integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=
 | 
			
		||||
 | 
			
		||||
os-homedir@^1.0.0:
 | 
			
		||||
  version "1.0.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
 | 
			
		||||
  integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
 | 
			
		||||
 | 
			
		||||
os-locale@^3.0.0, os-locale@^3.1.0:
 | 
			
		||||
  version "3.1.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a"
 | 
			
		||||
@@ -6439,19 +6282,11 @@ os-locale@^3.0.0, os-locale@^3.1.0:
 | 
			
		||||
    lcid "^2.0.0"
 | 
			
		||||
    mem "^4.0.0"
 | 
			
		||||
 | 
			
		||||
os-tmpdir@^1.0.0, os-tmpdir@~1.0.2:
 | 
			
		||||
os-tmpdir@~1.0.2:
 | 
			
		||||
  version "1.0.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
 | 
			
		||||
  integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
 | 
			
		||||
 | 
			
		||||
osenv@^0.1.4:
 | 
			
		||||
  version "0.1.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
 | 
			
		||||
  integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    os-homedir "^1.0.0"
 | 
			
		||||
    os-tmpdir "^1.0.0"
 | 
			
		||||
 | 
			
		||||
p-defer@^1.0.0:
 | 
			
		||||
  version "1.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
 | 
			
		||||
@@ -6923,7 +6758,7 @@ prop-types-exact@^1.2.0:
 | 
			
		||||
    object.assign "^4.1.0"
 | 
			
		||||
    reflect.ownkeys "^0.2.0"
 | 
			
		||||
 | 
			
		||||
prop-types@^15.5.6, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
 | 
			
		||||
prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
 | 
			
		||||
  version "15.7.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
 | 
			
		||||
  integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
 | 
			
		||||
@@ -7096,7 +6931,7 @@ randomfill@^1.0.3:
 | 
			
		||||
    randombytes "^2.0.5"
 | 
			
		||||
    safe-buffer "^5.1.0"
 | 
			
		||||
 | 
			
		||||
rc@1.2.8, rc@^1.2.7, rc@^1.2.8:
 | 
			
		||||
rc@1.2.8, rc@^1.2.8:
 | 
			
		||||
  version "1.2.8"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
 | 
			
		||||
  integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
 | 
			
		||||
@@ -7106,13 +6941,6 @@ rc@1.2.8, rc@^1.2.7, rc@^1.2.8:
 | 
			
		||||
    minimist "^1.2.0"
 | 
			
		||||
    strip-json-comments "~2.0.1"
 | 
			
		||||
 | 
			
		||||
react-addons-css-transition-group@15.6.2:
 | 
			
		||||
  version "15.6.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/react-addons-css-transition-group/-/react-addons-css-transition-group-15.6.2.tgz#9e4376bcf40b5217d14ec68553081cee4b08a6d6"
 | 
			
		||||
  integrity sha1-nkN2vPQLUhfRTsaFUwgc7ksIptY=
 | 
			
		||||
  dependencies:
 | 
			
		||||
    react-transition-group "^1.2.0"
 | 
			
		||||
 | 
			
		||||
react-beautiful-dnd@^4.0.1:
 | 
			
		||||
  version "4.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-4.0.1.tgz#3b0a49bf6be75af351176c904f012611dd292b81"
 | 
			
		||||
@@ -7200,17 +7028,6 @@ react-test-renderer@^16.0.0-0, react-test-renderer@^16.9.0:
 | 
			
		||||
    react-is "^16.8.6"
 | 
			
		||||
    scheduler "^0.19.1"
 | 
			
		||||
 | 
			
		||||
react-transition-group@^1.2.0:
 | 
			
		||||
  version "1.2.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.2.1.tgz#e11f72b257f921b213229a774df46612346c7ca6"
 | 
			
		||||
  integrity sha512-CWaL3laCmgAFdxdKbhhps+c0HRGF4c+hdM4H23+FI1QBNUyx/AMeIJGWorehPNSaKnQNOAxL7PQmqMu78CDj3Q==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    chain-function "^1.0.0"
 | 
			
		||||
    dom-helpers "^3.2.0"
 | 
			
		||||
    loose-envify "^1.3.1"
 | 
			
		||||
    prop-types "^15.5.6"
 | 
			
		||||
    warning "^3.0.0"
 | 
			
		||||
 | 
			
		||||
react@^16.9.0:
 | 
			
		||||
  version "16.13.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e"
 | 
			
		||||
@@ -7254,7 +7071,7 @@ read-pkg@^4.0.1:
 | 
			
		||||
    parse-json "^4.0.0"
 | 
			
		||||
    pify "^3.0.0"
 | 
			
		||||
 | 
			
		||||
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
 | 
			
		||||
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
 | 
			
		||||
  version "2.3.7"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
 | 
			
		||||
  integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
 | 
			
		||||
@@ -7614,7 +7431,7 @@ rimraf@2.6.3:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    glob "^7.1.3"
 | 
			
		||||
 | 
			
		||||
rimraf@^2.4.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3:
 | 
			
		||||
rimraf@^2.4.3, rimraf@^2.5.4, rimraf@^2.6.3:
 | 
			
		||||
  version "2.7.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
 | 
			
		||||
  integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
 | 
			
		||||
@@ -7776,7 +7593,7 @@ serialize-javascript@^2.1.2:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61"
 | 
			
		||||
  integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==
 | 
			
		||||
 | 
			
		||||
set-blocking@^2.0.0, set-blocking@~2.0.0:
 | 
			
		||||
set-blocking@^2.0.0:
 | 
			
		||||
  version "2.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
 | 
			
		||||
  integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
 | 
			
		||||
@@ -8112,7 +7929,7 @@ string-width@^1.0.1:
 | 
			
		||||
    is-fullwidth-code-point "^1.0.0"
 | 
			
		||||
    strip-ansi "^3.0.0"
 | 
			
		||||
 | 
			
		||||
"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
 | 
			
		||||
string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
 | 
			
		||||
  version "2.1.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
 | 
			
		||||
  integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
 | 
			
		||||
@@ -8393,19 +8210,6 @@ tapable@^1.0.0, tapable@^1.1.3:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
 | 
			
		||||
  integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
 | 
			
		||||
 | 
			
		||||
tar@^4.4.2:
 | 
			
		||||
  version "4.4.13"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525"
 | 
			
		||||
  integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    chownr "^1.1.1"
 | 
			
		||||
    fs-minipass "^1.2.5"
 | 
			
		||||
    minipass "^2.8.6"
 | 
			
		||||
    minizlib "^1.2.1"
 | 
			
		||||
    mkdirp "^0.5.0"
 | 
			
		||||
    safe-buffer "^5.1.2"
 | 
			
		||||
    yallist "^3.0.3"
 | 
			
		||||
 | 
			
		||||
terser-webpack-plugin@^1.4.3:
 | 
			
		||||
  version "1.4.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c"
 | 
			
		||||
@@ -8964,13 +8768,6 @@ walker@^1.0.7, walker@~1.0.5:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    makeerror "1.0.x"
 | 
			
		||||
 | 
			
		||||
warning@^3.0.0:
 | 
			
		||||
  version "3.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c"
 | 
			
		||||
  integrity sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=
 | 
			
		||||
  dependencies:
 | 
			
		||||
    loose-envify "^1.0.0"
 | 
			
		||||
 | 
			
		||||
watchpack@^1.6.0:
 | 
			
		||||
  version "1.6.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.1.tgz#280da0a8718592174010c078c7585a74cd8cd0e2"
 | 
			
		||||
@@ -9128,13 +8925,6 @@ which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    isexe "^2.0.0"
 | 
			
		||||
 | 
			
		||||
wide-align@^1.1.0:
 | 
			
		||||
  version "1.1.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
 | 
			
		||||
  integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    string-width "^1.0.2 || 2"
 | 
			
		||||
 | 
			
		||||
word-wrap@~1.2.3:
 | 
			
		||||
  version "1.2.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
 | 
			
		||||
@@ -9219,7 +9009,7 @@ xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
 | 
			
		||||
  integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
 | 
			
		||||
 | 
			
		||||
yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3:
 | 
			
		||||
yallist@^3.0.2:
 | 
			
		||||
  version "3.1.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
 | 
			
		||||
  integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user