Merge pull request #5454 from matrix-org/hs/bridge-info-v2
Various fixes for Bridge Info page (MSC2346)
This commit is contained in:
commit
117d8843c4
4 changed files with 177 additions and 131 deletions
|
@ -89,24 +89,18 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_showMore {
|
|
||||||
display: block;
|
|
||||||
text-align: left;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metadata {
|
.metadata {
|
||||||
color: $muted-fg-color;
|
color: $muted-fg-color;
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
|
||||||
|
|
||||||
.metadata.visible {
|
|
||||||
overflow-y: visible;
|
overflow-y: visible;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
> li {
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 />.", {}, {
|
|
||||||
user: <Pill
|
|
||||||
type={Pill.TYPE_USER_MENTION}
|
|
||||||
room={this.props.room}
|
|
||||||
url={makeUserPermalink(content.creator)}
|
|
||||||
shouldShowPillAvatar={SettingsStore.getValue("Pill.shouldShowPillAvatar")}
|
|
||||||
/>,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const bot = _t("This bridge is managed by <user />.", {}, {
|
|
||||||
user: <Pill
|
|
||||||
type={Pill.TYPE_USER_MENTION}
|
|
||||||
room={this.props.room}
|
|
||||||
url={makeUserPermalink(this.props.ev.getSender())}
|
|
||||||
shouldShowPillAvatar={SettingsStore.getValue("Pill.shouldShowPillAvatar")}
|
|
||||||
/>,
|
|
||||||
});
|
|
||||||
|
|
||||||
let networkIcon;
|
|
||||||
|
|
||||||
if (protocol.avatar) {
|
|
||||||
const avatarUrl = getHttpUriForMxc(
|
|
||||||
MatrixClientPeg.get().getHomeserverUrl(),
|
|
||||||
protocol.avatar, 64, 64, "crop",
|
|
||||||
);
|
|
||||||
|
|
||||||
networkIcon = <BaseAvatar className="protocol-icon"
|
|
||||||
width={48}
|
|
||||||
height={48}
|
|
||||||
resizeMethod='crop'
|
|
||||||
name={ protocolName }
|
|
||||||
idName={ protocolName }
|
|
||||||
url={ avatarUrl }
|
|
||||||
/>;
|
|
||||||
} else {
|
|
||||||
networkIcon = <div class="noProtocolIcon"></div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const id = this.props.ev.getId();
|
|
||||||
const metadataClassname = "metadata" + (this.state.visible ? " visible" : "");
|
|
||||||
return (<li key={id}>
|
|
||||||
<div className="column-icon">
|
|
||||||
{networkIcon}
|
|
||||||
</div>
|
|
||||||
<div className="column-data">
|
|
||||||
<h3>{protocolName}</h3>
|
|
||||||
<p className="workspace-channel-details">
|
|
||||||
<span>{_t("Workspace: %(networkName)s", {networkName})}</span>
|
|
||||||
<span className="channel">{_t("Channel: %(channelName)s", {channelName})}</span>
|
|
||||||
</p>
|
|
||||||
<p className={metadataClassname}>
|
|
||||||
{creator} {bot}
|
|
||||||
</p>
|
|
||||||
<AccessibleButton className="mx_showMore" kind="secondary" onClick={this._toggleVisible.bind(this)}>
|
|
||||||
{ this.state.visible ? _t("Show less") : _t("Show more") }
|
|
||||||
</AccessibleButton>
|
|
||||||
</div>
|
|
||||||
</li>);
|
|
||||||
}
|
|
||||||
}
|
|
167
src/components/views/settings/BridgeTile.tsx
Normal file
167
src/components/views/settings/BridgeTile.tsx
Normal file
|
@ -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<IProps> {
|
||||||
|
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 = <li>{_t("This bridge was provisioned by <user />.", {}, {
|
||||||
|
user: () => <Pill
|
||||||
|
type={Pill.TYPE_USER_MENTION}
|
||||||
|
room={this.props.room}
|
||||||
|
url={makeUserPermalink(content.creator)}
|
||||||
|
shouldShowPillAvatar={SettingsStore.getValue("Pill.shouldShowPillAvatar")}
|
||||||
|
/>,
|
||||||
|
})}</li>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bot = <li>{_t("This bridge is managed by <user />.", {}, {
|
||||||
|
user: () => <Pill
|
||||||
|
type={Pill.TYPE_USER_MENTION}
|
||||||
|
room={this.props.room}
|
||||||
|
url={makeUserPermalink(content.bridgebot)}
|
||||||
|
shouldShowPillAvatar={SettingsStore.getValue("Pill.shouldShowPillAvatar")}
|
||||||
|
/>,
|
||||||
|
})}</li>;
|
||||||
|
|
||||||
|
let networkIcon;
|
||||||
|
|
||||||
|
if (protocol.avatar_url) {
|
||||||
|
const avatarUrl = getHttpUriForMxc(
|
||||||
|
MatrixClientPeg.get().getHomeserverUrl(),
|
||||||
|
protocol.avatar_url, 64, 64, "crop",
|
||||||
|
);
|
||||||
|
|
||||||
|
networkIcon = <BaseAvatar className="protocol-icon"
|
||||||
|
width={48}
|
||||||
|
height={48}
|
||||||
|
resizeMethod='crop'
|
||||||
|
name={ protocolName }
|
||||||
|
idName={ protocolName }
|
||||||
|
url={ avatarUrl }
|
||||||
|
/>;
|
||||||
|
} else {
|
||||||
|
networkIcon = <div className="noProtocolIcon"></div>;
|
||||||
|
}
|
||||||
|
let networkItem = null;
|
||||||
|
if (network) {
|
||||||
|
const networkName = network.displayname || network.id;
|
||||||
|
let networkLink = <span>{networkName}</span>;
|
||||||
|
if (typeof network.external_url === "string" && isUrlPermitted(network.external_url)) {
|
||||||
|
networkLink = <a href={network.external_url} target="_blank" rel="noreferrer noopener">{networkName}</a>
|
||||||
|
}
|
||||||
|
networkItem = _t("Workspace: <networkLink/>", {}, {
|
||||||
|
networkLink: () => networkLink,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let channelLink = <span>{channelName}</span>;
|
||||||
|
if (typeof channel.external_url === "string" && isUrlPermitted(channel.external_url)) {
|
||||||
|
channelLink = <a href={channel.external_url} target="_blank" rel="noreferrer noopener">{channelName}</a>
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = this.props.ev.getId();
|
||||||
|
return (<li key={id}>
|
||||||
|
<div className="column-icon">
|
||||||
|
{networkIcon}
|
||||||
|
</div>
|
||||||
|
<div className="column-data">
|
||||||
|
<h3>{protocolName}</h3>
|
||||||
|
<p className="workspace-channel-details">
|
||||||
|
{networkItem}
|
||||||
|
<span className="channel">{_t("Channel: <channelLink/>", {}, {
|
||||||
|
channelLink: () => channelLink,
|
||||||
|
})}</span>
|
||||||
|
</p>
|
||||||
|
<ul className="metadata">
|
||||||
|
{creator} {bot}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>);
|
||||||
|
}
|
||||||
|
}
|
|
@ -965,10 +965,8 @@
|
||||||
"Upload": "Upload",
|
"Upload": "Upload",
|
||||||
"This bridge was provisioned by <user />.": "This bridge was provisioned by <user />.",
|
"This bridge was provisioned by <user />.": "This bridge was provisioned by <user />.",
|
||||||
"This bridge is managed by <user />.": "This bridge is managed by <user />.",
|
"This bridge is managed by <user />.": "This bridge is managed by <user />.",
|
||||||
"Workspace: %(networkName)s": "Workspace: %(networkName)s",
|
"Workspace: <networkLink/>": "Workspace: <networkLink/>",
|
||||||
"Channel: %(channelName)s": "Channel: %(channelName)s",
|
"Channel: <channelLink/>": "Channel: <channelLink/>",
|
||||||
"Show less": "Show less",
|
|
||||||
"Show more": "Show more",
|
|
||||||
"Failed to upload profile picture!": "Failed to upload profile picture!",
|
"Failed to upload profile picture!": "Failed to upload profile picture!",
|
||||||
"Upload new:": "Upload new:",
|
"Upload new:": "Upload new:",
|
||||||
"No display name": "No display name",
|
"No display name": "No display name",
|
||||||
|
@ -1532,6 +1530,7 @@
|
||||||
"Jump to first invite.": "Jump to first invite.",
|
"Jump to first invite.": "Jump to first invite.",
|
||||||
"Show %(count)s more|other": "Show %(count)s more",
|
"Show %(count)s more|other": "Show %(count)s more",
|
||||||
"Show %(count)s more|one": "Show %(count)s more",
|
"Show %(count)s more|one": "Show %(count)s more",
|
||||||
|
"Show less": "Show less",
|
||||||
"Use default": "Use default",
|
"Use default": "Use default",
|
||||||
"All messages": "All messages",
|
"All messages": "All messages",
|
||||||
"Mentions & Keywords": "Mentions & Keywords",
|
"Mentions & Keywords": "Mentions & Keywords",
|
||||||
|
@ -1594,6 +1593,7 @@
|
||||||
"New published address (e.g. #alias:server)": "New published address (e.g. #alias:server)",
|
"New published address (e.g. #alias:server)": "New published address (e.g. #alias:server)",
|
||||||
"Local Addresses": "Local Addresses",
|
"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)",
|
"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",
|
"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.",
|
"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",
|
"Invalid community ID": "Invalid community ID",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue