Merge branch 'develop' into gsouquet/message-bubbles-4635
commit
ba3e7e24ba
|
@ -0,0 +1,6 @@
|
||||||
|
// Stub out FontManager for tests as it doesn't validate anything we don't already know given
|
||||||
|
// our fixed test environment and it requires the installation of node-canvas.
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
fixupColorFonts: () => Promise.resolve(),
|
||||||
|
};
|
|
@ -54,7 +54,6 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.12.5",
|
"@babel/runtime": "^7.12.5",
|
||||||
"@types/commonmark": "^0.27.4",
|
|
||||||
"await-lock": "^2.1.0",
|
"await-lock": "^2.1.0",
|
||||||
"blurhash": "^1.1.3",
|
"blurhash": "^1.1.3",
|
||||||
"browser-encrypt-attachment": "^0.3.0",
|
"browser-encrypt-attachment": "^0.3.0",
|
||||||
|
@ -92,6 +91,7 @@
|
||||||
"re-resizable": "^6.9.0",
|
"re-resizable": "^6.9.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-beautiful-dnd": "^13.1.0",
|
"react-beautiful-dnd": "^13.1.0",
|
||||||
|
"react-blurhash": "^0.1.3",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-focus-lock": "^2.5.0",
|
"react-focus-lock": "^2.5.0",
|
||||||
"react-transition-group": "^4.4.1",
|
"react-transition-group": "^4.4.1",
|
||||||
|
@ -124,7 +124,9 @@
|
||||||
"@peculiar/webcrypto": "^1.1.4",
|
"@peculiar/webcrypto": "^1.1.4",
|
||||||
"@sinonjs/fake-timers": "^7.0.2",
|
"@sinonjs/fake-timers": "^7.0.2",
|
||||||
"@types/classnames": "^2.2.11",
|
"@types/classnames": "^2.2.11",
|
||||||
|
"@types/commonmark": "^0.27.4",
|
||||||
"@types/counterpart": "^0.18.1",
|
"@types/counterpart": "^0.18.1",
|
||||||
|
"@types/css-font-loading-module": "^0.0.6",
|
||||||
"@types/diff-match-patch": "^1.0.32",
|
"@types/diff-match-patch": "^1.0.32",
|
||||||
"@types/flux": "^3.1.9",
|
"@types/flux": "^3.1.9",
|
||||||
"@types/jest": "^26.0.20",
|
"@types/jest": "^26.0.20",
|
||||||
|
|
|
@ -202,6 +202,7 @@
|
||||||
@import "./views/rooms/_GroupLayout.scss";
|
@import "./views/rooms/_GroupLayout.scss";
|
||||||
@import "./views/rooms/_IRCLayout.scss";
|
@import "./views/rooms/_IRCLayout.scss";
|
||||||
@import "./views/rooms/_JumpToBottomButton.scss";
|
@import "./views/rooms/_JumpToBottomButton.scss";
|
||||||
|
@import "./views/rooms/_LinkPreviewGroup.scss";
|
||||||
@import "./views/rooms/_LinkPreviewWidget.scss";
|
@import "./views/rooms/_LinkPreviewWidget.scss";
|
||||||
@import "./views/rooms/_MemberInfo.scss";
|
@import "./views/rooms/_MemberInfo.scss";
|
||||||
@import "./views/rooms/_MemberList.scss";
|
@import "./views/rooms/_MemberList.scss";
|
||||||
|
@ -262,6 +263,7 @@
|
||||||
@import "./views/voip/_CallContainer.scss";
|
@import "./views/voip/_CallContainer.scss";
|
||||||
@import "./views/voip/_CallView.scss";
|
@import "./views/voip/_CallView.scss";
|
||||||
@import "./views/voip/_CallViewForRoom.scss";
|
@import "./views/voip/_CallViewForRoom.scss";
|
||||||
|
@import "./views/voip/_CallPreview.scss";
|
||||||
@import "./views/voip/_DialPad.scss";
|
@import "./views/voip/_DialPad.scss";
|
||||||
@import "./views/voip/_DialPadContextMenu.scss";
|
@import "./views/voip/_DialPadContextMenu.scss";
|
||||||
@import "./views/voip/_DialPadModal.scss";
|
@import "./views/voip/_DialPadModal.scss";
|
||||||
|
|
|
@ -72,7 +72,7 @@ limitations under the License.
|
||||||
|
|
||||||
.mx_AccessibleButton_kind_danger_outline {
|
.mx_AccessibleButton_kind_danger_outline {
|
||||||
color: $button-danger-bg-color;
|
color: $button-danger-bg-color;
|
||||||
background-color: $button-secondary-bg-color;
|
background-color: transparent;
|
||||||
border: 1px solid $button-danger-bg-color;
|
border: 1px solid $button-danger-bg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -451,8 +451,7 @@ $hover-select-border: 4px;
|
||||||
|
|
||||||
pre, code {
|
pre, code {
|
||||||
font-family: $monospace-font-family !important;
|
font-family: $monospace-font-family !important;
|
||||||
// deliberate constants as we're behind an invert filter
|
background-color: $header-panel-bg-color;
|
||||||
color: #333;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
|
@ -462,11 +461,6 @@ $hover-select-border: 4px;
|
||||||
overflow-x: overlay;
|
overflow-x: overlay;
|
||||||
overflow-y: visible;
|
overflow-y: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
|
||||||
// deliberate constants as we're behind an invert filter
|
|
||||||
background-color: #f8f8f8;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_EventTile_lineNumbers {
|
.mx_EventTile_lineNumbers {
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 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_LinkPreviewGroup {
|
||||||
|
.mx_LinkPreviewGroup_hide {
|
||||||
|
cursor: pointer;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
flex: 0 0 40px;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .mx_LinkPreviewGroup_hide img,
|
||||||
|
.mx_LinkPreviewGroup_hide.focus-visible:focus img {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .mx_AccessibleButton {
|
||||||
|
color: $accent-color;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,38 +33,29 @@ limitations under the License.
|
||||||
.mx_LinkPreviewWidget_caption {
|
.mx_LinkPreviewWidget_caption {
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
overflow-x: hidden; // cause it to wrap rather than clip
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_LinkPreviewWidget_title {
|
.mx_LinkPreviewWidget_title {
|
||||||
display: inline;
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
}
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
.mx_LinkPreviewWidget_siteName {
|
.mx_LinkPreviewWidget_siteName {
|
||||||
display: inline;
|
font-weight: normal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_LinkPreviewWidget_description {
|
.mx_LinkPreviewWidget_description {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
.mx_LinkPreviewWidget_cancel {
|
-webkit-box-orient: vertical;
|
||||||
cursor: pointer;
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
|
|
||||||
img {
|
|
||||||
flex: 0 0 40px;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_LinkPreviewWidget:hover .mx_LinkPreviewWidget_cancel img,
|
|
||||||
.mx_LinkPreviewWidget_cancel.focus-visible:focus img {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MatrixChat_useCompactLayout {
|
.mx_MatrixChat_useCompactLayout {
|
||||||
|
|
|
@ -30,8 +30,8 @@ limitations under the License.
|
||||||
pointer-events: initial; // restore pointer events so the user can leave/interact
|
pointer-events: initial; // restore pointer events so the user can leave/interact
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
.mx_CallView_video {
|
.mx_VideoFeed_remote.mx_VideoFeed_voice {
|
||||||
width: 350px;
|
min-height: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_VideoFeed_local {
|
.mx_VideoFeed_local {
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
|
||||||
|
|
||||||
|
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_CallPreview {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
|
@ -39,7 +39,6 @@ limitations under the License.
|
||||||
.mx_CallView_pip {
|
.mx_CallView_pip {
|
||||||
width: 320px;
|
width: 320px;
|
||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
margin-top: 10px;
|
|
||||||
background-color: $voipcall-plinth-color;
|
background-color: $voipcall-plinth-color;
|
||||||
box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.20);
|
box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.20);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
|
|
@ -15,8 +15,6 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.mx_VideoFeed_voice {
|
.mx_VideoFeed_voice {
|
||||||
// We don't want to collide with the call controls that have 52px of height
|
|
||||||
padding-bottom: 52px;
|
|
||||||
background-color: $inverted-bg-color;
|
background-color: $inverted-bg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,8 +119,6 @@ $voipcall-plinth-color: #394049;
|
||||||
|
|
||||||
$theme-button-bg-color: #e3e8f0;
|
$theme-button-bg-color: #e3e8f0;
|
||||||
$dialpad-button-bg-color: #6F7882;
|
$dialpad-button-bg-color: #6F7882;
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
$roomlist-button-bg-color: rgba(141, 151, 165, 0.2); // Buttons include the filter box, explore button, and sublist buttons
|
$roomlist-button-bg-color: rgba(141, 151, 165, 0.2); // Buttons include the filter box, explore button, and sublist buttons
|
||||||
$roomlist-filter-active-bg-color: $bg-color;
|
$roomlist-filter-active-bg-color: $bg-color;
|
||||||
|
@ -281,24 +279,7 @@ $eventbubble-reply-color: #C1C6CD;
|
||||||
}
|
}
|
||||||
|
|
||||||
// markdown overrides:
|
// markdown overrides:
|
||||||
.mx_EventTile_content .markdown-body pre:hover {
|
|
||||||
border-color: #808080 !important; // inverted due to rules below
|
|
||||||
scrollbar-color: rgba(0, 0, 0, 0.2) transparent; // copied from light theme due to inversion below
|
|
||||||
// the code above works only in Firefox, this is for other browsers
|
|
||||||
// see https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-color
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
background-color: rgba(0, 0, 0, 0.2); // copied from light theme due to inversion below
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.mx_EventTile_content .markdown-body {
|
.mx_EventTile_content .markdown-body {
|
||||||
pre, code {
|
|
||||||
filter: invert(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pre code {
|
|
||||||
filter: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
table {
|
||||||
tr {
|
tr {
|
||||||
background-color: #000000;
|
background-color: #000000;
|
||||||
|
@ -308,18 +289,9 @@ $eventbubble-reply-color: #C1C6CD;
|
||||||
background-color: #080808;
|
background-color: #080808;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
blockquote {
|
|
||||||
color: #919191;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// diff highlight colors
|
// highlight.js overrides
|
||||||
// intentionally swapped to avoid inversion
|
.hljs-tag {
|
||||||
.hljs-addition {
|
color: inherit; // Without this they'd be weirdly blue which doesn't match the theme
|
||||||
background: #fdd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-deletion {
|
|
||||||
background: #dfd;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,3 +9,4 @@
|
||||||
@import "_dark.scss";
|
@import "_dark.scss";
|
||||||
@import "../../light/css/_mods.scss";
|
@import "../../light/css/_mods.scss";
|
||||||
@import "../../../../res/css/_components.scss";
|
@import "../../../../res/css/_components.scss";
|
||||||
|
@import url("highlight.js/styles/atom-one-dark.css");
|
||||||
|
|
|
@ -118,7 +118,7 @@ $voipcall-plinth-color: #394049;
|
||||||
|
|
||||||
$theme-button-bg-color: #e3e8f0;
|
$theme-button-bg-color: #e3e8f0;
|
||||||
$dialpad-button-bg-color: #6F7882;
|
$dialpad-button-bg-color: #6F7882;
|
||||||
;
|
|
||||||
|
|
||||||
$roomlist-button-bg-color: #1A1D23; // Buttons include the filter box, explore button, and sublist buttons
|
$roomlist-button-bg-color: #1A1D23; // Buttons include the filter box, explore button, and sublist buttons
|
||||||
$roomlist-filter-active-bg-color: $roomlist-button-bg-color;
|
$roomlist-filter-active-bg-color: $roomlist-button-bg-color;
|
||||||
|
@ -249,7 +249,7 @@ $composer-shadow-color: tranparent;
|
||||||
@define-mixin mx_DialogButton_secondary {
|
@define-mixin mx_DialogButton_secondary {
|
||||||
// flip colours for the secondary ones
|
// flip colours for the secondary ones
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
border: 1px solid $accent-color ! important;
|
border: 1px solid $accent-color !important;
|
||||||
color: $accent-color;
|
color: $accent-color;
|
||||||
background-color: $button-secondary-bg-color;
|
background-color: $button-secondary-bg-color;
|
||||||
}
|
}
|
||||||
|
@ -267,18 +267,7 @@ $composer-shadow-color: tranparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// markdown overrides:
|
// markdown overrides:
|
||||||
.mx_EventTile_content .markdown-body pre:hover {
|
|
||||||
border-color: #808080 !important; // inverted due to rules below
|
|
||||||
}
|
|
||||||
.mx_EventTile_content .markdown-body {
|
.mx_EventTile_content .markdown-body {
|
||||||
pre, code {
|
|
||||||
filter: invert(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pre code {
|
|
||||||
filter: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
table {
|
||||||
tr {
|
tr {
|
||||||
background-color: #000000;
|
background-color: #000000;
|
||||||
|
@ -290,12 +279,7 @@ $composer-shadow-color: tranparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// diff highlight colors
|
// highlight.js overrides:
|
||||||
// intentionally swapped to avoid inversion
|
.hljs-tag {
|
||||||
.hljs-addition {
|
color: inherit; // Without this they'd be weirdly blue which doesn't match the theme
|
||||||
background: #fdd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-deletion {
|
|
||||||
background: #dfd;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,3 +4,4 @@
|
||||||
@import "../../legacy-light/css/_legacy-light.scss";
|
@import "../../legacy-light/css/_legacy-light.scss";
|
||||||
@import "_legacy-dark.scss";
|
@import "_legacy-dark.scss";
|
||||||
@import "../../../../res/css/_components.scss";
|
@import "../../../../res/css/_components.scss";
|
||||||
|
@import url("highlight.js/styles/atom-one-dark.css");
|
||||||
|
|
|
@ -3,3 +3,4 @@
|
||||||
@import "_fonts.scss";
|
@import "_fonts.scss";
|
||||||
@import "_legacy-light.scss";
|
@import "_legacy-light.scss";
|
||||||
@import "../../../../res/css/_components.scss";
|
@import "../../../../res/css/_components.scss";
|
||||||
|
@import url("highlight.js/styles/atom-one-light.css");
|
||||||
|
|
|
@ -4,3 +4,4 @@
|
||||||
@import "_light.scss";
|
@import "_light.scss";
|
||||||
@import "_mods.scss";
|
@import "_mods.scss";
|
||||||
@import "../../../../res/css/_components.scss";
|
@import "../../../../res/css/_components.scss";
|
||||||
|
@import url("highlight.js/styles/atom-one-light.css");
|
||||||
|
|
|
@ -6,8 +6,8 @@ scripts/fetchdep.sh matrix-org matrix-js-sdk
|
||||||
|
|
||||||
pushd matrix-js-sdk
|
pushd matrix-js-sdk
|
||||||
yarn link
|
yarn link
|
||||||
yarn install $@
|
yarn install --pure-lockfile $@
|
||||||
popd
|
popd
|
||||||
|
|
||||||
yarn link matrix-js-sdk
|
yarn link matrix-js-sdk
|
||||||
yarn install $@
|
yarn install --pure-lockfile $@
|
||||||
|
|
|
@ -13,13 +13,13 @@
|
||||||
scripts/fetchdep.sh matrix-org matrix-js-sdk
|
scripts/fetchdep.sh matrix-org matrix-js-sdk
|
||||||
pushd matrix-js-sdk
|
pushd matrix-js-sdk
|
||||||
yarn link
|
yarn link
|
||||||
yarn install
|
yarn install --pure-lockfile
|
||||||
popd
|
popd
|
||||||
|
|
||||||
# Now set up the react-sdk
|
# Now set up the react-sdk
|
||||||
yarn link matrix-js-sdk
|
yarn link matrix-js-sdk
|
||||||
yarn link
|
yarn link
|
||||||
yarn install
|
yarn install --pure-lockfile
|
||||||
yarn reskindex
|
yarn reskindex
|
||||||
|
|
||||||
# Finally, set up element-web
|
# Finally, set up element-web
|
||||||
|
@ -27,6 +27,6 @@ scripts/fetchdep.sh vector-im element-web
|
||||||
pushd element-web
|
pushd element-web
|
||||||
yarn link matrix-js-sdk
|
yarn link matrix-js-sdk
|
||||||
yarn link matrix-react-sdk
|
yarn link matrix-react-sdk
|
||||||
yarn install
|
yarn install --pure-lockfile
|
||||||
yarn build:res
|
yarn build:res
|
||||||
popd
|
popd
|
||||||
|
|
|
@ -15,7 +15,9 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "matrix-js-sdk/src/@types/global"; // load matrix-js-sdk's type extensions first
|
import "matrix-js-sdk/src/@types/global"; // load matrix-js-sdk's type extensions first
|
||||||
import * as ModernizrStatic from "modernizr";
|
// Load types for the WG CSS Font Loading APIs https://github.com/Microsoft/TypeScript/issues/13569
|
||||||
|
import "@types/css-font-loading-module";
|
||||||
|
import "@types/modernizr";
|
||||||
|
|
||||||
import ContentMessages from "../ContentMessages";
|
import ContentMessages from "../ContentMessages";
|
||||||
import { IMatrixClientPeg } from "../MatrixClientPeg";
|
import { IMatrixClientPeg } from "../MatrixClientPeg";
|
||||||
|
@ -50,7 +52,6 @@ import { RoomScrollStateStore } from "../stores/RoomScrollStateStore";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
Modernizr: ModernizrStatic;
|
|
||||||
matrixChat: ReturnType<Renderer>;
|
matrixChat: ReturnType<Renderer>;
|
||||||
mxMatrixClientPeg: IMatrixClientPeg;
|
mxMatrixClientPeg: IMatrixClientPeg;
|
||||||
Olm: {
|
Olm: {
|
||||||
|
|
|
@ -390,6 +390,7 @@ export class Analytics {
|
||||||
{ expl: _td('Your device resolution'), value: resolution },
|
{ expl: _td('Your device resolution'), value: resolution },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// FIXME: Using an import will result in test failures
|
||||||
const ErrorDialog = sdk.getComponent('dialogs.ErrorDialog');
|
const ErrorDialog = sdk.getComponent('dialogs.ErrorDialog');
|
||||||
Modal.createTrackedDialog('Analytics Details', '', ErrorDialog, {
|
Modal.createTrackedDialog('Analytics Details', '', ErrorDialog, {
|
||||||
title: _t('Analytics'),
|
title: _t('Analytics'),
|
||||||
|
|
|
@ -77,6 +77,7 @@ export default class AsyncWrapper extends React.Component<IProps, IState> {
|
||||||
const Component = this.state.component;
|
const Component = this.state.component;
|
||||||
return <Component {...this.props} />;
|
return <Component {...this.props} />;
|
||||||
} else if (this.state.error) {
|
} else if (this.state.error) {
|
||||||
|
// FIXME: Using an import will result in test failures
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||||
return <BaseDialog onFinished={this.props.onFinished} title={_t("Error")}>
|
return <BaseDialog onFinished={this.props.onFinished} title={_t("Error")}>
|
||||||
|
|
|
@ -49,8 +49,6 @@ const MAX_HEIGHT = 600;
|
||||||
const PHYS_HIDPI = [0x00, 0x00, 0x16, 0x25, 0x00, 0x00, 0x16, 0x25, 0x01];
|
const PHYS_HIDPI = [0x00, 0x00, 0x16, 0x25, 0x00, 0x00, 0x16, 0x25, 0x01];
|
||||||
|
|
||||||
export const BLURHASH_FIELD = "xyz.amorgan.blurhash"; // MSC2448
|
export const BLURHASH_FIELD = "xyz.amorgan.blurhash"; // MSC2448
|
||||||
const BLURHASH_X_COMPONENTS = 6;
|
|
||||||
const BLURHASH_Y_COMPONENTS = 6;
|
|
||||||
|
|
||||||
export class UploadCanceledError extends Error {}
|
export class UploadCanceledError extends Error {}
|
||||||
|
|
||||||
|
@ -137,8 +135,9 @@ function createThumbnail(
|
||||||
imageData.data,
|
imageData.data,
|
||||||
imageData.width,
|
imageData.width,
|
||||||
imageData.height,
|
imageData.height,
|
||||||
BLURHASH_X_COMPONENTS,
|
// use 4 components on the longer dimension, if square then both
|
||||||
BLURHASH_Y_COMPONENTS,
|
imageData.width >= imageData.height ? 4 : 3,
|
||||||
|
imageData.height >= imageData.width ? 4 : 3,
|
||||||
);
|
);
|
||||||
canvas.toBlob(function(thumbnail) {
|
canvas.toBlob(function(thumbnail) {
|
||||||
resolve({
|
resolve({
|
||||||
|
@ -419,6 +418,7 @@ export default class ContentMessages {
|
||||||
|
|
||||||
const isQuoting = Boolean(RoomViewStore.getQuotingEvent());
|
const isQuoting = Boolean(RoomViewStore.getQuotingEvent());
|
||||||
if (isQuoting) {
|
if (isQuoting) {
|
||||||
|
// FIXME: Using an import will result in Element crashing
|
||||||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
||||||
const { finished } = Modal.createTrackedDialog<[boolean]>('Upload Reply Warning', '', QuestionDialog, {
|
const { finished } = Modal.createTrackedDialog<[boolean]>('Upload Reply Warning', '', QuestionDialog, {
|
||||||
title: _t('Replying With Files'),
|
title: _t('Replying With Files'),
|
||||||
|
@ -453,6 +453,7 @@ export default class ContentMessages {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tooBigFiles.length > 0) {
|
if (tooBigFiles.length > 0) {
|
||||||
|
// FIXME: Using an import will result in Element crashing
|
||||||
const UploadFailureDialog = sdk.getComponent("dialogs.UploadFailureDialog");
|
const UploadFailureDialog = sdk.getComponent("dialogs.UploadFailureDialog");
|
||||||
const { finished } = Modal.createTrackedDialog<[boolean]>('Upload Failure', '', UploadFailureDialog, {
|
const { finished } = Modal.createTrackedDialog<[boolean]>('Upload Failure', '', UploadFailureDialog, {
|
||||||
badFiles: tooBigFiles,
|
badFiles: tooBigFiles,
|
||||||
|
@ -463,7 +464,6 @@ export default class ContentMessages {
|
||||||
if (!shouldContinue) return;
|
if (!shouldContinue) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UploadConfirmDialog = sdk.getComponent("dialogs.UploadConfirmDialog");
|
|
||||||
let uploadAll = false;
|
let uploadAll = false;
|
||||||
// Promise to complete before sending next file into room, used for synchronisation of file-sending
|
// Promise to complete before sending next file into room, used for synchronisation of file-sending
|
||||||
// to match the order the files were specified in
|
// to match the order the files were specified in
|
||||||
|
@ -471,6 +471,8 @@ export default class ContentMessages {
|
||||||
for (let i = 0; i < okFiles.length; ++i) {
|
for (let i = 0; i < okFiles.length; ++i) {
|
||||||
const file = okFiles[i];
|
const file = okFiles[i];
|
||||||
if (!uploadAll) {
|
if (!uploadAll) {
|
||||||
|
// FIXME: Using an import will result in Element crashing
|
||||||
|
const UploadConfirmDialog = sdk.getComponent("dialogs.UploadConfirmDialog");
|
||||||
const { finished } = Modal.createTrackedDialog<[boolean, boolean]>('Upload Files confirmation',
|
const { finished } = Modal.createTrackedDialog<[boolean, boolean]>('Upload Files confirmation',
|
||||||
'', UploadConfirmDialog, {
|
'', UploadConfirmDialog, {
|
||||||
file,
|
file,
|
||||||
|
@ -567,7 +569,7 @@ export default class ContentMessages {
|
||||||
dis.dispatch<UploadStartedPayload>({ action: Action.UploadStarted, upload });
|
dis.dispatch<UploadStartedPayload>({ action: Action.UploadStarted, upload });
|
||||||
|
|
||||||
// Focus the composer view
|
// Focus the composer view
|
||||||
dis.fire(Action.FocusComposer);
|
dis.fire(Action.FocusSendMessageComposer);
|
||||||
|
|
||||||
function onProgress(ev) {
|
function onProgress(ev) {
|
||||||
upload.total = ev.total;
|
upload.total = ev.total;
|
||||||
|
@ -606,6 +608,7 @@ export default class ContentMessages {
|
||||||
{ fileName: upload.fileName },
|
{ fileName: upload.fileName },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// FIXME: Using an import will result in Element crashing
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createTrackedDialog('Upload failed', '', ErrorDialog, {
|
Modal.createTrackedDialog('Upload failed', '', ErrorDialog, {
|
||||||
title: _t('Upload Failed'),
|
title: _t('Upload Failed'),
|
||||||
|
|
|
@ -160,7 +160,8 @@ export default class DeviceListener {
|
||||||
// which result in account data changes affecting checks below.
|
// which result in account data changes affecting checks below.
|
||||||
if (
|
if (
|
||||||
ev.getType().startsWith('m.secret_storage.') ||
|
ev.getType().startsWith('m.secret_storage.') ||
|
||||||
ev.getType().startsWith('m.cross_signing.')
|
ev.getType().startsWith('m.cross_signing.') ||
|
||||||
|
ev.getType() === 'm.megolm_backup.v1'
|
||||||
) {
|
) {
|
||||||
this._recheck();
|
this._recheck();
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,8 @@ const COLOR_REGEX = /^#[0-9a-fA-F]{6}$/;
|
||||||
|
|
||||||
export const PERMITTED_URL_SCHEMES = ['http', 'https', 'ftp', 'mailto', 'magnet'];
|
export const PERMITTED_URL_SCHEMES = ['http', 'https', 'ftp', 'mailto', 'magnet'];
|
||||||
|
|
||||||
|
const MEDIA_API_MXC_REGEX = /\/_matrix\/media\/r0\/(?:download|thumbnail)\/(.+?)\/(.+?)(?:[?/]|$)/;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return true if the given string contains emoji
|
* Return true if the given string contains emoji
|
||||||
* Uses a much, much simpler regex than emojibase's so will give false
|
* Uses a much, much simpler regex than emojibase's so will give false
|
||||||
|
@ -176,18 +178,31 @@ const transformTags: IExtendedSanitizeOptions["transformTags"] = { // custom to
|
||||||
return { tagName, attribs };
|
return { tagName, attribs };
|
||||||
},
|
},
|
||||||
'img': function(tagName: string, attribs: sanitizeHtml.Attributes) {
|
'img': function(tagName: string, attribs: sanitizeHtml.Attributes) {
|
||||||
|
let src = attribs.src;
|
||||||
// Strip out imgs that aren't `mxc` here instead of using allowedSchemesByTag
|
// Strip out imgs that aren't `mxc` here instead of using allowedSchemesByTag
|
||||||
// because transformTags is used _before_ we filter by allowedSchemesByTag and
|
// because transformTags is used _before_ we filter by allowedSchemesByTag and
|
||||||
// we don't want to allow images with `https?` `src`s.
|
// we don't want to allow images with `https?` `src`s.
|
||||||
// We also drop inline images (as if they were not present at all) when the "show
|
// We also drop inline images (as if they were not present at all) when the "show
|
||||||
// images" preference is disabled. Future work might expose some UI to reveal them
|
// images" preference is disabled. Future work might expose some UI to reveal them
|
||||||
// like standalone image events have.
|
// like standalone image events have.
|
||||||
if (!attribs.src || !attribs.src.startsWith('mxc://') || !SettingsStore.getValue("showImages")) {
|
if (!src || !SettingsStore.getValue("showImages")) {
|
||||||
return { tagName, attribs: {} };
|
return { tagName, attribs: {} };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!src.startsWith("mxc://")) {
|
||||||
|
const match = MEDIA_API_MXC_REGEX.exec(src);
|
||||||
|
if (match) {
|
||||||
|
src = `mxc://${match[1]}/${match[2]}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!src.startsWith("mxc://")) {
|
||||||
|
return { tagName, attribs: {} };
|
||||||
|
}
|
||||||
|
|
||||||
const width = Number(attribs.width) || 800;
|
const width = Number(attribs.width) || 800;
|
||||||
const height = Number(attribs.height) || 600;
|
const height = Number(attribs.height) || 600;
|
||||||
attribs.src = mediaFromMxc(attribs.src).getThumbnailOfSourceHttp(width, height);
|
attribs.src = mediaFromMxc(src).getThumbnailOfSourceHttp(width, height);
|
||||||
return { tagName, attribs };
|
return { tagName, attribs };
|
||||||
},
|
},
|
||||||
'code': function(tagName: string, attribs: sanitizeHtml.Attributes) {
|
'code': function(tagName: string, attribs: sanitizeHtml.Attributes) {
|
||||||
|
|
|
@ -33,7 +33,6 @@ import Presence from './Presence';
|
||||||
import dis from './dispatcher/dispatcher';
|
import dis from './dispatcher/dispatcher';
|
||||||
import DMRoomMap from './utils/DMRoomMap';
|
import DMRoomMap from './utils/DMRoomMap';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
import * as sdk from './index';
|
|
||||||
import ActiveWidgetStore from './stores/ActiveWidgetStore';
|
import ActiveWidgetStore from './stores/ActiveWidgetStore';
|
||||||
import PlatformPeg from "./PlatformPeg";
|
import PlatformPeg from "./PlatformPeg";
|
||||||
import { sendLoginRequest } from "./Login";
|
import { sendLoginRequest } from "./Login";
|
||||||
|
@ -52,6 +51,10 @@ import CallHandler from './CallHandler';
|
||||||
import LifecycleCustomisations from "./customisations/Lifecycle";
|
import LifecycleCustomisations from "./customisations/Lifecycle";
|
||||||
import ErrorDialog from "./components/views/dialogs/ErrorDialog";
|
import ErrorDialog from "./components/views/dialogs/ErrorDialog";
|
||||||
import { _t } from "./languageHandler";
|
import { _t } from "./languageHandler";
|
||||||
|
import LazyLoadingResyncDialog from "./components/views/dialogs/LazyLoadingResyncDialog";
|
||||||
|
import LazyLoadingDisabledDialog from "./components/views/dialogs/LazyLoadingDisabledDialog";
|
||||||
|
import SessionRestoreErrorDialog from "./components/views/dialogs/SessionRestoreErrorDialog";
|
||||||
|
import StorageEvictedDialog from "./components/views/dialogs/StorageEvictedDialog";
|
||||||
|
|
||||||
const HOMESERVER_URL_KEY = "mx_hs_url";
|
const HOMESERVER_URL_KEY = "mx_hs_url";
|
||||||
const ID_SERVER_URL_KEY = "mx_is_url";
|
const ID_SERVER_URL_KEY = "mx_is_url";
|
||||||
|
@ -238,8 +241,6 @@ export function handleInvalidStoreError(e: InvalidStoreError): Promise<void> {
|
||||||
return Promise.resolve().then(() => {
|
return Promise.resolve().then(() => {
|
||||||
const lazyLoadEnabled = e.value;
|
const lazyLoadEnabled = e.value;
|
||||||
if (lazyLoadEnabled) {
|
if (lazyLoadEnabled) {
|
||||||
const LazyLoadingResyncDialog =
|
|
||||||
sdk.getComponent("views.dialogs.LazyLoadingResyncDialog");
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
Modal.createDialog(LazyLoadingResyncDialog, {
|
Modal.createDialog(LazyLoadingResyncDialog, {
|
||||||
onFinished: resolve,
|
onFinished: resolve,
|
||||||
|
@ -250,8 +251,6 @@ export function handleInvalidStoreError(e: InvalidStoreError): Promise<void> {
|
||||||
// between LL/non-LL version on same host.
|
// between LL/non-LL version on same host.
|
||||||
// as disabling LL when previously enabled
|
// as disabling LL when previously enabled
|
||||||
// is a strong indicator of this (/develop & /app)
|
// is a strong indicator of this (/develop & /app)
|
||||||
const LazyLoadingDisabledDialog =
|
|
||||||
sdk.getComponent("views.dialogs.LazyLoadingDisabledDialog");
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
Modal.createDialog(LazyLoadingDisabledDialog, {
|
Modal.createDialog(LazyLoadingDisabledDialog, {
|
||||||
onFinished: resolve,
|
onFinished: resolve,
|
||||||
|
@ -451,9 +450,6 @@ export async function restoreFromLocalStorage(opts?: { ignoreGuest?: boolean }):
|
||||||
async function handleLoadSessionFailure(e: Error): Promise<boolean> {
|
async function handleLoadSessionFailure(e: Error): Promise<boolean> {
|
||||||
console.error("Unable to load session", e);
|
console.error("Unable to load session", e);
|
||||||
|
|
||||||
const SessionRestoreErrorDialog =
|
|
||||||
sdk.getComponent('views.dialogs.SessionRestoreErrorDialog');
|
|
||||||
|
|
||||||
const modal = Modal.createTrackedDialog('Session Restore Error', '', SessionRestoreErrorDialog, {
|
const modal = Modal.createTrackedDialog('Session Restore Error', '', SessionRestoreErrorDialog, {
|
||||||
error: e.message,
|
error: e.message,
|
||||||
});
|
});
|
||||||
|
@ -612,7 +608,6 @@ async function doSetLoggedIn(
|
||||||
}
|
}
|
||||||
|
|
||||||
function showStorageEvictedDialog(): Promise<boolean> {
|
function showStorageEvictedDialog(): Promise<boolean> {
|
||||||
const StorageEvictedDialog = sdk.getComponent('views.dialogs.StorageEvictedDialog');
|
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
Modal.createTrackedDialog('Storage evicted', '', StorageEvictedDialog, {
|
Modal.createTrackedDialog('Storage evicted', '', StorageEvictedDialog, {
|
||||||
onFinished: resolve,
|
onFinished: resolve,
|
||||||
|
|
|
@ -219,6 +219,7 @@ class _MatrixClientPeg implements IMatrixClientPeg {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e && e.name === 'InvalidCryptoStoreError') {
|
if (e && e.name === 'InvalidCryptoStoreError') {
|
||||||
// The js-sdk found a crypto DB too new for it to use
|
// The js-sdk found a crypto DB too new for it to use
|
||||||
|
// FIXME: Using an import will result in test failures
|
||||||
const CryptoStoreTooNewDialog =
|
const CryptoStoreTooNewDialog =
|
||||||
sdk.getComponent("views.dialogs.CryptoStoreTooNewDialog");
|
sdk.getComponent("views.dialogs.CryptoStoreTooNewDialog");
|
||||||
Modal.createDialog(CryptoStoreTooNewDialog);
|
Modal.createDialog(CryptoStoreTooNewDialog);
|
||||||
|
|
|
@ -20,12 +20,15 @@ import { SettingLevel } from "./settings/SettingLevel";
|
||||||
import { setMatrixCallAudioInput, setMatrixCallVideoInput } from "matrix-js-sdk/src/matrix";
|
import { setMatrixCallAudioInput, setMatrixCallVideoInput } from "matrix-js-sdk/src/matrix";
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
|
|
||||||
interface IMediaDevices {
|
// XXX: MediaDeviceKind is a union type, so we make our own enum
|
||||||
audioOutput: Array<MediaDeviceInfo>;
|
export enum MediaDeviceKindEnum {
|
||||||
audioInput: Array<MediaDeviceInfo>;
|
AudioOutput = "audiooutput",
|
||||||
videoInput: Array<MediaDeviceInfo>;
|
AudioInput = "audioinput",
|
||||||
|
VideoInput = "videoinput",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type IMediaDevices = Record<MediaDeviceKindEnum, Array<MediaDeviceInfo>>;
|
||||||
|
|
||||||
export enum MediaDeviceHandlerEvent {
|
export enum MediaDeviceHandlerEvent {
|
||||||
AudioOutputChanged = "audio_output_changed",
|
AudioOutputChanged = "audio_output_changed",
|
||||||
}
|
}
|
||||||
|
@ -51,20 +54,14 @@ export default class MediaDeviceHandler extends EventEmitter {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const devices = await navigator.mediaDevices.enumerateDevices();
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
||||||
|
const output = {
|
||||||
|
[MediaDeviceKindEnum.AudioOutput]: [],
|
||||||
|
[MediaDeviceKindEnum.AudioInput]: [],
|
||||||
|
[MediaDeviceKindEnum.VideoInput]: [],
|
||||||
|
};
|
||||||
|
|
||||||
const audioOutput = [];
|
devices.forEach((device) => output[device.kind].push(device));
|
||||||
const audioInput = [];
|
return output;
|
||||||
const videoInput = [];
|
|
||||||
|
|
||||||
devices.forEach((device) => {
|
|
||||||
switch (device.kind) {
|
|
||||||
case 'audiooutput': audioOutput.push(device); break;
|
|
||||||
case 'audioinput': audioInput.push(device); break;
|
|
||||||
case 'videoinput': videoInput.push(device); break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return { audioOutput, audioInput, videoInput };
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('Unable to refresh WebRTC Devices: ', error);
|
console.warn('Unable to refresh WebRTC Devices: ', error);
|
||||||
}
|
}
|
||||||
|
@ -106,6 +103,14 @@ export default class MediaDeviceHandler extends EventEmitter {
|
||||||
setMatrixCallVideoInput(deviceId);
|
setMatrixCallVideoInput(deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setDevice(deviceId: string, kind: MediaDeviceKindEnum): void {
|
||||||
|
switch (kind) {
|
||||||
|
case MediaDeviceKindEnum.AudioOutput: this.setAudioOutput(deviceId); break;
|
||||||
|
case MediaDeviceKindEnum.AudioInput: this.setAudioInput(deviceId); break;
|
||||||
|
case MediaDeviceKindEnum.VideoInput: this.setVideoInput(deviceId); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static getAudioOutput(): string {
|
public static getAudioOutput(): string {
|
||||||
return SettingsStore.getValueAt(SettingLevel.DEVICE, "webrtc_audiooutput");
|
return SettingsStore.getValueAt(SettingLevel.DEVICE, "webrtc_audiooutput");
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ import * as TextForEvent from './TextForEvent';
|
||||||
import Analytics from './Analytics';
|
import Analytics from './Analytics';
|
||||||
import * as Avatar from './Avatar';
|
import * as Avatar from './Avatar';
|
||||||
import dis from './dispatcher/dispatcher';
|
import dis from './dispatcher/dispatcher';
|
||||||
import * as sdk from './index';
|
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
import SettingsStore from "./settings/SettingsStore";
|
import SettingsStore from "./settings/SettingsStore";
|
||||||
|
@ -37,6 +36,7 @@ import { isPushNotifyDisabled } from "./settings/controllers/NotificationControl
|
||||||
import RoomViewStore from "./stores/RoomViewStore";
|
import RoomViewStore from "./stores/RoomViewStore";
|
||||||
import UserActivity from "./UserActivity";
|
import UserActivity from "./UserActivity";
|
||||||
import { mediaFromMxc } from "./customisations/Media";
|
import { mediaFromMxc } from "./customisations/Media";
|
||||||
|
import ErrorDialog from "./components/views/dialogs/ErrorDialog";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dispatches:
|
* Dispatches:
|
||||||
|
@ -240,7 +240,6 @@ export const Notifier = {
|
||||||
? _t('%(brand)s does not have permission to send you notifications - ' +
|
? _t('%(brand)s does not have permission to send you notifications - ' +
|
||||||
'please check your browser settings', { brand })
|
'please check your browser settings', { brand })
|
||||||
: _t('%(brand)s was not given permission to send notifications - please try again', { brand });
|
: _t('%(brand)s was not given permission to send notifications - please try again', { brand });
|
||||||
const ErrorDialog = sdk.getComponent('dialogs.ErrorDialog');
|
|
||||||
Modal.createTrackedDialog('Unable to enable Notifications', result, ErrorDialog, {
|
Modal.createTrackedDialog('Unable to enable Notifications', result, ErrorDialog, {
|
||||||
title: _t('Unable to enable Notifications'),
|
title: _t('Unable to enable Notifications'),
|
||||||
description,
|
description,
|
||||||
|
|
|
@ -22,13 +22,13 @@ import { User } from "matrix-js-sdk/src/models/user";
|
||||||
import { MatrixClientPeg } from './MatrixClientPeg';
|
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import MultiInviter, { CompletionStates } from './utils/MultiInviter';
|
import MultiInviter, { CompletionStates } from './utils/MultiInviter';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
import * as sdk from './';
|
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
import InviteDialog, { KIND_DM, KIND_INVITE, Member } from "./components/views/dialogs/InviteDialog";
|
import InviteDialog, { KIND_DM, KIND_INVITE, Member } from "./components/views/dialogs/InviteDialog";
|
||||||
import CommunityPrototypeInviteDialog from "./components/views/dialogs/CommunityPrototypeInviteDialog";
|
import CommunityPrototypeInviteDialog from "./components/views/dialogs/CommunityPrototypeInviteDialog";
|
||||||
import { CommunityPrototypeStore } from "./stores/CommunityPrototypeStore";
|
import { CommunityPrototypeStore } from "./stores/CommunityPrototypeStore";
|
||||||
import BaseAvatar from "./components/views/avatars/BaseAvatar";
|
import BaseAvatar from "./components/views/avatars/BaseAvatar";
|
||||||
import { mediaFromMxc } from "./customisations/Media";
|
import { mediaFromMxc } from "./customisations/Media";
|
||||||
|
import ErrorDialog from "./components/views/dialogs/ErrorDialog";
|
||||||
|
|
||||||
export interface IInviteResult {
|
export interface IInviteResult {
|
||||||
states: CompletionStates;
|
states: CompletionStates;
|
||||||
|
@ -51,7 +51,6 @@ export function inviteMultipleToRoom(roomId: string, addresses: string[]): Promi
|
||||||
|
|
||||||
export function showStartChatInviteDialog(initialText = ""): void {
|
export function showStartChatInviteDialog(initialText = ""): void {
|
||||||
// This dialog handles the room creation internally - we don't need to worry about it.
|
// This dialog handles the room creation internally - we don't need to worry about it.
|
||||||
const InviteDialog = sdk.getComponent("dialogs.InviteDialog");
|
|
||||||
Modal.createTrackedDialog(
|
Modal.createTrackedDialog(
|
||||||
'Start DM', '', InviteDialog, { kind: KIND_DM, initialText },
|
'Start DM', '', InviteDialog, { kind: KIND_DM, initialText },
|
||||||
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true,
|
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true,
|
||||||
|
@ -111,7 +110,6 @@ export function inviteUsersToRoom(roomId: string, userIds: string[]): Promise<vo
|
||||||
showAnyInviteErrors(result.states, room, result.inviter);
|
showAnyInviteErrors(result.states, room, result.inviter);
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.error(err.stack);
|
console.error(err.stack);
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
||||||
Modal.createTrackedDialog('Failed to invite', '', ErrorDialog, {
|
Modal.createTrackedDialog('Failed to invite', '', ErrorDialog, {
|
||||||
title: _t("Failed to invite"),
|
title: _t("Failed to invite"),
|
||||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||||
|
@ -131,7 +129,6 @@ export function showAnyInviteErrors(
|
||||||
// Just get the first message because there was a fatal problem on the first
|
// Just get the first message because there was a fatal problem on the first
|
||||||
// user. This usually means that no other users were attempted, making it
|
// user. This usually means that no other users were attempted, making it
|
||||||
// pointless for us to list who failed exactly.
|
// pointless for us to list who failed exactly.
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
||||||
Modal.createTrackedDialog('Failed to invite users to the room', '', ErrorDialog, {
|
Modal.createTrackedDialog('Failed to invite users to the room', '', ErrorDialog, {
|
||||||
title: _t("Failed to invite users to the room:", { roomName: room.name }),
|
title: _t("Failed to invite users to the room:", { roomName: room.name }),
|
||||||
description: inviter.getErrorText(failedUsers[0]),
|
description: inviter.getErrorText(failedUsers[0]),
|
||||||
|
@ -178,7 +175,6 @@ export function showAnyInviteErrors(
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
|
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
||||||
Modal.createTrackedDialog("Some invites could not be sent", "", ErrorDialog, {
|
Modal.createTrackedDialog("Some invites could not be sent", "", ErrorDialog, {
|
||||||
title: _t("Some invites couldn't be sent"),
|
title: _t("Some invites couldn't be sent"),
|
||||||
description,
|
description,
|
||||||
|
|
14
src/Rooms.ts
14
src/Rooms.ts
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
|
||||||
import { MatrixClientPeg } from './MatrixClientPeg';
|
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
|
import AliasCustomisations from './customisations/Alias';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a room object, return the alias we should use for it,
|
* Given a room object, return the alias we should use for it,
|
||||||
|
@ -28,7 +29,18 @@ import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
* @returns {string} A display alias for the given room
|
* @returns {string} A display alias for the given room
|
||||||
*/
|
*/
|
||||||
export function getDisplayAliasForRoom(room: Room): string {
|
export function getDisplayAliasForRoom(room: Room): string {
|
||||||
return room.getCanonicalAlias() || room.getAltAliases()[0];
|
return getDisplayAliasForAliasSet(
|
||||||
|
room.getCanonicalAlias(), room.getAltAliases(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The various display alias getters should all feed through this one path so
|
||||||
|
// there's a single place to change the logic.
|
||||||
|
export function getDisplayAliasForAliasSet(canonicalAlias: string, altAliases: string[]): string {
|
||||||
|
if (AliasCustomisations.getDisplayAliasForAliasSet) {
|
||||||
|
return AliasCustomisations.getDisplayAliasForAliasSet(canonicalAlias, altAliases);
|
||||||
|
}
|
||||||
|
return canonicalAlias || altAliases?.[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function looksLikeDirectMessageRoom(room: Room, myUserId: string): boolean {
|
export function looksLikeDirectMessageRoom(room: Room, myUserId: string): boolean {
|
||||||
|
|
|
@ -14,7 +14,8 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ICryptoCallbacks, ISecretStorageKeyInfo } from 'matrix-js-sdk/src/matrix';
|
import { ICryptoCallbacks } from 'matrix-js-sdk/src/matrix';
|
||||||
|
import { ISecretStorageKeyInfo } from 'matrix-js-sdk/src/crypto/api';
|
||||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
import * as sdk from './index';
|
import * as sdk from './index';
|
||||||
|
@ -354,6 +355,7 @@ export async function accessSecretStorage(func = async () => { }, forceReset = f
|
||||||
throw new Error("Secret storage creation canceled");
|
throw new Error("Secret storage creation canceled");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// FIXME: Using an import will result in test failures
|
||||||
const InteractiveAuthDialog = sdk.getComponent("dialogs.InteractiveAuthDialog");
|
const InteractiveAuthDialog = sdk.getComponent("dialogs.InteractiveAuthDialog");
|
||||||
await cli.bootstrapCrossSigning({
|
await cli.bootstrapCrossSigning({
|
||||||
authUploadDeviceSigningKeys: async (makeRequest) => {
|
authUploadDeviceSigningKeys: async (makeRequest) => {
|
||||||
|
|
|
@ -23,7 +23,6 @@ import { User } from "matrix-js-sdk/src/models/user";
|
||||||
import * as ContentHelpers from 'matrix-js-sdk/src/content-helpers';
|
import * as ContentHelpers from 'matrix-js-sdk/src/content-helpers';
|
||||||
import { MatrixClientPeg } from './MatrixClientPeg';
|
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import dis from './dispatcher/dispatcher';
|
import dis from './dispatcher/dispatcher';
|
||||||
import * as sdk from './index';
|
|
||||||
import { _t, _td } from './languageHandler';
|
import { _t, _td } from './languageHandler';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
import MultiInviter from './utils/MultiInviter';
|
import MultiInviter from './utils/MultiInviter';
|
||||||
|
@ -50,6 +49,12 @@ import { UIFeature } from "./settings/UIFeature";
|
||||||
import { CHAT_EFFECTS } from "./effects";
|
import { CHAT_EFFECTS } from "./effects";
|
||||||
import CallHandler from "./CallHandler";
|
import CallHandler from "./CallHandler";
|
||||||
import { guessAndSetDMRoom } from "./Rooms";
|
import { guessAndSetDMRoom } from "./Rooms";
|
||||||
|
import UploadConfirmDialog from './components/views/dialogs/UploadConfirmDialog';
|
||||||
|
import ErrorDialog from './components/views/dialogs/ErrorDialog';
|
||||||
|
import DevtoolsDialog from './components/views/dialogs/DevtoolsDialog';
|
||||||
|
import RoomUpgradeWarningDialog from "./components/views/dialogs/RoomUpgradeWarningDialog";
|
||||||
|
import InfoDialog from "./components/views/dialogs/InfoDialog";
|
||||||
|
import SlashCommandHelpDialog from "./components/views/dialogs/SlashCommandHelpDialog";
|
||||||
|
|
||||||
// XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816
|
// XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816
|
||||||
interface HTMLInputEvent extends Event {
|
interface HTMLInputEvent extends Event {
|
||||||
|
@ -63,7 +68,6 @@ const singleMxcUpload = async (): Promise<any> => {
|
||||||
fileSelector.onchange = (ev: HTMLInputEvent) => {
|
fileSelector.onchange = (ev: HTMLInputEvent) => {
|
||||||
const file = ev.target.files[0];
|
const file = ev.target.files[0];
|
||||||
|
|
||||||
const UploadConfirmDialog = sdk.getComponent("dialogs.UploadConfirmDialog");
|
|
||||||
Modal.createTrackedDialog('Upload Files confirmation', '', UploadConfirmDialog, {
|
Modal.createTrackedDialog('Upload Files confirmation', '', UploadConfirmDialog, {
|
||||||
file,
|
file,
|
||||||
onFinished: (shouldContinue) => {
|
onFinished: (shouldContinue) => {
|
||||||
|
@ -246,7 +250,6 @@ export const Commands = [
|
||||||
args: '<query>',
|
args: '<query>',
|
||||||
description: _td('Searches DuckDuckGo for results'),
|
description: _td('Searches DuckDuckGo for results'),
|
||||||
runFn: function() {
|
runFn: function() {
|
||||||
const ErrorDialog = sdk.getComponent('dialogs.ErrorDialog');
|
|
||||||
// TODO Don't explain this away, actually show a search UI here.
|
// TODO Don't explain this away, actually show a search UI here.
|
||||||
Modal.createTrackedDialog('Slash Commands', '/ddg is not a command', ErrorDialog, {
|
Modal.createTrackedDialog('Slash Commands', '/ddg is not a command', ErrorDialog, {
|
||||||
title: _t('/ddg is not a command'),
|
title: _t('/ddg is not a command'),
|
||||||
|
@ -269,8 +272,6 @@ export const Commands = [
|
||||||
return reject(_t("You do not have the required permissions to use this command."));
|
return reject(_t("You do not have the required permissions to use this command."));
|
||||||
}
|
}
|
||||||
|
|
||||||
const RoomUpgradeWarningDialog = sdk.getComponent("dialogs.RoomUpgradeWarningDialog");
|
|
||||||
|
|
||||||
const { finished } = Modal.createTrackedDialog('Slash Commands', 'upgrade room confirmation',
|
const { finished } = Modal.createTrackedDialog('Slash Commands', 'upgrade room confirmation',
|
||||||
RoomUpgradeWarningDialog, { roomId: roomId, targetVersion: args }, /*className=*/null,
|
RoomUpgradeWarningDialog, { roomId: roomId, targetVersion: args }, /*className=*/null,
|
||||||
/*isPriority=*/false, /*isStatic=*/true);
|
/*isPriority=*/false, /*isStatic=*/true);
|
||||||
|
@ -314,7 +315,6 @@ export const Commands = [
|
||||||
|
|
||||||
if (checkForUpgradeFn) cli.removeListener('Room', checkForUpgradeFn);
|
if (checkForUpgradeFn) cli.removeListener('Room', checkForUpgradeFn);
|
||||||
|
|
||||||
const ErrorDialog = sdk.getComponent('dialogs.ErrorDialog');
|
|
||||||
Modal.createTrackedDialog('Slash Commands', 'room upgrade error', ErrorDialog, {
|
Modal.createTrackedDialog('Slash Commands', 'room upgrade error', ErrorDialog, {
|
||||||
title: _t('Error upgrading room'),
|
title: _t('Error upgrading room'),
|
||||||
description: _t(
|
description: _t(
|
||||||
|
@ -434,7 +434,6 @@ export const Commands = [
|
||||||
const topic = topicEvents && topicEvents.getContent().topic;
|
const topic = topicEvents && topicEvents.getContent().topic;
|
||||||
const topicHtml = topic ? linkifyAndSanitizeHtml(topic) : _t('This room has no topic.');
|
const topicHtml = topic ? linkifyAndSanitizeHtml(topic) : _t('This room has no topic.');
|
||||||
|
|
||||||
const InfoDialog = sdk.getComponent('dialogs.InfoDialog');
|
|
||||||
Modal.createTrackedDialog('Slash Commands', 'Topic', InfoDialog, {
|
Modal.createTrackedDialog('Slash Commands', 'Topic', InfoDialog, {
|
||||||
title: room.name,
|
title: room.name,
|
||||||
description: <div dangerouslySetInnerHTML={{ __html: topicHtml }} />,
|
description: <div dangerouslySetInnerHTML={{ __html: topicHtml }} />,
|
||||||
|
@ -737,7 +736,6 @@ export const Commands = [
|
||||||
ignoredUsers.push(userId); // de-duped internally in the js-sdk
|
ignoredUsers.push(userId); // de-duped internally in the js-sdk
|
||||||
return success(
|
return success(
|
||||||
cli.setIgnoredUsers(ignoredUsers).then(() => {
|
cli.setIgnoredUsers(ignoredUsers).then(() => {
|
||||||
const InfoDialog = sdk.getComponent('dialogs.InfoDialog');
|
|
||||||
Modal.createTrackedDialog('Slash Commands', 'User ignored', InfoDialog, {
|
Modal.createTrackedDialog('Slash Commands', 'User ignored', InfoDialog, {
|
||||||
title: _t('Ignored user'),
|
title: _t('Ignored user'),
|
||||||
description: <div>
|
description: <div>
|
||||||
|
@ -768,7 +766,6 @@ export const Commands = [
|
||||||
if (index !== -1) ignoredUsers.splice(index, 1);
|
if (index !== -1) ignoredUsers.splice(index, 1);
|
||||||
return success(
|
return success(
|
||||||
cli.setIgnoredUsers(ignoredUsers).then(() => {
|
cli.setIgnoredUsers(ignoredUsers).then(() => {
|
||||||
const InfoDialog = sdk.getComponent('dialogs.InfoDialog');
|
|
||||||
Modal.createTrackedDialog('Slash Commands', 'User unignored', InfoDialog, {
|
Modal.createTrackedDialog('Slash Commands', 'User unignored', InfoDialog, {
|
||||||
title: _t('Unignored user'),
|
title: _t('Unignored user'),
|
||||||
description: <div>
|
description: <div>
|
||||||
|
@ -838,7 +835,6 @@ export const Commands = [
|
||||||
command: 'devtools',
|
command: 'devtools',
|
||||||
description: _td('Opens the Developer Tools dialog'),
|
description: _td('Opens the Developer Tools dialog'),
|
||||||
runFn: function(roomId) {
|
runFn: function(roomId) {
|
||||||
const DevtoolsDialog = sdk.getComponent('dialogs.DevtoolsDialog');
|
|
||||||
Modal.createDialog(DevtoolsDialog, { roomId });
|
Modal.createDialog(DevtoolsDialog, { roomId });
|
||||||
return success();
|
return success();
|
||||||
},
|
},
|
||||||
|
@ -943,7 +939,6 @@ export const Commands = [
|
||||||
await cli.setDeviceVerified(userId, deviceId, true);
|
await cli.setDeviceVerified(userId, deviceId, true);
|
||||||
|
|
||||||
// Tell the user we verified everything
|
// Tell the user we verified everything
|
||||||
const InfoDialog = sdk.getComponent('dialogs.InfoDialog');
|
|
||||||
Modal.createTrackedDialog('Slash Commands', 'Verified key', InfoDialog, {
|
Modal.createTrackedDialog('Slash Commands', 'Verified key', InfoDialog, {
|
||||||
title: _t('Verified key'),
|
title: _t('Verified key'),
|
||||||
description: <div>
|
description: <div>
|
||||||
|
@ -1000,8 +995,6 @@ export const Commands = [
|
||||||
command: "help",
|
command: "help",
|
||||||
description: _td("Displays list of commands with usages and descriptions"),
|
description: _td("Displays list of commands with usages and descriptions"),
|
||||||
runFn: function() {
|
runFn: function() {
|
||||||
const SlashCommandHelpDialog = sdk.getComponent('dialogs.SlashCommandHelpDialog');
|
|
||||||
|
|
||||||
Modal.createTrackedDialog('Slash Commands', 'Help', SlashCommandHelpDialog);
|
Modal.createTrackedDialog('Slash Commands', 'Help', SlashCommandHelpDialog);
|
||||||
return success();
|
return success();
|
||||||
},
|
},
|
||||||
|
|
|
@ -189,6 +189,7 @@ export function dialogTermsInteractionCallback(
|
||||||
): Promise<string[]> {
|
): Promise<string[]> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
console.log("Terms that need agreement", policiesAndServicePairs);
|
console.log("Terms that need agreement", policiesAndServicePairs);
|
||||||
|
// FIXME: Using an import will result in test failures
|
||||||
const TermsDialog = sdk.getComponent("views.dialogs.TermsDialog");
|
const TermsDialog = sdk.getComponent("views.dialogs.TermsDialog");
|
||||||
|
|
||||||
Modal.createTrackedDialog('Terms of Service', '', TermsDialog, {
|
Modal.createTrackedDialog('Terms of Service', '', TermsDialog, {
|
||||||
|
|
|
@ -447,7 +447,8 @@ function textForPowerEvent(event): () => string | null {
|
||||||
!event.getContent() || !event.getContent().users) {
|
!event.getContent() || !event.getContent().users) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const userDefault = event.getContent().users_default || 0;
|
const previousUserDefault = event.getPrevContent().users_default || 0;
|
||||||
|
const currentUserDefault = event.getContent().users_default || 0;
|
||||||
// Construct set of userIds
|
// Construct set of userIds
|
||||||
const users = [];
|
const users = [];
|
||||||
Object.keys(event.getContent().users).forEach(
|
Object.keys(event.getContent().users).forEach(
|
||||||
|
@ -463,9 +464,16 @@ function textForPowerEvent(event): () => string | null {
|
||||||
const diffs = [];
|
const diffs = [];
|
||||||
users.forEach((userId) => {
|
users.forEach((userId) => {
|
||||||
// Previous power level
|
// Previous power level
|
||||||
const from = event.getPrevContent().users[userId];
|
let from = event.getPrevContent().users[userId];
|
||||||
|
if (!Number.isInteger(from)) {
|
||||||
|
from = previousUserDefault;
|
||||||
|
}
|
||||||
// Current power level
|
// Current power level
|
||||||
const to = event.getContent().users[userId];
|
let to = event.getContent().users[userId];
|
||||||
|
if (!Number.isInteger(to)) {
|
||||||
|
to = currentUserDefault;
|
||||||
|
}
|
||||||
|
if (from === previousUserDefault && to === currentUserDefault) { return; }
|
||||||
if (to !== from) {
|
if (to !== from) {
|
||||||
diffs.push({ userId, from, to });
|
diffs.push({ userId, from, to });
|
||||||
}
|
}
|
||||||
|
@ -479,8 +487,8 @@ function textForPowerEvent(event): () => string | null {
|
||||||
powerLevelDiffText: diffs.map(diff =>
|
powerLevelDiffText: diffs.map(diff =>
|
||||||
_t('%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s', {
|
_t('%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s', {
|
||||||
userId: diff.userId,
|
userId: diff.userId,
|
||||||
fromPowerLevel: Roles.textualPowerLevel(diff.from, userDefault),
|
fromPowerLevel: Roles.textualPowerLevel(diff.from, previousUserDefault),
|
||||||
toPowerLevel: Roles.textualPowerLevel(diff.to, userDefault),
|
toPowerLevel: Roles.textualPowerLevel(diff.to, currentUserDefault),
|
||||||
}),
|
}),
|
||||||
).join(", "),
|
).join(", "),
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,10 +17,10 @@ limitations under the License.
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
import * as sdk from "../index";
|
|
||||||
import Modal from "../Modal";
|
import Modal from "../Modal";
|
||||||
import { _t, _td } from "../languageHandler";
|
import { _t, _td } from "../languageHandler";
|
||||||
import { isMac, Key } from "../Keyboard";
|
import { isMac, Key } from "../Keyboard";
|
||||||
|
import InfoDialog from "../components/views/dialogs/InfoDialog";
|
||||||
|
|
||||||
// TS: once languageHandler is TS we can probably inline this into the enum
|
// TS: once languageHandler is TS we can probably inline this into the enum
|
||||||
_td("Navigation");
|
_td("Navigation");
|
||||||
|
@ -375,7 +375,6 @@ export const toggleDialog = () => {
|
||||||
</div>;
|
</div>;
|
||||||
});
|
});
|
||||||
|
|
||||||
const InfoDialog = sdk.getComponent('dialogs.InfoDialog');
|
|
||||||
activeModal = Modal.createTrackedDialog("Keyboard Shortcuts", "", InfoDialog, {
|
activeModal = Modal.createTrackedDialog("Keyboard Shortcuts", "", InfoDialog, {
|
||||||
className: "mx_KeyboardShortcutsDialog",
|
className: "mx_KeyboardShortcutsDialog",
|
||||||
title: _t("Keyboard Shortcuts"),
|
title: _t("Keyboard Shortcuts"),
|
||||||
|
|
|
@ -19,13 +19,13 @@ import { asyncAction } from './actionCreators';
|
||||||
import Modal from '../Modal';
|
import Modal from '../Modal';
|
||||||
import * as Rooms from '../Rooms';
|
import * as Rooms from '../Rooms';
|
||||||
import { _t } from '../languageHandler';
|
import { _t } from '../languageHandler';
|
||||||
import * as sdk from '../index';
|
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { AsyncActionPayload } from "../dispatcher/payloads";
|
import { AsyncActionPayload } from "../dispatcher/payloads";
|
||||||
import RoomListStore from "../stores/room-list/RoomListStore";
|
import RoomListStore from "../stores/room-list/RoomListStore";
|
||||||
import { SortAlgorithm } from "../stores/room-list/algorithms/models";
|
import { SortAlgorithm } from "../stores/room-list/algorithms/models";
|
||||||
import { DefaultTagID } from "../stores/room-list/models";
|
import { DefaultTagID } from "../stores/room-list/models";
|
||||||
|
import ErrorDialog from '../components/views/dialogs/ErrorDialog';
|
||||||
|
|
||||||
export default class RoomListActions {
|
export default class RoomListActions {
|
||||||
/**
|
/**
|
||||||
|
@ -88,7 +88,6 @@ export default class RoomListActions {
|
||||||
return Rooms.guessAndSetDMRoom(
|
return Rooms.guessAndSetDMRoom(
|
||||||
room, newTag === DefaultTagID.DM,
|
room, newTag === DefaultTagID.DM,
|
||||||
).catch((err) => {
|
).catch((err) => {
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
||||||
console.error("Failed to set direct chat tag " + err);
|
console.error("Failed to set direct chat tag " + err);
|
||||||
Modal.createTrackedDialog('Failed to set direct chat tag', '', ErrorDialog, {
|
Modal.createTrackedDialog('Failed to set direct chat tag', '', ErrorDialog, {
|
||||||
title: _t('Failed to set direct chat tag'),
|
title: _t('Failed to set direct chat tag'),
|
||||||
|
@ -109,7 +108,6 @@ export default class RoomListActions {
|
||||||
const promiseToDelete = matrixClient.deleteRoomTag(
|
const promiseToDelete = matrixClient.deleteRoomTag(
|
||||||
roomId, oldTag,
|
roomId, oldTag,
|
||||||
).catch(function(err) {
|
).catch(function(err) {
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
||||||
console.error("Failed to remove tag " + oldTag + " from room: " + err);
|
console.error("Failed to remove tag " + oldTag + " from room: " + err);
|
||||||
Modal.createTrackedDialog('Failed to remove tag from room', '', ErrorDialog, {
|
Modal.createTrackedDialog('Failed to remove tag from room', '', ErrorDialog, {
|
||||||
title: _t('Failed to remove tag %(tagName)s from room', { tagName: oldTag }),
|
title: _t('Failed to remove tag %(tagName)s from room', { tagName: oldTag }),
|
||||||
|
@ -129,7 +127,6 @@ export default class RoomListActions {
|
||||||
metaData = metaData || {};
|
metaData = metaData || {};
|
||||||
|
|
||||||
const promiseToAdd = matrixClient.setRoomTag(roomId, newTag, metaData).catch(function(err) {
|
const promiseToAdd = matrixClient.setRoomTag(roomId, newTag, metaData).catch(function(err) {
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
||||||
console.error("Failed to add tag " + newTag + " to room: " + err);
|
console.error("Failed to add tag " + newTag + " to room: " + err);
|
||||||
Modal.createTrackedDialog('Failed to add tag to room', '', ErrorDialog, {
|
Modal.createTrackedDialog('Failed to add tag to room', '', ErrorDialog, {
|
||||||
title: _t('Failed to add tag %(tagName)s to room', { tagName: newTag }),
|
title: _t('Failed to add tag %(tagName)s to room', { tagName: newTag }),
|
||||||
|
|
|
@ -15,7 +15,6 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as sdk from '../../../../index';
|
|
||||||
import { _t } from '../../../../languageHandler';
|
import { _t } from '../../../../languageHandler';
|
||||||
import SdkConfig from '../../../../SdkConfig';
|
import SdkConfig from '../../../../SdkConfig';
|
||||||
import SettingsStore from "../../../../settings/SettingsStore";
|
import SettingsStore from "../../../../settings/SettingsStore";
|
||||||
|
@ -24,6 +23,9 @@ import Modal from '../../../../Modal';
|
||||||
import { formatBytes, formatCountLong } from "../../../../utils/FormattingUtils";
|
import { formatBytes, formatCountLong } from "../../../../utils/FormattingUtils";
|
||||||
import EventIndexPeg from "../../../../indexing/EventIndexPeg";
|
import EventIndexPeg from "../../../../indexing/EventIndexPeg";
|
||||||
import { SettingLevel } from "../../../../settings/SettingLevel";
|
import { SettingLevel } from "../../../../settings/SettingLevel";
|
||||||
|
import Field from '../../../../components/views/elements/Field';
|
||||||
|
import BaseDialog from "../../../../components/views/dialogs/BaseDialog";
|
||||||
|
import DialogButtons from "../../../../components/views/elements/DialogButtons";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onFinished: (confirmed: boolean) => void;
|
onFinished: (confirmed: boolean) => void;
|
||||||
|
@ -145,7 +147,6 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const brand = SdkConfig.get().brand;
|
const brand = SdkConfig.get().brand;
|
||||||
const Field = sdk.getComponent('views.elements.Field');
|
|
||||||
|
|
||||||
let crawlerState;
|
let crawlerState;
|
||||||
if (this.state.currentRoom === null) {
|
if (this.state.currentRoom === null) {
|
||||||
|
@ -176,15 +177,12 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
||||||
<Field
|
<Field
|
||||||
label={_t('Message downloading sleep time(ms)')}
|
label={_t('Message downloading sleep time(ms)')}
|
||||||
type='number'
|
type='number'
|
||||||
value={this.state.crawlerSleepTime}
|
value={this.state.crawlerSleepTime.toString()}
|
||||||
onChange={this.onCrawlerSleepTimeChange} />
|
onChange={this.onCrawlerSleepTimeChange} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog className='mx_ManageEventIndexDialog'
|
<BaseDialog className='mx_ManageEventIndexDialog'
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
|
|
|
@ -22,12 +22,12 @@ import AutocompleteProvider from './AutocompleteProvider';
|
||||||
import { MatrixClientPeg } from '../MatrixClientPeg';
|
import { MatrixClientPeg } from '../MatrixClientPeg';
|
||||||
import QueryMatcher from './QueryMatcher';
|
import QueryMatcher from './QueryMatcher';
|
||||||
import { PillCompletion } from './Components';
|
import { PillCompletion } from './Components';
|
||||||
import * as sdk from '../index';
|
|
||||||
import { sortBy } from "lodash";
|
import { sortBy } from "lodash";
|
||||||
import { makeGroupPermalink } from "../utils/permalinks/Permalinks";
|
import { makeGroupPermalink } from "../utils/permalinks/Permalinks";
|
||||||
import { ICompletion, ISelectionRange } from "./Autocompleter";
|
import { ICompletion, ISelectionRange } from "./Autocompleter";
|
||||||
import FlairStore from "../stores/FlairStore";
|
import FlairStore from "../stores/FlairStore";
|
||||||
import { mediaFromMxc } from "../customisations/Media";
|
import { mediaFromMxc } from "../customisations/Media";
|
||||||
|
import BaseAvatar from '../components/views/avatars/BaseAvatar';
|
||||||
|
|
||||||
const COMMUNITY_REGEX = /\B\+\S*/g;
|
const COMMUNITY_REGEX = /\B\+\S*/g;
|
||||||
|
|
||||||
|
@ -56,8 +56,6 @@ export default class CommunityProvider extends AutocompleteProvider {
|
||||||
force = false,
|
force = false,
|
||||||
limit = -1,
|
limit = -1,
|
||||||
): Promise<ICompletion[]> {
|
): Promise<ICompletion[]> {
|
||||||
const BaseAvatar = sdk.getComponent('views.avatars.BaseAvatar');
|
|
||||||
|
|
||||||
// Disable autocompletions when composing commands because of various issues
|
// Disable autocompletions when composing commands because of various issues
|
||||||
// (see https://github.com/vector-im/element-web/issues/4762)
|
// (see https://github.com/vector-im/element-web/issues/4762)
|
||||||
if (/^(\/join|\/leave)/.test(query)) {
|
if (/^(\/join|\/leave)/.test(query)) {
|
||||||
|
|
|
@ -21,8 +21,8 @@ import AutocompleteProvider from './AutocompleteProvider';
|
||||||
import { _t } from '../languageHandler';
|
import { _t } from '../languageHandler';
|
||||||
import { MatrixClientPeg } from '../MatrixClientPeg';
|
import { MatrixClientPeg } from '../MatrixClientPeg';
|
||||||
import { PillCompletion } from './Components';
|
import { PillCompletion } from './Components';
|
||||||
import * as sdk from '../index';
|
|
||||||
import { ICompletion, ISelectionRange } from "./Autocompleter";
|
import { ICompletion, ISelectionRange } from "./Autocompleter";
|
||||||
|
import RoomAvatar from '../components/views/avatars/RoomAvatar';
|
||||||
|
|
||||||
const AT_ROOM_REGEX = /@\S*/g;
|
const AT_ROOM_REGEX = /@\S*/g;
|
||||||
|
|
||||||
|
@ -40,8 +40,6 @@ export default class NotifProvider extends AutocompleteProvider {
|
||||||
force = false,
|
force = false,
|
||||||
limit = -1,
|
limit = -1,
|
||||||
): Promise<ICompletion[]> {
|
): Promise<ICompletion[]> {
|
||||||
const RoomAvatar = sdk.getComponent('views.avatars.RoomAvatar');
|
|
||||||
|
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
|
|
||||||
if (!this.room.currentState.mayTriggerNotifOfType('room', client.credentials.userId)) return [];
|
if (!this.room.currentState.mayTriggerNotifOfType('room', client.credentials.userId)) return [];
|
||||||
|
|
|
@ -21,7 +21,6 @@ import React from 'react';
|
||||||
import { _t } from '../languageHandler';
|
import { _t } from '../languageHandler';
|
||||||
import AutocompleteProvider from './AutocompleteProvider';
|
import AutocompleteProvider from './AutocompleteProvider';
|
||||||
import { PillCompletion } from './Components';
|
import { PillCompletion } from './Components';
|
||||||
import * as sdk from '../index';
|
|
||||||
import QueryMatcher from './QueryMatcher';
|
import QueryMatcher from './QueryMatcher';
|
||||||
import { sortBy } from 'lodash';
|
import { sortBy } from 'lodash';
|
||||||
import { MatrixClientPeg } from '../MatrixClientPeg';
|
import { MatrixClientPeg } from '../MatrixClientPeg';
|
||||||
|
@ -33,6 +32,7 @@ import { RoomState } from "matrix-js-sdk/src/models/room-state";
|
||||||
import { EventTimeline } from "matrix-js-sdk/src/models/event-timeline";
|
import { EventTimeline } from "matrix-js-sdk/src/models/event-timeline";
|
||||||
import { makeUserPermalink } from "../utils/permalinks/Permalinks";
|
import { makeUserPermalink } from "../utils/permalinks/Permalinks";
|
||||||
import { ICompletion, ISelectionRange } from "./Autocompleter";
|
import { ICompletion, ISelectionRange } from "./Autocompleter";
|
||||||
|
import MemberAvatar from '../components/views/avatars/MemberAvatar';
|
||||||
|
|
||||||
const USER_REGEX = /\B@\S*/g;
|
const USER_REGEX = /\B@\S*/g;
|
||||||
|
|
||||||
|
@ -108,8 +108,6 @@ export default class UserProvider extends AutocompleteProvider {
|
||||||
force = false,
|
force = false,
|
||||||
limit = -1,
|
limit = -1,
|
||||||
): Promise<ICompletion[]> {
|
): Promise<ICompletion[]> {
|
||||||
const MemberAvatar = sdk.getComponent('views.avatars.MemberAvatar');
|
|
||||||
|
|
||||||
// lazy-load user list into matcher
|
// lazy-load user list into matcher
|
||||||
if (!this.users) this._makeUsers();
|
if (!this.users) this._makeUsers();
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,6 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
import { Room } from 'matrix-js-sdk/src/models/room';
|
import { Room } from 'matrix-js-sdk/src/models/room';
|
||||||
import { TimelineWindow } from 'matrix-js-sdk/src/timeline-window';
|
import { TimelineWindow } from 'matrix-js-sdk/src/timeline-window';
|
||||||
|
|
||||||
import * as sdk from '../../index';
|
|
||||||
import { MatrixClientPeg } from '../../MatrixClientPeg';
|
import { MatrixClientPeg } from '../../MatrixClientPeg';
|
||||||
import EventIndexPeg from "../../indexing/EventIndexPeg";
|
import EventIndexPeg from "../../indexing/EventIndexPeg";
|
||||||
import { _t } from '../../languageHandler';
|
import { _t } from '../../languageHandler';
|
||||||
|
@ -34,6 +33,9 @@ import DesktopBuildsNotice, { WarningKind } from "../views/elements/DesktopBuild
|
||||||
import { replaceableComponent } from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
|
|
||||||
import ResizeNotifier from '../../utils/ResizeNotifier';
|
import ResizeNotifier from '../../utils/ResizeNotifier';
|
||||||
|
import TimelinePanel from "./TimelinePanel";
|
||||||
|
import Spinner from "../views/elements/Spinner";
|
||||||
|
import { TileShape } from '../views/rooms/EventTile';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
roomId: string;
|
roomId: string;
|
||||||
|
@ -237,8 +239,6 @@ class FilePanel extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// wrap a TimelinePanel with the jump-to-event bits turned off.
|
// wrap a TimelinePanel with the jump-to-event bits turned off.
|
||||||
const TimelinePanel = sdk.getComponent("structures.TimelinePanel");
|
|
||||||
const Loader = sdk.getComponent("elements.Spinner");
|
|
||||||
|
|
||||||
const emptyState = (<div className="mx_RightPanel_empty mx_FilePanel_empty">
|
const emptyState = (<div className="mx_RightPanel_empty mx_FilePanel_empty">
|
||||||
<h2>{_t('No files visible in this room')}</h2>
|
<h2>{_t('No files visible in this room')}</h2>
|
||||||
|
@ -264,7 +264,7 @@ class FilePanel extends React.Component<IProps, IState> {
|
||||||
timelineSet={this.state.timelineSet}
|
timelineSet={this.state.timelineSet}
|
||||||
showUrlPreview = {false}
|
showUrlPreview = {false}
|
||||||
onPaginationRequest={this.onPaginationRequest}
|
onPaginationRequest={this.onPaginationRequest}
|
||||||
tileShape="file_grid"
|
tileShape={TileShape.FileGrid}
|
||||||
resizeNotifier={this.props.resizeNotifier}
|
resizeNotifier={this.props.resizeNotifier}
|
||||||
empty={emptyState}
|
empty={emptyState}
|
||||||
/>
|
/>
|
||||||
|
@ -277,7 +277,7 @@ class FilePanel extends React.Component<IProps, IState> {
|
||||||
onClose={this.props.onClose}
|
onClose={this.props.onClose}
|
||||||
previousPhase={RightPanelPhases.RoomSummary}
|
previousPhase={RightPanelPhases.RoomSummary}
|
||||||
>
|
>
|
||||||
<Loader />
|
<Spinner />
|
||||||
</BaseCard>
|
</BaseCard>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,7 @@ const HomePage: React.FC<IProps> = ({ justRegistered = false }) => {
|
||||||
const pageUrl = getHomePageUrl(config);
|
const pageUrl = getHomePageUrl(config);
|
||||||
|
|
||||||
if (pageUrl) {
|
if (pageUrl) {
|
||||||
|
// FIXME: Using an import will result in wrench-element-tests failures
|
||||||
const EmbeddedPage = sdk.getComponent('structures.EmbeddedPage');
|
const EmbeddedPage = sdk.getComponent('structures.EmbeddedPage');
|
||||||
return <EmbeddedPage className="mx_HomePage" url={pageUrl} scrollbar={true} />;
|
return <EmbeddedPage className="mx_HomePage" url={pageUrl} scrollbar={true} />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ import { Key } from '../../Keyboard';
|
||||||
import PageTypes from '../../PageTypes';
|
import PageTypes from '../../PageTypes';
|
||||||
import MediaDeviceHandler from '../../MediaDeviceHandler';
|
import MediaDeviceHandler from '../../MediaDeviceHandler';
|
||||||
import { fixupColorFonts } from '../../utils/FontManager';
|
import { fixupColorFonts } from '../../utils/FontManager';
|
||||||
import * as sdk from '../../index';
|
|
||||||
import dis from '../../dispatcher/dispatcher';
|
import dis from '../../dispatcher/dispatcher';
|
||||||
import { IMatrixClientCreds } from '../../MatrixClientPeg';
|
import { IMatrixClientCreds } from '../../MatrixClientPeg';
|
||||||
import SettingsStore from "../../settings/SettingsStore";
|
import SettingsStore from "../../settings/SettingsStore";
|
||||||
|
@ -59,6 +58,11 @@ import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
import CallHandler, { CallHandlerEvent } from '../../CallHandler';
|
import CallHandler, { CallHandlerEvent } from '../../CallHandler';
|
||||||
import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call';
|
import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call';
|
||||||
import AudioFeedArrayForCall from '../views/voip/AudioFeedArrayForCall';
|
import AudioFeedArrayForCall from '../views/voip/AudioFeedArrayForCall';
|
||||||
|
import RoomView from './RoomView';
|
||||||
|
import ToastContainer from './ToastContainer';
|
||||||
|
import MyGroups from "./MyGroups";
|
||||||
|
import UserView from "./UserView";
|
||||||
|
import GroupView from "./GroupView";
|
||||||
|
|
||||||
// We need to fetch each pinned message individually (if we don't already have it)
|
// 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.
|
// so each pinned message may trigger a request. Limit the number per room for sanity.
|
||||||
|
@ -78,8 +82,8 @@ interface IProps {
|
||||||
hideToSRUsers: boolean;
|
hideToSRUsers: boolean;
|
||||||
resizeNotifier: ResizeNotifier;
|
resizeNotifier: ResizeNotifier;
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
page_type: string;
|
page_type?: string;
|
||||||
autoJoin: boolean;
|
autoJoin?: boolean;
|
||||||
threepidInvite?: IThreepidInvite;
|
threepidInvite?: IThreepidInvite;
|
||||||
roomOobData?: IOOBData;
|
roomOobData?: IOOBData;
|
||||||
currentRoomId: string;
|
currentRoomId: string;
|
||||||
|
@ -394,7 +398,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
// refocusing during a paste event will make the
|
// refocusing during a paste event will make the
|
||||||
// paste end up in the newly focused element,
|
// paste end up in the newly focused element,
|
||||||
// so dispatch synchronously before paste happens
|
// so dispatch synchronously before paste happens
|
||||||
dis.fire(Action.FocusComposer, true);
|
dis.fire(Action.FocusSendMessageComposer, true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -548,7 +552,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
if (!isClickShortcut && ev.key !== Key.TAB && !canElementReceiveInput(ev.target)) {
|
if (!isClickShortcut && ev.key !== Key.TAB && !canElementReceiveInput(ev.target)) {
|
||||||
// synchronous dispatch so we focus before key generates input
|
// synchronous dispatch so we focus before key generates input
|
||||||
dis.fire(Action.FocusComposer, true);
|
dis.fire(Action.FocusSendMessageComposer, true);
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
// we should *not* preventDefault() here as
|
// we should *not* preventDefault() here as
|
||||||
// that would prevent typing in the now-focussed composer
|
// that would prevent typing in the now-focussed composer
|
||||||
|
@ -567,12 +571,6 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const RoomView = sdk.getComponent('structures.RoomView');
|
|
||||||
const UserView = sdk.getComponent('structures.UserView');
|
|
||||||
const GroupView = sdk.getComponent('structures.GroupView');
|
|
||||||
const MyGroups = sdk.getComponent('structures.MyGroups');
|
|
||||||
const ToastContainer = sdk.getComponent('structures.ToastContainer');
|
|
||||||
|
|
||||||
let pageElement;
|
let pageElement;
|
||||||
|
|
||||||
switch (this.props.page_type) {
|
switch (this.props.page_type) {
|
||||||
|
|
|
@ -36,7 +36,6 @@ import dis from "../../dispatcher/dispatcher";
|
||||||
import Notifier from '../../Notifier';
|
import Notifier from '../../Notifier';
|
||||||
|
|
||||||
import Modal from "../../Modal";
|
import Modal from "../../Modal";
|
||||||
import * as sdk from '../../index';
|
|
||||||
import { showRoomInviteDialog, showStartChatInviteDialog } from '../../RoomInvite';
|
import { showRoomInviteDialog, showStartChatInviteDialog } from '../../RoomInvite';
|
||||||
import * as Rooms from '../../Rooms';
|
import * as Rooms from '../../Rooms';
|
||||||
import linkifyMatrix from "../../linkify-matrix";
|
import linkifyMatrix from "../../linkify-matrix";
|
||||||
|
@ -85,9 +84,27 @@ import RoomListStore from "../../stores/room-list/RoomListStore";
|
||||||
import { RoomUpdateCause } from "../../stores/room-list/models";
|
import { RoomUpdateCause } from "../../stores/room-list/models";
|
||||||
import defaultDispatcher from "../../dispatcher/dispatcher";
|
import defaultDispatcher from "../../dispatcher/dispatcher";
|
||||||
import SecurityCustomisations from "../../customisations/Security";
|
import SecurityCustomisations from "../../customisations/Security";
|
||||||
|
import Spinner from "../views/elements/Spinner";
|
||||||
|
import QuestionDialog from "../views/dialogs/QuestionDialog";
|
||||||
|
import UserSettingsDialog from '../views/dialogs/UserSettingsDialog';
|
||||||
|
import CreateGroupDialog from '../views/dialogs/CreateGroupDialog';
|
||||||
|
import CreateRoomDialog from '../views/dialogs/CreateRoomDialog';
|
||||||
|
import RoomDirectory from './RoomDirectory';
|
||||||
|
import KeySignatureUploadFailedDialog from "../views/dialogs/KeySignatureUploadFailedDialog";
|
||||||
|
import IncomingSasDialog from "../views/dialogs/IncomingSasDialog";
|
||||||
|
import CompleteSecurity from "./auth/CompleteSecurity";
|
||||||
|
import LoggedInView from './LoggedInView';
|
||||||
|
import Welcome from "../views/auth/Welcome";
|
||||||
|
import ForgotPassword from "./auth/ForgotPassword";
|
||||||
|
import E2eSetup from "./auth/E2eSetup";
|
||||||
|
import Registration from './auth/Registration';
|
||||||
|
import Login from "./auth/Login";
|
||||||
|
import ErrorBoundary from '../views/elements/ErrorBoundary';
|
||||||
|
import VerificationRequestToast from '../views/toasts/VerificationRequestToast';
|
||||||
|
|
||||||
import PerformanceMonitor, { PerformanceEntryNames } from "../../performance";
|
import PerformanceMonitor, { PerformanceEntryNames } from "../../performance";
|
||||||
import UIStore, { UI_EVENTS } from "../../stores/UIStore";
|
import UIStore, { UI_EVENTS } from "../../stores/UIStore";
|
||||||
|
import SoftLogout from './auth/SoftLogout';
|
||||||
|
|
||||||
/** constants for MatrixChat.state.view */
|
/** constants for MatrixChat.state.view */
|
||||||
export enum Views {
|
export enum Views {
|
||||||
|
@ -156,7 +173,12 @@ interface IRoomInfo {
|
||||||
/* eslint-enable camelcase */
|
/* eslint-enable camelcase */
|
||||||
|
|
||||||
interface IProps { // TODO type things better
|
interface IProps { // TODO type things better
|
||||||
config: Record<string, any>;
|
config: {
|
||||||
|
piwik: {
|
||||||
|
policyUrl: string;
|
||||||
|
};
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
serverConfig?: ValidatedServerConfig;
|
serverConfig?: ValidatedServerConfig;
|
||||||
onNewScreen: (screen: string, replaceLast: boolean) => void;
|
onNewScreen: (screen: string, replaceLast: boolean) => void;
|
||||||
enableGuest?: boolean;
|
enableGuest?: boolean;
|
||||||
|
@ -421,7 +443,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
CountlyAnalytics.instance.trackPageChange(durationMs);
|
CountlyAnalytics.instance.trackPageChange(durationMs);
|
||||||
}
|
}
|
||||||
if (this.focusComposer) {
|
if (this.focusComposer) {
|
||||||
dis.fire(Action.FocusComposer);
|
dis.fire(Action.FocusSendMessageComposer);
|
||||||
this.focusComposer = false;
|
this.focusComposer = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -519,7 +541,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
|
|
||||||
onAction = (payload) => {
|
onAction = (payload) => {
|
||||||
// console.log(`MatrixClientPeg.onAction: ${payload.action}`);
|
// console.log(`MatrixClientPeg.onAction: ${payload.action}`);
|
||||||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
|
||||||
|
|
||||||
// Start the onboarding process for certain actions
|
// Start the onboarding process for certain actions
|
||||||
if (MatrixClientPeg.get() && MatrixClientPeg.get().isGuest() &&
|
if (MatrixClientPeg.get() && MatrixClientPeg.get().isGuest() &&
|
||||||
|
@ -613,8 +634,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
onFinished: (confirm) => {
|
onFinished: (confirm) => {
|
||||||
if (confirm) {
|
if (confirm) {
|
||||||
// FIXME: controller shouldn't be loading a view :(
|
// FIXME: controller shouldn't be loading a view :(
|
||||||
const Loader = sdk.getComponent("elements.Spinner");
|
const modal = Modal.createDialog(Spinner, null, 'mx_Dialog_spinner');
|
||||||
const modal = Modal.createDialog(Loader, null, 'mx_Dialog_spinner');
|
|
||||||
|
|
||||||
MatrixClientPeg.get().leave(payload.room_id).then(() => {
|
MatrixClientPeg.get().leave(payload.room_id).then(() => {
|
||||||
modal.close();
|
modal.close();
|
||||||
|
@ -650,7 +670,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
case Action.ViewUserSettings: {
|
case Action.ViewUserSettings: {
|
||||||
const tabPayload = payload as OpenToTabPayload;
|
const tabPayload = payload as OpenToTabPayload;
|
||||||
const UserSettingsDialog = sdk.getComponent("dialogs.UserSettingsDialog");
|
|
||||||
Modal.createTrackedDialog('User settings', '', UserSettingsDialog,
|
Modal.createTrackedDialog('User settings', '', UserSettingsDialog,
|
||||||
{ initialTabId: tabPayload.initialTabId },
|
{ initialTabId: tabPayload.initialTabId },
|
||||||
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
|
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
|
||||||
|
@ -663,11 +682,12 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
this.createRoom(payload.public, payload.defaultName);
|
this.createRoom(payload.public, payload.defaultName);
|
||||||
break;
|
break;
|
||||||
case 'view_create_group': {
|
case 'view_create_group': {
|
||||||
let CreateGroupDialog = sdk.getComponent("dialogs.CreateGroupDialog");
|
const prototype = SettingsStore.getValue("feature_communities_v2_prototypes");
|
||||||
if (SettingsStore.getValue("feature_communities_v2_prototypes")) {
|
Modal.createTrackedDialog(
|
||||||
CreateGroupDialog = CreateCommunityPrototypeDialog;
|
'Create Community',
|
||||||
}
|
'',
|
||||||
Modal.createTrackedDialog('Create Community', '', CreateGroupDialog);
|
prototype ? CreateCommunityPrototypeDialog : CreateGroupDialog,
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Action.ViewRoomDirectory: {
|
case Action.ViewRoomDirectory: {
|
||||||
|
@ -677,7 +697,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
room_id: SpaceStore.instance.activeSpace.roomId,
|
room_id: SpaceStore.instance.activeSpace.roomId,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const RoomDirectory = sdk.getComponent("structures.RoomDirectory");
|
|
||||||
Modal.createTrackedDialog('Room directory', '', RoomDirectory, {
|
Modal.createTrackedDialog('Room directory', '', RoomDirectory, {
|
||||||
initialText: payload.initialText,
|
initialText: payload.initialText,
|
||||||
}, 'mx_RoomDirectory_dialogWrapper', false, true);
|
}, 'mx_RoomDirectory_dialogWrapper', false, true);
|
||||||
|
@ -1019,7 +1038,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const CreateRoomDialog = sdk.getComponent('dialogs.CreateRoomDialog');
|
|
||||||
const modal = Modal.createTrackedDialog('Create Room', '', CreateRoomDialog, {
|
const modal = Modal.createTrackedDialog('Create Room', '', CreateRoomDialog, {
|
||||||
defaultPublic,
|
defaultPublic,
|
||||||
defaultName,
|
defaultName,
|
||||||
|
@ -1116,7 +1134,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private leaveRoom(roomId: string) {
|
private leaveRoom(roomId: string) {
|
||||||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
|
||||||
const roomToLeave = MatrixClientPeg.get().getRoom(roomId);
|
const roomToLeave = MatrixClientPeg.get().getRoom(roomId);
|
||||||
const warnings = this.leaveRoomWarnings(roomId);
|
const warnings = this.leaveRoomWarnings(roomId);
|
||||||
|
|
||||||
|
@ -1143,8 +1160,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
const d = leaveRoomBehaviour(roomId);
|
const d = leaveRoomBehaviour(roomId);
|
||||||
|
|
||||||
// FIXME: controller shouldn't be loading a view :(
|
// FIXME: controller shouldn't be loading a view :(
|
||||||
const Loader = sdk.getComponent("elements.Spinner");
|
const modal = Modal.createDialog(Spinner, null, 'mx_Dialog_spinner');
|
||||||
const modal = Modal.createDialog(Loader, null, 'mx_Dialog_spinner');
|
|
||||||
|
|
||||||
d.finally(() => modal.close());
|
d.finally(() => modal.close());
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
|
@ -1411,7 +1427,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
showNotificationsToast(false);
|
showNotificationsToast(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
dis.fire(Action.FocusComposer);
|
dis.fire(Action.FocusSendMessageComposer);
|
||||||
this.setState({
|
this.setState({
|
||||||
ready: true,
|
ready: true,
|
||||||
});
|
});
|
||||||
|
@ -1439,7 +1455,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
cli.on('no_consent', function(message, consentUri) {
|
cli.on('no_consent', function(message, consentUri) {
|
||||||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
|
||||||
Modal.createTrackedDialog('No Consent Dialog', '', QuestionDialog, {
|
Modal.createTrackedDialog('No Consent Dialog', '', QuestionDialog, {
|
||||||
title: _t('Terms and Conditions'),
|
title: _t('Terms and Conditions'),
|
||||||
description: <div>
|
description: <div>
|
||||||
|
@ -1548,8 +1563,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
});
|
});
|
||||||
|
|
||||||
cli.on("crypto.keySignatureUploadFailure", (failures, source, continuation) => {
|
cli.on("crypto.keySignatureUploadFailure", (failures, source, continuation) => {
|
||||||
const KeySignatureUploadFailedDialog =
|
|
||||||
sdk.getComponent('views.dialogs.KeySignatureUploadFailedDialog');
|
|
||||||
Modal.createTrackedDialog(
|
Modal.createTrackedDialog(
|
||||||
'Failed to upload key signatures',
|
'Failed to upload key signatures',
|
||||||
'Failed to upload key signatures',
|
'Failed to upload key signatures',
|
||||||
|
@ -1559,7 +1572,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
|
|
||||||
cli.on("crypto.verification.request", request => {
|
cli.on("crypto.verification.request", request => {
|
||||||
if (request.verifier) {
|
if (request.verifier) {
|
||||||
const IncomingSasDialog = sdk.getComponent("views.dialogs.IncomingSasDialog");
|
|
||||||
Modal.createTrackedDialog('Incoming Verification', '', IncomingSasDialog, {
|
Modal.createTrackedDialog('Incoming Verification', '', IncomingSasDialog, {
|
||||||
verifier: request.verifier,
|
verifier: request.verifier,
|
||||||
}, null, /* priority = */ false, /* static = */ true);
|
}, null, /* priority = */ false, /* static = */ true);
|
||||||
|
@ -1569,7 +1581,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
title: _t("Verification requested"),
|
title: _t("Verification requested"),
|
||||||
icon: "verification",
|
icon: "verification",
|
||||||
props: { request },
|
props: { request },
|
||||||
component: sdk.getComponent("toasts.VerificationRequestToast"),
|
component: VerificationRequestToast,
|
||||||
priority: 90,
|
priority: 90,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1977,21 +1989,18 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
let view = null;
|
let view = null;
|
||||||
|
|
||||||
if (this.state.view === Views.LOADING) {
|
if (this.state.view === Views.LOADING) {
|
||||||
const Spinner = sdk.getComponent('elements.Spinner');
|
|
||||||
view = (
|
view = (
|
||||||
<div className="mx_MatrixChat_splash">
|
<div className="mx_MatrixChat_splash">
|
||||||
<Spinner />
|
<Spinner />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (this.state.view === Views.COMPLETE_SECURITY) {
|
} else if (this.state.view === Views.COMPLETE_SECURITY) {
|
||||||
const CompleteSecurity = sdk.getComponent('structures.auth.CompleteSecurity');
|
|
||||||
view = (
|
view = (
|
||||||
<CompleteSecurity
|
<CompleteSecurity
|
||||||
onFinished={this.onCompleteSecurityE2eSetupFinished}
|
onFinished={this.onCompleteSecurityE2eSetupFinished}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (this.state.view === Views.E2E_SETUP) {
|
} else if (this.state.view === Views.E2E_SETUP) {
|
||||||
const E2eSetup = sdk.getComponent('structures.auth.E2eSetup');
|
|
||||||
view = (
|
view = (
|
||||||
<E2eSetup
|
<E2eSetup
|
||||||
onFinished={this.onCompleteSecurityE2eSetupFinished}
|
onFinished={this.onCompleteSecurityE2eSetupFinished}
|
||||||
|
@ -2012,7 +2021,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
* we should go through and figure out what we actually need to pass down, as well
|
* we should go through and figure out what we actually need to pass down, as well
|
||||||
* as using something like redux to avoid having a billion bits of state kicking around.
|
* as using something like redux to avoid having a billion bits of state kicking around.
|
||||||
*/
|
*/
|
||||||
const LoggedInView = sdk.getComponent('structures.LoggedInView');
|
|
||||||
view = (
|
view = (
|
||||||
<LoggedInView
|
<LoggedInView
|
||||||
{...this.props}
|
{...this.props}
|
||||||
|
@ -2020,14 +2028,12 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
ref={this.loggedInView}
|
ref={this.loggedInView}
|
||||||
matrixClient={MatrixClientPeg.get()}
|
matrixClient={MatrixClientPeg.get()}
|
||||||
onRoomCreated={this.onRoomCreated}
|
onRoomCreated={this.onRoomCreated}
|
||||||
onCloseAllSettings={this.onCloseAllSettings}
|
|
||||||
onRegistered={this.onRegistered}
|
onRegistered={this.onRegistered}
|
||||||
currentRoomId={this.state.currentRoomId}
|
currentRoomId={this.state.currentRoomId}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// we think we are logged in, but are still waiting for the /sync to complete
|
// we think we are logged in, but are still waiting for the /sync to complete
|
||||||
const Spinner = sdk.getComponent('elements.Spinner');
|
|
||||||
let errorBox;
|
let errorBox;
|
||||||
if (this.state.syncError && !isStoreError) {
|
if (this.state.syncError && !isStoreError) {
|
||||||
errorBox = <div className="mx_MatrixChat_syncError">
|
errorBox = <div className="mx_MatrixChat_syncError">
|
||||||
|
@ -2045,10 +2051,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (this.state.view === Views.WELCOME) {
|
} else if (this.state.view === Views.WELCOME) {
|
||||||
const Welcome = sdk.getComponent('auth.Welcome');
|
|
||||||
view = <Welcome />;
|
view = <Welcome />;
|
||||||
} else if (this.state.view === Views.REGISTER && SettingsStore.getValue(UIFeature.Registration)) {
|
} else if (this.state.view === Views.REGISTER && SettingsStore.getValue(UIFeature.Registration)) {
|
||||||
const Registration = sdk.getComponent('structures.auth.Registration');
|
|
||||||
const email = ThreepidInviteStore.instance.pickBestInvite()?.toEmail;
|
const email = ThreepidInviteStore.instance.pickBestInvite()?.toEmail;
|
||||||
view = (
|
view = (
|
||||||
<Registration
|
<Registration
|
||||||
|
@ -2067,7 +2071,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (this.state.view === Views.FORGOT_PASSWORD && SettingsStore.getValue(UIFeature.PasswordReset)) {
|
} else if (this.state.view === Views.FORGOT_PASSWORD && SettingsStore.getValue(UIFeature.PasswordReset)) {
|
||||||
const ForgotPassword = sdk.getComponent('structures.auth.ForgotPassword');
|
|
||||||
view = (
|
view = (
|
||||||
<ForgotPassword
|
<ForgotPassword
|
||||||
onComplete={this.onLoginClick}
|
onComplete={this.onLoginClick}
|
||||||
|
@ -2078,7 +2081,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
);
|
);
|
||||||
} else if (this.state.view === Views.LOGIN) {
|
} else if (this.state.view === Views.LOGIN) {
|
||||||
const showPasswordReset = SettingsStore.getValue(UIFeature.PasswordReset);
|
const showPasswordReset = SettingsStore.getValue(UIFeature.PasswordReset);
|
||||||
const Login = sdk.getComponent('structures.auth.Login');
|
|
||||||
view = (
|
view = (
|
||||||
<Login
|
<Login
|
||||||
isSyncing={this.state.pendingInitialSync}
|
isSyncing={this.state.pendingInitialSync}
|
||||||
|
@ -2094,7 +2096,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (this.state.view === Views.SOFT_LOGOUT) {
|
} else if (this.state.view === Views.SOFT_LOGOUT) {
|
||||||
const SoftLogout = sdk.getComponent('structures.auth.SoftLogout');
|
|
||||||
view = (
|
view = (
|
||||||
<SoftLogout
|
<SoftLogout
|
||||||
realQueryParams={this.props.realQueryParams}
|
realQueryParams={this.props.realQueryParams}
|
||||||
|
@ -2106,7 +2107,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
console.error(`Unknown view ${this.state.view}`);
|
console.error(`Unknown view ${this.state.view}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ErrorBoundary = sdk.getComponent('elements.ErrorBoundary');
|
|
||||||
return <ErrorBoundary>
|
return <ErrorBoundary>
|
||||||
{view}
|
{view}
|
||||||
</ErrorBoundary>;
|
</ErrorBoundary>;
|
||||||
|
|
|
@ -44,10 +44,14 @@ import NetworkDropdown from "../views/directory/NetworkDropdown";
|
||||||
import ScrollPanel from "./ScrollPanel";
|
import ScrollPanel from "./ScrollPanel";
|
||||||
import Spinner from "../views/elements/Spinner";
|
import Spinner from "../views/elements/Spinner";
|
||||||
import { ActionPayload } from "../../dispatcher/payloads";
|
import { ActionPayload } from "../../dispatcher/payloads";
|
||||||
|
import { getDisplayAliasForAliasSet } from "../../Rooms";
|
||||||
|
|
||||||
const MAX_NAME_LENGTH = 80;
|
const MAX_NAME_LENGTH = 80;
|
||||||
const MAX_TOPIC_LENGTH = 800;
|
const MAX_TOPIC_LENGTH = 800;
|
||||||
|
|
||||||
|
const LAST_SERVER_KEY = "mx_last_room_directory_server";
|
||||||
|
const LAST_INSTANCE_KEY = "mx_last_room_directory_instance";
|
||||||
|
|
||||||
function track(action: string) {
|
function track(action: string) {
|
||||||
Analytics.trackEvent('RoomDirectory', action);
|
Analytics.trackEvent('RoomDirectory', action);
|
||||||
}
|
}
|
||||||
|
@ -61,7 +65,7 @@ interface IState {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
protocolsLoading: boolean;
|
protocolsLoading: boolean;
|
||||||
error?: string;
|
error?: string;
|
||||||
instanceId: string | symbol;
|
instanceId: string;
|
||||||
roomServer: string;
|
roomServer: string;
|
||||||
filterString: string;
|
filterString: string;
|
||||||
selectedCommunityId?: string;
|
selectedCommunityId?: string;
|
||||||
|
@ -116,6 +120,36 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
|
||||||
} else if (!selectedCommunityId) {
|
} else if (!selectedCommunityId) {
|
||||||
MatrixClientPeg.get().getThirdpartyProtocols().then((response) => {
|
MatrixClientPeg.get().getThirdpartyProtocols().then((response) => {
|
||||||
this.protocols = response;
|
this.protocols = response;
|
||||||
|
const myHomeserver = MatrixClientPeg.getHomeserverName();
|
||||||
|
const lsRoomServer = localStorage.getItem(LAST_SERVER_KEY);
|
||||||
|
const lsInstanceId = localStorage.getItem(LAST_INSTANCE_KEY);
|
||||||
|
|
||||||
|
let roomServer = myHomeserver;
|
||||||
|
if (
|
||||||
|
SdkConfig.get().roomDirectory?.servers?.includes(lsRoomServer) ||
|
||||||
|
SettingsStore.getValue("room_directory_servers")?.includes(lsRoomServer)
|
||||||
|
) {
|
||||||
|
roomServer = lsRoomServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
let instanceId: string = null;
|
||||||
|
if (roomServer === myHomeserver && (
|
||||||
|
lsInstanceId === ALL_ROOMS ||
|
||||||
|
Object.values(this.protocols).some(p => p.instances.some(i => i.instance_id === lsInstanceId))
|
||||||
|
)) {
|
||||||
|
instanceId = lsInstanceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh the room list only if validation failed and we had to change these
|
||||||
|
if (this.state.instanceId !== instanceId || this.state.roomServer !== roomServer) {
|
||||||
|
this.setState({
|
||||||
|
protocolsLoading: false,
|
||||||
|
instanceId,
|
||||||
|
roomServer,
|
||||||
|
});
|
||||||
|
this.refreshRoomList();
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.setState({ protocolsLoading: false });
|
this.setState({ protocolsLoading: false });
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
console.warn(`error loading third party protocols: ${err}`);
|
console.warn(`error loading third party protocols: ${err}`);
|
||||||
|
@ -150,8 +184,8 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
|
||||||
publicRooms: [],
|
publicRooms: [],
|
||||||
loading: true,
|
loading: true,
|
||||||
error: null,
|
error: null,
|
||||||
instanceId: undefined,
|
instanceId: localStorage.getItem(LAST_INSTANCE_KEY),
|
||||||
roomServer: MatrixClientPeg.getHomeserverName(),
|
roomServer: localStorage.getItem(LAST_SERVER_KEY),
|
||||||
filterString: this.props.initialText || "",
|
filterString: this.props.initialText || "",
|
||||||
selectedCommunityId,
|
selectedCommunityId,
|
||||||
communityName: null,
|
communityName: null,
|
||||||
|
@ -342,7 +376,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private onOptionChange = (server: string, instanceId?: string | symbol) => {
|
private onOptionChange = (server: string, instanceId?: string) => {
|
||||||
// clear next batch so we don't try to load more rooms
|
// clear next batch so we don't try to load more rooms
|
||||||
this.nextBatch = null;
|
this.nextBatch = null;
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -360,6 +394,14 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
|
||||||
// find the five gitter ones, at which point we do not want
|
// find the five gitter ones, at which point we do not want
|
||||||
// to render all those rooms when switching back to 'all networks'.
|
// to render all those rooms when switching back to 'all networks'.
|
||||||
// Easiest to just blow away the state & re-fetch.
|
// Easiest to just blow away the state & re-fetch.
|
||||||
|
|
||||||
|
// We have to be careful here so that we don't set instanceId = "undefined"
|
||||||
|
localStorage.setItem(LAST_SERVER_KEY, server);
|
||||||
|
if (instanceId) {
|
||||||
|
localStorage.setItem(LAST_INSTANCE_KEY, instanceId);
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem(LAST_INSTANCE_KEY);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private onFillRequest = (backwards: boolean) => {
|
private onFillRequest = (backwards: boolean) => {
|
||||||
|
@ -813,5 +855,5 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
|
||||||
// Similar to matrix-react-sdk's MatrixTools.getDisplayAliasForRoom
|
// Similar to matrix-react-sdk's MatrixTools.getDisplayAliasForRoom
|
||||||
// but works with the objects we get from the public room list
|
// but works with the objects we get from the public room list
|
||||||
function getDisplayAliasForRoom(room: IRoom) {
|
function getDisplayAliasForRoom(room: IRoom) {
|
||||||
return room.canonical_alias || room.aliases?.[0] || "";
|
return getDisplayAliasForAliasSet(room.canonical_alias, room.aliases);
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,7 +131,7 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case RoomListAction.ClearSearch:
|
case RoomListAction.ClearSearch:
|
||||||
this.clearInput();
|
this.clearInput();
|
||||||
defaultDispatcher.fire(Action.FocusComposer);
|
defaultDispatcher.fire(Action.FocusSendMessageComposer);
|
||||||
break;
|
break;
|
||||||
case RoomListAction.NextRoom:
|
case RoomListAction.NextRoom:
|
||||||
case RoomListAction.PrevRoom:
|
case RoomListAction.PrevRoom:
|
||||||
|
|
|
@ -118,12 +118,12 @@ export default class RoomStatusBar extends React.PureComponent {
|
||||||
this.setState({ isResending: false });
|
this.setState({ isResending: false });
|
||||||
});
|
});
|
||||||
this.setState({ isResending: true });
|
this.setState({ isResending: true });
|
||||||
dis.fire(Action.FocusComposer);
|
dis.fire(Action.FocusSendMessageComposer);
|
||||||
};
|
};
|
||||||
|
|
||||||
_onCancelAllClick = () => {
|
_onCancelAllClick = () => {
|
||||||
Resend.cancelUnsentEvents(this.props.room);
|
Resend.cancelUnsentEvents(this.props.room);
|
||||||
dis.fire(Action.FocusComposer);
|
dis.fire(Action.FocusSendMessageComposer);
|
||||||
};
|
};
|
||||||
|
|
||||||
_onRoomLocalEchoUpdated = (event, room, oldEventId, oldStatus) => {
|
_onRoomLocalEchoUpdated = (event, room, oldEventId, oldStatus) => {
|
||||||
|
|
|
@ -34,7 +34,6 @@ import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks';
|
||||||
import ResizeNotifier from '../../utils/ResizeNotifier';
|
import ResizeNotifier from '../../utils/ResizeNotifier';
|
||||||
import ContentMessages from '../../ContentMessages';
|
import ContentMessages from '../../ContentMessages';
|
||||||
import Modal from '../../Modal';
|
import Modal from '../../Modal';
|
||||||
import * as sdk from '../../index';
|
|
||||||
import CallHandler, { PlaceCallType } from '../../CallHandler';
|
import CallHandler, { PlaceCallType } from '../../CallHandler';
|
||||||
import dis from '../../dispatcher/dispatcher';
|
import dis from '../../dispatcher/dispatcher';
|
||||||
import * as Rooms from '../../Rooms';
|
import * as Rooms from '../../Rooms';
|
||||||
|
@ -82,6 +81,14 @@ import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
import UIStore from "../../stores/UIStore";
|
import UIStore from "../../stores/UIStore";
|
||||||
import EditorStateTransfer from "../../utils/EditorStateTransfer";
|
import EditorStateTransfer from "../../utils/EditorStateTransfer";
|
||||||
import { throttle } from "lodash";
|
import { throttle } from "lodash";
|
||||||
|
import ErrorDialog from '../views/dialogs/ErrorDialog';
|
||||||
|
import SearchResultTile from '../views/rooms/SearchResultTile';
|
||||||
|
import Spinner from "../views/elements/Spinner";
|
||||||
|
import UploadBar from './UploadBar';
|
||||||
|
import RoomStatusBar from "./RoomStatusBar";
|
||||||
|
import MessageComposer from '../views/rooms/MessageComposer';
|
||||||
|
import JumpToBottomButton from "../views/rooms/JumpToBottomButton";
|
||||||
|
import TopUnreadMessagesBar from "../views/rooms/TopUnreadMessagesBar";
|
||||||
|
|
||||||
const DEBUG = false;
|
const DEBUG = false;
|
||||||
let debuglog = function(msg: string) {};
|
let debuglog = function(msg: string) {};
|
||||||
|
@ -811,17 +818,16 @@ export default class RoomView extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
case Action.ComposerInsert: {
|
case Action.ComposerInsert: {
|
||||||
// re-dispatch to the correct composer
|
// re-dispatch to the correct composer
|
||||||
if (this.state.editState) {
|
dis.dispatch({
|
||||||
dis.dispatch({
|
...payload,
|
||||||
...payload,
|
action: this.state.editState ? "edit_composer_insert" : "send_composer_insert",
|
||||||
action: "edit_composer_insert",
|
});
|
||||||
});
|
break;
|
||||||
} else {
|
}
|
||||||
dis.dispatch({
|
|
||||||
...payload,
|
case Action.FocusAComposer: {
|
||||||
action: "send_composer_insert",
|
// re-dispatch to the correct composer
|
||||||
});
|
dis.fire(this.state.editState ? Action.FocusEditMessageComposer : Action.FocusSendMessageComposer);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1239,7 +1245,7 @@ export default class RoomView extends React.Component<IProps, IState> {
|
||||||
ContentMessages.sharedInstance().sendContentListToRoom(
|
ContentMessages.sharedInstance().sendContentListToRoom(
|
||||||
ev.dataTransfer.files, this.state.room.roomId, this.context,
|
ev.dataTransfer.files, this.state.room.roomId, this.context,
|
||||||
);
|
);
|
||||||
dis.fire(Action.FocusComposer);
|
dis.fire(Action.FocusSendMessageComposer);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
draggingFile: false,
|
draggingFile: false,
|
||||||
|
@ -1328,7 +1334,6 @@ export default class RoomView extends React.Component<IProps, IState> {
|
||||||
searchResults: results,
|
searchResults: results,
|
||||||
});
|
});
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
||||||
console.error("Search failed", error);
|
console.error("Search failed", error);
|
||||||
Modal.createTrackedDialog('Search failed', '', ErrorDialog, {
|
Modal.createTrackedDialog('Search failed', '', ErrorDialog, {
|
||||||
title: _t("Search failed"),
|
title: _t("Search failed"),
|
||||||
|
@ -1344,9 +1349,6 @@ export default class RoomView extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private getSearchResultTiles() {
|
private getSearchResultTiles() {
|
||||||
const SearchResultTile = sdk.getComponent('rooms.SearchResultTile');
|
|
||||||
const Spinner = sdk.getComponent("elements.Spinner");
|
|
||||||
|
|
||||||
// XXX: todo: merge overlapping results somehow?
|
// XXX: todo: merge overlapping results somehow?
|
||||||
// XXX: why doesn't searching on name work?
|
// XXX: why doesn't searching on name work?
|
||||||
|
|
||||||
|
@ -1466,7 +1468,6 @@ export default class RoomView extends React.Component<IProps, IState> {
|
||||||
console.error("Failed to reject invite: %s", error);
|
console.error("Failed to reject invite: %s", error);
|
||||||
|
|
||||||
const msg = error.message ? error.message : JSON.stringify(error);
|
const msg = error.message ? error.message : JSON.stringify(error);
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
||||||
Modal.createTrackedDialog('Failed to reject invite', '', ErrorDialog, {
|
Modal.createTrackedDialog('Failed to reject invite', '', ErrorDialog, {
|
||||||
title: _t("Failed to reject invite"),
|
title: _t("Failed to reject invite"),
|
||||||
description: msg,
|
description: msg,
|
||||||
|
@ -1500,7 +1501,6 @@ export default class RoomView extends React.Component<IProps, IState> {
|
||||||
console.error("Failed to reject invite: %s", error);
|
console.error("Failed to reject invite: %s", error);
|
||||||
|
|
||||||
const msg = error.message ? error.message : JSON.stringify(error);
|
const msg = error.message ? error.message : JSON.stringify(error);
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
||||||
Modal.createTrackedDialog('Failed to reject invite', '', ErrorDialog, {
|
Modal.createTrackedDialog('Failed to reject invite', '', ErrorDialog, {
|
||||||
title: _t("Failed to reject invite"),
|
title: _t("Failed to reject invite"),
|
||||||
description: msg,
|
description: msg,
|
||||||
|
@ -1547,7 +1547,7 @@ export default class RoomView extends React.Component<IProps, IState> {
|
||||||
} else {
|
} else {
|
||||||
// Otherwise we have to jump manually
|
// Otherwise we have to jump manually
|
||||||
this.messagePanel.jumpToLiveTimeline();
|
this.messagePanel.jumpToLiveTimeline();
|
||||||
dis.fire(Action.FocusComposer);
|
dis.fire(Action.FocusSendMessageComposer);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1834,10 +1834,8 @@ export default class RoomView extends React.Component<IProps, IState> {
|
||||||
let isStatusAreaExpanded = true;
|
let isStatusAreaExpanded = true;
|
||||||
|
|
||||||
if (ContentMessages.sharedInstance().getCurrentUploads().length > 0) {
|
if (ContentMessages.sharedInstance().getCurrentUploads().length > 0) {
|
||||||
const UploadBar = sdk.getComponent('structures.UploadBar');
|
|
||||||
statusBar = <UploadBar room={this.state.room} />;
|
statusBar = <UploadBar room={this.state.room} />;
|
||||||
} else if (!this.state.searchResults) {
|
} else if (!this.state.searchResults) {
|
||||||
const RoomStatusBar = sdk.getComponent('structures.RoomStatusBar');
|
|
||||||
isStatusAreaExpanded = this.state.statusBarVisible;
|
isStatusAreaExpanded = this.state.statusBarVisible;
|
||||||
statusBar = <RoomStatusBar
|
statusBar = <RoomStatusBar
|
||||||
room={this.state.room}
|
room={this.state.room}
|
||||||
|
@ -1943,12 +1941,9 @@ export default class RoomView extends React.Component<IProps, IState> {
|
||||||
myMembership === 'join' && !this.state.searchResults
|
myMembership === 'join' && !this.state.searchResults
|
||||||
);
|
);
|
||||||
if (canSpeak) {
|
if (canSpeak) {
|
||||||
const MessageComposer = sdk.getComponent('rooms.MessageComposer');
|
|
||||||
messageComposer =
|
messageComposer =
|
||||||
<MessageComposer
|
<MessageComposer
|
||||||
room={this.state.room}
|
room={this.state.room}
|
||||||
callState={this.state.callState}
|
|
||||||
showApps={this.state.showApps}
|
|
||||||
e2eStatus={this.state.e2eStatus}
|
e2eStatus={this.state.e2eStatus}
|
||||||
resizeNotifier={this.props.resizeNotifier}
|
resizeNotifier={this.props.resizeNotifier}
|
||||||
replyToEvent={this.state.replyToEvent}
|
replyToEvent={this.state.replyToEvent}
|
||||||
|
@ -2034,7 +2029,6 @@ export default class RoomView extends React.Component<IProps, IState> {
|
||||||
let topUnreadMessagesBar = null;
|
let topUnreadMessagesBar = null;
|
||||||
// Do not show TopUnreadMessagesBar if we have search results showing, it makes no sense
|
// Do not show TopUnreadMessagesBar if we have search results showing, it makes no sense
|
||||||
if (this.state.showTopUnreadMessagesBar && !this.state.searchResults) {
|
if (this.state.showTopUnreadMessagesBar && !this.state.searchResults) {
|
||||||
const TopUnreadMessagesBar = sdk.getComponent('rooms.TopUnreadMessagesBar');
|
|
||||||
topUnreadMessagesBar = (
|
topUnreadMessagesBar = (
|
||||||
<TopUnreadMessagesBar onScrollUpClick={this.jumpToReadMarker} onCloseClick={this.forgetReadMarker} />
|
<TopUnreadMessagesBar onScrollUpClick={this.jumpToReadMarker} onCloseClick={this.forgetReadMarker} />
|
||||||
);
|
);
|
||||||
|
@ -2042,7 +2036,6 @@ export default class RoomView extends React.Component<IProps, IState> {
|
||||||
let jumpToBottom;
|
let jumpToBottom;
|
||||||
// Do not show JumpToBottomButton if we have search results showing, it makes no sense
|
// Do not show JumpToBottomButton if we have search results showing, it makes no sense
|
||||||
if (!this.state.atEndOfLiveTimeline && !this.state.searchResults) {
|
if (!this.state.atEndOfLiveTimeline && !this.state.searchResults) {
|
||||||
const JumpToBottomButton = sdk.getComponent('rooms.JumpToBottomButton');
|
|
||||||
jumpToBottom = (<JumpToBottomButton
|
jumpToBottom = (<JumpToBottomButton
|
||||||
highlight={this.state.room.getUnreadNotificationCount(NotificationCountType.Highlight) > 0}
|
highlight={this.state.room.getUnreadNotificationCount(NotificationCountType.Highlight) > 0}
|
||||||
numUnreadMessages={this.state.numUnreadMessages}
|
numUnreadMessages={this.state.numUnreadMessages}
|
||||||
|
|
|
@ -42,6 +42,7 @@ import { useStateToggle } from "../../hooks/useStateToggle";
|
||||||
import { getChildOrder } from "../../stores/SpaceStore";
|
import { getChildOrder } from "../../stores/SpaceStore";
|
||||||
import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton";
|
import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton";
|
||||||
import { linkifyElement } from "../../HtmlUtils";
|
import { linkifyElement } from "../../HtmlUtils";
|
||||||
|
import { getDisplayAliasForAliasSet } from "../../Rooms";
|
||||||
|
|
||||||
interface IHierarchyProps {
|
interface IHierarchyProps {
|
||||||
space: Room;
|
space: Room;
|
||||||
|
@ -666,5 +667,5 @@ export default SpaceRoomDirectory;
|
||||||
// Similar to matrix-react-sdk's MatrixTools.getDisplayAliasForRoom
|
// Similar to matrix-react-sdk's MatrixTools.getDisplayAliasForRoom
|
||||||
// but works with the objects we get from the public room list
|
// but works with the objects we get from the public room list
|
||||||
function getDisplayAliasForRoom(room: ISpaceSummaryRoom) {
|
function getDisplayAliasForRoom(room: ISpaceSummaryRoom) {
|
||||||
return room.canonical_alias || (room.aliases ? room.aliases[0] : "");
|
return getDisplayAliasForAliasSet(room.canonical_alias, room.aliases);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,9 @@ limitations under the License.
|
||||||
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { _t } from '../../languageHandler';
|
import { _t } from '../../languageHandler';
|
||||||
import * as sdk from "../../index";
|
|
||||||
import AutoHideScrollbar from './AutoHideScrollbar';
|
import AutoHideScrollbar from './AutoHideScrollbar';
|
||||||
import { replaceableComponent } from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
|
import AccessibleButton from "../views/elements/AccessibleButton";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a tab for the TabbedView.
|
* Represents a tab for the TabbedView.
|
||||||
|
@ -82,8 +82,6 @@ export default class TabbedView extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _renderTabLabel(tab: Tab) {
|
private _renderTabLabel(tab: Tab) {
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
|
||||||
|
|
||||||
let classes = "mx_TabbedView_tabLabel ";
|
let classes = "mx_TabbedView_tabLabel ";
|
||||||
|
|
||||||
const idx = this.props.tabs.indexOf(tab);
|
const idx = this.props.tabs.indexOf(tab);
|
||||||
|
|
|
@ -32,7 +32,6 @@ import RoomContext from "../../contexts/RoomContext";
|
||||||
import UserActivity from "../../UserActivity";
|
import UserActivity from "../../UserActivity";
|
||||||
import Modal from "../../Modal";
|
import Modal from "../../Modal";
|
||||||
import dis from "../../dispatcher/dispatcher";
|
import dis from "../../dispatcher/dispatcher";
|
||||||
import * as sdk from "../../index";
|
|
||||||
import { Key } from '../../Keyboard';
|
import { Key } from '../../Keyboard';
|
||||||
import Timer from '../../utils/Timer';
|
import Timer from '../../utils/Timer';
|
||||||
import shouldHideEvent from '../../shouldHideEvent';
|
import shouldHideEvent from '../../shouldHideEvent';
|
||||||
|
@ -47,6 +46,7 @@ import ResizeNotifier from "../../utils/ResizeNotifier";
|
||||||
import { RoomPermalinkCreator } from "../../utils/permalinks/Permalinks";
|
import { RoomPermalinkCreator } from "../../utils/permalinks/Permalinks";
|
||||||
import Spinner from "../views/elements/Spinner";
|
import Spinner from "../views/elements/Spinner";
|
||||||
import EditorStateTransfer from '../../utils/EditorStateTransfer';
|
import EditorStateTransfer from '../../utils/EditorStateTransfer';
|
||||||
|
import ErrorDialog from '../views/dialogs/ErrorDialog';
|
||||||
|
|
||||||
const PAGINATE_SIZE = 20;
|
const PAGINATE_SIZE = 20;
|
||||||
const INITIAL_SIZE = 20;
|
const INITIAL_SIZE = 20;
|
||||||
|
@ -1096,7 +1096,6 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
console.error(
|
console.error(
|
||||||
`Error loading timeline panel at ${eventId}: ${error}`,
|
`Error loading timeline panel at ${eventId}: ${error}`,
|
||||||
);
|
);
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
||||||
|
|
||||||
let onFinished;
|
let onFinished;
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ enum Phase {
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
serverConfig: ValidatedServerConfig;
|
serverConfig: ValidatedServerConfig;
|
||||||
onServerConfigChange: () => void;
|
onServerConfigChange: (serverConfig: ValidatedServerConfig) => void;
|
||||||
onLoginClick?: () => void;
|
onLoginClick?: () => void;
|
||||||
onComplete: () => void;
|
onComplete: () => void;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ import React, { ReactNode } from 'react';
|
||||||
import { MatrixError } from "matrix-js-sdk/src/http-api";
|
import { MatrixError } from "matrix-js-sdk/src/http-api";
|
||||||
|
|
||||||
import { _t, _td } from '../../../languageHandler';
|
import { _t, _td } from '../../../languageHandler';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import Login, { ISSOFlow, LoginFlow } from '../../../Login';
|
import Login, { ISSOFlow, LoginFlow } from '../../../Login';
|
||||||
import SdkConfig from '../../../SdkConfig';
|
import SdkConfig from '../../../SdkConfig';
|
||||||
import { messageForResourceLimitError } from '../../../utils/ErrorUtils';
|
import { messageForResourceLimitError } from '../../../utils/ErrorUtils';
|
||||||
|
@ -36,6 +35,8 @@ import Spinner from "../../views/elements/Spinner";
|
||||||
import SSOButtons from "../../views/elements/SSOButtons";
|
import SSOButtons from "../../views/elements/SSOButtons";
|
||||||
import ServerPicker from "../../views/elements/ServerPicker";
|
import ServerPicker from "../../views/elements/ServerPicker";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import AuthBody from "../../views/auth/AuthBody";
|
||||||
|
import AuthHeader from "../../views/auth/AuthHeader";
|
||||||
|
|
||||||
// These are used in several places, and come from the js-sdk's autodiscovery
|
// These are used in several places, and come from the js-sdk's autodiscovery
|
||||||
// stuff. We define them here so that they'll be picked up by i18n.
|
// stuff. We define them here so that they'll be picked up by i18n.
|
||||||
|
@ -541,8 +542,6 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const AuthHeader = sdk.getComponent("auth.AuthHeader");
|
|
||||||
const AuthBody = sdk.getComponent("auth.AuthBody");
|
|
||||||
const loader = this.isBusy() && !this.state.busyLoggingIn ?
|
const loader = this.isBusy() && !this.state.busyLoggingIn ?
|
||||||
<div className="mx_Login_loader"><Spinner /></div> : null;
|
<div className="mx_Login_loader"><Spinner /></div> : null;
|
||||||
|
|
||||||
|
|
|
@ -18,19 +18,24 @@ import { createClient } from 'matrix-js-sdk/src/matrix';
|
||||||
import React, { ReactNode } from 'react';
|
import React, { ReactNode } from 'react';
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
|
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import { _t, _td } from '../../../languageHandler';
|
import { _t, _td } from '../../../languageHandler';
|
||||||
import { messageForResourceLimitError } from '../../../utils/ErrorUtils';
|
import { messageForResourceLimitError } from '../../../utils/ErrorUtils';
|
||||||
import AutoDiscoveryUtils, { ValidatedServerConfig } from "../../../utils/AutoDiscoveryUtils";
|
import AutoDiscoveryUtils, { ValidatedServerConfig } from "../../../utils/AutoDiscoveryUtils";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import * as Lifecycle from '../../../Lifecycle';
|
import * as Lifecycle from '../../../Lifecycle';
|
||||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
import { IMatrixClientCreds, MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
import AuthPage from "../../views/auth/AuthPage";
|
import AuthPage from "../../views/auth/AuthPage";
|
||||||
import Login, { ISSOFlow } from "../../../Login";
|
import Login, { ISSOFlow } from "../../../Login";
|
||||||
import dis from "../../../dispatcher/dispatcher";
|
import dis from "../../../dispatcher/dispatcher";
|
||||||
import SSOButtons from "../../views/elements/SSOButtons";
|
import SSOButtons from "../../views/elements/SSOButtons";
|
||||||
import ServerPicker from '../../views/elements/ServerPicker';
|
import ServerPicker from '../../views/elements/ServerPicker';
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import RegistrationForm from '../../views/auth/RegistrationForm';
|
||||||
|
import AccessibleButton from '../../views/elements/AccessibleButton';
|
||||||
|
import AuthBody from "../../views/auth/AuthBody";
|
||||||
|
import AuthHeader from "../../views/auth/AuthHeader";
|
||||||
|
import InteractiveAuth from "../InteractiveAuth";
|
||||||
|
import Spinner from "../../views/elements/Spinner";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
serverConfig: ValidatedServerConfig;
|
serverConfig: ValidatedServerConfig;
|
||||||
|
@ -47,13 +52,7 @@ interface IProps {
|
||||||
// - The user's password, if available and applicable (may be cached in memory
|
// - The user's password, if available and applicable (may be cached in memory
|
||||||
// for a short time so the user is not required to re-enter their password
|
// for a short time so the user is not required to re-enter their password
|
||||||
// for operations like uploading cross-signing keys).
|
// for operations like uploading cross-signing keys).
|
||||||
onLoggedIn(params: {
|
onLoggedIn(params: IMatrixClientCreds, password: string): void;
|
||||||
userId: string;
|
|
||||||
deviceId: string;
|
|
||||||
homeserverUrl: string;
|
|
||||||
identityServerUrl?: string;
|
|
||||||
accessToken: string;
|
|
||||||
}, password: string): void;
|
|
||||||
makeRegistrationUrl(params: {
|
makeRegistrationUrl(params: {
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
client_secret: string;
|
client_secret: string;
|
||||||
|
@ -246,7 +245,7 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onFormSubmit = formVals => {
|
private onFormSubmit = async (formVals): Promise<void> => {
|
||||||
this.setState({
|
this.setState({
|
||||||
errorText: "",
|
errorText: "",
|
||||||
busy: true,
|
busy: true,
|
||||||
|
@ -442,10 +441,6 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private renderRegisterComponent() {
|
private renderRegisterComponent() {
|
||||||
const InteractiveAuth = sdk.getComponent('structures.InteractiveAuth');
|
|
||||||
const Spinner = sdk.getComponent('elements.Spinner');
|
|
||||||
const RegistrationForm = sdk.getComponent('auth.RegistrationForm');
|
|
||||||
|
|
||||||
if (this.state.matrixClient && this.state.doingUIAuth) {
|
if (this.state.matrixClient && this.state.doingUIAuth) {
|
||||||
return <InteractiveAuth
|
return <InteractiveAuth
|
||||||
matrixClient={this.state.matrixClient}
|
matrixClient={this.state.matrixClient}
|
||||||
|
@ -516,10 +511,6 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const AuthHeader = sdk.getComponent('auth.AuthHeader');
|
|
||||||
const AuthBody = sdk.getComponent("auth.AuthBody");
|
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
|
||||||
|
|
||||||
let errorText;
|
let errorText;
|
||||||
const err = this.state.errorText;
|
const err = this.state.errorText;
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
@ -21,7 +21,7 @@ import Modal from '../../../Modal';
|
||||||
import VerificationRequestDialog from '../../views/dialogs/VerificationRequestDialog';
|
import VerificationRequestDialog from '../../views/dialogs/VerificationRequestDialog';
|
||||||
import { SetupEncryptionStore, Phase } from '../../../stores/SetupEncryptionStore';
|
import { SetupEncryptionStore, Phase } from '../../../stores/SetupEncryptionStore';
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { ISecretStorageKeyInfo } from 'matrix-js-sdk';
|
import { ISecretStorageKeyInfo } from 'matrix-js-sdk/src/crypto/api';
|
||||||
import EncryptionPanel from "../../views/right_panel/EncryptionPanel";
|
import EncryptionPanel from "../../views/right_panel/EncryptionPanel";
|
||||||
import AccessibleButton from '../../views/elements/AccessibleButton';
|
import AccessibleButton from '../../views/elements/AccessibleButton';
|
||||||
import Spinner from '../../views/elements/Spinner';
|
import Spinner from '../../views/elements/Spinner';
|
||||||
|
|
|
@ -16,7 +16,6 @@ limitations under the License.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import dis from '../../../dispatcher/dispatcher';
|
import dis from '../../../dispatcher/dispatcher';
|
||||||
import * as Lifecycle from '../../../Lifecycle';
|
import * as Lifecycle from '../../../Lifecycle';
|
||||||
import Modal from '../../../Modal';
|
import Modal from '../../../Modal';
|
||||||
|
@ -26,6 +25,12 @@ import AuthPage from "../../views/auth/AuthPage";
|
||||||
import { SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY } from "../../../BasePlatform";
|
import { SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY } from "../../../BasePlatform";
|
||||||
import SSOButtons from "../../views/elements/SSOButtons";
|
import SSOButtons from "../../views/elements/SSOButtons";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import ConfirmWipeDeviceDialog from '../../views/dialogs/ConfirmWipeDeviceDialog';
|
||||||
|
import Field from '../../views/elements/Field';
|
||||||
|
import AccessibleButton from '../../views/elements/AccessibleButton';
|
||||||
|
import Spinner from "../../views/elements/Spinner";
|
||||||
|
import AuthHeader from "../../views/auth/AuthHeader";
|
||||||
|
import AuthBody from "../../views/auth/AuthBody";
|
||||||
|
|
||||||
const LOGIN_VIEW = {
|
const LOGIN_VIEW = {
|
||||||
LOADING: 1,
|
LOADING: 1,
|
||||||
|
@ -94,7 +99,6 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
onClearAll = () => {
|
onClearAll = () => {
|
||||||
const ConfirmWipeDeviceDialog = sdk.getComponent('dialogs.ConfirmWipeDeviceDialog');
|
|
||||||
Modal.createTrackedDialog('Clear Data', 'Soft Logout', ConfirmWipeDeviceDialog, {
|
Modal.createTrackedDialog('Clear Data', 'Soft Logout', ConfirmWipeDeviceDialog, {
|
||||||
onFinished: (wipeData) => {
|
onFinished: (wipeData) => {
|
||||||
if (!wipeData) return;
|
if (!wipeData) return;
|
||||||
|
@ -202,7 +206,6 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
private renderSignInSection() {
|
private renderSignInSection() {
|
||||||
if (this.state.loginView === LOGIN_VIEW.LOADING) {
|
if (this.state.loginView === LOGIN_VIEW.LOADING) {
|
||||||
const Spinner = sdk.getComponent("elements.Spinner");
|
|
||||||
return <Spinner />;
|
return <Spinner />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,9 +217,6 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.loginView === LOGIN_VIEW.PASSWORD) {
|
if (this.state.loginView === LOGIN_VIEW.PASSWORD) {
|
||||||
const Field = sdk.getComponent("elements.Field");
|
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
|
||||||
|
|
||||||
let error = null;
|
let error = null;
|
||||||
if (this.state.errorText) {
|
if (this.state.errorText) {
|
||||||
error = <span className='mx_Login_error'>{this.state.errorText}</span>;
|
error = <span className='mx_Login_error'>{this.state.errorText}</span>;
|
||||||
|
@ -286,10 +286,6 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const AuthHeader = sdk.getComponent("auth.AuthHeader");
|
|
||||||
const AuthBody = sdk.getComponent("auth.AuthBody");
|
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthPage>
|
<AuthPage>
|
||||||
<AuthHeader />
|
<AuthHeader />
|
||||||
|
|
|
@ -18,7 +18,6 @@ import React, { ChangeEvent, createRef, FormEvent, MouseEvent } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
|
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import AccessibleButton from "../elements/AccessibleButton";
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
|
@ -26,6 +25,8 @@ import Spinner from "../elements/Spinner";
|
||||||
import CountlyAnalytics from "../../../CountlyAnalytics";
|
import CountlyAnalytics from "../../../CountlyAnalytics";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { LocalisedPolicy, Policies } from '../../../Terms';
|
import { LocalisedPolicy, Policies } from '../../../Terms';
|
||||||
|
import Field from '../elements/Field';
|
||||||
|
import CaptchaForm from "./CaptchaForm";
|
||||||
|
|
||||||
/* This file contains a collection of components which are used by the
|
/* This file contains a collection of components which are used by the
|
||||||
* InteractiveAuth to prompt the user to enter the information needed
|
* InteractiveAuth to prompt the user to enter the information needed
|
||||||
|
@ -164,8 +165,7 @@ export class PasswordAuthEntry extends React.Component<IAuthEntryProps, IPasswor
|
||||||
|
|
||||||
let submitButtonOrSpinner;
|
let submitButtonOrSpinner;
|
||||||
if (this.props.busy) {
|
if (this.props.busy) {
|
||||||
const Loader = sdk.getComponent("elements.Spinner");
|
submitButtonOrSpinner = <Spinner />;
|
||||||
submitButtonOrSpinner = <Loader />;
|
|
||||||
} else {
|
} else {
|
||||||
submitButtonOrSpinner = (
|
submitButtonOrSpinner = (
|
||||||
<input type="submit"
|
<input type="submit"
|
||||||
|
@ -185,8 +185,6 @@ export class PasswordAuthEntry extends React.Component<IAuthEntryProps, IPasswor
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Field = sdk.getComponent('elements.Field');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>{ _t("Confirm your identity by entering your account password below.") }</p>
|
<p>{ _t("Confirm your identity by entering your account password below.") }</p>
|
||||||
|
@ -236,13 +234,11 @@ export class RecaptchaAuthEntry extends React.Component<IRecaptchaAuthEntryProps
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.props.busy) {
|
if (this.props.busy) {
|
||||||
const Loader = sdk.getComponent("elements.Spinner");
|
return <Spinner />;
|
||||||
return <Loader />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let errorText = this.props.errorText;
|
let errorText = this.props.errorText;
|
||||||
|
|
||||||
const CaptchaForm = sdk.getComponent("views.auth.CaptchaForm");
|
|
||||||
let sitePublicKey;
|
let sitePublicKey;
|
||||||
if (!this.props.stageParams || !this.props.stageParams.public_key) {
|
if (!this.props.stageParams || !this.props.stageParams.public_key) {
|
||||||
errorText = _t(
|
errorText = _t(
|
||||||
|
@ -390,8 +386,7 @@ export class TermsAuthEntry extends React.Component<ITermsAuthEntryProps, ITerms
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.props.busy) {
|
if (this.props.busy) {
|
||||||
const Loader = sdk.getComponent("elements.Spinner");
|
return <Spinner />;
|
||||||
return <Loader />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkboxes = [];
|
const checkboxes = [];
|
||||||
|
@ -590,8 +585,7 @@ export class MsisdnAuthEntry extends React.Component<IMsisdnAuthEntryProps, IMsi
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.state.requestingToken) {
|
if (this.state.requestingToken) {
|
||||||
const Loader = sdk.getComponent("elements.Spinner");
|
return <Spinner />;
|
||||||
return <Loader />;
|
|
||||||
} else {
|
} else {
|
||||||
const enableSubmit = Boolean(this.state.token);
|
const enableSubmit = Boolean(this.state.token);
|
||||||
const submitClasses = classNames({
|
const submitClasses = classNames({
|
||||||
|
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import * as Email from '../../../email';
|
import * as Email from '../../../email';
|
||||||
import { looksValid as phoneNumberLooksValid } from '../../../phonenumber';
|
import { looksValid as phoneNumberLooksValid } from '../../../phonenumber';
|
||||||
import Modal from '../../../Modal';
|
import Modal from '../../../Modal';
|
||||||
|
@ -31,6 +30,7 @@ import CountlyAnalytics from "../../../CountlyAnalytics";
|
||||||
import Field from '../elements/Field';
|
import Field from '../elements/Field';
|
||||||
import RegistrationEmailPromptDialog from '../dialogs/RegistrationEmailPromptDialog';
|
import RegistrationEmailPromptDialog from '../dialogs/RegistrationEmailPromptDialog';
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import CountryDropdown from "./CountryDropdown";
|
||||||
|
|
||||||
enum RegistrationField {
|
enum RegistrationField {
|
||||||
Email = "field_email",
|
Email = "field_email",
|
||||||
|
@ -471,7 +471,6 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
||||||
if (!this.showPhoneNumber()) {
|
if (!this.showPhoneNumber()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const CountryDropdown = sdk.getComponent('views.auth.CountryDropdown');
|
|
||||||
const phoneLabel = this.authStepIsRequired('m.login.msisdn') ?
|
const phoneLabel = this.authStepIsRequired('m.login.msisdn') ?
|
||||||
_t("Phone") :
|
_t("Phone") :
|
||||||
_t("Phone (optional)");
|
_t("Phone (optional)");
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
|
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
|
||||||
Copyright 2015, 2016, 2018, 2019, 2021 The Matrix.org Foundation C.I.C.
|
Copyright 2015 - 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -16,12 +16,11 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import { EventStatus, MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
||||||
import { EventStatus } from 'matrix-js-sdk/src/models/event';
|
import { EventType, RelationType } from "matrix-js-sdk/src/@types/event";
|
||||||
|
|
||||||
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
||||||
import dis from '../../../dispatcher/dispatcher';
|
import dis from '../../../dispatcher/dispatcher';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import Modal from '../../../Modal';
|
import Modal from '../../../Modal';
|
||||||
import Resend from '../../../Resend';
|
import Resend from '../../../Resend';
|
||||||
|
@ -29,53 +28,65 @@ import SettingsStore from '../../../settings/SettingsStore';
|
||||||
import { isUrlPermitted } from '../../../HtmlUtils';
|
import { isUrlPermitted } from '../../../HtmlUtils';
|
||||||
import { isContentActionable } from '../../../utils/EventUtils';
|
import { isContentActionable } from '../../../utils/EventUtils';
|
||||||
import IconizedContextMenu, { IconizedContextMenuOption, IconizedContextMenuOptionList } from './IconizedContextMenu';
|
import IconizedContextMenu, { IconizedContextMenuOption, IconizedContextMenuOptionList } from './IconizedContextMenu';
|
||||||
import { EventType } from "matrix-js-sdk/src/@types/event";
|
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { ReadPinsEventId } from "../right_panel/PinnedMessagesCard";
|
import { ReadPinsEventId } from "../right_panel/PinnedMessagesCard";
|
||||||
import ForwardDialog from "../dialogs/ForwardDialog";
|
import ForwardDialog from "../dialogs/ForwardDialog";
|
||||||
import { Action } from "../../../dispatcher/actions";
|
import { Action } from "../../../dispatcher/actions";
|
||||||
|
import ReportEventDialog from '../dialogs/ReportEventDialog';
|
||||||
|
import ViewSource from '../../structures/ViewSource';
|
||||||
|
import ConfirmRedactDialog from '../dialogs/ConfirmRedactDialog';
|
||||||
|
import ErrorDialog from '../dialogs/ErrorDialog';
|
||||||
|
import ShareDialog from '../dialogs/ShareDialog';
|
||||||
|
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
|
||||||
|
|
||||||
export function canCancel(eventStatus) {
|
export function canCancel(eventStatus: EventStatus): boolean {
|
||||||
return eventStatus === EventStatus.QUEUED || eventStatus === EventStatus.NOT_SENT;
|
return eventStatus === EventStatus.QUEUED || eventStatus === EventStatus.NOT_SENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IEventTileOps {
|
||||||
|
isWidgetHidden(): boolean;
|
||||||
|
unhideWidget(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
/* the MatrixEvent associated with the context menu */
|
||||||
|
mxEvent: MatrixEvent;
|
||||||
|
/* an optional EventTileOps implementation that can be used to unhide preview widgets */
|
||||||
|
eventTileOps?: IEventTileOps;
|
||||||
|
permalinkCreator?: RoomPermalinkCreator;
|
||||||
|
/* an optional function to be called when the user clicks collapse thread, if not provided hide button */
|
||||||
|
collapseReplyThread?(): void;
|
||||||
|
/* callback called when the menu is dismissed */
|
||||||
|
onFinished(): void;
|
||||||
|
/* if the menu is inside a dialog, we sometimes need to close that dialog after click (forwarding) */
|
||||||
|
onCloseDialog?(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
canRedact: boolean;
|
||||||
|
canPin: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
@replaceableComponent("views.context_menus.MessageContextMenu")
|
@replaceableComponent("views.context_menus.MessageContextMenu")
|
||||||
export default class MessageContextMenu extends React.Component {
|
export default class MessageContextMenu extends React.Component<IProps, IState> {
|
||||||
static propTypes = {
|
|
||||||
/* the MatrixEvent associated with the context menu */
|
|
||||||
mxEvent: PropTypes.object.isRequired,
|
|
||||||
|
|
||||||
/* an optional EventTileOps implementation that can be used to unhide preview widgets */
|
|
||||||
eventTileOps: PropTypes.object,
|
|
||||||
|
|
||||||
/* an optional function to be called when the user clicks collapse thread, if not provided hide button */
|
|
||||||
collapseReplyThread: PropTypes.func,
|
|
||||||
|
|
||||||
/* callback called when the menu is dismissed */
|
|
||||||
onFinished: PropTypes.func,
|
|
||||||
|
|
||||||
/* if the menu is inside a dialog, we sometimes need to close that dialog after click (forwarding) */
|
|
||||||
onCloseDialog: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
canRedact: false,
|
canRedact: false,
|
||||||
canPin: false,
|
canPin: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
MatrixClientPeg.get().on('RoomMember.powerLevel', this._checkPermissions);
|
MatrixClientPeg.get().on('RoomMember.powerLevel', this.checkPermissions);
|
||||||
this._checkPermissions();
|
this.checkPermissions();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
if (cli) {
|
if (cli) {
|
||||||
cli.removeListener('RoomMember.powerLevel', this._checkPermissions);
|
cli.removeListener('RoomMember.powerLevel', this.checkPermissions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_checkPermissions = () => {
|
private checkPermissions = (): void => {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
const room = cli.getRoom(this.props.mxEvent.getRoomId());
|
const room = cli.getRoom(this.props.mxEvent.getRoomId());
|
||||||
|
|
||||||
|
@ -93,7 +104,7 @@ export default class MessageContextMenu extends React.Component {
|
||||||
this.setState({ canRedact, canPin });
|
this.setState({ canRedact, canPin });
|
||||||
};
|
};
|
||||||
|
|
||||||
_isPinned() {
|
private isPinned(): boolean {
|
||||||
const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
|
const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
|
||||||
const pinnedEvent = room.currentState.getStateEvents(EventType.RoomPinnedEvents, '');
|
const pinnedEvent = room.currentState.getStateEvents(EventType.RoomPinnedEvents, '');
|
||||||
if (!pinnedEvent) return false;
|
if (!pinnedEvent) return false;
|
||||||
|
@ -101,38 +112,35 @@ export default class MessageContextMenu extends React.Component {
|
||||||
return content.pinned && Array.isArray(content.pinned) && content.pinned.includes(this.props.mxEvent.getId());
|
return content.pinned && Array.isArray(content.pinned) && content.pinned.includes(this.props.mxEvent.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
onResendReactionsClick = () => {
|
private onResendReactionsClick = (): void => {
|
||||||
for (const reaction of this._getUnsentReactions()) {
|
for (const reaction of this.getUnsentReactions()) {
|
||||||
Resend.resend(reaction);
|
Resend.resend(reaction);
|
||||||
}
|
}
|
||||||
this.closeMenu();
|
this.closeMenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
onReportEventClick = () => {
|
private onReportEventClick = (): void => {
|
||||||
const ReportEventDialog = sdk.getComponent("dialogs.ReportEventDialog");
|
|
||||||
Modal.createTrackedDialog('Report Event', '', ReportEventDialog, {
|
Modal.createTrackedDialog('Report Event', '', ReportEventDialog, {
|
||||||
mxEvent: this.props.mxEvent,
|
mxEvent: this.props.mxEvent,
|
||||||
}, 'mx_Dialog_reportEvent');
|
}, 'mx_Dialog_reportEvent');
|
||||||
this.closeMenu();
|
this.closeMenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
onViewSourceClick = () => {
|
private onViewSourceClick = (): void => {
|
||||||
const ViewSource = sdk.getComponent('structures.ViewSource');
|
|
||||||
Modal.createTrackedDialog('View Event Source', '', ViewSource, {
|
Modal.createTrackedDialog('View Event Source', '', ViewSource, {
|
||||||
mxEvent: this.props.mxEvent,
|
mxEvent: this.props.mxEvent,
|
||||||
}, 'mx_Dialog_viewsource');
|
}, 'mx_Dialog_viewsource');
|
||||||
this.closeMenu();
|
this.closeMenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
onRedactClick = () => {
|
private onRedactClick = (): void => {
|
||||||
const ConfirmRedactDialog = sdk.getComponent("dialogs.ConfirmRedactDialog");
|
|
||||||
Modal.createTrackedDialog('Confirm Redact Dialog', '', ConfirmRedactDialog, {
|
Modal.createTrackedDialog('Confirm Redact Dialog', '', ConfirmRedactDialog, {
|
||||||
onFinished: async (proceed, reason) => {
|
onFinished: async (proceed: boolean, reason?: string) => {
|
||||||
if (!proceed) return;
|
if (!proceed) return;
|
||||||
|
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
try {
|
try {
|
||||||
if (this.props.onCloseDialog) this.props.onCloseDialog();
|
this.props.onCloseDialog?.();
|
||||||
await cli.redactEvent(
|
await cli.redactEvent(
|
||||||
this.props.mxEvent.getRoomId(),
|
this.props.mxEvent.getRoomId(),
|
||||||
this.props.mxEvent.getId(),
|
this.props.mxEvent.getId(),
|
||||||
|
@ -145,7 +153,6 @@ export default class MessageContextMenu extends React.Component {
|
||||||
// (e.g. no errcode or statusCode) as in that case the redactions end up in the
|
// (e.g. no errcode or statusCode) as in that case the redactions end up in the
|
||||||
// detached queue and we show the room status bar to allow retry
|
// detached queue and we show the room status bar to allow retry
|
||||||
if (typeof code !== "undefined") {
|
if (typeof code !== "undefined") {
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
||||||
// display error message stating you couldn't delete this.
|
// display error message stating you couldn't delete this.
|
||||||
Modal.createTrackedDialog('You cannot delete this message', '', ErrorDialog, {
|
Modal.createTrackedDialog('You cannot delete this message', '', ErrorDialog, {
|
||||||
title: _t('Error'),
|
title: _t('Error'),
|
||||||
|
@ -158,7 +165,7 @@ export default class MessageContextMenu extends React.Component {
|
||||||
this.closeMenu();
|
this.closeMenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
onForwardClick = () => {
|
private onForwardClick = (): void => {
|
||||||
Modal.createTrackedDialog('Forward Message', '', ForwardDialog, {
|
Modal.createTrackedDialog('Forward Message', '', ForwardDialog, {
|
||||||
matrixClient: MatrixClientPeg.get(),
|
matrixClient: MatrixClientPeg.get(),
|
||||||
event: this.props.mxEvent,
|
event: this.props.mxEvent,
|
||||||
|
@ -167,12 +174,12 @@ export default class MessageContextMenu extends React.Component {
|
||||||
this.closeMenu();
|
this.closeMenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
onPinClick = () => {
|
private onPinClick = (): void => {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
const room = cli.getRoom(this.props.mxEvent.getRoomId());
|
const room = cli.getRoom(this.props.mxEvent.getRoomId());
|
||||||
const eventId = this.props.mxEvent.getId();
|
const eventId = this.props.mxEvent.getId();
|
||||||
|
|
||||||
const pinnedIds = room?.currentState?.getStateEvents(EventType.RoomPinnedEvents, "")?.pinned || [];
|
const pinnedIds = room?.currentState?.getStateEvents(EventType.RoomPinnedEvents, "")?.getContent().pinned || [];
|
||||||
if (pinnedIds.includes(eventId)) {
|
if (pinnedIds.includes(eventId)) {
|
||||||
pinnedIds.splice(pinnedIds.indexOf(eventId), 1);
|
pinnedIds.splice(pinnedIds.indexOf(eventId), 1);
|
||||||
} else {
|
} else {
|
||||||
|
@ -188,18 +195,16 @@ export default class MessageContextMenu extends React.Component {
|
||||||
this.closeMenu();
|
this.closeMenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
closeMenu = () => {
|
private closeMenu = (): void => {
|
||||||
if (this.props.onFinished) this.props.onFinished();
|
this.props.onFinished();
|
||||||
};
|
};
|
||||||
|
|
||||||
onUnhidePreviewClick = () => {
|
private onUnhidePreviewClick = (): void => {
|
||||||
if (this.props.eventTileOps) {
|
this.props.eventTileOps?.unhideWidget();
|
||||||
this.props.eventTileOps.unhideWidget();
|
|
||||||
}
|
|
||||||
this.closeMenu();
|
this.closeMenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
onQuoteClick = () => {
|
private onQuoteClick = (): void => {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: Action.ComposerInsert,
|
action: Action.ComposerInsert,
|
||||||
event: this.props.mxEvent,
|
event: this.props.mxEvent,
|
||||||
|
@ -207,9 +212,8 @@ export default class MessageContextMenu extends React.Component {
|
||||||
this.closeMenu();
|
this.closeMenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
onPermalinkClick = (e) => {
|
private onPermalinkClick = (e: React.MouseEvent): void => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const ShareDialog = sdk.getComponent("dialogs.ShareDialog");
|
|
||||||
Modal.createTrackedDialog('share room message dialog', '', ShareDialog, {
|
Modal.createTrackedDialog('share room message dialog', '', ShareDialog, {
|
||||||
target: this.props.mxEvent,
|
target: this.props.mxEvent,
|
||||||
permalinkCreator: this.props.permalinkCreator,
|
permalinkCreator: this.props.permalinkCreator,
|
||||||
|
@ -217,30 +221,27 @@ export default class MessageContextMenu extends React.Component {
|
||||||
this.closeMenu();
|
this.closeMenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
onCollapseReplyThreadClick = () => {
|
private onCollapseReplyThreadClick = (): void => {
|
||||||
this.props.collapseReplyThread();
|
this.props.collapseReplyThread();
|
||||||
this.closeMenu();
|
this.closeMenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
_getReactions(filter) {
|
private getReactions(filter: (e: MatrixEvent) => boolean): MatrixEvent[] {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
const room = cli.getRoom(this.props.mxEvent.getRoomId());
|
const room = cli.getRoom(this.props.mxEvent.getRoomId());
|
||||||
const eventId = this.props.mxEvent.getId();
|
const eventId = this.props.mxEvent.getId();
|
||||||
return room.getPendingEvents().filter(e => {
|
return room.getPendingEvents().filter(e => {
|
||||||
const relation = e.getRelation();
|
const relation = e.getRelation();
|
||||||
return relation &&
|
return relation?.rel_type === RelationType.Annotation && relation.event_id === eventId && filter(e);
|
||||||
relation.rel_type === "m.annotation" &&
|
|
||||||
relation.event_id === eventId &&
|
|
||||||
filter(e);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_getPendingReactions() {
|
private getPendingReactions(): MatrixEvent[] {
|
||||||
return this._getReactions(e => canCancel(e.status));
|
return this.getReactions(e => canCancel(e.status));
|
||||||
}
|
}
|
||||||
|
|
||||||
_getUnsentReactions() {
|
private getUnsentReactions(): MatrixEvent[] {
|
||||||
return this._getReactions(e => e.status === EventStatus.NOT_SENT);
|
return this.getReactions(e => e.status === EventStatus.NOT_SENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -248,16 +249,17 @@ export default class MessageContextMenu extends React.Component {
|
||||||
const me = cli.getUserId();
|
const me = cli.getUserId();
|
||||||
const mxEvent = this.props.mxEvent;
|
const mxEvent = this.props.mxEvent;
|
||||||
const eventStatus = mxEvent.status;
|
const eventStatus = mxEvent.status;
|
||||||
const unsentReactionsCount = this._getUnsentReactions().length;
|
const unsentReactionsCount = this.getUnsentReactions().length;
|
||||||
let resendReactionsButton;
|
|
||||||
let redactButton;
|
let resendReactionsButton: JSX.Element;
|
||||||
let forwardButton;
|
let redactButton: JSX.Element;
|
||||||
let pinButton;
|
let forwardButton: JSX.Element;
|
||||||
let unhidePreviewButton;
|
let pinButton: JSX.Element;
|
||||||
let externalURLButton;
|
let unhidePreviewButton: JSX.Element;
|
||||||
let quoteButton;
|
let externalURLButton: JSX.Element;
|
||||||
let collapseReplyThread;
|
let quoteButton: JSX.Element;
|
||||||
let redactItemList;
|
let collapseReplyThread: JSX.Element;
|
||||||
|
let redactItemList: JSX.Element;
|
||||||
|
|
||||||
// status is SENT before remote-echo, null after
|
// status is SENT before remote-echo, null after
|
||||||
const isSent = !eventStatus || eventStatus === EventStatus.SENT;
|
const isSent = !eventStatus || eventStatus === EventStatus.SENT;
|
||||||
|
@ -296,7 +298,7 @@ export default class MessageContextMenu extends React.Component {
|
||||||
pinButton = (
|
pinButton = (
|
||||||
<IconizedContextMenuOption
|
<IconizedContextMenuOption
|
||||||
iconClassName="mx_MessageContextMenu_iconPin"
|
iconClassName="mx_MessageContextMenu_iconPin"
|
||||||
label={ this._isPinned() ? _t('Unpin') : _t('Pin') }
|
label={ this.isPinned() ? _t('Unpin') : _t('Pin') }
|
||||||
onClick={this.onPinClick}
|
onClick={this.onPinClick}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -327,16 +329,20 @@ export default class MessageContextMenu extends React.Component {
|
||||||
if (this.props.permalinkCreator) {
|
if (this.props.permalinkCreator) {
|
||||||
permalink = this.props.permalinkCreator.forEvent(this.props.mxEvent.getId());
|
permalink = this.props.permalinkCreator.forEvent(this.props.mxEvent.getId());
|
||||||
}
|
}
|
||||||
// XXX: if we use room ID, we should also include a server where the event can be found (other than in the domain of the event ID)
|
|
||||||
const permalinkButton = (
|
const permalinkButton = (
|
||||||
<IconizedContextMenuOption
|
<IconizedContextMenuOption
|
||||||
iconClassName="mx_MessageContextMenu_iconPermalink"
|
iconClassName="mx_MessageContextMenu_iconPermalink"
|
||||||
onClick={this.onPermalinkClick}
|
onClick={this.onPermalinkClick}
|
||||||
label= {_t('Share')}
|
label= {_t('Share')}
|
||||||
element="a"
|
element="a"
|
||||||
href={permalink}
|
{
|
||||||
target="_blank"
|
// XXX: Typescript signature for AccessibleButton doesn't work properly for non-inputs like `a`
|
||||||
rel="noreferrer noopener"
|
...{
|
||||||
|
href: permalink,
|
||||||
|
target: "_blank",
|
||||||
|
rel: "noreferrer noopener",
|
||||||
|
}
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -351,8 +357,8 @@ export default class MessageContextMenu extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bridges can provide a 'external_url' to link back to the source.
|
// Bridges can provide a 'external_url' to link back to the source.
|
||||||
if (typeof (mxEvent.event.content.external_url) === "string" &&
|
if (typeof (mxEvent.getContent().external_url) === "string" &&
|
||||||
isUrlPermitted(mxEvent.event.content.external_url)
|
isUrlPermitted(mxEvent.getContent().external_url)
|
||||||
) {
|
) {
|
||||||
externalURLButton = (
|
externalURLButton = (
|
||||||
<IconizedContextMenuOption
|
<IconizedContextMenuOption
|
||||||
|
@ -360,9 +366,14 @@ export default class MessageContextMenu extends React.Component {
|
||||||
onClick={this.closeMenu}
|
onClick={this.closeMenu}
|
||||||
label={ _t('Source URL') }
|
label={ _t('Source URL') }
|
||||||
element="a"
|
element="a"
|
||||||
target="_blank"
|
{
|
||||||
rel="noreferrer noopener"
|
// XXX: Typescript signature for AccessibleButton doesn't work properly for non-inputs like `a`
|
||||||
href={mxEvent.event.content.external_url}
|
...{
|
||||||
|
target: "_blank",
|
||||||
|
rel: "noreferrer noopener",
|
||||||
|
href: mxEvent.getContent().external_url,
|
||||||
|
}
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -377,7 +388,7 @@ export default class MessageContextMenu extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let reportEventButton;
|
let reportEventButton: JSX.Element;
|
||||||
if (mxEvent.getSender() !== me) {
|
if (mxEvent.getSender() !== me) {
|
||||||
reportEventButton = (
|
reportEventButton = (
|
||||||
<IconizedContextMenuOption
|
<IconizedContextMenuOption
|
|
@ -15,11 +15,11 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import { SettingLevel } from "../../../settings/SettingLevel";
|
import { SettingLevel } from "../../../settings/SettingLevel";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import BaseDialog from "./BaseDialog";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
unknownProfileUsers: Array<{
|
unknownProfileUsers: Array<{
|
||||||
|
@ -50,8 +50,6 @@ export default class AskInviteAnywayDialog extends React.Component<IProps> {
|
||||||
};
|
};
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
|
|
||||||
const errorList = this.props.unknownProfileUsers
|
const errorList = this.props.unknownProfileUsers
|
||||||
.map(address => <li key={address.userId}>{address.userId}: {address.errorText}</li>);
|
.map(address => <li key={address.userId}>{address.userId}: {address.errorText}</li>);
|
||||||
|
|
||||||
|
|
|
@ -18,13 +18,17 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import SdkConfig from '../../../SdkConfig';
|
import SdkConfig from '../../../SdkConfig';
|
||||||
import Modal from '../../../Modal';
|
import Modal from '../../../Modal';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import sendBugReport, { downloadBugReport } from '../../../rageshake/submit-rageshake';
|
import sendBugReport, { downloadBugReport } from '../../../rageshake/submit-rageshake';
|
||||||
import AccessibleButton from "../elements/AccessibleButton";
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import QuestionDialog from "./QuestionDialog";
|
||||||
|
import BaseDialog from "./BaseDialog";
|
||||||
|
import Field from '../elements/Field';
|
||||||
|
import Spinner from "../elements/Spinner";
|
||||||
|
import DialogButtons from "../elements/DialogButtons";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onFinished: (success: boolean) => void;
|
onFinished: (success: boolean) => void;
|
||||||
|
@ -93,7 +97,6 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
if (!this.unmounted) {
|
if (!this.unmounted) {
|
||||||
this.props.onFinished(false);
|
this.props.onFinished(false);
|
||||||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
|
||||||
// N.B. first param is passed to piwik and so doesn't want i18n
|
// N.B. first param is passed to piwik and so doesn't want i18n
|
||||||
Modal.createTrackedDialog('Bug report sent', '', QuestionDialog, {
|
Modal.createTrackedDialog('Bug report sent', '', QuestionDialog, {
|
||||||
title: _t('Logs sent'),
|
title: _t('Logs sent'),
|
||||||
|
@ -160,11 +163,6 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const Loader = sdk.getComponent("elements.Spinner");
|
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
|
||||||
const Field = sdk.getComponent('elements.Field');
|
|
||||||
|
|
||||||
let error = null;
|
let error = null;
|
||||||
if (this.state.err) {
|
if (this.state.err) {
|
||||||
error = <div className="error">
|
error = <div className="error">
|
||||||
|
@ -176,7 +174,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
|
||||||
if (this.state.busy) {
|
if (this.state.busy) {
|
||||||
progress = (
|
progress = (
|
||||||
<div className="progress">
|
<div className="progress">
|
||||||
<Loader />
|
<Spinner />
|
||||||
{this.state.progress} ...
|
{this.state.progress} ...
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -16,9 +16,10 @@ Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import request from 'browser-request';
|
import request from 'browser-request';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
|
import QuestionDialog from "./QuestionDialog";
|
||||||
|
import Spinner from "../elements/Spinner";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
newVersion: string;
|
newVersion: string;
|
||||||
|
@ -65,9 +66,6 @@ export default class ChangelogDialog extends React.Component<IProps> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const Spinner = sdk.getComponent('views.elements.Spinner');
|
|
||||||
const QuestionDialog = sdk.getComponent('dialogs.QuestionDialog');
|
|
||||||
|
|
||||||
const logs = REPOS.map(repo => {
|
const logs = REPOS.map(repo => {
|
||||||
let content;
|
let content;
|
||||||
if (this.state[repo] == null) {
|
if (this.state[repo] == null) {
|
||||||
|
|
|
@ -15,9 +15,12 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import ConfirmRedactDialog from './ConfirmRedactDialog';
|
||||||
|
import ErrorDialog from './ErrorDialog';
|
||||||
|
import BaseDialog from "./BaseDialog";
|
||||||
|
import Spinner from "../elements/Spinner";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
redact: () => Promise<void>;
|
redact: () => Promise<void>;
|
||||||
|
@ -73,7 +76,6 @@ export default class ConfirmAndWaitRedactDialog extends React.PureComponent<IPro
|
||||||
public render() {
|
public render() {
|
||||||
if (this.state.isRedacting) {
|
if (this.state.isRedacting) {
|
||||||
if (this.state.redactionErrorCode) {
|
if (this.state.redactionErrorCode) {
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
||||||
const code = this.state.redactionErrorCode;
|
const code = this.state.redactionErrorCode;
|
||||||
return (
|
return (
|
||||||
<ErrorDialog
|
<ErrorDialog
|
||||||
|
@ -83,8 +85,6 @@ export default class ConfirmAndWaitRedactDialog extends React.PureComponent<IPro
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const BaseDialog = sdk.getComponent("dialogs.BaseDialog");
|
|
||||||
const Spinner = sdk.getComponent('elements.Spinner');
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
|
@ -95,7 +95,6 @@ export default class ConfirmAndWaitRedactDialog extends React.PureComponent<IPro
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const ConfirmRedactDialog = sdk.getComponent("dialogs.ConfirmRedactDialog");
|
|
||||||
return <ConfirmRedactDialog onFinished={this.onParentFinished} />;
|
return <ConfirmRedactDialog onFinished={this.onParentFinished} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,9 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import TextInputDialog from "./TextInputDialog";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onFinished: (success: boolean) => void;
|
onFinished: (success: boolean) => void;
|
||||||
|
@ -29,7 +29,6 @@ interface IProps {
|
||||||
@replaceableComponent("views.dialogs.ConfirmRedactDialog")
|
@replaceableComponent("views.dialogs.ConfirmRedactDialog")
|
||||||
export default class ConfirmRedactDialog extends React.Component<IProps> {
|
export default class ConfirmRedactDialog extends React.Component<IProps> {
|
||||||
render() {
|
render() {
|
||||||
const TextInputDialog = sdk.getComponent('views.dialogs.TextInputDialog');
|
|
||||||
return (
|
return (
|
||||||
<TextInputDialog onFinished={this.props.onFinished}
|
<TextInputDialog onFinished={this.props.onFinished}
|
||||||
title={_t("Confirm Removal")}
|
title={_t("Confirm Removal")}
|
||||||
|
|
|
@ -17,11 +17,14 @@ limitations under the License.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import { GroupMemberType } from '../../../groups';
|
import { GroupMemberType } from '../../../groups';
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { mediaFromMxc } from "../../../customisations/Media";
|
import { mediaFromMxc } from "../../../customisations/Media";
|
||||||
|
import MemberAvatar from '../avatars/MemberAvatar';
|
||||||
|
import BaseAvatar from '../avatars/BaseAvatar';
|
||||||
|
import BaseDialog from "./BaseDialog";
|
||||||
|
import DialogButtons from "../elements/DialogButtons";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
// matrix-js-sdk (room) member object. Supply either this or 'groupMember'
|
// matrix-js-sdk (room) member object. Supply either this or 'groupMember'
|
||||||
|
@ -67,11 +70,6 @@ export default class ConfirmUserActionDialog extends React.Component<IProps> {
|
||||||
};
|
};
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
|
||||||
const MemberAvatar = sdk.getComponent("views.avatars.MemberAvatar");
|
|
||||||
const BaseAvatar = sdk.getComponent("views.avatars.BaseAvatar");
|
|
||||||
|
|
||||||
const confirmButtonClass = this.props.danger ? 'danger' : '';
|
const confirmButtonClass = this.props.danger ? 'danger' : '';
|
||||||
|
|
||||||
let reasonBox;
|
let reasonBox;
|
||||||
|
|
|
@ -16,8 +16,9 @@ limitations under the License.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import * as sdk from "../../../index";
|
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import BaseDialog from "./BaseDialog";
|
||||||
|
import DialogButtons from "../elements/DialogButtons";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onFinished: (success: boolean) => void;
|
onFinished: (success: boolean) => void;
|
||||||
|
@ -34,9 +35,6 @@ export default class ConfirmWipeDeviceDialog extends React.Component<IProps> {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
className='mx_ConfirmWipeDeviceDialog'
|
className='mx_ConfirmWipeDeviceDialog'
|
||||||
|
|
|
@ -15,11 +15,12 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import dis from '../../../dispatcher/dispatcher';
|
import dis from '../../../dispatcher/dispatcher';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import BaseDialog from "./BaseDialog";
|
||||||
|
import Spinner from "../elements/Spinner";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onFinished: (success: boolean) => void;
|
onFinished: (success: boolean) => void;
|
||||||
|
@ -106,9 +107,6 @@ export default class CreateGroupDialog extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
const Spinner = sdk.getComponent('elements.Spinner');
|
|
||||||
|
|
||||||
if (this.state.creating) {
|
if (this.state.creating) {
|
||||||
return <Spinner />;
|
return <Spinner />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,21 +16,22 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import dis from '../../../dispatcher/dispatcher';
|
import dis from '../../../dispatcher/dispatcher';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import SdkConfig from '../../../SdkConfig';
|
import SdkConfig from '../../../SdkConfig';
|
||||||
import Modal from '../../../Modal';
|
import Modal from '../../../Modal';
|
||||||
|
import BaseDialog from "./BaseDialog";
|
||||||
|
import DialogButtons from "../elements/DialogButtons";
|
||||||
|
import QuestionDialog from "./QuestionDialog";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onFinished: (success: boolean) => void;
|
onFinished: (success: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (props: IProps) => {
|
const CryptoStoreTooNewDialog: React.FC<IProps> = (props: IProps) => {
|
||||||
const brand = SdkConfig.get().brand;
|
const brand = SdkConfig.get().brand;
|
||||||
|
|
||||||
const _onLogoutClicked = () => {
|
const _onLogoutClicked = () => {
|
||||||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
|
||||||
Modal.createTrackedDialog('Logout e2e db too new', '', QuestionDialog, {
|
Modal.createTrackedDialog('Logout e2e db too new', '', QuestionDialog, {
|
||||||
title: _t("Sign out"),
|
title: _t("Sign out"),
|
||||||
description: _t(
|
description: _t(
|
||||||
|
@ -58,8 +59,6 @@ export default (props: IProps) => {
|
||||||
{ brand },
|
{ brand },
|
||||||
);
|
);
|
||||||
|
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
|
||||||
return (<BaseDialog className="mx_CryptoStoreTooNewDialog"
|
return (<BaseDialog className="mx_CryptoStoreTooNewDialog"
|
||||||
contentId='mx_Dialog_content'
|
contentId='mx_Dialog_content'
|
||||||
title={_t("Incompatible Database")}
|
title={_t("Incompatible Database")}
|
||||||
|
@ -79,3 +78,5 @@ export default (props: IProps) => {
|
||||||
</DialogButtons>
|
</DialogButtons>
|
||||||
</BaseDialog>);
|
</BaseDialog>);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default CryptoStoreTooNewDialog;
|
||||||
|
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import Analytics from '../../../Analytics';
|
import Analytics from '../../../Analytics';
|
||||||
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
||||||
import * as Lifecycle from '../../../Lifecycle';
|
import * as Lifecycle from '../../../Lifecycle';
|
||||||
|
@ -26,6 +25,7 @@ import InteractiveAuth, { ERROR_USER_CANCELLED } from "../../structures/Interact
|
||||||
import { DEFAULT_PHASE, PasswordAuthEntry, SSOAuthEntry } from "../auth/InteractiveAuthEntryComponents";
|
import { DEFAULT_PHASE, PasswordAuthEntry, SSOAuthEntry } from "../auth/InteractiveAuthEntryComponents";
|
||||||
import StyledCheckbox from "../elements/StyledCheckbox";
|
import StyledCheckbox from "../elements/StyledCheckbox";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import BaseDialog from "./BaseDialog";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onFinished: (success: boolean) => void;
|
onFinished: (success: boolean) => void;
|
||||||
|
@ -165,8 +165,6 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
|
|
||||||
let error = null;
|
let error = null;
|
||||||
if (this.state.errStr) {
|
if (this.state.errStr) {
|
||||||
error = <div className="error">
|
error = <div className="error">
|
||||||
|
|
|
@ -16,7 +16,6 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState, useEffect, ChangeEvent, MouseEvent } from 'react';
|
import React, { useState, useEffect, ChangeEvent, MouseEvent } from 'react';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import SyntaxHighlight from '../elements/SyntaxHighlight';
|
import SyntaxHighlight from '../elements/SyntaxHighlight';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import Field from "../elements/Field";
|
import Field from "../elements/Field";
|
||||||
|
@ -42,6 +41,8 @@ import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
import { SettingLevel } from '../../../settings/SettingLevel';
|
import { SettingLevel } from '../../../settings/SettingLevel';
|
||||||
|
import BaseDialog from "./BaseDialog";
|
||||||
|
import TruncatedList from "../elements/TruncatedList";
|
||||||
|
|
||||||
interface IGenericEditorProps {
|
interface IGenericEditorProps {
|
||||||
onBack: () => void;
|
onBack: () => void;
|
||||||
|
@ -369,7 +370,6 @@ class FilteredList extends React.PureComponent<IFilteredListProps, IFilteredList
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const TruncatedList = sdk.getComponent("elements.TruncatedList");
|
|
||||||
return <div>
|
return <div>
|
||||||
<Field label={_t('Filter results')} autoFocus={true} size={64}
|
<Field label={_t('Filter results')} autoFocus={true} size={64}
|
||||||
type="text" autoComplete="off" value={this.props.query} onChange={this.onQuery}
|
type="text" autoComplete="off" value={this.props.query} onChange={this.onQuery}
|
||||||
|
@ -1261,7 +1261,6 @@ export default class DevtoolsDialog extends React.PureComponent<IProps, IState>
|
||||||
</React.Fragment>;
|
</React.Fragment>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog className="mx_QuestionDialog" onFinished={this.props.onFinished} title={_t('Developer Tools')}>
|
<BaseDialog className="mx_QuestionDialog" onFinished={this.props.onFinished} title={_t('Developer Tools')}>
|
||||||
{ body }
|
{ body }
|
||||||
|
|
|
@ -26,9 +26,9 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import BaseDialog from "./BaseDialog";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onFinished: (success: boolean) => void;
|
onFinished: (success: boolean) => void;
|
||||||
|
@ -57,7 +57,6 @@ export default class ErrorDialog extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
className="mx_ErrorDialog"
|
className="mx_ErrorDialog"
|
||||||
|
|
|
@ -18,7 +18,6 @@ import React, { createRef } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { _t, _td } from "../../../languageHandler";
|
import { _t, _td } from "../../../languageHandler";
|
||||||
import * as sdk from "../../../index";
|
|
||||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
import { makeRoomPermalink, makeUserPermalink } from "../../../utils/permalinks/Permalinks";
|
import { makeRoomPermalink, makeUserPermalink } from "../../../utils/permalinks/Permalinks";
|
||||||
import DMRoomMap from "../../../utils/DMRoomMap";
|
import DMRoomMap from "../../../utils/DMRoomMap";
|
||||||
|
@ -65,6 +64,9 @@ import { copyPlaintext, selectText } from "../../../utils/strings";
|
||||||
import * as ContextMenu from "../../structures/ContextMenu";
|
import * as ContextMenu from "../../structures/ContextMenu";
|
||||||
import { toRightOf } from "../../structures/ContextMenu";
|
import { toRightOf } from "../../structures/ContextMenu";
|
||||||
import GenericTextContextMenu from "../context_menus/GenericTextContextMenu";
|
import GenericTextContextMenu from "../context_menus/GenericTextContextMenu";
|
||||||
|
import QuestionDialog from "./QuestionDialog";
|
||||||
|
import Spinner from "../elements/Spinner";
|
||||||
|
import BaseDialog from "./BaseDialog";
|
||||||
|
|
||||||
// we have a number of types defined from the Matrix spec which can't reasonably be altered here.
|
// we have a number of types defined from the Matrix spec which can't reasonably be altered here.
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
|
@ -1046,7 +1048,6 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
if (this.unmounted) return;
|
if (this.unmounted) return;
|
||||||
|
|
||||||
if (failed.length > 0) {
|
if (failed.length > 0) {
|
||||||
const QuestionDialog = sdk.getComponent('dialogs.QuestionDialog');
|
|
||||||
Modal.createTrackedDialog('Invite Paste Fail', '', QuestionDialog, {
|
Modal.createTrackedDialog('Invite Paste Fail', '', QuestionDialog, {
|
||||||
title: _t('Failed to find the following users'),
|
title: _t('Failed to find the following users'),
|
||||||
description: _t(
|
description: _t(
|
||||||
|
@ -1158,7 +1159,6 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
const toRender = sourceMembers.slice(0, showNum);
|
const toRender = sourceMembers.slice(0, showNum);
|
||||||
const hasMore = toRender.length < sourceMembers.length;
|
const hasMore = toRender.length < sourceMembers.length;
|
||||||
|
|
||||||
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
|
|
||||||
let showMore = null;
|
let showMore = null;
|
||||||
if (hasMore) {
|
if (hasMore) {
|
||||||
showMore = (
|
showMore = (
|
||||||
|
@ -1269,10 +1269,6 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
|
|
||||||
const Spinner = sdk.getComponent("elements.Spinner");
|
|
||||||
|
|
||||||
let spinner = null;
|
let spinner = null;
|
||||||
if (this.state.busy) {
|
if (this.state.busy) {
|
||||||
spinner = <Spinner w={20} h={20} />;
|
spinner = <Spinner w={20} h={20} />;
|
||||||
|
|
|
@ -15,7 +15,6 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import { ensureDMExists } from "../../../createRoom";
|
import { ensureDMExists } from "../../../createRoom";
|
||||||
import { IDialogProps } from "./IDialogProps";
|
import { IDialogProps } from "./IDialogProps";
|
||||||
|
@ -26,6 +25,10 @@ import Markdown from '../../../Markdown';
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import StyledRadioButton from "../elements/StyledRadioButton";
|
import StyledRadioButton from "../elements/StyledRadioButton";
|
||||||
|
import BaseDialog from "./BaseDialog";
|
||||||
|
import DialogButtons from "../elements/DialogButtons";
|
||||||
|
import Field from "../elements/Field";
|
||||||
|
import Spinner from "../elements/Spinner";
|
||||||
|
|
||||||
interface IProps extends IDialogProps {
|
interface IProps extends IDialogProps {
|
||||||
mxEvent: MatrixEvent;
|
mxEvent: MatrixEvent;
|
||||||
|
@ -239,11 +242,6 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
|
||||||
const Loader = sdk.getComponent('elements.Spinner');
|
|
||||||
const Field = sdk.getComponent('elements.Field');
|
|
||||||
|
|
||||||
let error = null;
|
let error = null;
|
||||||
if (this.state.err) {
|
if (this.state.err) {
|
||||||
error = <div className="error">
|
error = <div className="error">
|
||||||
|
@ -255,7 +253,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
|
||||||
if (this.state.busy) {
|
if (this.state.busy) {
|
||||||
progress = (
|
progress = (
|
||||||
<div className="progress">
|
<div className="progress">
|
||||||
<Loader />
|
<Spinner />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,12 @@ import GeneralRoomSettingsTab from "../settings/tabs/room/GeneralRoomSettingsTab
|
||||||
import SecurityRoomSettingsTab from "../settings/tabs/room/SecurityRoomSettingsTab";
|
import SecurityRoomSettingsTab from "../settings/tabs/room/SecurityRoomSettingsTab";
|
||||||
import NotificationSettingsTab from "../settings/tabs/room/NotificationSettingsTab";
|
import NotificationSettingsTab from "../settings/tabs/room/NotificationSettingsTab";
|
||||||
import BridgeSettingsTab from "../settings/tabs/room/BridgeSettingsTab";
|
import BridgeSettingsTab from "../settings/tabs/room/BridgeSettingsTab";
|
||||||
import * as sdk from "../../../index";
|
|
||||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
import dis from "../../../dispatcher/dispatcher";
|
import dis from "../../../dispatcher/dispatcher";
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import { UIFeature } from "../../../settings/UIFeature";
|
import { UIFeature } from "../../../settings/UIFeature";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import BaseDialog from "./BaseDialog";
|
||||||
|
|
||||||
export const ROOM_GENERAL_TAB = "ROOM_GENERAL_TAB";
|
export const ROOM_GENERAL_TAB = "ROOM_GENERAL_TAB";
|
||||||
export const ROOM_SECURITY_TAB = "ROOM_SECURITY_TAB";
|
export const ROOM_SECURITY_TAB = "ROOM_SECURITY_TAB";
|
||||||
|
@ -119,8 +119,6 @@ export default class RoomSettingsDialog extends React.Component<IProps> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
|
|
||||||
const roomName = MatrixClientPeg.get().getRoom(this.props.roomId).name;
|
const roomName = MatrixClientPeg.get().getRoom(this.props.roomId).name;
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
|
|
|
@ -22,7 +22,6 @@ import { User } from "matrix-js-sdk/src/models/user";
|
||||||
import { Group } from "matrix-js-sdk/src/models/group";
|
import { Group } from "matrix-js-sdk/src/models/group";
|
||||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import QRCode from "../elements/QRCode";
|
import QRCode from "../elements/QRCode";
|
||||||
import { RoomPermalinkCreator, makeGroupPermalink, makeUserPermalink } from "../../../utils/permalinks/Permalinks";
|
import { RoomPermalinkCreator, makeGroupPermalink, makeUserPermalink } from "../../../utils/permalinks/Permalinks";
|
||||||
|
@ -35,6 +34,8 @@ import { IDialogProps } from "./IDialogProps";
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import { UIFeature } from "../../../settings/UIFeature";
|
import { UIFeature } from "../../../settings/UIFeature";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import BaseDialog from "./BaseDialog";
|
||||||
|
import GenericTextContextMenu from "../context_menus/GenericTextContextMenu.js";
|
||||||
|
|
||||||
const socials = [
|
const socials = [
|
||||||
{
|
{
|
||||||
|
@ -119,7 +120,6 @@ export default class ShareDialog extends React.PureComponent<IProps, IState> {
|
||||||
|
|
||||||
const successful = await copyPlaintext(this.getUrl());
|
const successful = await copyPlaintext(this.getUrl());
|
||||||
const buttonRect = target.getBoundingClientRect();
|
const buttonRect = target.getBoundingClientRect();
|
||||||
const GenericTextContextMenu = sdk.getComponent('context_menus.GenericTextContextMenu');
|
|
||||||
const { close } = ContextMenu.createMenu(GenericTextContextMenu, {
|
const { close } = ContextMenu.createMenu(GenericTextContextMenu, {
|
||||||
...toRightOf(buttonRect, 2),
|
...toRightOf(buttonRect, 2),
|
||||||
message: successful ? _t('Copied!') : _t('Failed to copy'),
|
message: successful ? _t('Copied!') : _t('Failed to copy'),
|
||||||
|
@ -230,7 +230,6 @@ export default class ShareDialog extends React.PureComponent<IProps, IState> {
|
||||||
</>;
|
</>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
return <BaseDialog
|
return <BaseDialog
|
||||||
title={title}
|
title={title}
|
||||||
className='mx_ShareDialog'
|
className='mx_ShareDialog'
|
||||||
|
|
|
@ -16,11 +16,12 @@ limitations under the License.
|
||||||
|
|
||||||
import url from 'url';
|
import url from 'url';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import { _t, pickBestLanguage } from '../../../languageHandler';
|
import { _t, pickBestLanguage } from '../../../languageHandler';
|
||||||
|
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { SERVICE_TYPES } from "matrix-js-sdk/src/service-types";
|
import { SERVICE_TYPES } from "matrix-js-sdk/src/service-types";
|
||||||
|
import DialogButtons from "../elements/DialogButtons";
|
||||||
|
import BaseDialog from "./BaseDialog";
|
||||||
|
|
||||||
interface ITermsCheckboxProps {
|
interface ITermsCheckboxProps {
|
||||||
onChange: (url: string, checked: boolean) => void;
|
onChange: (url: string, checked: boolean) => void;
|
||||||
|
@ -117,9 +118,6 @@ export default class TermsDialog extends React.PureComponent<ITermsDialogProps,
|
||||||
};
|
};
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
|
||||||
|
|
||||||
const rows = [];
|
const rows = [];
|
||||||
for (const policiesAndService of this.props.policiesAndServicePairs) {
|
for (const policiesAndService of this.props.policiesAndServicePairs) {
|
||||||
const parsedBaseUrl = url.parse(policiesAndService.service.baseUrl);
|
const parsedBaseUrl = url.parse(policiesAndService.service.baseUrl);
|
||||||
|
|
|
@ -16,11 +16,12 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import filesize from "filesize";
|
import filesize from "filesize";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { getBlobSafeMimeType } from '../../../utils/blobs';
|
import { getBlobSafeMimeType } from '../../../utils/blobs';
|
||||||
|
import BaseDialog from "./BaseDialog";
|
||||||
|
import DialogButtons from "../elements/DialogButtons";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
file: File;
|
file: File;
|
||||||
|
@ -67,9 +68,6 @@ export default class UploadConfirmDialog extends React.Component<IProps> {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
|
||||||
|
|
||||||
let title;
|
let title;
|
||||||
if (this.props.totalFiles > 1 && this.props.currentIndex !== undefined) {
|
if (this.props.totalFiles > 1 && this.props.currentIndex !== undefined) {
|
||||||
title = _t(
|
title = _t(
|
||||||
|
|
|
@ -28,11 +28,11 @@ import PreferencesUserSettingsTab from "../settings/tabs/user/PreferencesUserSet
|
||||||
import VoiceUserSettingsTab from "../settings/tabs/user/VoiceUserSettingsTab";
|
import VoiceUserSettingsTab from "../settings/tabs/user/VoiceUserSettingsTab";
|
||||||
import HelpUserSettingsTab from "../settings/tabs/user/HelpUserSettingsTab";
|
import HelpUserSettingsTab from "../settings/tabs/user/HelpUserSettingsTab";
|
||||||
import FlairUserSettingsTab from "../settings/tabs/user/FlairUserSettingsTab";
|
import FlairUserSettingsTab from "../settings/tabs/user/FlairUserSettingsTab";
|
||||||
import * as sdk from "../../../index";
|
|
||||||
import SdkConfig from "../../../SdkConfig";
|
import SdkConfig from "../../../SdkConfig";
|
||||||
import MjolnirUserSettingsTab from "../settings/tabs/user/MjolnirUserSettingsTab";
|
import MjolnirUserSettingsTab from "../settings/tabs/user/MjolnirUserSettingsTab";
|
||||||
import { UIFeature } from "../../../settings/UIFeature";
|
import { UIFeature } from "../../../settings/UIFeature";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import BaseDialog from "./BaseDialog";
|
||||||
|
|
||||||
export enum UserTab {
|
export enum UserTab {
|
||||||
General = "USER_GENERAL_TAB",
|
General = "USER_GENERAL_TAB",
|
||||||
|
@ -162,8 +162,6 @@ export default class UserSettingsDialog extends React.Component<IProps, IState>
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
className='mx_UserSettingsDialog'
|
className='mx_UserSettingsDialog'
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import { debounce } from "lodash";
|
import { debounce } from "lodash";
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { ChangeEvent, FormEvent } from 'react';
|
import React, { ChangeEvent, FormEvent } from 'react';
|
||||||
import { ISecretStorageKeyInfo } from "matrix-js-sdk/src";
|
import { ISecretStorageKeyInfo } from "matrix-js-sdk/src/crypto/api";
|
||||||
|
|
||||||
import * as sdk from '../../../../index';
|
import * as sdk from '../../../../index';
|
||||||
import { MatrixClientPeg } from '../../../../MatrixClientPeg';
|
import { MatrixClientPeg } from '../../../../MatrixClientPeg';
|
||||||
|
|
|
@ -16,8 +16,9 @@ limitations under the License.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { _t } from "../../../../languageHandler";
|
import { _t } from "../../../../languageHandler";
|
||||||
import * as sdk from "../../../../index";
|
|
||||||
import { replaceableComponent } from "../../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../../utils/replaceableComponent";
|
||||||
|
import BaseDialog from "../BaseDialog";
|
||||||
|
import DialogButtons from "../../elements/DialogButtons";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onFinished: (success: boolean) => void;
|
onFinished: (success: boolean) => void;
|
||||||
|
@ -34,9 +35,6 @@ export default class ConfirmDestroyCrossSigningDialog extends React.Component<IP
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
className='mx_ConfirmDestroyCrossSigningDialog'
|
className='mx_ConfirmDestroyCrossSigningDialog'
|
||||||
|
|
|
@ -41,7 +41,8 @@ import QuestionDialog from "../dialogs/QuestionDialog";
|
||||||
import UIStore from "../../../stores/UIStore";
|
import UIStore from "../../../stores/UIStore";
|
||||||
import { compare } from "../../../utils/strings";
|
import { compare } from "../../../utils/strings";
|
||||||
|
|
||||||
export const ALL_ROOMS = Symbol("ALL_ROOMS");
|
// XXX: We would ideally use a symbol here but we can't since we save this value to localStorage
|
||||||
|
export const ALL_ROOMS = "ALL_ROOMS";
|
||||||
|
|
||||||
const SETTING_NAME = "room_directory_servers";
|
const SETTING_NAME = "room_directory_servers";
|
||||||
|
|
||||||
|
@ -94,8 +95,7 @@ export interface IInstance {
|
||||||
fields: object;
|
fields: object;
|
||||||
network_id: string;
|
network_id: string;
|
||||||
// XXX: this is undocumented but we rely on it.
|
// XXX: this is undocumented but we rely on it.
|
||||||
// we inject a fake entry with a symbolic instance_id.
|
instance_id: string;
|
||||||
instance_id: string | symbol;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IProtocol {
|
export interface IProtocol {
|
||||||
|
@ -112,8 +112,8 @@ export type Protocols = Record<string, IProtocol>;
|
||||||
interface IProps {
|
interface IProps {
|
||||||
protocols: Protocols;
|
protocols: Protocols;
|
||||||
selectedServerName: string;
|
selectedServerName: string;
|
||||||
selectedInstanceId: string | symbol;
|
selectedInstanceId: string;
|
||||||
onOptionChange(server: string, instanceId?: string | symbol): void;
|
onOptionChange(server: string, instanceId?: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This dropdown sources homeservers from three places:
|
// This dropdown sources homeservers from three places:
|
||||||
|
@ -171,7 +171,7 @@ const NetworkDropdown = ({ onOptionChange, protocols = {}, selectedServerName, s
|
||||||
|
|
||||||
const protocolsList = server === hsName ? Object.values(protocols) : [];
|
const protocolsList = server === hsName ? Object.values(protocols) : [];
|
||||||
if (protocolsList.length > 0) {
|
if (protocolsList.length > 0) {
|
||||||
// add a fake protocol with the ALL_ROOMS symbol
|
// add a fake protocol with ALL_ROOMS
|
||||||
protocolsList.push({
|
protocolsList.push({
|
||||||
instances: [{
|
instances: [{
|
||||||
fields: [],
|
fields: [],
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React, { ReactHTML } from 'react';
|
||||||
|
|
||||||
import { Key } from '../../../Keyboard';
|
import { Key } from '../../../Keyboard';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
@ -29,7 +29,7 @@ export type ButtonEvent = React.MouseEvent<Element> | React.KeyboardEvent<Elemen
|
||||||
*/
|
*/
|
||||||
interface IProps extends React.InputHTMLAttributes<Element> {
|
interface IProps extends React.InputHTMLAttributes<Element> {
|
||||||
inputRef?: React.Ref<Element>;
|
inputRef?: React.Ref<Element>;
|
||||||
element?: string;
|
element?: keyof ReactHTML;
|
||||||
// The kind of button, similar to how Bootstrap works.
|
// The kind of button, similar to how Bootstrap works.
|
||||||
// See available classes for AccessibleButton for options.
|
// See available classes for AccessibleButton for options.
|
||||||
kind?: string;
|
kind?: string;
|
||||||
|
@ -122,7 +122,7 @@ export default function AccessibleButton({
|
||||||
}
|
}
|
||||||
|
|
||||||
AccessibleButton.defaultProps = {
|
AccessibleButton.defaultProps = {
|
||||||
element: 'div',
|
element: 'div' as keyof ReactHTML,
|
||||||
role: 'button',
|
role: 'button',
|
||||||
tabIndex: 0,
|
tabIndex: 0,
|
||||||
};
|
};
|
||||||
|
|
|
@ -238,6 +238,7 @@ export default class AppTile extends React.Component {
|
||||||
case 'm.sticker':
|
case 'm.sticker':
|
||||||
if (this._sgWidget.widgetApi.hasCapability(MatrixCapabilities.StickerSending)) {
|
if (this._sgWidget.widgetApi.hasCapability(MatrixCapabilities.StickerSending)) {
|
||||||
dis.dispatch({ action: 'post_sticker_message', data: payload.data });
|
dis.dispatch({ action: 'post_sticker_message', data: payload.data });
|
||||||
|
dis.dispatch({ action: 'stickerpicker_close' });
|
||||||
} else {
|
} else {
|
||||||
console.warn('Ignoring sticker message. Invalid capability');
|
console.warn('Ignoring sticker message. Invalid capability');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
/*
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { decode } from "blurhash";
|
|
||||||
|
|
||||||
interface IProps {
|
|
||||||
blurhash: string;
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class BlurhashPlaceholder extends React.PureComponent<IProps> {
|
|
||||||
private canvas: React.RefObject<HTMLCanvasElement> = React.createRef();
|
|
||||||
|
|
||||||
public componentDidMount() {
|
|
||||||
this.draw();
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentDidUpdate() {
|
|
||||||
this.draw();
|
|
||||||
}
|
|
||||||
|
|
||||||
private draw() {
|
|
||||||
if (!this.canvas.current) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const { width, height } = this.props;
|
|
||||||
|
|
||||||
const pixels = decode(this.props.blurhash, Math.ceil(width), Math.ceil(height));
|
|
||||||
const ctx = this.canvas.current.getContext("2d");
|
|
||||||
const imgData = ctx.createImageData(width, height);
|
|
||||||
imgData.data.set(pixels);
|
|
||||||
ctx.putImageData(imgData, 0, 0);
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Error rendering blurhash: ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
return <canvas height={this.props.height} width={this.props.width} ref={this.canvas} />;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -260,6 +260,7 @@ export default class Field extends React.PureComponent<PropShapes, IState> {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle displaying feedback on validity
|
// Handle displaying feedback on validity
|
||||||
|
// FIXME: Using an import will result in test failures
|
||||||
const Tooltip = sdk.getComponent("elements.Tooltip");
|
const Tooltip = sdk.getComponent("elements.Tooltip");
|
||||||
let fieldTooltip;
|
let fieldTooltip;
|
||||||
if (tooltipContent || this.state.feedback) {
|
if (tooltipContent || this.state.feedback) {
|
||||||
|
|
|
@ -334,7 +334,7 @@ export default class ReplyThread extends React.Component {
|
||||||
events,
|
events,
|
||||||
});
|
});
|
||||||
|
|
||||||
dis.fire(Action.FocusComposer);
|
dis.fire(Action.FocusSendMessageComposer);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -27,6 +27,7 @@ interface IProps {
|
||||||
value: string;
|
value: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
disabled?: boolean;
|
||||||
onChange?(value: string): void;
|
onChange?(value: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +69,7 @@ export default class RoomAliasField extends React.PureComponent<IProps, IState>
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
value={this.props.value.substring(1, this.props.value.length - this.props.domain.length - 1)}
|
value={this.props.value.substring(1, this.props.value.length - this.props.domain.length - 1)}
|
||||||
maxLength={maxlength}
|
maxLength={maxlength}
|
||||||
|
disabled={this.props.disabled}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,11 @@ limitations under the License.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import Dropdown from "../../views/elements/Dropdown";
|
import Dropdown from "../../views/elements/Dropdown";
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import PlatformPeg from "../../../PlatformPeg";
|
import PlatformPeg from "../../../PlatformPeg";
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import Spinner from "./Spinner";
|
||||||
|
|
||||||
function languageMatchesSearchQuery(query, language) {
|
function languageMatchesSearchQuery(query, language) {
|
||||||
if (language.label.toUpperCase().includes(query.toUpperCase())) return true;
|
if (language.label.toUpperCase().includes(query.toUpperCase())) return true;
|
||||||
|
@ -84,7 +84,6 @@ export default class SpellCheckLanguagesDropdown extends React.Component<SpellCh
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.state.languages === null) {
|
if (this.state.languages === null) {
|
||||||
const Spinner = sdk.getComponent('elements.Spinner');
|
|
||||||
return <Spinner />;
|
return <Spinner />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import * as sdk from "../../../index";
|
import AccessibleButton from "./AccessibleButton";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
// Whether or not this toggle is in the 'on' position.
|
// Whether or not this toggle is in the 'on' position.
|
||||||
|
@ -43,7 +43,6 @@ export default ({ checked, disabled = false, onChange, ...props }: IProps) => {
|
||||||
"mx_ToggleSwitch_enabled": !disabled,
|
"mx_ToggleSwitch_enabled": !disabled,
|
||||||
});
|
});
|
||||||
|
|
||||||
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
|
|
||||||
return (
|
return (
|
||||||
<AccessibleButton {...props}
|
<AccessibleButton {...props}
|
||||||
className={classes}
|
className={classes}
|
||||||
|
|
|
@ -16,11 +16,11 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import Tooltip from './Tooltip';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
helpText: string;
|
helpText: React.ReactNode | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
|
@ -49,7 +49,6 @@ export default class TooltipButton extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const Tooltip = sdk.getComponent("elements.Tooltip");
|
|
||||||
const tip = this.state.hover ? <Tooltip
|
const tip = this.state.hover ? <Tooltip
|
||||||
className="mx_TooltipButton_container"
|
className="mx_TooltipButton_container"
|
||||||
tooltipClassName="mx_TooltipButton_helpText"
|
tooltipClassName="mx_TooltipButton_helpText"
|
||||||
|
|
|
@ -33,7 +33,7 @@ export const EMOJI_HEIGHT = 37;
|
||||||
export const EMOJIS_PER_ROW = 8;
|
export const EMOJIS_PER_ROW = 8;
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
selectedEmojis: Set<string>;
|
selectedEmojis?: Set<string>;
|
||||||
showQuickReactions?: boolean;
|
showQuickReactions?: boolean;
|
||||||
onChoose(unicode: string): boolean;
|
onChoose(unicode: string): boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import EmojiPicker from "./EmojiPicker";
|
||||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
import dis from "../../../dispatcher/dispatcher";
|
import dis from "../../../dispatcher/dispatcher";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import { Action } from '../../../dispatcher/actions';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
mxEvent: MatrixEvent;
|
mxEvent: MatrixEvent;
|
||||||
|
@ -93,6 +94,7 @@ class ReactionPicker extends React.Component<IProps, IState> {
|
||||||
this.props.mxEvent.getRoomId(),
|
this.props.mxEvent.getRoomId(),
|
||||||
myReactions[reaction],
|
myReactions[reaction],
|
||||||
);
|
);
|
||||||
|
dis.dispatch({ action: Action.FocusAComposer });
|
||||||
// Tell the emoji picker not to bump this in the more frequently used list.
|
// Tell the emoji picker not to bump this in the more frequently used list.
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -104,6 +106,7 @@ class ReactionPicker extends React.Component<IProps, IState> {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
dis.dispatch({ action: "message_sent" });
|
dis.dispatch({ action: "message_sent" });
|
||||||
|
dis.dispatch({ action: Action.FocusAComposer });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,6 +18,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React, { createRef } from 'react';
|
import React, { createRef } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import { Blurhash } from "react-blurhash";
|
||||||
|
|
||||||
import MFileBody from './MFileBody';
|
import MFileBody from './MFileBody';
|
||||||
import Modal from '../../../Modal';
|
import Modal from '../../../Modal';
|
||||||
|
@ -29,7 +30,6 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||||
import InlineSpinner from '../elements/InlineSpinner';
|
import InlineSpinner from '../elements/InlineSpinner';
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { mediaFromContent } from "../../../customisations/Media";
|
import { mediaFromContent } from "../../../customisations/Media";
|
||||||
import BlurhashPlaceholder from "../elements/BlurhashPlaceholder";
|
|
||||||
import { BLURHASH_FIELD } from "../../../ContentMessages";
|
import { BLURHASH_FIELD } from "../../../ContentMessages";
|
||||||
|
|
||||||
@replaceableComponent("views.messages.MImageBody")
|
@replaceableComponent("views.messages.MImageBody")
|
||||||
|
@ -436,7 +436,7 @@ export default class MImageBody extends React.Component {
|
||||||
// Overidden by MStickerBody
|
// Overidden by MStickerBody
|
||||||
getPlaceholder(width, height) {
|
getPlaceholder(width, height) {
|
||||||
const blurhash = this.props.mxEvent.getContent().info[BLURHASH_FIELD];
|
const blurhash = this.props.mxEvent.getContent().info[BLURHASH_FIELD];
|
||||||
if (blurhash) return <BlurhashPlaceholder blurhash={blurhash} width={width} height={height} />;
|
if (blurhash) return <Blurhash hash={blurhash} width={width} height={height} />;
|
||||||
return <div className="mx_MImageBody_thumbnail_spinner">
|
return <div className="mx_MImageBody_thumbnail_spinner">
|
||||||
<InlineSpinner w={32} h={32} />
|
<InlineSpinner w={32} h={32} />
|
||||||
</div>;
|
</div>;
|
||||||
|
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { MatrixEvent } from 'matrix-js-sdk/src';
|
import { MatrixEvent } from 'matrix-js-sdk/src';
|
||||||
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import { getNameForEventRoom, userLabelForEventRoom }
|
import { getNameForEventRoom, userLabelForEventRoom }
|
||||||
from '../../../utils/KeyVerificationStateObserver';
|
from '../../../utils/KeyVerificationStateObserver';
|
||||||
|
@ -26,6 +25,7 @@ import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
||||||
import { Action } from "../../../dispatcher/actions";
|
import { Action } from "../../../dispatcher/actions";
|
||||||
import EventTileBubble from "./EventTileBubble";
|
import EventTileBubble from "./EventTileBubble";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import AccessibleButton from '../elements/AccessibleButton';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
mxEvent: MatrixEvent;
|
mxEvent: MatrixEvent;
|
||||||
|
@ -115,8 +115,6 @@ export default class MKeyVerificationRequest extends React.Component<IProps> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
|
|
||||||
|
|
||||||
const { mxEvent } = this.props;
|
const { mxEvent } = this.props;
|
||||||
const request = mxEvent.verificationRequest;
|
const request = mxEvent.verificationRequest;
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
mxEvent: MatrixEvent;
|
mxEvent: MatrixEvent;
|
||||||
onClick(): void;
|
onClick?(): void;
|
||||||
enableFlair: boolean;
|
enableFlair: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ import Spoiler from "../elements/Spoiler";
|
||||||
import QuestionDialog from "../dialogs/QuestionDialog";
|
import QuestionDialog from "../dialogs/QuestionDialog";
|
||||||
import MessageEditHistoryDialog from "../dialogs/MessageEditHistoryDialog";
|
import MessageEditHistoryDialog from "../dialogs/MessageEditHistoryDialog";
|
||||||
import EditMessageComposer from '../rooms/EditMessageComposer';
|
import EditMessageComposer from '../rooms/EditMessageComposer';
|
||||||
import LinkPreviewWidget from '../rooms/LinkPreviewWidget';
|
import LinkPreviewGroup from '../rooms/LinkPreviewGroup';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
/* the MatrixEvent to show */
|
/* the MatrixEvent to show */
|
||||||
|
@ -244,7 +244,11 @@ export default class TextualBody extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private highlightCode(code: HTMLElement): void {
|
private highlightCode(code: HTMLElement): void {
|
||||||
if (SettingsStore.getValue("enableSyntaxHighlightLanguageDetection")) {
|
// Auto-detect language only if enabled and only for codeblocks
|
||||||
|
if (
|
||||||
|
SettingsStore.getValue("enableSyntaxHighlightLanguageDetection") &&
|
||||||
|
code.parentElement instanceof HTMLPreElement
|
||||||
|
) {
|
||||||
highlight.highlightBlock(code);
|
highlight.highlightBlock(code);
|
||||||
} else {
|
} else {
|
||||||
// Only syntax highlight if there's a class starting with language-
|
// Only syntax highlight if there's a class starting with language-
|
||||||
|
@ -294,14 +298,8 @@ export default class TextualBody extends React.Component<IProps, IState> {
|
||||||
// pass only the first child which is the event tile otherwise this recurses on edited events
|
// pass only the first child which is the event tile otherwise this recurses on edited events
|
||||||
let links = this.findLinks([this.contentRef.current]);
|
let links = this.findLinks([this.contentRef.current]);
|
||||||
if (links.length) {
|
if (links.length) {
|
||||||
// de-duplicate the links after stripping hashes as they don't affect the preview
|
// de-duplicate the links using a set here maintains the order
|
||||||
// using a set here maintains the order
|
links = Array.from(new Set(links));
|
||||||
links = Array.from(new Set(links.map(link => {
|
|
||||||
const url = new URL(link);
|
|
||||||
url.hash = "";
|
|
||||||
return url.toString();
|
|
||||||
})));
|
|
||||||
|
|
||||||
this.setState({ links });
|
this.setState({ links });
|
||||||
|
|
||||||
// lazy-load the hidden state of the preview widget from localstorage
|
// lazy-load the hidden state of the preview widget from localstorage
|
||||||
|
@ -530,15 +528,12 @@ export default class TextualBody extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
let widgets;
|
let widgets;
|
||||||
if (this.state.links.length && !this.state.widgetHidden && this.props.showUrlPreview) {
|
if (this.state.links.length && !this.state.widgetHidden && this.props.showUrlPreview) {
|
||||||
widgets = this.state.links.map((link)=>{
|
widgets = <LinkPreviewGroup
|
||||||
return <LinkPreviewWidget
|
links={this.state.links}
|
||||||
key={link}
|
mxEvent={this.props.mxEvent}
|
||||||
link={link}
|
onCancelClick={this.onCancelClick}
|
||||||
mxEvent={this.props.mxEvent}
|
onHeightChanged={this.props.onHeightChanged}
|
||||||
onCancelClick={this.onCancelClick}
|
/>;
|
||||||
onHeightChanged={this.props.onHeightChanged}
|
|
||||||
/>;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (content.msgtype) {
|
switch (content.msgtype) {
|
||||||
|
|
|
@ -16,13 +16,13 @@ limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import * as sdk from "../../../index";
|
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||||
import { User } from "matrix-js-sdk/src/models/user";
|
import { User } from "matrix-js-sdk/src/models/user";
|
||||||
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
|
import Spinner from "../elements/Spinner";
|
||||||
|
|
||||||
export const PendingActionSpinner = ({ text }) => {
|
export const PendingActionSpinner = ({ text }) => {
|
||||||
const Spinner = sdk.getComponent('elements.Spinner');
|
|
||||||
return <div className="mx_EncryptionInfo_spinner">
|
return <div className="mx_EncryptionInfo_spinner">
|
||||||
<Spinner />
|
<Spinner />
|
||||||
{ text }
|
{ text }
|
||||||
|
@ -64,7 +64,6 @@ const EncryptionInfo: React.FC<IProps> = ({
|
||||||
}
|
}
|
||||||
content = <PendingActionSpinner text={text} />;
|
content = <PendingActionSpinner text={text} />;
|
||||||
} else {
|
} else {
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
|
||||||
content = (
|
content = (
|
||||||
<AccessibleButton kind="primary" className="mx_UserInfo_wideButton" onClick={onStartVerification}>
|
<AccessibleButton kind="primary" className="mx_UserInfo_wideButton" onClick={onStartVerification}>
|
||||||
{_t("Start Verification")}
|
{_t("Start Verification")}
|
||||||
|
|
|
@ -81,6 +81,7 @@ const EncryptionPanel: React.FC<IProps> = (props: IProps) => {
|
||||||
const changeHandler = useCallback(() => {
|
const changeHandler = useCallback(() => {
|
||||||
// handle transitions -> cancelled for mismatches which fire a modal instead of showing a card
|
// handle transitions -> cancelled for mismatches which fire a modal instead of showing a card
|
||||||
if (request && request.cancelled && MISMATCHES.includes(request.cancellationCode)) {
|
if (request && request.cancelled && MISMATCHES.includes(request.cancellationCode)) {
|
||||||
|
// FIXME: Using an import will result in test failures
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createTrackedDialog("Verification failed", "insecure", ErrorDialog, {
|
Modal.createTrackedDialog("Verification failed", "insecure", ErrorDialog, {
|
||||||
headerImage: require("../../../../res/img/e2e/warning.svg"),
|
headerImage: require("../../../../res/img/e2e/warning.svg"),
|
||||||
|
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import { verificationMethods } from 'matrix-js-sdk/src/crypto';
|
import { verificationMethods } from 'matrix-js-sdk/src/crypto';
|
||||||
import { SCAN_QR_CODE_METHOD } from "matrix-js-sdk/src/crypto/verification/QRCode";
|
import { SCAN_QR_CODE_METHOD } from "matrix-js-sdk/src/crypto/verification/QRCode";
|
||||||
import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
||||||
|
@ -38,6 +37,8 @@ import {
|
||||||
} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
||||||
import Spinner from "../elements/Spinner";
|
import Spinner from "../elements/Spinner";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
|
import VerificationShowSas from "../verification/VerificationShowSas";
|
||||||
|
|
||||||
// XXX: Should be defined in matrix-js-sdk
|
// XXX: Should be defined in matrix-js-sdk
|
||||||
enum VerificationPhase {
|
enum VerificationPhase {
|
||||||
|
@ -81,7 +82,6 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
|
||||||
const { member, request } = this.props;
|
const { member, request } = this.props;
|
||||||
const showSAS: boolean = request.otherPartySupportsMethod(verificationMethods.SAS);
|
const showSAS: boolean = request.otherPartySupportsMethod(verificationMethods.SAS);
|
||||||
const showQR: boolean = request.otherPartySupportsMethod(SCAN_QR_CODE_METHOD);
|
const showQR: boolean = request.otherPartySupportsMethod(SCAN_QR_CODE_METHOD);
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
|
||||||
const brand = SdkConfig.get().brand;
|
const brand = SdkConfig.get().brand;
|
||||||
|
|
||||||
const noCommonMethodError: JSX.Element = !showSAS && !showQR ?
|
const noCommonMethodError: JSX.Element = !showSAS && !showQR ?
|
||||||
|
@ -195,7 +195,6 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
|
||||||
|
|
||||||
private renderQRReciprocatePhase() {
|
private renderQRReciprocatePhase() {
|
||||||
const { member, request } = this.props;
|
const { member, request } = this.props;
|
||||||
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
|
|
||||||
const description = request.isSelfVerification ?
|
const description = request.isSelfVerification ?
|
||||||
_t("Almost there! Is your other session showing the same shield?") :
|
_t("Almost there! Is your other session showing the same shield?") :
|
||||||
_t("Almost there! Is %(displayName)s showing the same shield?", {
|
_t("Almost there! Is %(displayName)s showing the same shield?", {
|
||||||
|
@ -265,7 +264,6 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_UserInfo_container mx_VerificationPanel_verified_section">
|
<div className="mx_UserInfo_container mx_VerificationPanel_verified_section">
|
||||||
<h3>{_t("Verified")}</h3>
|
<h3>{_t("Verified")}</h3>
|
||||||
|
@ -282,8 +280,6 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
|
||||||
private renderCancelledPhase() {
|
private renderCancelledPhase() {
|
||||||
const { member, request } = this.props;
|
const { member, request } = this.props;
|
||||||
|
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
|
||||||
|
|
||||||
let startAgainInstruction: string;
|
let startAgainInstruction: string;
|
||||||
if (request.isSelfVerification) {
|
if (request.isSelfVerification) {
|
||||||
startAgainInstruction = _t("Start verification again from the notification.");
|
startAgainInstruction = _t("Start verification again from the notification.");
|
||||||
|
@ -332,7 +328,6 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
|
||||||
case verificationMethods.RECIPROCATE_QR_CODE:
|
case verificationMethods.RECIPROCATE_QR_CODE:
|
||||||
return this.renderQRReciprocatePhase();
|
return this.renderQRReciprocatePhase();
|
||||||
case verificationMethods.SAS: {
|
case verificationMethods.SAS: {
|
||||||
const VerificationShowSas = sdk.getComponent('views.verification.VerificationShowSas');
|
|
||||||
const emojis = this.state.sasEvent ?
|
const emojis = this.state.sasEvent ?
|
||||||
<VerificationShowSas
|
<VerificationShowSas
|
||||||
displayName={displayName}
|
displayName={displayName}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue