mirror of
https://github.com/element-hq/element-web
synced 2024-11-23 17:56:01 +03:00
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');
|
||||
}
|
||||
|
||||
.mx_RoomSettingsDialog_bridgesIcon::before {
|
||||
// This icon is pants, please improve :)
|
||||
mask-image: url('$(res)/img/feather-customised/bridge.svg');
|
||||
}
|
||||
|
||||
.mx_RoomSettingsDialog_warningIcon::before {
|
||||
mask-image: url('$(res)/img/feather-customised/warning-triangle.svg');
|
||||
}
|
||||
|
@ -50,3 +55,17 @@ limitations under the License.
|
|||
mask-size: 36px;
|
||||
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 SecurityRoomSettingsTab from "../settings/tabs/room/SecurityRoomSettingsTab";
|
||||
import NotificationSettingsTab from "../settings/tabs/room/NotificationSettingsTab";
|
||||
import BridgeSettingsTab from "../settings/tabs/room/BridgeSettingsTab";
|
||||
import sdk from "../../../index";
|
||||
import MatrixClientPeg from "../../../MatrixClientPeg";
|
||||
import dis from "../../../dispatcher";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
|
||||
export default class RoomSettingsDialog extends React.Component {
|
||||
static propTypes = {
|
||||
|
@ -52,6 +54,9 @@ export default class RoomSettingsDialog extends React.Component {
|
|||
|
||||
_getTabs() {
|
||||
const tabs = [];
|
||||
const featureFlag = SettingsStore.isFeatureEnabled("feature_bridge_state");
|
||||
const shouldShowBridgeIcon = featureFlag &&
|
||||
BridgeSettingsTab.getBridgeStateEvents(this.props.roomId).length > 0;
|
||||
|
||||
tabs.push(new Tab(
|
||||
_td("General"),
|
||||
|
@ -73,6 +78,15 @@ export default class RoomSettingsDialog extends React.Component {
|
|||
"mx_RoomSettingsDialog_rolesIcon",
|
||||
<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(
|
||||
_td("Advanced"),
|
||||
"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)",
|
||||
"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)",
|
||||
"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",
|
||||
"Enable Emoji suggestions while typing": "Enable Emoji suggestions while typing",
|
||||
"Use compact timeline layout": "Use compact timeline layout",
|
||||
|
@ -763,6 +764,13 @@
|
|||
"Room version:": "Room version:",
|
||||
"Developer options": "Developer options",
|
||||
"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",
|
||||
"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",
|
||||
|
|
|
@ -155,6 +155,12 @@ export const SETTINGS = {
|
|||
displayName: _td("Enable local event indexing and E2EE search (requires restart)"),
|
||||
default: false,
|
||||
},
|
||||
"feature_bridge_state": {
|
||||
isFeature: true,
|
||||
supportedLevels: LEVELS_FEATURE,
|
||||
displayName: _td("Show info about bridges in room settings"),
|
||||
default: false,
|
||||
},
|
||||
"useCiderComposer": {
|
||||
displayName: _td("Use the new, faster, composer for writing messages"),
|
||||
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
|
||||
|
|
Loading…
Reference in a new issue