Add search help page
This commit is contained in:
parent
85f9b76176
commit
ff86be7276
|
@ -12,7 +12,7 @@ import scss from '../scss/main.scss';
|
||||||
import { ws_init } from './socket';
|
import { ws_init } from './socket';
|
||||||
import { filter_subscribe } from './actions/filter_subscribe';
|
import { filter_subscribe } from './actions/filter_subscribe';
|
||||||
import { socket_uri, socket_update, SOCKET_STATE } from './actions/socket';
|
import { socket_uri, socket_update, SOCKET_STATE } from './actions/socket';
|
||||||
import search_criteria from './search';
|
import { search_criteria } from './search';
|
||||||
|
|
||||||
import Main from './ui/main';
|
import Main from './ui/main';
|
||||||
import Connection from './ui/connection';
|
import Connection from './ui/connection';
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
import numeral from "numeral";
|
import numeral from "numeral";
|
||||||
|
import query from 'query-string';
|
||||||
|
import { filter_subscribe } from './actions/filter_subscribe';
|
||||||
|
import { push_query } from './actions/routing';
|
||||||
|
|
||||||
// via https://stackoverflow.com/a/46946490
|
// via https://stackoverflow.com/a/46946490
|
||||||
const ssplit = str => str.match(/\\?.|^$/g).reduce((p, c) => {
|
const ssplit = str => str.match(/\\?.|^$/g).reduce((p, c) => {
|
||||||
|
@ -12,7 +15,7 @@ const ssplit = str => str.match(/\\?.|^$/g).reduce((p, c) => {
|
||||||
return p;
|
return p;
|
||||||
}, {a: ['']}).a;
|
}, {a: ['']}).a;
|
||||||
|
|
||||||
export default function search_criteria(text) {
|
export function search_criteria(text) {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -41,3 +44,21 @@ export default function search_criteria(text) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function search_qs(text) {
|
||||||
|
const qs = query.stringify({
|
||||||
|
...query.parse(location.search),
|
||||||
|
s: text || undefined
|
||||||
|
});
|
||||||
|
return `${
|
||||||
|
location.pathname === "/" ? location.pathname : ""
|
||||||
|
}${qs && "?" + qs}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export 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_query(search_qs(text)));
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import TorrentTable from './torrent_table';
|
||||||
import AddTorrent from './add_torrent';
|
import AddTorrent from './add_torrent';
|
||||||
import TorrentDetails from './torrent_details';
|
import TorrentDetails from './torrent_details';
|
||||||
import Server from './server';
|
import Server from './server';
|
||||||
|
import SearchHelp from './search_help';
|
||||||
import ConnectionOverlay from './connection';
|
import ConnectionOverlay from './connection';
|
||||||
|
|
||||||
export default class Main extends Component {
|
export default class Main extends Component {
|
||||||
|
@ -20,6 +21,7 @@ export default class Main extends Component {
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-4">
|
<div className="col-md-4">
|
||||||
<Route exact path="/add-torrent" component={AddTorrent} />
|
<Route exact path="/add-torrent" component={AddTorrent} />
|
||||||
|
<Route path="/search-help" component={SearchHelp} />
|
||||||
<Route path="/add-torrent/:magnet" component={AddTorrent} />
|
<Route path="/add-torrent/:magnet" component={AddTorrent} />
|
||||||
<Route path="/torrents/:ids" component={TorrentDetails} />
|
<Route path="/torrents/:ids" component={TorrentDetails} />
|
||||||
<Route exact path="/" component={Server} />
|
<Route exact path="/" component={Server} />
|
||||||
|
|
|
@ -1,28 +1,9 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Link, NavLink } from 'react-router-dom';
|
import { Link, NavLink } from 'react-router-dom';
|
||||||
import { filter_subscribe } from '../actions/filter_subscribe';
|
import FontAwesome from 'react-fontawesome';
|
||||||
import { push_query } from '../actions/routing';
|
|
||||||
import query from 'query-string';
|
import query from 'query-string';
|
||||||
import search_criteria from '../search';
|
import { search_criteria, search_qs, update_filter } from '../search';
|
||||||
|
|
||||||
function search_qs(text) {
|
|
||||||
const qs = query.stringify({
|
|
||||||
...query.parse(location.search),
|
|
||||||
s: text || undefined
|
|
||||||
});
|
|
||||||
return `${
|
|
||||||
location.pathname === "/" ? location.pathname : ""
|
|
||||||
}${qs && "?" + qs}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_query(search_qs(text)));
|
|
||||||
}
|
|
||||||
|
|
||||||
function render(props) {
|
function render(props) {
|
||||||
const { dispatch, router } = props;
|
const { dispatch, router } = props;
|
||||||
|
@ -65,6 +46,11 @@ function render(props) {
|
||||||
value={qs.s}
|
value={qs.s}
|
||||||
onChange={e => update(e.target.value)} />
|
onChange={e => update(e.target.value)} />
|
||||||
</form>
|
</form>
|
||||||
|
<span class="navbar-text">
|
||||||
|
<Link to="/search-help">
|
||||||
|
<FontAwesome name="question-circle" />
|
||||||
|
</Link>
|
||||||
|
</span>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</nav>;
|
</nav>;
|
||||||
|
|
81
src/ui/search_help.js
Normal file
81
src/ui/search_help.js
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import query from 'query-string';
|
||||||
|
import { search_criteria, search_qs, update_filter } from '../search';
|
||||||
|
|
||||||
|
function SearchHelp(props) {
|
||||||
|
const { dispatch, router } = props;
|
||||||
|
const qs = query.parse(router.location.search);
|
||||||
|
const update = text => update_filter(
|
||||||
|
text || "", props.filter_subscribe, router.location, dispatch);
|
||||||
|
const navto = where => e => {
|
||||||
|
e.preventDefault();
|
||||||
|
update(where);
|
||||||
|
};
|
||||||
|
const searchLink = target =>
|
||||||
|
<a href={search_qs(target)} onClick={navto(target)} >{target}</a>;
|
||||||
|
const searchableProps = {
|
||||||
|
"name": "torrent name",
|
||||||
|
"path": "download path",
|
||||||
|
"status": "paused | pending | leeching | idle | seeding | hashing | error",
|
||||||
|
"size": "size in bytes",
|
||||||
|
"progress": "progress from 0 to 1",
|
||||||
|
"priority": "1-5, low to high",
|
||||||
|
"availability": "how much is available from the swarm, 0 to 1",
|
||||||
|
"rate_up": "rate up in bits/sec",
|
||||||
|
"rate_down": "rate down in bits/sec",
|
||||||
|
"throttle_up": "throttle up in bits/sec",
|
||||||
|
"throttle_down": "throttle down in bits/sec",
|
||||||
|
"transferred_up": "total transfer up in bits/sec",
|
||||||
|
"transferred_down": "total transfer down in bits/sec",
|
||||||
|
"peers": "number of peers",
|
||||||
|
"files": "number of files",
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>
|
||||||
|
Search help
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
You can search for torrents using the search box at the top of the
|
||||||
|
page. By default, it will search through torrent titles. You can also
|
||||||
|
search other properties of torrents with
|
||||||
|
<code>property<strong>operator</strong>value</code>, where operator is
|
||||||
|
one of the following:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>:</code> matches values that contain <code>value</code></li>
|
||||||
|
<li><code>==</code> matches values that are equal to <code>value</code></li>
|
||||||
|
<li><code>!=</code> matches values that are not equal to <code>value</code></li>
|
||||||
|
<li><code>></code> matches values that are greater than <code>value</code></li>
|
||||||
|
<li><code>>=</code> matches values that are greater than or equal to <code>value</code></li>
|
||||||
|
<li><code><</code> matches values that are less than <code>value</code></li>
|
||||||
|
<li><code><=</code> matches values that are less than or equal to <code>value</code></li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
The following torrent properties are searchable:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
{Object.keys(searchableProps).map(key =>
|
||||||
|
<li><strong>{key}</strong>: {searchableProps[key]}</li>)}
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
Here are some example searches:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>{searchLink("state:seeding")}</li>
|
||||||
|
<li>{searchLink("state:leeching")}</li>
|
||||||
|
<li>{searchLink("rate_up>1048576")}</li>
|
||||||
|
<li>{searchLink("files>1")}</li>
|
||||||
|
<li>{searchLink("files==1")}</li>
|
||||||
|
<li>{searchLink("progress<0.1")}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(state => ({
|
||||||
|
filter_subscribe: state.filter_subscribe,
|
||||||
|
router: state.router,
|
||||||
|
}))(SearchHelp);
|
Loading…
Reference in New Issue
Block a user