Convert Utilities to TypeScript
This commit is contained in:
parent
76650af9fd
commit
d46f4b2154
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"typescript.tsdk": "node_modules\\typescript\\lib"
|
||||||
|
}
|
|
@ -43,6 +43,13 @@ export interface AppSectionSchemaState<T> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AppSectionItemSchemaState<T> {
|
||||||
|
isSchemaFetching: boolean;
|
||||||
|
isSchemaPopulated: boolean;
|
||||||
|
schemaError: Error;
|
||||||
|
schema: T;
|
||||||
|
}
|
||||||
|
|
||||||
export interface AppSectionItemState<T> {
|
export interface AppSectionItemState<T> {
|
||||||
isFetching: boolean;
|
isFetching: boolean;
|
||||||
isPopulated: boolean;
|
isPopulated: boolean;
|
||||||
|
|
|
@ -35,14 +35,14 @@ export interface PropertyFilter {
|
||||||
export interface Filter {
|
export interface Filter {
|
||||||
key: string;
|
key: string;
|
||||||
label: string;
|
label: string;
|
||||||
filers: PropertyFilter[];
|
filters: PropertyFilter[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CustomFilter {
|
export interface CustomFilter {
|
||||||
id: number;
|
id: number;
|
||||||
type: string;
|
type: string;
|
||||||
label: string;
|
label: string;
|
||||||
filers: PropertyFilter[];
|
filters: PropertyFilter[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AppSectionState {
|
export interface AppSectionState {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import AppSectionState, {
|
import AppSectionState, {
|
||||||
AppSectionDeleteState,
|
AppSectionDeleteState,
|
||||||
|
AppSectionItemSchemaState,
|
||||||
AppSectionItemState,
|
AppSectionItemState,
|
||||||
AppSectionSaveState,
|
AppSectionSaveState,
|
||||||
AppSectionSchemaState,
|
|
||||||
PagedAppSectionState,
|
PagedAppSectionState,
|
||||||
} from 'App/State/AppSectionState';
|
} from 'App/State/AppSectionState';
|
||||||
import Language from 'Language/Language';
|
import Language from 'Language/Language';
|
||||||
|
@ -40,7 +40,7 @@ export interface NotificationAppState
|
||||||
|
|
||||||
export interface QualityProfilesAppState
|
export interface QualityProfilesAppState
|
||||||
extends AppSectionState<QualityProfile>,
|
extends AppSectionState<QualityProfile>,
|
||||||
AppSectionSchemaState<QualityProfile> {}
|
AppSectionItemSchemaState<QualityProfile> {}
|
||||||
|
|
||||||
export interface ImportListOptionsSettingsAppState
|
export interface ImportListOptionsSettingsAppState
|
||||||
extends AppSectionItemState<ImportListOptionsSettings>,
|
extends AppSectionItemState<ImportListOptionsSettings>,
|
||||||
|
|
|
@ -1,5 +1,16 @@
|
||||||
import ModelBase from 'App/ModelBase';
|
import ModelBase from 'App/ModelBase';
|
||||||
|
|
||||||
|
export type CommandStatus =
|
||||||
|
| 'queued'
|
||||||
|
| 'started'
|
||||||
|
| 'completed'
|
||||||
|
| 'failed'
|
||||||
|
| 'aborted'
|
||||||
|
| 'cancelled'
|
||||||
|
| 'orphaned';
|
||||||
|
|
||||||
|
export type CommandResult = 'unknown' | 'successful' | 'unsuccessful';
|
||||||
|
|
||||||
export interface CommandBody {
|
export interface CommandBody {
|
||||||
sendUpdatesToClient: boolean;
|
sendUpdatesToClient: boolean;
|
||||||
updateScheduledTask: boolean;
|
updateScheduledTask: boolean;
|
||||||
|
@ -15,6 +26,7 @@ export interface CommandBody {
|
||||||
seriesId?: number;
|
seriesId?: number;
|
||||||
seriesIds?: number[];
|
seriesIds?: number[];
|
||||||
seasonNumber?: number;
|
seasonNumber?: number;
|
||||||
|
[key: string]: string | number | boolean | undefined | number[] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Command extends ModelBase {
|
interface Command extends ModelBase {
|
||||||
|
@ -23,8 +35,8 @@ interface Command extends ModelBase {
|
||||||
message: string;
|
message: string;
|
||||||
body: CommandBody;
|
body: CommandBody;
|
||||||
priority: string;
|
priority: string;
|
||||||
status: string;
|
status: CommandStatus;
|
||||||
result: string;
|
result: CommandResult;
|
||||||
queued: string;
|
queued: string;
|
||||||
started: string;
|
started: string;
|
||||||
ended: string;
|
ended: string;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { Error } from 'App/State/AppSectionState';
|
|
||||||
import AppState from 'App/State/AppState';
|
import AppState from 'App/State/AppState';
|
||||||
import Alert from 'Components/Alert';
|
import Alert from 'Components/Alert';
|
||||||
import Form from 'Components/Form/Form';
|
import Form from 'Components/Form/Form';
|
||||||
|
@ -21,21 +20,14 @@ import { CheckInputChanged } from 'typings/inputs';
|
||||||
import getQualities from 'Utilities/Quality/getQualities';
|
import getQualities from 'Utilities/Quality/getQualities';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
|
|
||||||
interface QualitySchemaState {
|
|
||||||
isFetching: boolean;
|
|
||||||
isPopulated: boolean;
|
|
||||||
error: Error;
|
|
||||||
items: Quality[];
|
|
||||||
}
|
|
||||||
|
|
||||||
function createQualitySchemaSelector() {
|
function createQualitySchemaSelector() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state: AppState) => state.settings.qualityProfiles,
|
(state: AppState) => state.settings.qualityProfiles,
|
||||||
(qualityProfiles): QualitySchemaState => {
|
(qualityProfiles) => {
|
||||||
const { isSchemaFetching, isSchemaPopulated, schemaError, schema } =
|
const { isSchemaFetching, isSchemaPopulated, schemaError, schema } =
|
||||||
qualityProfiles;
|
qualityProfiles;
|
||||||
|
|
||||||
const items = getQualities(schema.items) as Quality[];
|
const items = getQualities(schema.items);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isFetching: isSchemaFetching,
|
isFetching: isSchemaFetching,
|
||||||
|
|
|
@ -2,6 +2,20 @@ import ModelBase from 'App/ModelBase';
|
||||||
import Language from 'Language/Language';
|
import Language from 'Language/Language';
|
||||||
|
|
||||||
export type SeriesType = 'anime' | 'daily' | 'standard';
|
export type SeriesType = 'anime' | 'daily' | 'standard';
|
||||||
|
export type SeriesMonitor =
|
||||||
|
| 'all'
|
||||||
|
| 'future'
|
||||||
|
| 'missing'
|
||||||
|
| 'existing'
|
||||||
|
| 'recent'
|
||||||
|
| 'pilot'
|
||||||
|
| 'firstSeason'
|
||||||
|
| 'lastSeason'
|
||||||
|
| 'monitorSpecials'
|
||||||
|
| 'unmonitorSpecials'
|
||||||
|
| 'none';
|
||||||
|
|
||||||
|
export type MonitorNewItems = 'all' | 'none';
|
||||||
|
|
||||||
export interface Image {
|
export interface Image {
|
||||||
coverType: string;
|
coverType: string;
|
||||||
|
@ -34,7 +48,15 @@ export interface Ratings {
|
||||||
|
|
||||||
export interface AlternateTitle {
|
export interface AlternateTitle {
|
||||||
seasonNumber: number;
|
seasonNumber: number;
|
||||||
|
sceneSeasonNumber?: number;
|
||||||
title: string;
|
title: string;
|
||||||
|
sceneOrigin: 'unknown' | 'unknown:tvdb' | 'mixed' | 'tvdb';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SeriesAddOptions {
|
||||||
|
monitor: SeriesMonitor;
|
||||||
|
searchForMissingEpisodes: boolean;
|
||||||
|
searchForCutoffUnmetEpisodes: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Series extends ModelBase {
|
interface Series extends ModelBase {
|
||||||
|
@ -48,6 +70,7 @@ interface Series extends ModelBase {
|
||||||
images: Image[];
|
images: Image[];
|
||||||
imdbId: string;
|
imdbId: string;
|
||||||
monitored: boolean;
|
monitored: boolean;
|
||||||
|
monitorNewItems: MonitorNewItems;
|
||||||
network: string;
|
network: string;
|
||||||
originalLanguage: Language;
|
originalLanguage: Language;
|
||||||
overview: string;
|
overview: string;
|
||||||
|
@ -74,6 +97,7 @@ interface Series extends ModelBase {
|
||||||
useSceneNumbering: boolean;
|
useSceneNumbering: boolean;
|
||||||
year: number;
|
year: number;
|
||||||
isSaving?: boolean;
|
isSaving?: boolean;
|
||||||
|
addOptions: SeriesAddOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Series;
|
export default Series;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import pages from 'Utilities/pages';
|
import pages from 'Utilities/State/pages';
|
||||||
import serverSideCollectionHandlers from 'Utilities/serverSideCollectionHandlers';
|
import serverSideCollectionHandlers from 'Utilities/State/serverSideCollectionHandlers';
|
||||||
import createFetchServerSideCollectionHandler from './createFetchServerSideCollectionHandler';
|
import createFetchServerSideCollectionHandler from './createFetchServerSideCollectionHandler';
|
||||||
import createSetServerSideCollectionFilterHandler from './createSetServerSideCollectionFilterHandler';
|
import createSetServerSideCollectionFilterHandler from './createSetServerSideCollectionFilterHandler';
|
||||||
import createSetServerSideCollectionPageHandler from './createSetServerSideCollectionPageHandler';
|
import createSetServerSideCollectionPageHandler from './createSetServerSideCollectionPageHandler';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import pages from 'Utilities/pages';
|
|
||||||
import getSectionState from 'Utilities/State/getSectionState';
|
import getSectionState from 'Utilities/State/getSectionState';
|
||||||
|
import pages from 'Utilities/State/pages';
|
||||||
|
|
||||||
function createSetServerSideCollectionPageHandler(section, page, fetchHandler) {
|
function createSetServerSideCollectionPageHandler(section, page, fetchHandler) {
|
||||||
return function(getState, payload, dispatch) {
|
return function(getState, payload, dispatch) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import createServerSideCollectionHandlers from 'Store/Actions/Creators/createSer
|
||||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||||
import createSetTableOptionReducer from 'Store/Actions/Creators/Reducers/createSetTableOptionReducer';
|
import createSetTableOptionReducer from 'Store/Actions/Creators/Reducers/createSetTableOptionReducer';
|
||||||
import { createThunk, handleThunks } from 'Store/thunks';
|
import { createThunk, handleThunks } from 'Store/thunks';
|
||||||
import serverSideCollectionHandlers from 'Utilities/serverSideCollectionHandlers';
|
import serverSideCollectionHandlers from 'Utilities/State/serverSideCollectionHandlers';
|
||||||
|
|
||||||
//
|
//
|
||||||
// Variables
|
// Variables
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { batchActions } from 'redux-batched-actions';
|
||||||
import { filterBuilderTypes, filterBuilderValueTypes, sortDirections } from 'Helpers/Props';
|
import { filterBuilderTypes, filterBuilderValueTypes, sortDirections } from 'Helpers/Props';
|
||||||
import { createThunk, handleThunks } from 'Store/thunks';
|
import { createThunk, handleThunks } from 'Store/thunks';
|
||||||
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
||||||
import serverSideCollectionHandlers from 'Utilities/serverSideCollectionHandlers';
|
import serverSideCollectionHandlers from 'Utilities/State/serverSideCollectionHandlers';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import { set, updateItem } from './baseActions';
|
import { set, updateItem } from './baseActions';
|
||||||
import createHandleActions from './Creators/createHandleActions';
|
import createHandleActions from './Creators/createHandleActions';
|
||||||
|
|
|
@ -4,7 +4,7 @@ import Icon from 'Components/Icon';
|
||||||
import { filterBuilderTypes, filterBuilderValueTypes, filterTypes, icons, sortDirections } from 'Helpers/Props';
|
import { filterBuilderTypes, filterBuilderValueTypes, filterTypes, icons, sortDirections } from 'Helpers/Props';
|
||||||
import { createThunk, handleThunks } from 'Store/thunks';
|
import { createThunk, handleThunks } from 'Store/thunks';
|
||||||
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
||||||
import serverSideCollectionHandlers from 'Utilities/serverSideCollectionHandlers';
|
import serverSideCollectionHandlers from 'Utilities/State/serverSideCollectionHandlers';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import { updateItem } from './baseActions';
|
import { updateItem } from './baseActions';
|
||||||
import createHandleActions from './Creators/createHandleActions';
|
import createHandleActions from './Creators/createHandleActions';
|
||||||
|
|
|
@ -6,7 +6,7 @@ import Icon from 'Components/Icon';
|
||||||
import { filterBuilderTypes, filterBuilderValueTypes, icons, sortDirections } from 'Helpers/Props';
|
import { filterBuilderTypes, filterBuilderValueTypes, icons, sortDirections } from 'Helpers/Props';
|
||||||
import { createThunk, handleThunks } from 'Store/thunks';
|
import { createThunk, handleThunks } from 'Store/thunks';
|
||||||
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
||||||
import serverSideCollectionHandlers from 'Utilities/serverSideCollectionHandlers';
|
import serverSideCollectionHandlers from 'Utilities/State/serverSideCollectionHandlers';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import { set, updateItem } from './baseActions';
|
import { set, updateItem } from './baseActions';
|
||||||
import createFetchHandler from './Creators/createFetchHandler';
|
import createFetchHandler from './Creators/createFetchHandler';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { filterTypes, sortDirections } from 'Helpers/Props';
|
||||||
import { setAppValue } from 'Store/Actions/appActions';
|
import { setAppValue } from 'Store/Actions/appActions';
|
||||||
import { createThunk, handleThunks } from 'Store/thunks';
|
import { createThunk, handleThunks } from 'Store/thunks';
|
||||||
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
||||||
import serverSideCollectionHandlers from 'Utilities/serverSideCollectionHandlers';
|
import serverSideCollectionHandlers from 'Utilities/State/serverSideCollectionHandlers';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import { pingServer } from './appActions';
|
import { pingServer } from './appActions';
|
||||||
import { set } from './baseActions';
|
import { set } from './baseActions';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { createAction } from 'redux-actions';
|
import { createAction } from 'redux-actions';
|
||||||
import { filterTypes, sortDirections } from 'Helpers/Props';
|
import { filterTypes, sortDirections } from 'Helpers/Props';
|
||||||
import { createThunk, handleThunks } from 'Store/thunks';
|
import { createThunk, handleThunks } from 'Store/thunks';
|
||||||
import serverSideCollectionHandlers from 'Utilities/serverSideCollectionHandlers';
|
import serverSideCollectionHandlers from 'Utilities/State/serverSideCollectionHandlers';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import createBatchToggleEpisodeMonitoredHandler from './Creators/createBatchToggleEpisodeMonitoredHandler';
|
import createBatchToggleEpisodeMonitoredHandler from './Creators/createBatchToggleEpisodeMonitoredHandler';
|
||||||
import createHandleActions from './Creators/createHandleActions';
|
import createHandleActions from './Creators/createHandleActions';
|
||||||
|
|
|
@ -4,7 +4,7 @@ import createCommandSelector from './createCommandSelector';
|
||||||
|
|
||||||
function createCommandExecutingSelector(name: string, contraints = {}) {
|
function createCommandExecutingSelector(name: string, contraints = {}) {
|
||||||
return createSelector(createCommandSelector(name, contraints), (command) => {
|
return createSelector(createCommandSelector(name, contraints), (command) => {
|
||||||
return isCommandExecuting(command);
|
return command ? isCommandExecuting(command) : false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
export default function getIndexOfFirstCharacter(items, character) {
|
|
||||||
return items.findIndex((item) => {
|
|
||||||
const firstCharacter = item.sortTitle.charAt(0);
|
|
||||||
|
|
||||||
if (character === '#') {
|
|
||||||
return !isNaN(firstCharacter);
|
|
||||||
}
|
|
||||||
|
|
||||||
return firstCharacter === character;
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
import Series from 'Series/Series';
|
||||||
|
|
||||||
|
const STARTS_WITH_NUMBER_REGEX = /^\d/;
|
||||||
|
|
||||||
|
export default function getIndexOfFirstCharacter(
|
||||||
|
items: Series[],
|
||||||
|
character: string
|
||||||
|
) {
|
||||||
|
return items.findIndex((item) => {
|
||||||
|
const firstCharacter = item.sortTitle.charAt(0);
|
||||||
|
|
||||||
|
if (character === '#') {
|
||||||
|
return STARTS_WITH_NUMBER_REGEX.test(firstCharacter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return firstCharacter === character;
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import Command, { CommandBody } from 'Commands/Command';
|
||||||
import isSameCommand from './isSameCommand';
|
import isSameCommand from './isSameCommand';
|
||||||
|
|
||||||
function findCommand(commands, options) {
|
function findCommand(commands: Command[], options: Partial<CommandBody>) {
|
||||||
return _.findLast(commands, (command) => {
|
return _.findLast(commands, (command) => {
|
||||||
return isSameCommand(command.body, options);
|
return isSameCommand(command.body, options);
|
||||||
});
|
});
|
|
@ -1,9 +0,0 @@
|
||||||
function isCommandComplete(command) {
|
|
||||||
if (!command) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return command.status === 'complete';
|
|
||||||
}
|
|
||||||
|
|
||||||
export default isCommandComplete;
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import Command from 'Commands/Command';
|
||||||
|
|
||||||
|
function isCommandComplete(command: Command) {
|
||||||
|
if (!command) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return command.status === 'completed';
|
||||||
|
}
|
||||||
|
|
||||||
|
export default isCommandComplete;
|
|
@ -1,4 +1,6 @@
|
||||||
function isCommandExecuting(command) {
|
import Command from 'Commands/Command';
|
||||||
|
|
||||||
|
function isCommandExecuting(command?: Command) {
|
||||||
if (!command) {
|
if (!command) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
|
@ -1,12 +0,0 @@
|
||||||
function isCommandFailed(command) {
|
|
||||||
if (!command) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return command.status === 'failed' ||
|
|
||||||
command.status === 'aborted' ||
|
|
||||||
command.status === 'cancelled' ||
|
|
||||||
command.status === 'orphaned';
|
|
||||||
}
|
|
||||||
|
|
||||||
export default isCommandFailed;
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
import Command from 'Commands/Command';
|
||||||
|
|
||||||
|
function isCommandFailed(command: Command) {
|
||||||
|
if (!command) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
command.status === 'failed' ||
|
||||||
|
command.status === 'aborted' ||
|
||||||
|
command.status === 'cancelled' ||
|
||||||
|
command.status === 'orphaned'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default isCommandFailed;
|
|
@ -1,24 +0,0 @@
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
function isSameCommand(commandA, commandB) {
|
|
||||||
if (commandA.name.toLocaleLowerCase() !== commandB.name.toLocaleLowerCase()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const key in commandB) {
|
|
||||||
if (key !== 'name') {
|
|
||||||
const value = commandB[key];
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
if (_.difference(value, commandA[key]).length > 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (value !== commandA[key]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default isSameCommand;
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
import { CommandBody } from 'Commands/Command';
|
||||||
|
|
||||||
|
function isSameCommand(
|
||||||
|
commandA: Partial<CommandBody>,
|
||||||
|
commandB: Partial<CommandBody>
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
commandA.name?.toLocaleLowerCase() !== commandB.name?.toLocaleLowerCase()
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key in commandB) {
|
||||||
|
if (key !== 'name') {
|
||||||
|
const value = commandB[key];
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
const sortedB = [...value].sort((a, b) => a - b);
|
||||||
|
const commandAProp = commandA[key];
|
||||||
|
const sortedA = Array.isArray(commandAProp)
|
||||||
|
? [...commandAProp].sort((a, b) => a - b)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
if (sortedA === sortedB) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sortedA == null || sortedB == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sortedA.length !== sortedB.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < sortedB.length; ++i) {
|
||||||
|
if (sortedB[i] !== sortedA[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (value !== commandA[key]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default isSameCommand;
|
|
@ -1,12 +1,17 @@
|
||||||
import _ from 'lodash';
|
import Episode from 'Episode/Episode';
|
||||||
import { update } from 'Store/Actions/baseActions';
|
import { update } from 'Store/Actions/baseActions';
|
||||||
|
|
||||||
function updateEpisodes(section, episodes, episodeIds, options) {
|
function updateEpisodes(
|
||||||
const data = _.reduce(episodes, (result, item) => {
|
section: string,
|
||||||
|
episodes: Episode[],
|
||||||
|
episodeIds: number[],
|
||||||
|
options: Partial<Episode>
|
||||||
|
) {
|
||||||
|
const data = episodes.reduce<Episode[]>((result, item) => {
|
||||||
if (episodeIds.indexOf(item.id) > -1) {
|
if (episodeIds.indexOf(item.id) > -1) {
|
||||||
result.push({
|
result.push({
|
||||||
...item,
|
...item,
|
||||||
...options
|
...options,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
result.push(item);
|
result.push(item);
|
|
@ -1,19 +0,0 @@
|
||||||
export default function findSelectedFilters(selectedFilterKey, filters = [], customFilters = []) {
|
|
||||||
if (!selectedFilterKey) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
let selectedFilter = filters.find((f) => f.key === selectedFilterKey);
|
|
||||||
|
|
||||||
if (!selectedFilter) {
|
|
||||||
selectedFilter = customFilters.find((f) => f.id === selectedFilterKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!selectedFilter) {
|
|
||||||
// TODO: throw in dev
|
|
||||||
console.error('Matching filter not found');
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return selectedFilter.filters;
|
|
||||||
}
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { CustomFilter, Filter } from 'App/State/AppState';
|
||||||
|
|
||||||
|
export default function findSelectedFilters(
|
||||||
|
selectedFilterKey: string | number,
|
||||||
|
filters: Filter[] = [],
|
||||||
|
customFilters: CustomFilter[] = []
|
||||||
|
) {
|
||||||
|
if (!selectedFilterKey) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
let selectedFilter: Filter | CustomFilter | undefined = filters.find(
|
||||||
|
(f) => f.key === selectedFilterKey
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!selectedFilter) {
|
||||||
|
selectedFilter = customFilters.find((f) => f.id === selectedFilterKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selectedFilter) {
|
||||||
|
// TODO: throw in dev
|
||||||
|
console.error('Matching filter not found');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectedFilter.filters;
|
||||||
|
}
|
|
@ -1,4 +1,11 @@
|
||||||
export default function getFilterValue(filters, filterKey, filterValueKey, defaultValue) {
|
import { Filter } from 'App/State/AppState';
|
||||||
|
|
||||||
|
export default function getFilterValue(
|
||||||
|
filters: Filter[],
|
||||||
|
filterKey: string | number,
|
||||||
|
filterValueKey: string,
|
||||||
|
defaultValue: string | number | boolean
|
||||||
|
) {
|
||||||
const filter = filters.find((f) => f.key === filterKey);
|
const filter = filters.find((f) => f.key === filterKey);
|
||||||
|
|
||||||
if (!filter) {
|
if (!filter) {
|
|
@ -1,5 +1,4 @@
|
||||||
|
function convertToBytes(input: number, power: number, binaryPrefix: boolean) {
|
||||||
function convertToBytes(input, power, binaryPrefix) {
|
|
||||||
const size = Number(input);
|
const size = Number(input);
|
||||||
|
|
||||||
if (isNaN(size)) {
|
if (isNaN(size)) {
|
|
@ -1,19 +0,0 @@
|
||||||
import translate from 'Utilities/String/translate';
|
|
||||||
|
|
||||||
function formatAge(age, ageHours, ageMinutes) {
|
|
||||||
age = Math.round(age);
|
|
||||||
ageHours = parseFloat(ageHours);
|
|
||||||
ageMinutes = ageMinutes && parseFloat(ageMinutes);
|
|
||||||
|
|
||||||
if (age < 2 && ageHours) {
|
|
||||||
if (ageHours < 2 && !!ageMinutes) {
|
|
||||||
return `${ageMinutes.toFixed(0)} ${ageHours === 1 ? translate('FormatAgeMinute') : translate('FormatAgeMinutes')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${ageHours.toFixed(1)} ${ageHours === 1 ? translate('FormatAgeHour') : translate('FormatAgeHours')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${age} ${age === 1 ? translate('FormatAgeDay') : translate('FormatAgeDays')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default formatAge;
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import translate from 'Utilities/String/translate';
|
||||||
|
|
||||||
|
function formatAge(
|
||||||
|
age: string | number,
|
||||||
|
ageHours: string | number,
|
||||||
|
ageMinutes: string | number
|
||||||
|
) {
|
||||||
|
const ageRounded = Math.round(Number(age));
|
||||||
|
const ageHoursFloat = parseFloat(String(ageHours));
|
||||||
|
const ageMinutesFloat = ageMinutes && parseFloat(String(ageMinutes));
|
||||||
|
|
||||||
|
if (ageRounded < 2 && ageHoursFloat) {
|
||||||
|
if (ageHoursFloat < 2 && !!ageMinutesFloat) {
|
||||||
|
return `${ageMinutesFloat.toFixed(0)} ${
|
||||||
|
ageHoursFloat === 1
|
||||||
|
? translate('FormatAgeMinute')
|
||||||
|
: translate('FormatAgeMinutes')
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${ageHoursFloat.toFixed(1)} ${
|
||||||
|
ageHoursFloat === 1
|
||||||
|
? translate('FormatAgeHour')
|
||||||
|
: translate('FormatAgeHours')
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${ageRounded} ${
|
||||||
|
ageRounded === 1 ? translate('FormatAgeDay') : translate('FormatAgeDays')
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default formatAge;
|
|
@ -1,6 +1,10 @@
|
||||||
import { filesize } from 'filesize';
|
import { filesize } from 'filesize';
|
||||||
|
|
||||||
function formatBytes(input) {
|
function formatBytes(input?: string | number) {
|
||||||
|
if (!input) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
const size = Number(input);
|
const size = Number(input);
|
||||||
|
|
||||||
if (isNaN(size)) {
|
if (isNaN(size)) {
|
||||||
|
@ -9,7 +13,7 @@ function formatBytes(input) {
|
||||||
|
|
||||||
return `${filesize(size, {
|
return `${filesize(size, {
|
||||||
base: 2,
|
base: 2,
|
||||||
round: 1
|
round: 1,
|
||||||
})}`;
|
})}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
function padNumber(input, width, paddingCharacter = 0) {
|
|
||||||
if (input == null) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
input = `${input}`;
|
|
||||||
return input.length >= width ? input : new Array(width - input.length + 1).join(paddingCharacter) + input;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default padNumber;
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
function padNumber(input: number, width: number, paddingCharacter = '0') {
|
||||||
|
if (input == null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = `${input}`;
|
||||||
|
|
||||||
|
return result.length >= width
|
||||||
|
? result
|
||||||
|
: new Array(width - result.length + 1).join(paddingCharacter) + result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default padNumber;
|
|
@ -1,4 +1,4 @@
|
||||||
export default function roundNumber(input, decimalPlaces = 1) {
|
export default function roundNumber(input: number, decimalPlaces = 1) {
|
||||||
const multiplier = Math.pow(10, decimalPlaces);
|
const multiplier = Math.pow(10, decimalPlaces);
|
||||||
|
|
||||||
return Math.round(input * multiplier) / multiplier;
|
return Math.round(input * multiplier) / multiplier;
|
|
@ -1,4 +1,12 @@
|
||||||
function getErrorMessage(xhr, fallbackErrorMessage) {
|
interface AjaxResponse {
|
||||||
|
responseJSON:
|
||||||
|
| {
|
||||||
|
message: string | undefined;
|
||||||
|
}
|
||||||
|
| undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getErrorMessage(xhr: AjaxResponse, fallbackErrorMessage?: string) {
|
||||||
if (!xhr || !xhr.responseJSON || !xhr.responseJSON.message) {
|
if (!xhr || !xhr.responseJSON || !xhr.responseJSON.message) {
|
||||||
return fallbackErrorMessage;
|
return fallbackErrorMessage;
|
||||||
}
|
}
|
|
@ -1,15 +0,0 @@
|
||||||
function getRemovedItems(prevItems, currentItems, idProp = 'id') {
|
|
||||||
if (prevItems === currentItems) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentItemIds = new Set();
|
|
||||||
|
|
||||||
currentItems.forEach((currentItem) => {
|
|
||||||
currentItemIds.add(currentItem[idProp]);
|
|
||||||
});
|
|
||||||
|
|
||||||
return prevItems.filter((prevItem) => !currentItemIds.has(prevItem[idProp]));
|
|
||||||
}
|
|
||||||
|
|
||||||
export default getRemovedItems;
|
|
|
@ -1,4 +1,10 @@
|
||||||
function hasDifferentItems(prevItems, currentItems, idProp = 'id') {
|
import ModelBase from 'App/ModelBase';
|
||||||
|
|
||||||
|
function hasDifferentItems<T extends ModelBase>(
|
||||||
|
prevItems: T[],
|
||||||
|
currentItems: T[],
|
||||||
|
idProp: keyof T = 'id'
|
||||||
|
) {
|
||||||
if (prevItems === currentItems) {
|
if (prevItems === currentItems) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
|
@ -1,4 +1,10 @@
|
||||||
function hasDifferentItemsOrOrder(prevItems, currentItems, idProp = 'id') {
|
import ModelBase from 'App/ModelBase';
|
||||||
|
|
||||||
|
function hasDifferentItemsOrOrder<T extends ModelBase>(
|
||||||
|
prevItems: T[],
|
||||||
|
currentItems: T[],
|
||||||
|
idProp: keyof T = 'id'
|
||||||
|
) {
|
||||||
if (prevItems === currentItems) {
|
if (prevItems === currentItems) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
|
@ -1,16 +0,0 @@
|
||||||
export default function getQualities(qualities) {
|
|
||||||
if (!qualities) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return qualities.reduce((acc, item) => {
|
|
||||||
if (item.quality) {
|
|
||||||
acc.push(item.quality);
|
|
||||||
} else {
|
|
||||||
const groupQualities = item.items.map((i) => i.quality);
|
|
||||||
acc.push(...groupQualities);
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, []);
|
|
||||||
}
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import Quality from 'Quality/Quality';
|
||||||
|
import { QualityProfileQualityItem } from 'typings/QualityProfile';
|
||||||
|
|
||||||
|
export default function getQualities(qualities?: QualityProfileQualityItem[]) {
|
||||||
|
if (!qualities) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return qualities.reduce<Quality[]>((acc, item) => {
|
||||||
|
if (item.quality) {
|
||||||
|
acc.push(item.quality);
|
||||||
|
} else {
|
||||||
|
const groupQualities = item.items.reduce<Quality[]>((acc, i) => {
|
||||||
|
if (i.quality) {
|
||||||
|
acc.push(i.quality);
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
acc.push(...groupQualities);
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
import $ from 'jquery';
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
resolutions: {
|
|
||||||
desktopLarge: 1200,
|
|
||||||
desktop: 992,
|
|
||||||
tablet: 768,
|
|
||||||
mobile: 480
|
|
||||||
},
|
|
||||||
|
|
||||||
isDesktopLarge() {
|
|
||||||
return $(window).width() < this.resolutions.desktopLarge;
|
|
||||||
},
|
|
||||||
|
|
||||||
isDesktop() {
|
|
||||||
return $(window).width() < this.resolutions.desktop;
|
|
||||||
},
|
|
||||||
|
|
||||||
isTablet() {
|
|
||||||
return $(window).width() < this.resolutions.tablet;
|
|
||||||
},
|
|
||||||
|
|
||||||
isMobile() {
|
|
||||||
return $(window).width() < this.resolutions.mobile;
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
module.exports = {
|
||||||
|
resolutions: {
|
||||||
|
desktopLarge: 1200,
|
||||||
|
desktop: 992,
|
||||||
|
tablet: 768,
|
||||||
|
mobile: 480,
|
||||||
|
},
|
||||||
|
|
||||||
|
isDesktopLarge() {
|
||||||
|
return window.innerWidth < this.resolutions.desktopLarge;
|
||||||
|
},
|
||||||
|
|
||||||
|
isDesktop() {
|
||||||
|
return window.innerWidth < this.resolutions.desktop;
|
||||||
|
},
|
||||||
|
|
||||||
|
isTablet() {
|
||||||
|
return window.innerWidth < this.resolutions.tablet;
|
||||||
|
},
|
||||||
|
|
||||||
|
isMobile() {
|
||||||
|
return window.innerWidth < this.resolutions.mobile;
|
||||||
|
},
|
||||||
|
};
|
|
@ -1,53 +0,0 @@
|
||||||
|
|
||||||
function filterAlternateTitles(alternateTitles, seriesTitle, useSceneNumbering, seasonNumber, sceneSeasonNumber) {
|
|
||||||
const globalTitles = [];
|
|
||||||
const seasonTitles = [];
|
|
||||||
|
|
||||||
if (alternateTitles) {
|
|
||||||
alternateTitles.forEach((alternateTitle) => {
|
|
||||||
if (alternateTitle.sceneOrigin === 'unknown' || alternateTitle.sceneOrigin === 'unknown:tvdb') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alternateTitle.sceneOrigin === 'mixed') {
|
|
||||||
// For now filter out 'mixed' from the UI, the user will get an rejection during manual search.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasAltSeasonNumber = (alternateTitle.seasonNumber !== -1 && alternateTitle.seasonNumber !== undefined);
|
|
||||||
const hasAltSceneSeasonNumber = (alternateTitle.sceneSeasonNumber !== -1 && alternateTitle.sceneSeasonNumber !== undefined);
|
|
||||||
|
|
||||||
// Global alias that should be displayed global
|
|
||||||
if (!hasAltSeasonNumber && !hasAltSceneSeasonNumber &&
|
|
||||||
(alternateTitle.title !== seriesTitle) &&
|
|
||||||
(!alternateTitle.sceneOrigin || !useSceneNumbering)) {
|
|
||||||
globalTitles.push(alternateTitle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Global alias that should be displayed per episode
|
|
||||||
if (!hasAltSeasonNumber && !hasAltSceneSeasonNumber && alternateTitle.sceneOrigin && useSceneNumbering) {
|
|
||||||
seasonTitles.push(alternateTitle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply the alternative mapping (release to scene)
|
|
||||||
const mappedAltSeasonNumber = hasAltSeasonNumber ? alternateTitle.seasonNumber : alternateTitle.sceneSeasonNumber;
|
|
||||||
// Select scene or tvdb on the episode
|
|
||||||
const mappedSeasonNumber = alternateTitle.sceneOrigin === 'tvdb' ? seasonNumber : sceneSeasonNumber;
|
|
||||||
|
|
||||||
if (mappedSeasonNumber !== undefined && mappedSeasonNumber === mappedAltSeasonNumber) {
|
|
||||||
seasonTitles.push(alternateTitle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seasonNumber === undefined) {
|
|
||||||
return globalTitles;
|
|
||||||
}
|
|
||||||
|
|
||||||
return seasonTitles;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default filterAlternateTitles;
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
import { AlternateTitle } from 'Series/Series';
|
||||||
|
|
||||||
|
function filterAlternateTitles(
|
||||||
|
alternateTitles: AlternateTitle[],
|
||||||
|
seriesTitle: string | null,
|
||||||
|
useSceneNumbering: boolean,
|
||||||
|
seasonNumber?: number,
|
||||||
|
sceneSeasonNumber?: number
|
||||||
|
) {
|
||||||
|
const globalTitles: AlternateTitle[] = [];
|
||||||
|
const seasonTitles: AlternateTitle[] = [];
|
||||||
|
|
||||||
|
if (alternateTitles) {
|
||||||
|
alternateTitles.forEach((alternateTitle) => {
|
||||||
|
if (
|
||||||
|
alternateTitle.sceneOrigin === 'unknown' ||
|
||||||
|
alternateTitle.sceneOrigin === 'unknown:tvdb'
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alternateTitle.sceneOrigin === 'mixed') {
|
||||||
|
// For now filter out 'mixed' from the UI, the user will get an rejection during manual search.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasAltSeasonNumber =
|
||||||
|
alternateTitle.seasonNumber !== -1 &&
|
||||||
|
alternateTitle.seasonNumber !== undefined;
|
||||||
|
const hasAltSceneSeasonNumber =
|
||||||
|
alternateTitle.sceneSeasonNumber !== -1 &&
|
||||||
|
alternateTitle.sceneSeasonNumber !== undefined;
|
||||||
|
|
||||||
|
// Global alias that should be displayed global
|
||||||
|
if (
|
||||||
|
!hasAltSeasonNumber &&
|
||||||
|
!hasAltSceneSeasonNumber &&
|
||||||
|
alternateTitle.title !== seriesTitle &&
|
||||||
|
(!alternateTitle.sceneOrigin || !useSceneNumbering)
|
||||||
|
) {
|
||||||
|
globalTitles.push(alternateTitle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global alias that should be displayed per episode
|
||||||
|
if (
|
||||||
|
!hasAltSeasonNumber &&
|
||||||
|
!hasAltSceneSeasonNumber &&
|
||||||
|
alternateTitle.sceneOrigin &&
|
||||||
|
useSceneNumbering
|
||||||
|
) {
|
||||||
|
seasonTitles.push(alternateTitle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the alternative mapping (release to scene)
|
||||||
|
const mappedAltSeasonNumber = hasAltSeasonNumber
|
||||||
|
? alternateTitle.seasonNumber
|
||||||
|
: alternateTitle.sceneSeasonNumber;
|
||||||
|
// Select scene or tvdb on the episode
|
||||||
|
const mappedSeasonNumber =
|
||||||
|
alternateTitle.sceneOrigin === 'tvdb'
|
||||||
|
? seasonNumber
|
||||||
|
: sceneSeasonNumber;
|
||||||
|
|
||||||
|
if (
|
||||||
|
mappedSeasonNumber !== undefined &&
|
||||||
|
mappedSeasonNumber === mappedAltSeasonNumber
|
||||||
|
) {
|
||||||
|
seasonTitles.push(alternateTitle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seasonNumber === undefined) {
|
||||||
|
return globalTitles;
|
||||||
|
}
|
||||||
|
|
||||||
|
return seasonTitles;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default filterAlternateTitles;
|
|
@ -1,5 +1,22 @@
|
||||||
|
import Series, {
|
||||||
|
MonitorNewItems,
|
||||||
|
SeriesMonitor,
|
||||||
|
SeriesType,
|
||||||
|
} from 'Series/Series';
|
||||||
|
|
||||||
function getNewSeries(series, payload) {
|
interface NewSeriesPayload {
|
||||||
|
rootFolderPath: string;
|
||||||
|
monitor: SeriesMonitor;
|
||||||
|
monitorNewItems: MonitorNewItems;
|
||||||
|
qualityProfileId: number;
|
||||||
|
seriesType: SeriesType;
|
||||||
|
seasonFolder: boolean;
|
||||||
|
tags: number[];
|
||||||
|
searchForMissingEpisodes?: boolean;
|
||||||
|
searchForCutoffUnmetEpisodes?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNewSeries(series: Series, payload: NewSeriesPayload) {
|
||||||
const {
|
const {
|
||||||
rootFolderPath,
|
rootFolderPath,
|
||||||
monitor,
|
monitor,
|
||||||
|
@ -9,13 +26,13 @@ function getNewSeries(series, payload) {
|
||||||
seasonFolder,
|
seasonFolder,
|
||||||
tags,
|
tags,
|
||||||
searchForMissingEpisodes = false,
|
searchForMissingEpisodes = false,
|
||||||
searchForCutoffUnmetEpisodes = false
|
searchForCutoffUnmetEpisodes = false,
|
||||||
} = payload;
|
} = payload;
|
||||||
|
|
||||||
const addOptions = {
|
const addOptions = {
|
||||||
monitor,
|
monitor,
|
||||||
searchForMissingEpisodes,
|
searchForMissingEpisodes,
|
||||||
searchForCutoffUnmetEpisodes
|
searchForCutoffUnmetEpisodes,
|
||||||
};
|
};
|
||||||
|
|
||||||
series.addOptions = addOptions;
|
series.addOptions = addOptions;
|
|
@ -5,14 +5,14 @@ const monitorNewItemsOptions = [
|
||||||
key: 'all',
|
key: 'all',
|
||||||
get value() {
|
get value() {
|
||||||
return translate('MonitorAllSeasons');
|
return translate('MonitorAllSeasons');
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'none',
|
key: 'none',
|
||||||
get value() {
|
get value() {
|
||||||
return translate('MonitorNoNewSeasons');
|
return translate('MonitorNoNewSeasons');
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default monitorNewItemsOptions;
|
export default monitorNewItemsOptions;
|
|
@ -5,68 +5,68 @@ const monitorOptions = [
|
||||||
key: 'all',
|
key: 'all',
|
||||||
get value() {
|
get value() {
|
||||||
return translate('MonitorAllEpisodes');
|
return translate('MonitorAllEpisodes');
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'future',
|
key: 'future',
|
||||||
get value() {
|
get value() {
|
||||||
return translate('MonitorFutureEpisodes');
|
return translate('MonitorFutureEpisodes');
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'missing',
|
key: 'missing',
|
||||||
get value() {
|
get value() {
|
||||||
return translate('MonitorMissingEpisodes');
|
return translate('MonitorMissingEpisodes');
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'existing',
|
key: 'existing',
|
||||||
get value() {
|
get value() {
|
||||||
return translate('MonitorExistingEpisodes');
|
return translate('MonitorExistingEpisodes');
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'recent',
|
key: 'recent',
|
||||||
get value() {
|
get value() {
|
||||||
return translate('MonitorRecentEpisodes');
|
return translate('MonitorRecentEpisodes');
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'pilot',
|
key: 'pilot',
|
||||||
get value() {
|
get value() {
|
||||||
return translate('MonitorPilotEpisode');
|
return translate('MonitorPilotEpisode');
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'firstSeason',
|
key: 'firstSeason',
|
||||||
get value() {
|
get value() {
|
||||||
return translate('MonitorFirstSeason');
|
return translate('MonitorFirstSeason');
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'lastSeason',
|
key: 'lastSeason',
|
||||||
get value() {
|
get value() {
|
||||||
return translate('MonitorLastSeason');
|
return translate('MonitorLastSeason');
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'monitorSpecials',
|
key: 'monitorSpecials',
|
||||||
get value() {
|
get value() {
|
||||||
return translate('MonitorSpecialEpisodes');
|
return translate('MonitorSpecialEpisodes');
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'unmonitorSpecials',
|
key: 'unmonitorSpecials',
|
||||||
get value() {
|
get value() {
|
||||||
return translate('UnmonitorSpecialEpisodes');
|
return translate('UnmonitorSpecialEpisodes');
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'none',
|
key: 'none',
|
||||||
get value() {
|
get value() {
|
||||||
return translate('MonitorNoEpisodes');
|
return translate('MonitorNoEpisodes');
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default monitorOptions;
|
export default monitorOptions;
|
|
@ -1,5 +0,0 @@
|
||||||
function getNextId(items) {
|
|
||||||
return items.reduce((id, x) => Math.max(id, x.id), 1) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default getNextId;
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import ModelBase from 'App/ModelBase';
|
||||||
|
|
||||||
|
function getNextId<T extends ModelBase>(items: T[]) {
|
||||||
|
return items.reduce((id, x) => Math.max(id, x.id), 1) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getNextId;
|
|
@ -1,5 +0,0 @@
|
||||||
export default function combinePath(isWindows, basePath, paths = []) {
|
|
||||||
const slash = isWindows ? '\\' : '/';
|
|
||||||
|
|
||||||
return `${basePath}${slash}${paths.join(slash)}`;
|
|
||||||
}
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
export default function combinePath(
|
||||||
|
isWindows: boolean,
|
||||||
|
basePath: string,
|
||||||
|
paths: string[] = []
|
||||||
|
) {
|
||||||
|
const slash = isWindows ? '\\' : '/';
|
||||||
|
|
||||||
|
return `${basePath}${slash}${paths.join(slash)}`;
|
||||||
|
}
|
|
@ -1,6 +0,0 @@
|
||||||
export default function generateUUIDv4() {
|
|
||||||
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, (c) =>
|
|
||||||
// eslint-disable-next-line no-bitwise
|
|
||||||
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,3 +1,3 @@
|
||||||
export default function isString(possibleString) {
|
export default function isString(possibleString: unknown) {
|
||||||
return typeof possibleString === 'string' || possibleString instanceof String;
|
return typeof possibleString === 'string' || possibleString instanceof String;
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
const regex = /\d+/g;
|
const regex = /\d+/g;
|
||||||
|
|
||||||
function naturalExpansion(input) {
|
function naturalExpansion(input: string) {
|
||||||
if (!input) {
|
if (!input) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
|
@ -4,13 +4,13 @@ import qs from 'qs';
|
||||||
// See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils
|
// See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils
|
||||||
const anchor = document.createElement('a');
|
const anchor = document.createElement('a');
|
||||||
|
|
||||||
export default function parseUrl(url) {
|
export default function parseUrl(url: string) {
|
||||||
anchor.href = url;
|
anchor.href = url;
|
||||||
|
|
||||||
// The `origin`, `password`, and `username` properties are unavailable in
|
// The `origin`, `password`, and `username` properties are unavailable in
|
||||||
// Opera Presto. We synthesize `origin` if it's not present. While `password`
|
// Opera Presto. We synthesize `origin` if it's not present. While `password`
|
||||||
// and `username` are ignored intentionally.
|
// and `username` are ignored intentionally.
|
||||||
const properties = _.pick(
|
const properties: Record<string, string | number | boolean | object> = _.pick(
|
||||||
anchor,
|
anchor,
|
||||||
'hash',
|
'hash',
|
||||||
'host',
|
'host',
|
||||||
|
@ -23,11 +23,11 @@ export default function parseUrl(url) {
|
||||||
'search'
|
'search'
|
||||||
);
|
);
|
||||||
|
|
||||||
properties.isAbsolute = (/^[\w:]*\/\//).test(url);
|
properties.isAbsolute = /^[\w:]*\/\//.test(url);
|
||||||
|
|
||||||
if (properties.search) {
|
if (properties.search) {
|
||||||
// Remove leading ? from querystring before parsing.
|
// Remove leading ? from querystring before parsing.
|
||||||
properties.params = qs.parse(properties.search.substring(1));
|
properties.params = qs.parse((properties.search as string).substring(1));
|
||||||
} else {
|
} else {
|
||||||
properties.params = {};
|
properties.params = {};
|
||||||
}
|
}
|
|
@ -1,17 +0,0 @@
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
function split(input, separator = ',') {
|
|
||||||
if (!input) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return _.reduce(input.split(separator), (result, s) => {
|
|
||||||
if (s) {
|
|
||||||
result.push(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default split;
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
function split(input: string, separator = ',') {
|
||||||
|
if (!input) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return input.split(separator).reduce<string[]>((acc, s) => {
|
||||||
|
if (s) {
|
||||||
|
acc.push(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default split;
|
|
@ -1,6 +1,6 @@
|
||||||
const regex = /\b\w+/g;
|
const regex = /\b\w+/g;
|
||||||
|
|
||||||
function titleCase(input) {
|
function titleCase(input: string | undefined) {
|
||||||
if (!input) {
|
if (!input) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
|
@ -1,17 +0,0 @@
|
||||||
export default function areAllSelected(selectedState) {
|
|
||||||
let allSelected = true;
|
|
||||||
let allUnselected = true;
|
|
||||||
|
|
||||||
Object.keys(selectedState).forEach((key) => {
|
|
||||||
if (selectedState[key]) {
|
|
||||||
allUnselected = false;
|
|
||||||
} else {
|
|
||||||
allSelected = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
allSelected,
|
|
||||||
allUnselected
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { SelectedState } from 'Helpers/Hooks/useSelectState';
|
||||||
|
|
||||||
|
export default function areAllSelected(selectedState: SelectedState) {
|
||||||
|
let allSelected = true;
|
||||||
|
let allUnselected = true;
|
||||||
|
|
||||||
|
Object.values(selectedState).forEach((value) => {
|
||||||
|
if (value) {
|
||||||
|
allUnselected = false;
|
||||||
|
} else {
|
||||||
|
allSelected = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
allSelected,
|
||||||
|
allUnselected,
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,23 +0,0 @@
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
function getToggledRange(items, id, lastToggled) {
|
|
||||||
const lastToggledIndex = _.findIndex(items, { id: lastToggled });
|
|
||||||
const changedIndex = _.findIndex(items, { id });
|
|
||||||
let lower = 0;
|
|
||||||
let upper = 0;
|
|
||||||
|
|
||||||
if (lastToggledIndex > changedIndex) {
|
|
||||||
lower = changedIndex;
|
|
||||||
upper = lastToggledIndex + 1;
|
|
||||||
} else {
|
|
||||||
lower = lastToggledIndex;
|
|
||||||
upper = changedIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
lower,
|
|
||||||
upper
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default getToggledRange;
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import ModelBase from 'App/ModelBase';
|
||||||
|
|
||||||
|
function getToggledRange<T extends ModelBase>(
|
||||||
|
items: T[],
|
||||||
|
id: number,
|
||||||
|
lastToggled: number
|
||||||
|
) {
|
||||||
|
const lastToggledIndex = items.findIndex((item) => item.id === lastToggled);
|
||||||
|
const changedIndex = items.findIndex((item) => item.id === id);
|
||||||
|
let lower = 0;
|
||||||
|
let upper = 0;
|
||||||
|
|
||||||
|
if (lastToggledIndex > changedIndex) {
|
||||||
|
lower = changedIndex;
|
||||||
|
upper = lastToggledIndex + 1;
|
||||||
|
} else {
|
||||||
|
lower = lastToggledIndex;
|
||||||
|
upper = changedIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
lower,
|
||||||
|
upper,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getToggledRange;
|
|
@ -1,16 +0,0 @@
|
||||||
import areAllSelected from './areAllSelected';
|
|
||||||
|
|
||||||
export default function removeOldSelectedState(state, prevItems) {
|
|
||||||
const selectedState = {
|
|
||||||
...state.selectedState
|
|
||||||
};
|
|
||||||
|
|
||||||
prevItems.forEach((item) => {
|
|
||||||
delete selectedState[item.id];
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
...areAllSelected(selectedState),
|
|
||||||
selectedState
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import ModelBase from 'App/ModelBase';
|
||||||
|
import { SelectState } from 'Helpers/Hooks/useSelectState';
|
||||||
|
import areAllSelected from './areAllSelected';
|
||||||
|
|
||||||
|
export default function removeOldSelectedState<T extends ModelBase>(
|
||||||
|
state: SelectState,
|
||||||
|
prevItems: T[]
|
||||||
|
) {
|
||||||
|
const selectedState = {
|
||||||
|
...state.selectedState,
|
||||||
|
};
|
||||||
|
|
||||||
|
prevItems.forEach((item) => {
|
||||||
|
delete selectedState[item.id];
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...areAllSelected(selectedState),
|
||||||
|
selectedState,
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,17 +0,0 @@
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
function selectAll(selectedState, selected) {
|
|
||||||
const newSelectedState = _.reduce(Object.keys(selectedState), (result, item) => {
|
|
||||||
result[item] = selected;
|
|
||||||
return result;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
return {
|
|
||||||
allSelected: selected,
|
|
||||||
allUnselected: !selected,
|
|
||||||
lastToggled: null,
|
|
||||||
selectedState: newSelectedState
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default selectAll;
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { SelectedState } from 'Helpers/Hooks/useSelectState';
|
||||||
|
|
||||||
|
function selectAll(selectedState: SelectedState, selected: boolean) {
|
||||||
|
const newSelectedState = Object.keys(selectedState).reduce<
|
||||||
|
Record<number, boolean>
|
||||||
|
>((acc, item) => {
|
||||||
|
acc[Number(item)] = selected;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
return {
|
||||||
|
allSelected: selected,
|
||||||
|
allUnselected: !selected,
|
||||||
|
lastToggled: null,
|
||||||
|
selectedState: newSelectedState,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default selectAll;
|
|
@ -1,11 +1,19 @@
|
||||||
|
import ModelBase from 'App/ModelBase';
|
||||||
|
import { SelectState } from 'Helpers/Hooks/useSelectState';
|
||||||
import areAllSelected from './areAllSelected';
|
import areAllSelected from './areAllSelected';
|
||||||
import getToggledRange from './getToggledRange';
|
import getToggledRange from './getToggledRange';
|
||||||
|
|
||||||
function toggleSelected(selectedState, items, id, selected, shiftKey) {
|
function toggleSelected<T extends ModelBase>(
|
||||||
const lastToggled = selectedState.lastToggled;
|
selectState: SelectState,
|
||||||
|
items: T[],
|
||||||
|
id: number,
|
||||||
|
selected: boolean,
|
||||||
|
shiftKey: boolean
|
||||||
|
) {
|
||||||
|
const lastToggled = selectState.lastToggled;
|
||||||
const nextSelectedState = {
|
const nextSelectedState = {
|
||||||
...selectedState.selectedState,
|
...selectState.selectedState,
|
||||||
[id]: selected
|
[id]: selected,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (selected == null) {
|
if (selected == null) {
|
||||||
|
@ -23,7 +31,7 @@ function toggleSelected(selectedState, items, id, selected, shiftKey) {
|
||||||
return {
|
return {
|
||||||
...areAllSelected(nextSelectedState),
|
...areAllSelected(nextSelectedState),
|
||||||
lastToggled: id,
|
lastToggled: id,
|
||||||
selectedState: nextSelectedState
|
selectedState: nextSelectedState,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ import MobileDetect from 'mobile-detect';
|
||||||
const mobileDetect = new MobileDetect(window.navigator.userAgent);
|
const mobileDetect = new MobileDetect(window.navigator.userAgent);
|
||||||
|
|
||||||
export function isMobile() {
|
export function isMobile() {
|
||||||
|
|
||||||
return mobileDetect.mobile() != null;
|
return mobileDetect.mobile() != null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
export default function getPathWithUrlBase(path) {
|
|
||||||
return `${window.Sonarr.urlBase}${path}`;
|
|
||||||
}
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default function getPathWithUrlBase(path: string) {
|
||||||
|
return `${window.Sonarr.urlBase}${path}`;
|
||||||
|
}
|
|
@ -1,19 +1,24 @@
|
||||||
let currentPopulator = null;
|
type Populator = () => void;
|
||||||
let currentReasons = [];
|
|
||||||
|
|
||||||
export function registerPagePopulator(populator, reasons = []) {
|
let currentPopulator: Populator | null = null;
|
||||||
|
let currentReasons: string[] = [];
|
||||||
|
|
||||||
|
export function registerPagePopulator(
|
||||||
|
populator: Populator,
|
||||||
|
reasons: string[] = []
|
||||||
|
) {
|
||||||
currentPopulator = populator;
|
currentPopulator = populator;
|
||||||
currentReasons = reasons;
|
currentReasons = reasons;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function unregisterPagePopulator(populator) {
|
export function unregisterPagePopulator(populator: Populator) {
|
||||||
if (currentPopulator === populator) {
|
if (currentPopulator === populator) {
|
||||||
currentPopulator = null;
|
currentPopulator = null;
|
||||||
currentReasons = [];
|
currentReasons = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function repopulatePage(reason) {
|
export function repopulatePage(reason: string) {
|
||||||
if (!currentPopulator) {
|
if (!currentPopulator) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
|
@ -1,18 +1,17 @@
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import _ from 'lodash';
|
|
||||||
import createAjaxRequest from './createAjaxRequest';
|
import createAjaxRequest from './createAjaxRequest';
|
||||||
|
|
||||||
function flattenProviderData(providerData) {
|
function flattenProviderData(providerData) {
|
||||||
return _.reduce(Object.keys(providerData), (result, key) => {
|
return Object.keys(providerData).reduce((acc, key) => {
|
||||||
const property = providerData[key];
|
const property = providerData[key];
|
||||||
|
|
||||||
if (key === 'fields') {
|
if (key === 'fields') {
|
||||||
result[key] = property;
|
acc[key] = property;
|
||||||
} else {
|
} else {
|
||||||
result[key] = property.value;
|
acc[key] = property.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,6 @@ export function isLocked() {
|
||||||
return scrollLock;
|
return scrollLock;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setScrollLock(locked) {
|
export function setScrollLock(locked: boolean) {
|
||||||
scrollLock = locked;
|
scrollLock = locked;
|
||||||
}
|
}
|
|
@ -1,6 +0,0 @@
|
||||||
const sectionTypes = {
|
|
||||||
COLLECTION: 'collection',
|
|
||||||
MODEL: 'model'
|
|
||||||
};
|
|
||||||
|
|
||||||
export default sectionTypes;
|
|
|
@ -92,6 +92,7 @@
|
||||||
"@babel/preset-react": "7.24.1",
|
"@babel/preset-react": "7.24.1",
|
||||||
"@babel/preset-typescript": "7.24.1",
|
"@babel/preset-typescript": "7.24.1",
|
||||||
"@types/lodash": "4.14.194",
|
"@types/lodash": "4.14.194",
|
||||||
|
"@types/qs": "6.9.15",
|
||||||
"@types/react-lazyload": "3.2.0",
|
"@types/react-lazyload": "3.2.0",
|
||||||
"@types/react-router-dom": "5.3.3",
|
"@types/react-router-dom": "5.3.3",
|
||||||
"@types/react-text-truncate": "0.14.1",
|
"@types/react-text-truncate": "0.14.1",
|
||||||
|
|
|
@ -1458,6 +1458,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6"
|
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6"
|
||||||
integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==
|
integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==
|
||||||
|
|
||||||
|
"@types/qs@6.9.15":
|
||||||
|
version "6.9.15"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.15.tgz#adde8a060ec9c305a82de1babc1056e73bd64dce"
|
||||||
|
integrity sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==
|
||||||
|
|
||||||
"@types/react-dom@18.2.25":
|
"@types/react-dom@18.2.25":
|
||||||
version "18.2.25"
|
version "18.2.25"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.25.tgz#2946a30081f53e7c8d585eb138277245caedc521"
|
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.25.tgz#2946a30081f53e7c8d585eb138277245caedc521"
|
||||||
|
|
Loading…
Reference in New Issue