Convert store selectors to Typescript

Closes #3937
This commit is contained in:
Bogdan 2023-07-30 16:23:41 +03:00
parent bc69fa4842
commit db9e62f79d
28 changed files with 188 additions and 125 deletions

View File

@ -28,7 +28,8 @@ module.exports = {
globals: {
expect: false,
chai: false,
sinon: false
sinon: false,
JSX: true
},
parserOptions: {

View File

@ -5,6 +5,7 @@ import CommandAppState from './CommandAppState';
import HistoryAppState from './HistoryAppState';
import QueueAppState from './QueueAppState';
import SettingsAppState from './SettingsAppState';
import SystemAppState from './SystemAppState';
import TagsAppState from './TagsAppState';
import TrackFilesAppState from './TrackFilesAppState';
import TracksAppState from './TracksAppState';
@ -62,6 +63,7 @@ interface AppState {
tags: TagsAppState;
trackFiles: TrackFilesAppState;
tracksSelection: TracksAppState;
system: SystemAppState;
}
export default AppState;

View File

@ -1,5 +1,6 @@
import AppSectionState, {
AppSectionDeleteState,
AppSectionItemState,
AppSectionSaveState,
AppSectionSchemaState,
} from 'App/State/AppSectionState';
@ -46,7 +47,7 @@ export interface RootFolderAppState
AppSectionSaveState {}
export type IndexerFlagSettingsAppState = AppSectionState<IndexerFlag>;
export type UiSettingsAppState = AppSectionState<UiSettings>;
export type UiSettingsAppState = AppSectionItemState<UiSettings>;
interface SettingsAppState {
downloadClients: DownloadClientAppState;
@ -57,7 +58,7 @@ interface SettingsAppState {
notifications: NotificationAppState;
qualityProfiles: QualityProfilesAppState;
rootFolders: RootFolderAppState;
uiSettings: UiSettingsAppState;
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[];
artistIds: number[];
}
export interface TagDetailAppState
extends AppSectionState<TagDetail>,
AppSectionDeleteState,
AppSectionSaveState {}
interface TagsAppState extends AppSectionState<Tag>, AppSectionDeleteState {
details: TagDetailAppState;
}
export default TagsAppState;

View File

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

View File

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

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) => {
return isCommandExecuting(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,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,15 @@
import _ from 'lodash';
import { some } from 'lodash';
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import createAllArtistSelector from './createAllArtistSelector';
function createExistingArtistSelector() {
return createSelector(
(state, { foreignArtistId }) => foreignArtistId,
(_: AppState, { foreignArtistId }: { foreignArtistId: string }) =>
foreignArtistId,
createAllArtistSelector(),
(foreignArtistId, artist) => {
return _.some(artist, { foreignArtistId });
return some(artist, { foreignArtistId });
}
);
}

View File

@ -1,15 +0,0 @@
import { createSelector } from 'reselect';
function createMetadataProfileSelector() {
return createSelector(
(state, { metadataProfileId }) => metadataProfileId,
(state) => state.settings.metadataProfiles.items,
(metadataProfileId, metadataProfiles) => {
return metadataProfiles.find((profile) => {
return profile.id === metadataProfileId;
});
}
);
}
export default createMetadataProfileSelector;

View File

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

View File

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

View File

@ -0,0 +1,25 @@
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import Artist from 'Artist/Artist';
import ImportList from 'typings/ImportList';
import createAllArtistSelector from './createAllArtistSelector';
function createProfileInUseSelector(profileProp: string) {
return createSelector(
(_: AppState, { id }: { id: number }) => id,
createAllArtistSelector(),
(state: AppState) => state.settings.importLists.items,
(id, artists, lists) => {
if (!id) {
return false;
}
return (
artists.some((a) => a[profileProp as keyof Artist] === 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,21 +1,16 @@
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
function createQueueItemSelector() {
return createSelector(
(state, { albumId }) => albumId,
(state) => state.queue.details.items,
(_: AppState, { albumId }: { albumId: number }) => albumId,
(state: AppState) => state.queue.details.items,
(albumId, details) => {
if (!albumId || !details) {
return null;
}
return details.find((item) => {
if (item.album) {
return item.album.id === albumId;
}
return false;
});
return details.find((item) => item.albumId === albumId);
}
);
}

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,9 +1,10 @@
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
function createTrackFileSelector() {
return createSelector(
(state, { trackFileId }) => trackFileId,
(state) => state.trackFiles,
(_: AppState, { trackFileId }: { trackFileId: number }) => trackFileId,
(state: AppState) => state.trackFiles,
(trackFileId, trackFiles) => {
if (!trackFileId) {
return;

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;