Merge pull request #2747 from vector-im/dbkr/third_party_filter
Support room dir 3rd party network filtering
This commit is contained in:
commit
61f9966fe0
3 changed files with 98 additions and 11 deletions
|
@ -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
|
||||||
|
|
|
@ -53,6 +53,7 @@ module.exports = React.createClass({
|
||||||
publicRooms: [],
|
publicRooms: [],
|
||||||
loading: true,
|
loading: true,
|
||||||
network: null,
|
network: null,
|
||||||
|
instance_id: null,
|
||||||
roomServer: null,
|
roomServer: null,
|
||||||
filterString: null,
|
filterString: null,
|
||||||
}
|
}
|
||||||
|
@ -131,6 +132,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 +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
|
// clear next batch so we don't try to load more rooms
|
||||||
this.nextBatch = null;
|
this.nextBatch = null;
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -241,6 +247,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 +622,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>
|
||||||
|
|
|
@ -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);
|
||||||
|
@ -98,15 +101,26 @@ export default class NetworkDropdown extends React.Component {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
onMenuOptionClick(server, network, ev) {
|
onMenuOptionClick(server, network) {
|
||||||
this.setState({
|
this.setState({
|
||||||
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) {
|
||||||
|
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,20 +158,57 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
_makeMenuOption(server, network, wire_onclick) {
|
_makeMenuOptionFromProtocolInstance(server, protocol, instance, handleClicks) {
|
||||||
if (wire_onclick === undefined) wire_onclick = true;
|
if (handleClicks === undefined) handleClicks = true;
|
||||||
|
|
||||||
|
const name = instance.desc;
|
||||||
|
const icon = <img src={protocol.icon || DEFAULT_ICON_URL} width="16" />;
|
||||||
|
const key = instance.instance_id;
|
||||||
|
const click_handler = handleClicks ? 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, handleClicks) {
|
||||||
|
if (handleClicks === undefined) wire_onclick = true;
|
||||||
let icon;
|
let icon;
|
||||||
let name;
|
let name;
|
||||||
let span_class;
|
let span_class;
|
||||||
|
@ -189,7 +240,7 @@ export default class NetworkDropdown extends React.Component {
|
||||||
span_class = 'mx_NetworkDropdown_menu_network';
|
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;
|
let key = server;
|
||||||
if (network !== null) {
|
if (network !== null) {
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -215,11 +284,19 @@ export default class NetworkDropdown extends React.Component {
|
||||||
ref={this.collectInputTextBox} onKeyUp={this.onInputKeyUp}
|
ref={this.collectInputTextBox} onKeyUp={this.onInputKeyUp}
|
||||||
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 {
|
||||||
|
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 {
|
} else {
|
||||||
current_value = this._makeMenuOption(
|
current_value = this._makeMenuOption(
|
||||||
this.state.selectedServer, this.state.selectedNetwork, false
|
this.state.selectedServer, this.state.selectedNetwork, false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return <div className="mx_NetworkDropdown" ref={this.collectRoot}>
|
return <div className="mx_NetworkDropdown" ref={this.collectRoot}>
|
||||||
<div className="mx_NetworkDropdown_input" onClick={this.onInputClick}>
|
<div className="mx_NetworkDropdown_input" onClick={this.onInputClick}>
|
||||||
|
@ -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: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue