Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support room dir 3rd party network filtering #2747

Merged
merged 5 commits into from Dec 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Expand Up @@ -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.<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.<network_type>.name`: Human-readable name for the network. Required.
1. `roomDirectory.<network_type>.protocol`: Protocol as given by the server in
Expand Down
11 changes: 9 additions & 2 deletions src/components/structures/RoomDirectory.js
Expand Up @@ -53,6 +53,7 @@ module.exports = React.createClass({
publicRooms: [],
loading: true,
network: null,
instance_id: null,
roomServer: null,
filterString: null,
}
Expand Down Expand Up @@ -131,6 +132,11 @@ module.exports = React.createClass({
if (my_server != MatrixClientPeg.getHomeServerName()) {
opts.server = my_server;
}
if (this.state.instance_id) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add instance_id to getInitialState?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

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) => {
Expand Down Expand Up @@ -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({
Expand All @@ -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
Expand Down Expand Up @@ -615,7 +622,7 @@ module.exports = React.createClass({
onChange={this.onFilterChange} onClear={this.onFilterClear} onJoinClick={this.onJoinClick}
placeholder={placeholder} showJoinButton={showJoinButton}
/>
<NetworkDropdown config={this.props.config} onOptionChange={this.onOptionChange} />
<NetworkDropdown config={this.props.config} protocols={this.protocols} onOptionChange={this.onOptionChange} />
</div>
{content}
</div>
Expand Down
95 changes: 87 additions & 8 deletions src/components/views/directory/NetworkDropdown.js
Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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({
Expand Down Expand Up @@ -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 = <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 name;
let span_class;
Expand Down Expand Up @@ -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) {
Expand All @@ -202,6 +253,24 @@ export default class NetworkDropdown extends React.Component {
</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() {
let current_value;

Expand All @@ -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 <div className="mx_NetworkDropdown" ref={this.collectRoot}>
Expand All @@ -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: {},
};