Merge remote-tracking branch 'upstream/develop' into ts/address-stuff
This commit is contained in:
commit
b1f4ba28d7
281 changed files with 2816 additions and 2309 deletions
|
@ -46,6 +46,7 @@
|
||||||
"start:build": "babel src -w -s -d lib --verbose --extensions \".ts,.js\"",
|
"start:build": "babel src -w -s -d lib --verbose --extensions \".ts,.js\"",
|
||||||
"lint": "yarn lint:types && yarn lint:js && yarn lint:style",
|
"lint": "yarn lint:types && yarn lint:js && yarn lint:style",
|
||||||
"lint:js": "eslint --max-warnings 0 src test",
|
"lint:js": "eslint --max-warnings 0 src test",
|
||||||
|
"lint:js-fix": "eslint --fix src test",
|
||||||
"lint:types": "tsc --noEmit --jsx react",
|
"lint:types": "tsc --noEmit --jsx react",
|
||||||
"lint:style": "stylelint 'res/css/**/*.scss'",
|
"lint:style": "stylelint 'res/css/**/*.scss'",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
|
|
|
@ -201,6 +201,7 @@
|
||||||
@import "./views/rooms/_EditMessageComposer.scss";
|
@import "./views/rooms/_EditMessageComposer.scss";
|
||||||
@import "./views/rooms/_EntityTile.scss";
|
@import "./views/rooms/_EntityTile.scss";
|
||||||
@import "./views/rooms/_EventTile.scss";
|
@import "./views/rooms/_EventTile.scss";
|
||||||
|
@import "./views/rooms/_EventBubbleTile.scss";
|
||||||
@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";
|
||||||
|
|
|
@ -27,6 +27,7 @@ limitations under the License.
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=255139
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=255139
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_BaseAvatar_initial {
|
.mx_BaseAvatar_initial {
|
||||||
|
|
|
@ -18,7 +18,6 @@ $timelineImageBorderRadius: 4px;
|
||||||
|
|
||||||
.mx_MImageBody {
|
.mx_MImageBody {
|
||||||
display: block;
|
display: block;
|
||||||
margin-right: 34px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MImageBody_thumbnail {
|
.mx_MImageBody_thumbnail {
|
||||||
|
|
|
@ -26,6 +26,7 @@ limitations under the License.
|
||||||
height: 24px;
|
height: 24px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
|
margin-right: 4px;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
content: '';
|
content: '';
|
||||||
|
|
323
res/css/views/rooms/_EventBubbleTile.scss
Normal file
323
res/css/views/rooms/_EventBubbleTile.scss
Normal file
|
@ -0,0 +1,323 @@
|
||||||
|
/*
|
||||||
|
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_EventTile[data-layout=bubble],
|
||||||
|
.mx_EventTile[data-layout=bubble] ~ .mx_EventListSummary {
|
||||||
|
--avatarSize: 32px;
|
||||||
|
--gutterSize: 11px;
|
||||||
|
--cornerRadius: 12px;
|
||||||
|
--maxWidth: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile[data-layout=bubble] {
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
margin-top: var(--gutterSize);
|
||||||
|
margin-left: 50px;
|
||||||
|
margin-right: 100px;
|
||||||
|
|
||||||
|
&.mx_EventTile_continuation {
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For replies */
|
||||||
|
.mx_EventTile {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: -1px;
|
||||||
|
bottom: -1px;
|
||||||
|
left: -60px;
|
||||||
|
right: -60px;
|
||||||
|
z-index: -1;
|
||||||
|
background: $eventbubble-bg-hover;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_avatar {
|
||||||
|
img {
|
||||||
|
box-shadow: 0 0 0 3px $eventbubble-bg-hover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_SenderProfile,
|
||||||
|
.mx_EventTile_line {
|
||||||
|
width: fit-content;
|
||||||
|
max-width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_SenderProfile {
|
||||||
|
position: relative;
|
||||||
|
top: -2px;
|
||||||
|
left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-self=false] {
|
||||||
|
.mx_EventTile_line {
|
||||||
|
border-bottom-right-radius: var(--cornerRadius);
|
||||||
|
}
|
||||||
|
.mx_EventTile_avatar {
|
||||||
|
left: -34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_MessageActionBar {
|
||||||
|
right: 0;
|
||||||
|
transform: translate3d(50%, 50%, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
--backgroundColor: $eventbubble-others-bg;
|
||||||
|
}
|
||||||
|
&[data-self=true] {
|
||||||
|
.mx_EventTile_line {
|
||||||
|
border-bottom-left-radius: var(--cornerRadius);
|
||||||
|
float: right;
|
||||||
|
> a {
|
||||||
|
left: auto;
|
||||||
|
right: -48px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mx_SenderProfile {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.mx_ReactionsRow {
|
||||||
|
float: right;
|
||||||
|
clear: right;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
/* Moving the "add reaction button" before the reactions */
|
||||||
|
> :last-child {
|
||||||
|
order: -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mx_EventTile_avatar {
|
||||||
|
top: -19px; // height of the sender block
|
||||||
|
right: -35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
--backgroundColor: $eventbubble-self-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_line {
|
||||||
|
position: relative;
|
||||||
|
padding: var(--gutterSize);
|
||||||
|
border-top-left-radius: var(--cornerRadius);
|
||||||
|
border-top-right-radius: var(--cornerRadius);
|
||||||
|
background: var(--backgroundColor);
|
||||||
|
display: flex;
|
||||||
|
gap: 5px;
|
||||||
|
margin: 0 -12px 0 -9px;
|
||||||
|
> a {
|
||||||
|
position: absolute;
|
||||||
|
left: -48px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_EventTile_continuation[data-self=false] .mx_EventTile_line {
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
}
|
||||||
|
&.mx_EventTile_lastInSection[data-self=false] .mx_EventTile_line {
|
||||||
|
border-bottom-left-radius: var(--cornerRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_EventTile_continuation[data-self=true] .mx_EventTile_line {
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
}
|
||||||
|
&.mx_EventTile_lastInSection[data-self=true] .mx_EventTile_line {
|
||||||
|
border-bottom-right-radius: var(--cornerRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_avatar {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
line-height: 1;
|
||||||
|
img {
|
||||||
|
box-shadow: 0 0 0 3px $eventbubble-avatar-outline;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-has-reply=true] {
|
||||||
|
> .mx_EventTile_line {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_ReplyThread_show {
|
||||||
|
order: 99999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_ReplyThread {
|
||||||
|
margin: 0 calc(-1 * var(--gutterSize));
|
||||||
|
|
||||||
|
.mx_EventTile_reply {
|
||||||
|
max-width: 90%;
|
||||||
|
padding: 0;
|
||||||
|
> a {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--gutterSize);
|
||||||
|
.mx_EventTile_avatar {
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
.mx_SenderProfile {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EditMessageComposer_buttons {
|
||||||
|
position: static;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_ReactionsRow {
|
||||||
|
margin-right: -18px;
|
||||||
|
margin-left: -9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_ReplyThread {
|
||||||
|
border-left-width: 2px;
|
||||||
|
border-left-color: $eventbubble-reply-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_EventTile_bubbleContainer,
|
||||||
|
&.mx_EventTile_info,
|
||||||
|
& ~ .mx_EventListSummary[data-expanded=false] {
|
||||||
|
--backgroundColor: transparent;
|
||||||
|
--gutterSize: 0;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.mx_EventTile_avatar {
|
||||||
|
position: static;
|
||||||
|
order: -1;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& ~ .mx_EventListSummary {
|
||||||
|
--maxWidth: 80%;
|
||||||
|
margin-left: calc(var(--avatarSize) + var(--gutterSize));
|
||||||
|
margin-right: calc(var(--gutterSize) + var(--avatarSize));
|
||||||
|
.mx_EventListSummary_toggle {
|
||||||
|
float: none;
|
||||||
|
margin: 0;
|
||||||
|
order: 9;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
.mx_EventListSummary_avatars {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile {
|
||||||
|
margin: 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_line {
|
||||||
|
margin: 0 5px;
|
||||||
|
> a {
|
||||||
|
left: auto;
|
||||||
|
right: 0;
|
||||||
|
transform: translateX(calc(100% + 5px));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_MessageActionBar {
|
||||||
|
transform: translate3d(50%, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& ~ .mx_EventListSummary[data-expanded=false] {
|
||||||
|
padding: 0 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* events that do not require bubble layout */
|
||||||
|
& ~ .mx_EventListSummary,
|
||||||
|
&.mx_EventTile_bad {
|
||||||
|
.mx_EventTile_line {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
&::before {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& + .mx_EventListSummary {
|
||||||
|
.mx_EventTile {
|
||||||
|
margin-top: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventListSummary_toggle {
|
||||||
|
margin-right: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Special layout scenario for "Unable To Decrypt (UTD)" events */
|
||||||
|
&.mx_EventTile_bad > .mx_EventTile_line {
|
||||||
|
display: grid;
|
||||||
|
grid-template:
|
||||||
|
"reply reply" auto
|
||||||
|
"shield body" auto
|
||||||
|
"shield link" auto
|
||||||
|
/ auto 1fr;
|
||||||
|
.mx_EventTile_e2eIcon {
|
||||||
|
grid-area: shield;
|
||||||
|
}
|
||||||
|
.mx_UnknownBody {
|
||||||
|
grid-area: body;
|
||||||
|
}
|
||||||
|
.mx_EventTile_keyRequestInfo {
|
||||||
|
grid-area: link;
|
||||||
|
}
|
||||||
|
.mx_ReplyThread_wrapper {
|
||||||
|
grid-area: reply;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.mx_EventTile_readAvatars {
|
||||||
|
position: absolute;
|
||||||
|
right: -110px;
|
||||||
|
bottom: 0;
|
||||||
|
top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_MTextBody {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2015, 2016 OpenMarket Ltd
|
Copyright 2015, 2016 OpenMarket Ltd
|
||||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
Copyright 2020-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.
|
||||||
|
@ -18,102 +18,305 @@ limitations under the License.
|
||||||
$left-gutter: 64px;
|
$left-gutter: 64px;
|
||||||
$hover-select-border: 4px;
|
$hover-select-border: 4px;
|
||||||
|
|
||||||
.mx_EventTile {
|
.mx_EventTile:not([data-layout=bubble]) {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
clear: both;
|
clear: both;
|
||||||
padding-top: 18px;
|
padding-top: 18px;
|
||||||
font-size: $font-14px;
|
font-size: $font-14px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile.mx_EventTile_info {
|
&.mx_EventTile_info {
|
||||||
padding-top: 1px;
|
padding-top: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_EventTile_avatar {
|
.mx_EventTile_avatar {
|
||||||
top: 14px;
|
top: 14px;
|
||||||
left: 8px;
|
left: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_EventTile.mx_EventTile_info .mx_EventTile_avatar {
|
&.mx_EventTile_info .mx_EventTile_avatar {
|
||||||
top: $font-6px;
|
top: $font-6px;
|
||||||
left: $left-gutter;
|
left: $left-gutter;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_EventTile_continuation {
|
&.mx_EventTile_continuation {
|
||||||
padding-top: 0px !important;
|
padding-top: 0px !important;
|
||||||
|
|
||||||
|
&.mx_EventTile_isEditing {
|
||||||
|
padding-top: 5px !important;
|
||||||
|
margin-top: -5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.mx_EventTile_isEditing {
|
&.mx_EventTile_isEditing {
|
||||||
padding-top: 5px !important;
|
background-color: $header-panel-bg-color;
|
||||||
margin-top: -5px;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_isEditing {
|
.mx_SenderProfile {
|
||||||
background-color: $header-panel-bg-color;
|
color: $primary-fg-color;
|
||||||
}
|
font-size: $font-14px;
|
||||||
|
display: inline-block; /* anti-zalgo, with overflow hidden */
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
padding-top: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
/* the next three lines, along with overflow hidden, truncate long display names */
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
max-width: calc(100% - $left-gutter);
|
||||||
|
}
|
||||||
|
|
||||||
.mx_EventTile .mx_SenderProfile {
|
.mx_SenderProfile .mx_Flair {
|
||||||
color: $primary-fg-color;
|
opacity: 0.7;
|
||||||
font-size: $font-14px;
|
margin-left: 5px;
|
||||||
display: inline-block; /* anti-zalgo, with overflow hidden */
|
display: inline-block;
|
||||||
overflow: hidden;
|
vertical-align: top;
|
||||||
cursor: pointer;
|
overflow: hidden;
|
||||||
padding-bottom: 0px;
|
user-select: none;
|
||||||
padding-top: 0px;
|
|
||||||
margin: 0px;
|
|
||||||
/* the next three lines, along with overflow hidden, truncate long display names */
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
max-width: calc(100% - $left-gutter);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile .mx_SenderProfile .mx_Flair {
|
img {
|
||||||
opacity: 0.7;
|
vertical-align: -2px;
|
||||||
margin-left: 5px;
|
margin-right: 2px;
|
||||||
display: inline-block;
|
border-radius: 8px;
|
||||||
vertical-align: top;
|
}
|
||||||
overflow: hidden;
|
}
|
||||||
user-select: none;
|
|
||||||
|
|
||||||
img {
|
&.mx_EventTile_isEditing .mx_MessageTimestamp {
|
||||||
vertical-align: -2px;
|
visibility: hidden;
|
||||||
margin-right: 2px;
|
}
|
||||||
|
|
||||||
|
.mx_MessageTimestamp {
|
||||||
|
display: block;
|
||||||
|
white-space: nowrap;
|
||||||
|
left: 0px;
|
||||||
|
text-align: center;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_EventTile_continuation .mx_EventTile_line {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_line, .mx_EventTile_reply {
|
||||||
|
position: relative;
|
||||||
|
padding-left: $left-gutter;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_isEditing .mx_MessageTimestamp {
|
.mx_EventTile_reply {
|
||||||
visibility: hidden;
|
margin-right: 10px;
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile .mx_MessageTimestamp {
|
|
||||||
display: block;
|
|
||||||
white-space: nowrap;
|
|
||||||
left: 0px;
|
|
||||||
text-align: center;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_continuation .mx_EventTile_line {
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_line, .mx_EventTile_reply {
|
|
||||||
position: relative;
|
|
||||||
padding-left: $left-gutter;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_RoomView_timeline_rr_enabled,
|
|
||||||
// on ELS we need the margin to allow interaction with the expand/collapse button which is normally in the RR gutter
|
|
||||||
.mx_EventListSummary {
|
|
||||||
.mx_EventTile_line {
|
|
||||||
/* ideally should be 100px, but 95px gives us a max thumbnail size of 800x600, which is nice */
|
|
||||||
margin-right: 110px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.mx_EventTile_selected > div > a > .mx_MessageTimestamp {
|
||||||
|
left: calc(-$hover-select-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this is used for the tile for the event which is selected via the URL.
|
||||||
|
* TODO: ultimately we probably want some transition on here.
|
||||||
|
*/
|
||||||
|
&.mx_EventTile_selected > .mx_EventTile_line {
|
||||||
|
border-left: $accent-color 4px solid;
|
||||||
|
padding-left: calc($left-gutter - $hover-select-border);
|
||||||
|
background-color: $event-selected-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_EventTile_highlight,
|
||||||
|
&.mx_EventTile_highlight .markdown-body {
|
||||||
|
color: $event-highlight-fg-color;
|
||||||
|
|
||||||
|
.mx_EventTile_line {
|
||||||
|
background-color: $event-highlight-bg-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_EventTile_info .mx_EventTile_line {
|
||||||
|
padding-left: calc($left-gutter + 18px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_EventTile_selected.mx_EventTile_info .mx_EventTile_line {
|
||||||
|
padding-left: calc($left-gutter + 18px - $hover-select-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_EventTile:hover .mx_EventTile_line,
|
||||||
|
&.mx_EventTile.mx_EventTile_actionBarFocused .mx_EventTile_line,
|
||||||
|
&.mx_EventTile.focus-visible:focus-within .mx_EventTile_line {
|
||||||
|
background-color: $event-selected-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_searchHighlight {
|
||||||
|
background-color: $accent-color;
|
||||||
|
color: $accent-fg-color;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding-left: 2px;
|
||||||
|
padding-right: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_searchHighlight a {
|
||||||
|
background-color: $accent-color;
|
||||||
|
color: $accent-fg-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_receiptSent,
|
||||||
|
.mx_EventTile_receiptSending {
|
||||||
|
// We don't use `position: relative` on the element because then it won't line
|
||||||
|
// up with the other read receipts
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
background-color: $tertiary-fg-color;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-position: center;
|
||||||
|
mask-size: 14px;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mx_EventTile_receiptSent::before {
|
||||||
|
mask-image: url('$(res)/img/element-icons/circle-sent.svg');
|
||||||
|
}
|
||||||
|
.mx_EventTile_receiptSending::before {
|
||||||
|
mask-image: url('$(res)/img/element-icons/circle-sending.svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_EventTile_contextual {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_msgOption {
|
||||||
|
float: right;
|
||||||
|
text-align: right;
|
||||||
|
position: relative;
|
||||||
|
width: 90px;
|
||||||
|
|
||||||
|
/* Hack to stop the height of this pushing the messages apart.
|
||||||
|
Replaces margin-top: -6px. This interacts better with a read
|
||||||
|
marker being in between. Content overflows. */
|
||||||
|
height: 1px;
|
||||||
|
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_msgOption a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* all the overflow-y: hidden; are to trap Zalgos -
|
||||||
|
but they introduce an implicit overflow-x: auto.
|
||||||
|
so make that explicitly hidden too to avoid random
|
||||||
|
horizontal scrollbars occasionally appearing, like in
|
||||||
|
https://github.com/vector-im/vector-web/issues/1154
|
||||||
|
*/
|
||||||
|
.mx_EventTile_content {
|
||||||
|
display: block;
|
||||||
|
overflow-y: hidden;
|
||||||
|
overflow-x: hidden;
|
||||||
|
margin-right: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* De-zalgoing */
|
||||||
|
.mx_EventTile_body {
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spoiler stuff */
|
||||||
|
.mx_EventTile_spoiler {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_spoiler_reason {
|
||||||
|
color: $event-timestamp-color;
|
||||||
|
font-size: $font-11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_spoiler_content {
|
||||||
|
filter: blur(5px) saturate(0.1) sepia(1);
|
||||||
|
transition-duration: 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_spoiler.visible > .mx_EventTile_spoiler_content {
|
||||||
|
filter: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover.mx_EventTile_verified .mx_EventTile_line,
|
||||||
|
&:hover.mx_EventTile_unverified .mx_EventTile_line,
|
||||||
|
&:hover.mx_EventTile_unknown .mx_EventTile_line {
|
||||||
|
padding-left: calc($left-gutter - $hover-select-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover.mx_EventTile_verified .mx_EventTile_line {
|
||||||
|
border-left: $e2e-verified-color $EventTile_e2e_state_indicator_width solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover.mx_EventTile_unverified .mx_EventTile_line {
|
||||||
|
border-left: $e2e-unverified-color $EventTile_e2e_state_indicator_width solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover.mx_EventTile_unknown .mx_EventTile_line {
|
||||||
|
border-left: $e2e-unknown-color $EventTile_e2e_state_indicator_width solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover.mx_EventTile_verified.mx_EventTile_info .mx_EventTile_line,
|
||||||
|
&:hover.mx_EventTile_unverified.mx_EventTile_info .mx_EventTile_line,
|
||||||
|
&:hover.mx_EventTile_unknown.mx_EventTile_info .mx_EventTile_line {
|
||||||
|
padding-left: calc($left-gutter + 18px - $hover-select-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End to end encryption stuff */
|
||||||
|
&:hover .mx_EventTile_e2eIcon {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explicit relationships so that it doesn't apply to nested EventTile components (e.g in Replies)
|
||||||
|
&:hover.mx_EventTile_verified .mx_EventTile_line > a > .mx_MessageTimestamp,
|
||||||
|
&:hover.mx_EventTile_unverified .mx_EventTile_line > a > .mx_MessageTimestamp,
|
||||||
|
&:hover.mx_EventTile_unknown .mx_EventTile_line > a > .mx_MessageTimestamp {
|
||||||
|
left: calc(-$hover-select-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explicit relationships so that it doesn't apply to nested EventTile components (e.g in Replies)
|
||||||
|
&:hover.mx_EventTile_verified .mx_EventTile_line > .mx_EventTile_e2eIcon,
|
||||||
|
&:hover.mx_EventTile_unverified .mx_EventTile_line > .mx_EventTile_e2eIcon,
|
||||||
|
&:hover.mx_EventTile_unknown .mx_EventTile_line > .mx_EventTile_e2eIcon {
|
||||||
|
display: block;
|
||||||
|
left: 41px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_MImageBody {
|
||||||
|
margin-right: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_e2eIcon {
|
||||||
|
position: absolute;
|
||||||
|
top: 6px;
|
||||||
|
left: 44px;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_ReactionsRow {
|
||||||
|
margin: 0;
|
||||||
|
padding: 6px 60px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomView_timeline_rr_enabled {
|
||||||
|
|
||||||
|
.mx_EventTile:not([data-layout=bubble]) {
|
||||||
|
.mx_EventTile_line {
|
||||||
|
/* ideally should be 100px, but 95px gives us a max thumbnail size of 800x600, which is nice */
|
||||||
|
margin-right: 110px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// on ELS we need the margin to allow interaction with the expand/collapse button which is normally in the RR gutter
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_EventTile_bubbleContainer {
|
.mx_EventTile_bubbleContainer {
|
||||||
|
@ -132,121 +335,6 @@ $hover-select-border: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_EventTile_reply {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HACK to override line-height which is already marked important elsewhere */
|
|
||||||
.mx_EventTile_bigEmoji.mx_EventTile_bigEmoji {
|
|
||||||
font-size: 48px !important;
|
|
||||||
line-height: 57px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_selected > div > a > .mx_MessageTimestamp {
|
|
||||||
left: calc(-$hover-select-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile:hover .mx_MessageActionBar,
|
|
||||||
.mx_EventTile.mx_EventTile_actionBarFocused .mx_MessageActionBar,
|
|
||||||
[data-whatinput='keyboard'] .mx_EventTile:focus-within .mx_MessageActionBar,
|
|
||||||
.mx_EventTile.focus-visible:focus-within .mx_MessageActionBar {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this is used for the tile for the event which is selected via the URL.
|
|
||||||
* TODO: ultimately we probably want some transition on here.
|
|
||||||
*/
|
|
||||||
.mx_EventTile_selected > .mx_EventTile_line {
|
|
||||||
border-left: $accent-color 4px solid;
|
|
||||||
padding-left: calc($left-gutter - $hover-select-border);
|
|
||||||
background-color: $event-selected-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_highlight,
|
|
||||||
.mx_EventTile_highlight .markdown-body {
|
|
||||||
color: $event-highlight-fg-color;
|
|
||||||
|
|
||||||
.mx_EventTile_line {
|
|
||||||
background-color: $event-highlight-bg-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_info .mx_EventTile_line {
|
|
||||||
padding-left: calc($left-gutter + 18px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_selected.mx_EventTile_info .mx_EventTile_line {
|
|
||||||
padding-left: calc($left-gutter + 18px - $hover-select-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile:hover .mx_EventTile_line,
|
|
||||||
.mx_EventTile.mx_EventTile_actionBarFocused .mx_EventTile_line,
|
|
||||||
.mx_EventTile.focus-visible:focus-within .mx_EventTile_line {
|
|
||||||
background-color: $event-selected-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_searchHighlight {
|
|
||||||
background-color: $accent-color;
|
|
||||||
color: $accent-fg-color;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding-left: 2px;
|
|
||||||
padding-right: 2px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_searchHighlight a {
|
|
||||||
background-color: $accent-color;
|
|
||||||
color: $accent-fg-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_receiptSent,
|
|
||||||
.mx_EventTile_receiptSending {
|
|
||||||
// We don't use `position: relative` on the element because then it won't line
|
|
||||||
// up with the other read receipts
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
background-color: $tertiary-fg-color;
|
|
||||||
mask-repeat: no-repeat;
|
|
||||||
mask-position: center;
|
|
||||||
mask-size: 14px;
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.mx_EventTile_receiptSent::before {
|
|
||||||
mask-image: url('$(res)/img/element-icons/circle-sent.svg');
|
|
||||||
}
|
|
||||||
.mx_EventTile_receiptSending::before {
|
|
||||||
mask-image: url('$(res)/img/element-icons/circle-sending.svg');
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_contextual {
|
|
||||||
opacity: 0.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_msgOption {
|
|
||||||
float: right;
|
|
||||||
text-align: right;
|
|
||||||
position: relative;
|
|
||||||
width: 90px;
|
|
||||||
|
|
||||||
/* Hack to stop the height of this pushing the messages apart.
|
|
||||||
Replaces margin-top: -6px. This interacts better with a read
|
|
||||||
marker being in between. Content overflows. */
|
|
||||||
height: 1px;
|
|
||||||
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_msgOption a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_readAvatars {
|
.mx_EventTile_readAvatars {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -277,52 +365,27 @@ $hover-select-border: 4px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* all the overflow-y: hidden; are to trap Zalgos -
|
/* HACK to override line-height which is already marked important elsewhere */
|
||||||
but they introduce an implicit overflow-x: auto.
|
.mx_EventTile_bigEmoji.mx_EventTile_bigEmoji {
|
||||||
so make that explicitly hidden too to avoid random
|
font-size: 48px !important;
|
||||||
horizontal scrollbars occasionally appearing, like in
|
line-height: 57px !important;
|
||||||
https://github.com/vector-im/vector-web/issues/1154
|
|
||||||
*/
|
|
||||||
.mx_EventTile_content {
|
|
||||||
display: block;
|
|
||||||
overflow-y: hidden;
|
|
||||||
overflow-x: hidden;
|
|
||||||
margin-right: 34px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* De-zalgoing */
|
.mx_EventTile_content .mx_EventTile_edited {
|
||||||
.mx_EventTile_body {
|
user-select: none;
|
||||||
overflow-y: hidden;
|
font-size: $font-12px;
|
||||||
}
|
color: $roomtopic-color;
|
||||||
|
display: inline-block;
|
||||||
/* Spoiler stuff */
|
margin-left: 9px;
|
||||||
.mx_EventTile_spoiler {
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_EventTile_spoiler_reason {
|
|
||||||
color: $event-timestamp-color;
|
|
||||||
font-size: $font-11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_spoiler_content {
|
|
||||||
filter: blur(5px) saturate(0.1) sepia(1);
|
|
||||||
transition-duration: 0.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_spoiler.visible > .mx_EventTile_spoiler_content {
|
|
||||||
filter: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_e2eIcon {
|
.mx_EventTile_e2eIcon {
|
||||||
position: absolute;
|
position: relative;
|
||||||
top: 6px;
|
|
||||||
left: 44px;
|
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
display: block;
|
display: block;
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
opacity: 0.2;
|
opacity: 0.2;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
|
@ -381,87 +444,6 @@ $hover-select-border: 4px;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_EventTile_keyRequestInfo {
|
|
||||||
font-size: $font-12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_keyRequestInfo_text {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_keyRequestInfo_text a {
|
|
||||||
color: $primary-fg-color;
|
|
||||||
text-decoration: underline;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_keyRequestInfo_tooltip_contents p {
|
|
||||||
text-align: auto;
|
|
||||||
margin-left: 3px;
|
|
||||||
margin-right: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_keyRequestInfo_tooltip_contents p:first-child {
|
|
||||||
margin-top: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_keyRequestInfo_tooltip_contents p:last-child {
|
|
||||||
margin-bottom: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line,
|
|
||||||
.mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line,
|
|
||||||
.mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line {
|
|
||||||
padding-left: calc($left-gutter - $hover-select-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line {
|
|
||||||
border-left: $e2e-verified-color $EventTile_e2e_state_indicator_width solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line {
|
|
||||||
border-left: $e2e-unverified-color $EventTile_e2e_state_indicator_width solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line {
|
|
||||||
border-left: $e2e-unknown-color $EventTile_e2e_state_indicator_width solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile:hover.mx_EventTile_verified.mx_EventTile_info .mx_EventTile_line,
|
|
||||||
.mx_EventTile:hover.mx_EventTile_unverified.mx_EventTile_info .mx_EventTile_line,
|
|
||||||
.mx_EventTile:hover.mx_EventTile_unknown.mx_EventTile_info .mx_EventTile_line {
|
|
||||||
padding-left: calc($left-gutter + 18px - $hover-select-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* End to end encryption stuff */
|
|
||||||
.mx_EventTile:hover .mx_EventTile_e2eIcon {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Explicit relationships so that it doesn't apply to nested EventTile components (e.g in Replies)
|
|
||||||
.mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line > a > .mx_MessageTimestamp,
|
|
||||||
.mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line > a > .mx_MessageTimestamp,
|
|
||||||
.mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line > a > .mx_MessageTimestamp {
|
|
||||||
left: calc(-$hover-select-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Explicit relationships so that it doesn't apply to nested EventTile components (e.g in Replies)
|
|
||||||
.mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line > .mx_EventTile_e2eIcon,
|
|
||||||
.mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line > .mx_EventTile_e2eIcon,
|
|
||||||
.mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line > .mx_EventTile_e2eIcon {
|
|
||||||
display: block;
|
|
||||||
left: 41px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_EventTile_content .mx_EventTile_edited {
|
|
||||||
user-select: none;
|
|
||||||
font-size: $font-12px;
|
|
||||||
color: $roomtopic-color;
|
|
||||||
display: inline-block;
|
|
||||||
margin-left: 9px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Various markdown overrides */
|
/* Various markdown overrides */
|
||||||
|
|
||||||
.mx_EventTile_body pre {
|
.mx_EventTile_body pre {
|
||||||
|
@ -595,6 +577,35 @@ $hover-select-border: 4px;
|
||||||
|
|
||||||
/* end of overrides */
|
/* end of overrides */
|
||||||
|
|
||||||
|
|
||||||
|
.mx_EventTile_keyRequestInfo {
|
||||||
|
font-size: $font-12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_keyRequestInfo_text {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_keyRequestInfo_text a {
|
||||||
|
color: $primary-fg-color;
|
||||||
|
text-decoration: underline;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_keyRequestInfo_tooltip_contents p {
|
||||||
|
text-align: auto;
|
||||||
|
margin-left: 3px;
|
||||||
|
margin-right: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_keyRequestInfo_tooltip_contents p:first-child {
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_keyRequestInfo_tooltip_contents p:last-child {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_EventTile_tileError {
|
.mx_EventTile_tileError {
|
||||||
color: red;
|
color: red;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -615,6 +626,13 @@ $hover-select-border: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_EventTile:hover .mx_MessageActionBar,
|
||||||
|
.mx_EventTile.mx_EventTile_actionBarFocused .mx_MessageActionBar,
|
||||||
|
[data-whatinput='keyboard'] .mx_EventTile:focus-within .mx_MessageActionBar,
|
||||||
|
.mx_EventTile.focus-visible:focus-within .mx_MessageActionBar {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 480px) {
|
@media only screen and (max-width: 480px) {
|
||||||
.mx_EventTile_line, .mx_EventTile_reply {
|
.mx_EventTile_line, .mx_EventTile_reply {
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
|
|
|
@ -227,6 +227,13 @@ $groupFilterPanel-background-blur-amount: 30px;
|
||||||
|
|
||||||
$composer-shadow-color: rgba(0, 0, 0, 0.28);
|
$composer-shadow-color: rgba(0, 0, 0, 0.28);
|
||||||
|
|
||||||
|
// Bubble tiles
|
||||||
|
$eventbubble-self-bg: #143A34;
|
||||||
|
$eventbubble-others-bg: #394049;
|
||||||
|
$eventbubble-bg-hover: #433C23;
|
||||||
|
$eventbubble-avatar-outline: $bg-color;
|
||||||
|
$eventbubble-reply-color: #C1C6CD;
|
||||||
|
|
||||||
// ***** Mixins! *****
|
// ***** Mixins! *****
|
||||||
|
|
||||||
@define-mixin mx_DialogButton {
|
@define-mixin mx_DialogButton {
|
||||||
|
|
|
@ -347,6 +347,13 @@ $appearance-tab-border-color: $input-darker-bg-color;
|
||||||
|
|
||||||
$composer-shadow-color: tranparent;
|
$composer-shadow-color: tranparent;
|
||||||
|
|
||||||
|
// Bubble tiles
|
||||||
|
$eventbubble-self-bg: #F8FDFC;
|
||||||
|
$eventbubble-others-bg: #F7F8F9;
|
||||||
|
$eventbubble-bg-hover: rgb(242, 242, 242);
|
||||||
|
$eventbubble-avatar-outline: #fff;
|
||||||
|
$eventbubble-reply-color: #C1C6CD;
|
||||||
|
|
||||||
// ***** Mixins! *****
|
// ***** Mixins! *****
|
||||||
|
|
||||||
@define-mixin mx_DialogButton {
|
@define-mixin mx_DialogButton {
|
||||||
|
|
|
@ -349,6 +349,13 @@ $groupFilterPanel-background-blur-amount: 20px;
|
||||||
|
|
||||||
$composer-shadow-color: rgba(0, 0, 0, 0.04);
|
$composer-shadow-color: rgba(0, 0, 0, 0.04);
|
||||||
|
|
||||||
|
// Bubble tiles
|
||||||
|
$eventbubble-self-bg: #F8FDFC;
|
||||||
|
$eventbubble-others-bg: #F7F8F9;
|
||||||
|
$eventbubble-bg-hover: #FEFCF5;
|
||||||
|
$eventbubble-avatar-outline: $primary-bg-color;
|
||||||
|
$eventbubble-reply-color: #C1C6CD;
|
||||||
|
|
||||||
// ***** Mixins! *****
|
// ***** Mixins! *****
|
||||||
|
|
||||||
@define-mixin mx_DialogButton {
|
@define-mixin mx_DialogButton {
|
||||||
|
|
4
src/@types/global.d.ts
vendored
4
src/@types/global.d.ts
vendored
|
@ -50,6 +50,8 @@ import UIStore from "../stores/UIStore";
|
||||||
import { SetupEncryptionStore } from "../stores/SetupEncryptionStore";
|
import { SetupEncryptionStore } from "../stores/SetupEncryptionStore";
|
||||||
import { RoomScrollStateStore } from "../stores/RoomScrollStateStore";
|
import { RoomScrollStateStore } from "../stores/RoomScrollStateStore";
|
||||||
|
|
||||||
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
matrixChat: ReturnType<Renderer>;
|
matrixChat: ReturnType<Renderer>;
|
||||||
|
@ -186,3 +188,5 @@ declare global {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* eslint-enable @typescript-eslint/naming-convention */
|
||||||
|
|
|
@ -270,7 +270,7 @@ export class Analytics {
|
||||||
localStorage.removeItem(LAST_VISIT_TS_KEY);
|
localStorage.removeItem(LAST_VISIT_TS_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _track(data: IData) {
|
private async track(data: IData) {
|
||||||
if (this.disabled) return;
|
if (this.disabled) return;
|
||||||
|
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
@ -304,7 +304,7 @@ export class Analytics {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ping() {
|
public ping() {
|
||||||
this._track({
|
this.track({
|
||||||
ping: "1",
|
ping: "1",
|
||||||
});
|
});
|
||||||
localStorage.setItem(LAST_VISIT_TS_KEY, String(new Date().getTime())); // update last visit ts
|
localStorage.setItem(LAST_VISIT_TS_KEY, String(new Date().getTime())); // update last visit ts
|
||||||
|
@ -324,14 +324,14 @@ export class Analytics {
|
||||||
// But continue anyway because we still want to track the change
|
// But continue anyway because we still want to track the change
|
||||||
}
|
}
|
||||||
|
|
||||||
this._track({
|
this.track({
|
||||||
gt_ms: String(generationTimeMs),
|
gt_ms: String(generationTimeMs),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public trackEvent(category: string, action: string, name?: string, value?: string) {
|
public trackEvent(category: string, action: string, name?: string, value?: string) {
|
||||||
if (this.disabled) return;
|
if (this.disabled) return;
|
||||||
this._track({
|
this.track({
|
||||||
e_c: category,
|
e_c: category,
|
||||||
e_a: action,
|
e_a: action,
|
||||||
e_n: name,
|
e_n: name,
|
||||||
|
@ -395,17 +395,17 @@ export class Analytics {
|
||||||
Modal.createTrackedDialog('Analytics Details', '', ErrorDialog, {
|
Modal.createTrackedDialog('Analytics Details', '', ErrorDialog, {
|
||||||
title: _t('Analytics'),
|
title: _t('Analytics'),
|
||||||
description: <div className="mx_AnalyticsModal">
|
description: <div className="mx_AnalyticsModal">
|
||||||
<div>{_t('The information being sent to us to help make %(brand)s better includes:', {
|
<div>{ _t('The information being sent to us to help make %(brand)s better includes:', {
|
||||||
brand: SdkConfig.get().brand,
|
brand: SdkConfig.get().brand,
|
||||||
})}</div>
|
}) }</div>
|
||||||
<table>
|
<table>
|
||||||
{ rows.map((row) => <tr key={row[0]}>
|
{ rows.map((row) => <tr key={row[0]}>
|
||||||
<td>{_t(
|
<td>{ _t(
|
||||||
customVariables[row[0]].expl,
|
customVariables[row[0]].expl,
|
||||||
customVariables[row[0]].getTextVariables ?
|
customVariables[row[0]].getTextVariables ?
|
||||||
customVariables[row[0]].getTextVariables() :
|
customVariables[row[0]].getTextVariables() :
|
||||||
null,
|
null,
|
||||||
)}</td>
|
) }</td>
|
||||||
{ row[1] !== undefined && <td><code>{ row[1] }</code></td> }
|
{ row[1] !== undefined && <td><code>{ row[1] }</code></td> }
|
||||||
</tr>) }
|
</tr>) }
|
||||||
{ otherVariables.map((item, index) =>
|
{ otherVariables.map((item, index) =>
|
||||||
|
|
|
@ -615,23 +615,23 @@ export default class CallHandler extends EventEmitter {
|
||||||
|
|
||||||
private showICEFallbackPrompt() {
|
private showICEFallbackPrompt() {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
const code = sub => <code>{sub}</code>;
|
const code = sub => <code>{ sub }</code>;
|
||||||
Modal.createTrackedDialog('No TURN servers', '', QuestionDialog, {
|
Modal.createTrackedDialog('No TURN servers', '', QuestionDialog, {
|
||||||
title: _t("Call failed due to misconfigured server"),
|
title: _t("Call failed due to misconfigured server"),
|
||||||
description: <div>
|
description: <div>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"Please ask the administrator of your homeserver " +
|
"Please ask the administrator of your homeserver " +
|
||||||
"(<code>%(homeserverDomain)s</code>) to configure a TURN server in " +
|
"(<code>%(homeserverDomain)s</code>) to configure a TURN server in " +
|
||||||
"order for calls to work reliably.",
|
"order for calls to work reliably.",
|
||||||
{ homeserverDomain: cli.getDomain() }, { code },
|
{ homeserverDomain: cli.getDomain() }, { code },
|
||||||
)}</p>
|
) }</p>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"Alternatively, you can try to use the public server at " +
|
"Alternatively, you can try to use the public server at " +
|
||||||
"<code>turn.matrix.org</code>, but this will not be as reliable, and " +
|
"<code>turn.matrix.org</code>, but this will not be as reliable, and " +
|
||||||
"it will share your IP address with that server. You can also manage " +
|
"it will share your IP address with that server. You can also manage " +
|
||||||
"this in Settings.",
|
"this in Settings.",
|
||||||
null, { code },
|
null, { code },
|
||||||
)}</p>
|
) }</p>
|
||||||
</div>,
|
</div>,
|
||||||
button: _t('Try using turn.matrix.org'),
|
button: _t('Try using turn.matrix.org'),
|
||||||
cancelButton: _t('OK'),
|
cancelButton: _t('OK'),
|
||||||
|
@ -649,19 +649,19 @@ export default class CallHandler extends EventEmitter {
|
||||||
if (call.type === CallType.Voice) {
|
if (call.type === CallType.Voice) {
|
||||||
title = _t("Unable to access microphone");
|
title = _t("Unable to access microphone");
|
||||||
description = <div>
|
description = <div>
|
||||||
{_t(
|
{ _t(
|
||||||
"Call failed because microphone could not be accessed. " +
|
"Call failed because microphone could not be accessed. " +
|
||||||
"Check that a microphone is plugged in and set up correctly.",
|
"Check that a microphone is plugged in and set up correctly.",
|
||||||
)}
|
) }
|
||||||
</div>;
|
</div>;
|
||||||
} else if (call.type === CallType.Video) {
|
} else if (call.type === CallType.Video) {
|
||||||
title = _t("Unable to access webcam / microphone");
|
title = _t("Unable to access webcam / microphone");
|
||||||
description = <div>
|
description = <div>
|
||||||
{_t("Call failed because webcam or microphone could not be accessed. Check that:")}
|
{ _t("Call failed because webcam or microphone could not be accessed. Check that:") }
|
||||||
<ul>
|
<ul>
|
||||||
<li>{_t("A microphone and webcam are plugged in and set up correctly")}</li>
|
<li>{ _t("A microphone and webcam are plugged in and set up correctly") }</li>
|
||||||
<li>{_t("Permission is granted to use the webcam")}</li>
|
<li>{ _t("Permission is granted to use the webcam") }</li>
|
||||||
<li>{_t("No other application is using the webcam")}</li>
|
<li>{ _t("No other application is using the webcam") }</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -425,10 +425,10 @@ export default class ContentMessages {
|
||||||
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'),
|
||||||
description: (
|
description: (
|
||||||
<div>{_t(
|
<div>{ _t(
|
||||||
'At this time it is not possible to reply with a file. ' +
|
'At this time it is not possible to reply with a file. ' +
|
||||||
'Would you like to upload this file without replying?',
|
'Would you like to upload this file without replying?',
|
||||||
)}</div>
|
) }</div>
|
||||||
),
|
),
|
||||||
hasCancelButton: true,
|
hasCancelButton: true,
|
||||||
button: _t("Continue"),
|
button: _t("Continue"),
|
||||||
|
|
|
@ -33,6 +33,7 @@ import { isSecretStorageBeingAccessed, accessSecretStorage } from "./SecurityMan
|
||||||
import { isSecureBackupRequired } from './utils/WellKnownUtils';
|
import { isSecureBackupRequired } from './utils/WellKnownUtils';
|
||||||
import { isLoggedIn } from './components/structures/MatrixChat';
|
import { isLoggedIn } from './components/structures/MatrixChat';
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
|
import { ActionPayload } from "./dispatcher/payloads";
|
||||||
|
|
||||||
const KEY_BACKUP_POLL_INTERVAL = 5 * 60 * 1000;
|
const KEY_BACKUP_POLL_INTERVAL = 5 * 60 * 1000;
|
||||||
|
|
||||||
|
@ -58,28 +59,28 @@ export default class DeviceListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
MatrixClientPeg.get().on('crypto.willUpdateDevices', this._onWillUpdateDevices);
|
MatrixClientPeg.get().on('crypto.willUpdateDevices', this.onWillUpdateDevices);
|
||||||
MatrixClientPeg.get().on('crypto.devicesUpdated', this._onDevicesUpdated);
|
MatrixClientPeg.get().on('crypto.devicesUpdated', this.onDevicesUpdated);
|
||||||
MatrixClientPeg.get().on('deviceVerificationChanged', this._onDeviceVerificationChanged);
|
MatrixClientPeg.get().on('deviceVerificationChanged', this.onDeviceVerificationChanged);
|
||||||
MatrixClientPeg.get().on('userTrustStatusChanged', this._onUserTrustStatusChanged);
|
MatrixClientPeg.get().on('userTrustStatusChanged', this.onUserTrustStatusChanged);
|
||||||
MatrixClientPeg.get().on('crossSigning.keysChanged', this._onCrossSingingKeysChanged);
|
MatrixClientPeg.get().on('crossSigning.keysChanged', this.onCrossSingingKeysChanged);
|
||||||
MatrixClientPeg.get().on('accountData', this._onAccountData);
|
MatrixClientPeg.get().on('accountData', this.onAccountData);
|
||||||
MatrixClientPeg.get().on('sync', this._onSync);
|
MatrixClientPeg.get().on('sync', this.onSync);
|
||||||
MatrixClientPeg.get().on('RoomState.events', this._onRoomStateEvents);
|
MatrixClientPeg.get().on('RoomState.events', this.onRoomStateEvents);
|
||||||
this.dispatcherRef = dis.register(this._onAction);
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
this._recheck();
|
this.recheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
if (MatrixClientPeg.get()) {
|
if (MatrixClientPeg.get()) {
|
||||||
MatrixClientPeg.get().removeListener('crypto.willUpdateDevices', this._onWillUpdateDevices);
|
MatrixClientPeg.get().removeListener('crypto.willUpdateDevices', this.onWillUpdateDevices);
|
||||||
MatrixClientPeg.get().removeListener('crypto.devicesUpdated', this._onDevicesUpdated);
|
MatrixClientPeg.get().removeListener('crypto.devicesUpdated', this.onDevicesUpdated);
|
||||||
MatrixClientPeg.get().removeListener('deviceVerificationChanged', this._onDeviceVerificationChanged);
|
MatrixClientPeg.get().removeListener('deviceVerificationChanged', this.onDeviceVerificationChanged);
|
||||||
MatrixClientPeg.get().removeListener('userTrustStatusChanged', this._onUserTrustStatusChanged);
|
MatrixClientPeg.get().removeListener('userTrustStatusChanged', this.onUserTrustStatusChanged);
|
||||||
MatrixClientPeg.get().removeListener('crossSigning.keysChanged', this._onCrossSingingKeysChanged);
|
MatrixClientPeg.get().removeListener('crossSigning.keysChanged', this.onCrossSingingKeysChanged);
|
||||||
MatrixClientPeg.get().removeListener('accountData', this._onAccountData);
|
MatrixClientPeg.get().removeListener('accountData', this.onAccountData);
|
||||||
MatrixClientPeg.get().removeListener('sync', this._onSync);
|
MatrixClientPeg.get().removeListener('sync', this.onSync);
|
||||||
MatrixClientPeg.get().removeListener('RoomState.events', this._onRoomStateEvents);
|
MatrixClientPeg.get().removeListener('RoomState.events', this.onRoomStateEvents);
|
||||||
}
|
}
|
||||||
if (this.dispatcherRef) {
|
if (this.dispatcherRef) {
|
||||||
dis.unregister(this.dispatcherRef);
|
dis.unregister(this.dispatcherRef);
|
||||||
|
@ -103,15 +104,15 @@ export default class DeviceListener {
|
||||||
this.dismissed.add(d);
|
this.dismissed.add(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._recheck();
|
this.recheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
dismissEncryptionSetup() {
|
dismissEncryptionSetup() {
|
||||||
this.dismissedThisDeviceToast = true;
|
this.dismissedThisDeviceToast = true;
|
||||||
this._recheck();
|
this.recheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
_ensureDeviceIdsAtStartPopulated() {
|
private ensureDeviceIdsAtStartPopulated() {
|
||||||
if (this.ourDeviceIdsAtStart === null) {
|
if (this.ourDeviceIdsAtStart === null) {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
this.ourDeviceIdsAtStart = new Set(
|
this.ourDeviceIdsAtStart = new Set(
|
||||||
|
@ -120,39 +121,39 @@ export default class DeviceListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onWillUpdateDevices = async (users: string[], initialFetch?: boolean) => {
|
private onWillUpdateDevices = async (users: string[], initialFetch?: boolean) => {
|
||||||
// If we didn't know about *any* devices before (ie. it's fresh login),
|
// If we didn't know about *any* devices before (ie. it's fresh login),
|
||||||
// then they are all pre-existing devices, so ignore this and set the
|
// then they are all pre-existing devices, so ignore this and set the
|
||||||
// devicesAtStart list to the devices that we see after the fetch.
|
// devicesAtStart list to the devices that we see after the fetch.
|
||||||
if (initialFetch) return;
|
if (initialFetch) return;
|
||||||
|
|
||||||
const myUserId = MatrixClientPeg.get().getUserId();
|
const myUserId = MatrixClientPeg.get().getUserId();
|
||||||
if (users.includes(myUserId)) this._ensureDeviceIdsAtStartPopulated();
|
if (users.includes(myUserId)) this.ensureDeviceIdsAtStartPopulated();
|
||||||
|
|
||||||
// No need to do a recheck here: we just need to get a snapshot of our devices
|
// No need to do a recheck here: we just need to get a snapshot of our devices
|
||||||
// before we download any new ones.
|
// before we download any new ones.
|
||||||
};
|
};
|
||||||
|
|
||||||
_onDevicesUpdated = (users: string[]) => {
|
private onDevicesUpdated = (users: string[]) => {
|
||||||
if (!users.includes(MatrixClientPeg.get().getUserId())) return;
|
if (!users.includes(MatrixClientPeg.get().getUserId())) return;
|
||||||
this._recheck();
|
this.recheck();
|
||||||
};
|
};
|
||||||
|
|
||||||
_onDeviceVerificationChanged = (userId: string) => {
|
private onDeviceVerificationChanged = (userId: string) => {
|
||||||
if (userId !== MatrixClientPeg.get().getUserId()) return;
|
if (userId !== MatrixClientPeg.get().getUserId()) return;
|
||||||
this._recheck();
|
this.recheck();
|
||||||
};
|
};
|
||||||
|
|
||||||
_onUserTrustStatusChanged = (userId: string) => {
|
private onUserTrustStatusChanged = (userId: string) => {
|
||||||
if (userId !== MatrixClientPeg.get().getUserId()) return;
|
if (userId !== MatrixClientPeg.get().getUserId()) return;
|
||||||
this._recheck();
|
this.recheck();
|
||||||
};
|
};
|
||||||
|
|
||||||
_onCrossSingingKeysChanged = () => {
|
private onCrossSingingKeysChanged = () => {
|
||||||
this._recheck();
|
this.recheck();
|
||||||
};
|
};
|
||||||
|
|
||||||
_onAccountData = (ev) => {
|
private onAccountData = (ev: MatrixEvent) => {
|
||||||
// User may have:
|
// User may have:
|
||||||
// * migrated SSSS to symmetric
|
// * migrated SSSS to symmetric
|
||||||
// * uploaded keys to secret storage
|
// * uploaded keys to secret storage
|
||||||
|
@ -163,32 +164,32 @@ export default class DeviceListener {
|
||||||
ev.getType().startsWith('m.cross_signing.') ||
|
ev.getType().startsWith('m.cross_signing.') ||
|
||||||
ev.getType() === 'm.megolm_backup.v1'
|
ev.getType() === 'm.megolm_backup.v1'
|
||||||
) {
|
) {
|
||||||
this._recheck();
|
this.recheck();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_onSync = (state, prevState) => {
|
private onSync = (state, prevState) => {
|
||||||
if (state === 'PREPARED' && prevState === null) this._recheck();
|
if (state === 'PREPARED' && prevState === null) this.recheck();
|
||||||
};
|
};
|
||||||
|
|
||||||
_onRoomStateEvents = (ev: MatrixEvent) => {
|
private onRoomStateEvents = (ev: MatrixEvent) => {
|
||||||
if (ev.getType() !== "m.room.encryption") {
|
if (ev.getType() !== "m.room.encryption") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a room changes to encrypted, re-check as it may be our first
|
// If a room changes to encrypted, re-check as it may be our first
|
||||||
// encrypted room. This also catches encrypted room creation as well.
|
// encrypted room. This also catches encrypted room creation as well.
|
||||||
this._recheck();
|
this.recheck();
|
||||||
};
|
};
|
||||||
|
|
||||||
_onAction = ({ action }) => {
|
private onAction = ({ action }: ActionPayload) => {
|
||||||
if (action !== "on_logged_in") return;
|
if (action !== "on_logged_in") return;
|
||||||
this._recheck();
|
this.recheck();
|
||||||
};
|
};
|
||||||
|
|
||||||
// The server doesn't tell us when key backup is set up, so we poll
|
// The server doesn't tell us when key backup is set up, so we poll
|
||||||
// & cache the result
|
// & cache the result
|
||||||
async _getKeyBackupInfo() {
|
private async getKeyBackupInfo() {
|
||||||
const now = (new Date()).getTime();
|
const now = (new Date()).getTime();
|
||||||
if (!this.keyBackupInfo || this.keyBackupFetchedAt < now - KEY_BACKUP_POLL_INTERVAL) {
|
if (!this.keyBackupInfo || this.keyBackupFetchedAt < now - KEY_BACKUP_POLL_INTERVAL) {
|
||||||
this.keyBackupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
|
this.keyBackupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
|
||||||
|
@ -206,7 +207,7 @@ export default class DeviceListener {
|
||||||
return cli && cli.getRooms().some(r => cli.isRoomEncrypted(r.roomId));
|
return cli && cli.getRooms().some(r => cli.isRoomEncrypted(r.roomId));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _recheck() {
|
private async recheck() {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
|
|
||||||
if (!await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")) return;
|
if (!await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")) return;
|
||||||
|
@ -235,7 +236,7 @@ export default class DeviceListener {
|
||||||
// Cross-signing on account but this device doesn't trust the master key (verify this session)
|
// Cross-signing on account but this device doesn't trust the master key (verify this session)
|
||||||
showSetupEncryptionToast(SetupKind.VERIFY_THIS_SESSION);
|
showSetupEncryptionToast(SetupKind.VERIFY_THIS_SESSION);
|
||||||
} else {
|
} else {
|
||||||
const backupInfo = await this._getKeyBackupInfo();
|
const backupInfo = await this.getKeyBackupInfo();
|
||||||
if (backupInfo) {
|
if (backupInfo) {
|
||||||
// No cross-signing on account but key backup available (upgrade encryption)
|
// No cross-signing on account but key backup available (upgrade encryption)
|
||||||
showSetupEncryptionToast(SetupKind.UPGRADE_ENCRYPTION);
|
showSetupEncryptionToast(SetupKind.UPGRADE_ENCRYPTION);
|
||||||
|
@ -256,7 +257,7 @@ export default class DeviceListener {
|
||||||
|
|
||||||
// This needs to be done after awaiting on downloadKeys() above, so
|
// This needs to be done after awaiting on downloadKeys() above, so
|
||||||
// we make sure we get the devices after the fetch is done.
|
// we make sure we get the devices after the fetch is done.
|
||||||
this._ensureDeviceIdsAtStartPopulated();
|
this.ensureDeviceIdsAtStartPopulated();
|
||||||
|
|
||||||
// Unverified devices that were there last time the app ran
|
// Unverified devices that were there last time the app ran
|
||||||
// (technically could just be a boolean: we don't actually
|
// (technically could just be a boolean: we don't actually
|
||||||
|
|
|
@ -149,17 +149,17 @@ export default class IdentityAuthClient {
|
||||||
title: _t("Identity server has no terms of service"),
|
title: _t("Identity server has no terms of service"),
|
||||||
description: (
|
description: (
|
||||||
<div>
|
<div>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"This action requires accessing the default identity server " +
|
"This action requires accessing the default identity server " +
|
||||||
"<server /> to validate an email address or phone number, " +
|
"<server /> to validate an email address or phone number, " +
|
||||||
"but the server does not have any terms of service.", {},
|
"but the server does not have any terms of service.", {},
|
||||||
{
|
{
|
||||||
server: () => <b>{abbreviateUrl(identityServerUrl)}</b>,
|
server: () => <b>{ abbreviateUrl(identityServerUrl) }</b>,
|
||||||
},
|
},
|
||||||
)}</p>
|
) }</p>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"Only continue if you trust the owner of the server.",
|
"Only continue if you trust the owner of the server.",
|
||||||
)}</p>
|
) }</p>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
button: _t("Trust"),
|
button: _t("Trust"),
|
||||||
|
|
|
@ -105,7 +105,7 @@ export interface IMatrixClientPeg {
|
||||||
* This module provides a singleton instance of this class so the 'current'
|
* This module provides a singleton instance of this class so the 'current'
|
||||||
* Matrix Client object is available easily.
|
* Matrix Client object is available easily.
|
||||||
*/
|
*/
|
||||||
class _MatrixClientPeg implements IMatrixClientPeg {
|
class MatrixClientPegClass implements IMatrixClientPeg {
|
||||||
// These are the default options used when when the
|
// These are the default options used when when the
|
||||||
// client is started in 'start'. These can be altered
|
// client is started in 'start'. These can be altered
|
||||||
// at any time up to after the 'will_start_client'
|
// at any time up to after the 'will_start_client'
|
||||||
|
@ -300,7 +300,7 @@ class _MatrixClientPeg implements IMatrixClientPeg {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!window.mxMatrixClientPeg) {
|
if (!window.mxMatrixClientPeg) {
|
||||||
window.mxMatrixClientPeg = new _MatrixClientPeg();
|
window.mxMatrixClientPeg = new MatrixClientPegClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MatrixClientPeg = window.mxMatrixClientPeg;
|
export const MatrixClientPeg = window.mxMatrixClientPeg;
|
||||||
|
|
|
@ -378,7 +378,7 @@ export class ModalManager {
|
||||||
const dialog = (
|
const dialog = (
|
||||||
<div className={classes}>
|
<div className={classes}>
|
||||||
<div className="mx_Dialog">
|
<div className="mx_Dialog">
|
||||||
{modal.elem}
|
{ modal.elem }
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_background" onClick={this.onBackgroundClick} />
|
<div className="mx_Dialog_background" onClick={this.onBackgroundClick} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -480,14 +480,14 @@ export const Commands = [
|
||||||
'Identity server',
|
'Identity server',
|
||||||
QuestionDialog, {
|
QuestionDialog, {
|
||||||
title: _t("Use an identity server"),
|
title: _t("Use an identity server"),
|
||||||
description: <p>{_t(
|
description: <p>{ _t(
|
||||||
"Use an identity server to invite by email. " +
|
"Use an identity server to invite by email. " +
|
||||||
"Click continue to use the default identity server " +
|
"Click continue to use the default identity server " +
|
||||||
"(%(defaultIdentityServerName)s) or manage in Settings.",
|
"(%(defaultIdentityServerName)s) or manage in Settings.",
|
||||||
{
|
{
|
||||||
defaultIdentityServerName: abbreviateUrl(defaultIdentityServerUrl),
|
defaultIdentityServerName: abbreviateUrl(defaultIdentityServerUrl),
|
||||||
},
|
},
|
||||||
)}</p>,
|
) }</p>,
|
||||||
button: _t("Continue"),
|
button: _t("Continue"),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -522,7 +522,7 @@ export const Commands = [
|
||||||
aliases: ['j', 'goto'],
|
aliases: ['j', 'goto'],
|
||||||
args: '<room-address>',
|
args: '<room-address>',
|
||||||
description: _td('Joins room with given address'),
|
description: _td('Joins room with given address'),
|
||||||
runFn: function(_, args) {
|
runFn: function(roomId, args) {
|
||||||
if (args) {
|
if (args) {
|
||||||
// Note: we support 2 versions of this command. The first is
|
// Note: we support 2 versions of this command. The first is
|
||||||
// the public-facing one for most users and the other is a
|
// the public-facing one for most users and the other is a
|
||||||
|
@ -1069,7 +1069,7 @@ export const Commands = [
|
||||||
command: "msg",
|
command: "msg",
|
||||||
description: _td("Sends a message to the given user"),
|
description: _td("Sends a message to the given user"),
|
||||||
args: "<user-id> <message>",
|
args: "<user-id> <message>",
|
||||||
runFn: function(_, args) {
|
runFn: function(roomId, args) {
|
||||||
if (args) {
|
if (args) {
|
||||||
// matches the first whitespace delimited group and then the rest of the string
|
// matches the first whitespace delimited group and then the rest of the string
|
||||||
const matches = args.match(/^(\S+?)(?: +(.*))?$/s);
|
const matches = args.match(/^(\S+?)(?: +(.*))?$/s);
|
||||||
|
|
|
@ -370,8 +370,8 @@ export const toggleDialog = () => {
|
||||||
const sections = categoryOrder.map(category => {
|
const sections = categoryOrder.map(category => {
|
||||||
const list = shortcuts[category];
|
const list = shortcuts[category];
|
||||||
return <div className="mx_KeyboardShortcutsDialog_category" key={category}>
|
return <div className="mx_KeyboardShortcutsDialog_category" key={category}>
|
||||||
<h3>{_t(category)}</h3>
|
<h3>{ _t(category) }</h3>
|
||||||
<div>{list.map(shortcut => <Shortcut key={shortcut.description} shortcut={shortcut} />)}</div>
|
<div>{ list.map(shortcut => <Shortcut key={shortcut.description} shortcut={shortcut} />) }</div>
|
||||||
</div>;
|
</div>;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -62,9 +62,9 @@ const Toolbar: React.FC<IProps> = ({ children, ...props }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return <RovingTabIndexProvider handleHomeEnd={true} onKeyDown={onKeyDown}>
|
return <RovingTabIndexProvider handleHomeEnd={true} onKeyDown={onKeyDown}>
|
||||||
{({ onKeyDownHandler }) => <div {...props} onKeyDown={onKeyDownHandler} role="toolbar">
|
{ ({ onKeyDownHandler }) => <div {...props} onKeyDown={onKeyDownHandler} role="toolbar">
|
||||||
{ children }
|
{ children }
|
||||||
</div>}
|
</div> }
|
||||||
</RovingTabIndexProvider>;
|
</RovingTabIndexProvider>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -59,8 +59,8 @@ export default class DisableEventIndexDialog extends React.Component {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog onFinished={this.props.onFinished} title={_t("Are you sure?")}>
|
<BaseDialog onFinished={this.props.onFinished} title={_t("Are you sure?")}>
|
||||||
{_t("If disabled, messages from encrypted rooms won't appear in search results.")}
|
{ _t("If disabled, messages from encrypted rooms won't appear in search results.") }
|
||||||
{this.state.disabling ? <Spinner /> : <div />}
|
{ this.state.disabling ? <Spinner /> : <div /> }
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t('Disable')}
|
primaryButton={_t('Disable')}
|
||||||
onPrimaryButtonClick={this._onDisable}
|
onPrimaryButtonClick={this._onDisable}
|
||||||
|
|
|
@ -161,19 +161,19 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
||||||
|
|
||||||
const eventIndexingSettings = (
|
const eventIndexingSettings = (
|
||||||
<div>
|
<div>
|
||||||
{_t(
|
{ _t(
|
||||||
"%(brand)s is securely caching encrypted messages locally for them " +
|
"%(brand)s is securely caching encrypted messages locally for them " +
|
||||||
"to appear in search results:",
|
"to appear in search results:",
|
||||||
{ brand },
|
{ brand },
|
||||||
)}
|
) }
|
||||||
<div className='mx_SettingsTab_subsectionText'>
|
<div className='mx_SettingsTab_subsectionText'>
|
||||||
{crawlerState}<br />
|
{ crawlerState }<br />
|
||||||
{_t("Space used:")} {formatBytes(this.state.eventIndexSize, 0)}<br />
|
{ _t("Space used:") } { formatBytes(this.state.eventIndexSize, 0) }<br />
|
||||||
{_t("Indexed messages:")} {formatCountLong(this.state.eventCount)}<br />
|
{ _t("Indexed messages:") } { formatCountLong(this.state.eventCount) }<br />
|
||||||
{_t("Indexed rooms:")} {_t("%(doneRooms)s out of %(totalRooms)s", {
|
{ _t("Indexed rooms:") } { _t("%(doneRooms)s out of %(totalRooms)s", {
|
||||||
doneRooms: formatCountLong(doneRooms),
|
doneRooms: formatCountLong(doneRooms),
|
||||||
totalRooms: formatCountLong(this.state.roomCount),
|
totalRooms: formatCountLong(this.state.roomCount),
|
||||||
})} <br />
|
}) } <br />
|
||||||
<Field
|
<Field
|
||||||
label={_t('Message downloading sleep time(ms)')}
|
label={_t('Message downloading sleep time(ms)')}
|
||||||
type='number'
|
type='number'
|
||||||
|
@ -188,7 +188,7 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
title={_t("Message search")}
|
title={_t("Message search")}
|
||||||
>
|
>
|
||||||
{eventIndexingSettings}
|
{ eventIndexingSettings }
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("Done")}
|
primaryButton={_t("Done")}
|
||||||
onPrimaryButtonClick={this.props.onFinished}
|
onPrimaryButtonClick={this.props.onFinished}
|
||||||
|
|
|
@ -232,15 +232,15 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||||
|
|
||||||
return <form onSubmit={this._onPassPhraseNextClick}>
|
return <form onSubmit={this._onPassPhraseNextClick}>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"<b>Warning</b>: You should only set up key backup from a trusted computer.", {},
|
"<b>Warning</b>: You should only set up key backup from a trusted computer.", {},
|
||||||
{ b: sub => <b>{sub}</b> },
|
{ b: sub => <b>{ sub }</b> },
|
||||||
)}</p>
|
) }</p>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"We'll store an encrypted copy of your keys on our server. " +
|
"We'll store an encrypted copy of your keys on our server. " +
|
||||||
"Secure your backup with a Security Phrase.",
|
"Secure your backup with a Security Phrase.",
|
||||||
)}</p>
|
) }</p>
|
||||||
<p>{_t("For maximum security, this should be different from your account password.")}</p>
|
<p>{ _t("For maximum security, this should be different from your account password.") }</p>
|
||||||
|
|
||||||
<div className="mx_CreateKeyBackupDialog_primaryContainer">
|
<div className="mx_CreateKeyBackupDialog_primaryContainer">
|
||||||
<div className="mx_CreateKeyBackupDialog_passPhraseContainer">
|
<div className="mx_CreateKeyBackupDialog_passPhraseContainer">
|
||||||
|
@ -268,9 +268,9 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>{_t("Advanced")}</summary>
|
<summary>{ _t("Advanced") }</summary>
|
||||||
<AccessibleButton kind='primary' onClick={this._onSkipPassPhraseClick} >
|
<AccessibleButton kind='primary' onClick={this._onSkipPassPhraseClick} >
|
||||||
{_t("Set up with a Security Key")}
|
{ _t("Set up with a Security Key") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</details>
|
</details>
|
||||||
</form>;
|
</form>;
|
||||||
|
@ -299,19 +299,19 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
|
||||||
let passPhraseMatch = null;
|
let passPhraseMatch = null;
|
||||||
if (matchText) {
|
if (matchText) {
|
||||||
passPhraseMatch = <div className="mx_CreateKeyBackupDialog_passPhraseMatch">
|
passPhraseMatch = <div className="mx_CreateKeyBackupDialog_passPhraseMatch">
|
||||||
<div>{matchText}</div>
|
<div>{ matchText }</div>
|
||||||
<div>
|
<div>
|
||||||
<AccessibleButton element="span" className="mx_linkButton" onClick={this._onSetAgainClick}>
|
<AccessibleButton element="span" className="mx_linkButton" onClick={this._onSetAgainClick}>
|
||||||
{changeText}
|
{ changeText }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||||
return <form onSubmit={this._onPassPhraseConfirmNextClick}>
|
return <form onSubmit={this._onPassPhraseConfirmNextClick}>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"Enter your Security Phrase a second time to confirm it.",
|
"Enter your Security Phrase a second time to confirm it.",
|
||||||
)}</p>
|
) }</p>
|
||||||
<div className="mx_CreateKeyBackupDialog_primaryContainer">
|
<div className="mx_CreateKeyBackupDialog_primaryContainer">
|
||||||
<div className="mx_CreateKeyBackupDialog_passPhraseContainer">
|
<div className="mx_CreateKeyBackupDialog_passPhraseContainer">
|
||||||
<div>
|
<div>
|
||||||
|
@ -323,7 +323,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{passPhraseMatch}
|
{ passPhraseMatch }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
|
@ -337,27 +337,27 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
|
||||||
|
|
||||||
_renderPhaseShowKey() {
|
_renderPhaseShowKey() {
|
||||||
return <div>
|
return <div>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"Your Security Key is a safety net - you can use it to restore " +
|
"Your Security Key is a safety net - you can use it to restore " +
|
||||||
"access to your encrypted messages if you forget your Security Phrase.",
|
"access to your encrypted messages if you forget your Security Phrase.",
|
||||||
)}</p>
|
) }</p>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"Keep a copy of it somewhere secure, like a password manager or even a safe.",
|
"Keep a copy of it somewhere secure, like a password manager or even a safe.",
|
||||||
)}</p>
|
) }</p>
|
||||||
<div className="mx_CreateKeyBackupDialog_primaryContainer">
|
<div className="mx_CreateKeyBackupDialog_primaryContainer">
|
||||||
<div className="mx_CreateKeyBackupDialog_recoveryKeyHeader">
|
<div className="mx_CreateKeyBackupDialog_recoveryKeyHeader">
|
||||||
{_t("Your Security Key")}
|
{ _t("Your Security Key") }
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_CreateKeyBackupDialog_recoveryKeyContainer">
|
<div className="mx_CreateKeyBackupDialog_recoveryKeyContainer">
|
||||||
<div className="mx_CreateKeyBackupDialog_recoveryKey">
|
<div className="mx_CreateKeyBackupDialog_recoveryKey">
|
||||||
<code ref={this._collectRecoveryKeyNode}>{this._keyBackupInfo.recovery_key}</code>
|
<code ref={this._collectRecoveryKeyNode}>{ this._keyBackupInfo.recovery_key }</code>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_CreateKeyBackupDialog_recoveryKeyButtons">
|
<div className="mx_CreateKeyBackupDialog_recoveryKeyButtons">
|
||||||
<button className="mx_Dialog_primary" onClick={this._onCopyClick}>
|
<button className="mx_Dialog_primary" onClick={this._onCopyClick}>
|
||||||
{_t("Copy")}
|
{ _t("Copy") }
|
||||||
</button>
|
</button>
|
||||||
<button className="mx_Dialog_primary" onClick={this._onDownloadClick}>
|
<button className="mx_Dialog_primary" onClick={this._onDownloadClick}>
|
||||||
{_t("Download")}
|
{ _t("Download") }
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -370,26 +370,26 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
|
||||||
if (this.state.copied) {
|
if (this.state.copied) {
|
||||||
introText = _t(
|
introText = _t(
|
||||||
"Your Security Key has been <b>copied to your clipboard</b>, paste it to:",
|
"Your Security Key has been <b>copied to your clipboard</b>, paste it to:",
|
||||||
{}, { b: s => <b>{s}</b> },
|
{}, { b: s => <b>{ s }</b> },
|
||||||
);
|
);
|
||||||
} else if (this.state.downloaded) {
|
} else if (this.state.downloaded) {
|
||||||
introText = _t(
|
introText = _t(
|
||||||
"Your Security Key is in your <b>Downloads</b> folder.",
|
"Your Security Key is in your <b>Downloads</b> folder.",
|
||||||
{}, { b: s => <b>{s}</b> },
|
{}, { b: s => <b>{ s }</b> },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||||
return <div>
|
return <div>
|
||||||
{introText}
|
{ introText }
|
||||||
<ul>
|
<ul>
|
||||||
<li>{_t("<b>Print it</b> and store it somewhere safe", {}, { b: s => <b>{s}</b> })}</li>
|
<li>{ _t("<b>Print it</b> and store it somewhere safe", {}, { b: s => <b>{ s }</b> }) }</li>
|
||||||
<li>{_t("<b>Save it</b> on a USB key or backup drive", {}, { b: s => <b>{s}</b> })}</li>
|
<li>{ _t("<b>Save it</b> on a USB key or backup drive", {}, { b: s => <b>{ s }</b> }) }</li>
|
||||||
<li>{_t("<b>Copy it</b> to your personal cloud storage", {}, { b: s => <b>{s}</b> })}</li>
|
<li>{ _t("<b>Copy it</b> to your personal cloud storage", {}, { b: s => <b>{ s }</b> }) }</li>
|
||||||
</ul>
|
</ul>
|
||||||
<DialogButtons primaryButton={_t("Continue")}
|
<DialogButtons primaryButton={_t("Continue")}
|
||||||
onPrimaryButtonClick={this._createBackup}
|
onPrimaryButtonClick={this._createBackup}
|
||||||
hasCancel={false}>
|
hasCancel={false}>
|
||||||
<button onClick={this._onKeepItSafeBackClick}>{_t("Back")}</button>
|
<button onClick={this._onKeepItSafeBackClick}>{ _t("Back") }</button>
|
||||||
</DialogButtons>
|
</DialogButtons>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
@ -404,9 +404,9 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
|
||||||
_renderPhaseDone() {
|
_renderPhaseDone() {
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||||
return <div>
|
return <div>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"Your keys are being backed up (the first backup could take a few minutes).",
|
"Your keys are being backed up (the first backup could take a few minutes).",
|
||||||
)}</p>
|
) }</p>
|
||||||
<DialogButtons primaryButton={_t('OK')}
|
<DialogButtons primaryButton={_t('OK')}
|
||||||
onPrimaryButtonClick={this._onDone}
|
onPrimaryButtonClick={this._onDone}
|
||||||
hasCancel={false}
|
hasCancel={false}
|
||||||
|
@ -417,10 +417,10 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
|
||||||
_renderPhaseOptOutConfirm() {
|
_renderPhaseOptOutConfirm() {
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||||
return <div>
|
return <div>
|
||||||
{_t(
|
{ _t(
|
||||||
"Without setting up Secure Message Recovery, you won't be able to restore your " +
|
"Without setting up Secure Message Recovery, you won't be able to restore your " +
|
||||||
"encrypted message history if you log out or use another session.",
|
"encrypted message history if you log out or use another session.",
|
||||||
)}
|
) }
|
||||||
<DialogButtons primaryButton={_t('Set up Secure Message Recovery')}
|
<DialogButtons primaryButton={_t('Set up Secure Message Recovery')}
|
||||||
onPrimaryButtonClick={this._onSetUpClick}
|
onPrimaryButtonClick={this._onSetUpClick}
|
||||||
hasCancel={false}
|
hasCancel={false}
|
||||||
|
@ -457,7 +457,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
|
||||||
if (this.state.error) {
|
if (this.state.error) {
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||||
content = <div>
|
content = <div>
|
||||||
<p>{_t("Unable to create key backup")}</p>
|
<p>{ _t("Unable to create key backup") }</p>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
<DialogButtons primaryButton={_t('Retry')}
|
<DialogButtons primaryButton={_t('Retry')}
|
||||||
onPrimaryButtonClick={this._createBackup}
|
onPrimaryButtonClick={this._createBackup}
|
||||||
|
@ -499,7 +499,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
|
||||||
hasCancel={[PHASE_PASSPHRASE, PHASE_DONE].includes(this.state.phase)}
|
hasCancel={[PHASE_PASSPHRASE, PHASE_DONE].includes(this.state.phase)}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
{content}
|
{ content }
|
||||||
</div>
|
</div>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
);
|
);
|
||||||
|
|
|
@ -475,9 +475,9 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
>
|
>
|
||||||
<div className="mx_CreateSecretStorageDialog_optionTitle">
|
<div className="mx_CreateSecretStorageDialog_optionTitle">
|
||||||
<span className="mx_CreateSecretStorageDialog_optionIcon mx_CreateSecretStorageDialog_optionIcon_secureBackup"></span>
|
<span className="mx_CreateSecretStorageDialog_optionIcon mx_CreateSecretStorageDialog_optionIcon_secureBackup"></span>
|
||||||
{_t("Generate a Security Key")}
|
{ _t("Generate a Security Key") }
|
||||||
</div>
|
</div>
|
||||||
<div>{_t("We’ll generate a Security Key for you to store somewhere safe, like a password manager or a safe.")}</div>
|
<div>{ _t("We’ll generate a Security Key for you to store somewhere safe, like a password manager or a safe.") }</div>
|
||||||
</StyledRadioButton>
|
</StyledRadioButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -494,9 +494,9 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
>
|
>
|
||||||
<div className="mx_CreateSecretStorageDialog_optionTitle">
|
<div className="mx_CreateSecretStorageDialog_optionTitle">
|
||||||
<span className="mx_CreateSecretStorageDialog_optionIcon mx_CreateSecretStorageDialog_optionIcon_securePhrase"></span>
|
<span className="mx_CreateSecretStorageDialog_optionIcon mx_CreateSecretStorageDialog_optionIcon_securePhrase"></span>
|
||||||
{_t("Enter a Security Phrase")}
|
{ _t("Enter a Security Phrase") }
|
||||||
</div>
|
</div>
|
||||||
<div>{_t("Use a secret phrase only you know, and optionally save a Security Key to use for backup.")}</div>
|
<div>{ _t("Use a secret phrase only you know, and optionally save a Security Key to use for backup.") }</div>
|
||||||
</StyledRadioButton>
|
</StyledRadioButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -507,13 +507,13 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
const optionPassphrase = setupMethods.includes("passphrase") ? this._renderOptionPassphrase() : null;
|
const optionPassphrase = setupMethods.includes("passphrase") ? this._renderOptionPassphrase() : null;
|
||||||
|
|
||||||
return <form onSubmit={this._onChooseKeyPassphraseFormSubmit}>
|
return <form onSubmit={this._onChooseKeyPassphraseFormSubmit}>
|
||||||
<p className="mx_CreateSecretStorageDialog_centeredBody">{_t(
|
<p className="mx_CreateSecretStorageDialog_centeredBody">{ _t(
|
||||||
"Safeguard against losing access to encrypted messages & data by " +
|
"Safeguard against losing access to encrypted messages & data by " +
|
||||||
"backing up encryption keys on your server.",
|
"backing up encryption keys on your server.",
|
||||||
)}</p>
|
) }</p>
|
||||||
<div className="mx_CreateSecretStorageDialog_primaryContainer" role="radiogroup">
|
<div className="mx_CreateSecretStorageDialog_primaryContainer" role="radiogroup">
|
||||||
{optionKey}
|
{ optionKey }
|
||||||
{optionPassphrase}
|
{ optionPassphrase }
|
||||||
</div>
|
</div>
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("Continue")}
|
primaryButton={_t("Continue")}
|
||||||
|
@ -536,7 +536,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
let nextCaption = _t("Next");
|
let nextCaption = _t("Next");
|
||||||
if (this.state.canUploadKeysWithPasswordOnly) {
|
if (this.state.canUploadKeysWithPasswordOnly) {
|
||||||
authPrompt = <div>
|
authPrompt = <div>
|
||||||
<div>{_t("Enter your account password to confirm the upgrade:")}</div>
|
<div>{ _t("Enter your account password to confirm the upgrade:") }</div>
|
||||||
<div><Field
|
<div><Field
|
||||||
type="password"
|
type="password"
|
||||||
label={_t("Password")}
|
label={_t("Password")}
|
||||||
|
@ -548,22 +548,22 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
</div>;
|
</div>;
|
||||||
} else if (!this.state.backupSigStatus.usable) {
|
} else if (!this.state.backupSigStatus.usable) {
|
||||||
authPrompt = <div>
|
authPrompt = <div>
|
||||||
<div>{_t("Restore your key backup to upgrade your encryption")}</div>
|
<div>{ _t("Restore your key backup to upgrade your encryption") }</div>
|
||||||
</div>;
|
</div>;
|
||||||
nextCaption = _t("Restore");
|
nextCaption = _t("Restore");
|
||||||
} else {
|
} else {
|
||||||
authPrompt = <p>
|
authPrompt = <p>
|
||||||
{_t("You'll need to authenticate with the server to confirm the upgrade.")}
|
{ _t("You'll need to authenticate with the server to confirm the upgrade.") }
|
||||||
</p>;
|
</p>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <form onSubmit={this._onMigrateFormSubmit}>
|
return <form onSubmit={this._onMigrateFormSubmit}>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"Upgrade this session to allow it to verify other sessions, " +
|
"Upgrade this session to allow it to verify other sessions, " +
|
||||||
"granting them access to encrypted messages and marking them " +
|
"granting them access to encrypted messages and marking them " +
|
||||||
"as trusted for other users.",
|
"as trusted for other users.",
|
||||||
)}</p>
|
) }</p>
|
||||||
<div>{authPrompt}</div>
|
<div>{ authPrompt }</div>
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={nextCaption}
|
primaryButton={nextCaption}
|
||||||
onPrimaryButtonClick={this._onMigrateFormSubmit}
|
onPrimaryButtonClick={this._onMigrateFormSubmit}
|
||||||
|
@ -571,7 +571,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
primaryDisabled={this.state.canUploadKeysWithPasswordOnly && !this.state.accountPassword}
|
primaryDisabled={this.state.canUploadKeysWithPasswordOnly && !this.state.accountPassword}
|
||||||
>
|
>
|
||||||
<button type="button" className="danger" onClick={this._onCancelClick}>
|
<button type="button" className="danger" onClick={this._onCancelClick}>
|
||||||
{_t('Skip')}
|
{ _t('Skip') }
|
||||||
</button>
|
</button>
|
||||||
</DialogButtons>
|
</DialogButtons>
|
||||||
</form>;
|
</form>;
|
||||||
|
@ -579,10 +579,10 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
|
|
||||||
_renderPhasePassPhrase() {
|
_renderPhasePassPhrase() {
|
||||||
return <form onSubmit={this._onPassPhraseNextClick}>
|
return <form onSubmit={this._onPassPhraseNextClick}>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"Enter a security phrase only you know, as it’s used to safeguard your data. " +
|
"Enter a security phrase only you know, as it’s used to safeguard your data. " +
|
||||||
"To be secure, you shouldn’t re-use your account password.",
|
"To be secure, you shouldn’t re-use your account password.",
|
||||||
)}</p>
|
) }</p>
|
||||||
|
|
||||||
<div className="mx_CreateSecretStorageDialog_passPhraseContainer">
|
<div className="mx_CreateSecretStorageDialog_passPhraseContainer">
|
||||||
<PassphraseField
|
<PassphraseField
|
||||||
|
@ -609,7 +609,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
<button type="button"
|
<button type="button"
|
||||||
onClick={this._onCancelClick}
|
onClick={this._onCancelClick}
|
||||||
className="danger"
|
className="danger"
|
||||||
>{_t("Cancel")}</button>
|
>{ _t("Cancel") }</button>
|
||||||
</DialogButtons>
|
</DialogButtons>
|
||||||
</form>;
|
</form>;
|
||||||
}
|
}
|
||||||
|
@ -637,18 +637,18 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
let passPhraseMatch = null;
|
let passPhraseMatch = null;
|
||||||
if (matchText) {
|
if (matchText) {
|
||||||
passPhraseMatch = <div>
|
passPhraseMatch = <div>
|
||||||
<div>{matchText}</div>
|
<div>{ matchText }</div>
|
||||||
<div>
|
<div>
|
||||||
<AccessibleButton element="span" className="mx_linkButton" onClick={this._onSetAgainClick}>
|
<AccessibleButton element="span" className="mx_linkButton" onClick={this._onSetAgainClick}>
|
||||||
{changeText}
|
{ changeText }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
return <form onSubmit={this._onPassPhraseConfirmNextClick}>
|
return <form onSubmit={this._onPassPhraseConfirmNextClick}>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"Enter your Security Phrase a second time to confirm it.",
|
"Enter your Security Phrase a second time to confirm it.",
|
||||||
)}</p>
|
) }</p>
|
||||||
<div className="mx_CreateSecretStorageDialog_passPhraseContainer">
|
<div className="mx_CreateSecretStorageDialog_passPhraseContainer">
|
||||||
<Field
|
<Field
|
||||||
type="password"
|
type="password"
|
||||||
|
@ -660,7 +660,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
<div className="mx_CreateSecretStorageDialog_passPhraseMatch">
|
<div className="mx_CreateSecretStorageDialog_passPhraseMatch">
|
||||||
{passPhraseMatch}
|
{ passPhraseMatch }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
|
@ -672,7 +672,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
<button type="button"
|
<button type="button"
|
||||||
onClick={this._onCancelClick}
|
onClick={this._onCancelClick}
|
||||||
className="danger"
|
className="danger"
|
||||||
>{_t("Skip")}</button>
|
>{ _t("Skip") }</button>
|
||||||
</DialogButtons>
|
</DialogButtons>
|
||||||
</form>;
|
</form>;
|
||||||
}
|
}
|
||||||
|
@ -691,35 +691,35 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
return <div>
|
return <div>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"Store your Security Key somewhere safe, like a password manager or a safe, " +
|
"Store your Security Key somewhere safe, like a password manager or a safe, " +
|
||||||
"as it’s used to safeguard your encrypted data.",
|
"as it’s used to safeguard your encrypted data.",
|
||||||
)}</p>
|
) }</p>
|
||||||
<div className="mx_CreateSecretStorageDialog_primaryContainer">
|
<div className="mx_CreateSecretStorageDialog_primaryContainer">
|
||||||
<div className="mx_CreateSecretStorageDialog_recoveryKeyContainer">
|
<div className="mx_CreateSecretStorageDialog_recoveryKeyContainer">
|
||||||
<div className="mx_CreateSecretStorageDialog_recoveryKey">
|
<div className="mx_CreateSecretStorageDialog_recoveryKey">
|
||||||
<code ref={this._collectRecoveryKeyNode}>{this._recoveryKey.encodedPrivateKey}</code>
|
<code ref={this._collectRecoveryKeyNode}>{ this._recoveryKey.encodedPrivateKey }</code>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_CreateSecretStorageDialog_recoveryKeyButtons">
|
<div className="mx_CreateSecretStorageDialog_recoveryKeyButtons">
|
||||||
<AccessibleButton kind='primary' className="mx_Dialog_primary"
|
<AccessibleButton kind='primary' className="mx_Dialog_primary"
|
||||||
onClick={this._onDownloadClick}
|
onClick={this._onDownloadClick}
|
||||||
disabled={this.state.phase === PHASE_STORING}
|
disabled={this.state.phase === PHASE_STORING}
|
||||||
>
|
>
|
||||||
{_t("Download")}
|
{ _t("Download") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
<span>{_t("or")}</span>
|
<span>{ _t("or") }</span>
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
kind='primary'
|
kind='primary'
|
||||||
className="mx_Dialog_primary mx_CreateSecretStorageDialog_recoveryKeyButtons_copyBtn"
|
className="mx_Dialog_primary mx_CreateSecretStorageDialog_recoveryKeyButtons_copyBtn"
|
||||||
onClick={this._onCopyClick}
|
onClick={this._onCopyClick}
|
||||||
disabled={this.state.phase === PHASE_STORING}
|
disabled={this.state.phase === PHASE_STORING}
|
||||||
>
|
>
|
||||||
{this.state.copied ? _t("Copied!") : _t("Copy")}
|
{ this.state.copied ? _t("Copied!") : _t("Copy") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{continueButton}
|
{ continueButton }
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,7 +732,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
|
|
||||||
_renderPhaseLoadError() {
|
_renderPhaseLoadError() {
|
||||||
return <div>
|
return <div>
|
||||||
<p>{_t("Unable to query secret storage status")}</p>
|
<p>{ _t("Unable to query secret storage status") }</p>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
<DialogButtons primaryButton={_t('Retry')}
|
<DialogButtons primaryButton={_t('Retry')}
|
||||||
onPrimaryButtonClick={this._onLoadRetryClick}
|
onPrimaryButtonClick={this._onLoadRetryClick}
|
||||||
|
@ -745,17 +745,17 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
|
|
||||||
_renderPhaseSkipConfirm() {
|
_renderPhaseSkipConfirm() {
|
||||||
return <div>
|
return <div>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"If you cancel now, you may lose encrypted messages & data if you lose access to your logins.",
|
"If you cancel now, you may lose encrypted messages & data if you lose access to your logins.",
|
||||||
)}</p>
|
) }</p>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"You can also set up Secure Backup & manage your keys in Settings.",
|
"You can also set up Secure Backup & manage your keys in Settings.",
|
||||||
)}</p>
|
) }</p>
|
||||||
<DialogButtons primaryButton={_t('Go back')}
|
<DialogButtons primaryButton={_t('Go back')}
|
||||||
onPrimaryButtonClick={this._onGoBackClick}
|
onPrimaryButtonClick={this._onGoBackClick}
|
||||||
hasCancel={false}
|
hasCancel={false}
|
||||||
>
|
>
|
||||||
<button type="button" className="danger" onClick={this._onCancel}>{_t('Cancel')}</button>
|
<button type="button" className="danger" onClick={this._onCancel}>{ _t('Cancel') }</button>
|
||||||
</DialogButtons>
|
</DialogButtons>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
@ -787,7 +787,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
let content;
|
let content;
|
||||||
if (this.state.error) {
|
if (this.state.error) {
|
||||||
content = <div>
|
content = <div>
|
||||||
<p>{_t("Unable to set up secret storage")}</p>
|
<p>{ _t("Unable to set up secret storage") }</p>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
<DialogButtons primaryButton={_t('Retry')}
|
<DialogButtons primaryButton={_t('Retry')}
|
||||||
onPrimaryButtonClick={this._bootstrapSecretStorage}
|
onPrimaryButtonClick={this._bootstrapSecretStorage}
|
||||||
|
@ -857,7 +857,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
fixedWidth={false}
|
fixedWidth={false}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
{content}
|
{ content }
|
||||||
</div>
|
</div>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
);
|
);
|
||||||
|
|
|
@ -54,28 +54,28 @@ export default class NewRecoveryMethodDialog extends React.PureComponent {
|
||||||
const DialogButtons = sdk.getComponent("views.elements.DialogButtons");
|
const DialogButtons = sdk.getComponent("views.elements.DialogButtons");
|
||||||
|
|
||||||
const title = <span className="mx_KeyBackupFailedDialog_title">
|
const title = <span className="mx_KeyBackupFailedDialog_title">
|
||||||
{_t("New Recovery Method")}
|
{ _t("New Recovery Method") }
|
||||||
</span>;
|
</span>;
|
||||||
|
|
||||||
const newMethodDetected = <p>{_t(
|
const newMethodDetected = <p>{ _t(
|
||||||
"A new Security Phrase and key for Secure Messages have been detected.",
|
"A new Security Phrase and key for Secure Messages have been detected.",
|
||||||
)}</p>;
|
) }</p>;
|
||||||
|
|
||||||
const hackWarning = <p className="warning">{_t(
|
const hackWarning = <p className="warning">{ _t(
|
||||||
"If you didn't set the new recovery method, an " +
|
"If you didn't set the new recovery method, an " +
|
||||||
"attacker may be trying to access your account. " +
|
"attacker may be trying to access your account. " +
|
||||||
"Change your account password and set a new recovery " +
|
"Change your account password and set a new recovery " +
|
||||||
"method immediately in Settings.",
|
"method immediately in Settings.",
|
||||||
)}</p>;
|
) }</p>;
|
||||||
|
|
||||||
let content;
|
let content;
|
||||||
if (MatrixClientPeg.get().getKeyBackupEnabled()) {
|
if (MatrixClientPeg.get().getKeyBackupEnabled()) {
|
||||||
content = <div>
|
content = <div>
|
||||||
{newMethodDetected}
|
{ newMethodDetected }
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"This session is encrypting history using the new recovery method.",
|
"This session is encrypting history using the new recovery method.",
|
||||||
)}</p>
|
) }</p>
|
||||||
{hackWarning}
|
{ hackWarning }
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("OK")}
|
primaryButton={_t("OK")}
|
||||||
onPrimaryButtonClick={this.onOkClick}
|
onPrimaryButtonClick={this.onOkClick}
|
||||||
|
@ -85,8 +85,8 @@ export default class NewRecoveryMethodDialog extends React.PureComponent {
|
||||||
</div>;
|
</div>;
|
||||||
} else {
|
} else {
|
||||||
content = <div>
|
content = <div>
|
||||||
{newMethodDetected}
|
{ newMethodDetected }
|
||||||
{hackWarning}
|
{ hackWarning }
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("Set up Secure Messages")}
|
primaryButton={_t("Set up Secure Messages")}
|
||||||
onPrimaryButtonClick={this.onSetupClick}
|
onPrimaryButtonClick={this.onSetupClick}
|
||||||
|
@ -101,7 +101,7 @@ export default class NewRecoveryMethodDialog extends React.PureComponent {
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
title={title}
|
title={title}
|
||||||
>
|
>
|
||||||
{content}
|
{ content }
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ export default class RecoveryMethodRemovedDialog extends React.PureComponent {
|
||||||
const DialogButtons = sdk.getComponent("views.elements.DialogButtons");
|
const DialogButtons = sdk.getComponent("views.elements.DialogButtons");
|
||||||
|
|
||||||
const title = <span className="mx_KeyBackupFailedDialog_title">
|
const title = <span className="mx_KeyBackupFailedDialog_title">
|
||||||
{_t("Recovery Method Removed")}
|
{ _t("Recovery Method Removed") }
|
||||||
</span>;
|
</span>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -55,21 +55,21 @@ export default class RecoveryMethodRemovedDialog extends React.PureComponent {
|
||||||
title={title}
|
title={title}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"This session has detected that your Security Phrase and key " +
|
"This session has detected that your Security Phrase and key " +
|
||||||
"for Secure Messages have been removed.",
|
"for Secure Messages have been removed.",
|
||||||
)}</p>
|
) }</p>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"If you did this accidentally, you can setup Secure Messages on " +
|
"If you did this accidentally, you can setup Secure Messages on " +
|
||||||
"this session which will re-encrypt this session's message " +
|
"this session which will re-encrypt this session's message " +
|
||||||
"history with a new recovery method.",
|
"history with a new recovery method.",
|
||||||
)}</p>
|
) }</p>
|
||||||
<p className="warning">{_t(
|
<p className="warning">{ _t(
|
||||||
"If you didn't remove the recovery method, an " +
|
"If you didn't remove the recovery method, an " +
|
||||||
"attacker may be trying to access your account. " +
|
"attacker may be trying to access your account. " +
|
||||||
"Change your account password and set a new recovery " +
|
"Change your account password and set a new recovery " +
|
||||||
"method immediately in Settings.",
|
"method immediately in Settings.",
|
||||||
)}</p>
|
) }</p>
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("Set up Secure Messages")}
|
primaryButton={_t("Set up Secure Messages")}
|
||||||
onPrimaryButtonClick={this.onSetupClick}
|
onPrimaryButtonClick={this.onSetupClick}
|
||||||
|
|
|
@ -109,7 +109,7 @@ export default class UserProvider extends AutocompleteProvider {
|
||||||
limit = -1,
|
limit = -1,
|
||||||
): Promise<ICompletion[]> {
|
): Promise<ICompletion[]> {
|
||||||
// lazy-load user list into matcher
|
// lazy-load user list into matcher
|
||||||
if (!this.users) this._makeUsers();
|
if (!this.users) this.makeUsers();
|
||||||
|
|
||||||
let completions = [];
|
let completions = [];
|
||||||
const { command, range } = this.getCurrentCommand(rawQuery, selection, force);
|
const { command, range } = this.getCurrentCommand(rawQuery, selection, force);
|
||||||
|
@ -147,7 +147,7 @@ export default class UserProvider extends AutocompleteProvider {
|
||||||
return _t('Users');
|
return _t('Users');
|
||||||
}
|
}
|
||||||
|
|
||||||
_makeUsers() {
|
private makeUsers() {
|
||||||
const events = this.room.getLiveTimeline().getEvents();
|
const events = this.room.getLiveTimeline().getEvents();
|
||||||
const lastSpoken = {};
|
const lastSpoken = {};
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ class CustomRoomTagPanel extends React.Component {
|
||||||
return (<div className={classes}>
|
return (<div className={classes}>
|
||||||
<div className="mx_CustomRoomTagPanel_divider" />
|
<div className="mx_CustomRoomTagPanel_divider" />
|
||||||
<AutoHideScrollbar className="mx_CustomRoomTagPanel_scroller">
|
<AutoHideScrollbar className="mx_CustomRoomTagPanel_scroller">
|
||||||
{tags}
|
{ tags }
|
||||||
</AutoHideScrollbar>
|
</AutoHideScrollbar>
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ class CustomRoomTagTile extends React.Component {
|
||||||
"mx_TagTile_badge": true,
|
"mx_TagTile_badge": true,
|
||||||
"mx_TagTile_badgeHighlight": badgeNotifState.hasMentions,
|
"mx_TagTile_badgeHighlight": badgeNotifState.hasMentions,
|
||||||
});
|
});
|
||||||
badgeElement = (<div className={badgeClasses}>{FormattingUtils.formatCount(badgeNotifState.count)}</div>);
|
badgeElement = (<div className={badgeClasses}>{ FormattingUtils.formatCount(badgeNotifState.count) }</div>);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -125,11 +125,11 @@ export default class EmbeddedPage extends React.PureComponent {
|
||||||
|
|
||||||
if (this.props.scrollbar) {
|
if (this.props.scrollbar) {
|
||||||
return <AutoHideScrollbar className={classes}>
|
return <AutoHideScrollbar className={classes}>
|
||||||
{content}
|
{ content }
|
||||||
</AutoHideScrollbar>;
|
</AutoHideScrollbar>;
|
||||||
} else {
|
} else {
|
||||||
return <div className={classes}>
|
return <div className={classes}>
|
||||||
{content}
|
{ content }
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -241,8 +241,8 @@ 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 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>
|
||||||
<p>{_t('Attach files from chat or just drag and drop them anywhere in a room.')}</p>
|
<p>{ _t('Attach files from chat or just drag and drop them anywhere in a room.') }</p>
|
||||||
</div>);
|
</div>);
|
||||||
|
|
||||||
const isRoomEncrypted = this.noRoom ? false : MatrixClientPeg.get().isRoomEncrypted(this.props.roomId);
|
const isRoomEncrypted = this.noRoom ? false : MatrixClientPeg.get().isRoomEncrypted(this.props.roomId);
|
||||||
|
@ -262,7 +262,7 @@ class FilePanel extends React.Component<IProps, IState> {
|
||||||
manageReadReceipts={false}
|
manageReadReceipts={false}
|
||||||
manageReadMarkers={false}
|
manageReadMarkers={false}
|
||||||
timelineSet={this.state.timelineSet}
|
timelineSet={this.state.timelineSet}
|
||||||
showUrlPreview = {false}
|
showUrlPreview={false}
|
||||||
onPaginationRequest={this.onPaginationRequest}
|
onPaginationRequest={this.onPaginationRequest}
|
||||||
tileShape={TileShape.FileGrid}
|
tileShape={TileShape.FileGrid}
|
||||||
resizeNotifier={this.props.resizeNotifier}
|
resizeNotifier={this.props.resizeNotifier}
|
||||||
|
|
|
@ -28,8 +28,8 @@ export default class GenericErrorPage extends React.PureComponent {
|
||||||
render() {
|
render() {
|
||||||
return <div className='mx_GenericErrorPage'>
|
return <div className='mx_GenericErrorPage'>
|
||||||
<div className='mx_GenericErrorPage_box'>
|
<div className='mx_GenericErrorPage_box'>
|
||||||
<h1>{this.props.title}</h1>
|
<h1>{ this.props.title }</h1>
|
||||||
<p>{this.props.message}</p>
|
<p>{ this.props.message }</p>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -819,12 +819,12 @@ export default class GroupView extends React.Component {
|
||||||
let hostingSignup = null;
|
let hostingSignup = null;
|
||||||
if (hostingSignupLink && this.state.isUserPrivileged) {
|
if (hostingSignupLink && this.state.isUserPrivileged) {
|
||||||
hostingSignup = <div className="mx_GroupView_hostingSignup">
|
hostingSignup = <div className="mx_GroupView_hostingSignup">
|
||||||
{_t(
|
{ _t(
|
||||||
"Want more than a community? <a>Get your own server</a>", {},
|
"Want more than a community? <a>Get your own server</a>", {},
|
||||||
{
|
{
|
||||||
a: sub => <a href={hostingSignupLink} target="_blank" rel="noreferrer noopener">{sub}</a>,
|
a: sub => <a href={hostingSignupLink} target="_blank" rel="noreferrer noopener">{ sub }</a>,
|
||||||
},
|
},
|
||||||
)}
|
) }
|
||||||
<a href={hostingSignupLink} target="_blank" rel="noreferrer noopener">
|
<a href={hostingSignupLink} target="_blank" rel="noreferrer noopener">
|
||||||
<img src={require("../../../res/img/external-link.svg")} width="11" height="10" alt='' />
|
<img src={require("../../../res/img/external-link.svg")} width="11" height="10" alt='' />
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -429,7 +429,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
onSelectRoom={this.selectRoom}
|
onSelectRoom={this.selectRoom}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{dialPadButton}
|
{ dialPadButton }
|
||||||
|
|
||||||
<AccessibleTooltipButton
|
<AccessibleTooltipButton
|
||||||
className={classNames("mx_LeftPanel_exploreButton", {
|
className={classNames("mx_LeftPanel_exploreButton", {
|
||||||
|
@ -448,7 +448,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
leftLeftPanel = (
|
leftLeftPanel = (
|
||||||
<div className="mx_LeftPanel_GroupFilterPanelContainer">
|
<div className="mx_LeftPanel_GroupFilterPanelContainer">
|
||||||
<GroupFilterPanel />
|
<GroupFilterPanel />
|
||||||
{SettingsStore.getValue("feature_custom_tags") ? <CustomRoomTagPanel /> : null}
|
{ SettingsStore.getValue("feature_custom_tags") ? <CustomRoomTagPanel /> : null }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -476,11 +476,11 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={containerClasses} ref={this.ref}>
|
<div className={containerClasses} ref={this.ref}>
|
||||||
{leftLeftPanel}
|
{ leftLeftPanel }
|
||||||
<aside className="mx_LeftPanel_roomListContainer">
|
<aside className="mx_LeftPanel_roomListContainer">
|
||||||
{this.renderHeader()}
|
{ this.renderHeader() }
|
||||||
{this.renderSearchDialExplore()}
|
{ this.renderSearchDialExplore() }
|
||||||
{this.renderBreadcrumbs()}
|
{ this.renderBreadcrumbs() }
|
||||||
<RoomListNumResults onVisibilityChange={this.refreshStickyHeaders} />
|
<RoomListNumResults onVisibilityChange={this.refreshStickyHeaders} />
|
||||||
<div className="mx_LeftPanel_roomListWrapper">
|
<div className="mx_LeftPanel_roomListWrapper">
|
||||||
<div
|
<div
|
||||||
|
@ -490,7 +490,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
// overflow:scroll;, so force it out of tab order.
|
// overflow:scroll;, so force it out of tab order.
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
>
|
>
|
||||||
{roomList}
|
{ roomList }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{ !this.props.isMinimized && <LeftPanelWidget /> }
|
{ !this.props.isMinimized && <LeftPanelWidget /> }
|
||||||
|
|
|
@ -125,15 +125,15 @@ const LeftPanelWidget: React.FC = () => {
|
||||||
<span>{ WidgetUtils.getWidgetName(app) }</span>
|
<span>{ WidgetUtils.getWidgetName(app) }</span>
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
|
|
||||||
{/* Code for the maximise button for once we have full screen widgets */}
|
{ /* Code for the maximise button for once we have full screen widgets */ }
|
||||||
{/*<AccessibleTooltipButton
|
{ /*<AccessibleTooltipButton
|
||||||
tabIndex={tabIndex}
|
tabIndex={tabIndex}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
}}
|
}}
|
||||||
className="mx_LeftPanelWidget_maximizeButton"
|
className="mx_LeftPanelWidget_maximizeButton"
|
||||||
tooltipClassName="mx_LeftPanelWidget_maximizeButtonTooltip"
|
tooltipClassName="mx_LeftPanelWidget_maximizeButtonTooltip"
|
||||||
title={_t("Maximize")}
|
title={_t("Maximize")}
|
||||||
/>*/}
|
/>*/ }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import * as PropTypes from 'prop-types';
|
|
||||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||||
|
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
||||||
|
|
||||||
import { Key } from '../../Keyboard';
|
import { Key } from '../../Keyboard';
|
||||||
import PageTypes from '../../PageTypes';
|
import PageTypes from '../../PageTypes';
|
||||||
|
@ -79,6 +79,8 @@ function canElementReceiveInput(el) {
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
matrixClient: MatrixClient;
|
matrixClient: MatrixClient;
|
||||||
|
// Called with the credentials of a registered user (if they were a ROU that
|
||||||
|
// transitioned to PWLU)
|
||||||
onRegistered: (credentials: IMatrixClientCreds) => Promise<MatrixClient>;
|
onRegistered: (credentials: IMatrixClientCreds) => Promise<MatrixClient>;
|
||||||
hideToSRUsers: boolean;
|
hideToSRUsers: boolean;
|
||||||
resizeNotifier: ResizeNotifier;
|
resizeNotifier: ResizeNotifier;
|
||||||
|
@ -140,18 +142,6 @@ interface IState {
|
||||||
class LoggedInView extends React.Component<IProps, IState> {
|
class LoggedInView extends React.Component<IProps, IState> {
|
||||||
static displayName = 'LoggedInView';
|
static displayName = 'LoggedInView';
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
matrixClient: PropTypes.instanceOf(MatrixClient).isRequired,
|
|
||||||
page_type: PropTypes.string.isRequired,
|
|
||||||
onRoomCreated: PropTypes.func,
|
|
||||||
|
|
||||||
// Called with the credentials of a registered user (if they were a ROU that
|
|
||||||
// transitioned to PWLU)
|
|
||||||
onRegistered: PropTypes.func,
|
|
||||||
|
|
||||||
// and lots and lots of other stuff.
|
|
||||||
};
|
|
||||||
|
|
||||||
protected readonly _matrixClient: MatrixClient;
|
protected readonly _matrixClient: MatrixClient;
|
||||||
protected readonly _roomView: React.RefObject<any>;
|
protected readonly _roomView: React.RefObject<any>;
|
||||||
protected readonly _resizeContainer: React.RefObject<ResizeHandle>;
|
protected readonly _resizeContainer: React.RefObject<ResizeHandle>;
|
||||||
|
@ -181,10 +171,10 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
document.addEventListener('keydown', this._onNativeKeyDown, false);
|
document.addEventListener('keydown', this.onNativeKeyDown, false);
|
||||||
CallHandler.sharedInstance().addListener(CallHandlerEvent.CallsChanged, this.onCallsChanged);
|
CallHandler.sharedInstance().addListener(CallHandlerEvent.CallsChanged, this.onCallsChanged);
|
||||||
|
|
||||||
this._updateServerNoticeEvents();
|
this.updateServerNoticeEvents();
|
||||||
|
|
||||||
this._matrixClient.on("accountData", this.onAccountData);
|
this._matrixClient.on("accountData", this.onAccountData);
|
||||||
this._matrixClient.on("sync", this.onSync);
|
this._matrixClient.on("sync", this.onSync);
|
||||||
|
@ -200,13 +190,13 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
"useCompactLayout", null, this.onCompactLayoutChanged,
|
"useCompactLayout", null, this.onCompactLayoutChanged,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.resizer = this._createResizer();
|
this.resizer = this.createResizer();
|
||||||
this.resizer.attach();
|
this.resizer.attach();
|
||||||
this._loadResizerPreferences();
|
this.loadResizerPreferences();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
document.removeEventListener('keydown', this._onNativeKeyDown, false);
|
document.removeEventListener('keydown', this.onNativeKeyDown, false);
|
||||||
CallHandler.sharedInstance().removeListener(CallHandlerEvent.CallsChanged, this.onCallsChanged);
|
CallHandler.sharedInstance().removeListener(CallHandlerEvent.CallsChanged, this.onCallsChanged);
|
||||||
this._matrixClient.removeListener("accountData", this.onAccountData);
|
this._matrixClient.removeListener("accountData", this.onAccountData);
|
||||||
this._matrixClient.removeListener("sync", this.onSync);
|
this._matrixClient.removeListener("sync", this.onSync);
|
||||||
|
@ -221,37 +211,37 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
canResetTimelineInRoom = (roomId) => {
|
public canResetTimelineInRoom = (roomId: string) => {
|
||||||
if (!this._roomView.current) {
|
if (!this._roomView.current) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return this._roomView.current.canResetTimeline();
|
return this._roomView.current.canResetTimeline();
|
||||||
};
|
};
|
||||||
|
|
||||||
_createResizer() {
|
private createResizer() {
|
||||||
let size;
|
let panelSize;
|
||||||
let collapsed;
|
let panelCollapsed;
|
||||||
const collapseConfig: ICollapseConfig = {
|
const collapseConfig: ICollapseConfig = {
|
||||||
// TODO decrease this once Spaces launches as it'll no longer need to include the 56px Community Panel
|
// TODO decrease this once Spaces launches as it'll no longer need to include the 56px Community Panel
|
||||||
toggleSize: 206 - 50,
|
toggleSize: 206 - 50,
|
||||||
onCollapsed: (_collapsed) => {
|
onCollapsed: (collapsed) => {
|
||||||
collapsed = _collapsed;
|
panelCollapsed = collapsed;
|
||||||
if (_collapsed) {
|
if (collapsed) {
|
||||||
dis.dispatch({ action: "hide_left_panel" });
|
dis.dispatch({ action: "hide_left_panel" });
|
||||||
window.localStorage.setItem("mx_lhs_size", '0');
|
window.localStorage.setItem("mx_lhs_size", '0');
|
||||||
} else {
|
} else {
|
||||||
dis.dispatch({ action: "show_left_panel" });
|
dis.dispatch({ action: "show_left_panel" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onResized: (_size) => {
|
onResized: (size) => {
|
||||||
size = _size;
|
panelSize = size;
|
||||||
this.props.resizeNotifier.notifyLeftHandleResized();
|
this.props.resizeNotifier.notifyLeftHandleResized();
|
||||||
},
|
},
|
||||||
onResizeStart: () => {
|
onResizeStart: () => {
|
||||||
this.props.resizeNotifier.startResizing();
|
this.props.resizeNotifier.startResizing();
|
||||||
},
|
},
|
||||||
onResizeStop: () => {
|
onResizeStop: () => {
|
||||||
if (!collapsed) window.localStorage.setItem("mx_lhs_size", '' + size);
|
if (!panelCollapsed) window.localStorage.setItem("mx_lhs_size", '' + panelSize);
|
||||||
this.props.resizeNotifier.stopResizing();
|
this.props.resizeNotifier.stopResizing();
|
||||||
},
|
},
|
||||||
isItemCollapsed: domNode => {
|
isItemCollapsed: domNode => {
|
||||||
|
@ -267,7 +257,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
return resizer;
|
return resizer;
|
||||||
}
|
}
|
||||||
|
|
||||||
_loadResizerPreferences() {
|
private loadResizerPreferences() {
|
||||||
let lhsSize = parseInt(window.localStorage.getItem("mx_lhs_size"), 10);
|
let lhsSize = parseInt(window.localStorage.getItem("mx_lhs_size"), 10);
|
||||||
if (isNaN(lhsSize)) {
|
if (isNaN(lhsSize)) {
|
||||||
lhsSize = 350;
|
lhsSize = 350;
|
||||||
|
@ -275,7 +265,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
this.resizer.forHandleAt(0).resize(lhsSize);
|
this.resizer.forHandleAt(0).resize(lhsSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
onAccountData = (event) => {
|
private onAccountData = (event: MatrixEvent) => {
|
||||||
if (event.getType() === "m.ignored_user_list") {
|
if (event.getType() === "m.ignored_user_list") {
|
||||||
dis.dispatch({ action: "ignore_state_changed" });
|
dis.dispatch({ action: "ignore_state_changed" });
|
||||||
}
|
}
|
||||||
|
@ -307,16 +297,16 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldSyncState === 'PREPARED' && syncState === 'SYNCING') {
|
if (oldSyncState === 'PREPARED' && syncState === 'SYNCING') {
|
||||||
this._updateServerNoticeEvents();
|
this.updateServerNoticeEvents();
|
||||||
} else {
|
} else {
|
||||||
this._calculateServerLimitToast(this.state.syncErrorData, this.state.usageLimitEventContent);
|
this.calculateServerLimitToast(this.state.syncErrorData, this.state.usageLimitEventContent);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onRoomStateEvents = (ev, state) => {
|
onRoomStateEvents = (ev, state) => {
|
||||||
const serverNoticeList = RoomListStore.instance.orderedLists[DefaultTagID.ServerNotice];
|
const serverNoticeList = RoomListStore.instance.orderedLists[DefaultTagID.ServerNotice];
|
||||||
if (serverNoticeList && serverNoticeList.some(r => r.roomId === ev.getRoomId())) {
|
if (serverNoticeList && serverNoticeList.some(r => r.roomId === ev.getRoomId())) {
|
||||||
this._updateServerNoticeEvents();
|
this.updateServerNoticeEvents();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -326,7 +316,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
_calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit) {
|
private calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit) {
|
||||||
const error = syncError && syncError.error && syncError.error.errcode === "M_RESOURCE_LIMIT_EXCEEDED";
|
const error = syncError && syncError.error && syncError.error.errcode === "M_RESOURCE_LIMIT_EXCEEDED";
|
||||||
if (error) {
|
if (error) {
|
||||||
usageLimitEventContent = syncError.error.data;
|
usageLimitEventContent = syncError.error.data;
|
||||||
|
@ -346,7 +336,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateServerNoticeEvents = async () => {
|
private updateServerNoticeEvents = async () => {
|
||||||
const serverNoticeList = RoomListStore.instance.orderedLists[DefaultTagID.ServerNotice];
|
const serverNoticeList = RoomListStore.instance.orderedLists[DefaultTagID.ServerNotice];
|
||||||
if (!serverNoticeList) return [];
|
if (!serverNoticeList) return [];
|
||||||
|
|
||||||
|
@ -378,7 +368,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
const usageLimitEventContent = usageLimitEvent && usageLimitEvent.getContent();
|
const usageLimitEventContent = usageLimitEvent && usageLimitEvent.getContent();
|
||||||
this._calculateServerLimitToast(this.state.syncErrorData, usageLimitEventContent);
|
this.calculateServerLimitToast(this.state.syncErrorData, usageLimitEventContent);
|
||||||
this.setState({
|
this.setState({
|
||||||
usageLimitEventContent,
|
usageLimitEventContent,
|
||||||
usageLimitEventTs: pinnedEventTs,
|
usageLimitEventTs: pinnedEventTs,
|
||||||
|
@ -387,7 +377,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
_onPaste = (ev) => {
|
private onPaste = (ev) => {
|
||||||
let canReceiveInput = false;
|
let canReceiveInput = false;
|
||||||
let element = ev.target;
|
let element = ev.target;
|
||||||
// test for all parents because the target can be a child of a contenteditable element
|
// test for all parents because the target can be a child of a contenteditable element
|
||||||
|
@ -425,22 +415,22 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
We also listen with a native listener on the document to get keydown events when no element is focused.
|
We also listen with a native listener on the document to get keydown events when no element is focused.
|
||||||
Bubbling is irrelevant here as the target is the body element.
|
Bubbling is irrelevant here as the target is the body element.
|
||||||
*/
|
*/
|
||||||
_onReactKeyDown = (ev) => {
|
private onReactKeyDown = (ev) => {
|
||||||
// events caught while bubbling up on the root element
|
// events caught while bubbling up on the root element
|
||||||
// of this component, so something must be focused.
|
// of this component, so something must be focused.
|
||||||
this._onKeyDown(ev);
|
this.onKeyDown(ev);
|
||||||
};
|
};
|
||||||
|
|
||||||
_onNativeKeyDown = (ev) => {
|
private onNativeKeyDown = (ev) => {
|
||||||
// only pass this if there is no focused element.
|
// only pass this if there is no focused element.
|
||||||
// if there is, _onKeyDown will be called by the
|
// if there is, onKeyDown will be called by the
|
||||||
// react keydown handler that respects the react bubbling order.
|
// react keydown handler that respects the react bubbling order.
|
||||||
if (ev.target === document.body) {
|
if (ev.target === document.body) {
|
||||||
this._onKeyDown(ev);
|
this.onKeyDown(ev);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_onKeyDown = (ev) => {
|
private onKeyDown = (ev) => {
|
||||||
let handled = false;
|
let handled = false;
|
||||||
|
|
||||||
const roomAction = getKeyBindingsManager().getRoomAction(ev);
|
const roomAction = getKeyBindingsManager().getRoomAction(ev);
|
||||||
|
@ -450,7 +440,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
case RoomAction.JumpToFirstMessage:
|
case RoomAction.JumpToFirstMessage:
|
||||||
case RoomAction.JumpToLatestMessage:
|
case RoomAction.JumpToLatestMessage:
|
||||||
// pass the event down to the scroll panel
|
// pass the event down to the scroll panel
|
||||||
this._onScrollKeyPressed(ev);
|
this.onScrollKeyPressed(ev);
|
||||||
handled = true;
|
handled = true;
|
||||||
break;
|
break;
|
||||||
case RoomAction.FocusSearch:
|
case RoomAction.FocusSearch:
|
||||||
|
@ -565,7 +555,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
* dispatch a page-up/page-down/etc to the appropriate component
|
* dispatch a page-up/page-down/etc to the appropriate component
|
||||||
* @param {Object} ev The key event
|
* @param {Object} ev The key event
|
||||||
*/
|
*/
|
||||||
_onScrollKeyPressed = (ev) => {
|
private onScrollKeyPressed = (ev) => {
|
||||||
if (this._roomView.current) {
|
if (this._roomView.current) {
|
||||||
this._roomView.current.handleScrollKey(ev);
|
this._roomView.current.handleScrollKey(ev);
|
||||||
}
|
}
|
||||||
|
@ -625,8 +615,8 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
return (
|
return (
|
||||||
<MatrixClientContext.Provider value={this._matrixClient}>
|
<MatrixClientContext.Provider value={this._matrixClient}>
|
||||||
<div
|
<div
|
||||||
onPaste={this._onPaste}
|
onPaste={this.onPaste}
|
||||||
onKeyDown={this._onReactKeyDown}
|
onKeyDown={this.onReactKeyDown}
|
||||||
className='mx_MatrixChat_wrapper'
|
className='mx_MatrixChat_wrapper'
|
||||||
aria-hidden={this.props.hideToSRUsers}
|
aria-hidden={this.props.hideToSRUsers}
|
||||||
>
|
>
|
||||||
|
@ -644,7 +634,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
<CallContainer />
|
<CallContainer />
|
||||||
<NonUrgentToastContainer />
|
<NonUrgentToastContainer />
|
||||||
<HostSignupContainer />
|
<HostSignupContainer />
|
||||||
{audioFeedArraysForCalls}
|
{ audioFeedArraysForCalls }
|
||||||
</MatrixClientContext.Provider>
|
</MatrixClientContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -431,7 +431,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: [REACT-WARNING] Replace with appropriate lifecycle stage
|
// TODO: [REACT-WARNING] Replace with appropriate lifecycle stage
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line
|
||||||
UNSAFE_componentWillUpdate(props, state) {
|
UNSAFE_componentWillUpdate(props, state) {
|
||||||
if (this.shouldTrackPageChange(this.state, state)) {
|
if (this.shouldTrackPageChange(this.state, state)) {
|
||||||
this.startPageChangeTimer();
|
this.startPageChangeTimer();
|
||||||
|
@ -1112,7 +1112,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
if (memberCount === 1) {
|
if (memberCount === 1) {
|
||||||
warnings.push((
|
warnings.push((
|
||||||
<span className="warning" key="only_member_warning">
|
<span className="warning" key="only_member_warning">
|
||||||
{' '/* Whitespace, otherwise the sentences get smashed together */ }
|
{ ' '/* Whitespace, otherwise the sentences get smashed together */ }
|
||||||
{ _t("You are the only person here. " +
|
{ _t("You are the only person here. " +
|
||||||
"If you leave, no one will be able to join in the future, including you.") }
|
"If you leave, no one will be able to join in the future, including you.") }
|
||||||
</span>
|
</span>
|
||||||
|
@ -1127,7 +1127,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
if (rule !== "public") {
|
if (rule !== "public") {
|
||||||
warnings.push((
|
warnings.push((
|
||||||
<span className="warning" key="non_public_warning">
|
<span className="warning" key="non_public_warning">
|
||||||
{' '/* Whitespace, otherwise the sentences get smashed together */ }
|
{ ' '/* Whitespace, otherwise the sentences get smashed together */ }
|
||||||
{ isSpace
|
{ isSpace
|
||||||
? _t("This space is not public. You will not be able to rejoin without an invite.")
|
? _t("This space is not public. You will not be able to rejoin without an invite.")
|
||||||
: _t("This room is not public. You will not be able to rejoin without an invite.") }
|
: _t("This room is not public. You will not be able to rejoin without an invite.") }
|
||||||
|
@ -1155,7 +1155,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
: _t(
|
: _t(
|
||||||
"Are you sure you want to leave the room '%(roomName)s'?",
|
"Are you sure you want to leave the room '%(roomName)s'?",
|
||||||
{ roomName: roomToLeave.name },
|
{ roomName: roomToLeave.name },
|
||||||
)}
|
) }
|
||||||
{ warnings }
|
{ warnings }
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
|
@ -1864,13 +1864,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
dis.dispatch({ action: 'timeline_resize' });
|
dis.dispatch({ action: 'timeline_resize' });
|
||||||
}
|
}
|
||||||
|
|
||||||
onRoomCreated(roomId: string) {
|
|
||||||
dis.dispatch({
|
|
||||||
action: "view_room",
|
|
||||||
room_id: roomId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onRegisterClick = () => {
|
onRegisterClick = () => {
|
||||||
this.showScreen("register");
|
this.showScreen("register");
|
||||||
};
|
};
|
||||||
|
@ -2043,7 +2036,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
{...this.state}
|
{...this.state}
|
||||||
ref={this.loggedInView}
|
ref={this.loggedInView}
|
||||||
matrixClient={MatrixClientPeg.get()}
|
matrixClient={MatrixClientPeg.get()}
|
||||||
onRoomCreated={this.onRoomCreated}
|
|
||||||
onRegistered={this.onRegistered}
|
onRegistered={this.onRegistered}
|
||||||
currentRoomId={this.state.currentRoomId}
|
currentRoomId={this.state.currentRoomId}
|
||||||
/>
|
/>
|
||||||
|
@ -2053,15 +2045,15 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
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">
|
||||||
{messageForSyncError(this.state.syncError)}
|
{ messageForSyncError(this.state.syncError) }
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
view = (
|
view = (
|
||||||
<div className="mx_MatrixChat_splash">
|
<div className="mx_MatrixChat_splash">
|
||||||
{errorBox}
|
{ errorBox }
|
||||||
<Spinner />
|
<Spinner />
|
||||||
<a href="#" className="mx_MatrixChat_splashButtons" onClick={this.onLogoutClick}>
|
<a href="#" className="mx_MatrixChat_splashButtons" onClick={this.onLogoutClick}>
|
||||||
{_t('Logout')}
|
{ _t('Logout') }
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -2124,7 +2116,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
return <ErrorBoundary>
|
return <ErrorBoundary>
|
||||||
{view}
|
{ view }
|
||||||
</ErrorBoundary>;
|
</ErrorBoundary>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -653,8 +653,10 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let willWantDateSeparator = false;
|
let willWantDateSeparator = false;
|
||||||
|
let lastInSection = true;
|
||||||
if (nextEvent) {
|
if (nextEvent) {
|
||||||
willWantDateSeparator = this.wantsDateSeparator(mxEv, nextEvent.getDate() || new Date());
|
willWantDateSeparator = this.wantsDateSeparator(mxEv, nextEvent.getDate() || new Date());
|
||||||
|
lastInSection = willWantDateSeparator || mxEv.getSender() !== nextEvent.getSender();
|
||||||
}
|
}
|
||||||
|
|
||||||
// is this a continuation of the previous message?
|
// is this a continuation of the previous message?
|
||||||
|
@ -712,7 +714,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||||
isTwelveHour={this.props.isTwelveHour}
|
isTwelveHour={this.props.isTwelveHour}
|
||||||
permalinkCreator={this.props.permalinkCreator}
|
permalinkCreator={this.props.permalinkCreator}
|
||||||
last={last}
|
last={last}
|
||||||
lastInSection={willWantDateSeparator}
|
lastInSection={lastInSection}
|
||||||
lastSuccessful={isLastSuccessful}
|
lastSuccessful={isLastSuccessful}
|
||||||
isSelectedEvent={highlight}
|
isSelectedEvent={highlight}
|
||||||
getRelationsForEvent={this.props.getRelationsForEvent}
|
getRelationsForEvent={this.props.getRelationsForEvent}
|
||||||
|
@ -720,6 +722,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||||
layout={this.props.layout}
|
layout={this.props.layout}
|
||||||
enableFlair={this.props.enableFlair}
|
enableFlair={this.props.enableFlair}
|
||||||
showReadReceipts={this.props.showReadReceipts}
|
showReadReceipts={this.props.showReadReceipts}
|
||||||
|
hideSender={this.props.room.getMembers().length <= 2 && this.props.layout === Layout.Bubble}
|
||||||
/>
|
/>
|
||||||
</TileErrorBoundary>,
|
</TileErrorBoundary>,
|
||||||
);
|
);
|
||||||
|
|
|
@ -121,7 +121,7 @@ export default class MyGroups extends React.Component {
|
||||||
) }
|
) }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/*<div className="mx_MyGroups_joinBox mx_MyGroups_headerCard">
|
{ /*<div className="mx_MyGroups_joinBox mx_MyGroups_headerCard">
|
||||||
<AccessibleButton className='mx_MyGroups_headerCard_button' onClick={this._onJoinGroupClick}>
|
<AccessibleButton className='mx_MyGroups_headerCard_button' onClick={this._onJoinGroupClick}>
|
||||||
<img src={require("../../../res/img/icons-create-room.svg")} width="50" height="50" />
|
<img src={require("../../../res/img/icons-create-room.svg")} width="50" height="50" />
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
|
@ -137,7 +137,7 @@ export default class MyGroups extends React.Component {
|
||||||
{ 'i': (sub) => <i>{ sub }</i> })
|
{ 'i': (sub) => <i>{ sub }</i> })
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>*/}
|
</div>*/ }
|
||||||
</div>
|
</div>
|
||||||
<BetaCard featureId="feature_spaces" title={_t("Communities are changing to Spaces")} />
|
<BetaCard featureId="feature_spaces" title={_t("Communities are changing to Spaces")} />
|
||||||
<div className="mx_MyGroups_content">
|
<div className="mx_MyGroups_content">
|
||||||
|
|
|
@ -51,14 +51,14 @@ export default class NonUrgentToastContainer extends React.PureComponent<IProps,
|
||||||
const toasts = this.state.toasts.map((t, i) => {
|
const toasts = this.state.toasts.map((t, i) => {
|
||||||
return (
|
return (
|
||||||
<div className="mx_NonUrgentToastContainer_toast" key={`toast-${i}`}>
|
<div className="mx_NonUrgentToastContainer_toast" key={`toast-${i}`}>
|
||||||
{React.createElement(t, {})}
|
{ React.createElement(t, {}) }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_NonUrgentToastContainer" role="alert">
|
<div className="mx_NonUrgentToastContainer" role="alert">
|
||||||
{toasts}
|
{ toasts }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,8 @@ interface IProps {
|
||||||
export default class NotificationPanel extends React.PureComponent<IProps> {
|
export default class NotificationPanel extends React.PureComponent<IProps> {
|
||||||
render() {
|
render() {
|
||||||
const emptyState = (<div className="mx_RightPanel_empty mx_NotificationPanel_empty">
|
const emptyState = (<div className="mx_RightPanel_empty mx_NotificationPanel_empty">
|
||||||
<h2>{_t('You’re all caught up')}</h2>
|
<h2>{ _t('You’re all caught up') }</h2>
|
||||||
<p>{_t('You have no visible notifications.')}</p>
|
<p>{ _t('You have no visible notifications.') }</p>
|
||||||
</div>);
|
</div>);
|
||||||
|
|
||||||
let content;
|
let content;
|
||||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
import { RoomState } from "matrix-js-sdk/src/models/room-state";
|
||||||
import { User } from "matrix-js-sdk/src/models/user";
|
import { User } from "matrix-js-sdk/src/models/user";
|
||||||
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";
|
||||||
|
@ -152,7 +153,7 @@ export default class RightPanel extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
|
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
|
||||||
UNSAFE_componentWillReceiveProps(newProps) { // eslint-disable-line camelcase
|
UNSAFE_componentWillReceiveProps(newProps) { // eslint-disable-line
|
||||||
if (newProps.groupId !== this.props.groupId) {
|
if (newProps.groupId !== this.props.groupId) {
|
||||||
this.unregisterGroupStore();
|
this.unregisterGroupStore();
|
||||||
this.initGroupStore(newProps.groupId);
|
this.initGroupStore(newProps.groupId);
|
||||||
|
@ -174,7 +175,7 @@ export default class RightPanel extends React.Component<IProps, IState> {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
private onRoomStateMember = (ev: MatrixEvent, _, member: RoomMember) => {
|
private onRoomStateMember = (ev: MatrixEvent, state: RoomState, member: RoomMember) => {
|
||||||
if (!this.props.room || member.roomId !== this.props.room.roomId) {
|
if (!this.props.room || member.roomId !== this.props.room.roomId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -589,7 +589,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
|
||||||
// We use onMouseDown instead of onClick, so that we can avoid text getting selected
|
// We use onMouseDown instead of onClick, so that we can avoid text getting selected
|
||||||
return [
|
return [
|
||||||
<div
|
<div
|
||||||
key={ `${room.room_id}_avatar` }
|
key={`${room.room_id}_avatar`}
|
||||||
onMouseDown={(ev) => this.onRoomClicked(room, ev)}
|
onMouseDown={(ev) => this.onRoomClicked(room, ev)}
|
||||||
className="mx_RoomDirectory_roomAvatar"
|
className="mx_RoomDirectory_roomAvatar"
|
||||||
>
|
>
|
||||||
|
@ -603,7 +603,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
|
||||||
/>
|
/>
|
||||||
</div>,
|
</div>,
|
||||||
<div
|
<div
|
||||||
key={ `${room.room_id}_description` }
|
key={`${room.room_id}_description`}
|
||||||
onMouseDown={(ev) => this.onRoomClicked(room, ev)}
|
onMouseDown={(ev) => this.onRoomClicked(room, ev)}
|
||||||
className="mx_RoomDirectory_roomDescription"
|
className="mx_RoomDirectory_roomDescription"
|
||||||
>
|
>
|
||||||
|
@ -626,14 +626,14 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
|
||||||
</div>
|
</div>
|
||||||
</div>,
|
</div>,
|
||||||
<div
|
<div
|
||||||
key={ `${room.room_id}_memberCount` }
|
key={`${room.room_id}_memberCount`}
|
||||||
onMouseDown={(ev) => this.onRoomClicked(room, ev)}
|
onMouseDown={(ev) => this.onRoomClicked(room, ev)}
|
||||||
className="mx_RoomDirectory_roomMemberCount"
|
className="mx_RoomDirectory_roomMemberCount"
|
||||||
>
|
>
|
||||||
{ room.num_joined_members }
|
{ room.num_joined_members }
|
||||||
</div>,
|
</div>,
|
||||||
<div
|
<div
|
||||||
key={ `${room.room_id}_preview` }
|
key={`${room.room_id}_preview`}
|
||||||
onMouseDown={(ev) => this.onRoomClicked(room, ev)}
|
onMouseDown={(ev) => this.onRoomClicked(room, ev)}
|
||||||
// cancel onMouseDown otherwise shift-clicking highlights text
|
// cancel onMouseDown otherwise shift-clicking highlights text
|
||||||
className="mx_RoomDirectory_preview"
|
className="mx_RoomDirectory_preview"
|
||||||
|
@ -641,7 +641,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
|
||||||
{ previewButton }
|
{ previewButton }
|
||||||
</div>,
|
</div>,
|
||||||
<div
|
<div
|
||||||
key={ `${room.room_id}_join` }
|
key={`${room.room_id}_join`}
|
||||||
onMouseDown={(ev) => this.onRoomClicked(room, ev)}
|
onMouseDown={(ev) => this.onRoomClicked(room, ev)}
|
||||||
className="mx_RoomDirectory_join"
|
className="mx_RoomDirectory_join"
|
||||||
>
|
>
|
||||||
|
@ -796,7 +796,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
|
||||||
showJoinButton={showJoinButton}
|
showJoinButton={showJoinButton}
|
||||||
initialText={this.props.initialText}
|
initialText={this.props.initialText}
|
||||||
/>
|
/>
|
||||||
{dropdown}
|
{ dropdown }
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
const explanation =
|
const explanation =
|
||||||
|
@ -814,16 +814,16 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
|
||||||
}) : _t("Explore rooms");
|
}) : _t("Explore rooms");
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
className={'mx_RoomDirectory_dialog'}
|
className="mx_RoomDirectory_dialog"
|
||||||
hasCancel={true}
|
hasCancel={true}
|
||||||
onFinished={this.onFinished}
|
onFinished={this.onFinished}
|
||||||
title={title}
|
title={title}
|
||||||
>
|
>
|
||||||
<div className="mx_RoomDirectory">
|
<div className="mx_RoomDirectory">
|
||||||
{explanation}
|
{ explanation }
|
||||||
<div className="mx_RoomDirectory_list">
|
<div className="mx_RoomDirectory_list">
|
||||||
{listHeader}
|
{ listHeader }
|
||||||
{content}
|
{ content }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
|
|
|
@ -209,9 +209,9 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes}>
|
<div className={classes}>
|
||||||
{icon}
|
{ icon }
|
||||||
{input}
|
{ input }
|
||||||
{clearButton}
|
{ clearButton }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,17 +222,17 @@ export default class RoomStatusBar extends React.PureComponent {
|
||||||
|
|
||||||
let buttonRow = <>
|
let buttonRow = <>
|
||||||
<AccessibleButton onClick={this._onCancelAllClick} className="mx_RoomStatusBar_unsentCancelAllBtn">
|
<AccessibleButton onClick={this._onCancelAllClick} className="mx_RoomStatusBar_unsentCancelAllBtn">
|
||||||
{_t("Delete all")}
|
{ _t("Delete all") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
<AccessibleButton onClick={this._onResendAllClick} className="mx_RoomStatusBar_unsentResendAllBtn">
|
<AccessibleButton onClick={this._onResendAllClick} className="mx_RoomStatusBar_unsentResendAllBtn">
|
||||||
{_t("Retry all")}
|
{ _t("Retry all") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</>;
|
</>;
|
||||||
if (this.state.isResending) {
|
if (this.state.isResending) {
|
||||||
buttonRow = <>
|
buttonRow = <>
|
||||||
<InlineSpinner w={20} h={20} />
|
<InlineSpinner w={20} h={20} />
|
||||||
{/* span for css */}
|
{ /* span for css */ }
|
||||||
<span>{_t("Sending")}</span>
|
<span>{ _t("Sending") }</span>
|
||||||
</>;
|
</>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ export default class RoomStatusBar extends React.PureComponent {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_RoomStatusBar_unsentButtonBar">
|
<div className="mx_RoomStatusBar_unsentButtonBar">
|
||||||
{buttonRow}
|
{ buttonRow }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -270,10 +270,10 @@ export default class RoomStatusBar extends React.PureComponent {
|
||||||
height="24" title="/!\ " alt="/!\ " />
|
height="24" title="/!\ " alt="/!\ " />
|
||||||
<div>
|
<div>
|
||||||
<div className="mx_RoomStatusBar_connectionLostBar_title">
|
<div className="mx_RoomStatusBar_connectionLostBar_title">
|
||||||
{_t('Connectivity to the server has been lost.')}
|
{ _t('Connectivity to the server has been lost.') }
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_RoomStatusBar_connectionLostBar_desc">
|
<div className="mx_RoomStatusBar_connectionLostBar_desc">
|
||||||
{_t('Sent messages will be stored until your connection has returned.')}
|
{ _t('Sent messages will be stored until your connection has returned.') }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1892,10 +1892,10 @@ export default class RoomView extends React.Component<IProps, IState> {
|
||||||
className="mx_RoomView_auxPanel_hiddenHighlights"
|
className="mx_RoomView_auxPanel_hiddenHighlights"
|
||||||
onClick={this.onHiddenHighlightsClick}
|
onClick={this.onHiddenHighlightsClick}
|
||||||
>
|
>
|
||||||
{_t(
|
{ _t(
|
||||||
"You have %(count)s unread notifications in a prior version of this room.",
|
"You have %(count)s unread notifications in a prior version of this room.",
|
||||||
{ count: hiddenHighlightCount },
|
{ count: hiddenHighlightCount },
|
||||||
)}
|
) }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2007,7 +2007,7 @@ export default class RoomView extends React.Component<IProps, IState> {
|
||||||
onScroll={this.onMessageListScroll}
|
onScroll={this.onMessageListScroll}
|
||||||
onUserScroll={this.onUserScroll}
|
onUserScroll={this.onUserScroll}
|
||||||
onReadMarkerUpdated={this.updateTopUnreadMessagesBar}
|
onReadMarkerUpdated={this.updateTopUnreadMessagesBar}
|
||||||
showUrlPreview = {this.state.showUrlPreview}
|
showUrlPreview={this.state.showUrlPreview}
|
||||||
className={messagePanelClassNames}
|
className={messagePanelClassNames}
|
||||||
membersLoaded={this.state.membersLoaded}
|
membersLoaded={this.state.membersLoaded}
|
||||||
permalinkCreator={this.getPermalinkCreatorForRoom(this.state.room)}
|
permalinkCreator={this.getPermalinkCreatorForRoom(this.state.room)}
|
||||||
|
@ -2057,7 +2057,7 @@ export default class RoomView extends React.Component<IProps, IState> {
|
||||||
return (
|
return (
|
||||||
<RoomContext.Provider value={this.state}>
|
<RoomContext.Provider value={this.state}>
|
||||||
<main className={mainClasses} ref={this.roomView} onKeyDown={this.onReactKeyDown}>
|
<main className={mainClasses} ref={this.roomView} onKeyDown={this.onReactKeyDown}>
|
||||||
{showChatEffects && this.roomView.current &&
|
{ showChatEffects && this.roomView.current &&
|
||||||
<EffectsOverlay roomWidth={this.roomView.current.offsetWidth} />
|
<EffectsOverlay roomWidth={this.roomView.current.offsetWidth} />
|
||||||
}
|
}
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
|
@ -2076,22 +2076,22 @@ export default class RoomView extends React.Component<IProps, IState> {
|
||||||
/>
|
/>
|
||||||
<MainSplit panel={rightPanel} resizeNotifier={this.props.resizeNotifier}>
|
<MainSplit panel={rightPanel} resizeNotifier={this.props.resizeNotifier}>
|
||||||
<div className="mx_RoomView_body">
|
<div className="mx_RoomView_body">
|
||||||
{auxPanel}
|
{ auxPanel }
|
||||||
<div className={timelineClasses}>
|
<div className={timelineClasses}>
|
||||||
{fileDropTarget}
|
{ fileDropTarget }
|
||||||
{topUnreadMessagesBar}
|
{ topUnreadMessagesBar }
|
||||||
{jumpToBottom}
|
{ jumpToBottom }
|
||||||
{messagePanel}
|
{ messagePanel }
|
||||||
{searchResultsPanel}
|
{ searchResultsPanel }
|
||||||
</div>
|
</div>
|
||||||
<div className={statusBarAreaClass}>
|
<div className={statusBarAreaClass}>
|
||||||
<div className="mx_RoomView_statusAreaBox">
|
<div className="mx_RoomView_statusAreaBox">
|
||||||
<div className="mx_RoomView_statusAreaBox_line" />
|
<div className="mx_RoomView_statusAreaBox_line" />
|
||||||
{statusBar}
|
{ statusBar }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{previewBar}
|
{ previewBar }
|
||||||
{messageComposer}
|
{ messageComposer }
|
||||||
</div>
|
</div>
|
||||||
</MainSplit>
|
</MainSplit>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
|
|
|
@ -136,7 +136,7 @@ export default class SearchBox extends React.Component {
|
||||||
key="button"
|
key="button"
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
className="mx_SearchBox_closeButton"
|
className="mx_SearchBox_closeButton"
|
||||||
onClick={ () => {this._clearSearch("button"); } }>
|
onClick={() => {this._clearSearch("button"); }}>
|
||||||
</AccessibleButton>) : undefined;
|
</AccessibleButton>) : undefined;
|
||||||
|
|
||||||
// show a shorter placeholder when blurred, if requested
|
// show a shorter placeholder when blurred, if requested
|
||||||
|
@ -153,12 +153,12 @@ export default class SearchBox extends React.Component {
|
||||||
type="text"
|
type="text"
|
||||||
ref={this._search}
|
ref={this._search}
|
||||||
className={"mx_textinput_icon mx_textinput_search " + className}
|
className={"mx_textinput_icon mx_textinput_search " + className}
|
||||||
value={ this.state.searchTerm }
|
value={this.state.searchTerm}
|
||||||
onFocus={ this._onFocus }
|
onFocus={this._onFocus}
|
||||||
onChange={ this.onChange }
|
onChange={this.onChange}
|
||||||
onKeyDown={ this._onKeyDown }
|
onKeyDown={this._onKeyDown}
|
||||||
onBlur={this._onBlur}
|
onBlur={this._onBlur}
|
||||||
placeholder={ placeholder }
|
placeholder={placeholder}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoFocus={this.props.autoFocus}
|
autoFocus={this.props.autoFocus}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -404,7 +404,7 @@ export const SpaceHierarchy: React.FC<IHierarchyProps> = ({
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
|
|
||||||
if (summaryError) {
|
if (summaryError) {
|
||||||
return <p>{_t("Your server does not support showing space hierarchies.")}</p>;
|
return <p>{ _t("Your server does not support showing space hierarchies.") }</p>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let content;
|
let content;
|
||||||
|
@ -569,7 +569,7 @@ export const SpaceHierarchy: React.FC<IHierarchyProps> = ({
|
||||||
return <>
|
return <>
|
||||||
<SearchBox
|
<SearchBox
|
||||||
className="mx_textinput_icon mx_textinput_search"
|
className="mx_textinput_icon mx_textinput_search"
|
||||||
placeholder={ _t("Search names and descriptions") }
|
placeholder={_t("Search names and descriptions")}
|
||||||
onSearch={setQuery}
|
onSearch={setQuery}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
initialValue={initialText}
|
initialValue={initialText}
|
||||||
|
@ -608,7 +608,7 @@ const SpaceRoomDirectory: React.FC<IProps> = ({ space, onFinished, initialText }
|
||||||
{ _t("If you can't find the room you're looking for, ask for an invite or <a>create a new room</a>.",
|
{ _t("If you can't find the room you're looking for, ask for an invite or <a>create a new room</a>.",
|
||||||
null,
|
null,
|
||||||
{ a: sub => {
|
{ a: sub => {
|
||||||
return <AccessibleButton kind="link" onClick={onCreateRoomClick}>{sub}</AccessibleButton>;
|
return <AccessibleButton kind="link" onClick={onCreateRoomClick}>{ sub }</AccessibleButton>;
|
||||||
} },
|
} },
|
||||||
) }
|
) }
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,7 @@ const SpaceInfo = ({ space }) => {
|
||||||
return <div className="mx_SpaceRoomView_info">
|
return <div className="mx_SpaceRoomView_info">
|
||||||
{ visibilitySection }
|
{ visibilitySection }
|
||||||
{ joinRule === "public" && <RoomMemberCount room={space}>
|
{ joinRule === "public" && <RoomMemberCount room={space}>
|
||||||
{(count) => count > 0 ? (
|
{ (count) => count > 0 ? (
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
kind="link"
|
kind="link"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -159,7 +159,7 @@ const SpaceInfo = ({ space }) => {
|
||||||
>
|
>
|
||||||
{ _t("%(count)s members", { count }) }
|
{ _t("%(count)s members", { count }) }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
) : null}
|
) : null }
|
||||||
</RoomMemberCount> }
|
</RoomMemberCount> }
|
||||||
</div>;
|
</div>;
|
||||||
};
|
};
|
||||||
|
@ -292,7 +292,7 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }) =>
|
||||||
</h1>
|
</h1>
|
||||||
<SpaceInfo space={space} />
|
<SpaceInfo space={space} />
|
||||||
<RoomTopic room={space}>
|
<RoomTopic room={space}>
|
||||||
{(topic, ref) =>
|
{ (topic, ref) =>
|
||||||
<div className="mx_SpaceRoomView_preview_topic" ref={ref}>
|
<div className="mx_SpaceRoomView_preview_topic" ref={ref}>
|
||||||
{ topic }
|
{ topic }
|
||||||
</div>
|
</div>
|
||||||
|
@ -419,12 +419,12 @@ const SpaceLanding = ({ space }) => {
|
||||||
<RoomAvatar room={space} height={80} width={80} viewAvatarOnClick={true} />
|
<RoomAvatar room={space} height={80} width={80} viewAvatarOnClick={true} />
|
||||||
<div className="mx_SpaceRoomView_landing_name">
|
<div className="mx_SpaceRoomView_landing_name">
|
||||||
<RoomName room={space}>
|
<RoomName room={space}>
|
||||||
{(name) => {
|
{ (name) => {
|
||||||
const tags = { name: () => <div className="mx_SpaceRoomView_landing_nameRow">
|
const tags = { name: () => <div className="mx_SpaceRoomView_landing_nameRow">
|
||||||
<h1>{ name }</h1>
|
<h1>{ name }</h1>
|
||||||
</div> };
|
</div> };
|
||||||
return _t("Welcome to <name/>", {}, tags) as JSX.Element;
|
return _t("Welcome to <name/>", {}, tags) as JSX.Element;
|
||||||
}}
|
} }
|
||||||
</RoomName>
|
</RoomName>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_SpaceRoomView_landing_info">
|
<div className="mx_SpaceRoomView_landing_info">
|
||||||
|
@ -434,11 +434,11 @@ const SpaceLanding = ({ space }) => {
|
||||||
{ settingsButton }
|
{ settingsButton }
|
||||||
</div>
|
</div>
|
||||||
<RoomTopic room={space}>
|
<RoomTopic room={space}>
|
||||||
{(topic, ref) => (
|
{ (topic, ref) => (
|
||||||
<div className="mx_SpaceRoomView_landing_topic" ref={ref}>
|
<div className="mx_SpaceRoomView_landing_topic" ref={ref}>
|
||||||
{ topic }
|
{ topic }
|
||||||
</div>
|
</div>
|
||||||
)}
|
) }
|
||||||
</RoomTopic>
|
</RoomTopic>
|
||||||
<SpaceFeedbackPrompt />
|
<SpaceFeedbackPrompt />
|
||||||
<hr />
|
<hr />
|
||||||
|
@ -458,7 +458,7 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => {
|
||||||
const numFields = 3;
|
const numFields = 3;
|
||||||
const placeholders = [_t("General"), _t("Random"), _t("Support")];
|
const placeholders = [_t("General"), _t("Random"), _t("Support")];
|
||||||
const [roomNames, setRoomName] = useStateArray(numFields, [_t("General"), _t("Random"), ""]);
|
const [roomNames, setRoomName] = useStateArray(numFields, [_t("General"), _t("Random"), ""]);
|
||||||
const fields = new Array(numFields).fill(0).map((_, i) => {
|
const fields = new Array(numFields).fill(0).map((x, i) => {
|
||||||
const name = "roomName" + i;
|
const name = "roomName" + i;
|
||||||
return <Field
|
return <Field
|
||||||
key={name}
|
key={name}
|
||||||
|
@ -625,7 +625,7 @@ const SpaceSetupPrivateInvite = ({ space, onFinished }) => {
|
||||||
const numFields = 3;
|
const numFields = 3;
|
||||||
const fieldRefs: RefObject<Field>[] = [useRef(), useRef(), useRef()];
|
const fieldRefs: RefObject<Field>[] = [useRef(), useRef(), useRef()];
|
||||||
const [emailAddresses, setEmailAddress] = useStateArray(numFields, "");
|
const [emailAddresses, setEmailAddress] = useStateArray(numFields, "");
|
||||||
const fields = new Array(numFields).fill(0).map((_, i) => {
|
const fields = new Array(numFields).fill(0).map((x, i) => {
|
||||||
const name = "emailAddress" + i;
|
const name = "emailAddress" + i;
|
||||||
return <Field
|
return <Field
|
||||||
key={name}
|
key={name}
|
||||||
|
|
|
@ -74,7 +74,7 @@ export default class TabbedView extends React.Component<IProps, IState> {
|
||||||
tabLocation: TabLocation.LEFT,
|
tabLocation: TabLocation.LEFT,
|
||||||
};
|
};
|
||||||
|
|
||||||
private _getActiveTabIndex() {
|
private getActiveTabIndex() {
|
||||||
if (!this.state || !this.state.activeTabIndex) return 0;
|
if (!this.state || !this.state.activeTabIndex) return 0;
|
||||||
return this.state.activeTabIndex;
|
return this.state.activeTabIndex;
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ export default class TabbedView extends React.Component<IProps, IState> {
|
||||||
* @param {Tab} tab the tab to show
|
* @param {Tab} tab the tab to show
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private _setActiveTab(tab: Tab) {
|
private setActiveTab(tab: Tab) {
|
||||||
const idx = this.props.tabs.indexOf(tab);
|
const idx = this.props.tabs.indexOf(tab);
|
||||||
if (idx !== -1) {
|
if (idx !== -1) {
|
||||||
if (this.props.onChange) this.props.onChange(tab.id);
|
if (this.props.onChange) this.props.onChange(tab.id);
|
||||||
|
@ -94,23 +94,23 @@ export default class TabbedView extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _renderTabLabel(tab: Tab) {
|
private renderTabLabel(tab: Tab) {
|
||||||
let classes = "mx_TabbedView_tabLabel ";
|
let classes = "mx_TabbedView_tabLabel ";
|
||||||
|
|
||||||
const idx = this.props.tabs.indexOf(tab);
|
const idx = this.props.tabs.indexOf(tab);
|
||||||
if (idx === this._getActiveTabIndex()) classes += "mx_TabbedView_tabLabel_active";
|
if (idx === this.getActiveTabIndex()) classes += "mx_TabbedView_tabLabel_active";
|
||||||
|
|
||||||
let tabIcon = null;
|
let tabIcon = null;
|
||||||
if (tab.icon) {
|
if (tab.icon) {
|
||||||
tabIcon = <span className={`mx_TabbedView_maskedIcon ${tab.icon}`} />;
|
tabIcon = <span className={`mx_TabbedView_maskedIcon ${tab.icon}`} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const onClickHandler = () => this._setActiveTab(tab);
|
const onClickHandler = () => this.setActiveTab(tab);
|
||||||
|
|
||||||
const label = _t(tab.label);
|
const label = _t(tab.label);
|
||||||
return (
|
return (
|
||||||
<AccessibleButton className={classes} key={"tab_label_" + tab.label} onClick={onClickHandler}>
|
<AccessibleButton className={classes} key={"tab_label_" + tab.label} onClick={onClickHandler}>
|
||||||
{tabIcon}
|
{ tabIcon }
|
||||||
<span className="mx_TabbedView_tabLabel_text">
|
<span className="mx_TabbedView_tabLabel_text">
|
||||||
{ label }
|
{ label }
|
||||||
</span>
|
</span>
|
||||||
|
@ -118,19 +118,19 @@ export default class TabbedView extends React.Component<IProps, IState> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _renderTabPanel(tab: Tab): React.ReactNode {
|
private renderTabPanel(tab: Tab): React.ReactNode {
|
||||||
return (
|
return (
|
||||||
<div className="mx_TabbedView_tabPanel" key={"mx_tabpanel_" + tab.label}>
|
<div className="mx_TabbedView_tabPanel" key={"mx_tabpanel_" + tab.label}>
|
||||||
<AutoHideScrollbar className='mx_TabbedView_tabPanelContent'>
|
<AutoHideScrollbar className='mx_TabbedView_tabPanelContent'>
|
||||||
{tab.body}
|
{ tab.body }
|
||||||
</AutoHideScrollbar>
|
</AutoHideScrollbar>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const labels = this.props.tabs.map(tab => this._renderTabLabel(tab));
|
const labels = this.props.tabs.map(tab => this.renderTabLabel(tab));
|
||||||
const panel = this._renderTabPanel(this.props.tabs[this._getActiveTabIndex()]);
|
const panel = this.renderTabPanel(this.props.tabs[this.getActiveTabIndex()]);
|
||||||
|
|
||||||
const tabbedViewClasses = classNames({
|
const tabbedViewClasses = classNames({
|
||||||
'mx_TabbedView': true,
|
'mx_TabbedView': true,
|
||||||
|
@ -141,9 +141,9 @@ export default class TabbedView extends React.Component<IProps, IState> {
|
||||||
return (
|
return (
|
||||||
<div className={tabbedViewClasses}>
|
<div className={tabbedViewClasses}>
|
||||||
<div className="mx_TabbedView_tabLabels">
|
<div className="mx_TabbedView_tabLabels">
|
||||||
{labels}
|
{ labels }
|
||||||
</div>
|
</div>
|
||||||
{panel}
|
{ panel }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -277,7 +277,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: [REACT-WARNING] Move into constructor
|
// TODO: [REACT-WARNING] Move into constructor
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line
|
||||||
UNSAFE_componentWillMount() {
|
UNSAFE_componentWillMount() {
|
||||||
if (this.props.manageReadReceipts) {
|
if (this.props.manageReadReceipts) {
|
||||||
this.updateReadReceiptOnUserActivity();
|
this.updateReadReceiptOnUserActivity();
|
||||||
|
@ -290,7 +290,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
|
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line
|
||||||
UNSAFE_componentWillReceiveProps(newProps) {
|
UNSAFE_componentWillReceiveProps(newProps) {
|
||||||
if (newProps.timelineSet !== this.props.timelineSet) {
|
if (newProps.timelineSet !== this.props.timelineSet) {
|
||||||
// throw new Error("changing timelineSet on a TimelinePanel is not supported");
|
// throw new Error("changing timelineSet on a TimelinePanel is not supported");
|
||||||
|
@ -1448,7 +1448,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
if (this.state.events.length == 0 && !this.state.canBackPaginate && this.props.empty) {
|
if (this.state.events.length == 0 && !this.state.canBackPaginate && this.props.empty) {
|
||||||
return (
|
return (
|
||||||
<div className={this.props.className + " mx_RoomView_messageListWrapper"}>
|
<div className={this.props.className + " mx_RoomView_messageListWrapper"}>
|
||||||
<div className="mx_RoomView_empty">{this.props.empty}</div>
|
<div className="mx_RoomView_empty">{ this.props.empty }</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,14 +37,14 @@ export default class ToastContainer extends React.Component<{}, IState> {
|
||||||
// toasts may dismiss themselves in their didMount if they find
|
// toasts may dismiss themselves in their didMount if they find
|
||||||
// they're already irrelevant by the time they're mounted, and
|
// they're already irrelevant by the time they're mounted, and
|
||||||
// our own componentDidMount is too late.
|
// our own componentDidMount is too late.
|
||||||
ToastStore.sharedInstance().on('update', this._onToastStoreUpdate);
|
ToastStore.sharedInstance().on('update', this.onToastStoreUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
ToastStore.sharedInstance().removeListener('update', this._onToastStoreUpdate);
|
ToastStore.sharedInstance().removeListener('update', this.onToastStoreUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onToastStoreUpdate = () => {
|
private onToastStoreUpdate = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
toasts: ToastStore.sharedInstance().getToasts(),
|
toasts: ToastStore.sharedInstance().getToasts(),
|
||||||
countSeen: ToastStore.sharedInstance().getCountSeen(),
|
countSeen: ToastStore.sharedInstance().getCountSeen(),
|
||||||
|
@ -75,10 +75,10 @@ export default class ToastContainer extends React.Component<{}, IState> {
|
||||||
});
|
});
|
||||||
toast = (<div className={toastClasses}>
|
toast = (<div className={toastClasses}>
|
||||||
<div className="mx_Toast_title">
|
<div className="mx_Toast_title">
|
||||||
<h2>{title}</h2>
|
<h2>{ title }</h2>
|
||||||
<span>{countIndicator}</span>
|
<span>{ countIndicator }</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Toast_body">{React.createElement(component, toastProps)}</div>
|
<div className="mx_Toast_body">{ React.createElement(component, toastProps) }</div>
|
||||||
</div>);
|
</div>);
|
||||||
|
|
||||||
containerClasses = classNames("mx_ToastContainer", {
|
containerClasses = classNames("mx_ToastContainer", {
|
||||||
|
@ -88,7 +88,7 @@ export default class ToastContainer extends React.Component<{}, IState> {
|
||||||
return toast
|
return toast
|
||||||
? (
|
? (
|
||||||
<div className={containerClasses} role="alert">
|
<div className={containerClasses} role="alert">
|
||||||
{toast}
|
{ toast }
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|
|
@ -104,7 +104,7 @@ export default class UploadBar extends React.Component<IProps, IState> {
|
||||||
const uploadSize = filesize(this.state.currentUpload.total);
|
const uploadSize = filesize(this.state.currentUpload.total);
|
||||||
return (
|
return (
|
||||||
<div className="mx_UploadBar">
|
<div className="mx_UploadBar">
|
||||||
<div className="mx_UploadBar_filename">{uploadText} ({uploadSize})</div>
|
<div className="mx_UploadBar_filename">{ uploadText } ({ uploadSize })</div>
|
||||||
<AccessibleButton onClick={this.onCancelClick} className='mx_UploadBar_cancel' />
|
<AccessibleButton onClick={this.onCancelClick} className='mx_UploadBar_cancel' />
|
||||||
<ProgressBar value={this.state.currentUpload.loaded} max={this.state.currentUpload.total} />
|
<ProgressBar value={this.state.currentUpload.loaded} max={this.state.currentUpload.total} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -342,20 +342,20 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||||
if (MatrixClientPeg.get().isGuest()) {
|
if (MatrixClientPeg.get().isGuest()) {
|
||||||
topSection = (
|
topSection = (
|
||||||
<div className="mx_UserMenu_contextMenu_header mx_UserMenu_contextMenu_guestPrompts">
|
<div className="mx_UserMenu_contextMenu_header mx_UserMenu_contextMenu_guestPrompts">
|
||||||
{_t("Got an account? <a>Sign in</a>", {}, {
|
{ _t("Got an account? <a>Sign in</a>", {}, {
|
||||||
a: sub => (
|
a: sub => (
|
||||||
<AccessibleButton kind="link" onClick={this.onSignInClick}>
|
<AccessibleButton kind="link" onClick={this.onSignInClick}>
|
||||||
{sub}
|
{ sub }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
),
|
),
|
||||||
})}
|
}) }
|
||||||
{_t("New here? <a>Create an account</a>", {}, {
|
{ _t("New here? <a>Create an account</a>", {}, {
|
||||||
a: sub => (
|
a: sub => (
|
||||||
<AccessibleButton kind="link" onClick={this.onRegisterClick}>
|
<AccessibleButton kind="link" onClick={this.onRegisterClick}>
|
||||||
{sub}
|
{ sub }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
),
|
),
|
||||||
})}
|
}) }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (hostSignupConfig) {
|
} else if (hostSignupConfig) {
|
||||||
|
@ -394,17 +394,17 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||||
let primaryHeader = (
|
let primaryHeader = (
|
||||||
<div className="mx_UserMenu_contextMenu_name">
|
<div className="mx_UserMenu_contextMenu_name">
|
||||||
<span className="mx_UserMenu_contextMenu_displayName">
|
<span className="mx_UserMenu_contextMenu_displayName">
|
||||||
{OwnProfileStore.instance.displayName}
|
{ OwnProfileStore.instance.displayName }
|
||||||
</span>
|
</span>
|
||||||
<span className="mx_UserMenu_contextMenu_userId">
|
<span className="mx_UserMenu_contextMenu_userId">
|
||||||
{MatrixClientPeg.get().getUserId()}
|
{ MatrixClientPeg.get().getUserId() }
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
let primaryOptionList = (
|
let primaryOptionList = (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<IconizedContextMenuOptionList>
|
<IconizedContextMenuOptionList>
|
||||||
{homeButton}
|
{ homeButton }
|
||||||
<IconizedContextMenuOption
|
<IconizedContextMenuOption
|
||||||
iconClassName="mx_UserMenu_iconBell"
|
iconClassName="mx_UserMenu_iconBell"
|
||||||
label={_t("Notification settings")}
|
label={_t("Notification settings")}
|
||||||
|
@ -420,11 +420,11 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||||
label={_t("All settings")}
|
label={_t("All settings")}
|
||||||
onClick={(e) => this.onSettingsOpen(e, null)}
|
onClick={(e) => this.onSettingsOpen(e, null)}
|
||||||
/>
|
/>
|
||||||
{/* <IconizedContextMenuOption
|
{ /* <IconizedContextMenuOption
|
||||||
iconClassName="mx_UserMenu_iconArchive"
|
iconClassName="mx_UserMenu_iconArchive"
|
||||||
label={_t("Archived rooms")}
|
label={_t("Archived rooms")}
|
||||||
onClick={this.onShowArchived}
|
onClick={this.onShowArchived}
|
||||||
/> */}
|
/> */ }
|
||||||
{ feedbackButton }
|
{ feedbackButton }
|
||||||
</IconizedContextMenuOptionList>
|
</IconizedContextMenuOptionList>
|
||||||
<IconizedContextMenuOptionList red>
|
<IconizedContextMenuOptionList red>
|
||||||
|
@ -443,7 +443,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||||
primaryHeader = (
|
primaryHeader = (
|
||||||
<div className="mx_UserMenu_contextMenu_name">
|
<div className="mx_UserMenu_contextMenu_name">
|
||||||
<span className="mx_UserMenu_contextMenu_displayName">
|
<span className="mx_UserMenu_contextMenu_displayName">
|
||||||
{prototypeCommunityName}
|
{ prototypeCommunityName }
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -470,13 +470,13 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
primaryOptionList = (
|
primaryOptionList = (
|
||||||
<IconizedContextMenuOptionList>
|
<IconizedContextMenuOptionList>
|
||||||
{settingsOption}
|
{ settingsOption }
|
||||||
<IconizedContextMenuOption
|
<IconizedContextMenuOption
|
||||||
iconClassName="mx_UserMenu_iconMembers"
|
iconClassName="mx_UserMenu_iconMembers"
|
||||||
label={_t("Members")}
|
label={_t("Members")}
|
||||||
onClick={this.onCommunityMembersClick}
|
onClick={this.onCommunityMembersClick}
|
||||||
/>
|
/>
|
||||||
{inviteOption}
|
{ inviteOption }
|
||||||
</IconizedContextMenuOptionList>
|
</IconizedContextMenuOptionList>
|
||||||
);
|
);
|
||||||
secondarySection = (
|
secondarySection = (
|
||||||
|
@ -485,10 +485,10 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||||
<div className="mx_UserMenu_contextMenu_header">
|
<div className="mx_UserMenu_contextMenu_header">
|
||||||
<div className="mx_UserMenu_contextMenu_name">
|
<div className="mx_UserMenu_contextMenu_name">
|
||||||
<span className="mx_UserMenu_contextMenu_displayName">
|
<span className="mx_UserMenu_contextMenu_displayName">
|
||||||
{OwnProfileStore.instance.displayName}
|
{ OwnProfileStore.instance.displayName }
|
||||||
</span>
|
</span>
|
||||||
<span className="mx_UserMenu_contextMenu_userId">
|
<span className="mx_UserMenu_contextMenu_userId">
|
||||||
{MatrixClientPeg.get().getUserId()}
|
{ MatrixClientPeg.get().getUserId() }
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -540,7 +540,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||||
className={classes}
|
className={classes}
|
||||||
>
|
>
|
||||||
<div className="mx_UserMenu_contextMenu_header">
|
<div className="mx_UserMenu_contextMenu_header">
|
||||||
{primaryHeader}
|
{ primaryHeader }
|
||||||
<AccessibleTooltipButton
|
<AccessibleTooltipButton
|
||||||
className="mx_UserMenu_contextMenu_themeButton"
|
className="mx_UserMenu_contextMenu_themeButton"
|
||||||
onClick={this.onSwitchThemeClick}
|
onClick={this.onSwitchThemeClick}
|
||||||
|
@ -553,9 +553,9 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||||
/>
|
/>
|
||||||
</AccessibleTooltipButton>
|
</AccessibleTooltipButton>
|
||||||
</div>
|
</div>
|
||||||
{topSection}
|
{ topSection }
|
||||||
{primaryOptionList}
|
{ primaryOptionList }
|
||||||
{secondarySection}
|
{ secondarySection }
|
||||||
</IconizedContextMenu>;
|
</IconizedContextMenu>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -570,27 +570,27 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
let isPrototype = false;
|
let isPrototype = false;
|
||||||
let menuName = _t("User menu");
|
let menuName = _t("User menu");
|
||||||
let name = <span className="mx_UserMenu_userName">{displayName}</span>;
|
let name = <span className="mx_UserMenu_userName">{ displayName }</span>;
|
||||||
let buttons = (
|
let buttons = (
|
||||||
<span className="mx_UserMenu_headerButtons">
|
<span className="mx_UserMenu_headerButtons">
|
||||||
{/* masked image in CSS */}
|
{ /* masked image in CSS */ }
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
let dnd;
|
let dnd;
|
||||||
if (this.state.selectedSpace) {
|
if (this.state.selectedSpace) {
|
||||||
name = (
|
name = (
|
||||||
<div className="mx_UserMenu_doubleName">
|
<div className="mx_UserMenu_doubleName">
|
||||||
<span className="mx_UserMenu_userName">{displayName}</span>
|
<span className="mx_UserMenu_userName">{ displayName }</span>
|
||||||
<RoomName room={this.state.selectedSpace}>
|
<RoomName room={this.state.selectedSpace}>
|
||||||
{(roomName) => <span className="mx_UserMenu_subUserName">{roomName}</span>}
|
{ (roomName) => <span className="mx_UserMenu_subUserName">{ roomName }</span> }
|
||||||
</RoomName>
|
</RoomName>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (prototypeCommunityName) {
|
} else if (prototypeCommunityName) {
|
||||||
name = (
|
name = (
|
||||||
<div className="mx_UserMenu_doubleName">
|
<div className="mx_UserMenu_doubleName">
|
||||||
<span className="mx_UserMenu_userName">{prototypeCommunityName}</span>
|
<span className="mx_UserMenu_userName">{ prototypeCommunityName }</span>
|
||||||
<span className="mx_UserMenu_subUserName">{displayName}</span>
|
<span className="mx_UserMenu_subUserName">{ displayName }</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
menuName = _t("Community and user menu");
|
menuName = _t("Community and user menu");
|
||||||
|
@ -598,8 +598,8 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||||
} else if (SettingsStore.getValue("feature_communities_v2_prototypes")) {
|
} else if (SettingsStore.getValue("feature_communities_v2_prototypes")) {
|
||||||
name = (
|
name = (
|
||||||
<div className="mx_UserMenu_doubleName">
|
<div className="mx_UserMenu_doubleName">
|
||||||
<span className="mx_UserMenu_userName">{_t("Home")}</span>
|
<span className="mx_UserMenu_userName">{ _t("Home") }</span>
|
||||||
<span className="mx_UserMenu_subUserName">{displayName}</span>
|
<span className="mx_UserMenu_subUserName">{ displayName }</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
isPrototype = true;
|
isPrototype = true;
|
||||||
|
@ -647,20 +647,20 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||||
className="mx_UserMenu_userAvatar"
|
className="mx_UserMenu_userAvatar"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
{name}
|
{ name }
|
||||||
{this.state.pendingRoomJoin.size > 0 && (
|
{ this.state.pendingRoomJoin.size > 0 && (
|
||||||
<InlineSpinner>
|
<InlineSpinner>
|
||||||
<TooltipButton helpText={_t(
|
<TooltipButton helpText={_t(
|
||||||
"Currently joining %(count)s rooms",
|
"Currently joining %(count)s rooms",
|
||||||
{ count: this.state.pendingRoomJoin.size },
|
{ count: this.state.pendingRoomJoin.size },
|
||||||
)} />
|
)} />
|
||||||
</InlineSpinner>
|
</InlineSpinner>
|
||||||
)}
|
) }
|
||||||
{dnd}
|
{ dnd }
|
||||||
{buttons}
|
{ buttons }
|
||||||
</div>
|
</div>
|
||||||
</ContextMenuButton>
|
</ContextMenuButton>
|
||||||
{this.renderContextMenu()}
|
{ this.renderContextMenu() }
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,23 +63,23 @@ export default class ViewSource extends React.Component {
|
||||||
<>
|
<>
|
||||||
<details open className="mx_ViewSource_details">
|
<details open className="mx_ViewSource_details">
|
||||||
<summary>
|
<summary>
|
||||||
<span className="mx_ViewSource_heading">{_t("Decrypted event source")}</span>
|
<span className="mx_ViewSource_heading">{ _t("Decrypted event source") }</span>
|
||||||
</summary>
|
</summary>
|
||||||
<SyntaxHighlight className="json">{JSON.stringify(decryptedEventSource, null, 2)}</SyntaxHighlight>
|
<SyntaxHighlight className="json">{ JSON.stringify(decryptedEventSource, null, 2) }</SyntaxHighlight>
|
||||||
</details>
|
</details>
|
||||||
<details className="mx_ViewSource_details">
|
<details className="mx_ViewSource_details">
|
||||||
<summary>
|
<summary>
|
||||||
<span className="mx_ViewSource_heading">{_t("Original event source")}</span>
|
<span className="mx_ViewSource_heading">{ _t("Original event source") }</span>
|
||||||
</summary>
|
</summary>
|
||||||
<SyntaxHighlight className="json">{JSON.stringify(originalEventSource, null, 2)}</SyntaxHighlight>
|
<SyntaxHighlight className="json">{ JSON.stringify(originalEventSource, null, 2) }</SyntaxHighlight>
|
||||||
</details>
|
</details>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="mx_ViewSource_heading">{_t("Original event source")}</div>
|
<div className="mx_ViewSource_heading">{ _t("Original event source") }</div>
|
||||||
<SyntaxHighlight className="json">{JSON.stringify(originalEventSource, null, 2)}</SyntaxHighlight>
|
<SyntaxHighlight className="json">{ JSON.stringify(originalEventSource, null, 2) }</SyntaxHighlight>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ export default class ViewSource extends React.Component {
|
||||||
if (isStateEvent) {
|
if (isStateEvent) {
|
||||||
return (
|
return (
|
||||||
<MatrixClientContext.Consumer>
|
<MatrixClientContext.Consumer>
|
||||||
{(cli) => (
|
{ (cli) => (
|
||||||
<SendCustomEvent
|
<SendCustomEvent
|
||||||
room={cli.getRoom(roomId)}
|
room={cli.getRoom(roomId)}
|
||||||
forceStateEvent={true}
|
forceStateEvent={true}
|
||||||
|
@ -121,7 +121,7 @@ export default class ViewSource extends React.Component {
|
||||||
stateKey: mxEvent.getStateKey(),
|
stateKey: mxEvent.getStateKey(),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
) }
|
||||||
</MatrixClientContext.Consumer>
|
</MatrixClientContext.Consumer>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -142,7 +142,7 @@ export default class ViewSource extends React.Component {
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<MatrixClientContext.Consumer>
|
<MatrixClientContext.Consumer>
|
||||||
{(cli) => (
|
{ (cli) => (
|
||||||
<SendCustomEvent
|
<SendCustomEvent
|
||||||
room={cli.getRoom(roomId)}
|
room={cli.getRoom(roomId)}
|
||||||
forceStateEvent={false}
|
forceStateEvent={false}
|
||||||
|
@ -153,7 +153,7 @@ export default class ViewSource extends React.Component {
|
||||||
evContent: JSON.stringify(newContent, null, "\t"),
|
evContent: JSON.stringify(newContent, null, "\t"),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
) }
|
||||||
</MatrixClientContext.Consumer>
|
</MatrixClientContext.Consumer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -176,16 +176,16 @@ export default class ViewSource extends React.Component {
|
||||||
return (
|
return (
|
||||||
<BaseDialog className="mx_ViewSource" onFinished={this.props.onFinished} title={_t("View Source")}>
|
<BaseDialog className="mx_ViewSource" onFinished={this.props.onFinished} title={_t("View Source")}>
|
||||||
<div>
|
<div>
|
||||||
<div>Room ID: {roomId}</div>
|
<div>Room ID: { roomId }</div>
|
||||||
<div>Event ID: {eventId}</div>
|
<div>Event ID: { eventId }</div>
|
||||||
<div className="mx_ViewSource_separator" />
|
<div className="mx_ViewSource_separator" />
|
||||||
{isEditing ? this.editSourceContent() : this.viewSourceContent()}
|
{ isEditing ? this.editSourceContent() : this.viewSourceContent() }
|
||||||
</div>
|
</div>
|
||||||
{!isEditing && canEdit && (
|
{ !isEditing && canEdit && (
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
<button onClick={() => this.onEdit()}>{_t("Edit")}</button>
|
<button onClick={() => this.onEdit()}>{ _t("Edit") }</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
) }
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,8 +79,8 @@ export default class CompleteSecurity extends React.Component<IProps, IState> {
|
||||||
<AuthPage>
|
<AuthPage>
|
||||||
<CompleteSecurityBody>
|
<CompleteSecurityBody>
|
||||||
<h2 className="mx_CompleteSecurity_header">
|
<h2 className="mx_CompleteSecurity_header">
|
||||||
{icon}
|
{ icon }
|
||||||
{title}
|
{ title }
|
||||||
</h2>
|
</h2>
|
||||||
<div className="mx_CompleteSecurity_body">
|
<div className="mx_CompleteSecurity_body">
|
||||||
<SetupEncryptionBody onFinished={this.props.onFinished} />
|
<SetupEncryptionBody onFinished={this.props.onFinished} />
|
||||||
|
|
|
@ -101,7 +101,7 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
|
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line
|
||||||
public UNSAFE_componentWillReceiveProps(newProps: IProps): void {
|
public UNSAFE_componentWillReceiveProps(newProps: IProps): void {
|
||||||
if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl &&
|
if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl &&
|
||||||
newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return;
|
newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return;
|
||||||
|
@ -239,14 +239,14 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
|
||||||
});
|
});
|
||||||
serverDeadSection = (
|
serverDeadSection = (
|
||||||
<div className={classes}>
|
<div className={classes}>
|
||||||
{this.state.serverDeadError}
|
{ this.state.serverDeadError }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div>
|
return <div>
|
||||||
{errorText}
|
{ errorText }
|
||||||
{serverDeadSection}
|
{ serverDeadSection }
|
||||||
<ServerPicker
|
<ServerPicker
|
||||||
serverConfig={this.props.serverConfig}
|
serverConfig={this.props.serverConfig}
|
||||||
onServerConfigChange={this.props.onServerConfigChange}
|
onServerConfigChange={this.props.onServerConfigChange}
|
||||||
|
@ -289,10 +289,10 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span>{_t(
|
<span>{ _t(
|
||||||
'A verification email will be sent to your inbox to confirm ' +
|
'A verification email will be sent to your inbox to confirm ' +
|
||||||
'setting your new password.',
|
'setting your new password.',
|
||||||
)}</span>
|
) }</span>
|
||||||
<input
|
<input
|
||||||
className="mx_Login_submit"
|
className="mx_Login_submit"
|
||||||
type="submit"
|
type="submit"
|
||||||
|
@ -300,7 +300,7 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
<a className="mx_AuthBody_changeFlow" onClick={this.onLoginClick} href="#">
|
<a className="mx_AuthBody_changeFlow" onClick={this.onLoginClick} href="#">
|
||||||
{_t('Sign in instead')}
|
{ _t('Sign in instead') }
|
||||||
</a>
|
</a>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
@ -312,8 +312,8 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
renderEmailSent() {
|
renderEmailSent() {
|
||||||
return <div>
|
return <div>
|
||||||
{_t("An email has been sent to %(emailAddress)s. Once you've followed the " +
|
{ _t("An email has been sent to %(emailAddress)s. Once you've followed the " +
|
||||||
"link it contains, click below.", { emailAddress: this.state.email })}
|
"link it contains, click below.", { emailAddress: this.state.email }) }
|
||||||
<br />
|
<br />
|
||||||
<input className="mx_Login_submit" type="button" onClick={this.onVerify}
|
<input className="mx_Login_submit" type="button" onClick={this.onVerify}
|
||||||
value={_t('I have verified my email address')} />
|
value={_t('I have verified my email address')} />
|
||||||
|
@ -322,12 +322,12 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
renderDone() {
|
renderDone() {
|
||||||
return <div>
|
return <div>
|
||||||
<p>{_t("Your password has been reset.")}</p>
|
<p>{ _t("Your password has been reset.") }</p>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"You have been logged out of all sessions and will no longer receive " +
|
"You have been logged out of all sessions and will no longer receive " +
|
||||||
"push notifications. To re-enable notifications, sign in again on each " +
|
"push notifications. To re-enable notifications, sign in again on each " +
|
||||||
"device.",
|
"device.",
|
||||||
)}</p>
|
) }</p>
|
||||||
<input className="mx_Login_submit" type="button" onClick={this.props.onComplete}
|
<input className="mx_Login_submit" type="button" onClick={this.props.onComplete}
|
||||||
value={_t('Return to login screen')} />
|
value={_t('Return to login screen')} />
|
||||||
</div>;
|
</div>;
|
||||||
|
@ -358,7 +358,7 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
|
||||||
<AuthHeader />
|
<AuthHeader />
|
||||||
<AuthBody>
|
<AuthBody>
|
||||||
<h2> { _t('Set a new password') } </h2>
|
<h2> { _t('Set a new password') } </h2>
|
||||||
{resetPasswordJsx}
|
{ resetPasswordJsx }
|
||||||
</AuthBody>
|
</AuthBody>
|
||||||
</AuthPage>
|
</AuthPage>
|
||||||
);
|
);
|
||||||
|
|
|
@ -144,7 +144,7 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
|
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line
|
||||||
UNSAFE_componentWillMount() {
|
UNSAFE_componentWillMount() {
|
||||||
this.initLoginLogic(this.props.serverConfig);
|
this.initLoginLogic(this.props.serverConfig);
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
|
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line
|
||||||
UNSAFE_componentWillReceiveProps(newProps) {
|
UNSAFE_componentWillReceiveProps(newProps) {
|
||||||
if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl &&
|
if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl &&
|
||||||
newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return;
|
newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return;
|
||||||
|
@ -239,8 +239,8 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
||||||
);
|
);
|
||||||
errorText = (
|
errorText = (
|
||||||
<div>
|
<div>
|
||||||
<div>{errorTop}</div>
|
<div>{ errorTop }</div>
|
||||||
<div className="mx_Login_smallError">{errorDetail}</div>
|
<div className="mx_Login_smallError">{ errorDetail }</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (error.httpStatus === 401 || error.httpStatus === 403) {
|
} else if (error.httpStatus === 401 || error.httpStatus === 403) {
|
||||||
|
@ -251,10 +251,10 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
||||||
<div>
|
<div>
|
||||||
<div>{ _t('Incorrect username and/or password.') }</div>
|
<div>{ _t('Incorrect username and/or password.') }</div>
|
||||||
<div className="mx_Login_smallError">
|
<div className="mx_Login_smallError">
|
||||||
{_t(
|
{ _t(
|
||||||
'Please note you are logging into the %(hs)s server, not matrix.org.',
|
'Please note you are logging into the %(hs)s server, not matrix.org.',
|
||||||
{ hs: this.props.serverConfig.hsName },
|
{ hs: this.props.serverConfig.hsName },
|
||||||
)}
|
) }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -565,7 +565,7 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
||||||
});
|
});
|
||||||
serverDeadSection = (
|
serverDeadSection = (
|
||||||
<div className={classes}>
|
<div className={classes}>
|
||||||
{this.state.serverDeadError}
|
{ this.state.serverDeadError }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -578,15 +578,15 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
||||||
{ this.props.isSyncing ? _t("Syncing...") : _t("Signing In...") }
|
{ this.props.isSyncing ? _t("Syncing...") : _t("Signing In...") }
|
||||||
</div>
|
</div>
|
||||||
{ this.props.isSyncing && <div className="mx_AuthBody_paddedFooter_subtitle">
|
{ this.props.isSyncing && <div className="mx_AuthBody_paddedFooter_subtitle">
|
||||||
{_t("If you've joined lots of rooms, this might take a while")}
|
{ _t("If you've joined lots of rooms, this might take a while") }
|
||||||
</div> }
|
</div> }
|
||||||
</div>;
|
</div>;
|
||||||
} else if (SettingsStore.getValue(UIFeature.Registration)) {
|
} else if (SettingsStore.getValue(UIFeature.Registration)) {
|
||||||
footer = (
|
footer = (
|
||||||
<span className="mx_AuthBody_changeFlow">
|
<span className="mx_AuthBody_changeFlow">
|
||||||
{_t("New? <a>Create account</a>", {}, {
|
{ _t("New? <a>Create account</a>", {}, {
|
||||||
a: sub => <a onClick={this.onTryRegisterClick} href="#">{ sub }</a>,
|
a: sub => <a onClick={this.onTryRegisterClick} href="#">{ sub }</a>,
|
||||||
})}
|
}) }
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -596,8 +596,8 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
||||||
<AuthHeader disableLanguageSelector={this.props.isSyncing || this.state.busyLoggingIn} />
|
<AuthHeader disableLanguageSelector={this.props.isSyncing || this.state.busyLoggingIn} />
|
||||||
<AuthBody>
|
<AuthBody>
|
||||||
<h2>
|
<h2>
|
||||||
{_t('Sign in')}
|
{ _t('Sign in') }
|
||||||
{loader}
|
{ loader }
|
||||||
</h2>
|
</h2>
|
||||||
{ errorTextSection }
|
{ errorTextSection }
|
||||||
{ serverDeadSection }
|
{ serverDeadSection }
|
||||||
|
|
|
@ -141,7 +141,7 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
|
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line
|
||||||
UNSAFE_componentWillReceiveProps(newProps) {
|
UNSAFE_componentWillReceiveProps(newProps) {
|
||||||
if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl &&
|
if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl &&
|
||||||
newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return;
|
newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return;
|
||||||
|
@ -290,8 +290,8 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
msg = <div>
|
msg = <div>
|
||||||
<p>{errorTop}</p>
|
<p>{ errorTop }</p>
|
||||||
<p>{errorDetail}</p>
|
<p>{ errorDetail }</p>
|
||||||
</div>;
|
</div>;
|
||||||
} else if (response.required_stages && response.required_stages.indexOf('m.login.msisdn') > -1) {
|
} else if (response.required_stages && response.required_stages.indexOf('m.login.msisdn') > -1) {
|
||||||
let msisdnAvailable = false;
|
let msisdnAvailable = false;
|
||||||
|
@ -482,13 +482,13 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
fragmentAfterLogin={this.props.fragmentAfterLogin}
|
fragmentAfterLogin={this.props.fragmentAfterLogin}
|
||||||
/>
|
/>
|
||||||
<h3 className="mx_AuthBody_centered">
|
<h3 className="mx_AuthBody_centered">
|
||||||
{_t(
|
{ _t(
|
||||||
"%(ssoButtons)s Or %(usernamePassword)s",
|
"%(ssoButtons)s Or %(usernamePassword)s",
|
||||||
{
|
{
|
||||||
ssoButtons: "",
|
ssoButtons: "",
|
||||||
usernamePassword: "",
|
usernamePassword: "",
|
||||||
},
|
},
|
||||||
).trim()}
|
).trim() }
|
||||||
</h3>
|
</h3>
|
||||||
</React.Fragment>;
|
</React.Fragment>;
|
||||||
}
|
}
|
||||||
|
@ -526,15 +526,15 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
});
|
});
|
||||||
serverDeadSection = (
|
serverDeadSection = (
|
||||||
<div className={classes}>
|
<div className={classes}>
|
||||||
{this.state.serverDeadError}
|
{ this.state.serverDeadError }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const signIn = <span className="mx_AuthBody_changeFlow">
|
const signIn = <span className="mx_AuthBody_changeFlow">
|
||||||
{_t("Already have an account? <a>Sign in here</a>", {}, {
|
{ _t("Already have an account? <a>Sign in here</a>", {}, {
|
||||||
a: sub => <a onClick={this.onLoginClick} href="#">{ sub }</a>,
|
a: sub => <a onClick={this.onLoginClick} href="#">{ sub }</a>,
|
||||||
})}
|
}) }
|
||||||
</span>;
|
</span>;
|
||||||
|
|
||||||
// Only show the 'go back' button if you're not looking at the form
|
// Only show the 'go back' button if you're not looking at the form
|
||||||
|
@ -550,43 +550,43 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
let regDoneText;
|
let regDoneText;
|
||||||
if (this.state.differentLoggedInUserId) {
|
if (this.state.differentLoggedInUserId) {
|
||||||
regDoneText = <div>
|
regDoneText = <div>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"Your new account (%(newAccountId)s) is registered, but you're already " +
|
"Your new account (%(newAccountId)s) is registered, but you're already " +
|
||||||
"logged into a different account (%(loggedInUserId)s).", {
|
"logged into a different account (%(loggedInUserId)s).", {
|
||||||
newAccountId: this.state.registeredUsername,
|
newAccountId: this.state.registeredUsername,
|
||||||
loggedInUserId: this.state.differentLoggedInUserId,
|
loggedInUserId: this.state.differentLoggedInUserId,
|
||||||
},
|
},
|
||||||
)}</p>
|
) }</p>
|
||||||
<p><AccessibleButton element="span" className="mx_linkButton" onClick={async event => {
|
<p><AccessibleButton element="span" className="mx_linkButton" onClick={async event => {
|
||||||
const sessionLoaded = await this.onLoginClickWithCheck(event);
|
const sessionLoaded = await this.onLoginClickWithCheck(event);
|
||||||
if (sessionLoaded) {
|
if (sessionLoaded) {
|
||||||
dis.dispatch({ action: "view_welcome_page" });
|
dis.dispatch({ action: "view_welcome_page" });
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
{_t("Continue with previous account")}
|
{ _t("Continue with previous account") }
|
||||||
</AccessibleButton></p>
|
</AccessibleButton></p>
|
||||||
</div>;
|
</div>;
|
||||||
} else if (this.state.formVals.password) {
|
} else if (this.state.formVals.password) {
|
||||||
// We're the client that started the registration
|
// We're the client that started the registration
|
||||||
regDoneText = <h3>{_t(
|
regDoneText = <h3>{ _t(
|
||||||
"<a>Log in</a> to your new account.", {},
|
"<a>Log in</a> to your new account.", {},
|
||||||
{
|
{
|
||||||
a: (sub) => <a href="#/login" onClick={this.onLoginClickWithCheck}>{sub}</a>,
|
a: (sub) => <a href="#/login" onClick={this.onLoginClickWithCheck}>{ sub }</a>,
|
||||||
},
|
},
|
||||||
)}</h3>;
|
) }</h3>;
|
||||||
} else {
|
} else {
|
||||||
// We're not the original client: the user probably got to us by clicking the
|
// We're not the original client: the user probably got to us by clicking the
|
||||||
// email validation link. We can't offer a 'go straight to your account' link
|
// email validation link. We can't offer a 'go straight to your account' link
|
||||||
// as we don't have the original creds.
|
// as we don't have the original creds.
|
||||||
regDoneText = <h3>{_t(
|
regDoneText = <h3>{ _t(
|
||||||
"You can now close this window or <a>log in</a> to your new account.", {},
|
"You can now close this window or <a>log in</a> to your new account.", {},
|
||||||
{
|
{
|
||||||
a: (sub) => <a href="#/login" onClick={this.onLoginClickWithCheck}>{sub}</a>,
|
a: (sub) => <a href="#/login" onClick={this.onLoginClickWithCheck}>{ sub }</a>,
|
||||||
},
|
},
|
||||||
)}</h3>;
|
) }</h3>;
|
||||||
}
|
}
|
||||||
body = <div>
|
body = <div>
|
||||||
<h2>{_t("Registration Successful")}</h2>
|
<h2>{ _t("Registration Successful") }</h2>
|
||||||
{ regDoneText }
|
{ regDoneText }
|
||||||
</div>;
|
</div>;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -152,7 +152,7 @@ export default class SetupEncryptionBody extends React.Component<IProps, IState>
|
||||||
let useRecoveryKeyButton;
|
let useRecoveryKeyButton;
|
||||||
if (recoveryKeyPrompt) {
|
if (recoveryKeyPrompt) {
|
||||||
useRecoveryKeyButton = <AccessibleButton kind="link" onClick={this.onUsePassphraseClick}>
|
useRecoveryKeyButton = <AccessibleButton kind="link" onClick={this.onUsePassphraseClick}>
|
||||||
{recoveryKeyPrompt}
|
{ recoveryKeyPrompt }
|
||||||
</AccessibleButton>;
|
</AccessibleButton>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,15 +165,15 @@ export default class SetupEncryptionBody extends React.Component<IProps, IState>
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"Verify your identity to access encrypted messages and prove your identity to others.",
|
"Verify your identity to access encrypted messages and prove your identity to others.",
|
||||||
)}</p>
|
) }</p>
|
||||||
|
|
||||||
<div className="mx_CompleteSecurity_actionRow">
|
<div className="mx_CompleteSecurity_actionRow">
|
||||||
{verifyButton}
|
{ verifyButton }
|
||||||
{useRecoveryKeyButton}
|
{ useRecoveryKeyButton }
|
||||||
<AccessibleButton kind="danger" onClick={this.onSkipClick}>
|
<AccessibleButton kind="danger" onClick={this.onSkipClick}>
|
||||||
{_t("Skip")}
|
{ _t("Skip") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -181,25 +181,25 @@ export default class SetupEncryptionBody extends React.Component<IProps, IState>
|
||||||
} else if (phase === Phase.Done) {
|
} else if (phase === Phase.Done) {
|
||||||
let message;
|
let message;
|
||||||
if (this.state.backupInfo) {
|
if (this.state.backupInfo) {
|
||||||
message = <p>{_t(
|
message = <p>{ _t(
|
||||||
"Your new session is now verified. It has access to your " +
|
"Your new session is now verified. It has access to your " +
|
||||||
"encrypted messages, and other users will see it as trusted.",
|
"encrypted messages, and other users will see it as trusted.",
|
||||||
)}</p>;
|
) }</p>;
|
||||||
} else {
|
} else {
|
||||||
message = <p>{_t(
|
message = <p>{ _t(
|
||||||
"Your new session is now verified. Other users will see it as trusted.",
|
"Your new session is now verified. Other users will see it as trusted.",
|
||||||
)}</p>;
|
) }</p>;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="mx_CompleteSecurity_heroIcon mx_E2EIcon_verified" />
|
<div className="mx_CompleteSecurity_heroIcon mx_E2EIcon_verified" />
|
||||||
{message}
|
{ message }
|
||||||
<div className="mx_CompleteSecurity_actionRow">
|
<div className="mx_CompleteSecurity_actionRow">
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
kind="primary"
|
kind="primary"
|
||||||
onClick={this.onDoneClick}
|
onClick={this.onDoneClick}
|
||||||
>
|
>
|
||||||
{_t("Done")}
|
{ _t("Done") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -207,23 +207,23 @@ export default class SetupEncryptionBody extends React.Component<IProps, IState>
|
||||||
} else if (phase === Phase.ConfirmSkip) {
|
} else if (phase === Phase.ConfirmSkip) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"Without verifying, you won’t have access to all your messages " +
|
"Without verifying, you won’t have access to all your messages " +
|
||||||
"and may appear as untrusted to others.",
|
"and may appear as untrusted to others.",
|
||||||
)}</p>
|
) }</p>
|
||||||
<div className="mx_CompleteSecurity_actionRow">
|
<div className="mx_CompleteSecurity_actionRow">
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
className="warning"
|
className="warning"
|
||||||
kind="secondary"
|
kind="secondary"
|
||||||
onClick={this.onSkipConfirmClick}
|
onClick={this.onSkipConfirmClick}
|
||||||
>
|
>
|
||||||
{_t("Skip")}
|
{ _t("Skip") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
kind="danger"
|
kind="danger"
|
||||||
onClick={this.onSkipBackClick}
|
onClick={this.onSkipBackClick}
|
||||||
>
|
>
|
||||||
{_t("Go Back")}
|
{ _t("Go Back") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -219,7 +219,7 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
||||||
if (this.state.loginView === LOGIN_VIEW.PASSWORD) {
|
if (this.state.loginView === LOGIN_VIEW.PASSWORD) {
|
||||||
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>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!introText) {
|
if (!introText) {
|
||||||
|
@ -228,8 +228,8 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={this.onPasswordLogin}>
|
<form onSubmit={this.onPasswordLogin}>
|
||||||
<p>{introText}</p>
|
<p>{ introText }</p>
|
||||||
{error}
|
{ error }
|
||||||
<Field
|
<Field
|
||||||
type="password"
|
type="password"
|
||||||
label={_t("Password")}
|
label={_t("Password")}
|
||||||
|
@ -243,10 +243,10 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={this.state.busy}
|
disabled={this.state.busy}
|
||||||
>
|
>
|
||||||
{_t("Sign In")}
|
{ _t("Sign In") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
<AccessibleButton onClick={this.onForgotPassword} kind="link">
|
<AccessibleButton onClick={this.onForgotPassword} kind="link">
|
||||||
{_t("Forgotten your password?")}
|
{ _t("Forgotten your password?") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
|
@ -262,7 +262,7 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>{introText}</p>
|
<p>{ introText }</p>
|
||||||
<SSOButtons
|
<SSOButtons
|
||||||
matrixClient={MatrixClientPeg.get()}
|
matrixClient={MatrixClientPeg.get()}
|
||||||
flow={flow}
|
flow={flow}
|
||||||
|
@ -277,10 +277,10 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
||||||
// Default: assume unsupported/error
|
// Default: assume unsupported/error
|
||||||
return (
|
return (
|
||||||
<p>
|
<p>
|
||||||
{_t(
|
{ _t(
|
||||||
"You cannot sign in to your account. Please contact your " +
|
"You cannot sign in to your account. Please contact your " +
|
||||||
"homeserver admin for more information.",
|
"homeserver admin for more information.",
|
||||||
)}
|
) }
|
||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -291,25 +291,25 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
||||||
<AuthHeader />
|
<AuthHeader />
|
||||||
<AuthBody>
|
<AuthBody>
|
||||||
<h2>
|
<h2>
|
||||||
{_t("You're signed out")}
|
{ _t("You're signed out") }
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<h3>{_t("Sign in")}</h3>
|
<h3>{ _t("Sign in") }</h3>
|
||||||
<div>
|
<div>
|
||||||
{this.renderSignInSection()}
|
{ this.renderSignInSection() }
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3>{_t("Clear personal data")}</h3>
|
<h3>{ _t("Clear personal data") }</h3>
|
||||||
<p>
|
<p>
|
||||||
{_t(
|
{ _t(
|
||||||
"Warning: Your personal data (including encryption keys) is still stored " +
|
"Warning: Your personal data (including encryption keys) is still stored " +
|
||||||
"in this session. Clear it if you're finished using this session, or want to sign " +
|
"in this session. Clear it if you're finished using this session, or want to sign " +
|
||||||
"in to another account.",
|
"in to another account.",
|
||||||
)}
|
) }
|
||||||
</p>
|
</p>
|
||||||
<div>
|
<div>
|
||||||
<AccessibleButton onClick={this.onClearAll} kind="danger">
|
<AccessibleButton onClick={this.onClearAll} kind="danger">
|
||||||
{_t("Clear all data")}
|
{ _t("Clear all data") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
</AuthBody>
|
</AuthBody>
|
||||||
|
|
|
@ -101,11 +101,11 @@ export default class AudioPlayer extends React.PureComponent<IProps, IState> {
|
||||||
/>
|
/>
|
||||||
<div className='mx_AudioPlayer_mediaInfo'>
|
<div className='mx_AudioPlayer_mediaInfo'>
|
||||||
<span className='mx_AudioPlayer_mediaName'>
|
<span className='mx_AudioPlayer_mediaName'>
|
||||||
{this.props.mediaName || _t("Unnamed audio")}
|
{ this.props.mediaName || _t("Unnamed audio") }
|
||||||
</span>
|
</span>
|
||||||
<div className='mx_AudioPlayer_byline'>
|
<div className='mx_AudioPlayer_byline'>
|
||||||
<DurationClock playback={this.props.playback} />
|
<DurationClock playback={this.props.playback} />
|
||||||
{/* easiest way to introduce a gap between the components */}
|
{ /* easiest way to introduce a gap between the components */ }
|
||||||
{ this.renderFileSize() }
|
{ this.renderFileSize() }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -43,6 +43,6 @@ export default class Clock extends React.Component<IProps, IState> {
|
||||||
public render() {
|
public render() {
|
||||||
const minutes = Math.floor(this.props.seconds / 60).toFixed(0).padStart(2, '0');
|
const minutes = Math.floor(this.props.seconds / 60).toFixed(0).padStart(2, '0');
|
||||||
const seconds = Math.floor(this.props.seconds % 60).toFixed(0).padStart(2, '0'); // hide millis
|
const seconds = Math.floor(this.props.seconds % 60).toFixed(0).padStart(2, '0'); // hide millis
|
||||||
return <span className='mx_Clock'>{minutes}:{seconds}</span>;
|
return <span className='mx_Clock'>{ minutes }:{ seconds }</span>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ export default class Waveform extends React.PureComponent<IProps, IState> {
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return <div className='mx_Waveform'>
|
return <div className='mx_Waveform'>
|
||||||
{this.props.relHeights.map((h, i) => {
|
{ this.props.relHeights.map((h, i) => {
|
||||||
const progress = this.props.progress;
|
const progress = this.props.progress;
|
||||||
const isCompleteBar = (i / this.props.relHeights.length) <= progress && progress > 0;
|
const isCompleteBar = (i / this.props.relHeights.length) <= progress && progress > 0;
|
||||||
const classes = classNames({
|
const classes = classNames({
|
||||||
|
@ -57,7 +57,7 @@ export default class Waveform extends React.PureComponent<IProps, IState> {
|
||||||
return <span key={i} style={{
|
return <span key={i} style={{
|
||||||
"--barHeight": h,
|
"--barHeight": h,
|
||||||
} as WaveformCSSProperties} className={classes} />;
|
} as WaveformCSSProperties} className={classes} />;
|
||||||
})}
|
}) }
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ export default class AuthPage extends React.PureComponent {
|
||||||
return (
|
return (
|
||||||
<div className="mx_AuthPage">
|
<div className="mx_AuthPage">
|
||||||
<div className="mx_AuthPage_modal">
|
<div className="mx_AuthPage_modal">
|
||||||
{this.props.children}
|
{ this.props.children }
|
||||||
</div>
|
</div>
|
||||||
<AuthFooter />
|
<AuthFooter />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -129,9 +129,9 @@ export default class CaptchaForm extends React.Component {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={this._recaptchaContainer}>
|
<div ref={this._recaptchaContainer}>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"This homeserver would like to make sure you are not a robot.",
|
"This homeserver would like to make sure you are not a robot.",
|
||||||
)}</p>
|
) }</p>
|
||||||
<div id={DIV_ID} />
|
<div id={DIV_ID} />
|
||||||
{ error }
|
{ error }
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -417,12 +417,12 @@ export class TermsAuthEntry extends React.Component<ITermsAuthEntryProps, ITerms
|
||||||
if (this.props.showContinue !== false) {
|
if (this.props.showContinue !== false) {
|
||||||
// XXX: button classes
|
// XXX: button classes
|
||||||
submitButton = <button className="mx_InteractiveAuthEntryComponents_termsSubmit mx_GeneralButton"
|
submitButton = <button className="mx_InteractiveAuthEntryComponents_termsSubmit mx_GeneralButton"
|
||||||
onClick={this.trySubmit} disabled={!allChecked}>{_t("Accept")}</button>;
|
onClick={this.trySubmit} disabled={!allChecked}>{ _t("Accept") }</button>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>{_t("Please review and accept the policies of this homeserver:")}</p>
|
<p>{ _t("Please review and accept the policies of this homeserver:") }</p>
|
||||||
{ checkboxes }
|
{ checkboxes }
|
||||||
{ errorSection }
|
{ errorSection }
|
||||||
{ submitButton }
|
{ submitButton }
|
||||||
|
@ -613,7 +613,7 @@ export class MsisdnAuthEntry extends React.Component<IMsisdnAuthEntryProps, IMsi
|
||||||
className="mx_InteractiveAuthEntryComponents_msisdnEntry"
|
className="mx_InteractiveAuthEntryComponents_msisdnEntry"
|
||||||
value={this.state.token}
|
value={this.state.token}
|
||||||
onChange={this.onTokenChange}
|
onChange={this.onTokenChange}
|
||||||
aria-label={ _t("Code")}
|
aria-label={_t("Code")}
|
||||||
/>
|
/>
|
||||||
<br />
|
<br />
|
||||||
<input type="submit" value={_t("Submit")}
|
<input type="submit" value={_t("Submit")}
|
||||||
|
@ -621,7 +621,7 @@ export class MsisdnAuthEntry extends React.Component<IMsisdnAuthEntryProps, IMsi
|
||||||
disabled={!enableSubmit}
|
disabled={!enableSubmit}
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
{errorSection}
|
{ errorSection }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -717,21 +717,21 @@ export class SSOAuthEntry extends React.Component<ISSOAuthEntryProps, ISSOAuthEn
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
onClick={this.props.onCancel}
|
onClick={this.props.onCancel}
|
||||||
kind={this.props.continueKind ? (this.props.continueKind + '_outline') : 'primary_outline'}
|
kind={this.props.continueKind ? (this.props.continueKind + '_outline') : 'primary_outline'}
|
||||||
>{_t("Cancel")}</AccessibleButton>
|
>{ _t("Cancel") }</AccessibleButton>
|
||||||
);
|
);
|
||||||
if (this.state.phase === SSOAuthEntry.PHASE_PREAUTH) {
|
if (this.state.phase === SSOAuthEntry.PHASE_PREAUTH) {
|
||||||
continueButton = (
|
continueButton = (
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
onClick={this.onStartAuthClick}
|
onClick={this.onStartAuthClick}
|
||||||
kind={this.props.continueKind || 'primary'}
|
kind={this.props.continueKind || 'primary'}
|
||||||
>{this.props.continueText || _t("Single Sign On")}</AccessibleButton>
|
>{ this.props.continueText || _t("Single Sign On") }</AccessibleButton>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
continueButton = (
|
continueButton = (
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
onClick={this.onConfirmClick}
|
onClick={this.onConfirmClick}
|
||||||
kind={this.props.continueKind || 'primary'}
|
kind={this.props.continueKind || 'primary'}
|
||||||
>{this.props.continueText || _t("Confirm")}</AccessibleButton>
|
>{ this.props.continueText || _t("Confirm") }</AccessibleButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,8 +753,8 @@ export class SSOAuthEntry extends React.Component<ISSOAuthEntryProps, ISSOAuthEn
|
||||||
return <React.Fragment>
|
return <React.Fragment>
|
||||||
{ errorSection }
|
{ errorSection }
|
||||||
<div className="mx_InteractiveAuthEntryComponents_sso_buttons">
|
<div className="mx_InteractiveAuthEntryComponents_sso_buttons">
|
||||||
{cancelButton}
|
{ cancelButton }
|
||||||
{continueButton}
|
{ continueButton }
|
||||||
</div>
|
</div>
|
||||||
</React.Fragment>;
|
</React.Fragment>;
|
||||||
}
|
}
|
||||||
|
@ -825,7 +825,7 @@ export class FallbackAuthEntry extends React.Component<IAuthEntryProps> {
|
||||||
<a href="" ref={this.fallbackButton} onClick={this.onShowFallbackClick}>{
|
<a href="" ref={this.fallbackButton} onClick={this.onShowFallbackClick}>{
|
||||||
_t("Start authentication")
|
_t("Start authentication")
|
||||||
}</a>
|
}</a>
|
||||||
{errorSection}
|
{ errorSection }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -416,7 +416,7 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
|
||||||
kind="link"
|
kind="link"
|
||||||
onClick={this.onForgotPasswordClick}
|
onClick={this.onForgotPasswordClick}
|
||||||
>
|
>
|
||||||
{_t("Forgot password?")}
|
{ _t("Forgot password?") }
|
||||||
</AccessibleButton>;
|
</AccessibleButton>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,16 +441,16 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
|
||||||
disabled={this.props.disableSubmit}
|
disabled={this.props.disableSubmit}
|
||||||
>
|
>
|
||||||
<option key={LoginField.MatrixId} value={LoginField.MatrixId}>
|
<option key={LoginField.MatrixId} value={LoginField.MatrixId}>
|
||||||
{_t('Username')}
|
{ _t('Username') }
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
key={LoginField.Email}
|
key={LoginField.Email}
|
||||||
value={LoginField.Email}
|
value={LoginField.Email}
|
||||||
>
|
>
|
||||||
{_t('Email address')}
|
{ _t('Email address') }
|
||||||
</option>
|
</option>
|
||||||
<option key={LoginField.Password} value={LoginField.Password}>
|
<option key={LoginField.Password} value={LoginField.Password}>
|
||||||
{_t('Phone')}
|
{ _t('Phone') }
|
||||||
</option>
|
</option>
|
||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
|
@ -460,8 +460,8 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<form onSubmit={this.onSubmitForm}>
|
<form onSubmit={this.onSubmitForm}>
|
||||||
{loginType}
|
{ loginType }
|
||||||
{loginField}
|
{ loginField }
|
||||||
<Field
|
<Field
|
||||||
className={pwFieldClass}
|
className={pwFieldClass}
|
||||||
type="password"
|
type="password"
|
||||||
|
@ -474,7 +474,7 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
|
||||||
onValidate={this.onPasswordValidate}
|
onValidate={this.onPasswordValidate}
|
||||||
ref={field => this[LoginField.Password] = field}
|
ref={field => this[LoginField.Password] = field}
|
||||||
/>
|
/>
|
||||||
{forgotPasswordJsx}
|
{ forgotPasswordJsx }
|
||||||
{ !this.props.busy && <input className="mx_Login_submit"
|
{ !this.props.busy && <input className="mx_Login_submit"
|
||||||
type="submit"
|
type="submit"
|
||||||
value={_t('Sign in')}
|
value={_t('Sign in')}
|
||||||
|
|
|
@ -537,15 +537,15 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
||||||
<div>
|
<div>
|
||||||
<form onSubmit={this.onSubmit}>
|
<form onSubmit={this.onSubmit}>
|
||||||
<div className="mx_AuthBody_fieldRow">
|
<div className="mx_AuthBody_fieldRow">
|
||||||
{this.renderUsername()}
|
{ this.renderUsername() }
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_AuthBody_fieldRow">
|
<div className="mx_AuthBody_fieldRow">
|
||||||
{this.renderPassword()}
|
{ this.renderPassword() }
|
||||||
{this.renderPasswordConfirm()}
|
{ this.renderPasswordConfirm() }
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_AuthBody_fieldRow">
|
<div className="mx_AuthBody_fieldRow">
|
||||||
{this.renderEmail()}
|
{ this.renderEmail() }
|
||||||
{this.renderPhoneNumber()}
|
{ this.renderPhoneNumber() }
|
||||||
</div>
|
</div>
|
||||||
{ emailHelperText }
|
{ emailHelperText }
|
||||||
{ registerButton }
|
{ registerButton }
|
||||||
|
|
|
@ -205,8 +205,8 @@ export default class DecoratedRoomAvatar extends React.PureComponent<IProps, ISt
|
||||||
oobData={this.props.oobData}
|
oobData={this.props.oobData}
|
||||||
viewAvatarOnClick={this.props.viewAvatarOnClick}
|
viewAvatarOnClick={this.props.viewAvatarOnClick}
|
||||||
/>
|
/>
|
||||||
{icon}
|
{ icon }
|
||||||
{badge}
|
{ badge }
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,7 +145,7 @@ export default class MemberStatusMessageAvatar extends React.Component {
|
||||||
isExpanded={this.state.menuDisplayed}
|
isExpanded={this.state.menuDisplayed}
|
||||||
label={_t("User Status")}
|
label={_t("User Status")}
|
||||||
>
|
>
|
||||||
{avatar}
|
{ avatar }
|
||||||
</ContextMenuButton>
|
</ContextMenuButton>
|
||||||
|
|
||||||
{ contextMenu }
|
{ contextMenu }
|
||||||
|
|
|
@ -65,15 +65,15 @@ export default class CallContextMenu extends React.Component<IProps> {
|
||||||
let transferItem;
|
let transferItem;
|
||||||
if (this.props.call.opponentCanBeTransferred()) {
|
if (this.props.call.opponentCanBeTransferred()) {
|
||||||
transferItem = <MenuItem className="mx_CallContextMenu_item" onClick={this.onTransferClick}>
|
transferItem = <MenuItem className="mx_CallContextMenu_item" onClick={this.onTransferClick}>
|
||||||
{_t("Transfer")}
|
{ _t("Transfer") }
|
||||||
</MenuItem>;
|
</MenuItem>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <ContextMenu {...this.props}>
|
return <ContextMenu {...this.props}>
|
||||||
<MenuItem className="mx_CallContextMenu_item" onClick={handler}>
|
<MenuItem className="mx_CallContextMenu_item" onClick={handler}>
|
||||||
{holdUnholdCaption}
|
{ holdUnholdCaption }
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
{transferItem}
|
{ transferItem }
|
||||||
</ContextMenu>;
|
</ContextMenu>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,8 +64,8 @@ export const IconizedContextMenuRadio: React.FC<IRadioProps> = ({
|
||||||
label={label}
|
label={label}
|
||||||
>
|
>
|
||||||
<span className={classNames("mx_IconizedContextMenu_icon", iconClassName)} />
|
<span className={classNames("mx_IconizedContextMenu_icon", iconClassName)} />
|
||||||
<span className="mx_IconizedContextMenu_label">{label}</span>
|
<span className="mx_IconizedContextMenu_label">{ label }</span>
|
||||||
{active && <span className="mx_IconizedContextMenu_icon mx_IconizedContextMenu_checked" />}
|
{ active && <span className="mx_IconizedContextMenu_icon mx_IconizedContextMenu_checked" /> }
|
||||||
</MenuItemRadio>;
|
</MenuItemRadio>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -85,15 +85,15 @@ export const IconizedContextMenuCheckbox: React.FC<ICheckboxProps> = ({
|
||||||
label={label}
|
label={label}
|
||||||
>
|
>
|
||||||
<span className={classNames("mx_IconizedContextMenu_icon", iconClassName)} />
|
<span className={classNames("mx_IconizedContextMenu_icon", iconClassName)} />
|
||||||
<span className="mx_IconizedContextMenu_label">{label}</span>
|
<span className="mx_IconizedContextMenu_label">{ label }</span>
|
||||||
{active && <span className="mx_IconizedContextMenu_icon mx_IconizedContextMenu_checked" />}
|
{ active && <span className="mx_IconizedContextMenu_icon mx_IconizedContextMenu_checked" /> }
|
||||||
</MenuItemCheckbox>;
|
</MenuItemCheckbox>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const IconizedContextMenuOption: React.FC<IOptionProps> = ({ label, iconClassName, ...props }) => {
|
export const IconizedContextMenuOption: React.FC<IOptionProps> = ({ label, iconClassName, ...props }) => {
|
||||||
return <MenuItem {...props} label={label}>
|
return <MenuItem {...props} label={label}>
|
||||||
{ iconClassName && <span className={classNames("mx_IconizedContextMenu_icon", iconClassName)} /> }
|
{ iconClassName && <span className={classNames("mx_IconizedContextMenu_icon", iconClassName)} /> }
|
||||||
<span className="mx_IconizedContextMenu_label">{label}</span>
|
<span className="mx_IconizedContextMenu_label">{ label }</span>
|
||||||
</MenuItem>;
|
</MenuItem>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ export const IconizedContextMenuOptionList: React.FC<IOptionListProps> = ({ firs
|
||||||
});
|
});
|
||||||
|
|
||||||
return <div className={classes}>
|
return <div className={classes}>
|
||||||
{children}
|
{ children }
|
||||||
</div>;
|
</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -268,7 +268,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
||||||
resendReactionsButton = (
|
resendReactionsButton = (
|
||||||
<IconizedContextMenuOption
|
<IconizedContextMenuOption
|
||||||
iconClassName="mx_MessageContextMenu_iconResend"
|
iconClassName="mx_MessageContextMenu_iconResend"
|
||||||
label={ _t('Resend %(unsentCount)s reaction(s)', { unsentCount: unsentReactionsCount }) }
|
label={_t('Resend %(unsentCount)s reaction(s)', { unsentCount: unsentReactionsCount })}
|
||||||
onClick={this.onResendReactionsClick}
|
onClick={this.onResendReactionsClick}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -298,7 +298,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
||||||
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}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -333,7 +333,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
||||||
<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"
|
||||||
{
|
{
|
||||||
// XXX: Typescript signature for AccessibleButton doesn't work properly for non-inputs like `a`
|
// XXX: Typescript signature for AccessibleButton doesn't work properly for non-inputs like `a`
|
||||||
|
@ -364,7 +364,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
||||||
<IconizedContextMenuOption
|
<IconizedContextMenuOption
|
||||||
iconClassName="mx_MessageContextMenu_iconLink"
|
iconClassName="mx_MessageContextMenu_iconLink"
|
||||||
onClick={this.closeMenu}
|
onClick={this.closeMenu}
|
||||||
label={ _t('Source URL') }
|
label={_t('Source URL')}
|
||||||
element="a"
|
element="a"
|
||||||
{
|
{
|
||||||
// XXX: Typescript signature for AccessibleButton doesn't work properly for non-inputs like `a`
|
// XXX: Typescript signature for AccessibleButton doesn't work properly for non-inputs like `a`
|
||||||
|
|
|
@ -99,20 +99,20 @@ export default class StatusMessageContextMenu extends React.Component {
|
||||||
actionButton = <AccessibleButton className="mx_StatusMessageContextMenu_clear"
|
actionButton = <AccessibleButton className="mx_StatusMessageContextMenu_clear"
|
||||||
onClick={this._onClearClick}
|
onClick={this._onClearClick}
|
||||||
>
|
>
|
||||||
<span>{_t("Clear status")}</span>
|
<span>{ _t("Clear status") }</span>
|
||||||
</AccessibleButton>;
|
</AccessibleButton>;
|
||||||
} else {
|
} else {
|
||||||
actionButton = <AccessibleButton className="mx_StatusMessageContextMenu_submit"
|
actionButton = <AccessibleButton className="mx_StatusMessageContextMenu_submit"
|
||||||
onClick={this._onSubmit}
|
onClick={this._onSubmit}
|
||||||
>
|
>
|
||||||
<span>{_t("Update status")}</span>
|
<span>{ _t("Update status") }</span>
|
||||||
</AccessibleButton>;
|
</AccessibleButton>;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
actionButton = <AccessibleButton className="mx_StatusMessageContextMenu_submit"
|
actionButton = <AccessibleButton className="mx_StatusMessageContextMenu_submit"
|
||||||
disabled={!this.state.message} onClick={this._onSubmit}
|
disabled={!this.state.message} onClick={this._onSubmit}
|
||||||
>
|
>
|
||||||
<span>{_t("Set status")}</span>
|
<span>{ _t("Set status") }</span>
|
||||||
</AccessibleButton>;
|
</AccessibleButton>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,8 +130,8 @@ export default class StatusMessageContextMenu extends React.Component {
|
||||||
onChange={this._onStatusChange}
|
onChange={this._onStatusChange}
|
||||||
/>
|
/>
|
||||||
<div className="mx_StatusMessageContextMenu_actionContainer">
|
<div className="mx_StatusMessageContextMenu_actionContainer">
|
||||||
{actionButton}
|
{ actionButton }
|
||||||
{spinner}
|
{ spinner }
|
||||||
</div>
|
</div>
|
||||||
</form>;
|
</form>;
|
||||||
|
|
||||||
|
|
|
@ -221,7 +221,7 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
|
||||||
return <div className="mx_AddExistingToSpace">
|
return <div className="mx_AddExistingToSpace">
|
||||||
<SearchBox
|
<SearchBox
|
||||||
className="mx_textinput_icon mx_textinput_search"
|
className="mx_textinput_icon mx_textinput_search"
|
||||||
placeholder={ _t("Filter your rooms and spaces") }
|
placeholder={_t("Filter your rooms and spaces")}
|
||||||
onSearch={setQuery}
|
onSearch={setQuery}
|
||||||
autoComplete={true}
|
autoComplete={true}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
|
|
|
@ -51,7 +51,7 @@ export default class AskInviteAnywayDialog extends React.Component<IProps> {
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
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>);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog className='mx_RetryInvitesDialog'
|
<BaseDialog className='mx_RetryInvitesDialog'
|
||||||
|
@ -60,8 +60,8 @@ export default class AskInviteAnywayDialog extends React.Component<IProps> {
|
||||||
contentId='mx_Dialog_content'
|
contentId='mx_Dialog_content'
|
||||||
>
|
>
|
||||||
<div id='mx_Dialog_content'>
|
<div id='mx_Dialog_content'>
|
||||||
{/* eslint-disable-next-line */}
|
<p>{ _t("Unable to find profiles for the Matrix IDs listed below - " +
|
||||||
<p>{_t("Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?")}</p>
|
"would you like to invite them anyway?") }</p>
|
||||||
<ul>
|
<ul>
|
||||||
{ errorList }
|
{ errorList }
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -149,7 +149,7 @@ export default class BaseDialog extends React.Component {
|
||||||
'mx_Dialog_headerWithCancel': !!cancelButton,
|
'mx_Dialog_headerWithCancel': !!cancelButton,
|
||||||
})}>
|
})}>
|
||||||
<div className={classNames('mx_Dialog_title', this.props.titleClass)} id='mx_BaseDialog_title'>
|
<div className={classNames('mx_Dialog_title', this.props.titleClass)} id='mx_BaseDialog_title'>
|
||||||
{headerImage}
|
{ headerImage }
|
||||||
{ this.props.title }
|
{ this.props.title }
|
||||||
</div>
|
</div>
|
||||||
{ this.props.headerButton }
|
{ this.props.headerButton }
|
||||||
|
|
|
@ -69,7 +69,7 @@ const BetaFeedbackDialog: React.FC<IProps> = ({ featureId, onFinished }) => {
|
||||||
<div className="mx_BetaFeedbackDialog_subheading">
|
<div className="mx_BetaFeedbackDialog_subheading">
|
||||||
{ _t(info.feedbackSubheading) }
|
{ _t(info.feedbackSubheading) }
|
||||||
|
|
||||||
{ _t("Your platform and username will be noted to help us use your feedback as much as we can.")}
|
{ _t("Your platform and username will be noted to help us use your feedback as much as we can.") }
|
||||||
|
|
||||||
<AccessibleButton kind="link" onClick={() => {
|
<AccessibleButton kind="link" onClick={() => {
|
||||||
onFinished(false);
|
onFinished(false);
|
||||||
|
|
|
@ -166,7 +166,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
|
||||||
let error = null;
|
let error = null;
|
||||||
if (this.state.err) {
|
if (this.state.err) {
|
||||||
error = <div className="error">
|
error = <div className="error">
|
||||||
{this.state.err}
|
{ this.state.err }
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
|
||||||
progress = (
|
progress = (
|
||||||
<div className="progress">
|
<div className="progress">
|
||||||
<Spinner />
|
<Spinner />
|
||||||
{this.state.progress} ...
|
{ this.state.progress } ...
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -221,7 +221,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
|
||||||
<AccessibleButton onClick={this.onDownload} kind="link" disabled={this.state.downloadBusy}>
|
<AccessibleButton onClick={this.onDownload} kind="link" disabled={this.state.downloadBusy}>
|
||||||
{ _t("Download logs") }
|
{ _t("Download logs") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
{this.state.downloadProgress && <span>{this.state.downloadProgress} ...</span>}
|
{ this.state.downloadProgress && <span>{ this.state.downloadProgress } ...</span> }
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Field
|
<Field
|
||||||
|
@ -246,8 +246,8 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
|
||||||
"please include those things here.",
|
"please include those things here.",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{progress}
|
{ progress }
|
||||||
{error}
|
{ error }
|
||||||
</div>
|
</div>
|
||||||
<DialogButtons primaryButton={_t("Send logs")}
|
<DialogButtons primaryButton={_t("Send logs")}
|
||||||
onPrimaryButtonClick={this.onSubmit}
|
onPrimaryButtonClick={this.onSubmit}
|
||||||
|
|
|
@ -59,7 +59,7 @@ export default class ChangelogDialog extends React.Component<IProps> {
|
||||||
return (
|
return (
|
||||||
<li key={commit.sha} className="mx_ChangelogDialog_li">
|
<li key={commit.sha} className="mx_ChangelogDialog_li">
|
||||||
<a href={commit.html_url} target="_blank" rel="noreferrer noopener">
|
<a href={commit.html_url} target="_blank" rel="noreferrer noopener">
|
||||||
{commit.commit.message.split('\n')[0]}
|
{ commit.commit.message.split('\n')[0] }
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
@ -79,15 +79,15 @@ export default class ChangelogDialog extends React.Component<IProps> {
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div key={repo}>
|
<div key={repo}>
|
||||||
<h2>{repo}</h2>
|
<h2>{ repo }</h2>
|
||||||
<ul>{content}</ul>
|
<ul>{ content }</ul>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const content = (
|
const content = (
|
||||||
<div className="mx_ChangelogDialog_content">
|
<div className="mx_ChangelogDialog_content">
|
||||||
{this.props.version == null || this.props.newVersion == null ? <h2>{_t("Unavailable")}</h2> : logs}
|
{ this.props.version == null || this.props.newVersion == null ? <h2>{ _t("Unavailable") }</h2> : logs }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -156,8 +156,8 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent<
|
||||||
height={avatarSize}
|
height={avatarSize}
|
||||||
/>
|
/>
|
||||||
<div className="mx_CommunityPrototypeInviteDialog_personIdentifiers">
|
<div className="mx_CommunityPrototypeInviteDialog_personIdentifiers">
|
||||||
<span className="mx_CommunityPrototypeInviteDialog_personName">{person.user.name}</span>
|
<span className="mx_CommunityPrototypeInviteDialog_personName">{ person.user.name }</span>
|
||||||
<span className="mx_CommunityPrototypeInviteDialog_personId">{person.userId}</span>
|
<span className="mx_CommunityPrototypeInviteDialog_personId">{ person.userId }</span>
|
||||||
</div>
|
</div>
|
||||||
<StyledCheckbox onChange={(e) => this.setPersonToggle(person, e.target.checked)} />
|
<StyledCheckbox onChange={(e) => this.setPersonToggle(person, e.target.checked)} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -187,7 +187,7 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent<
|
||||||
emailAddresses.push((
|
emailAddresses.push((
|
||||||
<Field
|
<Field
|
||||||
key={emailAddresses.length}
|
key={emailAddresses.length}
|
||||||
value={""}
|
value=""
|
||||||
onChange={(e) => this.onAddressChange(e, emailAddresses.length)}
|
onChange={(e) => this.onAddressChange(e, emailAddresses.length)}
|
||||||
label={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")}
|
label={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")}
|
||||||
placeholder={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")}
|
placeholder={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")}
|
||||||
|
@ -207,16 +207,16 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent<
|
||||||
onClick={this.onShowMorePeople}
|
onClick={this.onShowMorePeople}
|
||||||
kind="link" key="more"
|
kind="link" key="more"
|
||||||
className="mx_CommunityPrototypeInviteDialog_morePeople"
|
className="mx_CommunityPrototypeInviteDialog_morePeople"
|
||||||
>{_t("Show more")}</AccessibleButton>
|
>{ _t("Show more") }</AccessibleButton>
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.state.people.length > 0) {
|
if (this.state.people.length > 0) {
|
||||||
peopleIntro = (
|
peopleIntro = (
|
||||||
<div className="mx_CommunityPrototypeInviteDialog_people">
|
<div className="mx_CommunityPrototypeInviteDialog_people">
|
||||||
<span>{_t("People you know on %(brand)s", { brand: SdkConfig.get().brand })}</span>
|
<span>{ _t("People you know on %(brand)s", { brand: SdkConfig.get().brand }) }</span>
|
||||||
<AccessibleButton onClick={this.onShowPeopleClick}>
|
<AccessibleButton onClick={this.onShowPeopleClick}>
|
||||||
{this.state.showPeople ? _t("Hide") : _t("Show")}
|
{ this.state.showPeople ? _t("Hide") : _t("Show") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -236,14 +236,14 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent<
|
||||||
>
|
>
|
||||||
<form onSubmit={this.onSubmit}>
|
<form onSubmit={this.onSubmit}>
|
||||||
<div className="mx_Dialog_content">
|
<div className="mx_Dialog_content">
|
||||||
{emailAddresses}
|
{ emailAddresses }
|
||||||
{peopleIntro}
|
{ peopleIntro }
|
||||||
{people}
|
{ people }
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
kind="primary" onClick={this.onSubmit}
|
kind="primary" onClick={this.onSubmit}
|
||||||
disabled={this.state.busy}
|
disabled={this.state.busy}
|
||||||
className="mx_CommunityPrototypeInviteDialog_primaryButton"
|
className="mx_CommunityPrototypeInviteDialog_primaryButton"
|
||||||
>{buttonText}</AccessibleButton>
|
>{ buttonText }</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
|
|
|
@ -44,10 +44,10 @@ export default class ConfirmWipeDeviceDialog extends React.Component<IProps> {
|
||||||
>
|
>
|
||||||
<div className='mx_ConfirmWipeDeviceDialog_content'>
|
<div className='mx_ConfirmWipeDeviceDialog_content'>
|
||||||
<p>
|
<p>
|
||||||
{_t(
|
{ _t(
|
||||||
"Clearing all data from this session is permanent. Encrypted messages will be lost " +
|
"Clearing all data from this session is permanent. Encrypted messages will be lost " +
|
||||||
"unless their keys have been backed up.",
|
"unless their keys have been backed up.",
|
||||||
)}
|
) }
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
|
|
|
@ -144,11 +144,11 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent<
|
||||||
if (this.state.localpart) {
|
if (this.state.localpart) {
|
||||||
communityId = (
|
communityId = (
|
||||||
<span className="mx_CreateCommunityPrototypeDialog_communityId">
|
<span className="mx_CreateCommunityPrototypeDialog_communityId">
|
||||||
{_t("Community ID: +<localpart />:%(domain)s", {
|
{ _t("Community ID: +<localpart />:%(domain)s", {
|
||||||
domain: MatrixClientPeg.getHomeserverName(),
|
domain: MatrixClientPeg.getHomeserverName(),
|
||||||
}, {
|
}, {
|
||||||
localpart: () => <u>{this.state.localpart}</u>,
|
localpart: () => <u>{ this.state.localpart }</u>,
|
||||||
})}
|
}) }
|
||||||
<InfoTooltip
|
<InfoTooltip
|
||||||
tooltip={_t(
|
tooltip={_t(
|
||||||
"Use this when referencing your community to others. The community ID " +
|
"Use this when referencing your community to others. The community ID " +
|
||||||
|
@ -161,14 +161,14 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent<
|
||||||
|
|
||||||
let helpText = (
|
let helpText = (
|
||||||
<span className="mx_CreateCommunityPrototypeDialog_subtext">
|
<span className="mx_CreateCommunityPrototypeDialog_subtext">
|
||||||
{_t("You can change this later if needed.")}
|
{ _t("You can change this later if needed.") }
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
if (this.state.error) {
|
if (this.state.error) {
|
||||||
const classes = "mx_CreateCommunityPrototypeDialog_subtext mx_CreateCommunityPrototypeDialog_subtext_error";
|
const classes = "mx_CreateCommunityPrototypeDialog_subtext mx_CreateCommunityPrototypeDialog_subtext_error";
|
||||||
helpText = (
|
helpText = (
|
||||||
<span className={classes}>
|
<span className={classes}>
|
||||||
{this.state.error}
|
{ this.state.error }
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -193,13 +193,13 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent<
|
||||||
placeholder={_t("Enter name")}
|
placeholder={_t("Enter name")}
|
||||||
label={_t("Enter name")}
|
label={_t("Enter name")}
|
||||||
/>
|
/>
|
||||||
{helpText}
|
{ helpText }
|
||||||
<span className="mx_CreateCommunityPrototypeDialog_subtext">
|
<span className="mx_CreateCommunityPrototypeDialog_subtext">
|
||||||
{/*nbsp is to reserve the height of this element when there's nothing*/}
|
{ /*nbsp is to reserve the height of this element when there's nothing*/ }
|
||||||
{communityId}
|
{ communityId }
|
||||||
</span>
|
</span>
|
||||||
<AccessibleButton kind="primary" onClick={this.onSubmit} disabled={this.state.busy}>
|
<AccessibleButton kind="primary" onClick={this.onSubmit} disabled={this.state.busy}>
|
||||||
{_t("Create")}
|
{ _t("Create") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_CreateCommunityPrototypeDialog_colAvatar">
|
<div className="mx_CreateCommunityPrototypeDialog_colAvatar">
|
||||||
|
@ -212,12 +212,12 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent<
|
||||||
onClick={this.onChangeAvatar}
|
onClick={this.onChangeAvatar}
|
||||||
className="mx_CreateCommunityPrototypeDialog_avatarContainer"
|
className="mx_CreateCommunityPrototypeDialog_avatarContainer"
|
||||||
>
|
>
|
||||||
{preview}
|
{ preview }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
<div className="mx_CreateCommunityPrototypeDialog_tip">
|
<div className="mx_CreateCommunityPrototypeDialog_tip">
|
||||||
<b>{_t("Add image (optional)")}</b>
|
<b>{ _t("Add image (optional)") }</b>
|
||||||
<span>
|
<span>
|
||||||
{_t("An image will help people identify your community.")}
|
{ _t("An image will help people identify your community.") }
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -102,7 +102,7 @@ export default class CreateGroupDialog extends React.Component<IProps, IState> {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
_onCancel = () => {
|
private onCancel = () => {
|
||||||
this.props.onFinished(false);
|
this.props.onFinished(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ export default class CreateGroupDialog extends React.Component<IProps, IState> {
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
<input type="submit" value={_t('Create')} className="mx_Dialog_primary" />
|
<input type="submit" value={_t('Create')} className="mx_Dialog_primary" />
|
||||||
<button onClick={this._onCancel}>
|
<button onClick={this.onCancel}>
|
||||||
{ _t("Cancel") }
|
{ _t("Cancel") }
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -224,15 +224,15 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let publicPrivateLabel = <p>{_t(
|
let publicPrivateLabel = <p>{ _t(
|
||||||
"Private rooms can be found and joined by invitation only. Public rooms can be " +
|
"Private rooms can be found and joined by invitation only. Public rooms can be " +
|
||||||
"found and joined by anyone.",
|
"found and joined by anyone.",
|
||||||
)}</p>;
|
) }</p>;
|
||||||
if (CommunityPrototypeStore.instance.getSelectedCommunityId()) {
|
if (CommunityPrototypeStore.instance.getSelectedCommunityId()) {
|
||||||
publicPrivateLabel = <p>{_t(
|
publicPrivateLabel = <p>{ _t(
|
||||||
"Private rooms can be found and joined by invitation only. Public rooms can be " +
|
"Private rooms can be found and joined by invitation only. Public rooms can be " +
|
||||||
"found and joined by anyone in this community.",
|
"found and joined by anyone in this community.",
|
||||||
)}</p>;
|
) }</p>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let e2eeSection;
|
let e2eeSection;
|
||||||
|
@ -250,7 +250,7 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
e2eeSection = <React.Fragment>
|
e2eeSection = <React.Fragment>
|
||||||
<LabelledToggleSwitch
|
<LabelledToggleSwitch
|
||||||
label={ _t("Enable end-to-end encryption")}
|
label={_t("Enable end-to-end encryption")}
|
||||||
onChange={this.onEncryptedChange}
|
onChange={this.onEncryptedChange}
|
||||||
value={this.state.isEncrypted}
|
value={this.state.isEncrypted}
|
||||||
className='mx_CreateRoomDialog_e2eSwitch' // for end-to-end tests
|
className='mx_CreateRoomDialog_e2eSwitch' // for end-to-end tests
|
||||||
|
@ -318,7 +318,7 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
|
||||||
onChange={this.onNoFederateChange}
|
onChange={this.onNoFederateChange}
|
||||||
value={this.state.noFederate}
|
value={this.state.noFederate}
|
||||||
/>
|
/>
|
||||||
<p>{federateLabel}</p>
|
<p>{ federateLabel }</p>
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -172,11 +172,11 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let auth = <div>{_t("Loading...")}</div>;
|
let auth = <div>{ _t("Loading...") }</div>;
|
||||||
if (this.state.authData && this.state.authEnabled) {
|
if (this.state.authData && this.state.authEnabled) {
|
||||||
auth = (
|
auth = (
|
||||||
<div>
|
<div>
|
||||||
{this.state.bodyText}
|
{ this.state.bodyText }
|
||||||
<InteractiveAuth
|
<InteractiveAuth
|
||||||
matrixClient={MatrixClientPeg.get()}
|
matrixClient={MatrixClientPeg.get()}
|
||||||
authData={this.state.authData}
|
authData={this.state.authData}
|
||||||
|
@ -230,18 +230,18 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
|
||||||
checked={this.state.shouldErase}
|
checked={this.state.shouldErase}
|
||||||
onChange={this.onEraseFieldChange}
|
onChange={this.onEraseFieldChange}
|
||||||
>
|
>
|
||||||
{_t(
|
{ _t(
|
||||||
"Please forget all messages I have sent when my account is deactivated " +
|
"Please forget all messages I have sent when my account is deactivated " +
|
||||||
"(<b>Warning:</b> this will cause future users to see an incomplete view " +
|
"(<b>Warning:</b> this will cause future users to see an incomplete view " +
|
||||||
"of conversations)",
|
"of conversations)",
|
||||||
{},
|
{},
|
||||||
{ b: (sub) => <b>{ sub }</b> },
|
{ b: (sub) => <b>{ sub }</b> },
|
||||||
)}
|
) }
|
||||||
</StyledCheckbox>
|
</StyledCheckbox>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{error}
|
{ error }
|
||||||
{auth}
|
{ auth }
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -337,7 +337,7 @@ class FilteredList extends React.PureComponent<IFilteredListProps, IFilteredList
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
|
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
|
||||||
UNSAFE_componentWillReceiveProps(nextProps) { // eslint-disable-line camelcase
|
UNSAFE_componentWillReceiveProps(nextProps) { // eslint-disable-line
|
||||||
if (this.props.children === nextProps.children && this.props.query === nextProps.query) return;
|
if (this.props.children === nextProps.children && this.props.query === nextProps.query) return;
|
||||||
this.setState({
|
this.setState({
|
||||||
filteredChildren: FilteredList.filterChildren(nextProps.children, nextProps.query),
|
filteredChildren: FilteredList.filterChildren(nextProps.children, nextProps.query),
|
||||||
|
@ -494,7 +494,7 @@ class RoomStateExplorer extends React.PureComponent<IExplorerProps, IRoomStateEx
|
||||||
}
|
}
|
||||||
|
|
||||||
return <button className={classes} key={eventType} onClick={onClickFn}>
|
return <button className={classes} key={eventType} onClick={onClickFn}>
|
||||||
{eventType}
|
{ eventType }
|
||||||
</button>;
|
</button>;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -726,17 +726,17 @@ const VerificationRequestExplorer: React.FC<{
|
||||||
return (<div className="mx_DevTools_VerificationRequest">
|
return (<div className="mx_DevTools_VerificationRequest">
|
||||||
<dl>
|
<dl>
|
||||||
<dt>Transaction</dt>
|
<dt>Transaction</dt>
|
||||||
<dd>{txnId}</dd>
|
<dd>{ txnId }</dd>
|
||||||
<dt>Phase</dt>
|
<dt>Phase</dt>
|
||||||
<dd>{PHASE_MAP[request.phase] || request.phase}</dd>
|
<dd>{ PHASE_MAP[request.phase] || request.phase }</dd>
|
||||||
<dt>Timeout</dt>
|
<dt>Timeout</dt>
|
||||||
<dd>{Math.floor(timeout / 1000)}</dd>
|
<dd>{ Math.floor(timeout / 1000) }</dd>
|
||||||
<dt>Methods</dt>
|
<dt>Methods</dt>
|
||||||
<dd>{request.methods && request.methods.join(", ")}</dd>
|
<dd>{ request.methods && request.methods.join(", ") }</dd>
|
||||||
<dt>requestingUserId</dt>
|
<dt>requestingUserId</dt>
|
||||||
<dd>{request.requestingUserId}</dd>
|
<dd>{ request.requestingUserId }</dd>
|
||||||
<dt>observeOnly</dt>
|
<dt>observeOnly</dt>
|
||||||
<dd>{JSON.stringify(request.observeOnly)}</dd>
|
<dd>{ JSON.stringify(request.observeOnly) }</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>);
|
</div>);
|
||||||
};
|
};
|
||||||
|
@ -771,12 +771,12 @@ class VerificationExplorer extends React.PureComponent<IExplorerProps> {
|
||||||
|
|
||||||
return (<div>
|
return (<div>
|
||||||
<div className="mx_Dialog_content">
|
<div className="mx_Dialog_content">
|
||||||
{Array.from(inRoomRequests.entries()).reverse().map(([txnId, request]) =>
|
{ Array.from(inRoomRequests.entries()).reverse().map(([txnId, request]) =>
|
||||||
<VerificationRequestExplorer txnId={txnId} request={request} key={txnId} />,
|
<VerificationRequestExplorer txnId={txnId} request={request} key={txnId} />,
|
||||||
)}
|
) }
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
<button onClick={this.props.onBack}>{_t("Back")}</button>
|
<button onClick={this.props.onBack}>{ _t("Back") }</button>
|
||||||
</div>
|
</div>
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
|
@ -844,9 +844,9 @@ class WidgetExplorer extends React.Component<IExplorerProps, IWidgetExplorerStat
|
||||||
const stateEv = allState.find(ev => ev.getId() === editWidget.eventId);
|
const stateEv = allState.find(ev => ev.getId() === editWidget.eventId);
|
||||||
if (!stateEv) { // "should never happen"
|
if (!stateEv) { // "should never happen"
|
||||||
return <div>
|
return <div>
|
||||||
{_t("There was an error finding this widget.")}
|
{ _t("There was an error finding this widget.") }
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
<button onClick={this.onBack}>{_t("Back")}</button>
|
<button onClick={this.onBack}>{ _t("Back") }</button>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
@ -865,17 +865,17 @@ class WidgetExplorer extends React.Component<IExplorerProps, IWidgetExplorerStat
|
||||||
return (<div>
|
return (<div>
|
||||||
<div className="mx_Dialog_content">
|
<div className="mx_Dialog_content">
|
||||||
<FilteredList query={this.state.query} onChange={this.onQueryChange}>
|
<FilteredList query={this.state.query} onChange={this.onQueryChange}>
|
||||||
{widgets.map(w => {
|
{ widgets.map(w => {
|
||||||
return <button
|
return <button
|
||||||
className='mx_DevTools_RoomStateExplorer_button'
|
className='mx_DevTools_RoomStateExplorer_button'
|
||||||
key={w.url + w.eventId}
|
key={w.url + w.eventId}
|
||||||
onClick={() => this.onEditWidget(w)}
|
onClick={() => this.onEditWidget(w)}
|
||||||
>{w.url}</button>;
|
>{ w.url }</button>;
|
||||||
})}
|
}) }
|
||||||
</FilteredList>
|
</FilteredList>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
<button onClick={this.onBack}>{_t("Back")}</button>
|
<button onClick={this.onBack}>{ _t("Back") }</button>
|
||||||
</div>
|
</div>
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
|
@ -1007,7 +1007,7 @@ class SettingsExplorer extends React.PureComponent<IExplorerProps, ISettingsExpl
|
||||||
private renderCanEditLevel(roomId: string, level: SettingLevel): React.ReactNode {
|
private renderCanEditLevel(roomId: string, level: SettingLevel): React.ReactNode {
|
||||||
const canEdit = SettingsStore.canSetValue(this.state.editSetting, roomId, level);
|
const canEdit = SettingsStore.canSetValue(this.state.editSetting, roomId, level);
|
||||||
const className = canEdit ? 'mx_DevTools_SettingsExplorer_mutable' : 'mx_DevTools_SettingsExplorer_immutable';
|
const className = canEdit ? 'mx_DevTools_SettingsExplorer_mutable' : 'mx_DevTools_SettingsExplorer_immutable';
|
||||||
return <td className={className}><code>{canEdit.toString()}</code></td>;
|
return <td className={className}><code>{ canEdit.toString() }</code></td>;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -1028,17 +1028,17 @@ class SettingsExplorer extends React.PureComponent<IExplorerProps, ISettingsExpl
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{_t("Setting ID")}</th>
|
<th>{ _t("Setting ID") }</th>
|
||||||
<th>{_t("Value")}</th>
|
<th>{ _t("Value") }</th>
|
||||||
<th>{_t("Value in this room")}</th>
|
<th>{ _t("Value in this room") }</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{allSettings.map(i => (
|
{ allSettings.map(i => (
|
||||||
<tr key={i}>
|
<tr key={i}>
|
||||||
<td>
|
<td>
|
||||||
<a href="" onClick={(e) => this.onViewClick(e, i)}>
|
<a href="" onClick={(e) => this.onViewClick(e, i)}>
|
||||||
<code>{i}</code>
|
<code>{ i }</code>
|
||||||
</a>
|
</a>
|
||||||
<a href="" onClick={(e) => this.onEditClick(e, i)}
|
<a href="" onClick={(e) => this.onEditClick(e, i)}
|
||||||
className='mx_DevTools_SettingsExplorer_edit'
|
className='mx_DevTools_SettingsExplorer_edit'
|
||||||
|
@ -1047,20 +1047,20 @@ class SettingsExplorer extends React.PureComponent<IExplorerProps, ISettingsExpl
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<code>{this.renderSettingValue(SettingsStore.getValue(i))}</code>
|
<code>{ this.renderSettingValue(SettingsStore.getValue(i)) }</code>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<code>
|
<code>
|
||||||
{this.renderSettingValue(SettingsStore.getValue(i, room.roomId))}
|
{ this.renderSettingValue(SettingsStore.getValue(i, room.roomId)) }
|
||||||
</code>
|
</code>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
)) }
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
<button onClick={this.onBack}>{_t("Back")}</button>
|
<button onClick={this.onBack}>{ _t("Back") }</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1068,36 +1068,36 @@ class SettingsExplorer extends React.PureComponent<IExplorerProps, ISettingsExpl
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="mx_Dialog_content mx_DevTools_SettingsExplorer">
|
<div className="mx_Dialog_content mx_DevTools_SettingsExplorer">
|
||||||
<h3>{_t("Setting:")} <code>{this.state.editSetting}</code></h3>
|
<h3>{ _t("Setting:") } <code>{ this.state.editSetting }</code></h3>
|
||||||
|
|
||||||
<div className='mx_DevTools_SettingsExplorer_warning'>
|
<div className='mx_DevTools_SettingsExplorer_warning'>
|
||||||
<b>{_t("Caution:")}</b> {_t(
|
<b>{ _t("Caution:") }</b> { _t(
|
||||||
"This UI does NOT check the types of the values. Use at your own risk.",
|
"This UI does NOT check the types of the values. Use at your own risk.",
|
||||||
)}
|
) }
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{_t("Setting definition:")}
|
{ _t("Setting definition:") }
|
||||||
<pre><code>{JSON.stringify(SETTINGS[this.state.editSetting], null, 4)}</code></pre>
|
<pre><code>{ JSON.stringify(SETTINGS[this.state.editSetting], null, 4) }</code></pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{_t("Level")}</th>
|
<th>{ _t("Level") }</th>
|
||||||
<th>{_t("Settable at global")}</th>
|
<th>{ _t("Settable at global") }</th>
|
||||||
<th>{_t("Settable at room")}</th>
|
<th>{ _t("Settable at room") }</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{LEVEL_ORDER.map(lvl => (
|
{ LEVEL_ORDER.map(lvl => (
|
||||||
<tr key={lvl}>
|
<tr key={lvl}>
|
||||||
<td><code>{lvl}</code></td>
|
<td><code>{ lvl }</code></td>
|
||||||
{this.renderCanEditLevel(null, lvl)}
|
{ this.renderCanEditLevel(null, lvl) }
|
||||||
{this.renderCanEditLevel(room.roomId, lvl)}
|
{ this.renderCanEditLevel(room.roomId, lvl) }
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
)) }
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1122,8 +1122,8 @@ class SettingsExplorer extends React.PureComponent<IExplorerProps, ISettingsExpl
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
<button onClick={this.onSaveClick}>{_t("Save setting values")}</button>
|
<button onClick={this.onSaveClick}>{ _t("Save setting values") }</button>
|
||||||
<button onClick={this.onBack}>{_t("Back")}</button>
|
<button onClick={this.onBack}>{ _t("Back") }</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1131,39 +1131,39 @@ class SettingsExplorer extends React.PureComponent<IExplorerProps, ISettingsExpl
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="mx_Dialog_content mx_DevTools_SettingsExplorer">
|
<div className="mx_Dialog_content mx_DevTools_SettingsExplorer">
|
||||||
<h3>{_t("Setting:")} <code>{this.state.viewSetting}</code></h3>
|
<h3>{ _t("Setting:") } <code>{ this.state.viewSetting }</code></h3>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{_t("Setting definition:")}
|
{ _t("Setting definition:") }
|
||||||
<pre><code>{JSON.stringify(SETTINGS[this.state.viewSetting], null, 4)}</code></pre>
|
<pre><code>{ JSON.stringify(SETTINGS[this.state.viewSetting], null, 4) }</code></pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{_t("Value:")}
|
{ _t("Value:") }
|
||||||
<code>{this.renderSettingValue(
|
<code>{ this.renderSettingValue(
|
||||||
SettingsStore.getValue(this.state.viewSetting),
|
SettingsStore.getValue(this.state.viewSetting),
|
||||||
)}</code>
|
) }</code>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{_t("Value in this room:")}
|
{ _t("Value in this room:") }
|
||||||
<code>{this.renderSettingValue(
|
<code>{ this.renderSettingValue(
|
||||||
SettingsStore.getValue(this.state.viewSetting, room.roomId),
|
SettingsStore.getValue(this.state.viewSetting, room.roomId),
|
||||||
)}</code>
|
) }</code>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{_t("Values at explicit levels:")}
|
{ _t("Values at explicit levels:") }
|
||||||
<pre><code>{this.renderExplicitSettingValues(
|
<pre><code>{ this.renderExplicitSettingValues(
|
||||||
this.state.viewSetting, null,
|
this.state.viewSetting, null,
|
||||||
)}</code></pre>
|
) }</code></pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{_t("Values at explicit levels in this room:")}
|
{ _t("Values at explicit levels in this room:") }
|
||||||
<pre><code>{this.renderExplicitSettingValues(
|
<pre><code>{ this.renderExplicitSettingValues(
|
||||||
this.state.viewSetting, room.roomId,
|
this.state.viewSetting, room.roomId,
|
||||||
)}</code></pre>
|
) }</code></pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -1171,7 +1171,7 @@ class SettingsExplorer extends React.PureComponent<IExplorerProps, ISettingsExpl
|
||||||
<button onClick={(e) => this.onEditClick(e, this.state.viewSetting)}>{
|
<button onClick={(e) => this.onEditClick(e, this.state.viewSetting)}>{
|
||||||
_t("Edit Values")
|
_t("Edit Values")
|
||||||
}</button>
|
}</button>
|
||||||
<button onClick={this.onBack}>{_t("Back")}</button>
|
<button onClick={this.onBack}>{ _t("Back") }</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1232,12 +1232,12 @@ export default class DevtoolsDialog extends React.PureComponent<IProps, IState>
|
||||||
|
|
||||||
if (this.state.mode) {
|
if (this.state.mode) {
|
||||||
body = <MatrixClientContext.Consumer>
|
body = <MatrixClientContext.Consumer>
|
||||||
{(cli) => <React.Fragment>
|
{ (cli) => <React.Fragment>
|
||||||
<div className="mx_DevTools_label_left">{ this.state.mode.getLabel() }</div>
|
<div className="mx_DevTools_label_left">{ this.state.mode.getLabel() }</div>
|
||||||
<div className="mx_DevTools_label_right">Room ID: { this.props.roomId }</div>
|
<div className="mx_DevTools_label_right">Room ID: { this.props.roomId }</div>
|
||||||
<div className="mx_DevTools_label_bottom" />
|
<div className="mx_DevTools_label_bottom" />
|
||||||
<this.state.mode onBack={this.onBack} room={cli.getRoom(this.props.roomId)} />
|
<this.state.mode onBack={this.onBack} room={cli.getRoom(this.props.roomId)} />
|
||||||
</React.Fragment>}
|
</React.Fragment> }
|
||||||
</MatrixClientContext.Consumer>;
|
</MatrixClientContext.Consumer>;
|
||||||
} else {
|
} else {
|
||||||
const classes = "mx_DevTools_RoomStateExplorer_button";
|
const classes = "mx_DevTools_RoomStateExplorer_button";
|
||||||
|
|
|
@ -151,16 +151,16 @@ export default class EditCommunityPrototypeDialog extends React.PureComponent<IP
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
onClick={this.onChangeAvatar}
|
onClick={this.onChangeAvatar}
|
||||||
className="mx_EditCommunityPrototypeDialog_avatarContainer"
|
className="mx_EditCommunityPrototypeDialog_avatarContainer"
|
||||||
>{preview}</AccessibleButton>
|
>{ preview }</AccessibleButton>
|
||||||
<div className="mx_EditCommunityPrototypeDialog_tip">
|
<div className="mx_EditCommunityPrototypeDialog_tip">
|
||||||
<b>{_t("Add image (optional)")}</b>
|
<b>{ _t("Add image (optional)") }</b>
|
||||||
<span>
|
<span>
|
||||||
{_t("An image will help people identify your community.")}
|
{ _t("An image will help people identify your community.") }
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<AccessibleButton kind="primary" onClick={this.onSubmit} disabled={this.state.busy}>
|
<AccessibleButton kind="primary" onClick={this.onSubmit} disabled={this.state.busy}>
|
||||||
{_t("Save")}
|
{ _t("Save") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -58,10 +58,10 @@ export default (props) => {
|
||||||
countlyFeedbackSection = <React.Fragment>
|
countlyFeedbackSection = <React.Fragment>
|
||||||
<hr />
|
<hr />
|
||||||
<div className="mx_FeedbackDialog_section mx_FeedbackDialog_rateApp">
|
<div className="mx_FeedbackDialog_section mx_FeedbackDialog_rateApp">
|
||||||
<h3>{_t("Rate %(brand)s", { brand })}</h3>
|
<h3>{ _t("Rate %(brand)s", { brand }) }</h3>
|
||||||
|
|
||||||
<p>{_t("Tell us below how you feel about %(brand)s so far.", { brand })}</p>
|
<p>{ _t("Tell us below how you feel about %(brand)s so far.", { brand }) }</p>
|
||||||
<p>{_t("Please go into as much detail as you like, so we can track down the problem.")}</p>
|
<p>{ _t("Please go into as much detail as you like, so we can track down the problem.") }</p>
|
||||||
|
|
||||||
<StyledRadioGroup
|
<StyledRadioGroup
|
||||||
name="feedbackRating"
|
name="feedbackRating"
|
||||||
|
@ -95,7 +95,7 @@ export default (props) => {
|
||||||
let subheading;
|
let subheading;
|
||||||
if (hasFeedback) {
|
if (hasFeedback) {
|
||||||
subheading = (
|
subheading = (
|
||||||
<h2>{_t("There are two ways you can provide feedback and help us improve %(brand)s.", { brand })}</h2>
|
<h2>{ _t("There are two ways you can provide feedback and help us improve %(brand)s.", { brand }) }</h2>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ export default (props) => {
|
||||||
_t("PRO TIP: If you start a bug, please submit <debugLogsLink>debug logs</debugLogsLink> " +
|
_t("PRO TIP: If you start a bug, please submit <debugLogsLink>debug logs</debugLogsLink> " +
|
||||||
"to help us track down the problem.", {}, {
|
"to help us track down the problem.", {}, {
|
||||||
debugLogsLink: sub => (
|
debugLogsLink: sub => (
|
||||||
<AccessibleButton kind="link" onClick={onDebugLogsLinkClick}>{sub}</AccessibleButton>
|
<AccessibleButton kind="link" onClick={onDebugLogsLinkClick}>{ sub }</AccessibleButton>
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
}</p>
|
}</p>
|
||||||
|
@ -121,7 +121,7 @@ export default (props) => {
|
||||||
{ subheading }
|
{ subheading }
|
||||||
|
|
||||||
<div className="mx_FeedbackDialog_section mx_FeedbackDialog_reportBug">
|
<div className="mx_FeedbackDialog_section mx_FeedbackDialog_reportBug">
|
||||||
<h3>{_t("Report a bug")}</h3>
|
<h3>{ _t("Report a bug") }</h3>
|
||||||
<p>{
|
<p>{
|
||||||
_t("Please view <existingIssuesLink>existing bugs on Github</existingIssuesLink> first. " +
|
_t("Please view <existingIssuesLink>existing bugs on Github</existingIssuesLink> first. " +
|
||||||
"No match? <newIssueLink>Start a new one</newIssueLink>.", {}, {
|
"No match? <newIssueLink>Start a new one</newIssueLink>.", {}, {
|
||||||
|
@ -133,7 +133,7 @@ export default (props) => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}</p>
|
}</p>
|
||||||
{bugReports}
|
{ bugReports }
|
||||||
</div>
|
</div>
|
||||||
{ countlyFeedbackSection }
|
{ countlyFeedbackSection }
|
||||||
</React.Fragment>}
|
</React.Fragment>}
|
||||||
|
|
|
@ -177,32 +177,32 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
||||||
const textComponent = (
|
const textComponent = (
|
||||||
<>
|
<>
|
||||||
<p>
|
<p>
|
||||||
{_t("Continuing temporarily allows the %(hostSignupBrand)s setup process to access your " +
|
{ _t("Continuing temporarily allows the %(hostSignupBrand)s setup process to access your " +
|
||||||
"account to fetch verified email addresses. This data is not stored.", {
|
"account to fetch verified email addresses. This data is not stored.", {
|
||||||
hostSignupBrand: this.config.brand,
|
hostSignupBrand: this.config.brand,
|
||||||
})}
|
}) }
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{_t("Learn more in our <privacyPolicyLink />, <termsOfServiceLink /> and <cookiePolicyLink />.",
|
{ _t("Learn more in our <privacyPolicyLink />, <termsOfServiceLink /> and <cookiePolicyLink />.",
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
cookiePolicyLink: () => (
|
cookiePolicyLink: () => (
|
||||||
<a href={this.config.cookiePolicyUrl} target="_blank" rel="noreferrer noopener">
|
<a href={this.config.cookiePolicyUrl} target="_blank" rel="noreferrer noopener">
|
||||||
{_t("Cookie Policy")}
|
{ _t("Cookie Policy") }
|
||||||
</a>
|
</a>
|
||||||
),
|
),
|
||||||
privacyPolicyLink: () => (
|
privacyPolicyLink: () => (
|
||||||
<a href={this.config.privacyPolicyUrl} target="_blank" rel="noreferrer noopener">
|
<a href={this.config.privacyPolicyUrl} target="_blank" rel="noreferrer noopener">
|
||||||
{_t("Privacy Policy")}
|
{ _t("Privacy Policy") }
|
||||||
</a>
|
</a>
|
||||||
),
|
),
|
||||||
termsOfServiceLink: () => (
|
termsOfServiceLink: () => (
|
||||||
<a href={this.config.termsOfServiceUrl} target="_blank" rel="noreferrer noopener">
|
<a href={this.config.termsOfServiceUrl} target="_blank" rel="noreferrer noopener">
|
||||||
{_t("Terms of Service")}
|
{ _t("Terms of Service") }
|
||||||
</a>
|
</a>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
)}
|
) }
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -241,12 +241,12 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{this.state.minimized &&
|
{ this.state.minimized &&
|
||||||
<div className="mx_Dialog_header mx_Dialog_headerWithButton">
|
<div className="mx_Dialog_header mx_Dialog_headerWithButton">
|
||||||
<div className="mx_Dialog_title">
|
<div className="mx_Dialog_title">
|
||||||
{_t("%(hostSignupBrand)s Setup", {
|
{ _t("%(hostSignupBrand)s Setup", {
|
||||||
hostSignupBrand: this.config.brand,
|
hostSignupBrand: this.config.brand,
|
||||||
})}
|
}) }
|
||||||
</div>
|
</div>
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
className="mx_HostSignup_maximize_button"
|
className="mx_HostSignup_maximize_button"
|
||||||
|
@ -256,7 +256,7 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{!this.state.minimized &&
|
{ !this.state.minimized &&
|
||||||
<div className="mx_Dialog_header mx_Dialog_headerWithCancel">
|
<div className="mx_Dialog_header mx_Dialog_headerWithCancel">
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
onClick={this.minimizeDialog}
|
onClick={this.minimizeDialog}
|
||||||
|
@ -272,12 +272,12 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{this.state.error &&
|
{ this.state.error &&
|
||||||
<div>
|
<div>
|
||||||
{this.state.error}
|
{ this.state.error }
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{!this.state.error &&
|
{ !this.state.error &&
|
||||||
<iframe
|
<iframe
|
||||||
src={this.config.url}
|
src={this.config.url}
|
||||||
ref={this.iframeRef}
|
ref={this.iframeRef}
|
||||||
|
|
|
@ -138,7 +138,7 @@ export default class IncomingSasDialog extends React.Component {
|
||||||
url={url}
|
url={url}
|
||||||
width={48} height={48} resizeMethod='crop'
|
width={48} height={48} resizeMethod='crop'
|
||||||
/>
|
/>
|
||||||
<h2>{oppProfile.displayname}</h2>
|
<h2>{ oppProfile.displayname }</h2>
|
||||||
</div>;
|
</div>;
|
||||||
} else if (this.state.opponentProfileError) {
|
} else if (this.state.opponentProfileError) {
|
||||||
profile = <div>
|
profile = <div>
|
||||||
|
@ -146,42 +146,42 @@ export default class IncomingSasDialog extends React.Component {
|
||||||
idName={this.props.verifier.userId}
|
idName={this.props.verifier.userId}
|
||||||
width={48} height={48}
|
width={48} height={48}
|
||||||
/>
|
/>
|
||||||
<h2>{this.props.verifier.userId}</h2>
|
<h2>{ this.props.verifier.userId }</h2>
|
||||||
</div>;
|
</div>;
|
||||||
} else {
|
} else {
|
||||||
profile = <Spinner />;
|
profile = <Spinner />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const userDetailText = [
|
const userDetailText = [
|
||||||
<p key="p1">{_t(
|
<p key="p1">{ _t(
|
||||||
"Verify this user to mark them as trusted. " +
|
"Verify this user to mark them as trusted. " +
|
||||||
"Trusting users gives you extra peace of mind when using " +
|
"Trusting users gives you extra peace of mind when using " +
|
||||||
"end-to-end encrypted messages.",
|
"end-to-end encrypted messages.",
|
||||||
)}</p>,
|
) }</p>,
|
||||||
<p key="p2">{_t(
|
<p key="p2">{ _t(
|
||||||
// NB. Below wording adjusted to singular 'session' until we have
|
// NB. Below wording adjusted to singular 'session' until we have
|
||||||
// cross-signing
|
// cross-signing
|
||||||
"Verifying this user will mark their session as trusted, and " +
|
"Verifying this user will mark their session as trusted, and " +
|
||||||
"also mark your session as trusted to them.",
|
"also mark your session as trusted to them.",
|
||||||
)}</p>,
|
) }</p>,
|
||||||
];
|
];
|
||||||
|
|
||||||
const selfDetailText = [
|
const selfDetailText = [
|
||||||
<p key="p1">{_t(
|
<p key="p1">{ _t(
|
||||||
"Verify this device to mark it as trusted. " +
|
"Verify this device to mark it as trusted. " +
|
||||||
"Trusting this device gives you and other users extra peace of mind when using " +
|
"Trusting this device gives you and other users extra peace of mind when using " +
|
||||||
"end-to-end encrypted messages.",
|
"end-to-end encrypted messages.",
|
||||||
)}</p>,
|
) }</p>,
|
||||||
<p key="p2">{_t(
|
<p key="p2">{ _t(
|
||||||
"Verifying this device will mark it as trusted, and users who have verified with " +
|
"Verifying this device will mark it as trusted, and users who have verified with " +
|
||||||
"you will trust this device.",
|
"you will trust this device.",
|
||||||
)}</p>,
|
) }</p>,
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{profile}
|
{ profile }
|
||||||
{isSelf ? selfDetailText : userDetailText}
|
{ isSelf ? selfDetailText : userDetailText }
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t('Continue')}
|
primaryButton={_t('Continue')}
|
||||||
hasCancel={true}
|
hasCancel={true}
|
||||||
|
@ -209,7 +209,7 @@ export default class IncomingSasDialog extends React.Component {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Spinner />
|
<Spinner />
|
||||||
<p>{_t("Waiting for partner to confirm...")}</p>
|
<p>{ _t("Waiting for partner to confirm...") }</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -251,7 +251,7 @@ export default class IncomingSasDialog extends React.Component {
|
||||||
onFinished={this._onFinished}
|
onFinished={this._onFinished}
|
||||||
fixedWidth={false}
|
fixedWidth={false}
|
||||||
>
|
>
|
||||||
{body}
|
{ body }
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ export default class IntegrationsDisabledDialog extends React.Component {
|
||||||
title={_t("Integrations are disabled")}
|
title={_t("Integrations are disabled")}
|
||||||
>
|
>
|
||||||
<div className='mx_IntegrationsDisabledDialog_content'>
|
<div className='mx_IntegrationsDisabledDialog_content'>
|
||||||
<p>{_t("Enable 'Manage Integrations' in Settings to do this.")}</p>
|
<p>{ _t("Enable 'Manage Integrations' in Settings to do this.") }</p>
|
||||||
</div>
|
</div>
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("Settings")}
|
primaryButton={_t("Settings")}
|
||||||
|
|
|
@ -45,11 +45,11 @@ export default class IntegrationsImpossibleDialog extends React.Component {
|
||||||
>
|
>
|
||||||
<div className='mx_IntegrationsImpossibleDialog_content'>
|
<div className='mx_IntegrationsImpossibleDialog_content'>
|
||||||
<p>
|
<p>
|
||||||
{_t(
|
{ _t(
|
||||||
"Your %(brand)s doesn't allow you to use an integration manager to do this. " +
|
"Your %(brand)s doesn't allow you to use an integration manager to do this. " +
|
||||||
"Please contact an admin.",
|
"Please contact an admin.",
|
||||||
{ brand },
|
{ brand },
|
||||||
)}
|
) }
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
|
|
|
@ -163,7 +163,7 @@ export default class InteractiveAuthDialog extends React.Component {
|
||||||
} else {
|
} else {
|
||||||
content = (
|
content = (
|
||||||
<div id='mx_Dialog_content'>
|
<div id='mx_Dialog_content'>
|
||||||
{body}
|
{ body }
|
||||||
<InteractiveAuth
|
<InteractiveAuth
|
||||||
ref={this._collectInteractiveAuth}
|
ref={this._collectInteractiveAuth}
|
||||||
matrixClient={this.props.matrixClient}
|
matrixClient={this.props.matrixClient}
|
||||||
|
|
|
@ -224,8 +224,8 @@ class DMUserTile extends React.PureComponent<IDMUserTileProps> {
|
||||||
return (
|
return (
|
||||||
<span className='mx_InviteDialog_userTile'>
|
<span className='mx_InviteDialog_userTile'>
|
||||||
<span className='mx_InviteDialog_userTile_pill'>
|
<span className='mx_InviteDialog_userTile_pill'>
|
||||||
{avatar}
|
{ avatar }
|
||||||
<span className='mx_InviteDialog_userTile_name'>{this.props.member.name}</span>
|
<span className='mx_InviteDialog_userTile_name'>{ this.props.member.name }</span>
|
||||||
</span>
|
</span>
|
||||||
{ closeButton }
|
{ closeButton }
|
||||||
</span>
|
</span>
|
||||||
|
@ -267,20 +267,20 @@ class DMRoomTile extends React.PureComponent<IDMRoomTileProps> {
|
||||||
// Push any text we missed (first bit/middle of text)
|
// Push any text we missed (first bit/middle of text)
|
||||||
if (ii > i) {
|
if (ii > i) {
|
||||||
// Push any text we aren't highlighting (middle of text match, or beginning of text)
|
// Push any text we aren't highlighting (middle of text match, or beginning of text)
|
||||||
result.push(<span key={i + 'begin'}>{str.substring(i, ii)}</span>);
|
result.push(<span key={i + 'begin'}>{ str.substring(i, ii) }</span>);
|
||||||
}
|
}
|
||||||
|
|
||||||
i = ii; // copy over ii only if we have a match (to preserve i for end-of-text matching)
|
i = ii; // copy over ii only if we have a match (to preserve i for end-of-text matching)
|
||||||
|
|
||||||
// Highlight the word the user entered
|
// Highlight the word the user entered
|
||||||
const substr = str.substring(i, filterStr.length + i);
|
const substr = str.substring(i, filterStr.length + i);
|
||||||
result.push(<span className='mx_InviteDialog_roomTile_highlight' key={i + 'bold'}>{substr}</span>);
|
result.push(<span className='mx_InviteDialog_roomTile_highlight' key={i + 'bold'}>{ substr }</span>);
|
||||||
i += substr.length;
|
i += substr.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push any text we missed (end of text)
|
// Push any text we missed (end of text)
|
||||||
if (i < str.length) {
|
if (i < str.length) {
|
||||||
result.push(<span key={i + 'end'}>{str.substring(i)}</span>);
|
result.push(<span key={i + 'end'}>{ str.substring(i) }</span>);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -290,7 +290,7 @@ class DMRoomTile extends React.PureComponent<IDMRoomTileProps> {
|
||||||
let timestamp = null;
|
let timestamp = null;
|
||||||
if (this.props.lastActiveTs) {
|
if (this.props.lastActiveTs) {
|
||||||
const humanTs = humanizeTime(this.props.lastActiveTs);
|
const humanTs = humanizeTime(this.props.lastActiveTs);
|
||||||
timestamp = <span className='mx_InviteDialog_roomTile_time'>{humanTs}</span>;
|
timestamp = <span className='mx_InviteDialog_roomTile_time'>{ humanTs }</span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const avatarSize = 36;
|
const avatarSize = 36;
|
||||||
|
@ -317,8 +317,8 @@ class DMRoomTile extends React.PureComponent<IDMRoomTileProps> {
|
||||||
// the browser from reloading the image source when the avatar remounts).
|
// the browser from reloading the image source when the avatar remounts).
|
||||||
const stackedAvatar = (
|
const stackedAvatar = (
|
||||||
<span className='mx_InviteDialog_roomTile_avatarStack'>
|
<span className='mx_InviteDialog_roomTile_avatarStack'>
|
||||||
{avatar}
|
{ avatar }
|
||||||
{checkmark}
|
{ checkmark }
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -328,12 +328,12 @@ class DMRoomTile extends React.PureComponent<IDMRoomTileProps> {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='mx_InviteDialog_roomTile' onClick={this.onClick}>
|
<div className='mx_InviteDialog_roomTile' onClick={this.onClick}>
|
||||||
{stackedAvatar}
|
{ stackedAvatar }
|
||||||
<span className="mx_InviteDialog_roomTile_nameStack">
|
<span className="mx_InviteDialog_roomTile_nameStack">
|
||||||
<div className='mx_InviteDialog_roomTile_name'>{this.highlightName(this.props.member.name)}</div>
|
<div className='mx_InviteDialog_roomTile_name'>{ this.highlightName(this.props.member.name) }</div>
|
||||||
<div className='mx_InviteDialog_roomTile_userId'>{caption}</div>
|
<div className='mx_InviteDialog_roomTile_userId'>{ caption }</div>
|
||||||
</span>
|
</span>
|
||||||
{timestamp}
|
{ timestamp }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1152,8 +1152,8 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
if (sourceMembers.length === 0 && !hasAdditionalMembers) {
|
if (sourceMembers.length === 0 && !hasAdditionalMembers) {
|
||||||
return (
|
return (
|
||||||
<div className='mx_InviteDialog_section'>
|
<div className='mx_InviteDialog_section'>
|
||||||
<h3>{sectionName}</h3>
|
<h3>{ sectionName }</h3>
|
||||||
<p>{_t("No results")}</p>
|
<p>{ _t("No results") }</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1175,7 +1175,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
if (hasMore) {
|
if (hasMore) {
|
||||||
showMore = (
|
showMore = (
|
||||||
<AccessibleButton onClick={showMoreFn} kind="link">
|
<AccessibleButton onClick={showMoreFn} kind="link">
|
||||||
{_t("Show more")}
|
{ _t("Show more") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1192,10 +1192,10 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
));
|
));
|
||||||
return (
|
return (
|
||||||
<div className='mx_InviteDialog_section'>
|
<div className='mx_InviteDialog_section'>
|
||||||
<h3>{sectionName}</h3>
|
<h3>{ sectionName }</h3>
|
||||||
{sectionSubname ? <p className="mx_InviteDialog_subname">{sectionSubname}</p> : null}
|
{ sectionSubname ? <p className="mx_InviteDialog_subname">{ sectionSubname }</p> : null }
|
||||||
{tiles}
|
{ tiles }
|
||||||
{showMore}
|
{ showMore }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1225,8 +1225,8 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<div className='mx_InviteDialog_editor' onClick={this.onClickInputArea}>
|
<div className='mx_InviteDialog_editor' onClick={this.onClickInputArea}>
|
||||||
{targets}
|
{ targets }
|
||||||
{input}
|
{ input }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1241,7 +1241,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
const defaultIdentityServerUrl = getDefaultIdentityServerUrl();
|
const defaultIdentityServerUrl = getDefaultIdentityServerUrl();
|
||||||
if (defaultIdentityServerUrl) {
|
if (defaultIdentityServerUrl) {
|
||||||
return (
|
return (
|
||||||
<div className="mx_AddressPickerDialog_identityServer">{_t(
|
<div className="mx_AddressPickerDialog_identityServer">{ _t(
|
||||||
"Use an identity server to invite by email. " +
|
"Use an identity server to invite by email. " +
|
||||||
"<default>Use the default (%(defaultIdentityServerName)s)</default> " +
|
"<default>Use the default (%(defaultIdentityServerName)s)</default> " +
|
||||||
"or manage in <settings>Settings</settings>.",
|
"or manage in <settings>Settings</settings>.",
|
||||||
|
@ -1249,20 +1249,20 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
defaultIdentityServerName: abbreviateUrl(defaultIdentityServerUrl),
|
defaultIdentityServerName: abbreviateUrl(defaultIdentityServerUrl),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
default: sub => <a href="#" onClick={this.onUseDefaultIdentityServerClick}>{sub}</a>,
|
default: sub => <a href="#" onClick={this.onUseDefaultIdentityServerClick}>{ sub }</a>,
|
||||||
settings: sub => <a href="#" onClick={this.onManageSettingsClick}>{sub}</a>,
|
settings: sub => <a href="#" onClick={this.onManageSettingsClick}>{ sub }</a>,
|
||||||
},
|
},
|
||||||
)}</div>
|
) }</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<div className="mx_AddressPickerDialog_identityServer">{_t(
|
<div className="mx_AddressPickerDialog_identityServer">{ _t(
|
||||||
"Use an identity server to invite by email. " +
|
"Use an identity server to invite by email. " +
|
||||||
"Manage in <settings>Settings</settings>.",
|
"Manage in <settings>Settings</settings>.",
|
||||||
{}, {
|
{}, {
|
||||||
settings: sub => <a href="#" onClick={this.onManageSettingsClick}>{sub}</a>,
|
settings: sub => <a href="#" onClick={this.onManageSettingsClick}>{ sub }</a>,
|
||||||
},
|
},
|
||||||
)}</div>
|
) }</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1339,7 +1339,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
{},
|
{},
|
||||||
{ userId: () => {
|
{ userId: () => {
|
||||||
return (
|
return (
|
||||||
<a href={makeUserPermalink(userId)} rel="noreferrer noopener" target="_blank">{userId}</a>
|
<a href={makeUserPermalink(userId)} rel="noreferrer noopener" target="_blank">{ userId }</a>
|
||||||
);
|
);
|
||||||
} },
|
} },
|
||||||
);
|
);
|
||||||
|
@ -1349,7 +1349,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
{},
|
{},
|
||||||
{ userId: () => {
|
{ userId: () => {
|
||||||
return (
|
return (
|
||||||
<a href={makeUserPermalink(userId)} rel="noreferrer noopener" target="_blank">{userId}</a>
|
<a href={makeUserPermalink(userId)} rel="noreferrer noopener" target="_blank">{ userId }</a>
|
||||||
);
|
);
|
||||||
} },
|
} },
|
||||||
);
|
);
|
||||||
|
@ -1367,7 +1367,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
href={makeUserPermalink(userId)}
|
href={makeUserPermalink(userId)}
|
||||||
rel="noreferrer noopener"
|
rel="noreferrer noopener"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>{userId}</a>
|
>{ userId }</a>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
a: (sub) => {
|
a: (sub) => {
|
||||||
|
@ -1375,13 +1375,13 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
kind="link"
|
kind="link"
|
||||||
onClick={this.onCommunityInviteClick}
|
onClick={this.onCommunityInviteClick}
|
||||||
>{sub}</AccessibleButton>
|
>{ sub }</AccessibleButton>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
helpText = <React.Fragment>
|
helpText = <React.Fragment>
|
||||||
{ helpText } {inviteText}
|
{ helpText } { inviteText }
|
||||||
</React.Fragment>;
|
</React.Fragment>;
|
||||||
}
|
}
|
||||||
buttonText = _t("Go");
|
buttonText = _t("Go");
|
||||||
|
@ -1438,9 +1438,9 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
|
|
||||||
helpText = _t(helpTextUntranslated, {}, {
|
helpText = _t(helpTextUntranslated, {}, {
|
||||||
userId: () =>
|
userId: () =>
|
||||||
<a href={makeUserPermalink(userId)} rel="noreferrer noopener" target="_blank">{userId}</a>,
|
<a href={makeUserPermalink(userId)} rel="noreferrer noopener" target="_blank">{ userId }</a>,
|
||||||
a: (sub) =>
|
a: (sub) =>
|
||||||
<a href={makeRoomPermalink(this.props.roomId)} rel="noreferrer noopener" target="_blank">{sub}</a>,
|
<a href={makeRoomPermalink(this.props.roomId)} rel="noreferrer noopener" target="_blank">{ sub }</a>,
|
||||||
});
|
});
|
||||||
|
|
||||||
buttonText = _t("Invite");
|
buttonText = _t("Invite");
|
||||||
|
@ -1459,7 +1459,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
<img
|
<img
|
||||||
src={require("../../../../res/img/element-icons/info.svg")}
|
src={require("../../../../res/img/element-icons/info.svg")}
|
||||||
width={14} height={14} />
|
width={14} height={14} />
|
||||||
{" " + _t("Invited people will be able to read old messages.")}
|
{ " " + _t("Invited people will be able to read old messages.") }
|
||||||
</p>;
|
</p>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1469,14 +1469,14 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
consultConnectSection = <div className="mx_InviteDialog_transferConsultConnect">
|
consultConnectSection = <div className="mx_InviteDialog_transferConsultConnect">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" checked={this.state.consultFirst} onChange={this.onConsultFirstChange} />
|
<input type="checkbox" checked={this.state.consultFirst} onChange={this.onConsultFirstChange} />
|
||||||
{_t("Consult first")}
|
{ _t("Consult first") }
|
||||||
</label>
|
</label>
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
kind="secondary"
|
kind="secondary"
|
||||||
onClick={this.onCancel}
|
onClick={this.onCancel}
|
||||||
className='mx_InviteDialog_transferConsultConnect_pushRight'
|
className='mx_InviteDialog_transferConsultConnect_pushRight'
|
||||||
>
|
>
|
||||||
{_t("Cancel")}
|
{ _t("Cancel") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
kind="primary"
|
kind="primary"
|
||||||
|
@ -1484,7 +1484,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
className='mx_InviteDialog_transferButton'
|
className='mx_InviteDialog_transferButton'
|
||||||
disabled={!hasSelection && this.state.dialPadValue === ''}
|
disabled={!hasSelection && this.state.dialPadValue === ''}
|
||||||
>
|
>
|
||||||
{_t("Transfer")}
|
{ _t("Transfer") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>;
|
</div>;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1497,27 +1497,27 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
className='mx_InviteDialog_goButton'
|
className='mx_InviteDialog_goButton'
|
||||||
disabled={this.state.busy || !hasSelection}
|
disabled={this.state.busy || !hasSelection}
|
||||||
>
|
>
|
||||||
{buttonText}
|
{ buttonText }
|
||||||
</AccessibleButton>;
|
</AccessibleButton>;
|
||||||
|
|
||||||
const usersSection = <React.Fragment>
|
const usersSection = <React.Fragment>
|
||||||
<p className='mx_InviteDialog_helpText'>{helpText}</p>
|
<p className='mx_InviteDialog_helpText'>{ helpText }</p>
|
||||||
<div className='mx_InviteDialog_addressBar'>
|
<div className='mx_InviteDialog_addressBar'>
|
||||||
{this.renderEditor()}
|
{ this.renderEditor() }
|
||||||
<div className='mx_InviteDialog_buttonAndSpinner'>
|
<div className='mx_InviteDialog_buttonAndSpinner'>
|
||||||
{goButton}
|
{ goButton }
|
||||||
{spinner}
|
{ spinner }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{keySharingWarning}
|
{ keySharingWarning }
|
||||||
{this.renderIdentityServerWarning()}
|
{ this.renderIdentityServerWarning() }
|
||||||
<div className='error'>{this.state.errorText}</div>
|
<div className='error'>{ this.state.errorText }</div>
|
||||||
<div className='mx_InviteDialog_userSections'>
|
<div className='mx_InviteDialog_userSections'>
|
||||||
{this.renderSection('recents')}
|
{ this.renderSection('recents') }
|
||||||
{this.renderSection('suggestions')}
|
{ this.renderSection('suggestions') }
|
||||||
{extraSection}
|
{ extraSection }
|
||||||
</div>
|
</div>
|
||||||
{footer}
|
{ footer }
|
||||||
</React.Fragment>;
|
</React.Fragment>;
|
||||||
|
|
||||||
let dialogContent;
|
let dialogContent;
|
||||||
|
@ -1550,7 +1550,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
|
|
||||||
const dialPadSection = <div className="mx_InviteDialog_dialPad">
|
const dialPadSection = <div className="mx_InviteDialog_dialPad">
|
||||||
<form onSubmit={this.onDialFormSubmit}>
|
<form onSubmit={this.onDialFormSubmit}>
|
||||||
{dialPadField}
|
{ dialPadField }
|
||||||
</form>
|
</form>
|
||||||
<Dialpad hasDial={false}
|
<Dialpad hasDial={false}
|
||||||
onDigitPress={this.onDigitPress} onDeletePress={this.onDeletePress}
|
onDigitPress={this.onDigitPress} onDeletePress={this.onDeletePress}
|
||||||
|
@ -1561,12 +1561,12 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
<TabbedView tabs={tabs} initialTabId={this.state.currentTabId}
|
<TabbedView tabs={tabs} initialTabId={this.state.currentTabId}
|
||||||
tabLocation={TabLocation.TOP} onChange={this.onTabChange}
|
tabLocation={TabLocation.TOP} onChange={this.onTabChange}
|
||||||
/>
|
/>
|
||||||
{consultConnectSection}
|
{ consultConnectSection }
|
||||||
</React.Fragment>;
|
</React.Fragment>;
|
||||||
} else {
|
} else {
|
||||||
dialogContent = <React.Fragment>
|
dialogContent = <React.Fragment>
|
||||||
{usersSection}
|
{ usersSection }
|
||||||
{consultConnectSection}
|
{ consultConnectSection }
|
||||||
</React.Fragment>;
|
</React.Fragment>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1582,7 +1582,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
title={title}
|
title={title}
|
||||||
>
|
>
|
||||||
<div className='mx_InviteDialog_content'>
|
<div className='mx_InviteDialog_content'>
|
||||||
{dialogContent}
|
{ dialogContent }
|
||||||
</div>
|
</div>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
);
|
);
|
||||||
|
|
|
@ -69,10 +69,10 @@ export default function KeySignatureUploadFailedDialog({
|
||||||
const brand = SdkConfig.get().brand;
|
const brand = SdkConfig.get().brand;
|
||||||
|
|
||||||
body = (<div>
|
body = (<div>
|
||||||
<p>{_t("%(brand)s encountered an error during upload of:", { brand })}</p>
|
<p>{ _t("%(brand)s encountered an error during upload of:", { brand }) }</p>
|
||||||
<p>{reason}</p>
|
<p>{ reason }</p>
|
||||||
{retrying && <Spinner />}
|
{ retrying && <Spinner /> }
|
||||||
<pre>{JSON.stringify(failures, null, 2)}</pre>
|
<pre>{ JSON.stringify(failures, null, 2) }</pre>
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton='Retry'
|
primaryButton='Retry'
|
||||||
hasCancel={true}
|
hasCancel={true}
|
||||||
|
@ -83,11 +83,11 @@ export default function KeySignatureUploadFailedDialog({
|
||||||
</div>);
|
</div>);
|
||||||
} else {
|
} else {
|
||||||
body = (<div>
|
body = (<div>
|
||||||
{success ?
|
{ success ?
|
||||||
<span>{_t("Upload completed")}</span> :
|
<span>{ _t("Upload completed") }</span> :
|
||||||
cancelled ?
|
cancelled ?
|
||||||
<span>{_t("Cancelled signature upload")}</span> :
|
<span>{ _t("Cancelled signature upload") }</span> :
|
||||||
<span>{_t("Unable to upload")}</span>}
|
<span>{ _t("Unable to upload") }</span> }
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("OK")}
|
primaryButton={_t("OK")}
|
||||||
hasCancel={false}
|
hasCancel={false}
|
||||||
|
@ -104,7 +104,7 @@ export default function KeySignatureUploadFailedDialog({
|
||||||
fixedWidth={false}
|
fixedWidth={false}
|
||||||
onFinished={() => {}}
|
onFinished={() => {}}
|
||||||
>
|
>
|
||||||
{body}
|
{ body }
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ export default (props) => {
|
||||||
return (<QuestionDialog
|
return (<QuestionDialog
|
||||||
hasCancelButton={false}
|
hasCancelButton={false}
|
||||||
title={_t("Incompatible local cache")}
|
title={_t("Incompatible local cache")}
|
||||||
description={<div><p>{description1}</p><p>{description2}</p></div>}
|
description={<div><p>{ description1 }</p><p>{ description2 }</p></div>}
|
||||||
button={_t("Clear cache and resync")}
|
button={_t("Clear cache and resync")}
|
||||||
onFinished={props.onFinished}
|
onFinished={props.onFinished}
|
||||||
/>);
|
/>);
|
||||||
|
|
|
@ -33,7 +33,7 @@ export default (props) => {
|
||||||
return (<QuestionDialog
|
return (<QuestionDialog
|
||||||
hasCancelButton={false}
|
hasCancelButton={false}
|
||||||
title={_t("Updating %(brand)s", { brand })}
|
title={_t("Updating %(brand)s", { brand })}
|
||||||
description={<div>{description}</div>}
|
description={<div>{ description }</div>}
|
||||||
button={_t("OK")}
|
button={_t("OK")}
|
||||||
onFinished={props.onFinished}
|
onFinished={props.onFinished}
|
||||||
/>);
|
/>);
|
||||||
|
|
|
@ -123,11 +123,11 @@ export default class LogoutDialog extends React.Component {
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||||
|
|
||||||
const description = <div>
|
const description = <div>
|
||||||
<p>{_t(
|
<p>{ _t(
|
||||||
"Encrypted messages are secured with end-to-end encryption. " +
|
"Encrypted messages are secured with end-to-end encryption. " +
|
||||||
"Only you and the recipient(s) have the keys to read these messages.",
|
"Only you and the recipient(s) have the keys to read these messages.",
|
||||||
)}</p>
|
) }</p>
|
||||||
<p>{_t("Back up your keys before signing out to avoid losing them.")}</p>
|
<p>{ _t("Back up your keys before signing out to avoid losing them.") }</p>
|
||||||
</div>;
|
</div>;
|
||||||
|
|
||||||
let dialogContent;
|
let dialogContent;
|
||||||
|
@ -156,13 +156,13 @@ export default class LogoutDialog extends React.Component {
|
||||||
focus={true}
|
focus={true}
|
||||||
>
|
>
|
||||||
<button onClick={this._onLogoutConfirm}>
|
<button onClick={this._onLogoutConfirm}>
|
||||||
{_t("I don't want my encrypted messages")}
|
{ _t("I don't want my encrypted messages") }
|
||||||
</button>
|
</button>
|
||||||
</DialogButtons>
|
</DialogButtons>
|
||||||
<details>
|
<details>
|
||||||
<summary>{_t("Advanced")}</summary>
|
<summary>{ _t("Advanced") }</summary>
|
||||||
<p><button onClick={this._onExportE2eKeysClicked}>
|
<p><button onClick={this._onExportE2eKeysClicked}>
|
||||||
{_t("Manually export keys")}
|
{ _t("Manually export keys") }
|
||||||
</button></p>
|
</button></p>
|
||||||
</details>
|
</details>
|
||||||
</div>;
|
</div>;
|
||||||
|
@ -176,7 +176,7 @@ export default class LogoutDialog extends React.Component {
|
||||||
hasCancel={true}
|
hasCancel={true}
|
||||||
onFinished={this._onFinished}
|
onFinished={this._onFinished}
|
||||||
>
|
>
|
||||||
{dialogContent}
|
{ dialogContent }
|
||||||
</BaseDialog>);
|
</BaseDialog>);
|
||||||
} else {
|
} else {
|
||||||
const QuestionDialog = sdk.getComponent('views.dialogs.QuestionDialog');
|
const QuestionDialog = sdk.getComponent('views.dialogs.QuestionDialog');
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue