mirror of https://github.com/vector-im/riot-web
				
				
				
			
						commit
						781b69f4e3
					
				|  | @ -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; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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", | ||||
|  |  | |||
|  | @ -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 New Issue
	
	 Travis Ralston
						Travis Ralston