Flesh out server info page

This commit is contained in:
Drew DeVault 2017-09-10 21:21:08 +09:00
parent 1504288692
commit 83a281bee2
6 changed files with 207 additions and 127 deletions

View File

@ -25,3 +25,15 @@ export function formatBitrate(bitrate) {
return `${bitrate} b/s`; return `${bitrate} b/s`;
} }
} }
export function formatAmount(amount) {
if (amount > Rates["GiB/s"]) {
return `${(amount / Rates["GiB/s"]).toFixed(2)} GiB`;
} else if (amount > Rates["MiB/s"]) {
return `${(amount / Rates["MiB/s"]).toFixed(2)} MiB`;
} else if (amount > Rates["KiB/s"]) {
return `${(amount / Rates["KiB/s"]).toFixed(2)} KiB`;
} else {
return `${amount} bytes`;
}
}

View File

@ -177,6 +177,7 @@ class AddTorrent extends Component {
<Card> <Card>
<CardBlock> <CardBlock>
<TorrentOptions <TorrentOptions
id="new-torrent"
start={start} start={start}
startChanged={start => this.setState({ start })} startChanged={start => this.setState({ start })}
priority={priority} priority={priority}

View File

@ -1,44 +1,100 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import moment from 'moment'; import moment from 'moment';
import { formatBitrate } from '../bitrate'; import { formatBitrate, formatAmount } from '../bitrate';
import { ws_disconnect } from '../socket'; import { ws_disconnect } from '../socket';
import date from '../date'; import date from '../date';
import Throttle from './throttle';
import { updateResource } from '../actions/resources';
const throttle = _ => _ === null ? "Unlimited" : formatBitrate(_); const ratio = (up, down) => {
const ratio = up / down;
function Server({ server }) { if (isNaN(ratio)) {
if (!server.id) { return <dd>0</dd>;
return null;
} }
return ( return (
<div> <dd>
<h3> {`${
Server ratio.toFixed(3)
<button } (${
className="btn btn-sm btn-outline-danger pull-right" formatAmount(up)
onClick={() => { } up, ${
localStorage.removeItem("autoconnect"); formatAmount(down)
localStorage.removeItem("password"); } down)`}
ws_disconnect(); </dd>
}}
>Disconnect</button>
</h3>
<dl>
<dt>Running since</dt>
<dd>{date(moment(server.started))}</dd>
<dt>Rate up</dt>
<dd>{formatBitrate(server.rate_up)}</dd>
<dt>Rate down</dt>
<dd>{formatBitrate(server.rate_down)}</dd>
{/* TODO: Editable */}
<dt>Throttle up</dt>
<dd>{throttle(server.throttle_up)}</dd>
<dt>Throttle down</dt>
<dd>{throttle(server.throttle_down)}</dd>
</dl>
</div>
); );
};
class Server extends Component {
componentDidMount() {
this.interval = setInterval(this.forceUpdate, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
const { server, dispatch } = this.props;
if (!server.id) {
return null;
}
return (
<div>
<h3>
Synapse
<button
className="btn btn-sm btn-outline-danger pull-right"
onClick={() => {
localStorage.removeItem("autoconnect");
localStorage.removeItem("password");
ws_disconnect();
}}
>Disconnect</button>
</h3>
<dl>
<dt>Running since</dt>
<dd>{date(moment(server.started))}</dd>
<dt>Current network use</dt>
<dd>
{`${
formatBitrate(server.rate_up)
} up, ${
formatBitrate(server.rate_down)
} down`}
</dd>
<dt>Global download throttle</dt>
<dd>
<Throttle
prop={"dl-throttle-server"}
global={false}
limit={server.throttle_down}
onChange={throttle_down => dispatch(updateResource({
id: server.id,
throttle_down
}))}
/>
</dd>
<dt>Global upload throttle</dt>
<dd>
<Throttle
prop={"ul-throttle-server"}
global={false}
limit={server.throttle_up}
onChange={throttle_up => dispatch(updateResource({
id: server.id,
throttle_up
}))}
/>
</dd>
<dt>Lifetime ratio</dt>
{ratio(server.transferred_up, server.transferred_down)}
<dt>Session ratio</dt>
{ratio(server.ses_transferred_up, server.ses_transferred_down)}
</dl>
</div>
);
}
} }
export default connect(state => ({ server: state.server }))(Server); export default connect(state => ({ server: state.server }))(Server);

101
src/ui/throttle.js Normal file
View File

