Created generic Hinted EnhancedSelectInput components and use it instead of SelectInput
This commit is contained in:
parent
d3662f2302
commit
1af3e0bd93
|
@ -6,7 +6,7 @@ import classNames from 'classnames';
|
||||||
import getUniqueElememtId from 'Utilities/getUniqueElementId';
|
import getUniqueElememtId from 'Utilities/getUniqueElementId';
|
||||||
import isMobileUtil from 'Utilities/isMobile';
|
import isMobileUtil from 'Utilities/isMobile';
|
||||||
import * as keyCodes from 'Utilities/Constants/keyCodes';
|
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 Icon from 'Components/Icon';
|
||||||
import Portal from 'Components/Portal';
|
import Portal from 'Components/Portal';
|
||||||
import Link from 'Components/Link/Link';
|
import Link from 'Components/Link/Link';
|
||||||
|
@ -14,8 +14,8 @@ import Measure from 'Components/Measure';
|
||||||
import Modal from 'Components/Modal/Modal';
|
import Modal from 'Components/Modal/Modal';
|
||||||
import ModalBody from 'Components/Modal/ModalBody';
|
import ModalBody from 'Components/Modal/ModalBody';
|
||||||
import Scroller from 'Components/Scroller/Scroller';
|
import Scroller from 'Components/Scroller/Scroller';
|
||||||
import EnhancedSelectInputSelectedValue from './EnhancedSelectInputSelectedValue';
|
import HintedSelectInputSelectedValue from './HintedSelectInputSelectedValue';
|
||||||
import EnhancedSelectInputOption from './EnhancedSelectInputOption';
|
import HintedSelectInputOption from './HintedSelectInputOption';
|
||||||
import styles from './EnhancedSelectInput.css';
|
import styles from './EnhancedSelectInput.css';
|
||||||
|
|
||||||
function isArrowKey(keyCode) {
|
function isArrowKey(keyCode) {
|
||||||
|
@ -150,9 +150,11 @@ class EnhancedSelectInput extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBlur = () => {
|
onBlur = () => {
|
||||||
this.setState({
|
// Calling setState without this check prevents the click event from being properly handled on Chrome (it is on firefox)
|
||||||
selectedIndex: getSelectedIndex(this.props)
|
const origIndex = getSelectedIndex(this.props);
|
||||||
});
|
if (origIndex !== this.state.selectedIndex) {
|
||||||
|
this.setState({ selectedIndex: origIndex });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyDown = (event) => {
|
onKeyDown = (event) => {
|
||||||
|
@ -385,6 +387,7 @@ class EnhancedSelectInput extends Component {
|
||||||
isMobile &&
|
isMobile &&
|
||||||
<Modal
|
<Modal
|
||||||
className={styles.optionsModal}
|
className={styles.optionsModal}
|
||||||
|
size={sizes.EXTRA_SMALL}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onModalClose={this.onOptionsModalClose}
|
onModalClose={this.onOptionsModalClose}
|
||||||
>
|
>
|
||||||
|
@ -439,8 +442,8 @@ EnhancedSelectInput.defaultProps = {
|
||||||
disabledClassName: styles.isDisabled,
|
disabledClassName: styles.isDisabled,
|
||||||
isDisabled: false,
|
isDisabled: false,
|
||||||
selectedValueOptions: {},
|
selectedValueOptions: {},
|
||||||
selectedValueComponent: EnhancedSelectInputSelectedValue,
|
selectedValueComponent: HintedSelectInputSelectedValue,
|
||||||
optionComponent: EnhancedSelectInputOption
|
optionComponent: HintedSelectInputOption
|
||||||
};
|
};
|
||||||
|
|
||||||
export default EnhancedSelectInput;
|
export default EnhancedSelectInput;
|
||||||
|
|
|
@ -7,13 +7,17 @@
|
||||||
cursor: default;
|
cursor: default;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #f9f9f9;
|
background-color: #f8f8f8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.isSelected {
|
.isSelected {
|
||||||
background-color: #e2e2e2;
|
background-color: #e2e2e2;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #e2e2e2;
|
||||||
|
}
|
||||||
|
|
||||||
&.isMobile {
|
&.isMobile {
|
||||||
background-color: inherit;
|
background-color: inherit;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
.inputGroupContainer {
|
.inputGroupContainer {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inputGroup {
|
.inputGroup {
|
||||||
|
@ -11,6 +12,7 @@
|
||||||
.inputContainer {
|
.inputContainer {
|
||||||
position: relative;
|
position: relative;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inputUnit {
|
.inputUnit {
|
||||||
|
|
|
@ -16,7 +16,7 @@ import QualityProfileSelectInputConnector from './QualityProfileSelectInputConne
|
||||||
import LanguageProfileSelectInputConnector from './LanguageProfileSelectInputConnector';
|
import LanguageProfileSelectInputConnector from './LanguageProfileSelectInputConnector';
|
||||||
import RootFolderSelectInputConnector from './RootFolderSelectInputConnector';
|
import RootFolderSelectInputConnector from './RootFolderSelectInputConnector';
|
||||||
import SeriesTypeSelectInput from './SeriesTypeSelectInput';
|
import SeriesTypeSelectInput from './SeriesTypeSelectInput';
|
||||||
import SelectInput from './SelectInput';
|
import EnhancedSelectInput from './EnhancedSelectInput';
|
||||||
import TagInputConnector from './TagInputConnector';
|
import TagInputConnector from './TagInputConnector';
|
||||||
import TextTagInputConnector from './TextTagInputConnector';
|
import TextTagInputConnector from './TextTagInputConnector';
|
||||||
import TextInput from './TextInput';
|
import TextInput from './TextInput';
|
||||||
|
@ -65,7 +65,7 @@ function getComponent(type) {
|
||||||
return RootFolderSelectInputConnector;
|
return RootFolderSelectInputConnector;
|
||||||
|
|
||||||
case inputTypes.SELECT:
|
case inputTypes.SELECT:
|
||||||
return SelectInput;
|
return EnhancedSelectInput;
|
||||||
|
|
||||||
case inputTypes.SERIES_TYPE_SELECT:
|
case inputTypes.SERIES_TYPE_SELECT:
|
||||||
return SeriesTypeSelectInput;
|
return SeriesTypeSelectInput;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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 (
|
||||||
|
<EnhancedSelectInputOption
|
||||||
|
isMobile={isMobile}
|
||||||
|
{...otherProps}
|
||||||
|
>
|
||||||
|
<div className={classNames(
|
||||||
|
styles.optionText,
|
||||||
|
isMobile && styles.isMobile
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div>{value}</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
hint != null &&
|
||||||
|
<div className={styles.hintText}>
|
||||||
|
{hint}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</EnhancedSelectInputOption>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
HintedSelectInputOption.propTypes = {
|
||||||
|
value: PropTypes.string.isRequired,
|
||||||
|
hint: PropTypes.node,
|
||||||
|
isMobile: PropTypes.bool.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default HintedSelectInputOption;
|
|
@ -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;
|
||||||
|
}
|
|
@ -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 (
|
||||||
|
<EnhancedSelectInputSelectedValue
|
||||||
|
className={styles.selectedValue}
|
||||||
|
{...otherProps}
|
||||||
|
>
|
||||||
|
<div className={styles.valueText}>
|
||||||
|
{value}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
hint != null && includeHint &&
|
||||||
|
<div className={styles.hintText}>
|
||||||
|
{hint}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</EnhancedSelectInputSelectedValue>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
HintedSelectInputSelectedValue.propTypes = {
|
||||||
|
value: PropTypes.string,
|
||||||
|
hint: PropTypes.string,
|
||||||
|
includeHint: PropTypes.bool.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
HintedSelectInputSelectedValue.defaultProps = {
|
||||||
|
includeHint: true
|
||||||
|
};
|
||||||
|
|
||||||
|
export default HintedSelectInputSelectedValue;
|
|
@ -61,7 +61,7 @@ function EditRemotePathMappingModalContent(props) {
|
||||||
<FormLabel>Host</FormLabel>
|
<FormLabel>Host</FormLabel>
|
||||||
|
|
||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.AUTO_COMPLETE}
|
type={inputTypes.SELECT}
|
||||||
name="host"
|
name="host"
|
||||||
helpText="The same host you specified for the remote Download Client"
|
helpText="The same host you specified for the remote Download Client"
|
||||||
{...host}
|
{...host}
|
||||||
|
|
|
@ -16,17 +16,27 @@ const newRemotePathMapping = {
|
||||||
const selectDownloadClientHosts = createSelector(
|
const selectDownloadClientHosts = createSelector(
|
||||||
(state) => state.settings.downloadClients.items,
|
(state) => state.settings.downloadClients.items,
|
||||||
(downloadClients) => {
|
(downloadClients) => {
|
||||||
return downloadClients.reduce((acc, downloadClient) => {
|
const hosts = downloadClients.reduce((acc, downloadClient) => {
|
||||||
|
const name = downloadClient.name;
|
||||||
const host = downloadClient.fields.find((field) => {
|
const host = downloadClient.fields.find((field) => {
|
||||||
return field.name === 'host';
|
return field.name === 'host';
|
||||||
});
|
});
|
||||||
|
|
||||||
if (host && !acc.includes(host.value)) {
|
if (host) {
|
||||||
acc.push(host.value);
|
const group = acc[host.value] = acc[host.value] || [];
|
||||||
|
group.push(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, []);
|
}, {});
|
||||||
|
|
||||||
|
return Object.keys(hosts).map((host) => {
|
||||||
|
return {
|
||||||
|
key: host,
|
||||||
|
value: host,
|
||||||
|
hint: `${hosts[host].join(', ')}`
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -122,12 +122,12 @@ class Naming extends Component {
|
||||||
const renameEpisodes = hasSettings && settings.renameEpisodes.value;
|
const renameEpisodes = hasSettings && settings.renameEpisodes.value;
|
||||||
|
|
||||||
const multiEpisodeStyleOptions = [
|
const multiEpisodeStyleOptions = [
|
||||||
{ key: 0, value: 'Extend' },
|
{ key: 0, value: 'Extend', hint: 'S01E01-02-03' },
|
||||||
{ key: 1, value: 'Duplicate' },
|
{ key: 1, value: 'Duplicate', hint: 'S01E01.S01E02' },
|
||||||
{ key: 2, value: 'Repeat' },
|
{ key: 2, value: 'Repeat', hint: 'S01E01E02E03' },
|
||||||
{ key: 3, value: 'Scene' },
|
{ key: 3, value: 'Scene', hint: 'S01E01-E02-E03' },
|
||||||
{ key: 4, value: 'Range' },
|
{ key: 4, value: 'Range', hint: 'S01E01-03' },
|
||||||
{ key: 5, value: 'Prefixed Range' }
|
{ key: 5, value: 'Prefixed Range', hint: 'S01E01-E03' }
|
||||||
];
|
];
|
||||||
|
|
||||||
const standardEpisodeFormatHelpTexts = [];
|
const standardEpisodeFormatHelpTexts = [];
|
||||||
|
|
Loading…
Reference in New Issue