1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2026-04-27 23:06:29 -04:00

New: Series custom filter for Monitored Episodes

Closes #7552
This commit is contained in:
Mark McDowall
2025-12-24 16:52:29 -08:00
parent ee875ae654
commit 5f8297da6c
13 changed files with 96 additions and 51 deletions
@@ -16,11 +16,11 @@ import DefaultFilterBuilderRowValue from './DefaultFilterBuilderRowValue';
import HistoryEventTypeFilterBuilderRowValue from './HistoryEventTypeFilterBuilderRowValue';
import IndexerFilterBuilderRowValue from './IndexerFilterBuilderRowValue';
import LanguageFilterBuilderRowValue from './LanguageFilterBuilderRowValue';
import MonitoredStatusFilterBuilderRowValue from './MonitoredStatusFilterBuilderRowValue';
import ProtocolFilterBuilderRowValue from './ProtocolFilterBuilderRowValue';
import QualityFilterBuilderRowValue from './QualityFilterBuilderRowValue';
import QualityProfileFilterBuilderRowValue from './QualityProfileFilterBuilderRowValue';
import QueueStatusFilterBuilderRowValue from './QueueStatusFilterBuilderRowValue';
import SeasonsMonitoredStatusFilterBuilderRowValue from './SeasonsMonitoredStatusFilterBuilderRowValue';
import SeriesFilterBuilderRowValue from './SeriesFilterBuilderRowValue';
import SeriesStatusFilterBuilderRowValue from './SeriesStatusFilterBuilderRowValue';
import SeriesTypeFilterBuilderRowValue from './SeriesTypeFilterBuilderRowValue';
@@ -109,8 +109,8 @@ function getRowValueConnector<T>(
case filterBuilderValueTypes.QUEUE_STATUS:
return QueueStatusFilterBuilderRowValue;
case filterBuilderValueTypes.SEASONS_MONITORED_STATUS:
return SeasonsMonitoredStatusFilterBuilderRowValue;
case filterBuilderValueTypes.MONITORED_STATUS:
return MonitoredStatusFilterBuilderRowValue;
case filterBuilderValueTypes.SERIES:
return SeriesFilterBuilderRowValue;
@@ -0,0 +1,39 @@
import React from 'react';
import translate from 'Utilities/String/translate';
import FilterBuilderRowValue, {
FilterBuilderRowValueProps,
} from './FilterBuilderRowValue';
const monitoredStatusList = [
{
id: 'all',
get name() {
return translate('MonitoredAll');
},
},
{
id: 'partial',
get name() {
return translate('MonitoredPartial');
},
},
{
id: 'none',
get name() {
return translate('MonitoredNone');
},
},
];
type MonitoredStatusFilterBuilderRowValueProps<T> = Omit<
FilterBuilderRowValueProps<T, string, string>,
'tagList'
>;
function MonitoredStatusFilterBuilderRowValue<T>(
props: MonitoredStatusFilterBuilderRowValueProps<T>
) {
return <FilterBuilderRowValue tagList={monitoredStatusList} {...props} />;
}
export default MonitoredStatusFilterBuilderRowValue;
@@ -1,41 +0,0 @@
import React from 'react';
import translate from 'Utilities/String/translate';
import FilterBuilderRowValue, {
FilterBuilderRowValueProps,
} from './FilterBuilderRowValue';
const seasonsMonitoredStatusList = [
{
id: 'all',
get name() {
return translate('SeasonsMonitoredAll');
},
},
{
id: 'partial',
get name() {
return translate('SeasonsMonitoredPartial');
},
},
{
id: 'none',
get name() {
return translate('SeasonsMonitoredNone');
},
},
];
type SeasonsMonitoredStatusFilterBuilderRowValueProps<T> = Omit<
FilterBuilderRowValueProps<T, string, string>,
'tagList'
>;
function SeasonsMonitoredStatusFilterBuilderRowValue<T>(
props: SeasonsMonitoredStatusFilterBuilderRowValueProps<T>
) {
return (
<FilterBuilderRowValue tagList={seasonsMonitoredStatusList} {...props} />
);
}
export default SeasonsMonitoredStatusFilterBuilderRowValue;
@@ -9,7 +9,7 @@ export const PROTOCOL = 'protocol';
export const QUALITY = 'quality';
export const QUALITY_PROFILE = 'qualityProfile';
export const QUEUE_STATUS = 'queueStatus';
export const SEASONS_MONITORED_STATUS = 'seasonsMonitoredStatus';
export const MONITORED_STATUS = 'monitoredStatus';
export const SERIES = 'series';
export const SERIES_STATUS = 'seriesStatus';
export const SERIES_TYPES = 'seriesType';
@@ -27,7 +27,7 @@ export type FilterBuildValueType =
| 'quality'
| 'qualityProfile'
| 'queueStatus'
| 'seasonsMonitoredStatus'
| 'monitoredStatus'
| 'series'
| 'seriesStatus'
| 'seriesType'
+1
View File
@@ -36,6 +36,7 @@ export interface Statistics {
releaseGroups: string[];
sizeOnDisk: number;
totalEpisodeCount: number;
monitoredEpisodeCount: number;
lastAired?: string;
}
+39 -2
View File
@@ -17,7 +17,7 @@ import { SortDirection } from 'Helpers/Props/sortDirections';
import sortByProp from 'Utilities/Array/sortByProp';
import clientSideFilterAndSort from 'Utilities/Filter/clientSideFilterAndSort';
import translate from 'Utilities/String/translate';
import Series from './Series';
import Series, { Statistics } from './Series';
import { useSeriesOptions } from './seriesOptionsStore';
// Date filter predicate helper
@@ -315,6 +315,37 @@ const FILTER_PREDICATES = {
return predicate(seasonsMonitoredStatus, filterValue);
},
episodesMonitoredStatus: (
item: Series,
filterValue: string,
type: FilterType
) => {
const predicate = getFilterTypePredicate(type);
const { seasons, statistics = {} as Statistics } = item;
const { monitoredEpisodeCount = 0, totalEpisodeCount = 0 } = statistics;
const specials = seasons?.find((s) => s.seasonNumber === 0);
// The monitored count and total count include specials, but those areskipped
// for seasons monitored status so we should to exclude them here too.
const monitoredCount =
monitoredEpisodeCount -
(specials?.statistics?.monitoredEpisodeCount ?? 0);
const totalCount =
totalEpisodeCount - (specials?.statistics?.totalEpisodeCount ?? 0);
let episodesMonitoredStatus = 'partial';
if (monitoredCount === 0) {
episodesMonitoredStatus = 'none';
} else if (totalCount - monitoredCount === 0) {
episodesMonitoredStatus = 'all';
}
return predicate(episodesMonitoredStatus, filterValue);
},
} as const;
export const FILTER_BUILDER: FilterBuilderProp<Series>[] = [
@@ -498,7 +529,13 @@ export const FILTER_BUILDER: FilterBuilderProp<Series>[] = [
name: 'seasonsMonitoredStatus',
label: () => translate('SeasonsMonitoredStatus'),
type: filterBuilderTypes.EXACT,
valueType: filterBuilderValueTypes.SEASONS_MONITORED_STATUS,
valueType: filterBuilderValueTypes.MONITORED_STATUS,
},
{
name: 'episodesMonitoredStatus',
label: () => translate('EpisodesMonitoredStatus'),
type: filterBuilderTypes.EXACT,
valueType: filterBuilderValueTypes.MONITORED_STATUS,
},
{
name: 'year',