diff --git a/README.md b/README.md index 9a410529..066802c0 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,8 @@ You can configure the app by copying `config.sample.json` to down list. Optional. 1. `roomDirectory.serverConfig`: Config for each server in `roomDirectory.servers`. Optional. 1. `roomDirectory.serverConfig..networks`: List of networks (named - in `roomDirectory.networks`) to include for this server. Optional. + in `roomDirectory.networks`) to include for this server. Optional. If set, this will + override any networks sent by the Home Server (eg. if ASes are configured). 1. `roomDirectory.networks`: config for each network type. Optional. 1. `roomDirectory..name`: Human-readable name for the network. Required. 1. `roomDirectory..protocol`: Protocol as given by the server in diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index e369a26e..7960b4cf 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -53,6 +53,7 @@ module.exports = React.createClass({ publicRooms: [], loading: true, network: null, + instance_id: null, roomServer: null, filterString: null, } @@ -131,6 +132,11 @@ module.exports = React.createClass({ if (my_server != MatrixClientPeg.getHomeServerName()) { opts.server = my_server; } + if (this.state.instance_id) { + opts.third_party_instance_id = this.state.instance_id; + } else if (this.state.network !== '_matrix') { + opts.include_all_networks = true; + } if (this.nextBatch) opts.since = this.nextBatch; if (my_filter_string) opts.filter = { generic_search_term: my_filter_string } ; return MatrixClientPeg.get().publicRooms(opts).then((data) => { @@ -231,7 +237,7 @@ module.exports = React.createClass({ } }, - onOptionChange: function(server, network) { + onOptionChange: function(server, network, instance_id) { // clear next batch so we don't try to load more rooms this.nextBatch = null; this.setState({ @@ -241,6 +247,7 @@ module.exports = React.createClass({ publicRooms: [], roomServer: server, network: network, + instance_id: instance_id, }, this.refreshRoomList); // We also refresh the room list each time even though this // filtering is client-side. It hopefully won't be client side @@ -615,7 +622,7 @@ module.exports = React.createClass({ onChange={this.onFilterChange} onClear={this.onFilterClear} onJoinClick={this.onJoinClick} placeholder={placeholder} showJoinButton={showJoinButton} /> - + {content} diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index eb60c4a5..0de48bf6 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -17,6 +17,8 @@ limitations under the License. import React from 'react'; import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg'; +const DEFAULT_ICON_URL = "img/network-matrix.svg"; + export default class NetworkDropdown extends React.Component { constructor(props) { super(props); @@ -28,6 +30,7 @@ export default class NetworkDropdown extends React.Component { this.onRootClick = this.onRootClick.bind(this); this.onDocumentClick = this.onDocumentClick.bind(this); this.onMenuOptionClick = this.onMenuOptionClick.bind(this); + this.onMenuOptionClickProtocolInstance = this.onMenuOptionClickProtocolInstance.bind(this); this.onInputKeyUp = this.onInputKeyUp.bind(this); this.collectRoot = this.collectRoot.bind(this); this.collectInputTextBox = this.collectInputTextBox.bind(this); @@ -98,15 +101,26 @@ export default class NetworkDropdown extends React.Component { ev.preventDefault(); } - onMenuOptionClick(server, network, ev) { + onMenuOptionClick(server, network) { this.setState({ expanded: false, selectedServer: server, selectedNetwork: network, + selectedInstanceId: null, }); this.props.onOptionChange(server, network); } + onMenuOptionClickProtocolInstance(server, instance_id) { + this.setState({ + expanded: false, + selectedServer: server, + selectedNetwork: null, + selectedInstanceId: instance_id, + }); + this.props.onOptionChange(server, null, instance_id); + } + onInputKeyUp(e) { if (e.key == 'Enter') { this.setState({ @@ -144,20 +158,57 @@ export default class NetworkDropdown extends React.Component { servers.unshift(MatrixClientPeg.getHomeServerName()); } + // if the thirdparty/protocols entries have instance_ids, + // we can get the local server listings from here. If not, + // the server is too old. + let use_protocols = true; + for (const proto of Object.keys(this.props.protocols)) { + if (!this.props.protocols[proto].instances) continue; + for (const instance of this.props.protocols[proto].instances) { + if (!instance.instance_id) use_protocols = false; + } + } + + // For our own HS, we can use the instance_ids given in the third party protocols + // response to get the server to filter the room list by network for us (if the + // server is new enough), although for now we prefer the config if it exists. + // For remote HSes, we use the data from the config. for (const server of servers) { options.push(this._makeMenuOption(server, null)); if (this.props.config.serverConfig && this.props.config.serverConfig[server] && this.props.config.serverConfig[server].networks) { for (const network of this.props.config.serverConfig[server].networks) { options.push(this._makeMenuOption(server, network)); } + } else if (server == MatrixClientPeg.getHomeServerName() && use_protocols) { + options.push(this._makeMenuOption(server, '_matrix')); + for (const proto of Object.keys(this.props.protocols)) { + if (!this.props.protocols[proto].instances) continue; + for (const instance of this.props.protocols[proto].instances) { + options.push(this._makeMenuOptionFromProtocolInstance(server, this.props.protocols[proto], instance)); + } + } } } return options; } - _makeMenuOption(server, network, wire_onclick) { - if (wire_onclick === undefined) wire_onclick = true; + _makeMenuOptionFromProtocolInstance(server, protocol, instance, handleClicks) { + if (handleClicks === undefined) handleClicks = true; + + const name = instance.desc; + const icon = ; + const key = instance.instance_id; + const click_handler = handleClicks ? this.onMenuOptionClickProtocolInstance.bind(this, server, instance.instance_id) : null; + + return
+ {icon} + {name} +
; + } + + _makeMenuOption(server, network, handleClicks) { + if (handleClicks === undefined) wire_onclick = true; let icon; let name; let span_class; @@ -189,7 +240,7 @@ export default class NetworkDropdown extends React.Component { span_class = 'mx_NetworkDropdown_menu_network'; } - const click_handler = wire_onclick ? this.onMenuOptionClick.bind(this, server, network) : null; + const click_handler = handleClicks ? this.onMenuOptionClick.bind(this, server, network) : null; let key = server; if (network !== null) { @@ -202,6 +253,24 @@ export default class NetworkDropdown extends React.Component { ; } + _protocolNameForInstanceId(instance_id) { + for (const proto of Object.keys(this.props.protocols)) { + if (!this.props.protocols[proto].instances) continue; + for (const instance of this.props.protocols[proto].instances) { + if (instance.instance_id == instance_id) return proto; + } + } + } + + instanceForInstanceId(instance_id) { + for (const proto of Object.keys(this.props.protocols)) { + if (!this.props.protocols[proto].instances) continue; + for (const instance of this.props.protocols[proto].instances) { + if (instance.instance_id == instance_id) return instance; + } + } + } + render() { let current_value; @@ -216,9 +285,17 @@ export default class NetworkDropdown extends React.Component { placeholder="matrix.org" // 'matrix.org' as an example of an HS name /> } else { - current_value = this._makeMenuOption( - this.state.selectedServer, this.state.selectedNetwork, false - ); + if (this.state.selectedInstanceId) { + const protocolName = this._protocolNameForInstanceId(this.state.selectedInstanceId); + const instance = this.instanceForInstanceId(this.state.selectedInstanceId); + current_value = this._makeMenuOptionFromProtocolInstance( + this.state.selectedServer, this.props.protocols[protocolName], instance, false + ); + } else { + current_value = this._makeMenuOption( + this.state.selectedServer, this.state.selectedNetwork, false + ); + } } return
@@ -234,11 +311,13 @@ export default class NetworkDropdown extends React.Component { NetworkDropdown.propTypes = { onOptionChange: React.PropTypes.func.isRequired, config: React.PropTypes.object, + protocols: React.PropTypes.object, }; NetworkDropdown.defaultProps = { config: { networks: [], - } + }, + protocols: {}, };