mirror of
https://github.com/Sonarr/Sonarr
synced 2025-03-10 06:03:32 +00:00
Convert ProviderFieldFormGroup to TypeScript
This commit is contained in:
parent
24173139f0
commit
ac7ac34cc2
7 changed files with 156 additions and 166 deletions
|
@ -6,7 +6,7 @@ import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
import FormLabel from 'Components/Form/FormLabel';
|
import FormLabel from 'Components/Form/FormLabel';
|
||||||
import { inputTypes } from 'Helpers/Props';
|
import { inputTypes } from 'Helpers/Props';
|
||||||
import { gotoQueuePage, setQueueOption } from 'Store/Actions/queueActions';
|
import { gotoQueuePage, setQueueOption } from 'Store/Actions/queueActions';
|
||||||
import { CheckInputChanged } from 'typings/inputs';
|
import { InputChanged } from 'typings/inputs';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
|
|
||||||
function QueueOptions() {
|
function QueueOptions() {
|
||||||
|
@ -16,7 +16,7 @@ function QueueOptions() {
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleOptionChange = useCallback(
|
const handleOptionChange = useCallback(
|
||||||
({ name, value }: CheckInputChanged) => {
|
({ name, value }: InputChanged<boolean>) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
setQueueOption({
|
setQueueOption({
|
||||||
[name]: value,
|
[name]: value,
|
||||||
|
|
|
@ -3,6 +3,7 @@ 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 { Kind } from 'Helpers/Props/kinds';
|
||||||
|
import { InputChanged } from 'typings/inputs';
|
||||||
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 from './AutoCompleteInput';
|
||||||
|
@ -118,6 +119,12 @@ function getComponent(type: InputType) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// TODO: Remove once all parent components are updated to TSX and we can refactor to a consistent type
|
||||||
export interface ValidationMessage {
|
export interface ValidationMessage {
|
||||||
message: string;
|
message: string;
|
||||||
|
@ -129,7 +136,7 @@ interface FormInputGroupProps<T> {
|
||||||
inputClassName?: string;
|
inputClassName?: string;
|
||||||
name: string;
|
name: string;
|
||||||
value?: unknown;
|
value?: unknown;
|
||||||
values?: unknown[];
|
values?: FormInputGroupValues<unknown>[];
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
type?: InputType;
|
type?: InputType;
|
||||||
kind?: Kind;
|
kind?: Kind;
|
||||||
|
@ -143,10 +150,12 @@ interface FormInputGroupProps<T> {
|
||||||
helpLink?: string;
|
helpLink?: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
autoFocus?: boolean;
|
autoFocus?: boolean;
|
||||||
|
includeFiles?: boolean;
|
||||||
includeNoChange?: boolean;
|
includeNoChange?: boolean;
|
||||||
includeNoChangeDisabled?: boolean;
|
includeNoChangeDisabled?: boolean;
|
||||||
valueOptions?: object;
|
valueOptions?: object;
|
||||||
selectedValueOptions?: object;
|
selectedValueOptions?: object;
|
||||||
|
selectOptionsProviderAction?: string;
|
||||||
indexerFlags?: number;
|
indexerFlags?: number;
|
||||||
pending?: boolean;
|
pending?: boolean;
|
||||||
canEdit?: boolean;
|
canEdit?: boolean;
|
||||||
|
@ -155,7 +164,7 @@ interface FormInputGroupProps<T> {
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
errors?: (ValidationMessage | ValidationError)[];
|
errors?: (ValidationMessage | ValidationError)[];
|
||||||
warnings?: (ValidationMessage | ValidationWarning)[];
|
warnings?: (ValidationMessage | ValidationWarning)[];
|
||||||
onChange: (args: T) => void;
|
onChange: (change: InputChanged<T>) => void;
|
||||||
onFocus?: (event: FocusEvent<HTMLInputElement>) => void;
|
onFocus?: (event: FocusEvent<HTMLInputElement>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,155 +0,0 @@
|
||||||
import _ from 'lodash';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
|
||||||
import FormGroup from 'Components/Form/FormGroup';
|
|
||||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
|
||||||
import FormLabel from 'Components/Form/FormLabel';
|
|
||||||
import { inputTypes } from 'Helpers/Props';
|
|
||||||
|
|
||||||
function getType({ type, selectOptionsProviderAction }) {
|
|
||||||
switch (type) {
|
|
||||||
case 'captcha':
|
|
||||||
return inputTypes.CAPTCHA;
|
|
||||||
case 'checkbox':
|
|
||||||
return inputTypes.CHECK;
|
|
||||||
case 'device':
|
|
||||||
return inputTypes.DEVICE;
|
|
||||||
case 'keyValueList':
|
|
||||||
return inputTypes.KEY_VALUE_LIST;
|
|
||||||
case 'password':
|
|
||||||
return inputTypes.PASSWORD;
|
|
||||||
case 'number':
|
|
||||||
return inputTypes.NUMBER;
|
|
||||||
case 'path':
|
|
||||||
return inputTypes.PATH;
|
|
||||||
case 'filePath':
|
|
||||||
return inputTypes.PATH;
|
|
||||||
case 'select':
|
|
||||||
if (selectOptionsProviderAction) {
|
|
||||||
return inputTypes.DYNAMIC_SELECT;
|
|
||||||
}
|
|
||||||
return inputTypes.SELECT;
|
|
||||||
case 'seriesTag':
|
|
||||||
return inputTypes.SERIES_TAG;
|
|
||||||
case 'tag':
|
|
||||||
return inputTypes.TEXT_TAG;
|
|
||||||
case 'tagSelect':
|
|
||||||
return inputTypes.TAG_SELECT;
|
|
||||||
case 'textbox':
|
|
||||||
return inputTypes.TEXT;
|
|
||||||
case 'oAuth':
|
|
||||||
return inputTypes.OAUTH;
|
|
||||||
case 'rootFolder':
|
|
||||||
return inputTypes.ROOT_FOLDER_SELECT;
|
|
||||||
case 'qualityProfile':
|
|
||||||
return inputTypes.QUALITY_PROFILE_SELECT;
|
|
||||||
default:
|
|
||||||
return inputTypes.TEXT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSelectValues(selectOptions) {
|
|
||||||
if (!selectOptions) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _.reduce(selectOptions, (result, option) => {
|
|
||||||
result.push({
|
|
||||||
key: option.value,
|
|
||||||
value: option.name,
|
|
||||||
hint: option.hint
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ProviderFieldFormGroup(props) {
|
|
||||||
const {
|
|
||||||
advancedSettings,
|
|
||||||
name,
|
|
||||||
label,
|
|
||||||
helpText,
|
|
||||||
helpTextWarning,
|
|
||||||
helpLink,
|
|
||||||
placeholder,
|
|
||||||
value,
|
|
||||||
type,
|
|
||||||
advanced,
|
|
||||||
hidden,
|
|
||||||
pending,
|
|
||||||
errors,
|
|
||||||
warnings,
|
|
||||||
selectOptions,
|
|
||||||
onChange,
|
|
||||||
...otherProps
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
if (
|
|
||||||
hidden === 'hidden' ||
|
|
||||||
(hidden === 'hiddenIfNotSet' && !value)
|
|
||||||
) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormGroup
|
|
||||||
advancedSettings={advancedSettings}
|
|
||||||
isAdvanced={advanced}
|
|
||||||
>
|
|
||||||
<FormLabel>{label}</FormLabel>
|
|
||||||
|
|
||||||
<FormInputGroup
|
|
||||||
type={getType(props)}
|
|
||||||
name={name}
|
|
||||||
label={label}
|
|
||||||
helpText={helpText}
|
|
||||||
helpTextWarning={helpTextWarning}
|
|
||||||
helpLink={helpLink}
|
|
||||||
placeholder={placeholder}
|
|
||||||
value={value}
|
|
||||||
values={getSelectValues(selectOptions)}
|
|
||||||
errors={errors}
|
|
||||||
warnings={warnings}
|
|
||||||
pending={pending}
|
|
||||||
includeFiles={type === 'filePath' ? true : undefined}
|
|
||||||
onChange={onChange}
|
|
||||||
{...otherProps}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectOptionsShape = {
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
value: PropTypes.number.isRequired,
|
|
||||||
hint: PropTypes.string
|
|
||||||
};
|
|
||||||
|
|
||||||
ProviderFieldFormGroup.propTypes = {
|
|
||||||
advancedSettings: PropTypes.bool.isRequired,
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
label: PropTypes.string.isRequired,
|
|
||||||
helpText: PropTypes.string,
|
|
||||||
helpTextWarning: PropTypes.string,
|
|
||||||
helpLink: PropTypes.string,
|
|
||||||
placeholder: PropTypes.string,
|
|
||||||
value: PropTypes.any,
|
|
||||||
type: PropTypes.string.isRequired,
|
|
||||||
advanced: PropTypes.bool.isRequired,
|
|
||||||
hidden: PropTypes.string,
|
|
||||||
isDisabled: PropTypes.bool,
|
|
||||||
provider: PropTypes.string,
|
|
||||||
pending: PropTypes.bool.isRequired,
|
|
||||||
errors: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
warnings: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
selectOptions: PropTypes.arrayOf(PropTypes.shape(selectOptionsShape)),
|
|
||||||
selectOptionsProviderAction: PropTypes.string,
|
|
||||||
onChange: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
ProviderFieldFormGroup.defaultProps = {
|
|
||||||
advancedSettings: false
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ProviderFieldFormGroup;
|
|
136
frontend/src/Components/Form/ProviderFieldFormGroup.tsx
Normal file
136
frontend/src/Components/Form/ProviderFieldFormGroup.tsx
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import FormGroup from 'Components/Form/FormGroup';
|
||||||
|
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
|
import FormLabel from 'Components/Form/FormLabel';
|
||||||
|
import { FieldSelectOption } from 'typings/Field';
|
||||||
|
import { InputChanged } from 'typings/inputs';
|
||||||
|
import { Failure } from 'typings/pending';
|
||||||
|
|
||||||
|
interface ProviderFieldFormGroupProps<T> {
|
||||||
|
advancedSettings: boolean;
|
||||||
|
name: string;
|
||||||
|
label: string;
|
||||||
|
helpText?: string;
|
||||||
|
helpTextWarning?: string;
|
||||||
|
helpLink?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
value?: T;
|
||||||
|
type: string;
|
||||||
|
advanced: boolean;
|
||||||
|
hidden?: string;
|
||||||
|
isDisabled?: boolean;
|
||||||
|
provider?: string;
|
||||||
|
pending: boolean;
|
||||||
|
errors: Failure[];
|
||||||
|
warnings: Failure[];
|
||||||
|
selectOptions?: FieldSelectOption<T>[];
|
||||||
|
selectOptionsProviderAction?: string;
|
||||||
|
onChange: (change: InputChanged<T>) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ProviderFieldFormGroup<T>({
|
||||||
|
advancedSettings = false,
|
||||||
|
name,
|
||||||
|
label,
|
||||||
|
helpText,
|
||||||
|
helpTextWarning,
|
||||||
|
helpLink,
|
||||||
|
placeholder,
|
||||||
|
value,
|
||||||
|
type: providerType,
|
||||||
|
advanced,
|
||||||
|
hidden,
|
||||||
|
pending,
|
||||||
|
errors,
|
||||||
|
warnings,
|
||||||
|
selectOptions,
|
||||||
|
selectOptionsProviderAction,
|
||||||
|
onChange,
|
||||||
|
...otherProps
|
||||||
|
}: ProviderFieldFormGroupProps<T>) {
|
||||||
|
const type = useMemo(() => {
|
||||||
|
switch (providerType) {
|
||||||
|
case 'captcha':
|
||||||
|
return 'captcha';
|
||||||
|
case 'checkbox':
|
||||||
|
return 'check';
|
||||||
|
case 'device':
|
||||||
|
return 'device';
|
||||||
|
case 'keyValueList':
|
||||||
|
return 'keyValueList';
|
||||||
|
case 'password':
|
||||||
|
return 'password';
|
||||||
|
case 'number':
|
||||||
|
return 'number';
|
||||||
|
case 'path':
|
||||||
|
return 'path';
|
||||||
|
case 'filePath':
|
||||||
|
return 'path';
|
||||||
|
case 'select':
|
||||||
|
if (selectOptionsProviderAction) {
|
||||||
|
return 'dynamicSelect';
|
||||||
|
}
|
||||||
|
return 'select';
|
||||||
|
case 'seriesTag':
|
||||||
|
return 'seriesTag';
|
||||||
|
case 'tag':
|
||||||
|
return 'textTag';
|
||||||
|
case 'tagSelect':
|
||||||
|
return 'tagSelect';
|
||||||
|
case 'textbox':
|
||||||
|
return 'text';
|
||||||
|
case 'oAuth':
|
||||||
|
return 'oauth';
|
||||||
|
case 'rootFolder':
|
||||||
|
return 'rootFolderSelect';
|
||||||
|
case 'qualityProfile':
|
||||||
|
return 'qualityProfileSelect';
|
||||||
|
default:
|
||||||
|
return 'text';
|
||||||
|
}
|
||||||
|
}, [providerType, selectOptionsProviderAction]);
|
||||||
|
|
||||||
|
const selectValues = useMemo(() => {
|
||||||
|
if (!selectOptions) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectOptions.map((option) => {
|
||||||
|
return {
|
||||||
|
key: option.value,
|
||||||
|
value: option.name,
|
||||||
|
hint: option.hint,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, [selectOptions]);
|
||||||
|
|
||||||
|
if (hidden === 'hidden' || (hidden === 'hiddenIfNotSet' && !value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormGroup advancedSettings={advancedSettings} isAdvanced={advanced}>
|
||||||
|
<FormLabel>{label}</FormLabel>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={type}
|
||||||
|
name={name}
|
||||||
|
helpText={helpText}
|
||||||
|
helpTextWarning={helpTextWarning}
|
||||||
|
helpLink={helpLink}
|
||||||
|
placeholder={placeholder}
|
||||||
|
selectOptionsProviderAction={selectOptionsProviderAction}
|
||||||
|
value={value}
|
||||||
|
values={selectValues}
|
||||||
|
errors={errors}
|
||||||
|
warnings={warnings}
|
||||||
|
pending={pending}
|
||||||
|
includeFiles={providerType === 'filePath' ? true : undefined}
|
||||||
|
onChange={onChange}
|
||||||
|
{...otherProps}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProviderFieldFormGroup;
|
|
@ -16,7 +16,7 @@ import ModalHeader from 'Components/Modal/ModalHeader';
|
||||||
import { inputTypes, kinds } from 'Helpers/Props';
|
import { inputTypes, kinds } from 'Helpers/Props';
|
||||||
import Quality, { QualityModel } from 'Quality/Quality';
|
import Quality, { QualityModel } from 'Quality/Quality';
|
||||||
import { fetchQualityProfileSchema } from 'Store/Actions/settingsActions';
|
import { fetchQualityProfileSchema } from 'Store/Actions/settingsActions';
|
||||||
import { CheckInputChanged } from 'typings/inputs';
|
import { InputChanged } from 'typings/inputs';
|
||||||
import getQualities from 'Utilities/Quality/getQualities';
|
import getQualities from 'Utilities/Quality/getQualities';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
|
|
||||||
|
@ -85,14 +85,14 @@ function SelectQualityModalContent(props: SelectQualityModalContentProps) {
|
||||||
);
|
);
|
||||||
|
|
||||||
const onProperChange = useCallback(
|
const onProperChange = useCallback(
|
||||||
({ value }: CheckInputChanged) => {
|
({ value }: InputChanged<boolean>) => {
|
||||||
setProper(value);
|
setProper(value);
|
||||||
},
|
},
|
||||||
[setProper]
|
[setProper]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onRealChange = useCallback(
|
const onRealChange = useCallback(
|
||||||
({ value }: CheckInputChanged) => {
|
({ value }: InputChanged<boolean>) => {
|
||||||
setReal(value);
|
setReal(value);
|
||||||
},
|
},
|
||||||
[setReal]
|
[setReal]
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { inputTypes, kinds } from 'Helpers/Props';
|
||||||
import Series from 'Series/Series';
|
import Series from 'Series/Series';
|
||||||
import { bulkDeleteSeries, setDeleteOption } from 'Store/Actions/seriesActions';
|
import { bulkDeleteSeries, setDeleteOption } from 'Store/Actions/seriesActions';
|
||||||
import createAllSeriesSelector from 'Store/Selectors/createAllSeriesSelector';
|
import createAllSeriesSelector from 'Store/Selectors/createAllSeriesSelector';
|
||||||
import { CheckInputChanged } from 'typings/inputs';
|
import { InputChanged } from 'typings/inputs';
|
||||||
import formatBytes from 'Utilities/Number/formatBytes';
|
import formatBytes from 'Utilities/Number/formatBytes';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import styles from './DeleteSeriesModalContent.css';
|
import styles from './DeleteSeriesModalContent.css';
|
||||||
|
@ -48,7 +48,7 @@ function DeleteSeriesModalContent(props: DeleteSeriesModalContentProps) {
|
||||||
}, [seriesIds, allSeries]);
|
}, [seriesIds, allSeries]);
|
||||||
|
|
||||||
const onDeleteFilesChange = useCallback(
|
const onDeleteFilesChange = useCallback(
|
||||||
({ value }: CheckInputChanged) => {
|
({ value }: InputChanged<boolean>) => {
|
||||||
setDeleteFiles(value);
|
setDeleteFiles(value);
|
||||||
},
|
},
|
||||||
[setDeleteFiles]
|
[setDeleteFiles]
|
||||||
|
|
|
@ -4,7 +4,7 @@ import FormGroup from 'Components/Form/FormGroup';
|
||||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
import FormLabel from 'Components/Form/FormLabel';
|
import FormLabel from 'Components/Form/FormLabel';
|
||||||
import { inputTypes } from 'Helpers/Props';
|
import { inputTypes } from 'Helpers/Props';
|
||||||
import { CheckInputChanged } from 'typings/inputs';
|
import { InputChanged } from 'typings/inputs';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import selectTableOptions from './selectTableOptions';
|
import selectTableOptions from './selectTableOptions';
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ function SeriesIndexTableOptions(props: SeriesIndexTableOptionsProps) {
|
||||||
const { showBanners, showSearchAction } = tableOptions;
|
const { showBanners, showSearchAction } = tableOptions;
|
||||||
|
|
||||||
const onTableOptionChangeWrapper = useCallback(
|
const onTableOptionChangeWrapper = useCallback(
|
||||||
({ name, value }: CheckInputChanged) => {
|
({ name, value }: InputChanged<boolean>) => {
|
||||||
onTableOptionChange({
|
onTableOptionChange({
|
||||||
tableOptions: {
|
tableOptions: {
|
||||||
...tableOptions,
|
...tableOptions,
|
||||||
|
|
Loading…
Add table
Reference in a new issue