From b2fc4a1c4de9251284c392c3d1efe3ae06fd222c Mon Sep 17 00:00:00 2001
From: Half-Shot
Date: Tue, 21 Jan 2020 18:41:43 +0000
Subject: [PATCH 01/19] Style bridge settings tab according to design
Signed-off-by: Half-Shot
---
.../views/dialogs/_RoomSettingsDialog.scss | 58 ++++++-
.../views/dialogs/RoomSettingsDialog.js | 7 +-
.../settings/tabs/room/BridgeSettingsTab.js | 156 ++++++++++--------
src/i18n/strings/en_EN.json | 11 +-
4 files changed, 144 insertions(+), 88 deletions(-)
diff --git a/res/css/views/dialogs/_RoomSettingsDialog.scss b/res/css/views/dialogs/_RoomSettingsDialog.scss
index aa66e97f9e..0e8deb018e 100644
--- a/res/css/views/dialogs/_RoomSettingsDialog.scss
+++ b/res/css/views/dialogs/_RoomSettingsDialog.scss
@@ -63,9 +63,59 @@ limitations under the License.
.mx_RoomSettingsDialog_BridgeList li {
list-style-type: none;
padding: 5px;
- margin-bottom: 5px;
- border-width: 1px 0px;
- border-color: #dee1f3;
- border-style: solid;
+ margin-bottom: 8px;
+ border-width: 1px 1px;
+ border-color: $primary-hairline-color;
+ border-radius: 5px;
+
+ .protocol-icon {
+ float: left;
+ margin-right: 30px;
+ img {
+ border-radius: 5px;
+ border-width: 1px 1px;
+ border-color: $primary-hairline-color;
+ border-style: solid;
+ }
+ span {
+ /* Correct letter placement */
+ left: auto;
+ }
+ }
+
+ h3 {
+ margin-top: 0;
+ margin-bottom: 4px;
+ font-size: 16pt;
+ }
+
+ .column-icon {
+ float: left;
+ }
+
+ .column-data {
+ display: inline-block;
+ width: 85%;
+ }
+
+ .workspace-channel-details {
+ margin-top: 0;
+ color: $primary-fg-color;
+ }
+
+ .metadata {
+ color: $muted-fg-color;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ margin-bottom: 0;
+ }
+
+ .metadata.visible {
+ overflow-y: visible;
+ text-overflow: ellipsis;
+ white-space: normal;
+ }
+
}
diff --git a/src/components/views/dialogs/RoomSettingsDialog.js b/src/components/views/dialogs/RoomSettingsDialog.js
index a99141870b..76faf60eef 100644
--- a/src/components/views/dialogs/RoomSettingsDialog.js
+++ b/src/components/views/dialogs/RoomSettingsDialog.js
@@ -54,9 +54,6 @@ export default class RoomSettingsDialog extends React.Component {
_getTabs() {
const tabs = [];
- const featureFlag = SettingsStore.isFeatureEnabled("feature_bridge_state");
- const shouldShowBridgeIcon = featureFlag &&
- BridgeSettingsTab.getBridgeStateEvents(this.props.roomId).length > 0;
tabs.push(new Tab(
_td("General"),
@@ -79,9 +76,9 @@ export default class RoomSettingsDialog extends React.Component {
,
));
- if (shouldShowBridgeIcon) {
+ if (SettingsStore.isFeatureEnabled("feature_bridge_state")) {
tabs.push(new Tab(
- _td("Bridge Info"),
+ _td("Bridges"),
"mx_RoomSettingsDialog_bridgesIcon",
,
));
diff --git a/src/components/views/settings/tabs/room/BridgeSettingsTab.js b/src/components/views/settings/tabs/room/BridgeSettingsTab.js
index 19c19d3bc6..8090cf7d4d 100644
--- a/src/components/views/settings/tabs/room/BridgeSettingsTab.js
+++ b/src/components/views/settings/tabs/room/BridgeSettingsTab.js
@@ -33,6 +33,21 @@ export default class BridgeSettingsTab extends React.Component {
roomId: PropTypes.string.isRequired,
};
+ constructor() {
+ super();
+
+ this.state = {
+ showMoreCard: null,
+ };
+ }
+
+
+ _showMoreDetails(eventId) {
+ this.setState({
+ showMoreCard: eventId,
+ });
+ }
+
_renderBridgeCard(event, room) {
const content = event.getContent();
if (!content || !content.channel || !content.protocol) {
@@ -45,90 +60,59 @@ export default class BridgeSettingsTab extends React.Component {
let creator = null;
if (content.creator) {
- creator = { _t("This bridge was provisioned by ", {}, {
+ creator = _t("This bridge was provisioned by .", {}, {
user: ,
- })}
;
+ });
}
- const bot = ( {_t("This bridge is managed by .", {}, {
+ const bot = _t("This bridge is managed by .", {}, {
user: ,
- })}
);
- let channelLink = channelName;
- if (channel.external_url) {
- channelLink = {channelName};
- }
-
- let networkLink = networkName;
- if (network && network.external_url) {
- networkLink = {networkName};
- }
-
- const chanAndNetworkInfo = (
- _t("Bridged into , on ", {}, {
- channelLink,
- networkLink,
- protocolName,
- })
- );
-
- let networkIcon = null;
- if (networkName && network.avatar) {
- const avatarUrl = getHttpUriForMxc(
- MatrixClientPeg.get().getHomeserverUrl(),
- network.avatar, 32, 32, "crop",
- );
- networkIcon = ;
- }
-
- let channelIcon = null;
- if (channel.avatar) {
- const avatarUrl = getHttpUriForMxc(
- MatrixClientPeg.get().getHomeserverUrl(),
- channel.avatar, 32, 32, "crop",
- );
- channelIcon = ;
- }
-
- const heading = _t("Connected to on ", { }, {
- channelIcon,
- channelName,
- networkName,
- networkIcon,
});
- return (
-
-
{heading}
-
{_t("Connected via %(protocolName)s", { protocolName })}
-
- {creator}
- {bot}
- {chanAndNetworkInfo}
-
+ const avatarUrl = network.avatar ? getHttpUriForMxc(
+ MatrixClientPeg.get().getHomeserverUrl(),
+ network.avatar, 32, 32, "crop",
+ ) : null;
+
+ const networkIcon =
;
+
+ const workspaceChannelDetails = _t("Workspace: %(networkName)s Channel: %(channelName)s", {
+ networkName,
+ channelName,
+ });
+ const id = event.getId();
+ const isVisible = this.state.showMoreCard === id;
+ const metadataClassname = "metadata " + (isVisible ? "visible" : "");
+ return (
+
+ {networkIcon}
+
+
);
}
@@ -151,14 +135,40 @@ export default class BridgeSettingsTab extends React.Component {
const client = MatrixClientPeg.get();
const room = client.getRoom(this.props.roomId);
+ let content = null;
+
+ if (bridgeEvents.length > 0) {
+ content =
+
{_t(
+ "This room is bridging messages to the following platforms. " +
+ "Learn more.", {},
+ {
+ // TODO: We don't have this link yet: this will prevent the translators
+ // having to re-translate the string when we do.
+ a: sub => '',
+ },
+ )}
+
+ { bridgeEvents.map((event) => this._renderBridgeCard(event, room)) }
+
+
+ } else {
+ content =
{_t(
+ "This room isn’t bridging messages to any platforms. " +
+ "Learn more.", {},
+ {
+ // TODO: We don't have this link yet: this will prevent the translators
+ // having to re-translate the string when we do.
+ a: sub => '',
+ },
+ )}
+ }
+
return (
-
{_t("Bridge Info")}
+
{_t("Bridges")}
-
{ _t("Below is a list of bridges connected to this room.") }
-
- { bridgeEvents.map((event) => this._renderBridgeCard(event, room)) }
-
+ {content}
);
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index f0eab6b12d..e4ab764989 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -781,13 +781,12 @@
"Room version:": "Room version:",
"Developer options": "Developer options",
"Open Devtools": "Open Devtools",
- "This bridge was provisioned by
": "This bridge was provisioned by
",
+ "This bridge was provisioned by
.": "This bridge was provisioned by
.",
"This bridge is managed by
.": "This bridge is managed by
.",
- "Bridged into
, on
": "Bridged into
, on
",
- "Connected to
on
": "Connected to
on
",
- "Connected via %(protocolName)s": "Connected via %(protocolName)s",
- "Bridge Info": "Bridge Info",
- "Below is a list of bridges connected to this room.": "Below is a list of bridges connected to this room.",
+ "Workspace: %(networkName)s Channel: %(channelName)s": "Workspace: %(networkName)s Channel: %(channelName)s",
+ "This room is bridging messages to the following platforms.
Learn more.": "This room is bridging messages to the following platforms.
Learn more.",
+ "This room isn’t bridging messages to any platforms.
Learn more.": "This room isn’t bridging messages to any platforms.
Learn more.",
+ "Bridges": "Bridges",
"Room Addresses": "Room Addresses",
"Publish this room to the public in %(domain)s's room directory?": "Publish this room to the public in %(domain)s's room directory?",
"URL Previews": "URL Previews",
From c9a0e93a74f437978eef3266f8b2b279558e9857 Mon Sep 17 00:00:00 2001
From: Half-Shot
Date: Mon, 27 Jan 2020 11:14:32 +0000
Subject: [PATCH 02/19] tidy up borders
---
res/css/views/dialogs/_RoomSettingsDialog.scss | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/res/css/views/dialogs/_RoomSettingsDialog.scss b/res/css/views/dialogs/_RoomSettingsDialog.scss
index 0e8deb018e..66c34fd73d 100644
--- a/res/css/views/dialogs/_RoomSettingsDialog.scss
+++ b/res/css/views/dialogs/_RoomSettingsDialog.scss
@@ -66,16 +66,16 @@ limitations under the License.
margin-bottom: 8px;
border-width: 1px 1px;
border-color: $primary-hairline-color;
+ border-style: solid;
border-radius: 5px;
.protocol-icon {
float: left;
- margin-right: 30px;
+ margin-right: 5px;
img {
border-radius: 5px;
border-width: 1px 1px;
border-color: $primary-hairline-color;
- border-style: solid;
}
span {
/* Correct letter placement */
From c0d1298c4f7296fc066b5721fa4f01695acdc95a Mon Sep 17 00:00:00 2001
From: Half-Shot
Date: Mon, 27 Jan 2020 14:05:22 +0000
Subject: [PATCH 03/19] Factor out into BridgeTile
---
res/css/_components.scss | 1 +
.../dialogs/_RoomSettingsDialogBridges.scss | 93 ++++++++++++++
src/components/views/settings/BridgeTile.js | 116 ++++++++++++++++++
.../settings/tabs/room/BridgeSettingsTab.js | 79 +-----------
4 files changed, 212 insertions(+), 77 deletions(-)
create mode 100644 res/css/views/dialogs/_RoomSettingsDialogBridges.scss
create mode 100644 src/components/views/settings/BridgeTile.js
diff --git a/res/css/_components.scss b/res/css/_components.scss
index 60f749de9c..f6a680c438 100644
--- a/res/css/_components.scss
+++ b/res/css/_components.scss
@@ -66,6 +66,7 @@
@import "./views/dialogs/_InviteDialog.scss";
@import "./views/dialogs/_MessageEditHistoryDialog.scss";
@import "./views/dialogs/_RoomSettingsDialog.scss";
+@import "./views/dialogs/_RoomSettingsDialogBridges.scss";
@import "./views/dialogs/_RoomUpgradeDialog.scss";
@import "./views/dialogs/_RoomUpgradeWarningDialog.scss";
@import "./views/dialogs/_SetEmailDialog.scss";
diff --git a/res/css/views/dialogs/_RoomSettingsDialogBridges.scss b/res/css/views/dialogs/_RoomSettingsDialogBridges.scss
new file mode 100644
index 0000000000..85d5c76ffc
--- /dev/null
+++ b/res/css/views/dialogs/_RoomSettingsDialogBridges.scss
@@ -0,0 +1,93 @@
+/*
+Copyright 2020 New Vector Ltd.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+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_RoomSettingsDialog_BridgeList {
+ padding: 0;
+
+ .mx_AccessibleButton {
+ display: inline;
+ margin: 0;
+ padding: 0;
+ float: left;
+ }
+}
+
+.mx_RoomSettingsDialog_BridgeList li {
+ list-style-type: none;
+ padding: 5px;
+ margin-bottom: 8px;
+ border-width: 1px 1px;
+ border-color: $primary-hairline-color;
+ border-style: solid;
+ border-radius: 5px;
+
+ .protocol-icon {
+ float: left;
+ margin-right: 5px;
+ img {
+ border-radius: 5px;
+ border-width: 1px 1px;
+ border-color: $primary-hairline-color;
+ }
+ span {
+ /* Correct letter placement */
+ left: auto;
+ }
+ }
+
+ h3 {
+ margin-top: 0;
+ margin-bottom: 4px;
+ font-size: 16pt;
+ color: $primary-fg-color;
+ }
+
+ .column-icon {
+ float: left;
+ padding-right: 10px;
+
+ .noProtocolIcon {
+ width: 48px;
+ height: 48px;
+ background: $settings-profile-placeholder-bg-color;
+ border-radius: 5px;
+ }
+ }
+
+ .column-data {
+ display: inline-block;
+ width: 85%;
+ }
+
+ .workspace-channel-details {
+ margin-top: 0;
+ color: $primary-fg-color;
+ }
+
+ .metadata {
+ color: $muted-fg-color;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ margin-bottom: 0;
+ }
+
+ .metadata.visible {
+ overflow-y: visible;
+ text-overflow: ellipsis;
+ white-space: normal;
+ }
+}
diff --git a/src/components/views/settings/BridgeTile.js b/src/components/views/settings/BridgeTile.js
new file mode 100644
index 0000000000..330af4a18a
--- /dev/null
+++ b/src/components/views/settings/BridgeTile.js
@@ -0,0 +1,116 @@
+/*
+Copyright 2020 New Vector Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import {getHttpUriForMxc} from "matrix-js-sdk/src/content-repo";
+import {_t} from "../../../languageHandler";
+import {MatrixClientPeg} from "../../../MatrixClientPeg";
+import Pill from "../elements/Pill";
+import {makeUserPermalink} from "../../../utils/permalinks/Permalinks";
+import BaseAvatar from "../avatars/BaseAvatar";
+import AccessibleButton from "../elements/AccessibleButton";
+
+export default class BridgeTile extends React.PureComponent {
+ static propTypes = {
+ ev: PropTypes.object.isRequired,
+ room: PropTypes.object.isRequired,
+ }
+
+ state = {
+ visible: false
+ }
+
+ _toggleVisible() {
+ this.setState({
+ visible: !this.state.visible,
+ });
+ }
+
+ render() {
+ const content = this.props.ev.getContent();
+ const { channel, network, protocol } = content;
+ const protocolName = protocol.displayname || protocol.id;
+ const channelName = channel.displayname || channel.id;
+ const networkName = network ? network.displayname || network.id : protocolName;
+
+ let creator = null;
+ if (content.creator) {
+ creator = _t("This bridge was provisioned by .", {}, {
+ user: ,
+ });
+ }
+
+ const bot = _t("This bridge is managed by .", {}, {
+ user: ,
+ });
+
+ let networkIcon;
+
+ if (protocol.avatar) {
+ const avatarUrl = getHttpUriForMxc(
+ MatrixClientPeg.get().getHomeserverUrl(),
+ protocol.avatar, 64, 64, "crop",
+ );
+
+ networkIcon = ;
+ } else {
+ networkIcon = ;
+ }
+
+
+ const workspaceChannelDetails = _t("Workspace: %(networkName)s Channel: %(channelName)s", {
+ networkName,
+ channelName,
+ });
+ const id = this.props.ev.getId();
+ const metadataClassname = "metadata" + (this.state.visible ? " visible" : "");
+ return (
+
+ {networkIcon}
+
+
+
{protocolName}
+
+ {workspaceChannelDetails}
+
+
+ {creator} {bot}
+
+
+ Show { this.state.visible ? "less" : "more" }
+
+
+ );
+ }
+}
diff --git a/src/components/views/settings/tabs/room/BridgeSettingsTab.js b/src/components/views/settings/tabs/room/BridgeSettingsTab.js
index 8090cf7d4d..7a859b0594 100644
--- a/src/components/views/settings/tabs/room/BridgeSettingsTab.js
+++ b/src/components/views/settings/tabs/room/BridgeSettingsTab.js
@@ -18,10 +18,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import {_t} from "../../../../../languageHandler";
import {MatrixClientPeg} from "../../../../../MatrixClientPeg";
-import Pill from "../../../elements/Pill";
-import {makeUserPermalink} from "../../../../../utils/permalinks/Permalinks";
-import BaseAvatar from "../../../avatars/BaseAvatar";
-import {getHttpUriForMxc} from "matrix-js-sdk/src/content-repo";
+import BridgeTile from "../../BridgeTile";
const BRIDGE_EVENT_TYPES = [
"uk.half-shot.bridge",
@@ -35,17 +32,6 @@ export default class BridgeSettingsTab extends React.Component {
constructor() {
super();
-
- this.state = {
- showMoreCard: null,
- };
- }
-
-
- _showMoreDetails(eventId) {
- this.setState({
- showMoreCard: eventId,
- });
}
_renderBridgeCard(event, room) {
@@ -53,68 +39,7 @@ export default class BridgeSettingsTab extends React.Component {
if (!content || !content.channel || !content.protocol) {
return null;
}
- const { channel, network } = content;
- const protocolName = content.protocol.displayname || content.protocol.id;
- const channelName = channel.displayname || channel.id;
- const networkName = network ? network.displayname || network.id : protocolName;
-
- let creator = null;
- if (content.creator) {
- creator = _t("This bridge was provisioned by .", {}, {
- user: ,
- });
- }
-
- const bot = _t("This bridge is managed by .", {}, {
- user: ,
- });
-
- const avatarUrl = network.avatar ? getHttpUriForMxc(
- MatrixClientPeg.get().getHomeserverUrl(),
- network.avatar, 32, 32, "crop",
- ) : null;
-
- const networkIcon = ;
-
- const workspaceChannelDetails = _t("Workspace: %(networkName)s Channel: %(channelName)s", {
- networkName,
- channelName,
- });
- const id = event.getId();
- const isVisible = this.state.showMoreCard === id;
- const metadataClassname = "metadata " + (isVisible ? "visible" : "");
- return (
-
- {networkIcon}
-
-
- );
+ return
}
static getBridgeStateEvents(roomId) {
From 4d83288f4ea6ebfe61f6f7f0ef4784a9e175ad86 Mon Sep 17 00:00:00 2001
From: Half-Shot
Date: Mon, 27 Jan 2020 14:42:46 +0000
Subject: [PATCH 04/19] linting
---
src/components/views/settings/BridgeTile.js | 4 ++--
.../views/settings/tabs/room/BridgeSettingsTab.js | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/components/views/settings/BridgeTile.js b/src/components/views/settings/BridgeTile.js
index 330af4a18a..ee9343ec39 100644
--- a/src/components/views/settings/BridgeTile.js
+++ b/src/components/views/settings/BridgeTile.js
@@ -29,9 +29,9 @@ export default class BridgeTile extends React.PureComponent {
ev: PropTypes.object.isRequired,
room: PropTypes.object.isRequired,
}
-
+
state = {
- visible: false
+ visible: false,
}
_toggleVisible() {
diff --git a/src/components/views/settings/tabs/room/BridgeSettingsTab.js b/src/components/views/settings/tabs/room/BridgeSettingsTab.js
index 7a859b0594..65c59ff977 100644
--- a/src/components/views/settings/tabs/room/BridgeSettingsTab.js
+++ b/src/components/views/settings/tabs/room/BridgeSettingsTab.js
@@ -39,7 +39,7 @@ export default class BridgeSettingsTab extends React.Component {
if (!content || !content.channel || !content.protocol) {
return null;
}
- return
+ return ;
}
static getBridgeStateEvents(roomId) {
@@ -76,8 +76,8 @@ export default class BridgeSettingsTab extends React.Component {
{ bridgeEvents.map((event) => this._renderBridgeCard(event, room)) }
-
- } else {
+ ;
+ } else {
content = {_t(
"This room isn’t bridging messages to any platforms. " +
"Learn more.", {},
@@ -86,7 +86,7 @@ export default class BridgeSettingsTab extends React.Component {
// having to re-translate the string when we do.
a: sub => '',
},
- )}
+ )}
;
}
return (
From 5851b10f72af580b2be3357799075ea0fcd1dd82 Mon Sep 17 00:00:00 2001
From: Half-Shot
Date: Mon, 27 Jan 2020 14:44:11 +0000
Subject: [PATCH 05/19] strings
---
src/i18n/strings/en_EN.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index e4ab764989..1afa3a33c9 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -521,6 +521,9 @@
"Accept to continue:": "Accept to continue:",
"Upload": "Upload",
"Remove": "Remove",
+ "This bridge was provisioned by .": "This bridge was provisioned by .",
+ "This bridge is managed by .": "This bridge is managed by .",
+ "Workspace: %(networkName)s Channel: %(channelName)s": "Workspace: %(networkName)s Channel: %(channelName)s",
"Failed to upload profile picture!": "Failed to upload profile picture!",
"Upload new:": "Upload new:",
"No display name": "No display name",
@@ -781,9 +784,6 @@
"Room version:": "Room version:",
"Developer options": "Developer options",
"Open Devtools": "Open Devtools",
- "This bridge was provisioned by .": "This bridge was provisioned by .",
- "This bridge is managed by .": "This bridge is managed by .",
- "Workspace: %(networkName)s Channel: %(channelName)s": "Workspace: %(networkName)s Channel: %(channelName)s",
"This room is bridging messages to the following platforms. Learn more.": "This room is bridging messages to the following platforms. Learn more.",
"This room isn’t bridging messages to any platforms. Learn more.": "This room isn’t bridging messages to any platforms. Learn more.",
"Bridges": "Bridges",
From 1964e18315657f800257e66756f6f6e5505ba20b Mon Sep 17 00:00:00 2001
From: Zoe
Date: Mon, 27 Jan 2020 16:40:56 +0000
Subject: [PATCH 06/19] Fix issue where we don't notice if our own devices
shouldn't be trusted
---
src/components/structures/RoomView.js | 2 +-
src/components/views/rooms/RoomTile.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js
index 60fff5f1e3..2d669f9243 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.js
@@ -811,7 +811,7 @@ export default createReactClass({
debuglog("e2e verified", verified, "unverified", unverified);
/* Check all verified user devices. */
- for (const userId of verified) {
+ for (const userId of [...verified, cli.getUserId()]) {
const devices = await cli.getStoredDevicesForUser(userId);
const anyDeviceNotVerified = devices.some(({deviceId}) => {
return !cli.checkDeviceTrust(userId, deviceId).isVerified();
diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js
index 41975fe7b8..41d43476ea 100644
--- a/src/components/views/rooms/RoomTile.js
+++ b/src/components/views/rooms/RoomTile.js
@@ -166,7 +166,7 @@ export default createReactClass({
});
/* Check all verified user devices. */
- for (const userId of verified) {
+ for (const userId of [...verified, cli.getUserId()]) {
const devices = await cli.getStoredDevicesForUser(userId);
const allDevicesVerified = devices.every(({deviceId}) => {
return cli.checkDeviceTrust(userId, deviceId).isVerified();
From d014c5239be443911d3a3ad0b4650756c9e04a1a Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett"
Date: Mon, 27 Jan 2020 23:14:02 +0000
Subject: [PATCH 07/19] Add new session verification details dialog
This gives more info on the session you're about to verify, including device
name and ID.
Fixes https://github.com/vector-im/riot-web/issues/11977
---
res/css/_components.scss | 1 +
.../dialogs/_NewSessionReviewDialog.scss | 37 ++++++++
.../views/dialogs/NewSessionReviewDialog.js | 92 +++++++++++++++++++
.../views/elements/DialogButtons.js | 2 +-
.../views/toasts/NewSessionToast.js | 5 +-
src/i18n/strings/en_EN.json | 4 +
6 files changed, 138 insertions(+), 3 deletions(-)
create mode 100644 res/css/views/dialogs/_NewSessionReviewDialog.scss
create mode 100644 src/components/views/dialogs/NewSessionReviewDialog.js
diff --git a/res/css/_components.scss b/res/css/_components.scss
index 07e92bdc7b..de56ad77bb 100644
--- a/res/css/_components.scss
+++ b/res/css/_components.scss
@@ -65,6 +65,7 @@
@import "./views/dialogs/_IncomingSasDialog.scss";
@import "./views/dialogs/_InviteDialog.scss";
@import "./views/dialogs/_MessageEditHistoryDialog.scss";
+@import "./views/dialogs/_NewSessionReviewDialog.scss";
@import "./views/dialogs/_RoomSettingsDialog.scss";
@import "./views/dialogs/_RoomUpgradeDialog.scss";
@import "./views/dialogs/_RoomUpgradeWarningDialog.scss";
diff --git a/res/css/views/dialogs/_NewSessionReviewDialog.scss b/res/css/views/dialogs/_NewSessionReviewDialog.scss
new file mode 100644
index 0000000000..7e35fe941e
--- /dev/null
+++ b/res/css/views/dialogs/_NewSessionReviewDialog.scss
@@ -0,0 +1,37 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_NewSessionReviewDialog_header {
+ display: flex;
+ align-items: center;
+ margin-top: 0;
+}
+
+.mx_NewSessionReviewDialog_headerIcon {
+ width: 24px;
+ height: 24px;
+ margin-right: 4px;
+ position: relative;
+}
+
+.mx_NewSessionReviewDialog_deviceName {
+ font-weight: 600;
+}
+
+.mx_NewSessionReviewDialog_deviceID {
+ font-size: 12px;
+ color: $notice-secondary-color;
+}
diff --git a/src/components/views/dialogs/NewSessionReviewDialog.js b/src/components/views/dialogs/NewSessionReviewDialog.js
new file mode 100644
index 0000000000..c14f0f5614
--- /dev/null
+++ b/src/components/views/dialogs/NewSessionReviewDialog.js
@@ -0,0 +1,92 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import * as sdk from "../../../index";
+import { _t } from '../../../languageHandler';
+import Modal from "../../../Modal";
+
+export default class NewSessionReviewDialog extends React.PureComponent {
+ static propTypes = {
+ userId: PropTypes.string.isRequired,
+ device: PropTypes.object.isRequired,
+ onFinished: PropTypes.func.isRequired,
+ }
+
+ onCancelClick = () => {
+ this.props.onFinished(false);
+ }
+
+ onContinueClick = () => {
+ const DeviceVerifyDialog =
+ sdk.getComponent('views.dialogs.DeviceVerifyDialog');
+ const { userId, device } = this.props;
+ Modal.createTrackedDialog('New Session Verification', 'Starting dialog', DeviceVerifyDialog, {
+ userId,
+ device,
+ }, null, /* priority = */ false, /* static = */ true);
+ }
+
+ render() {
+ const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
+ const DialogButtons = sdk.getComponent("views.elements.DialogButtons");
+
+ const { device } = this.props;
+
+ const icon = ;
+ const titleText = _t("New session");
+
+ const title =
+ {icon}
+ {titleText}
+
;
+
+ return (
+
+
+
{_t(
+ "Use this session to verify your new one, " +
+ "granting it access to encrypted messages:",
+ )}
+
+
+
+ {device.getDisplayName()}
+
+ ({device.deviceId})
+
+
+
+
{_t(
+ "If you didn’t sign in to this session, " +
+ "your account may be compromised.",
+ )}
+
+
+
+ );
+ }
+}
diff --git a/src/components/views/elements/DialogButtons.js b/src/components/views/elements/DialogButtons.js
index ee15bfc3f2..9223b5ade8 100644
--- a/src/components/views/elements/DialogButtons.js
+++ b/src/components/views/elements/DialogButtons.js
@@ -83,7 +83,7 @@ export default createReactClass({
// primary in the DOM so will get form submissions unless we make it not a submit.
type="button"
onClick={this._onCancelClick}
- className={this.props.cancelButtonClass}
+ className={this.props.cancelButtonClass}
disabled={this.props.disabled}
>
{ this.props.cancelButton || _t("Cancel") }
diff --git a/src/components/views/toasts/NewSessionToast.js b/src/components/views/toasts/NewSessionToast.js
index 3b60f59131..ed8b15e25f 100644
--- a/src/components/views/toasts/NewSessionToast.js
+++ b/src/components/views/toasts/NewSessionToast.js
@@ -34,11 +34,12 @@ export default class VerifySessionToast extends React.PureComponent {
_onReviewClick = async () => {
const cli = MatrixClientPeg.get();
- const DeviceVerifyDialog = sdk.getComponent('views.dialogs.DeviceVerifyDialog');
+ const NewSessionReviewDialog =
+ sdk.getComponent('views.dialogs.NewSessionReviewDialog');
const device = await cli.getStoredDevice(cli.getUserId(), this.props.deviceId);
- Modal.createTrackedDialog('New Session Verify', 'Starting dialog', DeviceVerifyDialog, {
+ Modal.createTrackedDialog('New Session Review', 'Starting dialog', NewSessionReviewDialog, {
userId: MatrixClientPeg.get().getUserId(),
device,
}, null, /* priority = */ false, /* static = */ true);
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 23ca730d97..7ccce9e7f6 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -1508,6 +1508,10 @@
"Are you sure you want to sign out?": "Are you sure you want to sign out?",
"Your homeserver doesn't seem to support this feature.": "Your homeserver doesn't seem to support this feature.",
"Message edits": "Message edits",
+ "New session": "New session",
+ "Use this session to verify your new one, granting it access to encrypted messages:": "Use this session to verify your new one, granting it access to encrypted messages:",
+ "If you didn’t sign in to this session, your account may be compromised.": "If you didn’t sign in to this session, your account may be compromised.",
+ "This wasn't me": "This wasn't me",
"If you run into any bugs or have feedback you'd like to share, please let us know on GitHub.": "If you run into any bugs or have feedback you'd like to share, please let us know on GitHub.",
"To help avoid duplicate issues, please view existing issues first (and add a +1) or create a new issue if you can't find it.": "To help avoid duplicate issues, please view existing issues first (and add a +1) or create a new issue if you can't find it.",
"Report bugs & give feedback": "Report bugs & give feedback",
From bdaf9fd06d2ec85985753eda2d076c7f195dd367 Mon Sep 17 00:00:00 2001
From: Half-Shot
Date: Tue, 28 Jan 2020 10:05:42 +0000
Subject: [PATCH 08/19] i18n
---
src/components/views/settings/BridgeTile.js | 2 +-
src/i18n/strings/en_EN.json | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/components/views/settings/BridgeTile.js b/src/components/views/settings/BridgeTile.js
index ee9343ec39..a5672c271c 100644
--- a/src/components/views/settings/BridgeTile.js
+++ b/src/components/views/settings/BridgeTile.js
@@ -108,7 +108,7 @@ export default class BridgeTile extends React.PureComponent {
{creator} {bot}
- Show { this.state.visible ? "less" : "more" }
+ { this.state.visible ? _t("Show less") : _t("Show more") }
);
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 1afa3a33c9..270d964e56 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -524,6 +524,8 @@
"This bridge was provisioned by .": "This bridge was provisioned by .",
"This bridge is managed by .": "This bridge is managed by .",
"Workspace: %(networkName)s Channel: %(channelName)s": "Workspace: %(networkName)s Channel: %(channelName)s",
+ "Show less": "Show less",
+ "Show more": "Show more",
"Failed to upload profile picture!": "Failed to upload profile picture!",
"Upload new:": "Upload new:",
"No display name": "No display name",
@@ -1461,7 +1463,6 @@
"Recent Conversations": "Recent Conversations",
"Suggestions": "Suggestions",
"Recently Direct Messaged": "Recently Direct Messaged",
- "Show more": "Show more",
"Direct Messages": "Direct Messages",
"If you can't find someone, ask them for their username, or share your username (%(userId)s) or profile link.": "If you can't find someone, ask them for their username, or share your username (%(userId)s) or profile link.",
"Go": "Go",
From 67358e06bf5da0d40f58d00c75b589e70624bc79 Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett"
Date: Tue, 28 Jan 2020 10:10:37 +0000
Subject: [PATCH 09/19] Use annotations and imports
---
.../views/dialogs/NewSessionReviewDialog.js | 13 ++++++-------
src/components/views/toasts/NewSessionToast.js | 8 ++++----
2 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/src/components/views/dialogs/NewSessionReviewDialog.js b/src/components/views/dialogs/NewSessionReviewDialog.js
index c14f0f5614..2d2bcc8f35 100644
--- a/src/components/views/dialogs/NewSessionReviewDialog.js
+++ b/src/components/views/dialogs/NewSessionReviewDialog.js
@@ -16,10 +16,14 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import * as sdk from "../../../index";
import { _t } from '../../../languageHandler';
-import Modal from "../../../Modal";
+import Modal from '../../../Modal';
+import { replaceableComponent } from '../../../utils/replaceableComponent';
+import DeviceVerifyDialog from './DeviceVerifyDialog';
+import BaseDialog from './BaseDialog';
+import DialogButtons from '../elements/DialogButtons';
+@replaceableComponent("views.dialogs.NewSessionReviewDialog")
export default class NewSessionReviewDialog extends React.PureComponent {
static propTypes = {
userId: PropTypes.string.isRequired,
@@ -32,8 +36,6 @@ export default class NewSessionReviewDialog extends React.PureComponent {
}
onContinueClick = () => {
- const DeviceVerifyDialog =
- sdk.getComponent('views.dialogs.DeviceVerifyDialog');
const { userId, device } = this.props;
Modal.createTrackedDialog('New Session Verification', 'Starting dialog', DeviceVerifyDialog, {
userId,
@@ -42,9 +44,6 @@ export default class NewSessionReviewDialog extends React.PureComponent {
}
render() {
- const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
- const DialogButtons = sdk.getComponent("views.elements.DialogButtons");
-
const { device } = this.props;
const icon = ;
diff --git a/src/components/views/toasts/NewSessionToast.js b/src/components/views/toasts/NewSessionToast.js
index ed8b15e25f..80564f3494 100644
--- a/src/components/views/toasts/NewSessionToast.js
+++ b/src/components/views/toasts/NewSessionToast.js
@@ -16,12 +16,15 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import * as sdk from "../../../index";
import { _t } from '../../../languageHandler';
import Modal from "../../../Modal";
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import DeviceListener from '../../../DeviceListener';
+import NewSessionReviewDialog from '../dialogs/NewSessionReviewDialog';
+import FormButton from '../elements/FormButton';
+import { replaceableComponent } from '../../../utils/replaceableComponent';
+@replaceableComponent("views.toasts.VerifySessionToast")
export default class VerifySessionToast extends React.PureComponent {
static propTypes = {
toastKey: PropTypes.string.isRequired,
@@ -34,8 +37,6 @@ export default class VerifySessionToast extends React.PureComponent {
_onReviewClick = async () => {
const cli = MatrixClientPeg.get();
- const NewSessionReviewDialog =
- sdk.getComponent('views.dialogs.NewSessionReviewDialog');
const device = await cli.getStoredDevice(cli.getUserId(), this.props.deviceId);
@@ -46,7 +47,6 @@ export default class VerifySessionToast extends React.PureComponent {
};
render() {
- const FormButton = sdk.getComponent("elements.FormButton");
return (
{_t("Review & verify your new session")}
From 785277d4b8d44ad011bb79cf0db2369584ee0730 Mon Sep 17 00:00:00 2001
From: Half-Shot
Date: Tue, 28 Jan 2020 11:17:51 +0000
Subject: [PATCH 10/19] Review bits for travis
---
.../views/dialogs/_RoomSettingsDialog.scss | 63 -------------------
.../dialogs/_RoomSettingsDialogBridges.scss | 7 ++-
src/components/views/settings/BridgeTile.js | 13 ++--
.../settings/tabs/room/BridgeSettingsTab.js | 8 +--
src/i18n/strings/en_EN.json | 3 +-
5 files changed, 14 insertions(+), 80 deletions(-)
diff --git a/res/css/views/dialogs/_RoomSettingsDialog.scss b/res/css/views/dialogs/_RoomSettingsDialog.scss
index 66c34fd73d..2a4e62f9aa 100644
--- a/res/css/views/dialogs/_RoomSettingsDialog.scss
+++ b/res/css/views/dialogs/_RoomSettingsDialog.scss
@@ -56,66 +56,3 @@ limitations under the License.
mask-position: center;
}
-.mx_RoomSettingsDialog_BridgeList {
- padding: 0;
-}
-
-.mx_RoomSettingsDialog_BridgeList li {
- list-style-type: none;
- padding: 5px;
- margin-bottom: 8px;
- border-width: 1px 1px;
- border-color: $primary-hairline-color;
- border-style: solid;
- border-radius: 5px;
-
- .protocol-icon {
- float: left;
- margin-right: 5px;
- img {
- border-radius: 5px;
- border-width: 1px 1px;
- border-color: $primary-hairline-color;
- }
- span {
- /* Correct letter placement */
- left: auto;
- }
- }
-
- h3 {
- margin-top: 0;
- margin-bottom: 4px;
- font-size: 16pt;
- }
-
- .column-icon {
- float: left;
- }
-
- .column-data {
- display: inline-block;
- width: 85%;
- }
-
- .workspace-channel-details {
- margin-top: 0;
- color: $primary-fg-color;
- }
-
- .metadata {
- color: $muted-fg-color;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- margin-bottom: 0;
- }
-
- .metadata.visible {
- overflow-y: visible;
- text-overflow: ellipsis;
- white-space: normal;
- }
-
-}
-
diff --git a/res/css/views/dialogs/_RoomSettingsDialogBridges.scss b/res/css/views/dialogs/_RoomSettingsDialogBridges.scss
index 85d5c76ffc..ab54fb777b 100644
--- a/res/css/views/dialogs/_RoomSettingsDialogBridges.scss
+++ b/res/css/views/dialogs/_RoomSettingsDialogBridges.scss
@@ -1,5 +1,5 @@
/*
-Copyright 2020 New Vector Ltd.
+Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@ limitations under the License.
display: inline;
margin: 0;
padding: 0;
- float: left;
}
}
@@ -75,6 +74,10 @@ limitations under the License.
.workspace-channel-details {
margin-top: 0;
color: $primary-fg-color;
+
+ .channel {
+ margin-left: 15px;
+ }
}
.metadata {
diff --git a/src/components/views/settings/BridgeTile.js b/src/components/views/settings/BridgeTile.js
index a5672c271c..dca23723aa 100644
--- a/src/components/views/settings/BridgeTile.js
+++ b/src/components/views/settings/BridgeTile.js
@@ -1,5 +1,5 @@
/*
-Copyright 2020 New Vector Ltd
+Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -23,7 +23,8 @@ import Pill from "../elements/Pill";
import {makeUserPermalink} from "../../../utils/permalinks/Permalinks";
import BaseAvatar from "../avatars/BaseAvatar";
import AccessibleButton from "../elements/AccessibleButton";
-
+import {replaceableComponent} from "../../../utils/replaceableComponent";
+@replaceableComponent("views.settings.BridgeTile")
export default class BridgeTile extends React.PureComponent {
static propTypes = {
ev: PropTypes.object.isRequired,
@@ -88,11 +89,6 @@ export default class BridgeTile extends React.PureComponent {
networkIcon = ;
}
-
- const workspaceChannelDetails = _t("Workspace: %(networkName)s Channel: %(channelName)s", {
- networkName,
- channelName,
- });
const id = this.props.ev.getId();
const metadataClassname = "metadata" + (this.state.visible ? " visible" : "");
return (
@@ -102,7 +98,8 @@ export default class BridgeTile extends React.PureComponent {
{protocolName}
- {workspaceChannelDetails}
+ {_t("Workspace: %(networkName)s", {networkName})}
+ {_t("Channel: %(channelName)s", {channelName})}
{creator} {bot}
diff --git a/src/components/views/settings/tabs/room/BridgeSettingsTab.js b/src/components/views/settings/tabs/room/BridgeSettingsTab.js
index 65c59ff977..12a72ab8f9 100644
--- a/src/components/views/settings/tabs/room/BridgeSettingsTab.js
+++ b/src/components/views/settings/tabs/room/BridgeSettingsTab.js
@@ -30,10 +30,6 @@ export default class BridgeSettingsTab extends React.Component {
roomId: PropTypes.string.isRequired,
};
- constructor() {
- super();
- }
-
_renderBridgeCard(event, room) {
const content = event.getContent();
if (!content || !content.channel || !content.protocol) {
@@ -70,7 +66,7 @@ export default class BridgeSettingsTab extends React.Component {
{
// TODO: We don't have this link yet: this will prevent the translators
// having to re-translate the string when we do.
- a: sub => '',
+ a: sub => sub,
},
)}
@@ -84,7 +80,7 @@ export default class BridgeSettingsTab extends React.Component {
{
// TODO: We don't have this link yet: this will prevent the translators
// having to re-translate the string when we do.
- a: sub => '',
+ a: sub => sub,
},
)};
}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 270d964e56..61dcd90638 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -523,7 +523,8 @@
"Remove": "Remove",
"This bridge was provisioned by .": "This bridge was provisioned by .",
"This bridge is managed by .": "This bridge is managed by .",
- "Workspace: %(networkName)s Channel: %(channelName)s": "Workspace: %(networkName)s Channel: %(channelName)s",
+ "Workspace: %(networkName)s": "Workspace: %(networkName)s",
+ "Channel: %(channelName)s": "Channel: %(channelName)s",
"Show less": "Show less",
"Show more": "Show more",
"Failed to upload profile picture!": "Failed to upload profile picture!",
From 71233a5affbfc8a793cd74e5ae9d6c3fd99dea63 Mon Sep 17 00:00:00 2001
From: Half-Shot
Date: Tue, 28 Jan 2020 11:33:51 +0000
Subject: [PATCH 11/19] liney liney come back we need you
---
src/components/views/settings/BridgeTile.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/components/views/settings/BridgeTile.js b/src/components/views/settings/BridgeTile.js
index dca23723aa..6902639879 100644
--- a/src/components/views/settings/BridgeTile.js
+++ b/src/components/views/settings/BridgeTile.js
@@ -24,6 +24,7 @@ import {makeUserPermalink} from "../../../utils/permalinks/Permalinks";
import BaseAvatar from "../avatars/BaseAvatar";
import AccessibleButton from "../elements/AccessibleButton";
import {replaceableComponent} from "../../../utils/replaceableComponent";
+
@replaceableComponent("views.settings.BridgeTile")
export default class BridgeTile extends React.PureComponent {
static propTypes = {
From 9cf59ab16d6b08b0ae40a76e300e0b5d0e4612f7 Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett"
Date: Tue, 28 Jan 2020 12:30:39 +0000
Subject: [PATCH 12/19] Enable cross-signing lab when key in storage
When we're starting a new session and find the cross-signing keys in secret
storage, auto-enable the lab for the new session.
Fixes https://github.com/vector-im/riot-web/issues/12100
---
src/components/structures/MatrixChat.js | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js
index 133d74db45..1b4d0e9609 100644
--- a/src/components/structures/MatrixChat.js
+++ b/src/components/structures/MatrixChat.js
@@ -1834,6 +1834,7 @@ export default createReactClass({
this._accountPassword = null;
this._accountPasswordTimer = null;
}, 60 * 5 * 1000);
+
// Wait for the client to be logged in (but not started)
// which is enough to ask the server about account data.
const loggedIn = new Promise(resolve => {
@@ -1867,6 +1868,9 @@ export default createReactClass({
}
if (masterKeyInStorage) {
+ // Auto-enable cross-signing for the new session when key found in
+ // secret storage.
+ SettingsStore.setFeatureEnabled("feature_cross_signing", true);
this.setStateForNewView({ view: VIEWS.COMPLETE_SECURITY });
} else if (SettingsStore.isFeatureEnabled("feature_cross_signing")) {
// This will only work if the feature is set to 'enable' in the config,
From 21405b8f25ab36dc1967b53bdd349e872165dd18 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Tue, 28 Jan 2020 12:44:14 +0000
Subject: [PATCH 13/19] Fix skinning and babel tagets
---
babel.config.js | 4 ++--
src/Skinner.js | 14 ++++++++------
src/utils/replaceableComponent.ts | 8 ++++++--
3 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/babel.config.js b/babel.config.js
index c83be72518..944d9051bb 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -4,7 +4,7 @@ module.exports = {
["@babel/preset-env", {
"targets": {
"browsers": [
- "last 2 versions"
+ "last 2 Chrome versions", "last 2 Firefox versions", "last 2 Safari versions"
]
},
"modules": "commonjs"
@@ -14,7 +14,7 @@ module.exports = {
"@babel/preset-react"
],
"plugins": [
- ["@babel/plugin-proposal-decorators", { "legacy": true }],
+ ["@babel/plugin-proposal-decorators", {"legacy": false, decoratorsBeforeExport: true}],
"@babel/plugin-proposal-export-default-from",
"@babel/plugin-proposal-numeric-separator",
"@babel/plugin-proposal-class-properties",
diff --git a/src/Skinner.js b/src/Skinner.js
index 3baecc9fb3..1e121b8808 100644
--- a/src/Skinner.js
+++ b/src/Skinner.js
@@ -20,6 +20,7 @@ class Skinner {
}
getComponent(name) {
+ if (!name) throw new Error(`Invalid component name: ${name}`);
if (this.components === null) {
throw new Error(
"Attempted to get a component before a skin has been loaded."+
@@ -43,12 +44,6 @@ class Skinner {
// Check the skin first
let comp = doLookup(this.components);
- // If that failed, check against our own components
- if (!comp) {
- // Lazily load our own components because they might end up calling .getComponent()
- comp = doLookup(require("./component-index").components);
- }
-
// Just return nothing instead of erroring - the consumer should be smart enough to
// handle this at this point.
if (!comp) {
@@ -75,6 +70,13 @@ class Skinner {
const comp = skinObject.components[compKeys[i]];
this.addComponent(compKeys[i], comp);
}
+
+ // Now that we have a skin, load our components too
+ const idx = require("./component-index");
+ if (!idx || !idx.components) throw new Error("Invalid react-sdk component index");
+ for (const c in idx.components) {
+ if (!this.components[c]) this.components[c] = idx.components[c];
+ }
}
addComponent(name, comp) {
diff --git a/src/utils/replaceableComponent.ts b/src/utils/replaceableComponent.ts
index 9f617b27f3..92272e533c 100644
--- a/src/utils/replaceableComponent.ts
+++ b/src/utils/replaceableComponent.ts
@@ -32,9 +32,13 @@ import * as sdk from '../index';
* with a skinned version. If no skinned version is available, this component
* will be used.
*/
-export function replaceableComponent(name: string, origComponent: React.Component) {
+export function replaceableComponent(name: string) {
// Decorators return a function to override the class (origComponent). This
// ultimately assumes that `getComponent()` won't throw an error and instead
// return a falsey value like `null` when the skin doesn't have a component.
- return () => sdk.getComponent(name) || origComponent;
+ return (origComponent) => {
+ const c = sdk.getComponent(name) || origComponent;
+ c.kind = "class"; // appeases babel
+ return c;
+ };
}
From d0c28adfb1a13a54e78a7b9c825f824a784db28c Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Tue, 28 Jan 2020 12:53:37 +0000
Subject: [PATCH 14/19] Appease the linter
---
src/Skinner.js | 2 +-
src/utils/replaceableComponent.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Skinner.js b/src/Skinner.js
index 1e121b8808..87c5a7be7f 100644
--- a/src/Skinner.js
+++ b/src/Skinner.js
@@ -42,7 +42,7 @@ class Skinner {
};
// Check the skin first
- let comp = doLookup(this.components);
+ const comp = doLookup(this.components);
// Just return nothing instead of erroring - the consumer should be smart enough to
// handle this at this point.
diff --git a/src/utils/replaceableComponent.ts b/src/utils/replaceableComponent.ts
index 92272e533c..281ff4c1ac 100644
--- a/src/utils/replaceableComponent.ts
+++ b/src/utils/replaceableComponent.ts
@@ -32,7 +32,7 @@ import * as sdk from '../index';
* with a skinned version. If no skinned version is available, this component
* will be used.
*/
-export function replaceableComponent(name: string) {
+export function replaceableComponent(name: string) {
// Decorators return a function to override the class (origComponent). This
// ultimately assumes that `getComponent()` won't throw an error and instead
// return a falsey value like `null` when the skin doesn't have a component.
From a4778cc7e3371f12c32ec991a684c681911e0d1e Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Tue, 28 Jan 2020 14:18:12 +0000
Subject: [PATCH 15/19] Remove legacy
---
babel.config.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/babel.config.js b/babel.config.js
index 944d9051bb..333e5301af 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -14,7 +14,7 @@ module.exports = {
"@babel/preset-react"
],
"plugins": [
- ["@babel/plugin-proposal-decorators", {"legacy": false, decoratorsBeforeExport: true}],
+ ["@babel/plugin-proposal-decorators", {decoratorsBeforeExport: true}],
"@babel/plugin-proposal-export-default-from",
"@babel/plugin-proposal-numeric-separator",
"@babel/plugin-proposal-class-properties",
From 894568bf7aff3578970e6d577d28a14c19d2bce2 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Tue, 28 Jan 2020 14:19:06 +0000
Subject: [PATCH 16/19] Stop using deprecated stuff
---
babel.config.js | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/babel.config.js b/babel.config.js
index 333e5301af..3c0c3fcb85 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -2,12 +2,9 @@ module.exports = {
"sourceMaps": "inline",
"presets": [
["@babel/preset-env", {
- "targets": {
- "browsers": [
- "last 2 Chrome versions", "last 2 Firefox versions", "last 2 Safari versions"
- ]
- },
- "modules": "commonjs"
+ "targets": [
+ "last 2 Chrome versions", "last 2 Firefox versions", "last 2 Safari versions"
+ ],
}],
"@babel/preset-typescript",
"@babel/preset-flow",
From 85bcad0ea0e0a667de343efa81dac64e63c2cf85 Mon Sep 17 00:00:00 2001
From: Half-Shot
Date: Tue, 28 Jan 2020 14:42:58 +0000
Subject: [PATCH 17/19] Styling for Nad
---
.../dialogs/_RoomSettingsDialogBridges.scss | 100 ++++++++++--------
src/components/views/settings/BridgeTile.js | 2 +-
.../settings/tabs/room/BridgeSettingsTab.js | 6 +-
3 files changed, 63 insertions(+), 45 deletions(-)
diff --git a/res/css/views/dialogs/_RoomSettingsDialogBridges.scss b/res/css/views/dialogs/_RoomSettingsDialogBridges.scss
index ab54fb777b..d77e019cbf 100644
--- a/res/css/views/dialogs/_RoomSettingsDialogBridges.scss
+++ b/res/css/views/dialogs/_RoomSettingsDialogBridges.scss
@@ -33,64 +33,80 @@ limitations under the License.
border-style: solid;
border-radius: 5px;
- .protocol-icon {
- float: left;
- margin-right: 5px;
- img {
- border-radius: 5px;
- border-width: 1px 1px;
- border-color: $primary-hairline-color;
- }
- span {
- /* Correct letter placement */
- left: auto;
- }
- }
-
- h3 {
- margin-top: 0;
- margin-bottom: 4px;
- font-size: 16pt;
- color: $primary-fg-color;
- }
-
.column-icon {
float: left;
padding-right: 10px;
+ * {
+ border-radius: 5px;
+ border: 1px solid $input-darker-bg-color;
+ }
+
.noProtocolIcon {
width: 48px;
height: 48px;
- background: $settings-profile-placeholder-bg-color;
+ background: $input-darker-bg-color;
border-radius: 5px;
}
+
+ .protocol-icon {
+ float: left;
+ margin-right: 5px;
+ img {
+ border-radius: 5px;
+ border-width: 1px 1px;
+ border-color: $primary-hairline-color;
+ }
+ span {
+ /* Correct letter placement */
+ left: auto;
+ }
+ }
}
.column-data {
display: inline-block;
width: 85%;
- }
- .workspace-channel-details {
- margin-top: 0;
- color: $primary-fg-color;
+ > h3 {
+ margin-top: 0px;
+ margin-bottom: 0px;
+ font-size: 16pt;
+ color: $primary-fg-color;
+ }
- .channel {
- margin-left: 15px;
+ > * {
+ margin-top: 4px;
+ margin-bottom: 0;
+ }
+
+ .workspace-channel-details {
+ color: $primary-fg-color;
+ font-weight: 600;
+
+ .channel {
+ margin-left: 5px;
+ }
+ }
+
+ .showMore {
+ display: block;
+ text-align: left;
+ margin-top: 10px;
+ }
+
+ .metadata {
+ color: $muted-fg-color;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ margin-bottom: 0;
+ }
+
+ .metadata.visible {
+ overflow-y: visible;
+ text-overflow: ellipsis;
+ white-space: normal;
}
}
-
- .metadata {
- color: $muted-fg-color;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- margin-bottom: 0;
- }
-
- .metadata.visible {
- overflow-y: visible;
- text-overflow: ellipsis;
- white-space: normal;
- }
}
diff --git a/src/components/views/settings/BridgeTile.js b/src/components/views/settings/BridgeTile.js
index 6902639879..1759c0f58d 100644
--- a/src/components/views/settings/BridgeTile.js
+++ b/src/components/views/settings/BridgeTile.js
@@ -105,7 +105,7 @@ export default class BridgeTile extends React.PureComponent {
{creator} {bot}
-
+
{ this.state.visible ? _t("Show less") : _t("Show more") }
diff --git a/src/components/views/settings/tabs/room/BridgeSettingsTab.js b/src/components/views/settings/tabs/room/BridgeSettingsTab.js
index 12a72ab8f9..d66732de55 100644
--- a/src/components/views/settings/tabs/room/BridgeSettingsTab.js
+++ b/src/components/views/settings/tabs/room/BridgeSettingsTab.js
@@ -25,6 +25,8 @@ const BRIDGE_EVENT_TYPES = [
// m.bridge
];
+const BRIDGES_LINK = "https://matrix.org/bridges/";
+
export default class BridgeSettingsTab extends React.Component {
static propTypes = {
roomId: PropTypes.string.isRequired,
@@ -66,7 +68,7 @@ export default class BridgeSettingsTab extends React.Component {
{
// TODO: We don't have this link yet: this will prevent the translators
// having to re-translate the string when we do.
- a: sub => sub,
+ a: sub => {sub},
},
)}
@@ -80,7 +82,7 @@ export default class BridgeSettingsTab extends React.Component {
{
// TODO: We don't have this link yet: this will prevent the translators
// having to re-translate the string when we do.
- a: sub => sub,
+ a: sub => {sub},
},
)};
}
From bfaa9d56fbf368eb3ffb4c985794633fd8014833 Mon Sep 17 00:00:00 2001
From: Half-Shot
Date: Tue, 28 Jan 2020 16:05:27 +0000
Subject: [PATCH 18/19] prefixes
---
res/css/views/dialogs/_RoomSettingsDialogBridges.scss | 2 +-
src/components/views/settings/BridgeTile.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/res/css/views/dialogs/_RoomSettingsDialogBridges.scss b/res/css/views/dialogs/_RoomSettingsDialogBridges.scss
index d77e019cbf..a1793cc75e 100644
--- a/res/css/views/dialogs/_RoomSettingsDialogBridges.scss
+++ b/res/css/views/dialogs/_RoomSettingsDialogBridges.scss
@@ -89,7 +89,7 @@ limitations under the License.
}
}
- .showMore {
+ .mx_showMore {
display: block;
text-align: left;
margin-top: 10px;
diff --git a/src/components/views/settings/BridgeTile.js b/src/components/views/settings/BridgeTile.js
index 1759c0f58d..5b74e44c9e 100644
--- a/src/components/views/settings/BridgeTile.js
+++ b/src/components/views/settings/BridgeTile.js
@@ -105,7 +105,7 @@ export default class BridgeTile extends React.PureComponent {
{creator} {bot}
-
+
{ this.state.visible ? _t("Show less") : _t("Show more") }
From 330b489fd528b1f80bdbdd1ba1de091fec573cf7 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Tue, 28 Jan 2020 16:44:30 +0000
Subject: [PATCH 19/19] Switch back to legacy decorators
Empirically the build is fine with these, but it is unfortunate that we have to reply on deprecated semantics. TypeScript should help fix this.
---
babel.config.js | 2 +-
src/utils/replaceableComponent.ts | 8 ++------
2 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/babel.config.js b/babel.config.js
index 3c0c3fcb85..d5a97d56ce 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -11,7 +11,7 @@ module.exports = {
"@babel/preset-react"
],
"plugins": [
- ["@babel/plugin-proposal-decorators", {decoratorsBeforeExport: true}],
+ ["@babel/plugin-proposal-decorators", {legacy: true}],
"@babel/plugin-proposal-export-default-from",
"@babel/plugin-proposal-numeric-separator",
"@babel/plugin-proposal-class-properties",
diff --git a/src/utils/replaceableComponent.ts b/src/utils/replaceableComponent.ts
index 281ff4c1ac..9f617b27f3 100644
--- a/src/utils/replaceableComponent.ts
+++ b/src/utils/replaceableComponent.ts
@@ -32,13 +32,9 @@ import * as sdk from '../index';
* with a skinned version. If no skinned version is available, this component
* will be used.
*/
-export function replaceableComponent(name: string) {
+export function replaceableComponent(name: string, origComponent: React.Component) {
// Decorators return a function to override the class (origComponent). This
// ultimately assumes that `getComponent()` won't throw an error and instead
// return a falsey value like `null` when the skin doesn't have a component.
- return (origComponent) => {
- const c = sdk.getComponent(name) || origComponent;
- c.kind = "class"; // appeases babel
- return c;
- };
+ return () => sdk.getComponent(name) || origComponent;
}