Implement filtering

master
Drew DeVault 2017-12-30 12:41:44 -05:00
parent bc7f56426d
commit 1fa75747f2
2 changed files with 51 additions and 29 deletions

View File

@ -3,9 +3,9 @@ import ws_send from '../socket';
export const FILTER_SUBSCRIBE = 'FILTER_SUBSCRIBE'; export const FILTER_SUBSCRIBE = 'FILTER_SUBSCRIBE';
export const FILTER_UNSUBSCRIBE = 'FILTER_UNSUBSCRIBE'; export const FILTER_UNSUBSCRIBE = 'FILTER_UNSUBSCRIBE';
export function filter_subscribe(kind='torrent', criteria=[], serial=null) { export function filter_subscribe(kind='torrent', criteria=[], _serial=null) {
return dispatch => { return dispatch => {
const serial = ws_send(FILTER_SUBSCRIBE, { kind, criteria }, null, serial); const serial = ws_send(FILTER_SUBSCRIBE, { kind, criteria }, null, _serial);
dispatch({ type: FILTER_SUBSCRIBE, serial, kind, criteria }); dispatch({ type: FILTER_SUBSCRIBE, serial, kind, criteria });
}; };
} }

View File

@ -15,17 +15,61 @@ function search_qs(text) {
}${qs && "?" + qs}`; }${qs && "?" + qs}`;
} }
// via https://stackoverflow.com/a/46946490
const ssplit = str => str.match(/\\?.|^$/g).reduce((p, c) => {
if (c === '"') {
p.quote ^= 1;
} else if (!p.quote && c === ' ') {
p.a.push('');
} else {
p.a[p.a.length-1] += c.replace(/\\(.)/,"$1");
}
return p;
}, {a: ['']}).a;
function search_criteria(text) {
const terms = ssplit(text);
return terms.map(t => {
if (t.indexOf("status:") === 0) {
return {
field: "status",
op: "==",
value: t.split(":")[1]
};
} else {
return {
field: "name",
op: "ilike",
value: `%${t}%`
};
}
});
}
function update_filter(text, fs, location, dispatch) { function update_filter(text, fs, location, dispatch) {
// there will always be one torrent filter
const tfilter = fs.filter(fs => fs.kind === "torrent")[0];
const criteria = search_criteria(text);
dispatch(filter_subscribe("torrent", criteria, tfilter.serial));
dispatch(push(search_qs(text))); dispatch(push(search_qs(text)));
} }
function render(props) { function render(props) {
const { dispatch, router } = props; const { dispatch, router } = props;
const qs = query.parse(router.location.search); const qs = query.parse(router.location.search);
const update = text => update_filter(
text || "", props.filter_subscribe, router.location, dispatch);
const navto = where => e => { const navto = where => e => {
e.preventDefault(); e.preventDefault();
dispatch(push(where)); update(where);
}; };
const searchLink = (target, text) => <li className="nav-item">
<a
className={`nav-link ${qs.s === target && "active"}`}
href={search_qs(target)}
onClick={navto(target)}
>{text}</a>
</li>;
return <nav className="navbar navbar-light navbar-toggleable-xl"> return <nav className="navbar navbar-light navbar-toggleable-xl">
<Link to="/" className="navbar-brand">receptor</Link> <Link to="/" className="navbar-brand">receptor</Link>
<div className="navbar-collapse collapse"> <div className="navbar-collapse collapse">
@ -39,27 +83,9 @@ function render(props) {
</li> </li>
<li className="nav-item" style={{minWidth: "1rem"}}> <li className="nav-item" style={{minWidth: "1rem"}}>
</li> </li>
<li className="nav-item"> {searchLink(undefined, "all")}
<a {searchLink("status:leeching", "leeching")}
className="nav-link" {searchLink("status:seeding", "seeding")}
href={search_qs("")}
onClick={navto(search_qs(""))}
>all</a>
</li>
<li className="nav-item">
<a
className="nav-link"
href={search_qs("status:leeching")}
onClick={navto(search_qs("status:leeching"))}
>leeching</a>
</li>
<li className="nav-item">
<a
className="nav-link"
href={search_qs("status:seeding")}
onClick={navto(search_qs("status:seeding"))}
>seeding</a>
</li>
<form className="form-inline"> <form className="form-inline">
<input <input
className="form-control mr-sm-2" className="form-control mr-sm-2"
@ -67,11 +93,7 @@ function render(props) {
placeholder="Search" placeholder="Search"
aria-label="Search" aria-label="Search"
value={qs.s} value={qs.s}
onChange={e => update_filter( onChange={e => update(e.target.value)} />
e.target.value,
props.filter_subscribe,
router.location,
dispatch)} />
</form> </form>
</ul> </ul>
</div> </div>