@ -0,0 +1,101 @@
import React, { Component } from 'react';
import {
FormGroup,
Label,
Input
} from 'reactstrap';
import { convertFromBitrate, convertToBitrate } from '../bitrate';
export default class Throttle extends Component {
constructor() {
super();
this.setLimit = this.setLimit.bind(this);
this.setUnit = this.setUnit.bind(this);
this.state = { unit: "MiB/s" };
}
setLimit(limit) {
const { onChange } = this.props;
const { unit } = this.state;
const converted = limit <= 0 || limit === null ?
limit : convertToBitrate(limit, unit);
onChange && onChange(converted);
}
setUnit(unit) {
const limit = convertFromBitrate(this.props.limit, this.state.unit);
this.setState({ unit });
this.setLimit(limit);
}
render() {
const { global, limit, legend, prop } = this.props;
const { unit } = this.state;
return (
<div>
<FormGroup tag="fieldset">
<legend>{legend}</legend>
{typeof global === "undefined" || global &&
<FormGroup check className="form-check-inline">
<Label for={`${prop}-global`} check>
<Input
type="radio"
name={prop}
id={`${prop}-global`}
onChange={e => this.setLimit(null)}
checked={limit === null}
/> Global
</Label>
</FormGroup>
}
<FormGroup check className="form-check-inline">
<Label for={`${prop}-unlimited`} check>
<Input
type="radio"
name={prop}
id={`${prop}-unlimited`}
onChange={e => this.setLimit(-1)}
checked={limit === -1}
/> Unlimited
</Label>
</FormGroup>
<FormGroup check className="form-check-inline">
<Label for={`${prop}-custom`} check>
<Input
type="radio"
name={prop}
id={`${prop}-custom`}
onChange={e => this.setLimit(1)}
checked={limit !== -1 && limit !== null}
/> Custom
</Label>
</FormGroup>
</FormGroup>
{limit !== -1 && limit !== null &&
<div className="row">
<FormGroup className="col-md-6">
<Input
type="number"
value={convertFromBitrate(limit, unit)}
onChange={e => this.setLimit(parseFloat(e.target.value))}
/>
</FormGroup>
<FormGroup className="col-md-6">
<Input
type="select"
id="unit"
value={unit}
onChange={e => this.setUnit(e.target.value)}
>
<option value="b/s">b/s</option>
<option value="KiB/s">KiB/s</option>
<option value="MiB/s">MiB/s</option>
<option value="GiB/s">GiB/s</option>
</Input>
</FormGroup>
</div>
}
</div>
);
}
}

View File

@ -151,6 +151,7 @@ class Torrent extends Component {
<dd>{date(moment(torrent.created))}</dd> <dd>{date(moment(torrent.created))}</dd>
</dl> </dl>
<TorrentOptions <TorrentOptions
id={torrent.id}
priority={torrent.priority} priority={torrent.priority}
priorityChanged={priority => priorityChanged={priority =>
dispatch(updateResource({ id: torrent.id, priority }))} dispatch(updateResource({ id: torrent.id, priority }))}

View File

@ -4,103 +4,12 @@ import {
Label, Label,
Input Input
} from 'reactstrap'; } from 'reactstrap';
import { convertFromBitrate, convertToBitrate } from '../bitrate'; import Throttle from './throttle';
class Throttle extends Component {
constructor() {
super();
this.setLimit = this.setLimit.bind(this);
this.setUnit = this.setUnit.bind(this);
this.state = { unit: "MiB/s" };
}
setLimit(limit) {
const { onChange } = this.props;
const { unit } = this.state;
const converted = limit <= 0 || limit === null ?
limit : convertToBitrate(limit, unit);
onChange && onChange(converted);
}
setUnit(unit) {
const limit = convertFromBitrate(this.props.limit, this.state.unit);
this.setState({ unit });
this.setLimit(limit);
}
render() {
const { limit, legend, prop } = this.props;
const { unit } = this.state;
return (
<div>
<FormGroup tag="fieldset">
<legend>{legend}</legend>
<FormGroup check className="form-check-inline">
<Label for={`${prop}-global`} check>
<Input
type="radio"
name={prop}
id={`${prop}-global`}
onChange={e => this.setLimit(null)}
checked={limit === null}
/> Global
</Label>
</FormGroup>
<FormGroup check className="form-check-inline">
<Label for={`${prop}-unlimited`} check>
<Input
type="radio"
name={prop}
id={`${prop}-unlimited`}
onChange={e => this.setLimit(-1)}
checked={limit === -1}
/> Unlimited
</Label>
</FormGroup>
<FormGroup check className="form-check-inline">
<Label for={`${prop}-custom`} check>
<Input
type="radio"
name={prop}
id={`${prop}-custom`}
onChange={e => this.setLimit(1)}
checked={limit !== -1 && limit !== null}
/> Custom
</Label>
</FormGroup>
</FormGroup>
{limit !== -1 && limit !== null &&
<div className="row">
<FormGroup className="col-md-6">
<Input
type="number"
value={convertFromBitrate(limit, unit)}
onChange={e => this.setLimit(parseFloat(e.target.value))}
/>
</FormGroup>
<FormGroup className="col-md-6">
<Input
type="select"
id="unit"
value={unit}
onChange={e => this.setUnit(e.target.value)}
>
<option value="b/s">b/s</option>
<option value="KiB/s">KiB/s</option>
<option value="MiB/s">MiB/s</option>
<option value="GiB/s">GiB/s</option>
</Input>
</FormGroup>
</div>
}
</div>
);
}
}
export default class TorrentOptions extends Component { export default class TorrentOptions extends Component {
render() { render() {
const { const {
id,
start, start,
startChanged, startChanged,
priority, priority,
@ -140,13 +49,13 @@ export default class TorrentOptions extends Component {
</Input> </Input>
</FormGroup> </FormGroup>
<Throttle <Throttle
prop="dl-throttle" prop={`dl-throttle-${id}`}
legend="Download throttle" legend="Download throttle"
limit={downloadThrottle} limit={downloadThrottle}
onChange={limit => downloadThrottleChanged(limit)} onChange={limit => downloadThrottleChanged(limit)}
/> />
<Throttle <Throttle
prop="ul-throttle" prop={`ul-throttle-${id}`}
legend="Upload throttle" legend="Upload throttle"
limit={uploadThrottle} limit={uploadThrottle}
onChange={limit => uploadThrottleChanged(limit)} onChange={limit => uploadThrottleChanged(limit)}