Convert store selectors to Typescript

(cherry picked from commit a57b35a1966266b49d1241474fe3b69523f70474)
pull/8909/head
Bogdan 1 year ago
parent abad6a9f18
commit 43a0e75acf

@ -1,9 +1,12 @@
import InteractiveImportAppState from 'App/State/InteractiveImportAppState'; import InteractiveImportAppState from 'App/State/InteractiveImportAppState';
import CommandAppState from './CommandAppState';
import MovieCollectionAppState from './MovieCollectionAppState';
import MovieFilesAppState from './MovieFilesAppState'; import MovieFilesAppState from './MovieFilesAppState';
import MoviesAppState, { MovieIndexAppState } from './MoviesAppState'; import MoviesAppState, { MovieIndexAppState } from './MoviesAppState';
import ParseAppState from './ParseAppState'; import ParseAppState from './ParseAppState';
import QueueAppState from './QueueAppState'; import QueueAppState from './QueueAppState';
import SettingsAppState from './SettingsAppState'; import SettingsAppState from './SettingsAppState';
import SystemAppState from './SystemAppState';
import TagsAppState from './TagsAppState'; import TagsAppState from './TagsAppState';
interface FilterBuilderPropOption { interface FilterBuilderPropOption {
@ -39,14 +42,17 @@ export interface CustomFilter {
} }
interface AppState { interface AppState {
movieFiles: MovieFilesAppState; commands: CommandAppState;
interactiveImport: InteractiveImportAppState; interactiveImport: InteractiveImportAppState;
movieCollections: MovieCollectionAppState;
movieFiles: MovieFilesAppState;
movieIndex: MovieIndexAppState; movieIndex: MovieIndexAppState;
movies: MoviesAppState;
parse: ParseAppState; parse: ParseAppState;
queue: QueueAppState;
settings: SettingsAppState; settings: SettingsAppState;
movies: MoviesAppState; system: SystemAppState;
tags: TagsAppState; tags: TagsAppState;
queue: QueueAppState;
} }
export default AppState; export default AppState;

@ -0,0 +1,6 @@
import AppSectionState from 'App/State/AppSectionState';
import Command from 'Commands/Command';
export type CommandAppState = AppSectionState<Command>;
export default CommandAppState;

@ -0,0 +1,6 @@
import AppSectionState from 'App/State/AppSectionState';
import MovieCollection from 'typings/MovieCollection';
type MovieCollectionAppState = AppSectionState<MovieCollection>;
export default MovieCollectionAppState;

@ -1,5 +1,6 @@
import AppSectionState, { import AppSectionState, {
AppSectionDeleteState, AppSectionDeleteState,
AppSectionItemState,
AppSectionSaveState, AppSectionSaveState,
AppSectionSchemaState, AppSectionSchemaState,
} from 'App/State/AppSectionState'; } from 'App/State/AppSectionState';
@ -41,17 +42,17 @@ export interface RootFolderAppState
AppSectionSaveState {} AppSectionSaveState {}
export type LanguageSettingsAppState = AppSectionState<Language>; export type LanguageSettingsAppState = AppSectionState<Language>;
export type UiSettingsAppState = AppSectionState<UiSettings>; export type UiSettingsAppState = AppSectionItemState<UiSettings>;
interface SettingsAppState { interface SettingsAppState {
downloadClients: DownloadClientAppState; downloadClients: DownloadClientAppState;
importLists: ImportListAppState; importLists: ImportListAppState;
indexers: IndexerAppState; indexers: IndexerAppState;
language: LanguageSettingsAppState; languages: LanguageSettingsAppState;
notifications: NotificationAppState; notifications: NotificationAppState;
qualityProfiles: QualityProfilesAppState; qualityProfiles: QualityProfilesAppState;
rootFolders: RootFolderAppState; rootFolders: RootFolderAppState;
uiSettings: UiSettingsAppState; ui: UiSettingsAppState;
} }
export default SettingsAppState; export default SettingsAppState;

@ -0,0 +1,10 @@
import SystemStatus from 'typings/SystemStatus';
import { AppSectionItemState } from './AppSectionState';
export type SystemStatusAppState = AppSectionItemState<SystemStatus>;
interface SystemAppState {
status: SystemStatusAppState;
}
export default SystemAppState;

@ -1,12 +1,32 @@
import ModelBase from 'App/ModelBase'; import ModelBase from 'App/ModelBase';
import AppSectionState, { import AppSectionState, {
AppSectionDeleteState, AppSectionDeleteState,
AppSectionSaveState,
} from 'App/State/AppSectionState'; } from 'App/State/AppSectionState';
export interface Tag extends ModelBase { export interface Tag extends ModelBase {
label: string; label: string;
} }
interface TagsAppState extends AppSectionState<Tag>, AppSectionDeleteState {} export interface TagDetail extends ModelBase {
label: string;
autoTagIds: number[];
delayProfileIds: number[];
downloadClientIds: number[];
importListIds: number[];
indexerIds: number[];
movieIds: number[];
notificationIds: number[];
restrictionIds: number[];
}
export interface TagDetailAppState
extends AppSectionState<TagDetail>,
AppSectionDeleteState,
AppSectionSaveState {}
interface TagsAppState extends AppSectionState<Tag>, AppSectionDeleteState {
details: TagDetailAppState;
}
export default TagsAppState; export default TagsAppState;

@ -4,6 +4,7 @@ import { useSelector } from 'react-redux';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector'; import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
import dimensions from 'Styles/Variables/dimensions'; import dimensions from 'Styles/Variables/dimensions';
import QualityProfile from 'typings/QualityProfile';
import { UiSettings } from 'typings/UiSettings'; import { UiSettings } from 'typings/UiSettings';
import formatDateTime from 'Utilities/Date/formatDateTime'; import formatDateTime from 'Utilities/Date/formatDateTime';
import getRelativeDate from 'Utilities/Date/getRelativeDate'; import getRelativeDate from 'Utilities/Date/getRelativeDate';
@ -33,7 +34,7 @@ interface MovieIndexOverviewInfoProps {
showSizeOnDisk: boolean; showSizeOnDisk: boolean;
monitored: boolean; monitored: boolean;
studio?: string; studio?: string;
qualityProfile: object; qualityProfile?: QualityProfile;
added?: string; added?: string;
path: string; path: string;
sizeOnDisk?: number; sizeOnDisk?: number;
@ -100,13 +101,10 @@ function getInfoRowProps(
}; };
} }
if (name === 'qualityProfileId') { if (name === 'qualityProfileId' && !!props.qualityProfile?.name) {
return { return {
title: 'Quality Profile', title: 'Quality Profile',
iconName: icons.PROFILE, iconName: icons.PROFILE,
// TODO: Type QualityProfile
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore ts(2339)
label: props.qualityProfile.name, label: props.qualityProfile.name,
}; };
} }

