Flesh out server info page
This commit is contained in:
parent
1504288692
commit
83a281bee2
|
@ -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`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -1,20 +1,48 @@
|
||||||
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;
|
||||||
|
if (isNaN(ratio)) {
|
||||||
|
return <dd>0</dd>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<dd>
|
||||||
|
{`${
|
||||||
|
ratio.toFixed(3)
|
||||||
|
} (${
|
||||||
|
formatAmount(up)
|
||||||
|
} up, ${
|
||||||
|
formatAmount(down)
|
||||||
|
} down)`}
|
||||||
|
</dd>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
function Server({ server }) {
|
class Server extends Component {
|
||||||
|
componentDidMount() {
|
||||||
|
this.interval = setInterval(this.forceUpdate, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { server, dispatch } = this.props;
|
||||||
if (!server.id) {
|
if (!server.id) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h3>
|
<h3>
|
||||||
Server
|
Synapse
|
||||||
<button
|
<button
|
||||||
className="btn btn-sm btn-outline-danger pull-right"
|
className="btn btn-sm btn-outline-danger pull-right"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -27,18 +55,46 @@ function Server({ server }) {
|
||||||
<dl>
|
<dl>
|
||||||
<dt>Running since</dt>
|
<dt>Running since</dt>
|
||||||
<dd>{date(moment(server.started))}</dd>
|
<dd>{date(moment(server.started))}</dd>
|
||||||
<dt>Rate up</dt>
|
<dt>Current network use</dt>
|
||||||
<dd>{formatBitrate(server.rate_up)}</dd>
|
<dd>
|
||||||
<dt>Rate down</dt>
|
{`${
|
||||||
<dd>{formatBitrate(server.rate_down)}</dd>
|
formatBitrate(server.rate_up)
|
||||||
{/* TODO: Editable */}
|
} up, ${
|
||||||
<dt>Throttle up</dt>
|
formatBitrate(server.rate_down)
|
||||||
<dd>{throttle(server.throttle_up)}</dd>
|
} down`}
|
||||||
<dt>Throttle down</dt>
|
</dd>
|
||||||
<dd>{throttle(server.throttle_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>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(state => ({ server: state.server }))(Server);
|
export default connect(state => ({ server: state.server }))(Server);
|
||||||
|
|
101
src/ui/throttle.js
Normal file
101
src/ui/throttle.js
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 }))}
|
||||||
|
|
|
@ -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)}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user