Merge pull request #3693 from matrix-org/hs/bridge-info
Bridge info settings tab
This commit is contained in:
commit
781b69f4e3
6 changed files with 263 additions and 0 deletions
|
@ -29,6 +29,11 @@ limitations under the License.
|
||||||
mask-image: url('$(res)/img/feather-customised/users-sm.svg');
|
mask-image: url('$(res)/img/feather-customised/users-sm.svg');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_RoomSettingsDialog_bridgesIcon::before {
|
||||||
|
// This icon is pants, please improve :)
|
||||||
|
mask-image: url('$(res)/img/feather-customised/bridge.svg');
|
||||||
|
}
|
||||||
|
|
||||||
.mx_RoomSettingsDialog_warningIcon::before {
|
.mx_RoomSettingsDialog_warningIcon::before {
|
||||||
mask-image: url('$(res)/img/feather-customised/warning-triangle.svg');
|
mask-image: url('$(res)/img/feather-customised/warning-triangle.svg');
|
||||||
}
|
}
|
||||||
|
@ -50,3 +55,17 @@ limitations under the License.
|
||||||
mask-size: 36px;
|
mask-size: 36px;
|
||||||
mask-position: center;
|
mask-position: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_RoomSettingsDialog_BridgeList {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomSettingsDialog_BridgeList li {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
border-width: 1px 0px;
|
||||||
|
border-color: #dee1f3;
|
||||||
|
border-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
50
res/img/feather-customised/bridge.svg
Normal file
50
res/img/feather-customised/bridge.svg
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
id="svg8"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 5.487504 5.7341776"
|
||||||
|
height="5.7341776mm"
|
||||||
|
width="5.487504mm">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
transform="translate(14.166523,-96.032669)"
|
||||||
|
id="layer1">
|
||||||
|
<rect
|
||||||
|
y="99.461258"
|
||||||
|
x="-10.861272"
|
||||||
|
height="2.0555882"
|
||||||
|
width="1.9322528"
|
||||||
|
id="rect831-6"
|
||||||
|
style="fill:none;stroke:#b8bec9;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" />
|
||||||
|
<path
|
||||||
|
id="path883"
|
||||||
|
d="m -11.98427,98.338257 1.122998,1.122998"
|
||||||
|
style="fill:#b8bec9;fill-opacity:1;stroke:#b8bec9;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||||
|
<rect
|
||||||
|
transform="scale(-1)"
|
||||||
|
y="-98.338257"
|
||||||
|
x="11.98427"
|
||||||
|
height="2.0555882"
|
||||||
|
width="1.9322529"
|
||||||
|
id="rect831-6-7"
|
||||||
|
style="fill:none;stroke:#b8bec9;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -24,9 +24,11 @@ import RolesRoomSettingsTab from "../settings/tabs/room/RolesRoomSettingsTab";
|
||||||
import GeneralRoomSettingsTab from "../settings/tabs/room/GeneralRoomSettingsTab";
|
import GeneralRoomSettingsTab from "../settings/tabs/room/GeneralRoomSettingsTab";
|
||||||
import SecurityRoomSettingsTab from "../settings/tabs/room/SecurityRoomSettingsTab";
|
import SecurityRoomSettingsTab from "../settings/tabs/room/SecurityRoomSettingsTab";
|
||||||
import NotificationSettingsTab from "../settings/tabs/room/NotificationSettingsTab";
|
import NotificationSettingsTab from "../settings/tabs/room/NotificationSettingsTab";
|
||||||
|
import BridgeSettingsTab from "../settings/tabs/room/BridgeSettingsTab";
|
||||||
import sdk from "../../../index";
|
import sdk from "../../../index";
|
||||||
import MatrixClientPeg from "../../../MatrixClientPeg";
|
import MatrixClientPeg from "../../../MatrixClientPeg";
|
||||||
import dis from "../../../dispatcher";
|
import dis from "../../../dispatcher";
|
||||||
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
|
|
||||||
export default class RoomSettingsDialog extends React.Component {
|
export default class RoomSettingsDialog extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -52,6 +54,9 @@ export default class RoomSettingsDialog extends React.Component {
|
||||||
|
|
||||||
_getTabs() {
|
_getTabs() {
|
||||||
const tabs = [];
|
const tabs = [];
|
||||||
|
const featureFlag = SettingsStore.isFeatureEnabled("feature_bridge_state");
|
||||||
|
const shouldShowBridgeIcon = featureFlag &&
|
||||||
|
BridgeSettingsTab.getBridgeStateEvents(this.props.roomId).length > 0;
|
||||||
|
|
||||||
tabs.push(new Tab(
|
tabs.push(new Tab(
|
||||||
_td("General"),
|
_td("General"),
|
||||||
|
@ -73,6 +78,15 @@ export default class RoomSettingsDialog extends React.Component {
|
||||||
"mx_RoomSettingsDialog_rolesIcon",
|
"mx_RoomSettingsDialog_rolesIcon",
|
||||||
<NotificationSettingsTab roomId={this.props.roomId} />,
|
<NotificationSettingsTab roomId={this.props.roomId} />,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
if (shouldShowBridgeIcon) {
|
||||||
|
tabs.push(new Tab(
|
||||||
|
_td("Bridge Info"),
|
||||||
|
"mx_RoomSettingsDialog_bridgesIcon",
|
||||||
|
<BridgeSettingsTab roomId={this.props.roomId} />,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
tabs.push(new Tab(
|
tabs.push(new Tab(
|
||||||
_td("Advanced"),
|
_td("Advanced"),
|
||||||
"mx_RoomSettingsDialog_warningIcon",
|
"mx_RoomSettingsDialog_warningIcon",
|
||||||
|
|
166
src/components/views/settings/tabs/room/BridgeSettingsTab.js
Normal file
166
src/components/views/settings/tabs/room/BridgeSettingsTab.js
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 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 {_t} from "../../../../../languageHandler";
|
||||||
|
import MatrixClientPeg from "../../../../../MatrixClientPeg";
|
||||||
|
import Pill from "../../../elements/Pill";
|
||||||
|
import {makeUserPermalink} from "../../../../../utils/permalinks/Permalinks";
|
||||||
|
import BaseAvatar from "../../../avatars/BaseAvatar";
|
||||||
|
import { ContentRepo } from "matrix-js-sdk";
|
||||||
|
|
||||||
|
const BRIDGE_EVENT_TYPES = [
|
||||||
|
"uk.half-shot.bridge",
|
||||||
|
// m.bridge
|
||||||
|
];
|
||||||
|
|
||||||
|
export default class BridgeSettingsTab extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
roomId: PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
_renderBridgeCard(event, room) {
|
||||||
|
const content = event.getContent();
|
||||||
|
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 = <p> { _t("This bridge was provisioned by <user />", {}, {
|
||||||
|
user: <Pill
|
||||||
|
type={Pill.TYPE_USER_MENTION}
|
||||||
|
room={room}
|
||||||
|
url={makeUserPermalink(content.creator)}
|
||||||
|
shouldShowPillAvatar={true}
|
||||||
|
/>,
|
||||||
|
})}</p>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bot = (<p> {_t("This bridge is managed by <user />.", {}, {
|
||||||
|
user: <Pill
|
||||||
|
type={Pill.TYPE_USER_MENTION}
|
||||||
|
room={room}
|
||||||
|
url={makeUserPermalink(event.getSender())}
|
||||||
|
shouldShowPillAvatar={true}
|
||||||
|
/>,
|
||||||
|
})} </p>);
|
||||||
|
let channelLink = channelName;
|
||||||
|
if (channel.external_url) {
|
||||||
|
channelLink = <a target="_blank" href={channel.external_url} rel="noopener">{channelName}</a>;
|
||||||
|
}
|
||||||
|
|
||||||
|
let networkLink = networkName;
|
||||||
|
if (network && network.external_url) {
|
||||||
|
networkLink = <a target="_blank" href={network.external_url} rel="noopener">{networkName}</a>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const chanAndNetworkInfo = (
|
||||||
|
_t("Bridged into <channelLink /> <networkLink />, on <protocolName />", {}, {
|
||||||
|
channelLink,
|
||||||
|
networkLink,
|
||||||
|
protocolName,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
let networkIcon = null;
|
||||||
|
if (networkName && network.avatar) {
|
||||||
|
const avatarUrl = ContentRepo.getHttpUriForMxc(
|
||||||
|
MatrixClientPeg.get().getHomeserverUrl(),
|
||||||
|
network.avatar, 32, 32, "crop",
|
||||||
|
);
|
||||||
|
networkIcon = <BaseAvatar
|
||||||
|
width={32}
|
||||||
|
height={32}
|
||||||
|
resizeMethod='crop'
|
||||||
|
name={ networkName }
|
||||||
|
idName={ networkName }
|
||||||
|
url={ avatarUrl }
|
||||||
|
/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
let channelIcon = null;
|
||||||
|
if (channel.avatar) {
|
||||||
|
const avatarUrl = ContentRepo.getHttpUriForMxc(
|
||||||
|
MatrixClientPeg.get().getHomeserverUrl(),
|
||||||
|
channel.avatar, 32, 32, "crop",
|
||||||
|
);
|
||||||
|
channelIcon = <BaseAvatar
|
||||||
|
width={32}
|
||||||
|
height={32}
|
||||||
|
resizeMethod='crop'
|
||||||
|
name={ networkName }
|
||||||
|
idName={ networkName }
|
||||||
|
url={ avatarUrl }
|
||||||
|
/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const heading = _t("Connected to <channelIcon /> <channelName /> on <networkIcon /> <networkName />", { }, {
|
||||||
|
channelIcon,
|
||||||
|
channelName,
|
||||||
|
networkName,
|
||||||
|
networkIcon,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (<li key={event.stateKey}>
|
||||||
|
<div>
|
||||||
|
<h3>{heading}</h3>
|
||||||
|
<p>{_t("Connected via %(protocolName)s", { protocolName })}</p>
|
||||||
|
<details>
|
||||||
|
{creator}
|
||||||
|
{bot}
|
||||||
|
<p>{chanAndNetworkInfo}</p>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</li>);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getBridgeStateEvents(roomId) {
|
||||||
|
const client = MatrixClientPeg.get();
|
||||||
|
const roomState = (client.getRoom(roomId)).currentState;
|
||||||
|
|
||||||
|
const bridgeEvents = Array.concat(...BRIDGE_EVENT_TYPES.map((typeName) =>
|
||||||
|
Object.values(roomState.events[typeName] || {}),
|
||||||
|
));
|
||||||
|
|
||||||
|
return bridgeEvents;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
// This settings tab will only be invoked if the following function returns more
|
||||||
|
// than 0 events, so no validation is needed at this stage.
|
||||||
|
const bridgeEvents = BridgeSettingsTab.getBridgeStateEvents(this.props.roomId);
|
||||||
|
const client = MatrixClientPeg.get();
|
||||||
|
const room = client.getRoom(this.props.roomId);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mx_SettingsTab">
|
||||||
|
<div className="mx_SettingsTab_heading">{_t("Bridge Info")}</div>
|
||||||
|
<div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'>
|
||||||
|
<p>{ _t("Below is a list of bridges connected to this room.") }</p>
|
||||||
|
<ul className="mx_RoomSettingsDialog_BridgeList">
|
||||||
|
{ bridgeEvents.map((event) => this._renderBridgeCard(event, room)) }
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -361,6 +361,7 @@
|
||||||
"New DM invite dialog (under development)": "New DM invite dialog (under development)",
|
"New DM invite dialog (under development)": "New DM invite dialog (under development)",
|
||||||
"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)",
|
"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)",
|
||||||
"Enable local event indexing and E2EE search (requires restart)": "Enable local event indexing and E2EE search (requires restart)",
|
"Enable local event indexing and E2EE search (requires restart)": "Enable local event indexing and E2EE search (requires restart)",
|
||||||
|
"Show info about bridges in room settings": "Show info about bridges in room settings",
|
||||||
"Use the new, faster, composer for writing messages": "Use the new, faster, composer for writing messages",
|
"Use the new, faster, composer for writing messages": "Use the new, faster, composer for writing messages",
|
||||||
"Enable Emoji suggestions while typing": "Enable Emoji suggestions while typing",
|
"Enable Emoji suggestions while typing": "Enable Emoji suggestions while typing",
|
||||||
"Use compact timeline layout": "Use compact timeline layout",
|
"Use compact timeline layout": "Use compact timeline layout",
|
||||||
|
@ -763,6 +764,13 @@
|
||||||
"Room version:": "Room version:",
|
"Room version:": "Room version:",
|
||||||
"Developer options": "Developer options",
|
"Developer options": "Developer options",
|
||||||
"Open Devtools": "Open Devtools",
|
"Open Devtools": "Open Devtools",
|
||||||
|
"This bridge was provisioned by <user />": "This bridge was provisioned by <user />",
|
||||||
|
"This bridge is managed by <user />.": "This bridge is managed by <user />.",
|
||||||
|
"Bridged into <channelLink /> <networkLink />, on <protocolName />": "Bridged into <channelLink /> <networkLink />, on <protocolName />",
|
||||||
|
"Connected to <channelIcon /> <channelName /> on <networkIcon /> <networkName />": "Connected to <channelIcon /> <channelName /> on <networkIcon /> <networkName />",
|
||||||
|
"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.",
|
||||||
"Room Addresses": "Room Addresses",
|
"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?",
|
"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",
|
"URL Previews": "URL Previews",
|
||||||
|
|
|
@ -155,6 +155,12 @@ export const SETTINGS = {
|
||||||
displayName: _td("Enable local event indexing and E2EE search (requires restart)"),
|
displayName: _td("Enable local event indexing and E2EE search (requires restart)"),
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
"feature_bridge_state": {
|
||||||
|
isFeature: true,
|
||||||
|
supportedLevels: LEVELS_FEATURE,
|
||||||
|
displayName: _td("Show info about bridges in room settings"),
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
"useCiderComposer": {
|
"useCiderComposer": {
|
||||||
displayName: _td("Use the new, faster, composer for writing messages"),
|
displayName: _td("Use the new, faster, composer for writing messages"),
|
||||||
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
|
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
|
||||||
|
|
Loading…
Reference in a new issue