diff --git a/frontend/src/Activity/Queue/QueueOptions.tsx b/frontend/src/Activity/Queue/QueueOptions.tsx index 17a6ac1fe..dc2c9dc02 100644 --- a/frontend/src/Activity/Queue/QueueOptions.tsx +++ b/frontend/src/Activity/Queue/QueueOptions.tsx @@ -6,7 +6,7 @@ import FormInputGroup from 'Components/Form/FormInputGroup'; import FormLabel from 'Components/Form/FormLabel'; import { inputTypes } from 'Helpers/Props'; import { gotoQueuePage, setQueueOption } from 'Store/Actions/queueActions'; -import { CheckInputChanged } from 'typings/inputs'; +import { InputChanged } from 'typings/inputs'; import translate from 'Utilities/String/translate'; function QueueOptions() { @@ -16,7 +16,7 @@ function QueueOptions() { ); const handleOptionChange = useCallback( - ({ name, value }: CheckInputChanged) => { + ({ name, value }: InputChanged) => { dispatch( setQueueOption({ [name]: value, diff --git a/frontend/src/Components/Form/FormInputGroup.tsx b/frontend/src/Components/Form/FormInputGroup.tsx index 14e9a5909..dca3ef2db 100644 --- a/frontend/src/Components/Form/FormInputGroup.tsx +++ b/frontend/src/Components/Form/FormInputGroup.tsx @@ -3,6 +3,7 @@ import Link from 'Components/Link/Link'; import { inputTypes } from 'Helpers/Props'; import { InputType } from 'Helpers/Props/inputTypes'; import { Kind } from 'Helpers/Props/kinds'; +import { InputChanged } from 'typings/inputs'; import { ValidationError, ValidationWarning } from 'typings/pending'; import translate from 'Utilities/String/translate'; import AutoCompleteInput from './AutoCompleteInput'; @@ -118,6 +119,12 @@ function getComponent(type: InputType) { } } +export interface FormInputGroupValues { + key: T; + value: string; + hint?: string; +} + // TODO: Remove once all parent components are updated to TSX and we can refactor to a consistent type export interface ValidationMessage { message: string; @@ -129,7 +136,7 @@ interface FormInputGroupProps { inputClassName?: string; name: string; value?: unknown; - values?: unknown[]; + values?: FormInputGroupValues[]; isDisabled?: boolean; type?: InputType; kind?: Kind; @@ -143,10 +150,12 @@ interface FormInputGroupProps { helpLink?: string; placeholder?: string; autoFocus?: boolean; + includeFiles?: boolean; includeNoChange?: boolean; includeNoChangeDisabled?: boolean; valueOptions?: object; selectedValueOptions?: object; + selectOptionsProviderAction?: string; indexerFlags?: number; pending?: boolean; canEdit?: boolean; @@ -155,7 +164,7 @@ interface FormInputGroupProps { readOnly?: boolean; errors?: (ValidationMessage | ValidationError)[]; warnings?: (ValidationMessage | ValidationWarning)[]; - onChange: (args: T) => void; + onChange: (change: InputChanged) => void; onFocus?: (event: FocusEvent) => void; } diff --git a/frontend/src/Components/Form/ProviderFieldFormGroup.js b/frontend/src/Components/Form/ProviderFieldFormGroup.js deleted file mode 100644 index f081f5906..000000000 --- a/frontend/src/Components/Form/ProviderFieldFormGroup.js +++ /dev/null @@ -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 ( - - {label} - - - - ); -} - -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; diff --git a/frontend/src/Components/Form/ProviderFieldFormGroup.tsx b/frontend/src/Components/Form/ProviderFieldFormGroup.tsx new file mode 100644 index 000000000..ece6d090b --- /dev/null +++ b/frontend/src/Components/Form/ProviderFieldFormGroup.tsx @@ -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 { + 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[]; + selectOptionsProviderAction?: string; + onChange: (change: InputChanged) => void; +} + +function ProviderFieldFormGroup({ + advancedSettings = false, + name, + label, + helpText, + helpTextWarning, + helpLink, + placeholder, + value, + type: providerType, + advanced, + hidden, + pending, + errors, + warnings, + selectOptions, + selectOptionsProviderAction, + onChange, + ...otherProps +}: ProviderFieldFormGroupProps) { + 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 ( + + {label} + + + + ); +} + +export default ProviderFieldFormGroup; diff --git a/frontend/src/InteractiveImport/Quality/SelectQualityModalContent.tsx b/frontend/src/InteractiveImport/Quality/SelectQualityModalContent.tsx index 5d4d561b0..edaefdca7 100644 --- a/frontend/src/InteractiveImport/Quality/SelectQualityModalContent.tsx +++ b/frontend/src/InteractiveImport/Quality/SelectQualityModalContent.tsx @@ -16,7 +16,7 @@ import ModalHeader from 'Components/Modal/ModalHeader'; import { inputTypes, kinds } from 'Helpers/Props'; import Quality, { QualityModel } from 'Quality/Quality'; import { fetchQualityProfileSchema } from 'Store/Actions/settingsActions'; -import { CheckInputChanged } from 'typings/inputs'; +import { InputChanged } from 'typings/inputs'; import getQualities from 'Utilities/Quality/getQualities'; import translate from 'Utilities/String/translate'; @@ -85,14 +85,14 @@ function SelectQualityModalContent(props: SelectQualityModalContentProps) { ); const onProperChange = useCallback( - ({ value }: CheckInputChanged) => { + ({ value }: InputChanged) => { setProper(value); }, [setProper] ); const onRealChange = useCallback( - ({ value }: CheckInputChanged) => { + ({ value }: InputChanged) => { setReal(value); }, [setReal] diff --git a/frontend/src/Series/Index/Select/Delete/DeleteSeriesModalContent.tsx b/frontend/src/Series/Index/Select/Delete/DeleteSeriesModalContent.tsx index eb26675c6..6ec8249aa 100644 --- a/frontend/src/Series/Index/Select/Delete/DeleteSeriesModalContent.tsx +++ b/frontend/src/Series/Index/Select/Delete/DeleteSeriesModalContent.tsx @@ -15,7 +15,7 @@ import { inputTypes, kinds } from 'Helpers/Props'; import Series from 'Series/Series'; import { bulkDeleteSeries, setDeleteOption } from 'Store/Actions/seriesActions'; import createAllSeriesSelector from 'Store/Selectors/createAllSeriesSelector'; -import { CheckInputChanged } from 'typings/inputs'; +import { InputChanged } from 'typings/inputs'; import formatBytes from 'Utilities/Number/formatBytes'; import translate from 'Utilities/String/translate'; import styles from './DeleteSeriesModalContent.css'; @@ -48,7 +48,7 @@ function DeleteSeriesModalContent(props: DeleteSeriesModalContentProps) { }, [seriesIds, allSeries]); const onDeleteFilesChange = useCallback( - ({ value }: CheckInputChanged) => { + ({ value }: InputChanged) => { setDeleteFiles(value); }, [setDeleteFiles] diff --git a/frontend/src/Series/Index/Table/SeriesIndexTableOptions.tsx b/frontend/src/Series/Index/Table/SeriesIndexTableOptions.tsx index 0a9cc1d17..6e1f1b331 100644 --- a/frontend/src/Series/Index/Table/SeriesIndexTableOptions.tsx +++ b/frontend/src/Series/Index/Table/SeriesIndexTableOptions.tsx @@ -4,7 +4,7 @@ import FormGroup from 'Components/Form/FormGroup'; import FormInputGroup from 'Components/Form/FormInputGroup'; import FormLabel from 'Components/Form/FormLabel'; import { inputTypes } from 'Helpers/Props'; -import { CheckInputChanged } from 'typings/inputs'; +import { InputChanged } from 'typings/inputs'; import translate from 'Utilities/String/translate'; import selectTableOptions from './selectTableOptions'; @@ -20,7 +20,7 @@ function SeriesIndexTableOptions(props: SeriesIndexTableOptionsProps) { const { showBanners, showSearchAction } = tableOptions; const onTableOptionChangeWrapper = useCallback( - ({ name, value }: CheckInputChanged) => { + ({ name, value }: InputChanged) => { onTableOptionChange({ tableOptions: { ...tableOptions,