Fixed merge conflicts
commit
fb34925251
@ -0,0 +1,52 @@
|
||||
/*
|
||||
This file contains the search endpoint.
|
||||
As of now search is based on the basic LIKE query in SQLite and MySQL.
|
||||
Further improvements to the search feature should be moved to this file.
|
||||
|
||||
Why aren't we using Algolia or ElasticSearch?
|
||||
|
||||
Matterwiki wants to keep things simple. Setting up a ES instance or signing up
|
||||
for Algolia goes against that.
|
||||
*/
|
||||
|
||||
var Articles = require('../models/article.js');
|
||||
|
||||
module.exports = function(app) {
|
||||
|
||||
app.get('/search',function(req,res){
|
||||
/*
|
||||
This is a GET enpoint which takes the search query as a URL param
|
||||
Runs the search query and returns matching articles in the data key in the
|
||||
response object.
|
||||
The endpoint only searches article titles as of now.
|
||||
*/
|
||||
var SearchQuery = req.query.query;
|
||||
SearchQuery = "%"+SearchQuery+"%";
|
||||
Articles.query(function(qb) {
|
||||
qb.where('title', 'LIKE', SearchQuery).orWhere('body','LIKE',SearchQuery);
|
||||
}).fetchAll()
|
||||
.then(function (collection) {
|
||||
res.json({
|
||||
error: {
|
||||
error: false,
|
||||
message: ''
|
||||
},
|
||||
code: 'B131',
|
||||
data: collection.toJSON()
|
||||
});
|
||||
})
|
||||
.catch(function (error) {
|
||||
res.status(500).json({
|
||||
error: {
|
||||
error: true,
|
||||
message: "There was an error performing the search operation. Please try again."
|
||||
},
|
||||
code: 'B132',
|
||||
data: {
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
import React from 'react';
|
||||
import Loader from './loader.jsx';
|
||||
import {Link, hashHistory} from 'react-router';
|
||||
import Alert from 'react-s-alert';
|
||||
|
||||
|
||||
class Search extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { articles: [], loading: true};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
var myHeaders = new Headers({
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"x-access-token": window.localStorage.getItem('userToken')
|
||||
});
|
||||
var myInit = { method: 'GET',
|
||||
headers: myHeaders,
|
||||
};
|
||||
var that = this;
|
||||
fetch('/api/search?query='+this.props.location.query.query,myInit)
|
||||
.then(function(response) {
|
||||
return response.json();
|
||||
})
|
||||
.then(function(response) {
|
||||
if(response.error.error)
|
||||
Alert.error(response.error.message);
|
||||
else {
|
||||
that.setState({articles: response.data})
|
||||
}
|
||||
that.setState({loading: false});
|
||||
});
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
var myHeaders = new Headers({
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"x-access-token": window.localStorage.getItem('userToken')
|
||||
});
|
||||
var myInit = { method: 'GET',
|
||||
headers: myHeaders,
|
||||
};
|
||||
var that = this;
|
||||
fetch('/api/search?query='+nextProps.location.query.query,myInit)
|
||||
.then(function(response) {
|
||||
return response.json();
|
||||
})
|
||||
.then(function(response) {
|
||||
if(response.error.error){
|
||||
Alert.error(response.error.message);
|
||||
}
|
||||
else {
|
||||
that.setState({articles: response.data});
|
||||
}
|
||||
that.setState({loading: false});
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.setState({articles: []});
|
||||
}
|
||||
|
||||
render () {
|
||||
if(this.state.loading)
|
||||
return <Loader/>;
|
||||
else
|
||||
return(<div>
|
||||
<div className="result-info">
|
||||
<p className="help-block">
|
||||
We found {this.state.articles.length} articles for your query
|
||||
</p>
|
||||
</div>
|
||||
{(this.state.articles.length>0) ?
|
||||
<div className="article-list">
|
||||
{this.state.articles.map(article => (
|
||||
<div key={article.id} className="article-item">
|
||||
<div className="article-item-title">
|
||||
<Link to={"/article/"+article.id} >{article.title}</Link>
|
||||
</div>
|
||||
<div className="article-item-description">
|
||||
Last updated on {new Date(article.updated_at).toDateString()}
|
||||
</div>
|
||||
<hr className="article-separator"></hr>
|
||||
</div>
|
||||
|
||||
))}</div>
|
||||
:
|
||||
<div className="no-results">
|
||||
<i className="fa fa-frown-o"></i>
|
||||
<p>Please try again with another query</p>
|
||||
</div>
|
||||
|
||||
}
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
||||
export default Search;
|
@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import {hashHistory} from 'react-router';
|
||||
|
||||
class SearchForm extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.searchWiki = this.searchWiki.bind(this);
|
||||
}
|
||||
|
||||
searchWiki() {
|
||||
var results = '/search?query='+this.refs.search.value;
|
||||
hashHistory.push(results);
|
||||
}
|
||||
|
||||
render () {
|
||||
return(
|
||||
<form className="navbar-form navbar-right" onSubmit={this.searchWiki}>
|
||||
<div className="form-group">
|
||||
<input type="text" className="form-control search-input" placeholder="Search" ref="search"/>
|
||||
</div>
|
||||
<button type="submit" className="btn search-button"><i className="fa fa-search"></i></button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SearchForm;
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 434 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue