diff --git a/res/css/views/dialogs/_RoomSettingsDialogBridges.scss b/res/css/views/dialogs/_RoomSettingsDialogBridges.scss
index a1793cc75e..c97a3b69b7 100644
--- a/res/css/views/dialogs/_RoomSettingsDialogBridges.scss
+++ b/res/css/views/dialogs/_RoomSettingsDialogBridges.scss
@@ -89,24 +89,18 @@ limitations under the License.
}
}
- .mx_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;
+ padding: 0;
+
+ > li {
+ padding: 0;
+ border: 0;
+ }
}
}
}
diff --git a/src/components/views/settings/BridgeTile.js b/src/components/views/settings/BridgeTile.js
deleted file mode 100644
index e9c58518e4..0000000000
--- a/src/components/views/settings/BridgeTile.js
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
-Copyright 2020 The Matrix.org Foundation C.I.C.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-import React from 'react';
-import 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";
-import {replaceableComponent} from "../../../utils/replaceableComponent";
-import SettingsStore from "../../../settings/SettingsStore";
-
-@replaceableComponent("views.settings.BridgeTile")
-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 id = this.props.ev.getId();
- const metadataClassname = "metadata" + (this.state.visible ? " visible" : "");
- return (
-
- {networkIcon}
-
-
-
{protocolName}
-
- {_t("Workspace: %(networkName)s", {networkName})}
- {_t("Channel: %(channelName)s", {channelName})}
-
-
- {creator} {bot}
-
-
- { this.state.visible ? _t("Show less") : _t("Show more") }
-
-
- );
- }
-}
diff --git a/src/components/views/settings/BridgeTile.tsx b/src/components/views/settings/BridgeTile.tsx
new file mode 100644
index 0000000000..58499ebd25
--- /dev/null
+++ b/src/components/views/settings/BridgeTile.tsx
@@ -0,0 +1,167 @@
+/*
+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 {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 SettingsStore from "../../../settings/SettingsStore";
+import {MatrixEvent} from "matrix-js-sdk/src/models/event";
+import { Room } from "matrix-js-sdk/src/models/room";
+import { isUrlPermitted } from '../../../HtmlUtils';
+
+interface IProps {
+ ev: MatrixEvent;
+ room: Room;
+}
+
+/**
+ * This should match https://github.com/matrix-org/matrix-doc/blob/hs/msc-bridge-inf/proposals/2346-bridge-info-state-event.md#mbridge
+ */
+interface IBridgeStateEvent {
+ bridgebot: string;
+ creator?: string;
+ protocol: {
+ id: string;
+ displayname?: string;
+ // eslint-disable-next-line camelcase
+ avatar_url?: string;
+ // eslint-disable-next-line camelcase
+ external_url?: string;
+ };
+ network?: {
+ id: string;
+ displayname?: string;
+ // eslint-disable-next-line camelcase
+ avatar_url?: string;
+ // eslint-disable-next-line camelcase
+ external_url?: string;
+ };
+ channel: {
+ id: string;
+ displayname?: string;
+ // eslint-disable-next-line camelcase
+ avatar_url?: string;
+ // eslint-disable-next-line camelcase
+ external_url?: string;
+ };
+}
+
+export default class BridgeTile extends React.PureComponent {
+ static propTypes = {
+ ev: PropTypes.object.isRequired,
+ room: PropTypes.object.isRequired,
+ }
+
+ render() {
+ const content: IBridgeStateEvent = this.props.ev.getContent();
+ // Validate
+ if (!content.channel?.id || !content.protocol?.id) {
+ console.warn(`Bridge info event ${this.props.ev.getId()} has missing content. Tile will not render`);
+ return null;
+ }
+ if (!content.bridgebot) {
+ // Bridgebot was not required previously, so in order to not break rooms we are allowing
+ // the sender to be used in place. When the proposal is merged, this should be removed.
+ console.warn(`Bridge info event ${this.props.ev.getId()} does not provide a 'bridgebot' key which`
+ + "is deprecated behaviour. Using sender for now.");
+ content.bridgebot = this.props.ev.getSender();
+ }
+ const { channel, network, protocol } = content;
+ const protocolName = protocol.displayname || protocol.id;
+ const channelName = channel.displayname || channel.id;
+
+ 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_url) {
+ const avatarUrl = getHttpUriForMxc(
+ MatrixClientPeg.get().getHomeserverUrl(),
+ protocol.avatar_url, 64, 64, "crop",
+ );
+
+ networkIcon = ;
+ } else {
+ networkIcon = ;
+ }
+ let networkItem = null;
+ if (network) {
+ const networkName = network.displayname || network.id;
+ let networkLink = {networkName};
+ if (typeof network.external_url === "string" && isUrlPermitted(network.external_url)) {
+ networkLink = {networkName}
+ }
+ networkItem = _t("Workspace: ", {}, {
+ networkLink: () => networkLink,
+ });
+ }
+
+ let channelLink = {channelName};
+ if (typeof channel.external_url === "string" && isUrlPermitted(channel.external_url)) {
+ channelLink = {channelName}
+ }
+
+ const id = this.props.ev.getId();
+ return (
+
+ {networkIcon}
+
+
+
{protocolName}
+
+ {networkItem}
+ {_t("Channel: ", {}, {
+ channelLink: () => channelLink,
+ })}
+
+
+
+ );
+ }
+}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 8739d0cf2f..71b390f0fc 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -965,10 +965,8 @@
"Upload": "Upload",
"This bridge was provisioned by .": "This bridge was provisioned by .",
"This bridge is managed by .": "This bridge is managed by .",
- "Workspace: %(networkName)s": "Workspace: %(networkName)s",
- "Channel: %(channelName)s": "Channel: %(channelName)s",
- "Show less": "Show less",
- "Show more": "Show more",
+ "Workspace: ": "Workspace: ",
+ "Channel: ": "Channel: ",
"Failed to upload profile picture!": "Failed to upload profile picture!",
"Upload new:": "Upload new:",
"No display name": "No display name",
@@ -1532,6 +1530,7 @@
"Jump to first invite.": "Jump to first invite.",
"Show %(count)s more|other": "Show %(count)s more",
"Show %(count)s more|one": "Show %(count)s more",
+ "Show less": "Show less",
"Use default": "Use default",
"All messages": "All messages",
"Mentions & Keywords": "Mentions & Keywords",
@@ -1594,6 +1593,7 @@
"New published address (e.g. #alias:server)": "New published address (e.g. #alias:server)",
"Local Addresses": "Local Addresses",
"Set addresses for this room so users can find this room through your homeserver (%(localDomain)s)": "Set addresses for this room so users can find this room through your homeserver (%(localDomain)s)",
+ "Show more": "Show more",
"Error updating flair": "Error updating flair",
"There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.": "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.",
"Invalid community ID": "Invalid community ID",