mirror of
https://github.com/Sonarr/Sonarr
synced 2026-05-08 04:50:56 +02:00
New: Special Seasons filtering for Wanted Missing
This commit is contained in:
parent
24d780b77f
commit
e8e31def9b
8 changed files with 84 additions and 17 deletions
|
|
@ -20,6 +20,7 @@ import TablePager from 'Components/Table/TablePager';
|
|||
import Episode from 'Episode/Episode';
|
||||
import { useToggleEpisodesMonitored } from 'Episode/useEpisode';
|
||||
import { Filter } from 'Filters/Filter';
|
||||
import { useCustomFiltersList } from 'Filters/useCustomFilters';
|
||||
import { align, icons, kinds } from 'Helpers/Props';
|
||||
import { SortDirection } from 'Helpers/Props/sortDirections';
|
||||
import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal';
|
||||
|
|
@ -32,6 +33,7 @@ import {
|
|||
unregisterPagePopulator,
|
||||
} from 'Utilities/pagePopulator';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import MissingFilterModal from './MissingFilterModal';
|
||||
import {
|
||||
setMissingOption,
|
||||
setMissingOptions,
|
||||
|
|
@ -39,7 +41,7 @@ import {
|
|||
useMissingOptions,
|
||||
} from './missingOptionsStore';
|
||||
import MissingRow from './MissingRow';
|
||||
import useMissing, { FILTERS } from './useMissing';
|
||||
import useMissing, { FILTERS, useFilters } from './useMissing';
|
||||
|
||||
function getMonitoredValue(
|
||||
filters: Filter[],
|
||||
|
|
@ -66,6 +68,9 @@ function MissingContent() {
|
|||
const { columns, pageSize, sortKey, sortDirection, selectedFilterKey } =
|
||||
useMissingOptions();
|
||||
|
||||
const filters = useFilters();
|
||||
const customFilters = useCustomFiltersList('wanted.missing');
|
||||
|
||||
const isSearchingForAllEpisodes = useCommandExecuting(
|
||||
CommandNames.MissingEpisodeSearch
|
||||
);
|
||||
|
|
@ -257,8 +262,9 @@ function MissingContent() {
|
|||
<FilterMenu
|
||||
alignMenu={align.RIGHT}
|
||||
selectedFilterKey={selectedFilterKey}
|
||||
filters={FILTERS}
|
||||
customFilters={[]}
|
||||
filters={filters}
|
||||
customFilters={customFilters}
|
||||
filterModalConnectorComponent={MissingFilterModal}
|
||||
onFilterSelect={handleFilterSelect}
|
||||
/>
|
||||
</PageToolbarSection>
|
||||
|
|
|
|||
26
frontend/src/Wanted/Missing/MissingFilterModal.tsx
Normal file
26
frontend/src/Wanted/Missing/MissingFilterModal.tsx
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import { SetFilter } from 'Components/Filter/Filter';
|
||||
import FilterModal, { FilterModalProps } from 'Components/Filter/FilterModal';
|
||||
import Episode from 'Episode/Episode';
|
||||
import { setMissingOption } from './missingOptionsStore';
|
||||
import useMissing, { FILTER_BUILDER } from './useMissing';
|
||||
|
||||
type MissingFilterModalProps = FilterModalProps<Episode>;
|
||||
|
||||
export default function MissingFilterModal(props: MissingFilterModalProps) {
|
||||
const { records } = useMissing();
|
||||
|
||||
const dispatchSetFilter = useCallback(({ selectedFilterKey }: SetFilter) => {
|
||||
setMissingOption('selectedFilterKey', selectedFilterKey);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<FilterModal
|
||||
{...props}
|
||||
sectionItems={records}
|
||||
filterBuilderProps={FILTER_BUILDER}
|
||||
customFilterType="wanted.missing"
|
||||
dispatchSetFilter={dispatchSetFilter}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
import { keepPreviousData } from '@tanstack/react-query';
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import Episode from 'Episode/Episode';
|
||||
import { setEpisodeQueryKey } from 'Episode/useEpisode';
|
||||
import { Filter } from 'Filters/Filter';
|
||||
import { Filter, FilterBuilderProp } from 'Filters/Filter';
|
||||
import { useCustomFiltersList } from 'Filters/useCustomFilters';
|
||||
import usePage from 'Helpers/Hooks/usePage';
|
||||
import usePagedApiQuery from 'Helpers/Hooks/usePagedApiQuery';
|
||||
import { filterBuilderValueTypes } from 'Helpers/Props';
|
||||
import findSelectedFilters from 'Utilities/Filter/findSelectedFilters';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import { useMissingOptions } from './missingOptionsStore';
|
||||
|
||||
|
|
@ -31,20 +34,49 @@ export const FILTERS: Filter[] = [
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'excludeSpecials',
|
||||
label: () => translate('ExcludeSpecials'),
|
||||
filters: [
|
||||
{
|
||||
key: 'includeSpecials',
|
||||
value: [false],
|
||||
type: 'equal',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const FILTER_BUILDER: FilterBuilderProp<Episode>[] = [
|
||||
{
|
||||
name: 'monitored',
|
||||
label: () => translate('Monitored'),
|
||||
type: 'exact',
|
||||
valueType: filterBuilderValueTypes.BOOL,
|
||||
},
|
||||
{
|
||||
name: 'includeSpecials',
|
||||
label: () => translate('IncludeSpecials'),
|
||||
type: 'equal',
|
||||
valueType: filterBuilderValueTypes.BOOL,
|
||||
},
|
||||
];
|
||||
|
||||
const useMissing = () => {
|
||||
const { page, goToPage } = usePage('missing');
|
||||
const { pageSize, selectedFilterKey, sortKey, sortDirection } =
|
||||
useMissingOptions();
|
||||
const customFilters = useCustomFiltersList('wanted.missing');
|
||||
|
||||
const filters = useMemo(() => {
|
||||
return findSelectedFilters(selectedFilterKey, FILTERS, customFilters);
|
||||
}, [selectedFilterKey, customFilters]);
|
||||
|
||||
const { isPlaceholderData, queryKey, ...query } = usePagedApiQuery<Episode>({
|
||||
path: '/wanted/missing',
|
||||
page,
|
||||
pageSize,
|
||||
queryParams: {
|
||||
monitored: selectedFilterKey === 'monitored',
|
||||
},
|
||||
filters,
|
||||
sortKey,
|
||||
sortDirection,
|
||||
queryOptions: {
|
||||
|
|
@ -67,3 +99,7 @@ const useMissing = () => {
|
|||
};
|
||||
|
||||
export default useMissing;
|
||||
|
||||
export const useFilters = () => {
|
||||
return FILTERS;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ public void Execute(MissingEpisodeSearchCommand message)
|
|||
pagingSpec.FilterExpressions.Add(v => v.Monitored == false || v.Series.Monitored == false);
|
||||
}
|
||||
|
||||
episodes = _episodeService.EpisodesWithoutFiles(pagingSpec).Records.ToList();
|
||||
episodes = _episodeService.EpisodesWithoutFiles(pagingSpec, true).Records.ToList();
|
||||
}
|
||||
|
||||
var queue = GetQueuedEpisodeIds();
|
||||
|
|
|
|||
|
|
@ -708,6 +708,7 @@
|
|||
"Events": "Events",
|
||||
"Example": "Example",
|
||||
"Exception": "Exception",
|
||||
"ExcludeSpecials": "Exclude Specials",
|
||||
"ExcludeUnknownSeriesItems": "Exclude Unknown Series Items",
|
||||
"ExcludedReleaseProfile": "Excluded Release Profile",
|
||||
"ExcludedReleaseProfiles": "Excluded Release Profiles",
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ public interface IEpisodeService
|
|||
List<Episode> GetEpisodesBySeason(int seriesId, int seasonNumber);
|
||||
List<Episode> GetEpisodesBySceneSeason(int seriesId, int sceneSeasonNumber);
|
||||
List<Episode> EpisodesWithFiles(int seriesId);
|
||||
PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec);
|
||||
PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec, bool includeSpecials);
|
||||
List<Episode> GetEpisodesByFileId(int episodeFileId);
|
||||
void UpdateEpisode(Episode episode);
|
||||
void SetEpisodeMonitored(int episodeId, bool monitored);
|
||||
|
|
@ -158,11 +158,9 @@ public List<Episode> EpisodesWithFiles(int seriesId)
|
|||
return _episodeRepository.EpisodesWithFiles(seriesId);
|
||||
}
|
||||
|
||||
public PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec)
|
||||
public PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec, bool includeSpecials)
|
||||
{
|
||||
var episodeResult = _episodeRepository.EpisodesWithoutFiles(pagingSpec, true);
|
||||
|
||||
return episodeResult;
|
||||
return _episodeRepository.EpisodesWithoutFiles(pagingSpec, includeSpecials);
|
||||
}
|
||||
|
||||
public List<Episode> GetEpisodesByFileId(int episodeFileId)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ public PagingResource<EpisodeResource> GetMissingEpisodes([FromQuery] PagingRequ
|
|||
pagingSpec.FilterExpressions.Add(v => v.Monitored == false || v.Series.Monitored == false);
|
||||
}
|
||||
|
||||
var resource = pagingSpec.ApplyToPage(_episodeService.EpisodesWithoutFiles, v => MapToResource(v, includeSeries, false, includeImages));
|
||||
var resource = pagingSpec.ApplyToPage(spec => _episodeService.EpisodesWithoutFiles(spec, true), v => MapToResource(v, includeSeries, false, includeImages));
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public MissingController(IEpisodeService episodeService,
|
|||
|
||||
[HttpGet]
|
||||
[Produces("application/json")]
|
||||
public PagingResource<EpisodeResource> GetMissingEpisodes([FromQuery] PagingRequestResource paging, bool monitored = true, [FromQuery] MissingSubresource[]? includeSubresources = null)
|
||||
public PagingResource<EpisodeResource> GetMissingEpisodes([FromQuery] PagingRequestResource paging, bool monitored = true, bool includeSpecials = true, [FromQuery] MissingSubresource[]? includeSubresources = null)
|
||||
{
|
||||
var pagingResource = new PagingResource<EpisodeResource>(paging);
|
||||
var pagingSpec = pagingResource.MapToPagingSpec<EpisodeResource, Episode>(
|
||||
|
|
@ -49,7 +49,7 @@ public PagingResource<EpisodeResource> GetMissingEpisodes([FromQuery] PagingRequ
|
|||
var includeSeries = includeSubresources.Contains(MissingSubresource.Series);
|
||||
var includeImages = includeSubresources.Contains(MissingSubresource.Images);
|
||||
|
||||
var resource = pagingSpec.ApplyToPage(_episodeService.EpisodesWithoutFiles, v => MapToResource(v, includeSeries, false, includeImages));
|
||||
var resource = pagingSpec.ApplyToPage(spec => _episodeService.EpisodesWithoutFiles(spec, includeSpecials), v => MapToResource(v, includeSeries, false, includeImages));
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue