mirror of
https://github.com/transmission/transmission.git
synced 2025-12-24 20:35:36 +00:00
Add labels support into web client. (#1406)
* Add labels support into web client.
This commit is contained in:
committed by
GitHub
parent
7bdb6f777b
commit
ab02edfde2
File diff suppressed because one or more lines are too long
@@ -45,6 +45,10 @@ export class ActionManager extends EventTarget {
|
||||
shortcut: 'Alt+I',
|
||||
text: 'Torrent Inspector',
|
||||
},
|
||||
'show-labels-dialog': {
|
||||
enabled: false,
|
||||
text: 'Edit Labels…',
|
||||
},
|
||||
'show-move-dialog': {
|
||||
enabled: false,
|
||||
shortcut: 'Alt+L',
|
||||
@@ -185,9 +189,10 @@ export class ActionManager extends EventTarget {
|
||||
'move-down',
|
||||
'move-top',
|
||||
'move-up',
|
||||
'show-inspector',
|
||||
'show-move-dialog',
|
||||
'remove-selected-torrents',
|
||||
'show-inspector',
|
||||
'show-labels-dialog',
|
||||
'show-move-dialog',
|
||||
'trash-selected-torrents',
|
||||
'verify-selected-torrents',
|
||||
]);
|
||||
|
||||
@@ -89,6 +89,7 @@ export class ContextMenu extends EventTarget {
|
||||
add_item('verify-selected-torrents');
|
||||
add_item('show-move-dialog');
|
||||
add_item('show-rename-dialog');
|
||||
add_item('show-labels-dialog');
|
||||
add_separator();
|
||||
add_item('reannounce-selected-torrents');
|
||||
add_separator();
|
||||
|
||||
@@ -117,6 +117,7 @@ export class Inspector extends EventTarget {
|
||||
['origin', 'Origin:'],
|
||||
['magnetLink', 'Magnet:'],
|
||||
['comment', 'Comment:'],
|
||||
['labels', 'Labels:'],
|
||||
];
|
||||
for (const [name, text] of rows) {
|
||||
elements[name] = append_row(text);
|
||||
@@ -490,6 +491,10 @@ export class Inspector extends EventTarget {
|
||||
setTextContent(e.info.comment, string);
|
||||
}
|
||||
|
||||
// labels
|
||||
string = torrents.length === 0 ? none : torrents[0].getLabels().join(', ');
|
||||
setTextContent(e.info.labels, string);
|
||||
|
||||
// origin
|
||||
if (torrents.length === 0) {
|
||||
string = none;
|
||||
|
||||
@@ -103,6 +103,14 @@ export class Remote {
|
||||
this.sendRequest(o, callback, context);
|
||||
}
|
||||
|
||||
setLabels(torrentIds, labels, callback) {
|
||||
const args = {
|
||||
ids: torrentIds,
|
||||
labels,
|
||||
};
|
||||
this.sendRequest({ arguments: args, method: 'torrent-set' }, callback);
|
||||
}
|
||||
|
||||
loadDaemonStats(callback, context) {
|
||||
const o = {
|
||||
method: 'session-stats',
|
||||
|
||||
@@ -18,6 +18,12 @@ const TorrentRendererHelper = {
|
||||
}
|
||||
return `ETA: ${Formatter.timeInterval(eta)}`;
|
||||
},
|
||||
formatLabels: (t) => {
|
||||
if (t.getLabels().length > 0) {
|
||||
return `🏷 ${t.getLabels().join(', ')}`;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
formatUL: (t) => {
|
||||
return `▲${Formatter.speedBps(t.getUploadSpeed())}`;
|
||||
},
|
||||
@@ -215,6 +221,10 @@ export class TorrentRendererFull {
|
||||
setTextContent(e, t.getName());
|
||||
e.classList.toggle('paused', is_stopped);
|
||||
|
||||
// labels
|
||||
e = root._labels_container;
|
||||
setTextContent(e, TorrentRendererHelper.formatLabels(t));
|
||||
|
||||
// progressbar
|
||||
TorrentRendererHelper.renderProgressbar(controller, t, root._progressbar);
|
||||
root._progressbar.classList.add('full');
|
||||
@@ -251,6 +261,9 @@ export class TorrentRendererFull {
|
||||
const name = document.createElement('div');
|
||||
name.className = 'torrent-name';
|
||||
|
||||
const labels = document.createElement('div');
|
||||
labels.className = 'torrent-labels';
|
||||
|
||||
const peers = document.createElement('div');
|
||||
peers.className = 'torrent-peer-details';
|
||||
|
||||
@@ -268,12 +281,14 @@ export class TorrentRendererFull {
|
||||
|
||||
root.append(icon);
|
||||
root.append(name);
|
||||
root.append(labels);
|
||||
root.append(peers);
|
||||
root.append(progress);
|
||||
root.append(details);
|
||||
|
||||
root._icon = icon;
|
||||
root._name_container = name;
|
||||
root._labels_container = labels;
|
||||
root._peer_details_container = peers;
|
||||
root._progress_details_container = details;
|
||||
root._progressbar = progressbar;
|
||||
@@ -323,6 +338,10 @@ export class TorrentRendererCompact {
|
||||
e.classList.toggle('paused', t.isStopped());
|
||||
setTextContent(e, t.getName());
|
||||
|
||||
// labels
|
||||
e = root._labels_container;
|
||||
setTextContent(e, TorrentRendererHelper.formatLabels(t));
|
||||
|
||||
// peer details
|
||||
const has_error = t.getError() !== Torrent._ErrNone;
|
||||
e = root._details_container;
|
||||
@@ -350,17 +369,22 @@ export class TorrentRendererCompact {
|
||||
const details = document.createElement('div');
|
||||
details.className = 'torrent-peer-details compact';
|
||||
|
||||
const labels = document.createElement('div');
|
||||
labels.className = 'torrent-labels compact';
|
||||
|
||||
const name = document.createElement('div');
|
||||
name.className = 'torrent-name compact';
|
||||
|
||||
const root = document.createElement('li');
|
||||
root.append(progressbar);
|
||||
root.append(details);
|
||||
root.append(labels);
|
||||
root.append(name);
|
||||
root.append(icon);
|
||||
root.className = 'torrent compact';
|
||||
root._progressbar = progressbar;
|
||||
root._details_container = details;
|
||||
root._labels_container = labels;
|
||||
root._name_container = name;
|
||||
return root;
|
||||
}
|
||||
|
||||
@@ -203,6 +203,9 @@ export class Torrent extends EventTarget {
|
||||
getId() {
|
||||
return this.fields.id;
|
||||
}
|
||||
getLabels() {
|
||||
return this.fields.labels.sort();
|
||||
}
|
||||
getLastActivity() {
|
||||
return this.fields.activityDate;
|
||||
}
|
||||
@@ -419,19 +422,36 @@ export class Torrent extends EventTarget {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param filter one of Prefs.Filter*
|
||||
* @param state one of Prefs.Filter*
|
||||
* @param tracker tracker name
|
||||
* @param search substring to look for, or null
|
||||
* @param labels array of labels. Empty array matches all.
|
||||
* @return true if it passes the test, false if it fails
|
||||
*/
|
||||
test(state, search, tracker) {
|
||||
test(state, tracker, search, labels) {
|
||||
// flter by state...
|
||||
let pass = this.testState(state);
|
||||
|
||||
// maybe filter by text...
|
||||
if (pass && search && search.length > 0) {
|
||||
if (pass && search) {
|
||||
pass = this.getCollatedName().includes(search.toLowerCase());
|
||||
}
|
||||
|
||||
// maybe filter by labels...
|
||||
if (pass) {
|
||||
for (const l of labels) {
|
||||
let m = false;
|
||||
for (let j = 0; j < this.getLabels().length; j++) {
|
||||
if (l === this.getLabels()[j]) {
|
||||
m = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pass = pass && m;
|
||||
}
|
||||
}
|
||||
|
||||
// maybe filter by tracker...
|
||||
if (pass && tracker && tracker.length > 0) {
|
||||
pass = this.getCollatedTrackers().includes(tracker);
|
||||
@@ -627,6 +647,7 @@ Torrent.Fields.Stats = [
|
||||
'eta',
|
||||
'isFinished',
|
||||
'isStalled',
|
||||
'labels',
|
||||
'leftUntilDone',
|
||||
'metadataPercentComplete',
|
||||
'peersConnected',
|
||||
|
||||
@@ -14,6 +14,7 @@ import { PrefsDialog } from './prefs-dialog.js';
|
||||
import { Remote, RPC } from './remote.js';
|
||||
import { RemoveDialog } from './remove-dialog.js';
|
||||
import { RenameDialog } from './rename-dialog.js';
|
||||
import { LabelsDialog } from './labels-dialog.js';
|
||||
import { ShortcutsDialog } from './shortcuts-dialog.js';
|
||||
import { StatisticsDialog } from './statistics-dialog.js';
|
||||
import { Torrent } from './torrent.js';
|
||||
@@ -170,6 +171,9 @@ export class Transmission extends EventTarget {
|
||||
case 'show-rename-dialog':
|
||||
this.setCurrentPopup(new RenameDialog(this, this.remote));
|
||||
break;
|
||||
case 'show-labels-dialog':
|
||||
this.setCurrentPopup(new LabelsDialog(this, this.remote));
|
||||
break;
|
||||
case 'start-all-torrents':
|
||||
this._startTorrents(this._getAllTorrents());
|
||||
break;
|
||||
@@ -909,11 +913,21 @@ TODO: fix this when notifications get fixed
|
||||
|
||||
_refilter(rebuildEverything) {
|
||||
const { sort_mode, sort_direction, filter_mode } = this.prefs;
|
||||
const filter_text = this.filterText;
|
||||
const filter_tracker = this.filterTracker;
|
||||
const renderer = this.torrentRenderer;
|
||||
const list = this.elements.torrent_list;
|
||||
|
||||
let filter_text = null;
|
||||
let labels = null;
|
||||
const m = /^labels:([\w,]*)(.*)$/.exec(this.filterText);
|
||||
if (m) {
|
||||
filter_text = m[2].trim();
|
||||
labels = m[1].split(',');
|
||||
} else {
|
||||
filter_text = this.filterText;
|
||||
labels = [];
|
||||
}
|
||||
|
||||
const countRows = () => [...list.children].length;
|
||||
const countSelectedRows = () =>
|
||||
[...list.children].reduce(
|
||||
@@ -958,7 +972,7 @@ TODO: fix this when notifications get fixed
|
||||
for (const row of dirty_rows) {
|
||||
const id = row.getTorrentId();
|
||||
const t = this._torrents[id];
|
||||
if (t && t.test(filter_mode, filter_text, filter_tracker)) {
|
||||
if (t && t.test(filter_mode, filter_tracker, filter_text, labels)) {
|
||||
temporary.push(row);
|
||||
}
|
||||
this.dirtyTorrents.delete(id);
|
||||
@@ -969,7 +983,7 @@ TODO: fix this when notifications get fixed
|
||||
// but don't already have a row
|
||||
for (const id of this.dirtyTorrents.values()) {
|
||||
const t = this._torrents[id];
|
||||
if (t && t.test(filter_mode, filter_text, filter_tracker)) {
|
||||
if (t && t.test(filter_mode, filter_tracker, filter_text, labels)) {
|
||||
const row = new TorrentRow(renderer, this, t);
|
||||
const e = row.getElement();
|
||||
e.row = row;
|
||||
|
||||
@@ -450,11 +450,11 @@ $popup-top: 61px; // TODO: ugly that this is hardcoded
|
||||
display: grid;
|
||||
grid-column-gap: 12px;
|
||||
grid-template-areas:
|
||||
'icon name'
|
||||
'icon peers'
|
||||
'icon progressbar'
|
||||
'icon progress-text';
|
||||
grid-template-columns: $icon-size 1fr;
|
||||
'icon name labels'
|
||||
'icon peers peers'
|
||||
'icon progressbar progressbar'
|
||||
'icon progress-text progress-text';
|
||||
grid-template-columns: $icon-size auto 1fr;
|
||||
padding: 2px 12px;
|
||||
|
||||
.icon {
|
||||
@@ -468,6 +468,10 @@ $popup-top: 61px; // TODO: ugly that this is hardcoded
|
||||
grid-area: name;
|
||||
}
|
||||
|
||||
.torrent-labels {
|
||||
grid-area: labels;
|
||||
}
|
||||
|
||||
.torrent-peer-details {
|
||||
grid-area: peers;
|
||||
}
|
||||
@@ -539,7 +543,6 @@ $popup-top: 61px; // TODO: ugly that this is hardcoded
|
||||
white-space: nowrap;
|
||||
|
||||
&.compact {
|
||||
flex: 1;
|
||||
font-size: 1em;
|
||||
font-weight: normal;
|
||||
}
|
||||
@@ -549,6 +552,21 @@ $popup-top: 61px; // TODO: ugly that this is hardcoded
|
||||
}
|
||||
}
|
||||
|
||||
.torrent-labels {
|
||||
font-size: x-small;
|
||||
font-weight: normal;
|
||||
margin-bottom: 2px;
|
||||
margin-top: 2px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
&.compact {
|
||||
flex: 1;
|
||||
font-size: x-small;
|
||||
}
|
||||
}
|
||||
|
||||
.torrent-progress-details,
|
||||
.torrent-peer-details {
|
||||
font-size: x-small;
|
||||
|
||||
Reference in New Issue
Block a user