Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 781b69f

Browse files
authored
Merge pull request #3693 from matrix-org/hs/bridge-info
Bridge info settings tab
2 parents 449efec + 7f0ed05 commit 781b69f

File tree

6 files changed

+263
-0
lines changed

6 files changed

+263
-0
lines changed

res/css/views/dialogs/_RoomSettingsDialog.scss

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ limitations under the License.
2929
mask-image: url('$(res)/img/feather-customised/users-sm.svg');
3030
}
3131

32+
.mx_RoomSettingsDialog_bridgesIcon::before {
33+
// This icon is pants, please improve :)
34+
mask-image: url('$(res)/img/feather-customised/bridge.svg');
35+
}
36+
3237
.mx_RoomSettingsDialog_warningIcon::before {
3338
mask-image: url('$(res)/img/feather-customised/warning-triangle.svg');
3439
}
@@ -50,3 +55,17 @@ limitations under the License.
5055
mask-size: 36px;
5156
mask-position: center;
5257
}
58+
59+
.mx_RoomSettingsDialog_BridgeList {
60+
padding: 0;
61+
}
62+
63+
.mx_RoomSettingsDialog_BridgeList li {
64+
list-style-type: none;
65+
padding: 5px;
66+
margin-bottom: 5px;
67+
border-width: 1px 0px;
68+
border-color: #dee1f3;
69+
border-style: solid;
70+
}
71+
Lines changed: 50 additions & 0 deletions
Loading

src/components/views/dialogs/RoomSettingsDialog.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ import RolesRoomSettingsTab from "../settings/tabs/room/RolesRoomSettingsTab";
2424
import GeneralRoomSettingsTab from "../settings/tabs/room/GeneralRoomSettingsTab";
2525
import SecurityRoomSettingsTab from "../settings/tabs/room/SecurityRoomSettingsTab";
2626
import NotificationSettingsTab from "../settings/tabs/room/NotificationSettingsTab";
27+
import BridgeSettingsTab from "../settings/tabs/room/BridgeSettingsTab";
2728
import sdk from "../../../index";
2829
import MatrixClientPeg from "../../../MatrixClientPeg";
2930
import dis from "../../../dispatcher";
31+
import SettingsStore from "../../../settings/SettingsStore";
3032