@ -229,7 +229,7 @@ function MovieIndexPoster(props: MovieIndexPosterProps) {
</div> </div>
) : null} ) : null}
{showQualityProfile ? ( {showQualityProfile && !!qualityProfile?.name ? (
<div className={styles.title} title={translate('QualityProfile')}> <div className={styles.title} title={translate('QualityProfile')}>
{qualityProfile.name} {qualityProfile.name}
</div> </div>

@ -14,7 +14,7 @@ import styles from './MovieIndexPosterInfo.css';
interface MovieIndexPosterInfoProps { interface MovieIndexPosterInfoProps {
studio?: string; studio?: string;
showQualityProfile: boolean; showQualityProfile: boolean;
qualityProfile: QualityProfile; qualityProfile?: QualityProfile;
added?: string; added?: string;
year: number; year: number;
inCinemas?: string; inCinemas?: string;
@ -68,7 +68,11 @@ function MovieIndexPosterInfo(props: MovieIndexPosterInfoProps) {
); );
} }
if (sortKey === 'qualityProfileId' && !showQualityProfile) { if (
sortKey === 'qualityProfileId' &&
!showQualityProfile &&
!!qualityProfile?.name
) {
return ( return (
<div className={styles.info} title={translate('QualityProfile')}> <div className={styles.info} title={translate('QualityProfile')}>
{qualityProfile.name} {qualityProfile.name}

@ -210,7 +210,7 @@ function MovieIndexRow(props: MovieIndexRowProps) {
if (name === 'qualityProfileId') { if (name === 'qualityProfileId') {
return ( return (
<VirtualTableRowCell key={name} className={styles[name]}> <VirtualTableRowCell key={name} className={styles[name]}>
{qualityProfile.name} {qualityProfile?.name ?? ''}
</VirtualTableRowCell> </VirtualTableRowCell>
); );
} }

@ -35,7 +35,7 @@ interface Movie extends ModelBase {
titleSlug: string; titleSlug: string;
collection: Collection; collection: Collection;
studio: string; studio: string;
qualityProfile: object; qualityProfileId: number;
added: string; added: string;
year: number; year: number;
inCinemas: string; inCinemas: string;

@ -1,8 +1,9 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
function createAllMoviesSelector() { function createAllMoviesSelector() {
return createSelector( return createSelector(
(state) => state.movies, (state: AppState) => state.movies,
(movies) => { (movies) => {
return movies.items; return movies.items;
} }

@ -2,13 +2,10 @@ import { createSelector } from 'reselect';
import { isCommandExecuting } from 'Utilities/Command'; import { isCommandExecuting } from 'Utilities/Command';
import createCommandSelector from './createCommandSelector'; import createCommandSelector from './createCommandSelector';
function createCommandExecutingSelector(name, contraints = {}) { function createCommandExecutingSelector(name: string, contraints = {}) {
return createSelector( return createSelector(createCommandSelector(name, contraints), (command) => {
createCommandSelector(name, contraints), return isCommandExecuting(command);
(command) => { });
return isCommandExecuting(command);
}
);
} }
export default createCommandExecutingSelector; export default createCommandExecutingSelector;

@ -1,14 +0,0 @@
import { createSelector } from 'reselect';
import { findCommand } from 'Utilities/Command';
import createCommandsSelector from './createCommandsSelector';
function createCommandSelector(name, contraints = {}) {
return createSelector(
createCommandsSelector(),
(commands) => {
return findCommand(commands, { name, ...contraints });
}
);
}
export default createCommandSelector;

@ -0,0 +1,11 @@
import { createSelector } from 'reselect';
import { findCommand } from 'Utilities/Command';
import createCommandsSelector from './createCommandsSelector';
function createCommandSelector(name: string, contraints = {}) {
return createSelector(createCommandsSelector(), (commands) => {
return findCommand(commands, { name, ...contraints });
});
}
export default createCommandSelector;

@ -1,8 +1,9 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
function createCommandsSelector() { function createCommandsSelector() {
return createSelector( return createSelector(
(state) => state.commands, (state: AppState) => state.commands,
(commands) => { (commands) => {
return commands.items; return commands.items;
} }

@ -1,9 +0,0 @@
import _ from 'lodash';
import { createSelectorCreator, defaultMemoize } from 'reselect';
const createDeepEqualSelector = createSelectorCreator(
defaultMemoize,
_.isEqual
);
export default createDeepEqualSelector;

@ -0,0 +1,6 @@
import { isEqual } from 'lodash';
import { createSelectorCreator, defaultMemoize } from 'reselect';
const createDeepEqualSelector = createSelectorCreator(defaultMemoize, isEqual);
export default createDeepEqualSelector;

@ -1,9 +1,10 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import { isCommandExecuting } from 'Utilities/Command'; import { isCommandExecuting } from 'Utilities/Command';
function createExecutingCommandsSelector() { function createExecutingCommandsSelector() {
return createSelector( return createSelector(
(state) => state.commands.items, (state: AppState) => state.commands.items,
(commands) => { (commands) => {
return commands.filter((command) => isCommandExecuting(command)); return commands.filter((command) => isCommandExecuting(command));
} }

@ -1,13 +1,14 @@
import _ from 'lodash'; import { some } from 'lodash';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import createAllMoviesSelector from './createAllMoviesSelector'; import createAllMoviesSelector from './createAllMoviesSelector';
function createExistingMovieSelector() { function createExistingMovieSelector() {
return createSelector( return createSelector(
(state, { tmdbId }) => tmdbId, (_: AppState, { tmdbId }: { tmdbId: number }) => tmdbId,
createAllMoviesSelector(), createAllMoviesSelector(),
(tmdbId, movies) => { (tmdbId, movies) => {
return _.some(movies, { tmdbId }); return some(movies, { tmdbId });
} }
); );
} }

@ -1,27 +0,0 @@
import { createSelector } from 'reselect';
function createLanguagesSelector() {
return createSelector(
(state) => state.settings.languages,
(languages) => {
const {
isFetching,
isPopulated,
error,
items
} = languages;
const filterItems = ['Any'];
const filteredLanguages = items.filter((lang) => !filterItems.includes(lang.name));
return {
isFetching,
isPopulated,
error,
items: filteredLanguages
};
}
);
}
export default createLanguagesSelector;

@ -0,0 +1,25 @@
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
function createLanguagesSelector() {
return createSelector(
(state: AppState) => state.settings.languages,
(languages) => {
const { isFetching, isPopulated, error, items } = languages;
const filterItems = ['Any'];
const filteredLanguages = items.filter(
(lang) => !filterItems.includes(lang.name)
);
return {
isFetching,
isPopulated,
error,
items: filteredLanguages,
};
}
);
}
export default createLanguagesSelector;

@ -1,18 +1,19 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import createAllMoviesSelector from './createAllMoviesSelector'; import createAllMoviesSelector from './createAllMoviesSelector';
function createMovieCountSelector() { function createMovieCountSelector() {
return createSelector( return createSelector(
createAllMoviesSelector(), createAllMoviesSelector(),
(state) => state.movies.error, (state: AppState) => state.movies.error,
(state) => state.movies.isFetching, (state: AppState) => state.movies.isFetching,
(state) => state.movies.isPopulated, (state: AppState) => state.movies.isPopulated,
(movies, error, isFetching, isPopulated) => { (movies, error, isFetching, isPopulated) => {
return { return {
count: movies.length, count: movies.length,
error, error,
isFetching, isFetching,
isPopulated isPopulated,
}; };
} }
); );

@ -1,9 +1,10 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
function createMovieFileSelector() { function createMovieFileSelector() {
return createSelector( return createSelector(
(state, { movieFileId }) => movieFileId, (_: AppState, { movieFileId }: { movieFileId: number }) => movieFileId,
(state) => state.movieFiles, (state: AppState) => state.movieFiles,
(movieFileId, movieFiles) => { (movieFileId, movieFiles) => {
if (!movieFileId) { if (!movieFileId) {
return; return;

@ -1,16 +0,0 @@
import { createSelector } from 'reselect';
import { createMovieSelectorForHook } from './createMovieSelector';
function createMovieQualityProfileSelector(movieId) {
return createSelector(
(state) => state.settings.qualityProfiles.items,
createMovieSelectorForHook(movieId),
(qualityProfiles, movie = {}) => {
return qualityProfiles.find((profile) => {
return profile.id === movie.qualityProfileId;
});
}
);
}
export default createMovieQualityProfileSelector;

@ -0,0 +1,18 @@
import { createSelector } from 'reselect';
import appState from 'App/State/AppState';
import Movie from 'Movie/Movie';
import { createMovieSelectorForHook } from './createMovieSelector';
function createMovieQualityProfileSelector(movieId: number) {
return createSelector(
(state: appState) => state.settings.qualityProfiles.items,
createMovieSelectorForHook(movieId),
(qualityProfiles, movie = {} as Movie) => {
return qualityProfiles.find(
(profile) => profile.id === movie.qualityProfileId
);
}
);
}
export default createMovieQualityProfileSelector;

@ -1,25 +0,0 @@
import _ from 'lodash';
import { createSelector } from 'reselect';
import createAllMoviesSelector from './createAllMoviesSelector';
function createProfileInUseSelector(profileProp) {
return createSelector(
(state, { id }) => id,
createAllMoviesSelector(),
(state) => state.settings.importLists.items,
(state) => state.movieCollections.items,
(id, movies, lists, collections) => {
if (!id) {
return false;
}
if (_.some(movies, { [profileProp]: id }) || _.some(lists, { [profileProp]: id }) || _.some(collections, { [profileProp]: id })) {
return true;
}
return false;
}
);
}
export default createProfileInUseSelector;

@ -0,0 +1,31 @@
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import Movie from 'Movie/Movie';
import ImportList from 'typings/ImportList';
import MovieCollection from 'typings/MovieCollection';
import createAllMoviesSelector from './createAllMoviesSelector';
function createProfileInUseSelector(profileProp: string) {
return createSelector(
(_: AppState, { id }: { id: number }) => id,
createAllMoviesSelector(),
(state: AppState) => state.settings.importLists.items,
(state: AppState) => state.movieCollections.items,
(id, movies, lists, collections) => {
if (!id) {
return false;
}
return (
movies.some((m) => m[profileProp as keyof Movie] === id) ||
lists.some((list) => list[profileProp as keyof ImportList] === id) ||
collections.some(
(collection) =>
collection[profileProp as keyof MovieCollection] === id
)
);
}
);
}
export default createProfileInUseSelector;

@ -1,26 +0,0 @@
import { createSelector } from 'reselect';
export function createQualityProfileSelectorForHook(qualityProfileId) {
return createSelector(
(state) => state.settings.qualityProfiles.items,
(qualityProfiles) => {
return qualityProfiles.find((profile) => {
return profile.id === qualityProfileId;
});
}
);
}
function createQualityProfileSelector() {
return createSelector(
(state, { qualityProfileId }) => qualityProfileId,
(state) => state.settings.qualityProfiles.items,
(qualityProfileId, qualityProfiles) => {
return qualityProfiles.find((profile) => {
return profile.id === qualityProfileId;
});
}
);
}
export default createQualityProfileSelector;

@ -0,0 +1,24 @@
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
export function createQualityProfileSelectorForHook(qualityProfileId: number) {
return createSelector(
(state: AppState) => state.settings.qualityProfiles.items,
(qualityProfiles) => {
return qualityProfiles.find((profile) => profile.id === qualityProfileId);
}
);
}
function createQualityProfileSelector() {
return createSelector(
(_: AppState, { qualityProfileId }: { qualityProfileId: number }) =>
qualityProfileId,
(state: AppState) => state.settings.qualityProfiles.items,
(qualityProfileId, qualityProfiles) => {
return qualityProfiles.find((profile) => profile.id === qualityProfileId);
}
);
}
export default createQualityProfileSelector;

@ -1,17 +1,16 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
function createQueueItemSelector() { function createQueueItemSelector() {
return createSelector( return createSelector(
(state, { movieId }) => movieId, (_: AppState, { movieId }: { movieId: number }) => movieId,
(state) => state.queue.details.items, (state: AppState) => state.queue.details.items,
(movieId, details) => { (movieId, details) => {
if (!movieId || !details) { if (!movieId || !details) {
return null; return null;
} }
return details.find((item) => { return details.find((item) => item.movieId === movieId);
return item.movieId === movieId;
});
} }
); );
} }

@ -1,8 +1,9 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
function createSystemStatusSelector() { function createSystemStatusSelector() {
return createSelector( return createSelector(
(state) => state.system.status, (state: AppState) => state.system.status,
(status) => { (status) => {
return status.item; return status.item;
} }

@ -1,9 +1,10 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
function createTagDetailsSelector() { function createTagDetailsSelector() {
return createSelector( return createSelector(
(state, { id }) => id, (_: AppState, { id }: { id: number }) => id,
(state) => state.tags.details.items, (state: AppState) => state.tags.details.items,
(id, tagDetails) => { (id, tagDetails) => {
return tagDetails.find((t) => t.id === id); return tagDetails.find((t) => t.id === id);
} }

@ -1,8 +1,9 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
function createTagsSelector() { function createTagsSelector() {
return createSelector( return createSelector(
(state) => state.tags.items, (state: AppState) => state.tags.items,
(tags) => { (tags) => {
return tags; return tags;
} }

@ -1,8 +1,9 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
function createUISettingsSelector() { function createUISettingsSelector() {
return createSelector( return createSelector(
(state) => state.settings.ui, (state: AppState) => state.settings.ui,
(ui) => { (ui) => {
return ui.item; return ui.item;
} }

@ -0,0 +1,17 @@
import ModelBase from 'App/ModelBase';
import Movie from 'Movie/Movie';
interface MovieCollection extends ModelBase {
title: string;
sortTitle: string;
tmdbId: number;
overview: string;
monitored: boolean;
rootFolderPath: string;
qualityProfileId: number;
movies: Movie[];
missingMovies: number;
tags: number[];
}
export default MovieCollection;

@ -0,0 +1,31 @@
interface SystemStatus {
appData: string;
appName: string;
authentication: string;
branch: string;
buildTime: string;
instanceName: string;
isAdmin: boolean;
isDebug: boolean;
isDocker: boolean;
isLinux: boolean;
isNetCore: boolean;
isOsx: boolean;
isProduction: boolean;
isUserInteractive: boolean;
isWindows: boolean;
migrationVersion: number;
mode: string;
osName: string;
osVersion: string;
packageUpdateMechanism: string;
runtimeName: string;
runtimeVersion: string;
sqliteVersion: string;
startTime: string;
startupPath: string;
urlBase: string;
version: string;
}
export default SystemStatus;

@ -3,4 +3,5 @@ export interface UiSettings {
shortDateFormat: string; shortDateFormat: string;
longDateFormat: string; longDateFormat: string;
timeFormat: string; timeFormat: string;
movieRuntimeFormat: string;
} }

Loading…
Cancel
Save