1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2026-04-19 21:46:43 -04:00

Typings cleanup and improvements

This commit is contained in:
Mark McDowall
2023-04-04 09:21:34 -07:00
parent 5326a102e2
commit b2c43fb2a6
92 changed files with 1019 additions and 346 deletions
@@ -2,6 +2,8 @@ import { cloneDeep, without } from 'lodash';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import InteractiveImportAppState from 'App/State/InteractiveImportAppState';
import * as commandNames from 'Commands/commandNames';
import SelectInput from 'Components/Form/SelectInput';
import Icon from 'Components/Icon';
@@ -20,16 +22,24 @@ import ModalHeader from 'Components/Modal/ModalHeader';
import Column from 'Components/Table/Column';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import { EpisodeFile } from 'EpisodeFile/EpisodeFile';
import usePrevious from 'Helpers/Hooks/usePrevious';
import useSelectState from 'Helpers/Hooks/useSelectState';
import { align, icons, kinds, scrollDirections } from 'Helpers/Props';
import SelectEpisodeModal from 'InteractiveImport/Episode/SelectEpisodeModal';
import { SelectedEpisode } from 'InteractiveImport/Episode/SelectEpisodeModalContent';
import ImportMode from 'InteractiveImport/ImportMode';
import InteractiveImport, {
InteractiveImportCommandOptions,
} from 'InteractiveImport/InteractiveImport';
import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal';
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
import SelectReleaseGroupModal from 'InteractiveImport/ReleaseGroup/SelectReleaseGroupModal';
import SelectSeasonModal from 'InteractiveImport/Season/SelectSeasonModal';
import SelectSeriesModal from 'InteractiveImport/Series/SelectSeriesModal';
import Language from 'Language/Language';
import { QualityModel } from 'Quality/Quality';
import Series from 'Series/Series';
import { executeCommand } from 'Store/Actions/commandActions';
import {
deleteEpisodeFiles,
@@ -44,6 +54,8 @@ import {
updateInteractiveImportItems,
} from 'Store/Actions/interactiveImportActions';
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
import { SortCallback } from 'typings/callbacks';
import { SelectStateInputProps } from 'typings/props';
import getErrorMessage from 'Utilities/Object/getErrorMessage';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import getSelectedIds from 'Utilities/Table/getSelectedIds';
@@ -59,6 +71,13 @@ type SelectType =
| 'quality'
| 'language';
type FilterExistingFiles = 'all' | 'new';
// TODO: This feels janky to do, but not sure of a better way currently
type OnSelectedChangeCallback = React.ComponentProps<
typeof InteractiveImportRow
>['onSelectedChange'];
const COLUMNS = [
{
name: 'relativePath',
@@ -125,25 +144,23 @@ const COLUMNS = [
},
];
const filterExistingFilesOptions = {
ALL: 'all',
NEW: 'new',
};
const importModeOptions = [
{ key: 'chooseImportMode', value: 'Choose Import Mode', disabled: true },
{ key: 'move', value: 'Move Files' },
{ key: 'copy', value: 'Hardlink/Copy Files' },
];
function isSameEpisodeFile(file, originalFile) {
function isSameEpisodeFile(
file: InteractiveImport,
originalFile?: InteractiveImport
) {
const { series, seasonNumber, episodes } = file;
if (!originalFile) {
return false;
}
if (!originalFile.series || series.id !== originalFile.series.id) {
if (!originalFile.series || series?.id !== originalFile.series.id) {
return false;
}
@@ -155,8 +172,8 @@ function isSameEpisodeFile(file, originalFile) {
}
const episodeFilesInfoSelector = createSelector(
(state) => state.episodeFiles.isDeleting,
(state) => state.episodeFiles.deleteError,
(state: AppState) => state.episodeFiles.isDeleting,
(state: AppState) => state.episodeFiles.deleteError,
(isDeleting, deleteError) => {
return {
isDeleting,
@@ -166,7 +183,7 @@ const episodeFilesInfoSelector = createSelector(
);
const importModeSelector = createSelector(
(state) => state.interactiveImport.importMode,
(state: AppState) => state.interactiveImport.importMode,
(importMode) => {
return importMode;
}
@@ -178,7 +195,6 @@ interface InteractiveImportModalContentProps {
seasonNumber?: number;
showSeries?: boolean;
allowSeriesChange?: boolean;
autoSelectRow?: boolean;
showDelete?: boolean;
showImportMode?: boolean;
showFilterExistingFiles?: boolean;
@@ -200,7 +216,6 @@ function InteractiveImportModalContent(
seriesId,
seasonNumber,
allowSeriesChange = true,
autoSelectRow = true,
showSeries = true,
showFilterExistingFiles = false,
showDelete = false,
@@ -221,16 +236,18 @@ function InteractiveImportModalContent(
originalItems,
sortKey,
sortDirection,
} = useSelector(createClientSideCollectionSelector('interactiveImport'));
}: InteractiveImportAppState = useSelector(
createClientSideCollectionSelector('interactiveImport')
);
const { isDeleting, deleteError } = useSelector(episodeFilesInfoSelector);
const importMode = useSelector(importModeSelector);
const [invalidRowsSelected, setInvalidRowsSelected] = useState([]);
const [invalidRowsSelected, setInvalidRowsSelected] = useState<number[]>([]);
const [
withoutEpisodeFileIdRowsSelected,
setWithoutEpisodeFileIdRowsSelected,
] = useState([]);
] = useState<number[]>([]);
const [selectModalOpen, setSelectModalOpen] = useState<SelectType | null>(
null
);
@@ -253,16 +270,20 @@ function InteractiveImportModalContent(
const dispatch = useDispatch();
const columns: Column[] = useMemo(() => {
const result = cloneDeep(COLUMNS);
const result: Column[] = cloneDeep(COLUMNS);
if (!showSeries) {
result.find((c) => c.name === 'series').isVisible = false;
const seriesColumn = result.find((c) => c.name === 'series');
if (seriesColumn) {
seriesColumn.isVisible = false;
}
}
return result;
}, [showSeries]);
const selectedIds = useMemo(() => {
const selectedIds: number[] = useMemo(() => {
return getSelectedIds(selectedState);
}, [selectedState]);
@@ -317,13 +338,13 @@ function InteractiveImportModalContent(
}, [previousIsDeleting, isDeleting, deleteError, onModalClose]);
const onSelectAllChange = useCallback(
({ value }) => {
({ value }: SelectStateInputProps) => {
setSelectState({ type: value ? 'selectAll' : 'unselectAll', items });
},
[items, setSelectState]
);
const onSelectedChange = useCallback(
const onSelectedChange = useCallback<OnSelectedChangeCallback>(
({ id, value, hasEpisodeFileId, shiftKey = false }) => {
setSelectState({
type: 'toggleSelected',
@@ -365,7 +386,7 @@ function InteractiveImportModalContent(
const onConfirmDelete = useCallback(() => {
setIsConfirmDeleteModalOpen(false);
const episodeFileIds = items.reduce((acc, item) => {
const episodeFileIds = items.reduce((acc: number[], item) => {
if (selectedIds.indexOf(item.id) > -1 && item.episodeFileId) {
acc.push(item.episodeFileId);
}
@@ -381,11 +402,10 @@ function InteractiveImportModalContent(
}, [setIsConfirmDeleteModalOpen]);
const onImportSelectedPress = useCallback(() => {
const finalImportMode =
downloadId || !showImportMode ? ImportMode.Auto : importMode;
const finalImportMode = downloadId || !showImportMode ? 'auto' : importMode;
const existingFiles = [];
const files = [];
const existingFiles: Partial<EpisodeFile>[] = [];
const files: InteractiveImportCommandOptions[] = [];
if (finalImportMode === 'chooseImportMode') {
setInteractiveImportErrorMessage('An import mode must be selected');
@@ -511,16 +531,18 @@ function InteractiveImportModalContent(
dispatch,
]);
const onSortPress = useCallback(
const onSortPress = useCallback<SortCallback>(
(sortKey, sortDirection) => {
dispatch(setInteractiveImportSort({ sortKey, sortDirection }));
},
[dispatch]
);
const onFilterExistingFilesChange = useCallback(
const onFilterExistingFilesChange = useCallback<
(value: FilterExistingFiles) => void
>(
(value) => {
const filter = value !== filterExistingFilesOptions.ALL;
const filter = value !== 'all';
setFilterExistingFiles(filter);
@@ -536,14 +558,18 @@ function InteractiveImportModalContent(
[downloadId, seriesId, folder, setFilterExistingFiles, dispatch]
);
const onImportModeChange = useCallback(
const onImportModeChange = useCallback<
({ value }: { value: ImportMode }) => void
>(
({ value }) => {
dispatch(setInteractiveImportMode({ importMode: value }));
},
[dispatch]
);
const onSelectModalSelect = useCallback(
const onSelectModalSelect = useCallback<
({ value }: { value: SelectType }) => void
>(
({ value }) => {
setSelectModalOpen(value);
},
@@ -555,7 +581,7 @@ function InteractiveImportModalContent(
}, [setSelectModalOpen]);
const onSeriesSelect = useCallback(
(series) => {
(series: Series) => {
dispatch(
updateInteractiveImportItems({
ids: selectedIds,
@@ -573,7 +599,7 @@ function InteractiveImportModalContent(
);
const onSeasonSelect = useCallback(
(seasonNumber) => {
(seasonNumber: number) => {
dispatch(
updateInteractiveImportItems({
ids: selectedIds,
@@ -590,7 +616,7 @@ function InteractiveImportModalContent(
);
const onEpisodesSelect = useCallback(
(episodes) => {
(episodes: SelectedEpisode[]) => {
dispatch(
updateInteractiveImportItems({
ids: selectedIds,
@@ -606,7 +632,7 @@ function InteractiveImportModalContent(
);
const onReleaseGroupSelect = useCallback(
(releaseGroup) => {
(releaseGroup: string) => {
dispatch(
updateInteractiveImportItems({
ids: selectedIds,
@@ -622,7 +648,7 @@ function InteractiveImportModalContent(
);
const onLanguagesSelect = useCallback(
(newLanguages) => {
(newLanguages: Language[]) => {
dispatch(
updateInteractiveImportItems({
ids: selectedIds,
@@ -638,7 +664,7 @@ function InteractiveImportModalContent(
);
const onQualitySelect = useCallback(
(quality) => {
(quality: QualityModel) => {
dispatch(
updateInteractiveImportItems({
ids: selectedIds,
@@ -653,7 +679,7 @@ function InteractiveImportModalContent(
[selectedIds, dispatch]
);
const orderedSelectedIds = items.reduce((acc, file) => {
const orderedSelectedIds = items.reduce((acc: number[], file) => {
if (selectedIds.includes(file.id)) {
acc.push(file.id);
}
@@ -690,7 +716,7 @@ function InteractiveImportModalContent(
<MenuContent>
<SelectedMenuItem
name={filterExistingFilesOptions.ALL}
name={'all'}
isSelected={!filterExistingFiles}
onPress={onFilterExistingFilesChange}
>
@@ -698,7 +724,7 @@ function InteractiveImportModalContent(
</SelectedMenuItem>
<SelectedMenuItem
name={filterExistingFilesOptions.NEW}
name={'new'}
isSelected={filterExistingFiles}
onPress={onFilterExistingFilesChange}
>
@@ -733,7 +759,6 @@ function InteractiveImportModalContent(
isSelected={selectedState[item.id]}
{...item}
allowSeriesChange={allowSeriesChange}
autoSelectRow={autoSelectRow}
columns={columns}
modalTitle={modalTitle}
onSelectedChange={onSelectedChange}