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