Use new searchRoomEvents and backPaginateRoomEventsSearch methods

MatrixClient now exposes higher-level search APIs, so use them.
pull/21833/head
Richard van der Hoff 2015-12-22 18:15:32 +00:00
parent 103b0a03b1
commit cc72f7ec24
2 changed files with 74 additions and 93 deletions

View File

@ -365,10 +365,9 @@ module.exports = React.createClass({
if (!backwards || this.state.searchInProgress) if (!backwards || this.state.searchInProgress)
return; return;
if (this.nextSearchBatch) { if (this.state.searchResults.next_batch) {
if (DEBUG_SCROLL) console.log("requesting more search results"); if (DEBUG_SCROLL) console.log("requesting more search results");
this._getSearchBatch(this.state.searchTerm, this._backPaginateSearch();
this.state.searchScope);
} else { } else {
if (DEBUG_SCROLL) console.log("no more search results"); if (DEBUG_SCROLL) console.log("no more search results");
} }
@ -484,10 +483,8 @@ module.exports = React.createClass({
this.setState({ this.setState({
searchTerm: term, searchTerm: term,
searchScope: scope, searchScope: scope,
searchResults: [], searchResults: {},
searchHighlights: [], searchHighlights: [],
searchCount: null,
searchCanPaginate: null,
}); });
// if we already have a search panel, we need to tell it to forget // if we already have a search panel, we need to tell it to forget
@ -496,64 +493,72 @@ module.exports = React.createClass({
this.refs.searchResultsPanel.resetScrollState(); this.refs.searchResultsPanel.resetScrollState();
} }
this.nextSearchBatch = null; // make sure that we don't end up showing results from
this._getSearchBatch(term, scope); // an aborted search by keeping a unique id.
//
// todo: should cancel any previous search requests.
this.searchId = new Date().getTime();
var filter;
if (scope === "Room") {
filter = {
// XXX: it's unintuitive that the filter for searching doesn't have the same shape as the v2 filter API :(
rooms: [
this.props.roomId
]
};
}
if (DEBUG_SCROLL) console.log("sending search request");
var searchPromise = MatrixClientPeg.get().searchRoomEvents(
{ filter: filter,
term: term,
});
this._handleSearchResult(searchPromise)
.done();
}, },
// fire off a request for a batch of search results _backPaginateSearch: function() {
_getSearchBatch: function(term, scope) { if (DEBUG_SCROLL) console.log("sending search back-paginate request");
var searchPromise = MatrixClientPeg.get().backPaginateRoomEventsSearch(
this.state.searchResults);
this._handleSearchResult(searchPromise)
.done();
},
_handleSearchResult: function(searchPromise) {
var self = this;
var searchId = this.searchId;
this.setState({ this.setState({
searchInProgress: true, searchInProgress: true,
}); });
// make sure that we don't end up merging results from return searchPromise.then(function(results) {
// different searches by keeping a unique id.
//
// todo: should cancel any previous search requests.
var searchId = this.searchId = new Date().getTime();
var self = this;
if (DEBUG_SCROLL) console.log("sending search request");
MatrixClientPeg.get().search({ body: this._getSearchCondition(term, scope),
next_batch: this.nextSearchBatch })
.then(function(data) {
if (DEBUG_SCROLL) console.log("search complete"); if (DEBUG_SCROLL) console.log("search complete");
if (!self.state.searching || self.searchId != searchId) { if (!self.state.searching || self.searchId != searchId) {
console.error("Discarding stale search results"); console.error("Discarding stale search results");
return; return;
} }
var results = data.search_categories.room_events;
// postgres on synapse returns us precise details of the // postgres on synapse returns us precise details of the
// strings which actually got matched for highlighting. // strings which actually got matched for highlighting.
// combine the highlight list with our existing list; build an object // For overlapping highlights,
// to avoid O(N^2) fail
var highlights = {};
results.highlights.forEach(function(hl) { highlights[hl] = 1; });
self.state.searchHighlights.forEach(function(hl) { highlights[hl] = 1; });
// turn it back into an ordered list. For overlapping highlights,
// favour longer (more specific) terms first // favour longer (more specific) terms first
highlights = Object.keys(highlights).sort(function(a, b) { b.length - a.length }); var highlights = results.highlights.sort(function(a, b) { b.length - a.length });
// sqlite doesn't give us any highlights, so just try to highlight the literal search term // sqlite doesn't give us any highlights, so just try to highlight the literal search term
if (highlights.length == 0) { if (highlights.length == 0) {
highlights = [ term ]; highlights = [ self.state.searchTerm ];
} }
// append the new results to our existing results
var events = self.state.searchResults.concat(results.results);
self.setState({ self.setState({
searchHighlights: highlights, searchHighlights: highlights,
searchResults: events, searchResults: results,
searchCount: results.count,
searchCanPaginate: !!(results.next_batch),
}); });
self.nextSearchBatch = results.next_batch;
}, function(error) { }, function(error) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
@ -564,51 +569,27 @@ module.exports = React.createClass({
self.setState({ self.setState({
searchInProgress: false searchInProgress: false
}); });
}).done(); });
}, },
_getSearchCondition: function(term, scope) {
var filter;
if (scope === "Room") {
filter = {
// XXX: it's unintuitive that the filter for searching doesn't have the same shape as the v2 filter API :(
rooms: [
this.props.roomId
]
};
}
return {
search_categories: {
room_events: {
search_term: term,
filter: filter,
order_by: "recent",
event_context: {
before_limit: 1,
after_limit: 1,
include_profile: true,
}
}
}
}
},
getSearchResultTiles: function() { getSearchResultTiles: function() {
var DateSeparator = sdk.getComponent('messages.DateSeparator'); var DateSeparator = sdk.getComponent('messages.DateSeparator');
var cli = MatrixClientPeg.get();
var ret = [];
var EventTile = sdk.getComponent('rooms.EventTile'); var EventTile = sdk.getComponent('rooms.EventTile');
var cli = MatrixClientPeg.get();
// XXX: todo: merge overlapping results somehow? // XXX: todo: merge overlapping results somehow?
// XXX: why doesn't searching on name work? // XXX: why doesn't searching on name work?
if (this.state.searchResults.results === undefined) {
// awaiting results
return [];
}
if (this.state.searchCanPaginate === false) { var ret = [];
if (this.state.searchResults.length == 0) {
if (!this.state.searchResults.next_batch) {
if (this.state.searchResults.results.length == 0) {
ret.push(<li key="search-top-marker"> ret.push(<li key="search-top-marker">
<h2 className="mx_RoomView_topMarker">No results</h2> <h2 className="mx_RoomView_topMarker">No results</h2>
</li> </li>
@ -623,9 +604,10 @@ module.exports = React.createClass({
var lastRoomId; var lastRoomId;
for (var i = this.state.searchResults.length - 1; i >= 0; i--) { for (var i = this.state.searchResults.results.length - 1; i >= 0; i--) {
var result = this.state.searchResults[i]; var result = this.state.searchResults.results[i];
var mxEv = new Matrix.MatrixEvent(result.result);
var mxEv = result.context.getEvent();
if (!EventTile.haveTileForEvent(mxEv)) { if (!EventTile.haveTileForEvent(mxEv)) {
// XXX: can this ever happen? It will make the result count // XXX: can this ever happen? It will make the result count
@ -636,29 +618,28 @@ module.exports = React.createClass({
var eventId = mxEv.getId(); var eventId = mxEv.getId();
if (this.state.searchScope === 'All') { if (this.state.searchScope === 'All') {
var roomId = result.result.room_id; var roomId = mxEv.getRoomId();
if(roomId != lastRoomId) { if(roomId != lastRoomId) {
ret.push(<li key={eventId + "-room"}><h1>Room: { cli.getRoom(roomId).name }</h1></li>); ret.push(<li key={eventId + "-room"}><h1>Room: { cli.getRoom(roomId).name }</h1></li>);
lastRoomId = roomId; lastRoomId = roomId;
} }
} }
var ts1 = result.result.origin_server_ts; var ts1 = mxEv.getTs();
ret.push(<li key={ts1 + "-search"}><DateSeparator ts={ts1}/></li>); // Rank: {resultList[i].rank} ret.push(<li key={ts1 + "-search"}><DateSeparator ts={ts1}/></li>); // Rank: {resultList[i].rank}
if (result.context.events_before[0]) { var timeline = result.context.getTimeline();
var mxEv2 = new Matrix.MatrixEvent(result.context.events_before[0]); for (var j = 0; j < timeline.length; j++) {
if (EventTile.haveTileForEvent(mxEv2)) { var ev = timeline[j];
ret.push(<li key={eventId+"-1"} data-scroll-token={eventId+"-1"}><EventTile mxEvent={mxEv2} contextual={true} /></li>); var highlights;
var contextual = (j != result.context.getOurEventIndex());
if (!contextual) {
highlights = this.state.searchHighlights;
} }
} if (EventTile.haveTileForEvent(ev)) {
ret.push(<li key={eventId+"+"+j} data-scroll-token={eventId+"+"+j}>
ret.push(<li key={eventId+"+0"} data-scroll-token={eventId+"+0"}><EventTile mxEvent={mxEv} highlights={this.state.searchHighlights}/></li>); <EventTile mxEvent={ev} contextual={contextual} highlights={highlights} />
</li>);
if (result.context.events_after[0]) {
var mxEv2 = new Matrix.MatrixEvent(result.context.events_after[0]);
if (EventTile.haveTileForEvent(mxEv2)) {
ret.push(<li key={eventId+"+1"} data-scroll-token={eventId+"+1"}><EventTile mxEvent={mxEv2} contextual={true} /></li>);
} }
} }
} }
@ -1290,7 +1271,7 @@ module.exports = React.createClass({
searchInfo = { searchInfo = {
searchTerm : this.state.searchTerm, searchTerm : this.state.searchTerm,
searchScope : this.state.searchScope, searchScope : this.state.searchScope,
searchCount : this.state.searchCount, searchCount : this.state.searchResults.count,
}; };
} }

View File

@ -110,7 +110,7 @@ module.exports = React.createClass({
var searchStatus; var searchStatus;
// don't display the search count until the search completes and // don't display the search count until the search completes and
// gives us a non-null searchCount. // gives us a non-null searchCount.
if (this.props.searchInfo && this.props.searchInfo.searchCount !== null) { if (this.props.searchInfo && this.props.searchInfo.searchCount != null) {
searchStatus = <div className="mx_RoomHeader_searchStatus">&nbsp;(~{ this.props.searchInfo.searchCount } results)</div>; searchStatus = <div className="mx_RoomHeader_searchStatus">&nbsp;(~{ this.props.searchInfo.searchCount } results)</div>;
} }