diff --git a/client/src/javascript/components/general/TorrentStatusIcon.tsx b/client/src/javascript/components/general/TorrentStatusIcon.tsx index aa65d7d3b..ea776fffa 100644 --- a/client/src/javascript/components/general/TorrentStatusIcon.tsx +++ b/client/src/javascript/components/general/TorrentStatusIcon.tsx @@ -16,7 +16,8 @@ const TorrentStatusIcon: FC = memo(({status}: TorrentSta return ; case 'downloading': return ; - case 'queued': + case 'downloading-queued': + case 'seeding-queued': return ; case 'seeding': return ; diff --git a/client/src/javascript/components/sidebar/SidebarFilter.tsx b/client/src/javascript/components/sidebar/SidebarFilter.tsx index 35798338f..8c7f04564 100644 --- a/client/src/javascript/components/sidebar/SidebarFilter.tsx +++ b/client/src/javascript/components/sidebar/SidebarFilter.tsx @@ -28,7 +28,7 @@ const SidebarFilter: FC = ({ const classNames = classnames('sidebar-filter__item', { 'is-active': isActive, - 'queued': slug === 'queued', + 'queued': slug === 'downloading-queued' || slug === 'seeding-queued', }); let name = _name; @@ -41,7 +41,7 @@ const SidebarFilter: FC = ({ name = i18n._('filter.untagged'); } - if (slug === 'checking' || slug === 'error' || slug === 'queued') { + if (slug === 'checking' || slug === 'error' || slug === 'downloading-queued' || slug === 'seeding-queued') { if (count === 0) { return null; } diff --git a/client/src/javascript/components/sidebar/StatusFilters.tsx b/client/src/javascript/components/sidebar/StatusFilters.tsx index 6ec86b39d..311f42a25 100644 --- a/client/src/javascript/components/sidebar/StatusFilters.tsx +++ b/client/src/javascript/components/sidebar/StatusFilters.tsx @@ -30,7 +30,7 @@ const StatusFilters: FC = observer(() => { }, { label: i18n._('filter.status.queued'), - slug: 'queued', + slug: 'downloading-queued', icon: , }, { @@ -38,6 +38,11 @@ const StatusFilters: FC = observer(() => { slug: 'seeding', icon: , }, + { + label: i18n._('filter.status.queued'), + slug: 'seeding-queued', + icon: , + }, { label: i18n._('filter.status.checking'), slug: 'checking', diff --git a/client/src/javascript/stores/TorrentStore.ts b/client/src/javascript/stores/TorrentStore.ts index 92491004a..8514d33e8 100644 --- a/client/src/javascript/stores/TorrentStore.ts +++ b/client/src/javascript/stores/TorrentStore.ts @@ -10,6 +10,7 @@ import type {TorrentProperties, TorrentList} from '@shared/types/Torrent'; import SettingStore from './SettingStore'; import TorrentFilterStore from './TorrentFilterStore'; +import { TorrentStatus } from '@shared/constants/torrentStatusMap'; class TorrentStore { selectedTorrents: Array = []; @@ -37,6 +38,14 @@ class TorrentStore { type: 'status', filter: statusFilter, }); + if (['downloading','seeding'].includes(statusFilter)) { + const queuedStatus = statusFilter + '-queued' as TorrentStatus; + filteredTorrents = filterTorrents(filteredTorrents, { + type: 'status', + filter: queuedStatus, + negated: true, + }); + } } if (tagFilter !== '') { diff --git a/client/src/javascript/util/filterTorrents.ts b/client/src/javascript/util/filterTorrents.ts index af990cce0..6215c8be9 100644 --- a/client/src/javascript/util/filterTorrents.ts +++ b/client/src/javascript/util/filterTorrents.ts @@ -4,30 +4,39 @@ import type {TorrentStatus} from '@shared/constants/torrentStatusMap'; interface StatusFilter { type: 'status'; filter: TorrentStatus; + negated?: boolean; } interface TrackerFilter { type: 'tracker'; filter: string; + negated?: boolean; } interface TagFilter { type: 'tag'; filter: string; + negated?: boolean; } function filterTorrents( torrentList: TorrentProperties[], opts: StatusFilter | TrackerFilter | TagFilter, ): TorrentProperties[] { - const {type, filter} = opts; + const {type, filter, negated} = opts; if (filter !== '') { if (type === 'status') { - return torrentList.filter((torrent) => torrent.status.includes(filter as TorrentStatus)); + return torrentList.filter((torrent) => { + const included = torrent.status.includes(filter as TorrentStatus); + return included && !negated || !included && negated; + }); } if (type === 'tracker') { - return torrentList.filter((torrent) => torrent.trackerURIs.includes(filter)); + return torrentList.filter((torrent) => { + const included = torrent.trackerURIs.includes(filter); + return included && !negated || !included && negated; + }); } if (type === 'tag') { return torrentList.filter((torrent) => { @@ -35,7 +44,8 @@ function filterTorrents( return torrent.tags.length === 0; } - return torrent.tags.includes(filter); + const included = torrent.tags.includes(filter); + return included && !negated || !included && negated; }); } } diff --git a/client/src/javascript/util/torrentStatus.ts b/client/src/javascript/util/torrentStatus.ts index edf9db5cb..cf726a260 100644 --- a/client/src/javascript/util/torrentStatus.ts +++ b/client/src/javascript/util/torrentStatus.ts @@ -16,12 +16,13 @@ export const torrentStatusClasses = ( 'torrent--is-completed': status.includes('complete'), 'torrent--is-checking': status.includes('checking'), 'torrent--is-inactive': status.includes('inactive'), + 'torrent--is-queued': status.includes('downloading-queued') || status.includes('seeding-queued'), }); export const torrentStatusEffective = (status: TorrentProperties['status']): TorrentProperties['status'][number] => { let result: TorrentProperties['status'][number] = 'stopped'; - ['error', 'checking', 'stopped', 'downloading', 'queued', 'seeding'].some((state) => { + ['error', 'checking', 'stopped', 'downloading', 'downloading-queued', 'seeding', 'seeding-queued'].some((state) => { if (status.includes(state as TorrentProperties['status'][number])) { result = state as TorrentProperties['status'][number]; return true; diff --git a/server/services/Transmission/util/torrentPropertiesUtil.ts b/server/services/Transmission/util/torrentPropertiesUtil.ts index d5311641c..06c698c3c 100644 --- a/server/services/Transmission/util/torrentPropertiesUtil.ts +++ b/server/services/Transmission/util/torrentPropertiesUtil.ts @@ -17,6 +17,8 @@ const getTorrentStatus = ( case TransmissionTorrentStatus.TR_STATUS_CHECK_WAIT: statuses.push('checking'); break; + case TransmissionTorrentStatus.TR_STATUS_DOWNLOAD_WAIT: + statuses.push('downloading-queued'); case TransmissionTorrentStatus.TR_STATUS_DOWNLOAD: statuses.push('downloading'); if (rateDownload > 0) { @@ -25,11 +27,9 @@ const getTorrentStatus = ( statuses.push('inactive'); } break; - case TransmissionTorrentStatus.TR_STATUS_DOWNLOAD_WAIT: - statuses.push('queued', 'inactive'); - break; - case TransmissionTorrentStatus.TR_STATUS_SEED: case TransmissionTorrentStatus.TR_STATUS_SEED_WAIT: + statuses.push('seeding-queued'); + case TransmissionTorrentStatus.TR_STATUS_SEED: statuses.push('seeding'); if (rateUpload > 0) { statuses.push('active'); diff --git a/shared/constants/torrentStatusMap.ts b/shared/constants/torrentStatusMap.ts index 48aa73b98..28ab3a200 100644 --- a/shared/constants/torrentStatusMap.ts +++ b/shared/constants/torrentStatusMap.ts @@ -7,7 +7,8 @@ const torrentStatusMap = [ 'error', 'inactive', 'active', - 'queued', + 'downloading-queued', + 'seeding-queued', ] as const; export type TorrentStatus = typeof torrentStatusMap[number];