diff --git a/frontend/src/Components/Form/EnhancedSelectInput.js b/frontend/src/Components/Form/EnhancedSelectInput.js index 6dafc8bea..214aae25d 100644 --- a/frontend/src/Components/Form/EnhancedSelectInput.js +++ b/frontend/src/Components/Form/EnhancedSelectInput.js @@ -6,7 +6,7 @@ import classNames from 'classnames'; import getUniqueElememtId from 'Utilities/getUniqueElementId'; import isMobileUtil from 'Utilities/isMobile'; import * as keyCodes from 'Utilities/Constants/keyCodes'; -import { icons, scrollDirections } from 'Helpers/Props'; +import { icons, sizes, scrollDirections } from 'Helpers/Props'; import Icon from 'Components/Icon'; import Portal from 'Components/Portal'; import Link from 'Components/Link/Link'; @@ -14,8 +14,8 @@ import Measure from 'Components/Measure'; import Modal from 'Components/Modal/Modal'; import ModalBody from 'Components/Modal/ModalBody'; import Scroller from 'Components/Scroller/Scroller'; -import EnhancedSelectInputSelectedValue from './EnhancedSelectInputSelectedValue'; -import EnhancedSelectInputOption from './EnhancedSelectInputOption'; +import HintedSelectInputSelectedValue from './HintedSelectInputSelectedValue'; +import HintedSelectInputOption from './HintedSelectInputOption'; import styles from './EnhancedSelectInput.css'; function isArrowKey(keyCode) { @@ -150,9 +150,11 @@ class EnhancedSelectInput extends Component { } onBlur = () => { - this.setState({ - selectedIndex: getSelectedIndex(this.props) - }); + // Calling setState without this check prevents the click event from being properly handled on Chrome (it is on firefox) + const origIndex = getSelectedIndex(this.props); + if (origIndex !== this.state.selectedIndex) { + this.setState({ selectedIndex: origIndex }); + } } onKeyDown = (event) => { @@ -385,6 +387,7 @@ class EnhancedSelectInput extends Component { isMobile && @@ -439,8 +442,8 @@ EnhancedSelectInput.defaultProps = { disabledClassName: styles.isDisabled, isDisabled: false, selectedValueOptions: {}, - selectedValueComponent: EnhancedSelectInputSelectedValue, - optionComponent: EnhancedSelectInputOption + selectedValueComponent: HintedSelectInputSelectedValue, + optionComponent: HintedSelectInputOption }; export default EnhancedSelectInput; diff --git a/frontend/src/Components/Form/EnhancedSelectInputOption.css b/frontend/src/Components/Form/EnhancedSelectInputOption.css index 2b96de47f..18440c50d 100644 --- a/frontend/src/Components/Form/EnhancedSelectInputOption.css +++ b/frontend/src/Components/Form/EnhancedSelectInputOption.css @@ -7,13 +7,17 @@ cursor: default; &:hover { - background-color: #f9f9f9; + background-color: #f8f8f8; } } .isSelected { background-color: #e2e2e2; + &:hover { + background-color: #e2e2e2; + } + &.isMobile { background-color: inherit; diff --git a/frontend/src/Components/Form/FormInputGroup.css b/frontend/src/Components/Form/FormInputGroup.css index acdeb772f..1a1b104e6 100644 --- a/frontend/src/Components/Form/FormInputGroup.css +++ b/frontend/src/Components/Form/FormInputGroup.css @@ -1,5 +1,6 @@ .inputGroupContainer { flex: 1 1 auto; + min-width: 0; } .inputGroup { @@ -11,6 +12,7 @@ .inputContainer { position: relative; flex: 1 1 auto; + min-width: 0; } .inputUnit { diff --git a/frontend/src/Components/Form/FormInputGroup.js b/frontend/src/Components/Form/FormInputGroup.js index 7abb297d1..87f39bab3 100644 --- a/frontend/src/Components/Form/FormInputGroup.js +++ b/frontend/src/Components/Form/FormInputGroup.js @@ -16,7 +16,7 @@ import QualityProfileSelectInputConnector from './QualityProfileSelectInputConne import LanguageProfileSelectInputConnector from './LanguageProfileSelectInputConnector'; import RootFolderSelectInputConnector from './RootFolderSelectInputConnector'; import SeriesTypeSelectInput from './SeriesTypeSelectInput'; -import SelectInput from './SelectInput'; +import EnhancedSelectInput from './EnhancedSelectInput'; import TagInputConnector from './TagInputConnector'; import TextTagInputConnector from './TextTagInputConnector'; import TextInput from './TextInput'; @@ -65,7 +65,7 @@ function getComponent(type) { return RootFolderSelectInputConnector; case inputTypes.SELECT: - return SelectInput; + return EnhancedSelectInput; case inputTypes.SERIES_TYPE_SELECT: return SeriesTypeSelectInput; diff --git a/frontend/src/Components/Form/HintedSelectInputOption.css b/frontend/src/Components/Form/HintedSelectInputOption.css new file mode 100644 index 000000000..74d1fb088 --- /dev/null +++ b/frontend/src/Components/Form/HintedSelectInputOption.css @@ -0,0 +1,23 @@ +.optionText { + display: flex; + align-items: center; + justify-content: space-between; + flex: 1 0 0; + min-width: 0; + + &.isMobile { + display: block; + + .hintText { + margin-left: 0; + } + } +} + +.hintText { + @add-mixin truncate; + + margin-left: 15px; + color: $darkGray; + font-size: $smallFontSize; +} diff --git a/frontend/src/Components/Form/HintedSelectInputOption.js b/frontend/src/Components/Form/HintedSelectInputOption.js new file mode 100644 index 000000000..5ccc48a13 --- /dev/null +++ b/frontend/src/Components/Form/HintedSelectInputOption.js @@ -0,0 +1,44 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import classNames from 'classnames'; +import EnhancedSelectInputOption from './EnhancedSelectInputOption'; +import styles from './HintedSelectInputOption.css'; + +function HintedSelectInputOption(props) { + const { + value, + hint, + isMobile, + ...otherProps + } = props; + + return ( + +
+
{value}
+ + { + hint != null && +
+ {hint} +
+ } +
+
+ ); +} + +HintedSelectInputOption.propTypes = { + value: PropTypes.string.isRequired, + hint: PropTypes.node, + isMobile: PropTypes.bool.isRequired +}; + +export default HintedSelectInputOption; diff --git a/frontend/src/Components/Form/HintedSelectInputSelectedValue.css b/frontend/src/Components/Form/HintedSelectInputSelectedValue.css new file mode 100644 index 000000000..a31970a9e --- /dev/null +++ b/frontend/src/Components/Form/HintedSelectInputSelectedValue.css @@ -0,0 +1,24 @@ +.selectedValue { + composes: selectedValue from '~./EnhancedSelectInputSelectedValue.css'; + + display: flex; + align-items: center; + justify-content: space-between; + overflow: hidden; +} + +.valueText { + @add-mixin truncate; + + flex: 0 0 auto; +} + +.hintText { + @add-mixin truncate; + + flex: 1 10 0; + margin-left: 15px; + color: $gray; + text-align: right; + font-size: $smallFontSize; +} diff --git a/frontend/src/Components/Form/HintedSelectInputSelectedValue.js b/frontend/src/Components/Form/HintedSelectInputSelectedValue.js new file mode 100644 index 000000000..d43c3e4da --- /dev/null +++ b/frontend/src/Components/Form/HintedSelectInputSelectedValue.js @@ -0,0 +1,43 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import EnhancedSelectInputSelectedValue from './EnhancedSelectInputSelectedValue'; +import styles from './HintedSelectInputSelectedValue.css'; + +function HintedSelectInputSelectedValue(props) { + const { + value, + hint, + includeHint, + ...otherProps + } = props; + + return ( + +
+ {value} +
+ + { + hint != null && includeHint && +
+ {hint} +
+ } +
+ ); +} + +HintedSelectInputSelectedValue.propTypes = { + value: PropTypes.string, + hint: PropTypes.string, + includeHint: PropTypes.bool.isRequired +}; + +HintedSelectInputSelectedValue.defaultProps = { + includeHint: true +}; + +export default HintedSelectInputSelectedValue; diff --git a/frontend/src/Settings/DownloadClients/RemotePathMappings/EditRemotePathMappingModalContent.js b/frontend/src/Settings/DownloadClients/RemotePathMappings/EditRemotePathMappingModalContent.js index e03b39975..7b9a2b7fd 100644 --- a/frontend/src/Settings/DownloadClients/RemotePathMappings/EditRemotePathMappingModalContent.js +++ b/frontend/src/Settings/DownloadClients/RemotePathMappings/EditRemotePathMappingModalContent.js @@ -61,7 +61,7 @@ function EditRemotePathMappingModalContent(props) { Host state.settings.downloadClients.items, (downloadClients) => { - return downloadClients.reduce((acc, downloadClient) => { + const hosts = downloadClients.reduce((acc, downloadClient) => { + const name = downloadClient.name; const host = downloadClient.fields.find((field) => { return field.name === 'host'; }); - if (host && !acc.includes(host.value)) { - acc.push(host.value); + if (host) { + const group = acc[host.value] = acc[host.value] || []; + group.push(name); } return acc; - }, []); + }, {}); + + return Object.keys(hosts).map((host) => { + return { + key: host, + value: host, + hint: `${hosts[host].join(', ')}` + }; + }); } ); diff --git a/frontend/src/Settings/MediaManagement/Naming/Naming.js b/frontend/src/Settings/MediaManagement/Naming/Naming.js index 863eb78dc..d39747709 100644 --- a/frontend/src/Settings/MediaManagement/Naming/Naming.js +++ b/frontend/src/Settings/MediaManagement/Naming/Naming.js @@ -122,12 +122,12 @@ class Naming extends Component { const renameEpisodes = hasSettings && settings.renameEpisodes.value; const multiEpisodeStyleOptions = [ - { key: 0, value: 'Extend' }, - { key: 1, value: 'Duplicate' }, - { key: 2, value: 'Repeat' }, - { key: 3, value: 'Scene' }, - { key: 4, value: 'Range' }, - { key: 5, value: 'Prefixed Range' } + { key: 0, value: 'Extend', hint: 'S01E01-02-03' }, + { key: 1, value: 'Duplicate', hint: 'S01E01.S01E02' }, + { key: 2, value: 'Repeat', hint: 'S01E01E02E03' }, + { key: 3, value: 'Scene', hint: 'S01E01-E02-E03' }, + { key: 4, value: 'Range', hint: 'S01E01-03' }, + { key: 5, value: 'Prefixed Range', hint: 'S01E01-E03' } ]; const standardEpisodeFormatHelpTexts = [];