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, + })} +

    +
      + {creator} {bot} +
    +
    +
  • ); + } +} 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",