1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2026-04-20 21:54:58 -04:00

New: Improve 'Select All' in Library Import

Closes #7909
This commit is contained in:
Mark McDowall
2025-10-25 16:13:31 -07:00
parent 08f0a5a960
commit 910b85f37d
32 changed files with 666 additions and 439 deletions
@@ -5,7 +5,7 @@ import {
setAddSeriesOption,
useAddSeriesOption,
} from 'AddSeries/addSeriesOptionsStore';
import { SelectProvider } from 'App/SelectContext';
import { SelectProvider } from 'App/Select/SelectContext';
import AppState from 'App/State/AppState';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
@@ -5,7 +5,7 @@ import {
setAddSeriesOption,
useAddSeriesOptions,
} from 'AddSeries/addSeriesOptionsStore';
import { useSelect } from 'App/SelectContext';
import { useSelect } from 'App/Select/SelectContext';
import AppState from 'App/State/AppState';
import CheckInput from 'Components/Form/CheckInput';
import FormInputGroup from 'Components/Form/FormInputGroup';
@@ -25,7 +25,6 @@ import {
} from 'Store/Actions/importSeriesActions';
import { InputChanged } from 'typings/inputs';
import translate from 'Utilities/String/translate';
import getSelectedIds from 'Utilities/Table/getSelectedIds';
import styles from './ImportSeriesFooter.css';
type MixedType = 'mixed';
@@ -56,11 +55,7 @@ function ImportSeriesFooter() {
defaultSeasonFolder
);
const [selectState] = useSelect();
const selectedIds = useMemo(() => {
return getSelectedIds(selectState.selectedState, (id) => id);
}, [selectState.selectedState]);
const { selectedCount, getSelectedIds } = useSelect();
const {
hasUnsearchedItems,
@@ -127,7 +122,7 @@ function ImportSeriesFooter() {
setAddSeriesOption(name as keyof AddSeriesOptions, value);
selectedIds.forEach((id) => {
getSelectedIds().forEach((id) => {
dispatch(
// @ts-expect-error - actions are not typed
setImportSeriesValue({
@@ -137,7 +132,7 @@ function ImportSeriesFooter() {
);
});
},
[selectedIds, dispatch]
[getSelectedIds, dispatch]
);
const handleLookupPress = useCallback(() => {
@@ -149,8 +144,8 @@ function ImportSeriesFooter() {
}, [dispatch]);
const handleImportPress = useCallback(() => {
dispatch(importSeries({ ids: selectedIds }));
}, [selectedIds, dispatch]);
dispatch(importSeries({ ids: getSelectedIds() }));
}, [getSelectedIds, dispatch]);
useEffect(() => {
if (isMonitorMixed && monitor !== 'mixed') {
@@ -187,8 +182,6 @@ function ImportSeriesFooter() {
}
}, [defaultSeasonFolder, isSeasonFolderMixed, seasonFolder]);
const selectedCount = selectedIds.length;
return (
<PageContentFooter>
<div className={styles.inputContainer}>
@@ -1,7 +1,7 @@
import React, { useCallback } from 'react';
import React, { useCallback, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import { useSelect } from 'App/SelectContext';
import { useSelect } from 'App/Select/SelectContext';
import AppState from 'App/State/AppState';
import { ImportSeries } from 'App/State/ImportSeriesAppState';
import FormInputGroup from 'Components/Form/FormInputGroup';
@@ -48,7 +48,8 @@ function ImportSeriesRow({ id }: ImportSeriesRowProps) {
createExistingSeriesSelector(selectedSeries?.tvdbId)
);
const [selectState, selectDispatch] = useSelect();
const { getIsSelected, toggleSelected, toggleDisabled } =
useSelect<ImportSeries>();
const handleInputChange = useCallback(
({ name, value }: InputChanged) => {
@@ -64,23 +65,26 @@ function ImportSeriesRow({ id }: ImportSeriesRowProps) {
);
const handleSelectedChange = useCallback(
({ id, value, shiftKey }: SelectStateInputProps) => {
selectDispatch({
type: 'toggleSelected',
({ id, value, shiftKey }: SelectStateInputProps<string>) => {
toggleSelected({
id,
isSelected: value,
shiftKey,
});
},
[selectDispatch]
[toggleSelected]
);
useEffect(() => {
toggleDisabled(id, !selectedSeries || isExistingSeries);
}, [id, selectedSeries, isExistingSeries, toggleDisabled]);
return (
<>
<VirtualTableSelectCell
<VirtualTableSelectCell<string>
inputClassName={styles.selectInput}
id={id}
isSelected={selectState.selectedState[id]}
isSelected={getIsSelected(id)}
isDisabled={!selectedSeries || isExistingSeries}
onSelectedChange={handleSelectedChange}
/>
@@ -2,7 +2,7 @@ import React, { RefObject, useCallback, useEffect, useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { FixedSizeList, ListChildComponentProps } from 'react-window';
import { useAddSeriesOptions } from 'AddSeries/addSeriesOptionsStore';
import { useSelect } from 'App/SelectContext';
import { useSelect } from 'App/Select/SelectContext';
import AppState from 'App/State/AppState';
import { ImportSeries } from 'App/State/ImportSeriesAppState';
import VirtualTable from 'Components/Table/VirtualTable';
@@ -66,7 +66,14 @@ function ImportSeriesTable({
const items = useSelector((state: AppState) => state.importSeries.items);
const { isSmallScreen } = useSelector(createDimensionsSelector());
const allSeries = useSelector(createAllSeriesSelector());
const [selectState, selectDispatch] = useSelect();
const {
allSelected,
allUnselected,
getIsSelected,
toggleSelected,
selectAll,
unselectAll,
} = useSelect();
const defaultValues = useRef({
monitor,
@@ -78,38 +85,36 @@ function ImportSeriesTable({
const listRef = useRef<FixedSizeList<RowItemData>>(null);
const initialUnmappedFolders = useRef(unmappedFolders);
const previousItems = usePrevious(items);
const { allSelected, allUnselected, selectedState } = selectState;
const handleSelectAllChange = useCallback(
({ value }: CheckInputChanged) => {
selectDispatch({
type: value ? 'selectAll' : 'unselectAll',
});
if (value) {
selectAll();
} else {
unselectAll();
}
},
[selectDispatch]
[selectAll, unselectAll]
);
const handleSelectedChange = useCallback(
({ id, value, shiftKey }: SelectStateInputProps) => {
selectDispatch({
type: 'toggleSelected',
({ id, value, shiftKey }: SelectStateInputProps<string>) => {
toggleSelected({
id,
isSelected: value,
shiftKey,
});
},
[selectDispatch]
[toggleSelected]
);
const handleRemoveSelectedStateItem = useCallback(
(id: string) => {
selectDispatch({
type: 'removeItem',
id,
});
},
[selectDispatch]
);
// TODO: Check if this is still needed
const handleRemoveSelectedStateItem = useCallback((_id: string) => {
// selectDispatch({
// type: 'removeItem',
// id,
// });
}, []);
useEffect(() => {
initialUnmappedFolders.current.forEach(({ name, path, relativePath }) => {
@@ -144,7 +149,7 @@ function ImportSeriesTable({
}
const selectedSeries = item.selectedSeries;
const isSelected = selectedState[id];
const isSelected = getIsSelected(id);
const isExistingSeries =
!!selectedSeries &&
@@ -175,9 +180,9 @@ function ImportSeriesTable({
allSeries,
items,
previousItems,
selectedState,
handleRemoveSelectedStateItem,
handleSelectedChange,
getIsSelected,
]);
if (!items.length) {