mirror of
https://github.com/Radarr/Radarr.git
synced 2025-04-24 22:47:05 -04:00
Improve typings in FormInputGroup
(cherry picked from commit 6838f068bcd04b770cd9c53873f160be97ea745f)
This commit is contained in:
parent
8fb2f64e98
commit
2c81f3be0f
43 changed files with 321 additions and 301 deletions
|
@ -110,7 +110,7 @@ class AddNewMovieModalContent extends Component {
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
|
||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.MOVIE_MONITORED_SELECT}
|
type={inputTypes.MONITOR_MOVIES_SELECT}
|
||||||
name="monitor"
|
name="monitor"
|
||||||
onChange={onInputChange}
|
onChange={onInputChange}
|
||||||
{...monitor}
|
{...monitor}
|
||||||
|
|
|
@ -117,7 +117,7 @@ class ImportMovieFooter extends Component {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.MOVIE_MONITORED_SELECT}
|
type={inputTypes.MONITOR_MOVIES_SELECT}
|
||||||
name="monitor"
|
name="monitor"
|
||||||
value={monitor}
|
value={monitor}
|
||||||
isDisabled={!selectedCount}
|
isDisabled={!selectedCount}
|
||||||
|
|
|
@ -44,7 +44,7 @@ function ImportMovieRow(props) {
|
||||||
|
|
||||||
<VirtualTableRowCell className={styles.monitor}>
|
<VirtualTableRowCell className={styles.monitor}>
|
||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.MOVIE_MONITORED_SELECT}
|
type={inputTypes.MONITOR_MOVIES_SELECT}
|
||||||
name="monitor"
|
name="monitor"
|
||||||
value={monitor}
|
value={monitor}
|
||||||
onChange={onInputChange}
|
onChange={onInputChange}
|
||||||
|
|
|
@ -107,7 +107,7 @@ class AddNewCollectionMovieModalContent extends Component {
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
|
||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.MOVIE_MONITORED_SELECT}
|
type={inputTypes.MONITOR_MOVIES_SELECT}
|
||||||
name="monitor"
|
name="monitor"
|
||||||
onChange={onInputChange}
|
onChange={onInputChange}
|
||||||
{...monitor}
|
{...monitor}
|
||||||
|
|
|
@ -7,8 +7,9 @@ import {
|
||||||
import { InputChanged } from 'typings/inputs';
|
import { InputChanged } from 'typings/inputs';
|
||||||
import AutoSuggestInput from './AutoSuggestInput';
|
import AutoSuggestInput from './AutoSuggestInput';
|
||||||
|
|
||||||
interface AutoCompleteInputProps {
|
export interface AutoCompleteInputProps {
|
||||||
name: string;
|
name: string;
|
||||||
|
readOnly?: boolean;
|
||||||
value?: string;
|
value?: string;
|
||||||
values: string[];
|
values: string[];
|
||||||
onChange: (change: InputChanged<string>) => unknown;
|
onChange: (change: InputChanged<string>) => unknown;
|
||||||
|
|
|
@ -16,7 +16,7 @@ import FormInputButton from './FormInputButton';
|
||||||
import TextInput from './TextInput';
|
import TextInput from './TextInput';
|
||||||
import styles from './CaptchaInput.css';
|
import styles from './CaptchaInput.css';
|
||||||
|
|
||||||
interface CaptchaInputProps {
|
export interface CaptchaInputProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
name: string;
|
name: string;
|
||||||
value?: string;
|
value?: string;
|
||||||
|
|
|
@ -41,10 +41,11 @@
|
||||||
.checkbox:focus + .input {
|
.checkbox:focus + .input {
|
||||||
outline: 0;
|
outline: 0;
|
||||||
border-color: var(--inputFocusBorderColor);
|
border-color: var(--inputFocusBorderColor);
|
||||||
box-shadow: inset 0 1px 1px var(--inputBoxShadowColor), 0 0 8px var(--inputFocusBoxShadowColor);
|
box-shadow: inset 0 1px 1px var(--inputBoxShadowColor),
|
||||||
|
0 0 8px var(--inputFocusBoxShadowColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dangerIsChecked {
|
.danger {
|
||||||
border-color: var(--dangerColor);
|
border-color: var(--dangerColor);
|
||||||
background-color: var(--dangerColor);
|
background-color: var(--dangerColor);
|
||||||
|
|
||||||
|
@ -53,7 +54,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.primaryIsChecked {
|
.primary {
|
||||||
border-color: var(--primaryColor);
|
border-color: var(--primaryColor);
|
||||||
background-color: var(--primaryColor);
|
background-color: var(--primaryColor);
|
||||||
|
|
||||||
|
@ -62,7 +63,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.successIsChecked {
|
.success {
|
||||||
border-color: var(--successColor);
|
border-color: var(--successColor);
|
||||||
background-color: var(--successColor);
|
background-color: var(--successColor);
|
||||||
|
|
||||||
|
@ -71,7 +72,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.warningIsChecked {
|
.warning {
|
||||||
border-color: var(--warningColor);
|
border-color: var(--warningColor);
|
||||||
background-color: var(--warningColor);
|
background-color: var(--warningColor);
|
||||||
|
|
||||||
|
|
|
@ -3,16 +3,16 @@
|
||||||
interface CssExports {
|
interface CssExports {
|
||||||
'checkbox': string;
|
'checkbox': string;
|
||||||
'container': string;
|
'container': string;
|
||||||
'dangerIsChecked': string;
|
'danger': string;
|
||||||
'helpText': string;
|
'helpText': string;
|
||||||
'input': string;
|
'input': string;
|
||||||
'isDisabled': string;
|
'isDisabled': string;
|
||||||
'isIndeterminate': string;
|
'isIndeterminate': string;
|
||||||
'isNotChecked': string;
|
'isNotChecked': string;
|
||||||
'label': string;
|
'label': string;
|
||||||
'primaryIsChecked': string;
|
'primary': string;
|
||||||
'successIsChecked': string;
|
'success': string;
|
||||||
'warningIsChecked': string;
|
'warning': string;
|
||||||
}
|
}
|
||||||
export const cssExports: CssExports;
|
export const cssExports: CssExports;
|
||||||
export default cssExports;
|
export default cssExports;
|
||||||
|
|
|
@ -11,7 +11,7 @@ interface ChangeEvent<T = Element> extends SyntheticEvent<T, MouseEvent> {
|
||||||
target: EventTarget & T;
|
target: EventTarget & T;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CheckInputProps {
|
export interface CheckInputProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
containerClassName?: string;
|
containerClassName?: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -45,7 +45,6 @@ function CheckInput(props: CheckInputProps) {
|
||||||
const isChecked = value === checkedValue;
|
const isChecked = value === checkedValue;
|
||||||
const isUnchecked = value === uncheckedValue;
|
const isUnchecked = value === uncheckedValue;
|
||||||
const isIndeterminate = !isChecked && !isUnchecked;
|
const isIndeterminate = !isChecked && !isUnchecked;
|
||||||
const isCheckClass: keyof typeof styles = `${kind}IsChecked`;
|
|
||||||
|
|
||||||
const toggleChecked = useCallback(
|
const toggleChecked = useCallback(
|
||||||
(checked: boolean, shiftKey: boolean) => {
|
(checked: boolean, shiftKey: boolean) => {
|
||||||
|
@ -112,7 +111,7 @@ function CheckInput(props: CheckInputProps) {
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
className,
|
className,
|
||||||
isChecked ? styles[isCheckClass] : styles.isNotChecked,
|
isChecked ? styles[kind] : styles.isNotChecked,
|
||||||
isIndeterminate && styles.isIndeterminate,
|
isIndeterminate && styles.isIndeterminate,
|
||||||
isDisabled && styles.isDisabled
|
isDisabled && styles.isDisabled
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,166 +1,197 @@
|
||||||
import React, { FocusEvent, ReactNode } from 'react';
|
import React, { ElementType, ReactNode } from 'react';
|
||||||
import Link from 'Components/Link/Link';
|
import Link from 'Components/Link/Link';
|
||||||
import { inputTypes } from 'Helpers/Props';
|
import { inputTypes } from 'Helpers/Props';
|
||||||
import { InputType } from 'Helpers/Props/inputTypes';
|
import { InputType } from 'Helpers/Props/inputTypes';
|
||||||
import { Kind } from 'Helpers/Props/kinds';
|
|
||||||
import { ValidationError, ValidationWarning } from 'typings/pending';
|
import { ValidationError, ValidationWarning } from 'typings/pending';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import AutoCompleteInput from './AutoCompleteInput';
|
import AutoCompleteInput, { AutoCompleteInputProps } from './AutoCompleteInput';
|
||||||
import CaptchaInput from './CaptchaInput';
|
import CaptchaInput, { CaptchaInputProps } from './CaptchaInput';
|
||||||
import CheckInput from './CheckInput';
|
import CheckInput, { CheckInputProps } from './CheckInput';
|
||||||
import { FormInputButtonProps } from './FormInputButton';
|
import { FormInputButtonProps } from './FormInputButton';
|
||||||
import FormInputHelpText from './FormInputHelpText';
|
import FormInputHelpText from './FormInputHelpText';
|
||||||
import KeyValueListInput from './KeyValueListInput';
|
import KeyValueListInput, { KeyValueListInputProps } from './KeyValueListInput';
|
||||||
import NumberInput from './NumberInput';
|
import NumberInput, { NumberInputProps } from './NumberInput';
|
||||||
import OAuthInput from './OAuthInput';
|
import OAuthInput, { OAuthInputProps } from './OAuthInput';
|
||||||
import PasswordInput from './PasswordInput';
|
import PasswordInput from './PasswordInput';
|
||||||
import PathInput from './PathInput';
|
import PathInput, { PathInputProps } from './PathInput';
|
||||||
import AvailabilitySelectInput from './Select/AvailabilitySelectInput';
|
import AvailabilitySelectInput, {
|
||||||
import DownloadClientSelectInput from './Select/DownloadClientSelectInput';
|
AvailabilitySelectInputProps,
|
||||||
import EnhancedSelectInput from './Select/EnhancedSelectInput';
|
} from './Select/AvailabilitySelectInput';
|
||||||
import IndexerFlagsSelectInput from './Select/IndexerFlagsSelectInput';
|
import DownloadClientSelectInput, {
|
||||||
import IndexerSelectInput from './Select/IndexerSelectInput';
|
DownloadClientSelectInputProps,
|
||||||
import LanguageSelectInput from './Select/LanguageSelectInput';
|
} from './Select/DownloadClientSelectInput';
|
||||||
import MonitorMoviesSelectInput from './Select/MonitorMoviesSelectInput';
|
import EnhancedSelectInput, {
|
||||||
import ProviderDataSelectInput from './Select/ProviderOptionSelectInput';
|
EnhancedSelectInputProps,
|
||||||
import QualityProfileSelectInput from './Select/QualityProfileSelectInput';
|
} from './Select/EnhancedSelectInput';
|
||||||
import RootFolderSelectInput from './Select/RootFolderSelectInput';
|
import IndexerFlagsSelectInput, {
|
||||||
import UMaskInput from './Select/UMaskInput';
|
IndexerFlagsSelectInputProps,
|
||||||
import DeviceInput from './Tag/DeviceInput';
|
} from './Select/IndexerFlagsSelectInput';
|
||||||
import MovieTagInput from './Tag/MovieTagInput';
|
import IndexerSelectInput, {
|
||||||
import TagSelectInput from './Tag/TagSelectInput';
|
IndexerSelectInputProps,
|
||||||
import TextTagInput from './Tag/TextTagInput';
|
} from './Select/IndexerSelectInput';
|
||||||
import TextArea from './TextArea';
|
import LanguageSelectInput, {
|
||||||
import TextInput from './TextInput';
|
LanguageSelectInputProps,
|
||||||
|
} from './Select/LanguageSelectInput';
|
||||||
|
import MonitorMoviesSelectInput, {
|
||||||
|
MonitorMoviesSelectInputProps,
|
||||||
|
} from './Select/MonitorMoviesSelectInput';
|
||||||
|
import ProviderDataSelectInput, {
|
||||||
|
ProviderOptionSelectInputProps,
|
||||||
|
} from './Select/ProviderOptionSelectInput';
|
||||||
|
import QualityProfileSelectInput, {
|
||||||
|
QualityProfileSelectInputProps,
|
||||||
|
} from './Select/QualityProfileSelectInput';
|
||||||
|
import RootFolderSelectInput, {
|
||||||
|
RootFolderSelectInputProps,
|
||||||
|
} from './Select/RootFolderSelectInput';
|
||||||
|
import UMaskInput, { UMaskInputProps } from './Select/UMaskInput';
|
||||||
|
import DeviceInput, { DeviceInputProps } from './Tag/DeviceInput';
|
||||||
|
import MovieTagInput, { MovieTagInputProps } from './Tag/MovieTagInput';
|
||||||
|
import TagSelectInput, { TagSelectInputProps } from './Tag/TagSelectInput';
|
||||||
|
import TextTagInput, { TextTagInputProps } from './Tag/TextTagInput';
|
||||||
|
import TextArea, { TextAreaProps } from './TextArea';
|
||||||
|
import TextInput, { TextInputProps } from './TextInput';
|
||||||
import styles from './FormInputGroup.css';
|
import styles from './FormInputGroup.css';
|
||||||
|
|
||||||
function getComponent(type: InputType) {
|
const componentMap: Record<InputType, ElementType> = {
|
||||||
switch (type) {
|
autoComplete: AutoCompleteInput,
|
||||||
case inputTypes.AUTO_COMPLETE:
|
availabilitySelect: AvailabilitySelectInput,
|
||||||
return AutoCompleteInput;
|
captcha: CaptchaInput,
|
||||||
|
check: CheckInput,
|
||||||
|
date: TextInput,
|
||||||
|
device: DeviceInput,
|
||||||
|
downloadClientSelect: DownloadClientSelectInput,
|
||||||
|
dynamicSelect: ProviderDataSelectInput,
|
||||||
|
file: TextInput,
|
||||||
|
float: NumberInput,
|
||||||
|
indexerFlagsSelect: IndexerFlagsSelectInput,
|
||||||
|
indexerSelect: IndexerSelectInput,
|
||||||
|
keyValueList: KeyValueListInput,
|
||||||
|
languageSelect: LanguageSelectInput,
|
||||||
|
monitorMoviesSelect: MonitorMoviesSelectInput,
|
||||||
|
movieTag: MovieTagInput,
|
||||||
|
number: NumberInput,
|
||||||
|
oauth: OAuthInput,
|
||||||
|
password: PasswordInput,
|
||||||
|
path: PathInput,
|
||||||
|
qualityProfileSelect: QualityProfileSelectInput,
|
||||||
|
rootFolderSelect: RootFolderSelectInput,
|
||||||
|
select: EnhancedSelectInput,
|
||||||
|
tag: MovieTagInput,
|
||||||
|
tagSelect: TagSelectInput,
|
||||||
|
text: TextInput,
|
||||||
|
textArea: TextArea,
|
||||||
|
textTag: TextTagInput,
|
||||||
|
umask: UMaskInput,
|
||||||
|
} as const;
|
||||||
|
|
||||||
case inputTypes.AVAILABILITY_SELECT:
|
// type Components = typeof componentMap;
|
||||||
return AvailabilitySelectInput;
|
|
||||||
|
|
||||||
case inputTypes.CAPTCHA:
|
type PickProps<V, C extends InputType> = C extends 'text'
|
||||||
return CaptchaInput;
|
? TextInputProps
|
||||||
|
: C extends 'autoComplete'
|
||||||
|
? AutoCompleteInputProps
|
||||||
|
: C extends 'availabilitySelect'
|
||||||
|
? AvailabilitySelectInputProps
|
||||||
|
: C extends 'captcha'
|
||||||
|
? CaptchaInputProps
|
||||||
|
: C extends 'check'
|
||||||
|
? CheckInputProps
|
||||||
|
: C extends 'date'
|
||||||
|
? TextInputProps
|
||||||
|
: C extends 'device'
|
||||||
|
? DeviceInputProps
|
||||||
|
: C extends 'downloadClientSelect'
|
||||||
|
? DownloadClientSelectInputProps
|
||||||
|
: C extends 'dynamicSelect'
|
||||||
|
? ProviderOptionSelectInputProps
|
||||||
|
: C extends 'file'
|
||||||
|
? TextInputProps
|
||||||
|
: C extends 'float'
|
||||||
|
? TextInputProps
|
||||||
|
: C extends 'indexerFlagsSelect'
|
||||||
|
? IndexerFlagsSelectInputProps
|
||||||
|
: C extends 'indexerSelect'
|
||||||
|
? IndexerSelectInputProps
|
||||||
|
: C extends 'keyValueList'
|
||||||
|
? KeyValueListInputProps
|
||||||
|
: C extends 'languageSelect'
|
||||||
|
? LanguageSelectInputProps
|
||||||
|
: C extends 'monitorMoviesSelect'
|
||||||
|
? MonitorMoviesSelectInputProps
|
||||||
|
: C extends 'movieTag'
|
||||||
|
? MovieTagInputProps
|
||||||
|
: C extends 'number'
|
||||||
|
? NumberInputProps
|
||||||
|
: C extends 'oauth'
|
||||||
|
? OAuthInputProps
|
||||||
|
: C extends 'password'
|
||||||
|
? TextInputProps
|
||||||
|
: C extends 'path'
|
||||||
|
? PathInputProps
|
||||||
|
: C extends 'qualityProfileSelect'
|
||||||
|
? QualityProfileSelectInputProps
|
||||||
|
: C extends 'rootFolderSelect'
|
||||||
|
? RootFolderSelectInputProps
|
||||||
|
: C extends 'select'
|
||||||
|
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
EnhancedSelectInputProps<any, V>
|
||||||
|
: C extends 'tag'
|
||||||
|
? MovieTagInputProps
|
||||||
|
: C extends 'tagSelect'
|
||||||
|
? TagSelectInputProps
|
||||||
|
: C extends 'text'
|
||||||
|
? TextInputProps
|
||||||
|
: C extends 'textArea'
|
||||||
|
? TextAreaProps
|
||||||
|
: C extends 'textTag'
|
||||||
|
? TextTagInputProps
|
||||||
|
: C extends 'umask'
|
||||||
|
? UMaskInputProps
|
||||||
|
: never;
|
||||||
|
|
||||||
case inputTypes.CHECK:
|
export interface FormInputGroupValues<T> {
|
||||||
return CheckInput;
|
key: T;
|
||||||
|
value: string;
|
||||||
case inputTypes.DEVICE:
|
hint?: string;
|
||||||
return DeviceInput;
|
|
||||||
|
|
||||||
case inputTypes.KEY_VALUE_LIST:
|
|
||||||
return KeyValueListInput;
|
|
||||||
|
|
||||||
case inputTypes.LANGUAGE_SELECT:
|
|
||||||
return LanguageSelectInput;
|
|
||||||
|
|
||||||
case inputTypes.MOVIE_MONITORED_SELECT:
|
|
||||||
return MonitorMoviesSelectInput;
|
|
||||||
|
|
||||||
case inputTypes.NUMBER:
|
|
||||||
return NumberInput;
|
|
||||||
|
|
||||||
case inputTypes.OAUTH:
|
|
||||||
return OAuthInput;
|
|
||||||
|
|
||||||
case inputTypes.PASSWORD:
|
|
||||||
return PasswordInput;
|
|
||||||
|
|
||||||
case inputTypes.PATH:
|
|
||||||
return PathInput;
|
|
||||||
|
|
||||||
case inputTypes.QUALITY_PROFILE_SELECT:
|
|
||||||
return QualityProfileSelectInput;
|
|
||||||
|
|
||||||
case inputTypes.INDEXER_SELECT:
|
|
||||||
return IndexerSelectInput;
|
|
||||||
|
|
||||||
case inputTypes.INDEXER_FLAGS_SELECT:
|
|
||||||
return IndexerFlagsSelectInput;
|
|
||||||
|
|
||||||
case inputTypes.DOWNLOAD_CLIENT_SELECT:
|
|
||||||
return DownloadClientSelectInput;
|
|
||||||
|
|
||||||
case inputTypes.ROOT_FOLDER_SELECT:
|
|
||||||
return RootFolderSelectInput;
|
|
||||||
|
|
||||||
case inputTypes.SELECT:
|
|
||||||
return EnhancedSelectInput;
|
|
||||||
|
|
||||||
case inputTypes.DYNAMIC_SELECT:
|
|
||||||
return ProviderDataSelectInput;
|
|
||||||
|
|
||||||
case inputTypes.TAG:
|
|
||||||
case inputTypes.MOVIE_TAG:
|
|
||||||
return MovieTagInput;
|
|
||||||
|
|
||||||
case inputTypes.TEXT_AREA:
|
|
||||||
return TextArea;
|
|
||||||
|
|
||||||
case inputTypes.TEXT_TAG:
|
|
||||||
return TextTagInput;
|
|
||||||
|
|
||||||
case inputTypes.TAG_SELECT:
|
|
||||||
return TagSelectInput;
|
|
||||||
|
|
||||||
case inputTypes.UMASK:
|
|
||||||
return UMaskInput;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return TextInput;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove once all parent components are updated to TSX and we can refactor to a consistent type
|
// TODO: Remove once all parent components are updated to TSX and we can refactor to a consistent type
|
||||||
interface ValidationMessage {
|
export interface ValidationMessage {
|
||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FormInputGroupProps<T> {
|
export type FormInputGroupProps<V, C extends InputType> = Omit<
|
||||||
|
PickProps<V, C>,
|
||||||
|
'className'
|
||||||
|
> & {
|
||||||
|
type: C;
|
||||||
className?: string;
|
className?: string;
|
||||||
containerClassName?: string;
|
containerClassName?: string;
|
||||||
inputClassName?: string;
|
inputClassName?: string;
|
||||||
|
autoFocus?: boolean;
|
||||||
|
autocomplete?: string;
|
||||||
name: string;
|
name: string;
|
||||||
value?: unknown;
|
|
||||||
values?: unknown[];
|
|
||||||
isDisabled?: boolean;
|
|
||||||
type?: InputType;
|
|
||||||
kind?: Kind;
|
|
||||||
min?: number;
|
|
||||||
max?: number;
|
|
||||||
unit?: string;
|
|
||||||
buttons?: ReactNode | ReactNode[];
|
buttons?: ReactNode | ReactNode[];
|
||||||
helpText?: string;
|
helpText?: string;
|
||||||
helpTexts?: string[];
|
helpTexts?: string[];
|
||||||
helpTextWarning?: string;
|
helpTextWarning?: string;
|
||||||
helpLink?: string;
|
helpLink?: string;
|
||||||
placeholder?: string;
|
|
||||||
autoFocus?: boolean;
|
|
||||||
includeNoChange?: boolean;
|
|
||||||
includeNoChangeDisabled?: boolean;
|
|
||||||
valueOptions?: object;
|
|
||||||
selectedValueOptions?: object;
|
|
||||||
indexerFlags?: number;
|
|
||||||
pending?: boolean;
|
pending?: boolean;
|
||||||
canEdit?: boolean;
|
placeholder?: string;
|
||||||
includeAny?: boolean;
|
unit?: string;
|
||||||
delimiters?: string[];
|
|
||||||
readOnly?: boolean;
|
|
||||||
errors?: (ValidationMessage | ValidationError)[];
|
errors?: (ValidationMessage | ValidationError)[];
|
||||||
warnings?: (ValidationMessage | ValidationWarning)[];
|
warnings?: (ValidationMessage | ValidationWarning)[];
|
||||||
onChange: (args: T) => void;
|
};
|
||||||
onFocus?: (event: FocusEvent<HTMLInputElement>) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
function FormInputGroup<T>(props: FormInputGroupProps<T>) {
|
function FormInputGroup<T, C extends InputType>(
|
||||||
|
props: FormInputGroupProps<T, C>
|
||||||
|
) {
|
||||||
const {
|
const {
|
||||||
className = styles.inputGroup,
|
className = styles.inputGroup,
|
||||||
containerClassName = styles.inputGroupContainer,
|
containerClassName = styles.inputGroupContainer,
|
||||||
inputClassName,
|
inputClassName,
|
||||||
type = 'text',
|
type,
|
||||||
unit,
|
unit,
|
||||||
buttons = [],
|
buttons = [],
|
||||||
helpText,
|
helpText,
|
||||||
|
@ -173,7 +204,7 @@ function FormInputGroup<T>(props: FormInputGroupProps<T>) {
|
||||||
...otherProps
|
...otherProps
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const InputComponent = getComponent(type);
|
const InputComponent = componentMap[type];
|
||||||
const checkInput = type === inputTypes.CHECK;
|
const checkInput = type === inputTypes.CHECK;
|
||||||
const hasError = !!errors.length;
|
const hasError = !!errors.length;
|
||||||
const hasWarning = !hasError && !!warnings.length;
|
const hasWarning = !hasError && !!warnings.length;
|
||||||
|
@ -185,7 +216,7 @@ function FormInputGroup<T>(props: FormInputGroupProps<T>) {
|
||||||
<div className={containerClassName}>
|
<div className={containerClassName}>
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<div className={styles.inputContainer}>
|
<div className={styles.inputContainer}>
|
||||||
{/* @ts-expect-error - need to pass through all the expected options */}
|
{/* @ts-expect-error - types are validated already */}
|
||||||
<InputComponent
|
<InputComponent
|
||||||
className={inputClassName}
|
className={inputClassName}
|
||||||
helpText={helpText}
|
helpText={helpText}
|
||||||
|
|
|
@ -24,12 +24,13 @@ function parseValue(
|
||||||
return newValue;
|
return newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NumberInputProps
|
export interface NumberInputProps
|
||||||
extends Omit<TextInputProps<number | null>, 'value'> {
|
extends Omit<TextInputProps, 'value' | 'onChange'> {
|
||||||
value?: number | null;
|
value?: number | null;
|
||||||
min?: number;
|
min?: number;
|
||||||
max?: number;
|
max?: number;
|
||||||
isFloat?: boolean;
|
isFloat?: boolean;
|
||||||
|
onChange: (input: InputChanged<number | null>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function NumberInput({
|
function NumberInput({
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { kinds } from 'Helpers/Props';
|
||||||
import { resetOAuth, startOAuth } from 'Store/Actions/oAuthActions';
|
import { resetOAuth, startOAuth } from 'Store/Actions/oAuthActions';
|
||||||
import { InputOnChange } from 'typings/inputs';
|
import { InputOnChange } from 'typings/inputs';
|
||||||
|
|
||||||
interface OAuthInputProps {
|
export interface OAuthInputProps {
|
||||||
label?: string;
|
label?: string;
|
||||||
name: string;
|
name: string;
|
||||||
provider: string;
|
provider: string;
|
||||||
|
|
|
@ -7,7 +7,7 @@ function onCopy(e: SyntheticEvent) {
|
||||||
e.nativeEvent.stopImmediatePropagation();
|
e.nativeEvent.stopImmediatePropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
function PasswordInput(props: TextInputProps<string>) {
|
function PasswordInput(props: TextInputProps) {
|
||||||
return <TextInput {...props} type="password" onCopy={onCopy} />;
|
return <TextInput {...props} type="password" onCopy={onCopy} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ import AutoSuggestInput from './AutoSuggestInput';
|
||||||
import FormInputButton from './FormInputButton';
|
import FormInputButton from './FormInputButton';
|
||||||
import styles from './PathInput.css';
|
import styles from './PathInput.css';
|
||||||
|
|
||||||
interface PathInputProps {
|
export interface PathInputProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
name: string;
|
name: string;
|
||||||
value?: string;
|
value?: string;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import EnhancedSelectInput, {
|
||||||
EnhancedSelectInputValue,
|
EnhancedSelectInputValue,
|
||||||
} from './EnhancedSelectInput';
|
} from './EnhancedSelectInput';
|
||||||
|
|
||||||
interface AvailabilitySelectInputProps
|
export interface AvailabilitySelectInputProps
|
||||||
extends Omit<
|
extends Omit<
|
||||||
EnhancedSelectInputProps<EnhancedSelectInputValue<string>, string>,
|
EnhancedSelectInputProps<EnhancedSelectInputValue<string>, string>,
|
||||||
'values'
|
'values'
|
||||||
|
|
|
@ -51,7 +51,7 @@ function createDownloadClientsSelector(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DownloadClientSelectInputProps
|
export interface DownloadClientSelectInputProps
|
||||||
extends Omit<
|
extends Omit<
|
||||||
EnhancedSelectInputProps<EnhancedSelectInputValue<number>, number>,
|
EnhancedSelectInputProps<EnhancedSelectInputValue<number>, number>,
|
||||||
'values'
|
'values'
|
||||||
|
|
|
@ -30,7 +30,7 @@ const selectIndexerFlagsValues = (selectedFlags: number) =>
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
interface IndexerFlagsSelectInputProps {
|
export interface IndexerFlagsSelectInputProps {
|
||||||
name: string;
|
name: string;
|
||||||
indexerFlags: number;
|
indexerFlags: number;
|
||||||
onChange(payload: EnhancedSelectInputChanged<number>): void;
|
onChange(payload: EnhancedSelectInputChanged<number>): void;
|
||||||
|
|
|
@ -38,7 +38,7 @@ function createIndexersSelector(includeAny: boolean) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IndexerSelectInputProps {
|
export interface IndexerSelectInputProps {
|
||||||
name: string;
|
name: string;
|
||||||
value: number;
|
value: number;
|
||||||
includeAny?: boolean;
|
includeAny?: boolean;
|
||||||
|
|
|
@ -4,7 +4,7 @@ import EnhancedSelectInput, {
|
||||||
EnhancedSelectInputValue,
|
EnhancedSelectInputValue,
|
||||||
} from './EnhancedSelectInput';
|
} from './EnhancedSelectInput';
|
||||||
|
|
||||||
interface LanguageSelectInputProps {
|
export interface LanguageSelectInputProps {
|
||||||
name: string;
|
name: string;
|
||||||
value: number;
|
value: number;
|
||||||
values: EnhancedSelectInputValue<number>[];
|
values: EnhancedSelectInputValue<number>[];
|
||||||
|
|
|
@ -6,7 +6,7 @@ import EnhancedSelectInput, {
|
||||||
EnhancedSelectInputValue,
|
EnhancedSelectInputValue,
|
||||||
} from './EnhancedSelectInput';
|
} from './EnhancedSelectInput';
|
||||||
|
|
||||||
interface MonitorMoviesSelectInputProps
|
export interface MonitorMoviesSelectInputProps
|
||||||
extends Omit<
|
extends Omit<
|
||||||
EnhancedSelectInputProps<EnhancedSelectInputValue<string>, string>,
|
EnhancedSelectInputProps<EnhancedSelectInputValue<string>, string>,
|
||||||
'values'
|
'values'
|
||||||
|
|
|
@ -69,7 +69,7 @@ function createProviderOptionsSelector(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ProviderOptionSelectInputProps
|
export interface ProviderOptionSelectInputProps
|
||||||
extends Omit<
|
extends Omit<
|
||||||
EnhancedSelectInputProps<EnhancedSelectInputValue<unknown>, unknown>,
|
EnhancedSelectInputProps<EnhancedSelectInputValue<unknown>, unknown>,
|
||||||
'values'
|
'values'
|
||||||
|
|
|
@ -56,7 +56,7 @@ function createQualityProfilesSelector(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface QualityProfileSelectInputProps
|
export interface QualityProfileSelectInputProps
|
||||||
extends Omit<
|
extends Omit<
|
||||||
EnhancedSelectInputProps<
|
EnhancedSelectInputProps<
|
||||||
EnhancedSelectInputValue<number | string>,
|
EnhancedSelectInputValue<number | string>,
|
||||||
|
|
|
@ -24,7 +24,7 @@ export interface RootFolderSelectInputValue
|
||||||
isMissing?: boolean;
|
isMissing?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RootFolderSelectInputProps
|
export interface RootFolderSelectInputProps
|
||||||
extends Omit<
|
extends Omit<
|
||||||
EnhancedSelectInputProps<EnhancedSelectInputValue<string>, string>,
|
EnhancedSelectInputProps<EnhancedSelectInputValue<string>, string>,
|
||||||
'value' | 'values'
|
'value' | 'values'
|
||||||
|
|
|
@ -66,7 +66,7 @@ function formatPermissions(permissions: number) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UMaskInputProps {
|
export interface UMaskInputProps {
|
||||||
name: string;
|
name: string;
|
||||||
value: string;
|
value: string;
|
||||||
hasError?: boolean;
|
hasError?: boolean;
|
||||||
|
|
|
@ -19,7 +19,7 @@ interface DeviceTag {
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DeviceInputProps extends TagInputProps<DeviceTag> {
|
export interface DeviceInputProps extends TagInputProps<DeviceTag> {
|
||||||
className?: string;
|
className?: string;
|
||||||
name: string;
|
name: string;
|
||||||
value: string[];
|
value: string[];
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { addTag } from 'Store/Actions/tagActions';
|
import { addTag } from 'Store/Actions/tagActions';
|
||||||
|
@ -12,10 +12,10 @@ interface MovieTag extends TagBase {
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MovieTagInputProps {
|
export interface MovieTagInputProps {
|
||||||
name: string;
|
name: string;
|
||||||
value: number | number[];
|
value: number[];
|
||||||
onChange: (change: InputChanged<number | number[]>) => void;
|
onChange: (change: InputChanged<number[]>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const VALID_TAG_REGEX = new RegExp('[^-_a-z0-9]', 'i');
|
const VALID_TAG_REGEX = new RegExp('[^-_a-z0-9]', 'i');
|
||||||
|
@ -65,42 +65,22 @@ export default function MovieTagInput({
|
||||||
onChange,
|
onChange,
|
||||||
}: MovieTagInputProps) {
|
}: MovieTagInputProps) {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const isArray = Array.isArray(value);
|
|
||||||
|
|
||||||
const arrayValue = useMemo(() => {
|
|
||||||
if (isArray) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value === 0 ? [] : [value];
|
|
||||||
}, [isArray, value]);
|
|
||||||
|
|
||||||
const { tags, tagList, allTags } = useSelector(
|
const { tags, tagList, allTags } = useSelector(
|
||||||
createMovieTagsSelector(arrayValue)
|
createMovieTagsSelector(value)
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleTagCreated = useCallback(
|
const handleTagCreated = useCallback(
|
||||||
(tag: MovieTag) => {
|
(tag: MovieTag) => {
|
||||||
if (isArray) {
|
onChange({ name, value: [...value, tag.id] });
|
||||||
onChange({ name, value: [...value, tag.id] });
|
|
||||||
} else {
|
|
||||||
onChange({
|
|
||||||
name,
|
|
||||||
value: tag.id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[name, value, isArray, onChange]
|
[name, value, onChange]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleTagAdd = useCallback(
|
const handleTagAdd = useCallback(
|
||||||
(newTag: MovieTag) => {
|
(newTag: MovieTag) => {
|
||||||
if (newTag.id) {
|
if (newTag.id) {
|
||||||
if (isArray) {
|
onChange({ name, value: [...value, newTag.id] });
|
||||||
onChange({ name, value: [...value, newTag.id] });
|
|
||||||
} else {
|
|
||||||
onChange({ name, value: newTag.id });
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -116,21 +96,17 @@ export default function MovieTagInput({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[name, value, isArray, allTags, handleTagCreated, onChange, dispatch]
|
[name, value, allTags, handleTagCreated, onChange, dispatch]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleTagDelete = useCallback(
|
const handleTagDelete = useCallback(
|
||||||
({ index }: { index: number }) => {
|
({ index }: { index: number }) => {
|
||||||
if (isArray) {
|
const newValue = value.slice();
|
||||||
const newValue = value.slice();
|
newValue.splice(index, 1);
|
||||||
newValue.splice(index, 1);
|
|
||||||
|
|
||||||
onChange({ name, value: newValue });
|
onChange({ name, value: newValue });
|
||||||
} else {
|
|
||||||
onChange({ name, value: 0 });
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[name, value, isArray, onChange]
|
[name, value, onChange]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -13,7 +13,7 @@ interface TagSelectValue {
|
||||||
order: number;
|
order: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TagSelectInputProps extends TagInputProps<SelectTag> {
|
export interface TagSelectInputProps extends TagInputProps<SelectTag> {
|
||||||
name: string;
|
name: string;
|
||||||
value: number[];
|
value: number[];
|
||||||
values: TagSelectValue[];
|
values: TagSelectValue[];
|
||||||
|
|
|
@ -8,7 +8,11 @@ interface TextTag extends TagBase {
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TextTagInputProps extends TagInputProps<TextTag> {
|
export interface TextTagInputProps
|
||||||
|
extends Omit<
|
||||||
|
TagInputProps<TextTag>,
|
||||||
|
'tags' | 'tagList' | 'onTagAdd' | 'onTagDelete'
|
||||||
|
> {
|
||||||
name: string;
|
name: string;
|
||||||
value: string | string[];
|
value: string | string[];
|
||||||
onChange: (change: InputChanged<string[]>) => unknown;
|
onChange: (change: InputChanged<string[]>) => unknown;
|
||||||
|
|
|
@ -9,7 +9,7 @@ import React, {
|
||||||
import { InputChanged } from 'typings/inputs';
|
import { InputChanged } from 'typings/inputs';
|
||||||
import styles from './TextArea.css';
|
import styles from './TextArea.css';
|
||||||
|
|
||||||
interface TextAreaProps {
|
export interface TextAreaProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
autoFocus?: boolean;
|
autoFocus?: boolean;
|
||||||
|
|
|
@ -7,13 +7,11 @@ import React, {
|
||||||
useEffect,
|
useEffect,
|
||||||
useRef,
|
useRef,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { InputType } from 'Helpers/Props/inputTypes';
|
|
||||||
import { FileInputChanged, InputChanged } from 'typings/inputs';
|
import { FileInputChanged, InputChanged } from 'typings/inputs';
|
||||||
import styles from './TextInput.css';
|
import styles from './TextInput.css';
|
||||||
|
|
||||||
export interface TextInputProps<T> {
|
export interface CommonTextInputProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
type?: InputType;
|
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
autoFocus?: boolean;
|
autoFocus?: boolean;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
@ -25,14 +23,23 @@ export interface TextInputProps<T> {
|
||||||
step?: number;
|
step?: number;
|
||||||
min?: number;
|
min?: number;
|
||||||
max?: number;
|
max?: number;
|
||||||
onChange: (change: InputChanged<T> | FileInputChanged) => void;
|
onFocus?: (event: FocusEvent<HTMLInputElement, Element>) => void;
|
||||||
onFocus?: (event: FocusEvent) => void;
|
|
||||||
onBlur?: (event: SyntheticEvent) => void;
|
onBlur?: (event: SyntheticEvent) => void;
|
||||||
onCopy?: (event: SyntheticEvent) => void;
|
onCopy?: (event: SyntheticEvent) => void;
|
||||||
onSelectionChange?: (start: number | null, end: number | null) => void;
|
onSelectionChange?: (start: number | null, end: number | null) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function TextInput<T>({
|
export interface TextInputProps extends CommonTextInputProps {
|
||||||
|
type?: 'date' | 'number' | 'password' | 'text';
|
||||||
|
onChange: (change: InputChanged<string>) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileInputProps extends CommonTextInputProps {
|
||||||
|
type: 'file';
|
||||||
|
onChange: (change: FileInputChanged) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function TextInput({
|
||||||
className = styles.input,
|
className = styles.input,
|
||||||
type = 'text',
|
type = 'text',
|
||||||
readOnly = false,
|
readOnly = false,
|
||||||
|
@ -51,7 +58,7 @@ function TextInput<T>({
|
||||||
onCopy,
|
onCopy,
|
||||||
onChange,
|
onChange,
|
||||||
onSelectionChange,
|
onSelectionChange,
|
||||||
}: TextInputProps<T>) {
|
}: TextInputProps | FileInputProps): JSX.Element {
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
const selectionTimeout = useRef<ReturnType<typeof setTimeout>>();
|
const selectionTimeout = useRef<ReturnType<typeof setTimeout>>();
|
||||||
const selectionStart = useRef<number | null>();
|
const selectionStart = useRef<number | null>();
|
||||||
|
@ -95,7 +102,7 @@ function TextInput<T>({
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleFocus = useCallback(
|
const handleFocus = useCallback(
|
||||||
(event: FocusEvent) => {
|
(event: FocusEvent<HTMLInputElement, Element>) => {
|
||||||
onFocus?.(event);
|
onFocus?.(event);
|
||||||
|
|
||||||
selectionChanged();
|
selectionChanged();
|
||||||
|
|
|
@ -4,7 +4,7 @@ export const CAPTCHA = 'captcha';
|
||||||
export const CHECK = 'check';
|
export const CHECK = 'check';
|
||||||
export const DEVICE = 'device';
|
export const DEVICE = 'device';
|
||||||
export const KEY_VALUE_LIST = 'keyValueList';
|
export const KEY_VALUE_LIST = 'keyValueList';
|
||||||
export const MOVIE_MONITORED_SELECT = 'movieMonitoredSelect';
|
export const MONITOR_MOVIES_SELECT = 'monitorMoviesSelect';
|
||||||
export const FLOAT = 'float';
|
export const FLOAT = 'float';
|
||||||
export const NUMBER = 'number';
|
export const NUMBER = 'number';
|
||||||
export const OAUTH = 'oauth';
|
export const OAUTH = 'oauth';
|
||||||
|
@ -33,7 +33,7 @@ export const all = [
|
||||||
CHECK,
|
CHECK,
|
||||||
DEVICE,
|
DEVICE,
|
||||||
KEY_VALUE_LIST,
|
KEY_VALUE_LIST,
|
||||||
MOVIE_MONITORED_SELECT,
|
MONITOR_MOVIES_SELECT,
|
||||||
FLOAT,
|
FLOAT,
|
||||||
NUMBER,
|
NUMBER,
|
||||||
OAUTH,
|
OAUTH,
|
||||||
|
@ -61,9 +61,10 @@ export type InputType =
|
||||||
| 'availabilitySelect'
|
| 'availabilitySelect'
|
||||||
| 'captcha'
|
| 'captcha'
|
||||||
| 'check'
|
| 'check'
|
||||||
|
| 'date'
|
||||||
| 'device'
|
| 'device'
|
||||||
| 'keyValueList'
|
| 'keyValueList'
|
||||||
| 'movieMonitoredSelect'
|
| 'monitorMoviesSelect'
|
||||||
| 'file'
|
| 'file'
|
||||||
| 'float'
|
| 'float'
|
||||||
| 'number'
|
| 'number'
|
||||||
|
|
|
@ -86,8 +86,8 @@ function SelectQualityModalContent(props: SelectQualityModalContentProps) {
|
||||||
}, [items]);
|
}, [items]);
|
||||||
|
|
||||||
const onQualityChange = useCallback(
|
const onQualityChange = useCallback(
|
||||||
({ value }: { value: string }) => {
|
({ value }: { value: number }) => {
|
||||||
setQualityId(parseInt(value));
|
setQualityId(value);
|
||||||
},
|
},
|
||||||
[setQualityId]
|
[setQualityId]
|
||||||
);
|
);
|
||||||
|
@ -128,7 +128,7 @@ function SelectQualityModalContent(props: SelectQualityModalContentProps) {
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
|
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
{isFetching && <LoadingIndicator />}
|
{isFetching ? <LoadingIndicator /> : null}
|
||||||
|
|
||||||
{!isFetching && error ? (
|
{!isFetching && error ? (
|
||||||
<Alert kind={kinds.DANGER}>{translate('QualitiesLoadError')}</Alert>
|
<Alert kind={kinds.DANGER}>{translate('QualitiesLoadError')}</Alert>
|
||||||
|
|
|
@ -183,6 +183,7 @@ function EditMovieModalContent({
|
||||||
type={inputTypes.PATH}
|
type={inputTypes.PATH}
|
||||||
name="path"
|
name="path"
|
||||||
{...settings.path}
|
{...settings.path}
|
||||||
|
includeFiles={false}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
|
@ -141,7 +141,7 @@ function DeleteMovieModalContent(props: DeleteMovieModalContentProps) {
|
||||||
? translate('DeleteMovieFoldersHelpText')
|
? translate('DeleteMovieFoldersHelpText')
|
||||||
: translate('DeleteMovieFolderHelpText')
|
: translate('DeleteMovieFolderHelpText')
|
||||||
}
|
}
|
||||||
kind={kinds.DANGER}
|
kind="danger"
|
||||||
onChange={onDeleteFilesChange}
|
onChange={onDeleteFilesChange}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
|
@ -9,6 +9,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
|
||||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||||
import { inputTypes } from 'Helpers/Props';
|
import { inputTypes } from 'Helpers/Props';
|
||||||
import MoveMovieModal from 'Movie/MoveMovie/MoveMovieModal';
|
import MoveMovieModal from 'Movie/MoveMovie/MoveMovieModal';
|
||||||
|
import { InputChanged } from 'typings/inputs';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import styles from './EditMoviesModalContent.css';
|
import styles from './EditMoviesModalContent.css';
|
||||||
|
|
||||||
|
@ -104,19 +105,19 @@ function EditMoviesModalContent(props: EditMoviesModalContentProps) {
|
||||||
);
|
);
|
||||||
|
|
||||||
const onInputChange = useCallback(
|
const onInputChange = useCallback(
|
||||||
({ name, value }: { name: string; value: string }) => {
|
({ name, value }: InputChanged) => {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'monitored':
|
case 'monitored':
|
||||||
setMonitored(value);
|
setMonitored(value as string);
|
||||||
break;
|
break;
|
||||||
case 'qualityProfileId':
|
case 'qualityProfileId':
|
||||||
setQualityProfileId(value);
|
setQualityProfileId(value as string);
|
||||||
break;
|
break;
|
||||||
case 'minimumAvailability':
|
case 'minimumAvailability':
|
||||||
setMinimumAvailability(value);
|
setMinimumAvailability(value as string);
|
||||||
break;
|
break;
|
||||||
case 'rootFolderPath':
|
case 'rootFolderPath':
|
||||||
setRootFolderPath(value);
|
setRootFolderPath(value as string);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.warn('EditMoviesModalContent Unknown Input');
|
console.warn('EditMoviesModalContent Unknown Input');
|
||||||
|
|
|
@ -8,6 +8,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
||||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||||
import { inputTypes } from 'Helpers/Props';
|
import { inputTypes } from 'Helpers/Props';
|
||||||
|
import { InputChanged } from 'typings/inputs';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import styles from './ManageDownloadClientsEditModalContent.css';
|
import styles from './ManageDownloadClientsEditModalContent.css';
|
||||||
|
|
||||||
|
@ -57,7 +58,7 @@ function ManageDownloadClientsEditModalContent(
|
||||||
const [removeCompletedDownloads, setRemoveCompletedDownloads] =
|
const [removeCompletedDownloads, setRemoveCompletedDownloads] =
|
||||||
useState(NO_CHANGE);
|
useState(NO_CHANGE);
|
||||||
const [removeFailedDownloads, setRemoveFailedDownloads] = useState(NO_CHANGE);
|
const [removeFailedDownloads, setRemoveFailedDownloads] = useState(NO_CHANGE);
|
||||||
const [priority, setPriority] = useState<null | string | number>(null);
|
const [priority, setPriority] = useState<null | number>(null);
|
||||||
|
|
||||||
const save = useCallback(() => {
|
const save = useCallback(() => {
|
||||||
let hasChanges = false;
|
let hasChanges = false;
|
||||||
|
@ -97,29 +98,26 @@ function ManageDownloadClientsEditModalContent(
|
||||||
onModalClose,
|
onModalClose,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const onInputChange = useCallback(
|
const onInputChange = useCallback(({ name, value }: InputChanged) => {
|
||||||
({ name, value }: { name: string; value: string }) => {
|
switch (name) {
|
||||||
switch (name) {
|
case 'enable':
|
||||||
case 'enable':
|
setEnable(value as string);
|
||||||
setEnable(value);
|
break;
|
||||||
break;
|
case 'priority':
|
||||||
case 'priority':
|
setPriority(value as number);
|
||||||
setPriority(value);
|
break;
|
||||||
break;
|
case 'removeCompletedDownloads':
|
||||||
case 'removeCompletedDownloads':
|
setRemoveCompletedDownloads(value as string);
|
||||||
setRemoveCompletedDownloads(value);
|
break;
|
||||||
break;
|
case 'removeFailedDownloads':
|
||||||
case 'removeFailedDownloads':
|
setRemoveFailedDownloads(value as string);
|
||||||
setRemoveFailedDownloads(value);
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
console.warn(
|
||||||
console.warn(
|
`EditDownloadClientsModalContent Unknown Input: '${name}'`
|
||||||
`EditDownloadClientsModalContent Unknown Input: '${name}'`
|
);
|
||||||
);
|
}
|
||||||
}
|
}, []);
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const selectedCount = downloadClientIds.length;
|
const selectedCount = downloadClientIds.length;
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ function BackupSettings(props) {
|
||||||
type={inputTypes.PATH}
|
type={inputTypes.PATH}
|
||||||
name="backupFolder"
|
name="backupFolder"
|
||||||
helpText={translate('BackupFolderHelpText')}
|
helpText={translate('BackupFolderHelpText')}
|
||||||
|
includeFiles={false}
|
||||||
onChange={onInputChange}
|
onChange={onInputChange}
|
||||||
{...backupFolder}
|
{...backupFolder}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -22,6 +22,7 @@ import {
|
||||||
} from 'Store/Actions/settingsActions';
|
} from 'Store/Actions/settingsActions';
|
||||||
import selectSettings from 'Store/Selectors/selectSettings';
|
import selectSettings from 'Store/Selectors/selectSettings';
|
||||||
import ImportListExclusion from 'typings/ImportListExclusion';
|
import ImportListExclusion from 'typings/ImportListExclusion';
|
||||||
|
import { InputChanged } from 'typings/inputs';
|
||||||
import { PendingSection } from 'typings/pending';
|
import { PendingSection } from 'typings/pending';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import styles from './EditImportListExclusionModalContent.css';
|
import styles from './EditImportListExclusionModalContent.css';
|
||||||
|
@ -104,9 +105,9 @@ function EditImportListExclusionModalContent({
|
||||||
}, [dispatch, id]);
|
}, [dispatch, id]);
|
||||||
|
|
||||||
const onInputChange = useCallback(
|
const onInputChange = useCallback(
|
||||||
(payload: { name: string; value: string | number }) => {
|
(change: InputChanged) => {
|
||||||
// @ts-expect-error 'setImportListExclusionValue' isn't typed yet
|
// @ts-expect-error 'setImportListExclusionValue' isn't typed yet
|
||||||
dispatch(setImportListExclusionValue(payload));
|
dispatch(setImportListExclusionValue(change));
|
||||||
},
|
},
|
||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
|
|
@ -142,7 +142,7 @@ function EditImportListModalContent(props) {
|
||||||
<FormLabel>{translate('Monitor')}</FormLabel>
|
<FormLabel>{translate('Monitor')}</FormLabel>
|
||||||
|
|
||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.MOVIE_MONITORED_SELECT}
|
type={inputTypes.MONITOR_MOVIES_SELECT}
|
||||||
name="monitor"
|
name="monitor"
|
||||||
helpText={translate('ListMonitorMovieHelpText')}
|
helpText={translate('ListMonitorMovieHelpText')}
|
||||||
{...monitor}
|
{...monitor}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
||||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||||
import { inputTypes } from 'Helpers/Props';
|
import { inputTypes } from 'Helpers/Props';
|
||||||
|
import { InputChanged } from 'typings/inputs';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import styles from './ManageImportListsEditModalContent.css';
|
import styles from './ManageImportListsEditModalContent.css';
|
||||||
|
|
||||||
|
@ -106,30 +107,27 @@ function ManageImportListsEditModalContent(
|
||||||
onModalClose,
|
onModalClose,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const onInputChange = useCallback(
|
const onInputChange = useCallback(({ name, value }: InputChanged) => {
|
||||||
({ name, value }: { name: string; value: string }) => {
|
switch (name) {
|
||||||
switch (name) {
|
case 'enabled':
|
||||||
case 'enabled':
|
setEnabled(value as string);
|
||||||
setEnabled(value);
|
break;
|
||||||
break;
|
case 'enableAuto':
|
||||||
case 'enableAuto':
|
setEnableAuto(value as string);
|
||||||
setEnableAuto(value);
|
break;
|
||||||
break;
|
case 'qualityProfileId':
|
||||||
case 'qualityProfileId':
|
setQualityProfileId(value as string);
|
||||||
setQualityProfileId(value);
|
break;
|
||||||
break;
|
case 'minimumAvailability':
|
||||||
case 'minimumAvailability':
|
setMinimumAvailability(value as string);
|
||||||
setMinimumAvailability(value);
|
break;
|
||||||
break;
|
case 'rootFolderPath':
|
||||||
case 'rootFolderPath':
|
setRootFolderPath(value as string);
|
||||||
setRootFolderPath(value);
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
console.warn(`EditImportListModalContent Unknown Input: '${name}'`);
|
||||||
console.warn(`EditImportListModalContent Unknown Input: '${name}'`);
|
}
|
||||||
}
|
}, []);
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const selectedCount = importListIds.length;
|
const selectedCount = importListIds.length;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
||||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||||
import { inputTypes } from 'Helpers/Props';
|
import { inputTypes } from 'Helpers/Props';
|
||||||
|
import { InputChanged } from 'typings/inputs';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import styles from './ManageIndexersEditModalContent.css';
|
import styles from './ManageIndexersEditModalContent.css';
|
||||||
|
|
||||||
|
@ -57,7 +58,7 @@ function ManageIndexersEditModalContent(
|
||||||
const [enableAutomaticSearch, setEnableAutomaticSearch] = useState(NO_CHANGE);
|
const [enableAutomaticSearch, setEnableAutomaticSearch] = useState(NO_CHANGE);
|
||||||
const [enableInteractiveSearch, setEnableInteractiveSearch] =
|
const [enableInteractiveSearch, setEnableInteractiveSearch] =
|
||||||
useState(NO_CHANGE);
|
useState(NO_CHANGE);
|
||||||
const [priority, setPriority] = useState<null | string | number>(null);
|
const [priority, setPriority] = useState<null | number>(null);
|
||||||
|
|
||||||
const save = useCallback(() => {
|
const save = useCallback(() => {
|
||||||
let hasChanges = false;
|
let hasChanges = false;
|
||||||
|
@ -97,27 +98,24 @@ function ManageIndexersEditModalContent(
|
||||||
onModalClose,
|
onModalClose,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const onInputChange = useCallback(
|
const onInputChange = useCallback(({ name, value }: InputChanged) => {
|
||||||
({ name, value }: { name: string; value: string }) => {
|
switch (name) {
|
||||||
switch (name) {
|
case 'enableRss':
|
||||||
case 'enableRss':
|
setEnableRss(value as string);
|
||||||
setEnableRss(value);
|
break;
|
||||||
break;
|
case 'enableAutomaticSearch':
|
||||||
case 'enableAutomaticSearch':
|
setEnableAutomaticSearch(value as string);
|
||||||
setEnableAutomaticSearch(value);
|
break;
|
||||||
break;
|
case 'enableInteractiveSearch':
|
||||||
case 'enableInteractiveSearch':
|
setEnableInteractiveSearch(value as string);
|
||||||
setEnableInteractiveSearch(value);
|
break;
|
||||||
break;
|
case 'priority':
|
||||||
case 'priority':
|
setPriority(value as number);
|
||||||
setPriority(value);
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
console.warn(`EditIndexersModalContent Unknown Input: '${name}'`);
|
||||||
console.warn(`EditIndexersModalContent Unknown Input: '${name}'`);
|
}
|
||||||
}
|
}, []);
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const selectedCount = indexerIds.length;
|
const selectedCount = indexerIds.length;
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import {
|
||||||
setNamingSettingsValue,
|
setNamingSettingsValue,
|
||||||
} from 'Store/Actions/settingsActions';
|
} from 'Store/Actions/settingsActions';
|
||||||
import createSettingsSectionSelector from 'Store/Selectors/createSettingsSectionSelector';
|
import createSettingsSectionSelector from 'Store/Selectors/createSettingsSectionSelector';
|
||||||
|
import { InputChanged } from 'typings/inputs';
|
||||||
import NamingConfig from 'typings/Settings/NamingConfig';
|
import NamingConfig from 'typings/Settings/NamingConfig';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import NamingModal from './NamingModal';
|
import NamingModal from './NamingModal';
|
||||||
|
@ -77,9 +78,9 @@ function Naming() {
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
const handleInputChange = useCallback(
|
const handleInputChange = useCallback(
|
||||||
({ name, value }: { name: string; value: string }) => {
|
(change: InputChanged) => {
|
||||||
// @ts-expect-error 'setNamingSettingsValue' isn't typed yet
|
// @ts-expect-error 'setNamingSettingsValue' isn't typed yet
|
||||||
dispatch(setNamingSettingsValue({ name, value }));
|
dispatch(setNamingSettingsValue(change));
|
||||||
|
|
||||||
if (namingExampleTimeout.current) {
|
if (namingExampleTimeout.current) {
|
||||||
clearTimeout(namingExampleTimeout.current);
|
clearTimeout(namingExampleTimeout.current);
|
||||||
|
|
|
@ -19,6 +19,7 @@ import {
|
||||||
setReleaseProfileValue,
|
setReleaseProfileValue,
|
||||||
} from 'Store/Actions/Settings/releaseProfiles';
|
} from 'Store/Actions/Settings/releaseProfiles';
|
||||||
import selectSettings from 'Store/Selectors/selectSettings';
|
import selectSettings from 'Store/Selectors/selectSettings';
|
||||||
|
import { InputChanged } from 'typings/inputs';
|
||||||
import ReleaseProfile from 'typings/Settings/ReleaseProfile';
|
import ReleaseProfile from 'typings/Settings/ReleaseProfile';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import styles from './EditReleaseProfileModalContent.css';
|
import styles from './EditReleaseProfileModalContent.css';
|
||||||
|
@ -102,9 +103,9 @@ function EditReleaseProfileModalContent({
|
||||||
}, [dispatch, id]);
|
}, [dispatch, id]);
|
||||||
|
|
||||||
const handleInputChange = useCallback(
|
const handleInputChange = useCallback(
|
||||||
(payload: { name: string; value: string | number }) => {
|
(change: InputChanged) => {
|
||||||
// @ts-expect-error 'setReleaseProfileValue' isn't typed yet
|
// @ts-expect-error 'setReleaseProfileValue' isn't typed yet
|
||||||
dispatch(setReleaseProfileValue(payload));
|
dispatch(setReleaseProfileValue(change));
|
||||||
},
|
},
|
||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
@ -125,7 +126,6 @@ function EditReleaseProfileModalContent({
|
||||||
name="name"
|
name="name"
|
||||||
{...name}
|
{...name}
|
||||||
placeholder={translate('OptionalName')}
|
placeholder={translate('OptionalName')}
|
||||||
canEdit={true}
|
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue