Convert store selectors to Typescript

This commit is contained in:
Bogdan 2023-07-30 16:23:41 +03:00 committed by Mark McDowall
parent 94c6b0fde3
commit a57b35a196
35 changed files with 250 additions and 173 deletions

View File

@ -1,11 +1,13 @@
import InteractiveImportAppState from 'App/State/InteractiveImportAppState';
import CalendarAppState from './CalendarAppState';
import CommandAppState from './CommandAppState';
import EpisodeFilesAppState from './EpisodeFilesAppState';
import EpisodesAppState from './EpisodesAppState';
import ParseAppState from './ParseAppState';
import QueueAppState from './QueueAppState';
import SeriesAppState, { SeriesIndexAppState } from './SeriesAppState';
import SettingsAppState from './SettingsAppState';
import SystemAppState from './SystemAppState';
import TagsAppState from './TagsAppState';
interface FilterBuilderPropOption {
@ -42,15 +44,17 @@ export interface CustomFilter {
interface AppState {
calendar: CalendarAppState;
episodesSelection: EpisodesAppState;
commands: CommandAppState;
episodeFiles: EpisodeFilesAppState;
episodesSelection: EpisodesAppState;
interactiveImport: InteractiveImportAppState;
parse: ParseAppState;
queue: QueueAppState;
series: SeriesAppState;
seriesIndex: SeriesIndexAppState;
settings: SettingsAppState;
series: SeriesAppState;
system: SystemAppState;
tags: TagsAppState;
queue: QueueAppState;
}
export default AppState;

View File

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

View File

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

View File

@ -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;

View File

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

View File

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

View File

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

View File

@ -11,7 +11,7 @@ interface SeriesIndexPosterInfoProps {
originalLanguage?: Language;
network?: string;
showQualityProfile: boolean;
qualityProfile: QualityProfile;
qualityProfile?: QualityProfile;
previousAiring?: string;
added?: string;
seasonCount: number;
@ -58,7 +58,11 @@ function SeriesIndexPosterInfo(props: SeriesIndexPosterInfoProps) {
);
}
if (sortKey === 'qualityProfileId' && !showQualityProfile) {
if (
sortKey === 'qualityProfileId' &&
!showQualityProfile &&
!!qualityProfile?.name
) {
return (
<div className={styles.info} title={translate('QualityProfile')}>
{qualityProfile.name}

View File

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

View File

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

View File

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

View File

@ -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;

View File

@ -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;

View File

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

View File

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

View File

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

View File

@ -1,17 +0,0 @@
import { createSelector } from 'reselect';
function createEpisodeFileSelector() {
return createSelector(
(state, { episodeFileId }) => episodeFileId,
(state) => state.episodeFiles,
(episodeFileId, episodeFiles) => {
if (!episodeFileId) {
return;
}
return episodeFiles.items.find((episodeFile) => episodeFile.id === episodeFileId);
}
);
}
export default createEpisodeFileSelector;

View File

@ -0,0 +1,21 @@
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
function createEpisodeFileSelector() {
return createSelector(
(_: AppState, { episodeFileId }: { episodeFileId: number }) =>
episodeFileId,
(state: AppState) => state.episodeFiles,
(episodeFileId, episodeFiles) => {
if (!episodeFileId) {
return;
}
return episodeFiles.items.find(
(episodeFile) => episodeFile.id === episodeFileId
);
}
);
}
export default createEpisodeFileSelector;

View File

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

View File

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

View File

@ -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;

View File

@ -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;

View File

@ -1,19 +0,0 @@
import { createSelector } from 'reselect';
import createAllSeriesSelector from './createAllSeriesSelector';
function createProfileInUseSelector(profileProp) {
return createSelector(
(state, { id }) => id,
createAllSeriesSelector(),
(state) => state.settings.importLists.items,
(id, series, lists) => {
if (!id) {
return false;
}
return series.some((s) => s[profileProp] === id) || lists.some((list) => list[profileProp] === id);
}
);
}
export default createProfileInUseSelector;

View File

@ -0,0 +1,25 @@
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import Series from 'Series/Series';
import ImportList from 'typings/ImportList';
import createAllSeriesSelector from './createAllSeriesSelector';
function createProfileInUseSelector(profileProp: string) {
return createSelector(
(_: AppState, { id }: { id: number }) => id,
createAllSeriesSelector(),
(state: AppState) => state.settings.importLists.items,
(id, series, lists) => {
if (!id) {
return false;
}
return (
series.some((s) => s[profileProp as keyof Series] === id) ||
lists.some((list) => list[profileProp as keyof ImportList] === id)
);
}
);
}
export default createProfileInUseSelector;

View File

@ -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;

View File

@ -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;

View File

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

View File

@ -2,12 +2,9 @@ import { createSelector } from 'reselect';
import createAllSeriesSelector from './createAllSeriesSelector';
function createSeriesCountSelector() {
return createSelector(
createAllSeriesSelector(),
(series) => {
return createSelector(createAllSeriesSelector(), (series) => {
return series.length;
}
);
});
}
export default createSeriesCountSelector;

View File

@ -1,16 +0,0 @@
import { createSelector } from 'reselect';
import { createSeriesSelectorForHook } from './createSeriesSelector';
function createSeriesQualityProfileSelector(seriesId) {
return createSelector(
(state) => state.settings.qualityProfiles.items,
createSeriesSelectorForHook(seriesId),
(qualityProfiles, series = {}) => {
return qualityProfiles.find((profile) => {
return profile.id === series.qualityProfileId;
});
}
);
}
export default createSeriesQualityProfileSelector;

View File

@ -0,0 +1,18 @@
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import Series from 'Series/Series';
import { createSeriesSelectorForHook } from './createSeriesSelector';
function createSeriesQualityProfileSelector(seriesId: number) {
return createSelector(
(state: AppState) => state.settings.qualityProfiles.items,
createSeriesSelectorForHook(seriesId),
(qualityProfiles, series = {} as Series) => {
return qualityProfiles.find(
(profile) => profile.id === series.qualityProfileId
);
}
);
}
export default createSeriesQualityProfileSelector;

View File

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

View File

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

View File

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

View File

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

View File

@ -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;