feature: allow multi-torrent priority change

This commit is contained in:
Jesse Chan
2020-10-04 20:59:30 +08:00
parent 4bd090d0bb
commit 5e1c09153c
9 changed files with 89 additions and 61 deletions
@@ -6,6 +6,7 @@ import type {
CheckTorrentsOptions,
DeleteTorrentsOptions,
MoveTorrentsOptions,
SetTorrentsPriorityOptions,
StartTorrentsOptions,
StopTorrentsOptions,
} from '@shared/types/Action';
@@ -220,12 +221,9 @@ const TorrentActions = {
},
),
setPriority: (hash: TorrentProperties['hash'], priority: number) =>
setPriority: (options: SetTorrentsPriorityOptions) =>
axios
.patch(`${baseURI}api/torrents/${hash}/priority`, {
hash,
priority,
})
.patch(`${baseURI}api/torrents/priority`, options)
.then((json) => json.data)
.then(
(data) => {
@@ -9,8 +9,8 @@ interface PriorityMeterProps extends WrappedComponentProps {
maxLevel: number;
priorityType: keyof typeof PriorityLevels;
showLabel?: boolean;
clickHandled?: boolean;
onChange: (id: this['id'], level: this['level']) => void;
bindExternalChangeHandler?: (clickHandler: (() => void) | null) => void;
}
interface PriorityMeterStates {
@@ -36,18 +36,6 @@ class PriorityMeter extends React.Component<PriorityMeterProps, PriorityMeterSta
});
}
componentDidMount() {
if (this.props.bindExternalChangeHandler) {
this.props.bindExternalChangeHandler(this.handleClick);
}
}
componentWillUnmount() {
if (this.props.bindExternalChangeHandler) {
this.props.bindExternalChangeHandler(null);
}
}
getPriorityLabel() {
const priorityLevel = PriorityLevels[this.props.priorityType];
switch (priorityLevel[this.getPriorityLevel() as keyof typeof priorityLevel]) {
@@ -101,7 +89,7 @@ class PriorityMeter extends React.Component<PriorityMeterProps, PriorityMeterSta
}
return (
<div className="priority-meter__wrapper" onClick={this.handleClick}>
<div className="priority-meter__wrapper" onClick={this.props.clickHandled ? undefined : this.handleClick}>
<div
className={
'priority-meter ' +
@@ -115,4 +103,4 @@ class PriorityMeter extends React.Component<PriorityMeterProps, PriorityMeterSta
}
}
export default injectIntl(PriorityMeter);
export default injectIntl(PriorityMeter, {forwardRef: true});
@@ -64,7 +64,7 @@ export default class TorrentHeading extends React.Component<TorrentHeadingProps,
maxLevel={3}
priorityType="torrent"
onChange={(hash, level) => {
TorrentActions.setPriority(hash as string, level);
TorrentActions.setPriority({hashes: [`${hash}`], priority: level});
}}
/>
</li>,
@@ -7,9 +7,8 @@ import TorrentContextMenuItems from '../../constants/TorrentContextMenuItems';
import TorrentStore from '../../stores/TorrentStore';
import UIActions from '../../actions/UIActions';
let handleTorrentPriorityChange = (hash, level) => {
TorrentActions.setPriority(hash, level);
};
const priorityMeterRef = React.createRef();
let prioritySelected = 1;
const handleDetailsClick = (torrent, event) => {
UIActions.handleDetailsClick({
@@ -71,7 +70,11 @@ const handleItemClick = (action, event, torrent) => {
handleTorrentDownload(torrent, event);
break;
case 'set-priority':
handleTorrentPriorityChange(event);
priorityMeterRef.current.handleClick();
TorrentActions.setPriority({
hashes: selectedTorrents,
priority: prioritySelected,
});
break;
default:
break;
@@ -138,14 +141,15 @@ const getContextMenuItems = (intl, torrent, settings) => {
<PriorityMeter
id={torrent.hash}
key={torrent.hash}
bindExternalChangeHandler={(priorityChangeHandler) => {
handleTorrentPriorityChange = priorityChangeHandler;
}}
ref={priorityMeterRef}
level={torrent.priority}
maxLevel={3}
priorityType="torrent"
onChange={handleTorrentPriorityChange}
onChange={(_id, level) => {
prioritySelected = level;
}}
showLabel={false}
clickHandled
/>
),
},
-9
View File
@@ -238,15 +238,6 @@ class ClientRequest {
});
}
setPriority(options) {
const hashes = getEnsuredArray(options.hashes);
hashes.forEach((hash) => {
this.requests.push(getMethodCall('d.priority.set', [hash, options.priority]));
this.requests.push(getMethodCall('d.update_priorities', [hash]));
});
}
setSettings(options) {
const settings = getEnsuredArray(options.settings);
-11
View File
@@ -229,17 +229,6 @@ const client = {
request.send();
},
setPriority(user, services, hashes, data, callback) {
const request = new ClientRequest(user, services);
request.setPriority({hashes, priority: data.priority});
request.onComplete((response, error) => {
services.torrentService.fetchTorrentList();
callback(response, error);
});
request.send();
},
setSettings(user, services, payloads, callback) {
const request = new ClientRequest(user, services);
if (payloads.length === 0) return callback({});
+27 -12
View File
@@ -1,11 +1,12 @@
import express from 'express';
import type {
import {
AddTorrentByFileOptions,
AddTorrentByURLOptions,
CheckTorrentsOptions,
DeleteTorrentsOptions,
MoveTorrentsOptions,
SetTorrentsPriorityOptions,
StartTorrentsOptions,
StopTorrentsOptions,
} from '@shared/types/Action';
@@ -167,6 +168,31 @@ router.post<unknown, unknown, DeleteTorrentsOptions>('/delete', (req, res) => {
});
});
/**
* PATCH /api/torrents/priority
* @summary Sets priority of torrents.
* @tags Torrent
* @security AuthenticatedUser
* @param {SetTorrentsPriorityOptions} request.body.required - options - application/json
* @return {object} 200 - success response - application/json
* @return {Error} 500 - failure response - application/json
*/
router.patch<unknown, unknown, SetTorrentsPriorityOptions>('/priority', (req, res) => {
const {hashes, priority} = req.body;
const callback = ajaxUtil.getResponseFn(res);
req.services?.clientGatewayService
.setTorrentsPriority({hashes, priority})
.then((response) => {
req.services?.torrentService.fetchTorrentList();
return response;
})
.then(callback)
.catch((err) => {
callback(null, err);
});
});
/**
* PATCH /api/torrents/taxonomy
* @summary Sets tags of torrents.
@@ -258,15 +284,4 @@ router.get('/:hash/mediainfo', (req, res) => {
mediainfo.getMediainfo(req.services, req.params.hash, ajaxUtil.getResponseFn(res));
});
/**
* PATCH /api/torrents/{hash}/priority
* @summary Sets priority of a torrent.
* @tags Torrent
* @security AuthenticatedUser
* @param {string} hash.path
*/
router.patch('/:hash/priority', (req, res) => {
client.setPriority(req.user, req.services, req.params.hash, req.body, ajaxUtil.getResponseFn(res));
});
export default router;
+31
View File
@@ -9,6 +9,7 @@ import type {
CheckTorrentsOptions,
DeleteTorrentsOptions,
MoveTorrentsOptions,
SetTorrentsPriorityOptions,
StartTorrentsOptions,
StopTorrentsOptions,
} from '@shared/types/Action';
@@ -257,6 +258,36 @@ class ClientGatewayService extends BaseService<ClientGatewayServiceEvents> {
}, this.processClientRequestError);
}
/**
* Sets priority of torrents
*
* @param {SetTorrentsPriorityOptions} options - An object of options...
* @return {Promise} - Resolves with RPC call response or rejects with error.
*/
async setTorrentsPriority({hashes, priority}: SetTorrentsPriorityOptions) {
if (this.services == null || this.services.clientRequestManager == null) {
return Promise.reject();
}
const methodCalls = hashes.reduce((accumulator: MultiMethodCalls, hash) => {
accumulator.push({
methodName: 'd.priority.set',
params: [hash, `${priority}`],
});
accumulator.push({
methodName: 'd.update_priorities',
params: [hash],
});
return accumulator;
}, []);
return this.services.clientRequestManager
.methodCall('system.multicall', [methodCalls])
.then(this.processClientRequestSuccess, this.processClientRequestError);
}
/**
* Starts torrents
*
+12
View File
@@ -67,3 +67,15 @@ export interface StopTorrentsOptions {
// An array of string representing hashes of torrents to be stopped
hashes: Array<TorrentProperties['hash']>;
}
// PATCH /api/torrents/priority
export interface SetTorrentsPriorityOptions {
// An array of string representing hashes of torrents to operated on
hashes: Array<TorrentProperties['hash']>;
// Number representing priority:
// 0 - DON'T_DOWNLOAD
// 1 - LOW
// 2 - NORMAL
// 3 - HIGH
priority: number;
}