3133
export default class RoomSettingsDialog extends React.Component {
3234
static propTypes = {
@@ -52,6 +54,9 @@ export default class RoomSettingsDialog extends React.Component {
5254

5355
_getTabs() {
5456
const tabs = [];
57+
const featureFlag = SettingsStore.isFeatureEnabled("feature_bridge_state");
58+
const shouldShowBridgeIcon = featureFlag &&
59+
BridgeSettingsTab.getBridgeStateEvents(this.props.roomId).length > 0;
5560

5661
tabs.push(new Tab(
5762
_td("General"),
@@ -73,6 +78,15 @@ export default class RoomSettingsDialog extends React.Component {
7378
"mx_RoomSettingsDialog_rolesIcon",
7479
<NotificationSettingsTab roomId={this.props.roomId} />,
7580
));
81+
82+
if (shouldShowBridgeIcon) {
83+
tabs.push(new Tab(
84+
_td("Bridge Info"),
85+
"mx_RoomSettingsDialog_bridgesIcon",
86+
<BridgeSettingsTab roomId={this.props.roomId} />,
87+
));
88+
}
89+
7690
tabs.push(new Tab(
7791
_td("Advanced"),
7892
"mx_RoomSettingsDialog_warningIcon",
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
Copyright 2019 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import React from 'react';
18+
import PropTypes from 'prop-types';
19+
import {_t} from "../../../../../languageHandler";
20+
import MatrixClientPeg from "../../../../../MatrixClientPeg";
21+
import Pill from "../../../elements/Pill";
22+
import {makeUserPermalink} from "../../../../../utils/permalinks/Permalinks";
23+
import BaseAvatar from "../../../avatars/BaseAvatar";
24+
import { ContentRepo } from "matrix-js-sdk";
25+
26+
const BRIDGE_EVENT_TYPES = [
27+
"uk.half-shot.bridge",
28+
// m.bridge
29+
];
30+
31+
export default class BridgeSettingsTab extends React.Component {
32+
static propTypes = {
33+
roomId: PropTypes.string.isRequired,
34+
};
35+
36+
_renderBridgeCard(event, room) {
37+
const content = event.getContent();
38+
if (!content || !content.channel || !content.protocol) {
39+
return null;
40+
}
41+
const { channel, network } = content;
42+
const protocolName = content.protocol.displayname || content.protocol.id;
43+
const channelName = channel.displayname || channel.id;
44+
const networkName = network ? network.displayname || network.id : protocolName;
45+
46+
let creator = null;
47+
if (content.creator) {
48+
creator = <p> { _t("This bridge was provisioned by <user />", {}, {
49+
user: <Pill
50+
type={Pill.TYPE_USER_MENTION}
51+
room={room}
52+
url={makeUserPermalink(content.creator)}
53+
shouldShowPillAvatar={true}
54+
/>,
55+
})}</p>;
56+
}
57+
58+
const bot = (<p> {_t("This bridge is managed by <user />.", {}, {
59+
user: <Pill
60+
type={Pill.TYPE_USER_MENTION}
61+
room={room}
62+
url={makeUserPermalink(event.getSender())}
63+
shouldShowPillAvatar={true}
64+
/>,
65+
})} </p>);
66+
let channelLink = channelName;
67+
if (channel.external_url) {
68+
channelLink = <a target="_blank" href={channel.external_url} rel="noopener">{channelName}</a>;
69+
}
70+
71+
let networkLink = networkName;
72+
if (network && network.external_url) {
73+
networkLink = <a target="_blank" href={network.external_url} rel="noopener">{networkName}</a>;
74+
}
75+
76+
const chanAndNetworkInfo = (
77+
_t("Bridged into <channelLink /> <networkLink />, on <protocolName />", {}, {
78+
channelLink,
79+
networkLink,
80+
protocolName,
81+
})
82+
);
83+
84+
let networkIcon = null;
85+
if (networkName && network.avatar) {
86+
const avatarUrl = ContentRepo.getHttpUriForMxc(
87+
MatrixClientPeg.get().getHomeserverUrl(),
88+
network.avatar, 32, 32, "crop",
89+
);
90+
networkIcon = <BaseAvatar
91+
width={32}
92+
height={32}
93+
resizeMethod='crop'
94+
name={ networkName }
95+
idName={ networkName }
96+
url={ avatarUrl }
97+
/>;
98+
}
99+
100+
let channelIcon = null;
101+
if (channel.avatar) {
102+
const avatarUrl = ContentRepo.getHttpUriForMxc(
103+
MatrixClientPeg.get().getHomeserverUrl(),
104+
channel.avatar, 32, 32, "crop",
105+
);
106+
channelIcon = <BaseAvatar
107+
width={32}
108+
height={32}
109+
resizeMethod='crop'
110+
name={ networkName }
111+
idName={ networkName }
112+
url={ avatarUrl }
113+
/>;
114+
}
115+
116+
const heading = _t("Connected to <channelIcon /> <channelName /> on <networkIcon /> <networkName />", { }, {
117+
channelIcon,
118+
channelName,
119+
networkName,
120+
networkIcon,
121+
});
122+
123+
return (<li key={event.stateKey}>
124+
<div>
125+
<h3>{heading}</h3>
126+
<p>{_t("Connected via %(protocolName)s", { protocolName })}</p>
127+
<details>
128+
{creator}
129+
{bot}
130+
<p>{chanAndNetworkInfo}</p>
131+
</details>
132+
</div>
133+
</li>);
134+
}
135+
136+
static getBridgeStateEvents(roomId) {
137+
const client = MatrixClientPeg.get();
138+
const roomState = (client.getRoom(roomId)).currentState;
139+
140+
const bridgeEvents = Array.concat(...BRIDGE_EVENT_TYPES.map((typeName) =>
141+
Object.values(roomState.events[typeName] || {}),
142+
));
143+
144+
return bridgeEvents;
145+
}
146+
147+
render() {
148+
// This settings tab will only be invoked if the following function returns more
149+
// than 0 events, so no validation is needed at this stage.
150+
const bridgeEvents = BridgeSettingsTab.getBridgeStateEvents(this.props.roomId);
151+
const client = MatrixClientPeg.get();
152+
const room = client.getRoom(this.props.roomId);
153+
154+
return (
155+
<div className="mx_SettingsTab">
156+
<div className="mx_SettingsTab_heading">{_t("Bridge Info")}</div>
157+
<div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'>
158+
<p>{ _t("Below is a list of bridges connected to this room.") }</p>
159+
<ul className="mx_RoomSettingsDialog_BridgeList">
160+
{ bridgeEvents.map((event) => this._renderBridgeCard(event, room)) }
161+
</ul>
162+
</div>
163+
</div>
164+
);
165+
}
166+
}

src/i18n/strings/en_EN.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@
361361
"New DM invite dialog (under development)": "New DM invite dialog (under development)",
362362
"Enable cross-signing to verify per-user instead of per-device (in development)": "Enable cross-signing to verify per-user instead of per-device (in development)",
363363
"Enable local event indexing and E2EE search (requires restart)": "Enable local event indexing and E2EE search (requires restart)",
364+
"Show info about bridges in room settings": "Show info about bridges in room settings",
364365
"Use the new, faster, composer for writing messages": "Use the new, faster, composer for writing messages",
365366
"Enable Emoji suggestions while typing": "Enable Emoji suggestions while typing",
366367
"Use compact timeline layout": "Use compact timeline layout",
@@ -763,6 +764,13 @@
763764
"Room version:": "Room version:",
764765
"Developer options": "Developer options",
765766
"Open Devtools": "Open Devtools",
767+
"This bridge was provisioned by <user />": "This bridge was provisioned by <user />",
768+
"This bridge is managed by <user />.": "This bridge is managed by <user />.",
769+
"Bridged into <channelLink /> <networkLink />, on <protocolName />": "Bridged into <channelLink /> <networkLink />, on <protocolName />",
770+
"Connected to <channelIcon /> <channelName /> on <networkIcon /> <networkName />": "Connected to <channelIcon /> <channelName /> on <networkIcon /> <networkName />",
771+
"Connected via %(protocolName)s": "Connected via %(protocolName)s",
772+
"Bridge Info": "Bridge Info",
773+
"Below is a list of bridges connected to this room.": "Below is a list of bridges connected to this room.",
766774
"Room Addresses": "Room Addresses",
767775
"Publish this room to the public in %(domain)s's room directory?": "Publish this room to the public in %(domain)s's room directory?",
768776
"URL Previews": "URL Previews",

src/settings/Settings.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ export const SETTINGS = {
155155
displayName: _td("Enable local event indexing and E2EE search (requires restart)"),
156156
default: false,
157157
},
158+
"feature_bridge_state": {
159+
isFeature: true,
160+
supportedLevels: LEVELS_FEATURE,
161+
displayName: _td("Show info about bridges in room settings"),
162+
default: false,
163+
},
158164
"useCiderComposer": {
159165
displayName: _td("Use the new, faster, composer for writing messages"),
160166
supportedLevels: LEVELS_ACCOUNT_SETTINGS,

0 commit comments

Comments
 (0)