Support room dir 3rd party network filtering

As per https://github.com/matrix-org/synapse/pull/1676

The existing local config system still exists and is used for
remote home server directories (since /thirdparty/protocols
doesn't support listing remote home servers, and also because
people are using it).
This commit is contained in:
David Baker 2016-12-14 15:41:15 +00:00
parent 2740013625
commit f5bd8abfda
3 changed files with 93 additions and 7 deletions

View File

@ -89,7 +89,8 @@ You can configure the app by copying `config.sample.json` to
down list. Optional. down list. Optional.
1. `roomDirectory.serverConfig`: Config for each server in `roomDirectory.servers`. Optional. 1. `roomDirectory.serverConfig`: Config for each server in `roomDirectory.servers`. Optional.
1. `roomDirectory.serverConfig.<server_name>.networks`: List of networks (named 1. `roomDirectory.serverConfig.<server_name>.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.networks`: config for each network type. Optional.
1. `roomDirectory.<network_type>.name`: Human-readable name for the network. Required. 1. `roomDirectory.<network_type>.name`: Human-readable name for the network. Required.
1. `roomDirectory.<network_type>.protocol`: Protocol as given by the server in 1. `roomDirectory.<network_type>.protocol`: Protocol as given by the server in

View File

@ -131,6 +131,11 @@ module.exports = React.createClass({
if (my_server != MatrixClientPeg.getHomeServerName()) { if (my_server != MatrixClientPeg.getHomeServerName()) {
opts.server = my_server; 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 (this.nextBatch) opts.since = this.nextBatch;
if (my_filter_string) opts.filter = { generic_search_term: my_filter_string } ; if (my_filter_string) opts.filter = { generic_search_term: my_filter_string } ;
return MatrixClientPeg.get().publicRooms(opts).then((data) => { return MatrixClientPeg.get().publicRooms(opts).then((data) => {
@ -231,7 +236,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 // clear next batch so we don't try to load more rooms
this.nextBatch = null; this.nextBatch = null;
this.setState({ this.setState({
@ -241,6 +246,7 @@ module.exports = React.createClass({
publicRooms: [], publicRooms: [],
roomServer: server, roomServer: server,
network: network, network: network,
instance_id: instance_id,
}, this.refreshRoomList); }, this.refreshRoomList);
// We also refresh the room list each time even though this // We also refresh the room list each time even though this
// filtering is client-side. It hopefully won't be client side // filtering is client-side. It hopefully won't be client side
@ -615,7 +621,7 @@ module.exports = React.createClass({
onChange={this.onFilterChange} onClear={this.onFilterClear} onJoinClick={this.onJoinClick} onChange={this.onFilterChange} onClear={this.onFilterClear} onJoinClick={this.onJoinClick}
placeholder={placeholder} showJoinButton={showJoinButton} placeholder={placeholder} showJoinButton={showJoinButton}
/> />
<NetworkDropdown config={this.props.config} onOptionChange={this.onOptionChange} /> <NetworkDropdown config={this.props.config} protocols={this.protocols} onOptionChange={this.onOptionChange} />
</div> </div>
{content} {content}
</div> </div>

View File

@ -17,6 +17,8 @@ limitations under the License.
import React from 'react'; import React from 'react';
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg'; import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
const DEFAULT_ICON_URL = "img/network-matrix.svg";
export default class NetworkDropdown extends React.Component { export default class NetworkDropdown extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
@ -28,6 +30,7 @@ export default class NetworkDropdown extends React.Component {
this.onRootClick = this.onRootClick.bind(this); this.onRootClick = this.onRootClick.bind(this);
this.onDocumentClick = this.onDocumentClick.bind(this); this.onDocumentClick = this.onDocumentClick.bind(this);
this.onMenuOptionClick = this.onMenuOptionClick.bind(this); this.onMenuOptionClick = this.onMenuOptionClick.bind(this);
this.onMenuOptionClickProtocolInstance = this.onMenuOptionClickProtocolInstance.bind(this);
this.onInputKeyUp = this.onInputKeyUp.bind(this); this.onInputKeyUp = this.onInputKeyUp.bind(this);
this.collectRoot = this.collectRoot.bind(this); this.collectRoot = this.collectRoot.bind(this);
this.collectInputTextBox = this.collectInputTextBox.bind(this); this.collectInputTextBox = this.collectInputTextBox.bind(this);
@ -103,10 +106,21 @@ export default class NetworkDropdown extends React.Component {
expanded: false, expanded: false,
selectedServer: server, selectedServer: server,
selectedNetwork: network, selectedNetwork: network,
selectedInstanceId: null,
}); });
this.props.onOptionChange(server, network); this.props.onOptionChange(server, network);
} }
onMenuOptionClickProtocolInstance(server, instance_id, ev) {
this.setState({
expanded: false,
selectedServer: server,
selectedNetwork: null,
selectedInstanceId: instance_id,
});
this.props.onOptionChange(server, null, instance_id);
}
onInputKeyUp(e) { onInputKeyUp(e) {
if (e.key == 'Enter') { if (e.key == 'Enter') {
this.setState({ this.setState({
@ -144,18 +158,55 @@ export default class NetworkDropdown extends React.Component {
servers.unshift(MatrixClientPeg.getHomeServerName()); 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) { for (const server of servers) {
options.push(this._makeMenuOption(server, null)); options.push(this._makeMenuOption(server, null));
if (this.props.config.serverConfig && this.props.config.serverConfig[server] && this.props.config.serverConfig[server].networks) { 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) { for (const network of this.props.config.serverConfig[server].networks) {
options.push(this._makeMenuOption(server, network)); 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; return options;
} }
_makeMenuOptionFromProtocolInstance(server, protocol, instance, wire_onclick) {
if (wire_onclick === undefined) wire_onclick = true;
const name = instance.desc;
const icon = <img src={protocol.icon || DEFAULT_ICON_URL} width="16" />;
const key = instance.instance_id;
const click_handler = wire_onclick ? this.onMenuOptionClickProtocolInstance.bind(this, server, instance.instance_id) : null;
return <div key={key} className="mx_NetworkDropdown_networkoption" onClick={click_handler}>
{icon}
<span className="mx_NetworkDropdown_menu_network">{name}</span>
</div>;
}
_makeMenuOption(server, network, wire_onclick) { _makeMenuOption(server, network, wire_onclick) {
if (wire_onclick === undefined) wire_onclick = true; if (wire_onclick === undefined) wire_onclick = true;
let icon; let icon;
@ -202,6 +253,24 @@ export default class NetworkDropdown extends React.Component {
</div>; </div>;
} }
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() { render() {
let current_value; 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 placeholder="matrix.org" // 'matrix.org' as an example of an HS name
/> />
} else { } else {
current_value = this._makeMenuOption( if (this.state.selectedInstanceId) {
this.state.selectedServer, this.state.selectedNetwork, false 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
);
} else {
current_value = this._makeMenuOption(
this.state.selectedServer, this.state.selectedNetwork, false
);
}
} }
return <div className="mx_NetworkDropdown" ref={this.collectRoot}> return <div className="mx_NetworkDropdown" ref={this.collectRoot}>
@ -234,11 +311,13 @@ export default class NetworkDropdown extends React.Component {
NetworkDropdown.propTypes = { NetworkDropdown.propTypes = {
onOptionChange: React.PropTypes.func.isRequired, onOptionChange: React.PropTypes.func.isRequired,
config: React.PropTypes.object, config: React.PropTypes.object,
protocols: React.PropTypes.object,
}; };
NetworkDropdown.defaultProps = { NetworkDropdown.defaultProps = {
config: { config: {
networks: [], networks: [],
} },
protocols: {},
}; };