2017-08-22 21:49:48 +02:00
|
|
|
import React, { Component } from 'react';
|
|
|
|
import { connect } from 'react-redux';
|
2018-03-13 09:09:22 +01:00
|
|
|
import FontAwesome from 'react-fontawesome';
|
2017-08-25 15:43:54 +02:00
|
|
|
import selectTorrent, { UNION, SUBTRACT, EXCLUSIVE } from '../actions/selection';
|
2018-03-13 09:09:22 +01:00
|
|
|
import { formatBitrate, formatAmount } from '../bitrate';
|
2017-09-10 14:56:21 +02:00
|
|
|
import TorrentProgress from './torrent_progress';
|
2017-08-23 14:52:08 +02:00
|
|
|
|
2018-02-26 01:18:39 +01:00
|
|
|
const name_style = {
|
|
|
|
maxWidth: `${window.innerWidth * 0.25}px`,
|
|
|
|
textOverflow: 'ellipsis',
|
|
|
|
overflowX: 'hidden',
|
|
|
|
whiteSpace: 'nowrap'
|
|
|
|
};
|
|
|
|
|
2018-02-26 08:17:36 +01:00
|
|
|
class _Torrent extends Component {
|
2018-02-26 01:18:39 +01:00
|
|
|
shouldComponentUpdate(nextProps, _) {
|
|
|
|
const { selection, torrent } = this.props;
|
|
|
|
const nt = nextProps.torrent;
|
|
|
|
const active = selection.indexOf(torrent.id);
|
|
|
|
const nActive = nextProps.selection.indexOf(torrent.id);
|
2018-02-27 10:40:08 +01:00
|
|
|
return active !== nActive || torrent !== nt;
|
2018-02-26 01:18:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const { dispatch, selection, torrent } = this.props;
|
|
|
|
const t = torrent;
|
2018-03-13 09:09:22 +01:00
|
|
|
const up = t.transferred_up;
|
|
|
|
const down = t.transferred_down;
|
|
|
|
const ratio = up / down;
|
2018-02-26 01:18:39 +01:00
|
|
|
return (
|
|
|
|
<tr
|
|
|
|
className={`torrent ${
|
|
|
|
t.status
|
|
|
|
} ${
|
|
|
|
selection.indexOf(t.id) !== -1 ? "selected" : ""
|
|
|
|
}`}
|
|
|
|
>
|
|
|
|
<td>
|
|
|
|
<input
|
|
|
|
type="checkbox"
|
|
|
|
checked={selection.indexOf(t.id) !== -1}
|
|
|
|
onChange={e =>
|
|
|
|
dispatch(selectTorrent([t.id], e.target.checked ? UNION : SUBTRACT))
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
</td>
|
|
|
|
<td style={name_style}>
|
|
|
|
<a
|
|
|
|
href={`/torrents/${t.id}`}
|
|
|
|
onClick={e => {
|
|
|
|
e.preventDefault();
|
|
|
|
dispatch(selectTorrent([t.id], EXCLUSIVE));
|
|
|
|
}}
|
|
|
|
>{t.name}</a>
|
|
|
|
</td>
|
|
|
|
<td>{formatBitrate(t.rate_up)}</td>
|
|
|
|
<td>{formatBitrate(t.rate_down)}</td>
|
2018-03-13 09:09:22 +01:00
|
|
|
<td>{isFinite(ratio) ? `${ratio.toFixed(2)}` : "∞"}</td>
|
|
|
|
<td>{formatAmount(up)}</td>
|
|
|
|
<td>{formatAmount(down)}</td>
|
2018-02-26 01:18:39 +01:00
|
|
|
<td><TorrentProgress torrent={t} /></td>
|
|
|
|
</tr>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 08:17:36 +01:00
|
|
|
const Torrent = connect((state, props) => {
|
|
|
|
return {
|
|
|
|
torrent: state.torrents[props.id],
|
|
|
|
selection: state.selection,
|
|
|
|
};
|
|
|
|
})(_Torrent);
|
|
|
|
|
2018-03-13 09:09:22 +01:00
|
|
|
const comparators = {
|
|
|
|
"name": (a, b) => a.name.localeCompare(b.name),
|
|
|
|
"up": (a, b) => a.up - b.up,
|
|
|
|
"down": (a, b) => a.down - b.down,
|
|
|
|
"ul": (a, b) => a.transferred_up - b.transferred_up,
|
|
|
|
"dl": (a, b) => a.transferred_down - b.transferred_down,
|
|
|
|
"ratio": (a, b) => {
|
|
|
|
const ratioA = a.transferred_up/a.transferred_down;
|
|
|
|
const ratioB = b.transferred_up/b.transferred_down;
|
|
|
|
if (!isFinite(ratioA - ratioB)) {
|
|
|
|
return !isFinite(ratioA) ? 1 : -1;
|
|
|
|
} else {
|
|
|
|
return ratioA - ratioB;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"progress": (a, b) => a.progress - b.progress,
|
|
|
|
}
|
|
|
|
|
2018-02-26 08:17:36 +01:00
|
|
|
class TorrentTable extends Component {
|
2018-03-13 09:09:22 +01:00
|
|
|
constructor() {
|
|
|
|
super();
|
|
|
|
this.state = {
|
|
|
|
sortBy: "name",
|
|
|
|
sortAsc: true,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
updateSort(column) {
|
|
|
|
if (column === this.state.sortBy) {
|
|
|
|
this.setState({ sortBy: column, sortAsc: !this.state.sortAsc});
|
|
|
|
} else {
|
|
|
|
this.setState({ sortBy: column, sortAsc: this.state.sortAsc});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 08:17:36 +01:00
|
|
|
render() {
|
|
|
|
const { selection, torrents, dispatch } = this.props;
|
2018-03-13 09:09:22 +01:00
|
|
|
const { sortBy, sortAsc } = this.state;
|
|
|
|
|
|
|
|
const comparator = (a, b) => comparators[sortBy](a, b) * (sortAsc ? 1 : -1);
|
|
|
|
const arrowStyle = { marginLeft: "5px", marginRight: "5px" };
|
|
|
|
const sortArrow = sortAsc === true
|
|
|
|
? <FontAwesome name="angle-up" style={arrowStyle} />
|
|
|
|
: <FontAwesome name="angle-down" style={arrowStyle} />;
|
|
|
|
|
|
|
|
const sortCol = (name, minWidth) => <th
|
|
|
|
style={{ minWidth }}
|
|
|
|
onClick={e => {
|
|
|
|
e.preventDefault();
|
|
|
|
this.updateSort(name)
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{name}
|
|
|
|
{sortBy === name ? sortArrow : null}
|
|
|
|
</th>;
|
|
|
|
|
2018-02-26 08:17:36 +01:00
|
|
|
return (
|
|
|
|
<table className="table torrents">
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th style={{width: "1px"}}>
|
|
|
|
<input
|
|
|
|
type="checkbox"
|
|
|
|
checked={selection.length === Object.values(torrents).length}
|
|
|
|
onChange={e => {
|
|
|
|
if (selection.length > 0) {
|
|
|
|
dispatch(selectTorrent([], EXCLUSIVE));
|
|
|
|
} else {
|
|
|
|
dispatch(selectTorrent(Object.keys(torrents), EXCLUSIVE));
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</th>
|
2018-03-13 09:09:22 +01:00
|
|
|
<th
|
|
|
|
style={name_style}
|
|
|
|
onClick={e => {
|
|
|
|
e.preventDefault();
|
|
|
|
this.updateSort("name");
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
name
|
|
|
|
{sortBy === "name" ? sortArrow : null}
|
2018-02-26 08:17:36 +01:00
|
|
|
</th>
|
2018-03-13 09:09:22 +01:00
|
|
|
{sortCol("up", "65px")}
|
|
|
|
{sortCol("down", "85px")}
|
|
|
|
{sortCol("ratio", "95px")}
|
|
|
|
{sortCol("ul", "65px")}
|
|
|
|
{sortCol("dl", "75px")}
|
|
|
|
{sortCol("progress", "115px")}
|
2018-02-26 08:17:36 +01:00
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
2018-03-13 09:09:22 +01:00
|
|
|
{Object.values(torrents).slice().sort(comparator).map(t =>
|
2018-02-26 08:17:36 +01:00
|
|
|
<Torrent
|
|
|
|
dispatch={dispatch}
|
|
|
|
id={t.id}
|
|
|
|
key={t.id}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-25 02:01:15 +02:00
|
|
|
export default connect(state => ({
|
|
|
|
torrents: state.torrents,
|
2017-08-25 15:43:54 +02:00
|
|
|
selection: state.selection,
|
2017-08-25 02:01:15 +02:00
|
|
|
router: state.router
|
|
|
|
}))(TorrentTable);
|