mirror of
https://github.com/Sonarr/Sonarr.git
synced 2024-11-24 08:42:19 +02:00
New: Custom Format Language Condition
This commit is contained in:
parent
52760e0908
commit
89b0b04e08
@ -1,4 +1,4 @@
|
||||
.language,
|
||||
.languages,
|
||||
.quality {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
|
@ -6,7 +6,7 @@ import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import EpisodeFormats from 'Episode/EpisodeFormats';
|
||||
import EpisodeLanguage from 'Episode/EpisodeLanguage';
|
||||
import EpisodeLanguages from 'Episode/EpisodeLanguages';
|
||||
import EpisodeQuality from 'Episode/EpisodeQuality';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import SeriesTitleLink from 'Series/SeriesTitleLink';
|
||||
@ -45,7 +45,7 @@ class BlocklistRow extends Component {
|
||||
id,
|
||||
series,
|
||||
sourceTitle,
|
||||
language,
|
||||
languages,
|
||||
quality,
|
||||
customFormats,
|
||||
date,
|
||||
@ -96,14 +96,14 @@ class BlocklistRow extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'language') {
|
||||
if (name === 'languages') {
|
||||
return (
|
||||
<TableRowCell
|
||||
key={name}
|
||||
className={styles.language}
|
||||
className={styles.languages}
|
||||
>
|
||||
<EpisodeLanguage
|
||||
language={language}
|
||||
<EpisodeLanguages
|
||||
languages={languages}
|
||||
/>
|
||||
</TableRowCell>
|
||||
);
|
||||
@ -195,7 +195,7 @@ BlocklistRow.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
series: PropTypes.object.isRequired,
|
||||
sourceTitle: PropTypes.string.isRequired,
|
||||
language: PropTypes.object.isRequired,
|
||||
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
quality: PropTypes.object.isRequired,
|
||||
customFormats: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
date: PropTypes.string.isRequired,
|
||||
|
@ -6,7 +6,7 @@ import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import episodeEntities from 'Episode/episodeEntities';
|
||||
import EpisodeFormats from 'Episode/EpisodeFormats';
|
||||
import EpisodeLanguage from 'Episode/EpisodeLanguage';
|
||||
import EpisodeLanguages from 'Episode/EpisodeLanguages';
|
||||
import EpisodeQuality from 'Episode/EpisodeQuality';
|
||||
import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
|
||||
import SeasonEpisodeNumber from 'Episode/SeasonEpisodeNumber';
|
||||
@ -59,7 +59,7 @@ class HistoryRow extends Component {
|
||||
episodeId,
|
||||
series,
|
||||
episode,
|
||||
language,
|
||||
languages,
|
||||
languageCutoffNotMet,
|
||||
quality,
|
||||
customFormats,
|
||||
@ -144,11 +144,11 @@ class HistoryRow extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'language') {
|
||||
if (name === 'languages') {
|
||||
return (
|
||||
<TableRowCell key={name}>
|
||||
<EpisodeLanguage
|
||||
language={language}
|
||||
<EpisodeLanguages
|
||||
languages={languages}
|
||||
isCutoffMet={languageCutoffNotMet}
|
||||
/>
|
||||
</TableRowCell>
|
||||
@ -278,7 +278,7 @@ HistoryRow.propTypes = {
|
||||
episodeId: PropTypes.number,
|
||||
series: PropTypes.object.isRequired,
|
||||
episode: PropTypes.object,
|
||||
language: PropTypes.object.isRequired,
|
||||
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
languageCutoffNotMet: PropTypes.bool.isRequired,
|
||||
quality: PropTypes.object.isRequired,
|
||||
customFormats: PropTypes.arrayOf(PropTypes.object),
|
||||
|
@ -9,7 +9,7 @@ import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import EpisodeFormats from 'Episode/EpisodeFormats';
|
||||
import EpisodeLanguage from 'Episode/EpisodeLanguage';
|
||||
import EpisodeLanguages from 'Episode/EpisodeLanguages';
|
||||
import EpisodeQuality from 'Episode/EpisodeQuality';
|
||||
import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
|
||||
import SeasonEpisodeNumber from 'Episode/SeasonEpisodeNumber';
|
||||
@ -88,7 +88,7 @@ class QueueRow extends Component {
|
||||
errorMessage,
|
||||
series,
|
||||
episode,
|
||||
language,
|
||||
languages,
|
||||
quality,
|
||||
customFormats,
|
||||
protocol,
|
||||
@ -225,11 +225,11 @@ class QueueRow extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'language') {
|
||||
if (name === 'languages') {
|
||||
return (
|
||||
<TableRowCell key={name}>
|
||||
<EpisodeLanguage
|
||||
language={language}
|
||||
<EpisodeLanguages
|
||||
languages={languages}
|
||||
/>
|
||||
</TableRowCell>
|
||||
);
|
||||
@ -410,7 +410,7 @@ QueueRow.propTypes = {
|
||||
errorMessage: PropTypes.string,
|
||||
series: PropTypes.object,
|
||||
episode: PropTypes.object,
|
||||
language: PropTypes.object.isRequired,
|
||||
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
quality: PropTypes.object.isRequired,
|
||||
customFormats: PropTypes.arrayOf(PropTypes.object),
|
||||
protocol: PropTypes.string.isRequired,
|
||||
|
@ -57,12 +57,6 @@
|
||||
composes: button from '~Components/Link/SpinnerButton.css';
|
||||
}
|
||||
|
||||
.hideLanguageProfile {
|
||||
composes: group from '~Components/Form/FormGroup.css';
|
||||
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: $breakpointSmall) {
|
||||
.modalFooter {
|
||||
display: block;
|
||||
|
@ -47,10 +47,6 @@ class AddNewSeriesModalContent extends Component {
|
||||
this.props.onInputChange({ name: 'qualityProfileId', value: parseInt(value) });
|
||||
};
|
||||
|
||||
onLanguageProfileIdChange = ({ value }) => {
|
||||
this.props.onInputChange({ name: 'languageProfileId', value: parseInt(value) });
|
||||
};
|
||||
|
||||
onAddSeriesPress = () => {
|
||||
const {
|
||||
seriesType
|
||||
@ -74,14 +70,12 @@ class AddNewSeriesModalContent extends Component {
|
||||
rootFolderPath,
|
||||
monitor,
|
||||
qualityProfileId,
|
||||
languageProfileId,
|
||||
seriesType,
|
||||
seasonFolder,
|
||||
searchForMissingEpisodes,
|
||||
searchForCutoffUnmetEpisodes,
|
||||
folder,
|
||||
tags,
|
||||
showLanguageProfile,
|
||||
isSmallScreen,
|
||||
isWindows,
|
||||
onModalClose,
|
||||
@ -180,17 +174,6 @@ class AddNewSeriesModalContent extends Component {
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup className={showLanguageProfile ? undefined : styles.hideLanguageProfile}>
|
||||
<FormLabel>Language Profile</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.LANGUAGE_PROFILE_SELECT}
|
||||
name="languageProfileId"
|
||||
onChange={this.onLanguageProfileIdChange}
|
||||
{...languageProfileId}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>
|
||||
Series Type
|
||||
@ -299,14 +282,12 @@ AddNewSeriesModalContent.propTypes = {
|
||||
rootFolderPath: PropTypes.object,
|
||||
monitor: PropTypes.object.isRequired,
|
||||
qualityProfileId: PropTypes.object,
|
||||
languageProfileId: PropTypes.object,
|
||||
seriesType: PropTypes.object.isRequired,
|
||||
seasonFolder: PropTypes.object.isRequired,
|
||||
searchForMissingEpisodes: PropTypes.object.isRequired,
|
||||
searchForCutoffUnmetEpisodes: PropTypes.object.isRequired,
|
||||
folder: PropTypes.string.isRequired,
|
||||
tags: PropTypes.object.isRequired,
|
||||
showLanguageProfile: PropTypes.bool.isRequired,
|
||||
isSmallScreen: PropTypes.bool.isRequired,
|
||||
isWindows: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired,
|
||||
|
@ -11,10 +11,9 @@ import AddNewSeriesModalContent from './AddNewSeriesModalContent';
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.addSeries,
|
||||
(state) => state.settings.languageProfiles,
|
||||
createDimensionsSelector(),
|
||||
createSystemStatusSelector(),
|
||||
(addSeriesState, languageProfiles, dimensions, systemStatus) => {
|
||||
(addSeriesState, dimensions, systemStatus) => {
|
||||
const {
|
||||
isAdding,
|
||||
addError,
|
||||
@ -30,7 +29,6 @@ function createMapStateToProps() {
|
||||
return {
|
||||
isAdding,
|
||||
addError,
|
||||
showLanguageProfile: languageProfiles.items.length > 1,
|
||||
isSmallScreen: dimensions.isSmallScreen,
|
||||
validationErrors,
|
||||
validationWarnings,
|
||||
@ -61,7 +59,6 @@ class AddNewSeriesModalContentConnector extends Component {
|
||||
rootFolderPath,
|
||||
monitor,
|
||||
qualityProfileId,
|
||||
languageProfileId,
|
||||
seasonFolder,
|
||||
searchForMissingEpisodes,
|
||||
searchForCutoffUnmetEpisodes,
|
||||
@ -73,7 +70,6 @@ class AddNewSeriesModalContentConnector extends Component {
|
||||
rootFolderPath: rootFolderPath.value,
|
||||
monitor: monitor.value,
|
||||
qualityProfileId: qualityProfileId.value,
|
||||
languageProfileId: languageProfileId.value,
|
||||
seriesType,
|
||||
seasonFolder: seasonFolder.value,
|
||||
searchForMissingEpisodes: searchForMissingEpisodes.value,
|
||||
@ -101,7 +97,6 @@ AddNewSeriesModalContentConnector.propTypes = {
|
||||
rootFolderPath: PropTypes.object,
|
||||
monitor: PropTypes.object.isRequired,
|
||||
qualityProfileId: PropTypes.object,
|
||||
languageProfileId: PropTypes.object,
|
||||
seriesType: PropTypes.object.isRequired,
|
||||
seasonFolder: PropTypes.object.isRequired,
|
||||
searchForMissingEpisodes: PropTypes.object.isRequired,
|
||||
|
@ -84,8 +84,7 @@ class ImportSeries extends Component {
|
||||
rootFoldersFetching,
|
||||
rootFoldersPopulated,
|
||||
rootFoldersError,
|
||||
unmappedFolders,
|
||||
showLanguageProfile
|
||||
unmappedFolders
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
@ -135,7 +134,6 @@ class ImportSeries extends Component {
|
||||
allUnselected={allUnselected}
|
||||
selectedState={selectedState}
|
||||
scroller={scroller}
|
||||
showLanguageProfile={showLanguageProfile}
|
||||
onSelectAllChange={this.onSelectAllChange}
|
||||
onSelectedChange={this.onSelectedChange}
|
||||
onRemoveSelectedStateItem={this.onRemoveSelectedStateItem}
|
||||
@ -150,7 +148,6 @@ class ImportSeries extends Component {
|
||||
!!unmappedFolders.length ?
|
||||
<ImportSeriesFooterConnector
|
||||
selectedIds={this.getSelectedIds()}
|
||||
showLanguageProfile={showLanguageProfile}
|
||||
onInputChange={this.onInputChange}
|
||||
onImportPress={this.onImportPress}
|
||||
/> :
|
||||
@ -169,7 +166,6 @@ ImportSeries.propTypes = {
|
||||
rootFoldersError: PropTypes.object,
|
||||
unmappedFolders: PropTypes.arrayOf(PropTypes.object),
|
||||
items: PropTypes.arrayOf(PropTypes.object),
|
||||
showLanguageProfile: PropTypes.bool.isRequired,
|
||||
onInputChange: PropTypes.func.isRequired,
|
||||
onImportPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
@ -16,14 +16,12 @@ function createMapStateToProps() {
|
||||
(state) => state.addSeries,
|
||||
(state) => state.importSeries,
|
||||
(state) => state.settings.qualityProfiles,
|
||||
(state) => state.settings.languageProfiles,
|
||||
(
|
||||
match,
|
||||
rootFolders,
|
||||
addSeries,
|
||||
importSeriesState,
|
||||
qualityProfiles,
|
||||
languageProfiles
|
||||
qualityProfiles
|
||||
) => {
|
||||
const {
|
||||
isFetching: rootFoldersFetching,
|
||||
@ -40,10 +38,7 @@ function createMapStateToProps() {
|
||||
rootFoldersPopulated,
|
||||
rootFoldersError,
|
||||
qualityProfiles: qualityProfiles.items,
|
||||
languageProfiles: languageProfiles.items,
|
||||
showLanguageProfile: languageProfiles.items.length > 1,
|
||||
defaultQualityProfileId: addSeries.defaults.qualityProfileId,
|
||||
defaultLanguageProfileId: addSeries.defaults.languageProfileId
|
||||
defaultQualityProfileId: addSeries.defaults.qualityProfileId
|
||||
};
|
||||
|
||||
if (items.length) {
|
||||
@ -78,9 +73,7 @@ class ImportSeriesConnector extends Component {
|
||||
const {
|
||||
rootFolderId,
|
||||
qualityProfiles,
|
||||
languageProfiles,
|
||||
defaultQualityProfileId,
|
||||
defaultLanguageProfileId,
|
||||
dispatchFetchRootFolders,
|
||||
dispatchSetAddSeriesDefault
|
||||
} = this.props;
|
||||
@ -98,14 +91,6 @@ class ImportSeriesConnector extends Component {
|
||||
setDefaultPayload.qualityProfileId = qualityProfiles[0].id;
|
||||
}
|
||||
|
||||
if (
|
||||
!defaultLanguageProfileId ||
|
||||
!languageProfiles.some((p) => p.id === defaultLanguageProfileId)
|
||||
) {
|
||||
setDefaults = true;
|
||||
setDefaultPayload.languageProfileId = languageProfiles[0].id;
|
||||
}
|
||||
|
||||
if (setDefaults) {
|
||||
dispatchSetAddSeriesDefault(setDefaultPayload);
|
||||
}
|
||||
@ -157,9 +142,7 @@ ImportSeriesConnector.propTypes = {
|
||||
rootFoldersFetching: PropTypes.bool.isRequired,
|
||||
rootFoldersPopulated: PropTypes.bool.isRequired,
|
||||
qualityProfiles: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
languageProfiles: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
defaultQualityProfileId: PropTypes.number.isRequired,
|
||||
defaultLanguageProfileId: PropTypes.number.isRequired,
|
||||
dispatchSetImportSeriesValue: PropTypes.func.isRequired,
|
||||
dispatchImportSeries: PropTypes.func.isRequired,
|
||||
dispatchClearImportSeries: PropTypes.func.isRequired,
|
||||
|
@ -25,7 +25,6 @@ class ImportSeriesFooter extends Component {
|
||||
const {
|
||||
defaultMonitor,
|
||||
defaultQualityProfileId,
|
||||
defaultLanguageProfileId,
|
||||
defaultSeasonFolder,
|
||||
defaultSeriesType
|
||||
} = props;
|
||||
@ -33,7 +32,6 @@ class ImportSeriesFooter extends Component {
|
||||
this.state = {
|
||||
monitor: defaultMonitor,
|
||||
qualityProfileId: defaultQualityProfileId,
|
||||
languageProfileId: defaultLanguageProfileId,
|
||||
seriesType: defaultSeriesType,
|
||||
seasonFolder: defaultSeasonFolder
|
||||
};
|
||||
@ -43,12 +41,10 @@ class ImportSeriesFooter extends Component {
|
||||
const {
|
||||
defaultMonitor,
|
||||
defaultQualityProfileId,
|
||||
defaultLanguageProfileId,
|
||||
defaultSeriesType,
|
||||
defaultSeasonFolder,
|
||||
isMonitorMixed,
|
||||
isQualityProfileIdMixed,
|
||||
isLanguageProfileIdMixed,
|
||||
isSeriesTypeMixed,
|
||||
isSeasonFolderMixed
|
||||
} = this.props;
|
||||
@ -56,7 +52,6 @@ class ImportSeriesFooter extends Component {
|
||||
const {
|
||||
monitor,
|
||||
qualityProfileId,
|
||||
languageProfileId,
|
||||
seriesType,
|
||||
seasonFolder
|
||||
} = this.state;
|
||||
@ -75,12 +70,6 @@ class ImportSeriesFooter extends Component {
|
||||
newState.qualityProfileId = defaultQualityProfileId;
|
||||
}
|
||||
|
||||
if (isLanguageProfileIdMixed && languageProfileId !== MIXED) {
|
||||
newState.languageProfileId = MIXED;
|
||||
} else if (!isLanguageProfileIdMixed && languageProfileId !== defaultLanguageProfileId) {
|
||||
newState.languageProfileId = defaultLanguageProfileId;
|
||||
}
|
||||
|
||||
if (isSeriesTypeMixed && seriesType !== MIXED) {
|
||||
newState.seriesType = MIXED;
|
||||
} else if (!isSeriesTypeMixed && seriesType !== defaultSeriesType) {
|
||||
@ -116,10 +105,8 @@ class ImportSeriesFooter extends Component {
|
||||
isLookingUpSeries,
|
||||
isMonitorMixed,
|
||||
isQualityProfileIdMixed,
|
||||
isLanguageProfileIdMixed,
|
||||
isSeriesTypeMixed,
|
||||
hasUnsearchedItems,
|
||||
showLanguageProfile,
|
||||
importError,
|
||||
onImportPress,
|
||||
onLookupPress,
|
||||
@ -129,7 +116,6 @@ class ImportSeriesFooter extends Component {
|
||||
const {
|
||||
monitor,
|
||||
qualityProfileId,
|
||||
languageProfileId,
|
||||
seriesType,
|
||||
seasonFolder
|
||||
} = this.state;
|
||||
@ -166,24 +152,6 @@ class ImportSeriesFooter extends Component {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{
|
||||
showLanguageProfile &&
|
||||
<div className={styles.inputContainer}>
|
||||
<div className={styles.label}>
|
||||
Language Profile
|
||||
</div>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.LANGUAGE_PROFILE_SELECT}
|
||||
name="languageProfileId"
|
||||
value={languageProfileId}
|
||||
isDisabled={!selectedCount}
|
||||
includeMixed={isLanguageProfileIdMixed}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div className={styles.inputContainer}>
|
||||
<div className={styles.label}>
|
||||
Series Type
|
||||
@ -308,16 +276,13 @@ ImportSeriesFooter.propTypes = {
|
||||
isLookingUpSeries: PropTypes.bool.isRequired,
|
||||
defaultMonitor: PropTypes.string.isRequired,
|
||||
defaultQualityProfileId: PropTypes.number,
|
||||
defaultLanguageProfileId: PropTypes.number,
|
||||
defaultSeriesType: PropTypes.string.isRequired,
|
||||
defaultSeasonFolder: PropTypes.bool.isRequired,
|
||||
isMonitorMixed: PropTypes.bool.isRequired,
|
||||
isQualityProfileIdMixed: PropTypes.bool.isRequired,
|
||||
isLanguageProfileIdMixed: PropTypes.bool.isRequired,
|
||||
isSeriesTypeMixed: PropTypes.bool.isRequired,
|
||||
isSeasonFolderMixed: PropTypes.bool.isRequired,
|
||||
hasUnsearchedItems: PropTypes.bool.isRequired,
|
||||
showLanguageProfile: PropTypes.bool.isRequired,
|
||||
importError: PropTypes.object,
|
||||
onInputChange: PropTypes.func.isRequired,
|
||||
onImportPress: PropTypes.func.isRequired,
|
||||
|
@ -19,7 +19,6 @@ function createMapStateToProps() {
|
||||
const {
|
||||
monitor: defaultMonitor,
|
||||
qualityProfileId: defaultQualityProfileId,
|
||||
languageProfileId: defaultLanguageProfileId,
|
||||
seriesType: defaultSeriesType,
|
||||
seasonFolder: defaultSeasonFolder
|
||||
} = addSeries.defaults;
|
||||
@ -33,7 +32,6 @@ function createMapStateToProps() {
|
||||
|
||||
const isMonitorMixed = isMixed(items, selectedIds, defaultMonitor, 'monitor');
|
||||
const isQualityProfileIdMixed = isMixed(items, selectedIds, defaultQualityProfileId, 'qualityProfileId');
|
||||
const isLanguageProfileIdMixed = isMixed(items, selectedIds, defaultLanguageProfileId, 'languageProfileId');
|
||||
const isSeriesTypeMixed = isMixed(items, selectedIds, defaultSeriesType, 'seriesType');
|
||||
const isSeasonFolderMixed = isMixed(items, selectedIds, defaultSeasonFolder, 'seasonFolder');
|
||||
const hasUnsearchedItems = !isLookingUpSeries && items.some((item) => !item.isPopulated);
|
||||
@ -44,12 +42,10 @@ function createMapStateToProps() {
|
||||
isImporting,
|
||||
defaultMonitor,
|
||||
defaultQualityProfileId,
|
||||
defaultLanguageProfileId,
|
||||
defaultSeriesType,
|
||||
defaultSeasonFolder,
|
||||
isMonitorMixed,
|
||||
isQualityProfileIdMixed,
|
||||
isLanguageProfileIdMixed,
|
||||
isSeriesTypeMixed,
|
||||
isSeasonFolderMixed,
|
||||
importError,
|
||||
|
@ -11,8 +11,7 @@
|
||||
min-width: 185px;
|
||||
}
|
||||
|
||||
.qualityProfile,
|
||||
.languageProfile {
|
||||
.qualityProfile {
|
||||
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
|
||||
|
||||
flex: 0 1 250px;
|
||||
|
@ -12,7 +12,6 @@ import styles from './ImportSeriesHeader.css';
|
||||
|
||||
function ImportSeriesHeader(props) {
|
||||
const {
|
||||
showLanguageProfile,
|
||||
allSelected,
|
||||
allUnselected,
|
||||
onSelectAllChange
|
||||
@ -59,16 +58,6 @@ function ImportSeriesHeader(props) {
|
||||
Quality Profile
|
||||
</VirtualTableHeaderCell>
|
||||
|
||||
{
|
||||
showLanguageProfile &&
|
||||
<VirtualTableHeaderCell
|
||||
className={styles.languageProfile}
|
||||
name="languageProfileId"
|
||||
>
|
||||
Language Profile
|
||||
</VirtualTableHeaderCell>
|
||||
}
|
||||
|
||||
<VirtualTableHeaderCell
|
||||
className={styles.seriesType}
|
||||
name="seriesType"
|
||||
@ -106,7 +95,6 @@ function ImportSeriesHeader(props) {
|
||||
}
|
||||
|
||||
ImportSeriesHeader.propTypes = {
|
||||
showLanguageProfile: PropTypes.bool.isRequired,
|
||||
allSelected: PropTypes.bool.isRequired,
|
||||
allUnselected: PropTypes.bool.isRequired,
|
||||
onSelectAllChange: PropTypes.func.isRequired
|
||||
|
@ -16,8 +16,7 @@
|
||||
min-width: 185px;
|
||||
}
|
||||
|
||||
.qualityProfile,
|
||||
.languageProfile {
|
||||
.qualityProfile {
|
||||
composes: cell from '~Components/Table/Cells/VirtualTableRowCell.css';
|
||||
|
||||
flex: 0 1 250px;
|
||||
@ -44,9 +43,3 @@
|
||||
flex: 0 1 400px;
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
.hideLanguageProfile {
|
||||
composes: cell from '~Components/Table/Cells/VirtualTableRowCell.css';
|
||||
|
||||
display: none;
|
||||
}
|
||||
|
@ -12,12 +12,10 @@ function ImportSeriesRow(props) {
|
||||
id,
|
||||
monitor,
|
||||
qualityProfileId,
|
||||
languageProfileId,
|
||||
seasonFolder,
|
||||
seriesType,
|
||||
selectedSeries,
|
||||
isExistingSeries,
|
||||
showLanguageProfile,
|
||||
isSelected,
|
||||
onSelectedChange,
|
||||
onInputChange
|
||||
@ -55,17 +53,6 @@ function ImportSeriesRow(props) {
|
||||
/>
|
||||
</VirtualTableRowCell>
|
||||
|
||||
<VirtualTableRowCell
|
||||
className={showLanguageProfile ? styles.languageProfile : styles.hideLanguageProfile}
|
||||
>
|
||||
<FormInputGroup
|
||||
type={inputTypes.LANGUAGE_PROFILE_SELECT}
|
||||
name="languageProfileId"
|
||||
value={languageProfileId}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</VirtualTableRowCell>
|
||||
|
||||
<VirtualTableRowCell className={styles.seriesType}>
|
||||
<FormInputGroup
|
||||
type={inputTypes.SERIES_TYPE_SELECT}
|
||||
@ -99,13 +86,11 @@ ImportSeriesRow.propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
monitor: PropTypes.string.isRequired,
|
||||
qualityProfileId: PropTypes.number.isRequired,
|
||||
languageProfileId: PropTypes.number.isRequired,
|
||||
seriesType: PropTypes.string.isRequired,
|
||||
seasonFolder: PropTypes.bool.isRequired,
|
||||
selectedSeries: PropTypes.object,
|
||||
isExistingSeries: PropTypes.bool.isRequired,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
showLanguageProfile: PropTypes.bool.isRequired,
|
||||
isSelected: PropTypes.bool,
|
||||
onSelectedChange: PropTypes.func.isRequired,
|
||||
onInputChange: PropTypes.func.isRequired
|
||||
|
@ -16,7 +16,6 @@ class ImportSeriesTable extends Component {
|
||||
unmappedFolders,
|
||||
defaultMonitor,
|
||||
defaultQualityProfileId,
|
||||
defaultLanguageProfileId,
|
||||
defaultSeriesType,
|
||||
defaultSeasonFolder,
|
||||
onSeriesLookup,
|
||||
@ -26,7 +25,6 @@ class ImportSeriesTable extends Component {
|
||||
const values = {
|
||||
monitor: defaultMonitor,
|
||||
qualityProfileId: defaultQualityProfileId,
|
||||
languageProfileId: defaultLanguageProfileId,
|
||||
seriesType: defaultSeriesType,
|
||||
seasonFolder: defaultSeasonFolder
|
||||
};
|
||||
@ -106,7 +104,6 @@ class ImportSeriesTable extends Component {
|
||||
rootFolderId,
|
||||
items,
|
||||
selectedState,
|
||||
showLanguageProfile,
|
||||
onSelectedChange
|
||||
} = this.props;
|
||||
|
||||
@ -120,7 +117,6 @@ class ImportSeriesTable extends Component {
|
||||
<ImportSeriesRowConnector
|
||||
key={item.id}
|
||||
rootFolderId={rootFolderId}
|
||||
showLanguageProfile={showLanguageProfile}
|
||||
isSelected={selectedState[item.id]}
|
||||
onSelectedChange={onSelectedChange}
|
||||
id={item.id}
|
||||
@ -139,7 +135,6 @@ class ImportSeriesTable extends Component {
|
||||
allUnselected,
|
||||
isSmallScreen,
|
||||
scroller,
|
||||
showLanguageProfile,
|
||||
selectedState,
|
||||
onSelectAllChange
|
||||
} = this.props;
|
||||
@ -158,7 +153,6 @@ class ImportSeriesTable extends Component {
|
||||
rowRenderer={this.rowRenderer}
|
||||
header={
|
||||
<ImportSeriesHeader
|
||||
showLanguageProfile={showLanguageProfile}
|
||||
allSelected={allSelected}
|
||||
allUnselected={allUnselected}
|
||||
onSelectAllChange={onSelectAllChange}
|
||||
@ -176,7 +170,6 @@ ImportSeriesTable.propTypes = {
|
||||
unmappedFolders: PropTypes.arrayOf(PropTypes.object),
|
||||
defaultMonitor: PropTypes.string.isRequired,
|
||||
defaultQualityProfileId: PropTypes.number,
|
||||
defaultLanguageProfileId: PropTypes.number,
|
||||
defaultSeriesType: PropTypes.string.isRequired,
|
||||
defaultSeasonFolder: PropTypes.bool.isRequired,
|
||||
allSelected: PropTypes.bool.isRequired,
|
||||
@ -185,7 +178,6 @@ ImportSeriesTable.propTypes = {
|
||||
isSmallScreen: PropTypes.bool.isRequired,
|
||||
allSeries: PropTypes.arrayOf(PropTypes.object),
|
||||
scroller: PropTypes.instanceOf(Element).isRequired,
|
||||
showLanguageProfile: PropTypes.bool.isRequired,
|
||||
onSelectAllChange: PropTypes.func.isRequired,
|
||||
onSelectedChange: PropTypes.func.isRequired,
|
||||
onRemoveSelectedStateItem: PropTypes.func.isRequired,
|
||||
|
@ -14,7 +14,6 @@ function createMapStateToProps() {
|
||||
return {
|
||||
defaultMonitor: addSeries.defaults.monitor,
|
||||
defaultQualityProfileId: addSeries.defaults.qualityProfileId,
|
||||
defaultLanguageProfileId: addSeries.defaults.languageProfileId,
|
||||
defaultSeriesType: addSeries.defaults.seriesType,
|
||||
defaultSeasonFolder: addSeries.defaults.seasonFolder,
|
||||
items: importSeries.items,
|
||||
|
@ -175,19 +175,6 @@ class AgendaEvent extends Component {
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
showCutoffUnmetIcon &&
|
||||
!!episodeFile &&
|
||||
episodeFile.languageCutoffNotMet &&
|
||||
!episodeFile.qualityCutoffNotMet &&
|
||||
<Icon
|
||||
className={styles.statusIcon}
|
||||
name={icons.EPISODE_FILE}
|
||||
kind={kinds.WARNING}
|
||||
title="Language cutoff has not been met"
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
episodeNumber === 1 && seasonNumber > 0 &&
|
||||
<Icon
|
||||
|
@ -152,20 +152,6 @@ class CalendarEvent extends Component {
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
showCutoffUnmetIcon &&
|
||||
!!episodeFile &&
|
||||
episodeFile.languageCutoffNotMet &&
|
||||
!episodeFile.qualityCutoffNotMet ?
|
||||
<Icon
|
||||
className={styles.statusIcon}
|
||||
name={icons.EPISODE_FILE}
|
||||
kind={fullColorEvents ? kinds.DEFAULT : kinds.WARNING}
|
||||
title="Language cutoff has not been met"
|
||||
/> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
episodeNumber === 1 && seasonNumber > 0 ?
|
||||
<Icon
|
||||
|
@ -47,7 +47,7 @@ function Legend(props) {
|
||||
name="Cutoff Not Met"
|
||||
icon={icons.EPISODE_FILE}
|
||||
kind={fullColorEvents ? kinds.DEFAULT : kinds.WARNING}
|
||||
tooltip="Quality or language cutoff has not been met"
|
||||
tooltip="Quality cutoff has not been met"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import BoolFilterBuilderRowValue from './BoolFilterBuilderRowValue';
|
||||
import DateFilterBuilderRowValue from './DateFilterBuilderRowValue';
|
||||
import FilterBuilderRowValueConnector from './FilterBuilderRowValueConnector';
|
||||
import IndexerFilterBuilderRowValueConnector from './IndexerFilterBuilderRowValueConnector';
|
||||
import LanguageProfileFilterBuilderRowValueConnector from './LanguageProfileFilterBuilderRowValueConnector';
|
||||
import ProtocolFilterBuilderRowValue from './ProtocolFilterBuilderRowValue';
|
||||
import QualityFilterBuilderRowValueConnector from './QualityFilterBuilderRowValueConnector';
|
||||
import QualityProfileFilterBuilderRowValueConnector from './QualityProfileFilterBuilderRowValueConnector';
|
||||
@ -61,9 +60,6 @@ function getRowValueConnector(selectedFilterBuilderProp) {
|
||||
case filterBuilderValueTypes.INDEXER:
|
||||
return IndexerFilterBuilderRowValueConnector;
|
||||
|
||||
case filterBuilderValueTypes.LANGUAGE_PROFILE:
|
||||
return LanguageProfileFilterBuilderRowValueConnector;
|
||||
|
||||
case filterBuilderValueTypes.PROTOCOL:
|
||||
return ProtocolFilterBuilderRowValue;
|
||||
|
||||
|
@ -1,28 +0,0 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import FilterBuilderRowValue from './FilterBuilderRowValue';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.settings.languageProfiles,
|
||||
(languageProfiles) => {
|
||||
const tagList = languageProfiles.items.map((languageProfile) => {
|
||||
const {
|
||||
id,
|
||||
name
|
||||
} = languageProfile;
|
||||
|
||||
return {
|
||||
id,
|
||||
name
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
tagList
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(createMapStateToProps)(FilterBuilderRowValue);
|
@ -12,7 +12,6 @@ import EnhancedSelectInputConnector from './EnhancedSelectInputConnector';
|
||||
import FormInputHelpText from './FormInputHelpText';
|
||||
import IndexerSelectInputConnector from './IndexerSelectInputConnector';
|
||||
import KeyValueListInput from './KeyValueListInput';
|
||||
import LanguageProfileSelectInputConnector from './LanguageProfileSelectInputConnector';
|
||||
import MonitorEpisodesSelectInput from './MonitorEpisodesSelectInput';
|
||||
import NumberInput from './NumberInput';
|
||||
import OAuthInputConnector from './OAuthInputConnector';
|
||||
@ -64,9 +63,6 @@ function getComponent(type) {
|
||||
case inputTypes.QUALITY_PROFILE_SELECT:
|
||||
return QualityProfileSelectInputConnector;
|
||||
|
||||
case inputTypes.LANGUAGE_PROFILE_SELECT:
|
||||
return LanguageProfileSelectInputConnector;
|
||||
|
||||
case inputTypes.INDEXER_SELECT:
|
||||
return IndexerSelectInputConnector;
|
||||
|
||||
|
@ -1,99 +0,0 @@
|
||||
import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector';
|
||||
import sortByName from 'Utilities/Array/sortByName';
|
||||
import SelectInput from './SelectInput';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createSortedSectionSelector('settings.languageProfiles', sortByName),
|
||||
(state, { includeNoChange }) => includeNoChange,
|
||||
(state, { includeMixed }) => includeMixed,
|
||||
(languageProfiles, includeNoChange, includeMixed) => {
|
||||
const values = _.map(languageProfiles.items, (languageProfile) => {
|
||||
return {
|
||||
key: languageProfile.id,
|
||||
value: languageProfile.name
|
||||
};
|
||||
});
|
||||
|
||||
if (includeNoChange) {
|
||||
values.unshift({
|
||||
key: 'noChange',
|
||||
value: 'No Change',
|
||||
disabled: true
|
||||
});
|
||||
}
|
||||
|
||||
if (includeMixed) {
|
||||
values.unshift({
|
||||
key: 'mixed',
|
||||
value: '(Mixed)',
|
||||
disabled: true
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
values
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
class LanguageProfileSelectInputConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
name,
|
||||
value,
|
||||
values
|
||||
} = this.props;
|
||||
|
||||
if (!value || !_.some(values, (option) => parseInt(option.key) === value)) {
|
||||
const firstValue = _.find(values, (option) => !isNaN(parseInt(option.key)));
|
||||
|
||||
if (firstValue) {
|
||||
this.onChange({ name, value: firstValue.key });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onChange = ({ name, value }) => {
|
||||
this.props.onChange({ name, value: parseInt(value) });
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<SelectInput
|
||||
{...this.props}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LanguageProfileSelectInputConnector.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
values: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
includeNoChange: PropTypes.bool.isRequired,
|
||||
onChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
LanguageProfileSelectInputConnector.defaultProps = {
|
||||
includeNoChange: false
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps)(LanguageProfileSelectInputConnector);
|
52
frontend/src/Components/Form/LanguageSelectInputConnector.js
Normal file
52
frontend/src/Components/Form/LanguageSelectInputConnector.js
Normal file
@ -0,0 +1,52 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import EnhancedSelectInput from './EnhancedSelectInput';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state, { values }) => values,
|
||||
( languages ) => {
|
||||
|
||||
const minId = languages.reduce((min, v) => (v.key < 1 ? v.key : min), languages[0].key);
|
||||
|
||||
const values = languages.map(({ key, value }) => {
|
||||
return {
|
||||
key,
|
||||
value,
|
||||
dividerAfter: minId < 1 ? key === minId : false
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
values
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
class LanguageSelectInputConnector extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<EnhancedSelectInput
|
||||
{...this.props}
|
||||
onChange={this.props.onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LanguageSelectInputConnector.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
value: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.number]).isRequired,
|
||||
values: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
onChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps)(LanguageSelectInputConnector);
|
@ -11,7 +11,6 @@ function ErrorPage(props) {
|
||||
customFiltersError,
|
||||
tagsError,
|
||||
qualityProfilesError,
|
||||
languageProfilesError,
|
||||
uiSettingsError,
|
||||
systemStatusError
|
||||
} = props;
|
||||
@ -28,8 +27,6 @@ function ErrorPage(props) {
|
||||
errorMessage = getErrorMessage(tagsError, 'Failed to load tags from API');
|
||||
} else if (qualityProfilesError) {
|
||||
errorMessage = getErrorMessage(qualityProfilesError, 'Failed to load quality profiles from API');
|
||||
} else if (languageProfilesError) {
|
||||
errorMessage = getErrorMessage(languageProfilesError, 'Failed to load language profiles from API');
|
||||
} else if (uiSettingsError) {
|
||||
errorMessage = getErrorMessage(uiSettingsError, 'Failed to load UI settings from API');
|
||||
} else if (systemStatusError) {
|
||||
@ -56,7 +53,6 @@ ErrorPage.propTypes = {
|
||||
customFiltersError: PropTypes.object,
|
||||
tagsError: PropTypes.object,
|
||||
qualityProfilesError: PropTypes.object,
|
||||
languageProfilesError: PropTypes.object,
|
||||
uiSettingsError: PropTypes.object,
|
||||
systemStatusError: PropTypes.object
|
||||
};
|
||||
|
@ -6,7 +6,7 @@ import { createSelector } from 'reselect';
|
||||
import { saveDimensions, setIsSidebarVisible } from 'Store/Actions/appActions';
|
||||
import { fetchCustomFilters } from 'Store/Actions/customFilterActions';
|
||||
import { fetchSeries } from 'Store/Actions/seriesActions';
|
||||
import { fetchImportLists, fetchLanguageProfiles, fetchQualityProfiles, fetchUISettings } from 'Store/Actions/settingsActions';
|
||||
import { fetchImportLists, fetchLanguages, fetchQualityProfiles, fetchUISettings } from 'Store/Actions/settingsActions';
|
||||
import { fetchStatus } from 'Store/Actions/systemActions';
|
||||
import { fetchTags } from 'Store/Actions/tagActions';
|
||||
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
||||
@ -49,7 +49,7 @@ const selectIsPopulated = createSelector(
|
||||
(state) => state.tags.isPopulated,
|
||||
(state) => state.settings.ui.isPopulated,
|
||||
(state) => state.settings.qualityProfiles.isPopulated,
|
||||
(state) => state.settings.languageProfiles.isPopulated,
|
||||
(state) => state.settings.languages.isPopulated,
|
||||
(state) => state.settings.importLists.isPopulated,
|
||||
(state) => state.system.status.isPopulated,
|
||||
(
|
||||
@ -58,7 +58,7 @@ const selectIsPopulated = createSelector(
|
||||
tagsIsPopulated,
|
||||
uiSettingsIsPopulated,
|
||||
qualityProfilesIsPopulated,
|
||||
languageProfilesIsPopulated,
|
||||
languagesIsPopulated,
|
||||
importListsIsPopulated,
|
||||
systemStatusIsPopulated
|
||||
) => {
|
||||
@ -68,7 +68,7 @@ const selectIsPopulated = createSelector(
|
||||
tagsIsPopulated &&
|
||||
uiSettingsIsPopulated &&
|
||||
qualityProfilesIsPopulated &&
|
||||
languageProfilesIsPopulated &&
|
||||
languagesIsPopulated &&
|
||||
importListsIsPopulated &&
|
||||
systemStatusIsPopulated
|
||||
);
|
||||
@ -81,7 +81,7 @@ const selectErrors = createSelector(
|
||||
(state) => state.tags.error,
|
||||
(state) => state.settings.ui.error,
|
||||
(state) => state.settings.qualityProfiles.error,
|
||||
(state) => state.settings.languageProfiles.error,
|
||||
(state) => state.settings.languages.error,
|
||||
(state) => state.settings.importLists.error,
|
||||
(state) => state.system.status.error,
|
||||
(
|
||||
@ -90,7 +90,7 @@ const selectErrors = createSelector(
|
||||
tagsError,
|
||||
uiSettingsError,
|
||||
qualityProfilesError,
|
||||
languageProfilesError,
|
||||
languagesError,
|
||||
importListsError,
|
||||
systemStatusError
|
||||
) => {
|
||||
@ -100,7 +100,7 @@ const selectErrors = createSelector(
|
||||
tagsError ||
|
||||
uiSettingsError ||
|
||||
qualityProfilesError ||
|
||||
languageProfilesError ||
|
||||
languagesError ||
|
||||
importListsError ||
|
||||
systemStatusError
|
||||
);
|
||||
@ -112,7 +112,7 @@ const selectErrors = createSelector(
|
||||
tagsError,
|
||||
uiSettingsError,
|
||||
qualityProfilesError,
|
||||
languageProfilesError,
|
||||
languagesError,
|
||||
importListsError,
|
||||
systemStatusError
|
||||
};
|
||||
@ -161,8 +161,8 @@ function createMapDispatchToProps(dispatch, props) {
|
||||
dispatchFetchQualityProfiles() {
|
||||
dispatch(fetchQualityProfiles());
|
||||
},
|
||||
dispatchFetchLanguageProfiles() {
|
||||
dispatch(fetchLanguageProfiles());
|
||||
dispatchFetchLanguages() {
|
||||
dispatch(fetchLanguages());
|
||||
},
|
||||
dispatchFetchImportLists() {
|
||||
dispatch(fetchImportLists());
|
||||
@ -201,7 +201,7 @@ class PageConnector extends Component {
|
||||
this.props.dispatchFetchCustomFilters();
|
||||
this.props.dispatchFetchTags();
|
||||
this.props.dispatchFetchQualityProfiles();
|
||||
this.props.dispatchFetchLanguageProfiles();
|
||||
this.props.dispatchFetchLanguages();
|
||||
this.props.dispatchFetchImportLists();
|
||||
this.props.dispatchFetchUISettings();
|
||||
this.props.dispatchFetchStatus();
|
||||
@ -225,7 +225,7 @@ class PageConnector extends Component {
|
||||
dispatchFetchSeries,
|
||||
dispatchFetchTags,
|
||||
dispatchFetchQualityProfiles,
|
||||
dispatchFetchLanguageProfiles,
|
||||
dispatchFetchLanguages,
|
||||
dispatchFetchImportLists,
|
||||
dispatchFetchUISettings,
|
||||
dispatchFetchStatus,
|
||||
@ -264,7 +264,7 @@ PageConnector.propTypes = {
|
||||
dispatchFetchCustomFilters: PropTypes.func.isRequired,
|
||||
dispatchFetchTags: PropTypes.func.isRequired,
|
||||
dispatchFetchQualityProfiles: PropTypes.func.isRequired,
|
||||
dispatchFetchLanguageProfiles: PropTypes.func.isRequired,
|
||||
dispatchFetchLanguages: PropTypes.func.isRequired,
|
||||
dispatchFetchImportLists: PropTypes.func.isRequired,
|
||||
dispatchFetchUISettings: PropTypes.func.isRequired,
|
||||
dispatchFetchStatus: PropTypes.func.isRequired,
|
||||
|
@ -1,37 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Label from 'Components/Label';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
|
||||
function EpisodeLanguage(props) {
|
||||
const {
|
||||
className,
|
||||
language,
|
||||
isCutoffNotMet
|
||||
} = props;
|
||||
|
||||
if (!language) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Label
|
||||
className={className}
|
||||
kind={isCutoffNotMet ? kinds.INVERSE : kinds.DEFAULT}
|
||||
>
|
||||
{language.name}
|
||||
</Label>
|
||||
);
|
||||
}
|
||||
|
||||
EpisodeLanguage.propTypes = {
|
||||
className: PropTypes.string,
|
||||
language: PropTypes.object,
|
||||
isCutoffNotMet: PropTypes.bool
|
||||
};
|
||||
|
||||
EpisodeLanguage.defaultProps = {
|
||||
isCutoffNotMet: true
|
||||
};
|
||||
|
||||
export default EpisodeLanguage;
|
69
frontend/src/Episode/EpisodeLanguages.js
Normal file
69
frontend/src/Episode/EpisodeLanguages.js
Normal file
@ -0,0 +1,69 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Label from 'Components/Label';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import { kinds, tooltipPositions } from 'Helpers/Props';
|
||||
|
||||
function EpisodeLanguages(props) {
|
||||
const {
|
||||
className,
|
||||
languages,
|
||||
isCutoffNotMet
|
||||
} = props;
|
||||
|
||||
if (!languages) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (languages.length === 1) {
|
||||
return (
|
||||
<Label
|
||||
className={className}
|
||||
kind={isCutoffNotMet ? kinds.INVERSE : kinds.DEFAULT}
|
||||
>
|
||||
{languages[0].name}
|
||||
</Label>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Popover
|
||||
className={className}
|
||||
anchor={
|
||||
<Label
|
||||
className={className}
|
||||
kind={isCutoffNotMet ? kinds.INVERSE : kinds.DEFAULT}
|
||||
>
|
||||
Multi-Languages
|
||||
</Label>
|
||||
}
|
||||
title={'Languages'}
|
||||
body={
|
||||
<ul>
|
||||
{
|
||||
languages.map((language) => {
|
||||
return (
|
||||
<li key={language.id}>
|
||||
{language.name}
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
position={tooltipPositions.LEFT}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
EpisodeLanguages.propTypes = {
|
||||
className: PropTypes.string,
|
||||
languages: PropTypes.arrayOf(PropTypes.object),
|
||||
isCutoffNotMet: PropTypes.bool
|
||||
};
|
||||
|
||||
EpisodeLanguages.defaultProps = {
|
||||
isCutoffNotMet: true
|
||||
};
|
||||
|
||||
export default EpisodeLanguages;
|
@ -18,8 +18,8 @@ const columns = [
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'language',
|
||||
label: 'Language',
|
||||
name: 'languages',
|
||||
label: 'Languages',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
|
@ -11,7 +11,7 @@ import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import Tooltip from 'Components/Tooltip/Tooltip';
|
||||
import EpisodeLanguage from 'Episode/EpisodeLanguage';
|
||||
import EpisodeLanguages from 'Episode/EpisodeLanguages';
|
||||
import EpisodeQuality from 'Episode/EpisodeQuality';
|
||||
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import formatPreferredWordScore from 'Utilities/Number/formatPreferredWordScore';
|
||||
@ -65,7 +65,7 @@ class EpisodeHistoryRow extends Component {
|
||||
const {
|
||||
eventType,
|
||||
sourceTitle,
|
||||
language,
|
||||
languages,
|
||||
languageCutoffNotMet,
|
||||
quality,
|
||||
qualityCutoffNotMet,
|
||||
@ -90,8 +90,8 @@ class EpisodeHistoryRow extends Component {
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell>
|
||||
<EpisodeLanguage
|
||||
language={language}
|
||||
<EpisodeLanguages
|
||||
languages={languages}
|
||||
isCutoffNotMet={languageCutoffNotMet}
|
||||
/>
|
||||
</TableRowCell>
|
||||
@ -177,7 +177,7 @@ EpisodeHistoryRow.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
eventType: PropTypes.string.isRequired,
|
||||
sourceTitle: PropTypes.string.isRequired,
|
||||
language: PropTypes.object.isRequired,
|
||||
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
languageCutoffNotMet: PropTypes.bool.isRequired,
|
||||
quality: PropTypes.object.isRequired,
|
||||
qualityCutoffNotMet: PropTypes.bool.isRequired,
|
||||
|
@ -4,7 +4,7 @@
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.language,
|
||||
.languages,
|
||||
.quality {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
|
@ -6,7 +6,7 @@ import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import EpisodeLanguage from 'Episode/EpisodeLanguage';
|
||||
import EpisodeLanguages from 'Episode/EpisodeLanguages';
|
||||
import EpisodeQuality from 'Episode/EpisodeQuality';
|
||||
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import formatBytes from 'Utilities/Number/formatBytes';
|
||||
@ -50,7 +50,7 @@ class EpisodeFileRow extends Component {
|
||||
const {
|
||||
path,
|
||||
size,
|
||||
language,
|
||||
languages,
|
||||
quality,
|
||||
languageCutoffNotMet,
|
||||
qualityCutoffNotMet,
|
||||
@ -87,14 +87,14 @@ class EpisodeFileRow extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'language') {
|
||||
if (name === 'languages') {
|
||||
return (
|
||||
<TableRowCell
|
||||
key={name}
|
||||
className={styles.language}
|
||||
className={styles.languages}
|
||||
>
|
||||
<EpisodeLanguage
|
||||
language={language}
|
||||
<EpisodeLanguages
|
||||
languages={languages}
|
||||
isCutoffNotMet={languageCutoffNotMet}
|
||||
/>
|
||||
</TableRowCell>
|
||||
@ -167,7 +167,7 @@ class EpisodeFileRow extends Component {
|
||||
EpisodeFileRow.propTypes = {
|
||||
path: PropTypes.string.isRequired,
|
||||
size: PropTypes.number.isRequired,
|
||||
language: PropTypes.object.isRequired,
|
||||
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
languageCutoffNotMet: PropTypes.bool.isRequired,
|
||||
quality: PropTypes.object.isRequired,
|
||||
qualityCutoffNotMet: PropTypes.bool.isRequired,
|
||||
|
@ -24,8 +24,8 @@ const columns = [
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'language',
|
||||
label: 'Language',
|
||||
name: 'languages',
|
||||
label: 'Languages',
|
||||
isSortable: false,
|
||||
isVisible: true
|
||||
},
|
||||
@ -84,7 +84,7 @@ class EpisodeSummary extends Component {
|
||||
mediaInfo,
|
||||
path,
|
||||
size,
|
||||
language,
|
||||
languages,
|
||||
quality,
|
||||
languageCutoffNotMet,
|
||||
qualityCutoffNotMet,
|
||||
@ -132,7 +132,7 @@ class EpisodeSummary extends Component {
|
||||
<EpisodeFileRow
|
||||
path={path}
|
||||
size={size}
|
||||
language={language}
|
||||
languages={languages}
|
||||
languageCutoffNotMet={languageCutoffNotMet}
|
||||
quality={quality}
|
||||
qualityCutoffNotMet={qualityCutoffNotMet}
|
||||
@ -168,7 +168,7 @@ EpisodeSummary.propTypes = {
|
||||
mediaInfo: PropTypes.object,
|
||||
path: PropTypes.string,
|
||||
size: PropTypes.number,
|
||||
language: PropTypes.object,
|
||||
languages: PropTypes.arrayOf(PropTypes.object),
|
||||
languageCutoffNotMet: PropTypes.bool,
|
||||
quality: PropTypes.object,
|
||||
qualityCutoffNotMet: PropTypes.bool,
|
||||
|
@ -28,7 +28,7 @@ function createMapStateToProps() {
|
||||
mediaInfo,
|
||||
path,
|
||||
size,
|
||||
language,
|
||||
languages,
|
||||
languageCutoffNotMet,
|
||||
quality,
|
||||
qualityCutoffNotMet
|
||||
@ -42,7 +42,7 @@ function createMapStateToProps() {
|
||||
mediaInfo,
|
||||
path,
|
||||
size,
|
||||
language,
|
||||
languages,
|
||||
languageCutoffNotMet,
|
||||
quality,
|
||||
qualityCutoffNotMet
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import EpisodeLanguage from 'Episode/EpisodeLanguage';
|
||||
import EpisodeLanguages from 'Episode/EpisodeLanguages';
|
||||
import createEpisodeFileSelector from 'Store/Selectors/createEpisodeFileSelector';
|
||||
|
||||
function createMapStateToProps() {
|
||||
@ -8,10 +8,10 @@ function createMapStateToProps() {
|
||||
createEpisodeFileSelector(),
|
||||
(episodeFile) => {
|
||||
return {
|
||||
language: episodeFile ? episodeFile.language : undefined
|
||||
languages: episodeFile ? episodeFile.languages : undefined
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(createMapStateToProps)(EpisodeLanguage);
|
||||
export default connect(createMapStateToProps)(EpisodeLanguages);
|
||||
|
@ -3,7 +3,6 @@ export const BYTES = 'bytes';
|
||||
export const DATE = 'date';
|
||||
export const DEFAULT = 'default';
|
||||
export const INDEXER = 'indexer';
|
||||
export const LANGUAGE_PROFILE = 'languageProfile';
|
||||
export const PROTOCOL = 'protocol';
|
||||
export const QUALITY = 'quality';
|
||||
export const QUALITY_PROFILE = 'qualityProfile';
|
||||
|
@ -9,8 +9,8 @@ export const OAUTH = 'oauth';
|
||||
export const PASSWORD = 'password';
|
||||
export const PATH = 'path';
|
||||
export const QUALITY_PROFILE_SELECT = 'qualityProfileSelect';
|
||||
export const LANGUAGE_PROFILE_SELECT = 'languageProfileSelect';
|
||||
export const INDEXER_SELECT = 'indexerSelect';
|
||||
export const LANGUAGE_SELECT = 'languageSelect';
|
||||
export const DOWNLOAD_CLIENT_SELECT = 'downloadClientSelect';
|
||||
export const ROOT_FOLDER_SELECT = 'rootFolderSelect';
|
||||
export const SELECT = 'select';
|
||||
@ -35,10 +35,10 @@ export const all = [
|
||||
PASSWORD,
|
||||
PATH,
|
||||
QUALITY_PROFILE_SELECT,
|
||||
LANGUAGE_PROFILE_SELECT,
|
||||
INDEXER_SELECT,
|
||||
DOWNLOAD_CLIENT_SELECT,
|
||||
ROOT_FOLDER_SELECT,
|
||||
LANGUAGE_SELECT,
|
||||
SELECT,
|
||||
DYNAMIC_SELECT,
|
||||
SERIES_TYPE_SELECT,
|
||||
|
@ -66,8 +66,8 @@ const columns = [
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'language',
|
||||
label: 'Language',
|
||||
name: 'languages',
|
||||
label: 'Languages',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
|
@ -193,7 +193,7 @@ class InteractiveImportModalContentConnector extends Component {
|
||||
episodes,
|
||||
releaseGroup,
|
||||
quality,
|
||||
language,
|
||||
languages,
|
||||
episodeFileId
|
||||
} = item;
|
||||
|
||||
@ -217,8 +217,8 @@ class InteractiveImportModalContentConnector extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!language) {
|
||||
this.setState({ interactiveImportErrorMessage: 'Language must be chosen for each selected file' });
|
||||
if (!languages) {
|
||||
this.setState({ interactiveImportErrorMessage: 'Language(s) must be chosen for each selected file' });
|
||||
return;
|
||||
}
|
||||
|
||||
@ -230,7 +230,7 @@ class InteractiveImportModalContentConnector extends Component {
|
||||
id: episodeFileId,
|
||||
releaseGroup,
|
||||
quality,
|
||||
language
|
||||
languages
|
||||
});
|
||||
|
||||
return;
|
||||
@ -244,7 +244,7 @@ class InteractiveImportModalContentConnector extends Component {
|
||||
episodeIds: episodes.map((e) => e.id),
|
||||
releaseGroup,
|
||||
quality,
|
||||
language,
|
||||
languages,
|
||||
downloadId: this.props.downloadId,
|
||||
episodeFileId
|
||||
});
|
||||
|
@ -5,7 +5,7 @@
|
||||
}
|
||||
|
||||
.quality,
|
||||
.language {
|
||||
.languages {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
text-align: center;
|
||||
|
@ -7,7 +7,7 @@ import TableRowCellButton from 'Components/Table/Cells/TableRowCellButton';
|
||||
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import EpisodeLanguage from 'Episode/EpisodeLanguage';
|
||||
import EpisodeLanguages from 'Episode/EpisodeLanguages';
|
||||
import EpisodeQuality from 'Episode/EpisodeQuality';
|
||||
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import SelectEpisodeModal from 'InteractiveImport/Episode/SelectEpisodeModal';
|
||||
@ -47,7 +47,7 @@ class InteractiveImportRow extends Component {
|
||||
seasonNumber,
|
||||
episodes,
|
||||
quality,
|
||||
language,
|
||||
languages,
|
||||
episodeFileId,
|
||||
columns
|
||||
} = this.props;
|
||||
@ -58,7 +58,7 @@ class InteractiveImportRow extends Component {
|
||||
seasonNumber != null &&
|
||||
episodes.length &&
|
||||
quality &&
|
||||
language
|
||||
languages
|
||||
) {
|
||||
this.props.onSelectedChange({
|
||||
id,
|
||||
@ -79,7 +79,7 @@ class InteractiveImportRow extends Component {
|
||||
seasonNumber,
|
||||
episodes,
|
||||
quality,
|
||||
language,
|
||||
languages,
|
||||
isSelected,
|
||||
onValidRowChange
|
||||
} = this.props;
|
||||
@ -89,7 +89,7 @@ class InteractiveImportRow extends Component {
|
||||
prevProps.seasonNumber === seasonNumber &&
|
||||
!hasDifferentItems(prevProps.episodes, episodes) &&
|
||||
prevProps.quality === quality &&
|
||||
prevProps.language === language &&
|
||||
prevProps.languages === languages &&
|
||||
prevProps.isSelected === isSelected
|
||||
) {
|
||||
return;
|
||||
@ -100,7 +100,7 @@ class InteractiveImportRow extends Component {
|
||||
seasonNumber != null &&
|
||||
episodes.length &&
|
||||
quality &&
|
||||
language
|
||||
languages
|
||||
);
|
||||
|
||||
if (isSelected && !isValid) {
|
||||
@ -210,7 +210,7 @@ class InteractiveImportRow extends Component {
|
||||
seasonNumber,
|
||||
episodes,
|
||||
quality,
|
||||
language,
|
||||
languages,
|
||||
releaseGroup,
|
||||
size,
|
||||
rejections,
|
||||
@ -252,7 +252,7 @@ class InteractiveImportRow extends Component {
|
||||
const showEpisodeNumbersPlaceholder = isSelected && Number.isInteger(seasonNumber) && !episodes.length;
|
||||
const showReleaseGroupPlaceholder = isSelected && !releaseGroup;
|
||||
const showQualityPlaceholder = isSelected && !quality;
|
||||
const showLanguagePlaceholder = isSelected && !language;
|
||||
const showLanguagePlaceholder = isSelected && !languages;
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
@ -352,10 +352,10 @@ class InteractiveImportRow extends Component {
|
||||
}
|
||||
|
||||
{
|
||||
!showLanguagePlaceholder && !!language &&
|
||||
<EpisodeLanguage
|
||||
!showLanguagePlaceholder && !!languages &&
|
||||
<EpisodeLanguages
|
||||
className={styles.label}
|
||||
language={language}
|
||||
languages={languages}
|
||||
/>
|
||||
}
|
||||
</TableRowCellButton>
|
||||
@ -441,7 +441,7 @@ class InteractiveImportRow extends Component {
|
||||
<SelectLanguageModal
|
||||
isOpen={isSelectLanguageModalOpen}
|
||||
ids={[id]}
|
||||
languageId={language ? language.id : 0}
|
||||
languageId={languages ? languages.id : 0}
|
||||
modalTitle={modalTitle}
|
||||
onModalClose={this.onSelectLanguageModalClose}
|
||||
/>
|
||||
@ -460,7 +460,7 @@ InteractiveImportRow.propTypes = {
|
||||
episodes: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
releaseGroup: PropTypes.string,
|
||||
quality: PropTypes.object,
|
||||
language: PropTypes.object,
|
||||
languages: PropTypes.arrayOf(PropTypes.object),
|
||||
size: PropTypes.number.isRequired,
|
||||
rejections: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
|
@ -4,7 +4,6 @@ import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { reprocessInteractiveImportItems, updateInteractiveImportItems } from 'Store/Actions/interactiveImportActions';
|
||||
import { fetchLanguageProfileSchema } from 'Store/Actions/settingsActions';
|
||||
import createLanguagesSelector from 'Store/Selectors/createLanguagesSelector';
|
||||
import SelectLanguageModalContent from './SelectLanguageModalContent';
|
||||
|
||||
@ -18,22 +17,12 @@ function createMapStateToProps() {
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
dispatchFetchLanguageProfileSchema: fetchLanguageProfileSchema,
|
||||
dispatchUpdateInteractiveImportItems: updateInteractiveImportItems,
|
||||
dispatchReprocessInteractiveImportItems: reprocessInteractiveImportItems
|
||||
};
|
||||
|
||||
class SelectLanguageModalContentConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount = () => {
|
||||
if (!this.props.isPopulated) {
|
||||
this.props.dispatchFetchLanguageProfileSchema();
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
@ -44,13 +33,20 @@ class SelectLanguageModalContentConnector extends Component {
|
||||
dispatchReprocessInteractiveImportItems
|
||||
} = this.props;
|
||||
|
||||
const languageId = parseInt(value);
|
||||
const language = _.find(this.props.items,
|
||||
(item) => item.language.id === languageId).language;
|
||||
const languages = [];
|
||||
|
||||
value.forEach((languageId) => {
|
||||
const language = _.find(this.props.items,
|
||||
(item) => item.id === parseInt(languageId));
|
||||
|
||||
if (language !== undefined) {
|
||||
languages.push(language);
|
||||
}
|
||||
});
|
||||
|
||||
dispatchUpdateInteractiveImportItems({
|
||||
ids,
|
||||
language
|
||||
languages
|
||||
});
|
||||
|
||||
dispatchReprocessInteractiveImportItems({ ids });
|
||||
@ -77,7 +73,6 @@ SelectLanguageModalContentConnector.propTypes = {
|
||||
isPopulated: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
dispatchFetchLanguageProfileSchema: PropTypes.func.isRequired,
|
||||
dispatchUpdateInteractiveImportItems: PropTypes.func.isRequired,
|
||||
dispatchReprocessInteractiveImportItems: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
|
@ -51,7 +51,7 @@ const columns = [
|
||||
},
|
||||
{
|
||||
name: 'languageWeight',
|
||||
label: 'Language',
|
||||
label: 'Languages',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
|
@ -24,13 +24,13 @@
|
||||
}
|
||||
|
||||
.quality,
|
||||
.language {
|
||||
.languages {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.language {
|
||||
.languages {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import Tooltip from 'Components/Tooltip/Tooltip';
|
||||
import EpisodeLanguage from 'Episode/EpisodeLanguage';
|
||||
import EpisodeLanguages from 'Episode/EpisodeLanguages';
|
||||
import EpisodeQuality from 'Episode/EpisodeQuality';
|
||||
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import formatDateTime from 'Utilities/Date/formatDateTime';
|
||||
@ -116,7 +116,7 @@ class InteractiveSearchRow extends Component {
|
||||
seeders,
|
||||
leechers,
|
||||
quality,
|
||||
language,
|
||||
languages,
|
||||
customFormatScore,
|
||||
customFormats,
|
||||
sceneMapping,
|
||||
@ -188,8 +188,8 @@ class InteractiveSearchRow extends Component {
|
||||
}
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell className={styles.language}>
|
||||
<EpisodeLanguage language={language} />
|
||||
<TableRowCell className={styles.languages}>
|
||||
<EpisodeLanguages languages={languages} />
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell className={styles.quality}>
|
||||
@ -286,7 +286,7 @@ InteractiveSearchRow.propTypes = {
|
||||
seeders: PropTypes.number,
|
||||
leechers: PropTypes.number,
|
||||
quality: PropTypes.object.isRequired,
|
||||
language: PropTypes.object.isRequired,
|
||||
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
customFormats: PropTypes.arrayOf(PropTypes.object),
|
||||
customFormatScore: PropTypes.number.isRequired,
|
||||
sceneMapping: PropTypes.object,
|
||||
|
@ -28,7 +28,7 @@
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.language,
|
||||
.languages,
|
||||
.audio,
|
||||
.video,
|
||||
.status {
|
||||
|
@ -180,11 +180,11 @@ class EpisodeRow extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'language') {
|
||||
if (name === 'languages') {
|
||||
return (
|
||||
<TableRowCell
|
||||
key={name}
|
||||
className={styles.language}
|
||||
className={styles.languages}
|
||||
>
|
||||
<EpisodeFileLanguageConnector
|
||||
episodeFileId={episodeFileId}
|
||||
|
@ -59,7 +59,6 @@ class EditSeriesModalContent extends Component {
|
||||
title,
|
||||
item,
|
||||
isSaving,
|
||||
showLanguageProfile,
|
||||
originalPath,
|
||||
onInputChange,
|
||||
onModalClose,
|
||||
@ -71,7 +70,6 @@ class EditSeriesModalContent extends Component {
|
||||
monitored,
|
||||
seasonFolder,
|
||||
qualityProfileId,
|
||||
languageProfileId,
|
||||
seriesType,
|
||||
path,
|
||||
tags
|
||||
@ -120,20 +118,6 @@ class EditSeriesModalContent extends Component {
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
{
|
||||
showLanguageProfile &&
|
||||
<FormGroup>
|
||||
<FormLabel>Language Profile</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.LANGUAGE_PROFILE_SELECT}
|
||||
name="languageProfileId"
|
||||
{...languageProfileId}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
}
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Series Type</FormLabel>
|
||||
|
||||
@ -209,7 +193,6 @@ EditSeriesModalContent.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
item: PropTypes.object.isRequired,
|
||||
isSaving: PropTypes.bool.isRequired,
|
||||
showLanguageProfile: PropTypes.bool.isRequired,
|
||||
isPathChanging: PropTypes.bool.isRequired,
|
||||
originalPath: PropTypes.string.isRequired,
|
||||
onInputChange: PropTypes.func.isRequired,
|
||||
|
@ -27,10 +27,9 @@ function createIsPathChangingSelector() {
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.series,
|
||||
(state) => state.settings.languageProfiles,
|
||||
createSeriesSelector(),
|
||||
createIsPathChangingSelector(),
|
||||
(seriesState, languageProfiles, series, isPathChanging) => {
|
||||
(seriesState, series, isPathChanging) => {
|
||||
const {
|
||||
isSaving,
|
||||
saveError,
|
||||
@ -41,7 +40,6 @@ function createMapStateToProps() {
|
||||
'monitored',
|
||||
'seasonFolder',
|
||||
'qualityProfileId',
|
||||
'languageProfileId',
|
||||
'seriesType',
|
||||
'path',
|
||||
'tags'
|
||||
@ -56,7 +54,6 @@ function createMapStateToProps() {
|
||||
isPathChanging,
|
||||
originalPath: series.path,
|
||||
item: settings.settings,
|
||||
showLanguageProfile: languageProfiles.items.length > 1,
|
||||
...settings
|
||||
};
|
||||
}
|
||||
|
@ -212,7 +212,6 @@ class SeriesEditor extends Component {
|
||||
deleteError={deleteError}
|
||||
isOrganizingSeries={isOrganizingSeries}
|
||||
columns={columns}
|
||||
showLanguageProfile={columns.find((column) => column.name === 'languageProfileId').isVisible}
|
||||
onSaveSelected={this.onSaveSelected}
|
||||
onOrganizeSeriesPress={this.onOrganizeSeriesPress}
|
||||
/>
|
||||
|
@ -1,6 +1,5 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import LanguageProfileSelectInputConnector from 'Components/Form/LanguageProfileSelectInputConnector';
|
||||
import QualityProfileSelectInputConnector from 'Components/Form/QualityProfileSelectInputConnector';
|
||||
import RootFolderSelectInputConnector from 'Components/Form/RootFolderSelectInputConnector';
|
||||
import SelectInput from 'Components/Form/SelectInput';
|
||||
@ -27,7 +26,6 @@ class SeriesEditorFooter extends Component {
|
||||
this.state = {
|
||||
monitored: NO_CHANGE,
|
||||
qualityProfileId: NO_CHANGE,
|
||||
languageProfileId: NO_CHANGE,
|
||||
seriesType: NO_CHANGE,
|
||||
seasonFolder: NO_CHANGE,
|
||||
rootFolderPath: NO_CHANGE,
|
||||
@ -49,7 +47,6 @@ class SeriesEditorFooter extends Component {
|
||||
this.setState({
|
||||
monitored: NO_CHANGE,
|
||||
qualityProfileId: NO_CHANGE,
|
||||
languageProfileId: NO_CHANGE,
|
||||
seriesType: NO_CHANGE,
|
||||
seasonFolder: NO_CHANGE,
|
||||
rootFolderPath: NO_CHANGE,
|
||||
@ -152,7 +149,6 @@ class SeriesEditorFooter extends Component {
|
||||
const {
|
||||
monitored,
|
||||
qualityProfileId,
|
||||
languageProfileId,
|
||||
seriesType,
|
||||
seasonFolder,
|
||||
rootFolderPath,
|
||||
@ -225,28 +221,6 @@ class SeriesEditorFooter extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'languageProfileId') {
|
||||
return (
|
||||
<div
|
||||
key={name}
|
||||
className={styles.inputContainer}
|
||||
>
|
||||
<SeriesEditorFooterLabel
|
||||
label="Language Profile"
|
||||
isSaving={isSaving && languageProfileId !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
<LanguageProfileSelectInputConnector
|
||||
name="languageProfileId"
|
||||
value={languageProfileId}
|
||||
includeNoChange={true}
|
||||
isDisabled={!selectedCount}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'seriesType') {
|
||||
return (
|
||||
<div
|
||||
@ -392,7 +366,6 @@ SeriesEditorFooter.propTypes = {
|
||||
isDeleting: PropTypes.bool.isRequired,
|
||||
deleteError: PropTypes.object,
|
||||
isOrganizingSeries: PropTypes.bool.isRequired,
|
||||
showLanguageProfile: PropTypes.bool.isRequired,
|
||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
onSaveSelected: PropTypes.func.isRequired,
|
||||
onOrganizeSeriesPress: PropTypes.func.isRequired
|
||||
|
@ -33,7 +33,6 @@ class SeriesEditorRow extends Component {
|
||||
titleSlug,
|
||||
seriesType,
|
||||
qualityProfile,
|
||||
languageProfile,
|
||||
path,
|
||||
tags,
|
||||
seasonFolder,
|
||||
@ -95,14 +94,6 @@ class SeriesEditorRow extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'languageProfileId') {
|
||||
return (
|
||||
<TableRowCell key={name}>
|
||||
{languageProfile.name}
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'seriesType') {
|
||||
return (
|
||||
<TableRowCell key={name}>
|
||||
@ -167,7 +158,6 @@ SeriesEditorRow.propTypes = {
|
||||
titleSlug: PropTypes.string.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
monitored: PropTypes.bool.isRequired,
|
||||
languageProfile: PropTypes.object.isRequired,
|
||||
qualityProfile: PropTypes.object.isRequired,
|
||||
seriesType: PropTypes.string.isRequired,
|
||||
seasonFolder: PropTypes.bool.isRequired,
|
||||
|
@ -2,17 +2,14 @@ import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import createLanguageProfileSelector from 'Store/Selectors/createLanguageProfileSelector';
|
||||
import createQualityProfileSelector from 'Store/Selectors/createQualityProfileSelector';
|
||||
import SeriesEditorRow from './SeriesEditorRow';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createLanguageProfileSelector(),
|
||||
createQualityProfileSelector(),
|
||||
(languageProfile, qualityProfile) => {
|
||||
(qualityProfile) => {
|
||||
return {
|
||||
languageProfile,
|
||||
qualityProfile
|
||||
};
|
||||
}
|
||||
|
@ -29,8 +29,8 @@ const columns = [
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'language',
|
||||
label: 'Language',
|
||||
name: 'languages',
|
||||
label: 'Languages',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
|
@ -11,7 +11,7 @@ import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import Tooltip from 'Components/Tooltip/Tooltip';
|
||||
import EpisodeLanguage from 'Episode/EpisodeLanguage';
|
||||
import EpisodeLanguages from 'Episode/EpisodeLanguages';
|
||||
import EpisodeNumber from 'Episode/EpisodeNumber';
|
||||
import EpisodeQuality from 'Episode/EpisodeQuality';
|
||||
import SeasonEpisodeNumber from 'Episode/SeasonEpisodeNumber';
|
||||
@ -67,7 +67,7 @@ class SeriesHistoryRow extends Component {
|
||||
const {
|
||||
eventType,
|
||||
sourceTitle,
|
||||
language,
|
||||
languages,
|
||||
languageCutoffNotMet,
|
||||
quality,
|
||||
qualityCutoffNotMet,
|
||||
@ -110,8 +110,8 @@ class SeriesHistoryRow extends Component {
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell>
|
||||
<EpisodeLanguage
|
||||
language={language}
|
||||
<EpisodeLanguages
|
||||
languages={languages}
|
||||
isCutoffNotMet={languageCutoffNotMet}
|
||||
/>
|
||||
</TableRowCell>
|
||||
@ -197,7 +197,7 @@ SeriesHistoryRow.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
eventType: PropTypes.string.isRequired,
|
||||
sourceTitle: PropTypes.string.isRequired,
|
||||
language: PropTypes.object.isRequired,
|
||||
languages: PropTypes.object.isRequired,
|
||||
languageCutoffNotMet: PropTypes.bool.isRequired,
|
||||
quality: PropTypes.object.isRequired,
|
||||
qualityCutoffNotMet: PropTypes.bool.isRequired,
|
||||
|
@ -55,15 +55,6 @@ function SeriesIndexSortMenu(props) {
|
||||
Quality Profile
|
||||
</SortMenuItem>
|
||||
|
||||
<SortMenuItem
|
||||
name="languageProfileId"
|
||||
sortKey={sortKey}
|
||||
sortDirection={sortDirection}
|
||||
onPress={onSortSelect}
|
||||
>
|
||||
Language Profile
|
||||
</SortMenuItem>
|
||||
|
||||
<SortMenuItem
|
||||
name="nextAiring"
|
||||
sortKey={sortKey}
|
||||
|
@ -188,7 +188,6 @@ class SeriesIndexOverviews extends Component {
|
||||
isSmallScreen={isSmallScreen}
|
||||
style={style}
|
||||
seriesId={series.id}
|
||||
languageProfileId={series.languageProfileId}
|
||||
qualityProfileId={series.qualityProfileId}
|
||||
/>
|
||||
</div>
|
||||
|
@ -243,7 +243,6 @@ class SeriesIndexPosters extends Component {
|
||||
timeFormat={timeFormat}
|
||||
style={style}
|
||||
seriesId={series.id}
|
||||
languageProfileId={series.languageProfileId}
|
||||
qualityProfileId={series.qualityProfileId}
|
||||
/>
|
||||
</div>
|
||||
|
@ -6,7 +6,6 @@ import { createSelector } from 'reselect';
|
||||
import * as commandNames from 'Commands/commandNames';
|
||||
import { executeCommand } from 'Store/Actions/commandActions';
|
||||
import createExecutingCommandsSelector from 'Store/Selectors/createExecutingCommandsSelector';
|
||||
import createSeriesLanguageProfileSelector from 'Store/Selectors/createSeriesLanguageProfileSelector';
|
||||
import createSeriesQualityProfileSelector from 'Store/Selectors/createSeriesQualityProfileSelector';
|
||||
import createSeriesSelector from 'Store/Selectors/createSeriesSelector';
|
||||
|
||||
@ -32,13 +31,11 @@ function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createSeriesSelector(),
|
||||
createSeriesQualityProfileSelector(),
|
||||
createSeriesLanguageProfileSelector(),
|
||||
selectShowSearchAction(),
|
||||
createExecutingCommandsSelector(),
|
||||
(
|
||||
series,
|
||||
qualityProfile,
|
||||
languageProfile,
|
||||
showSearchAction,
|
||||
executingCommands
|
||||
) => {
|
||||
@ -71,7 +68,6 @@ function createMapStateToProps() {
|
||||
return {
|
||||
...series,
|
||||
qualityProfile,
|
||||
languageProfile,
|
||||
latestSeason,
|
||||
showSearchAction,
|
||||
isRefreshingSeries,
|
||||
|
@ -30,8 +30,7 @@
|
||||
flex: 2 0 90px;
|
||||
}
|
||||
|
||||
.qualityProfileId,
|
||||
.languageProfileId {
|
||||
.qualityProfileId {
|
||||
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
|
||||
|
||||
flex: 1 0 125px;
|
||||
|
@ -66,8 +66,7 @@
|
||||
flex: 2 0 90px;
|
||||
}
|
||||
|
||||
.qualityProfileId,
|
||||
.languageProfileId {
|
||||
.qualityProfileId {
|
||||
composes: cell;
|
||||
|
||||
flex: 1 0 125px;
|
||||
|
@ -86,7 +86,6 @@ class SeriesIndexRow extends Component {
|
||||
seriesType,
|
||||
network,
|
||||
qualityProfile,
|
||||
languageProfile,
|
||||
nextAiring,
|
||||
previousAiring,
|
||||
added,
|
||||
@ -224,17 +223,6 @@ class SeriesIndexRow extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'languageProfileId') {
|
||||
return (
|
||||
<VirtualTableRowCell
|
||||
key={name}
|
||||
className={styles[name]}
|
||||
>
|
||||
{languageProfile.name}
|
||||
</VirtualTableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'nextAiring') {
|
||||
return (
|
||||
<RelativeDateCellConnector
|
||||
@ -525,7 +513,6 @@ SeriesIndexRow.propTypes = {
|
||||
seriesType: PropTypes.string.isRequired,
|
||||
network: PropTypes.string,
|
||||
qualityProfile: PropTypes.object.isRequired,
|
||||
languageProfile: PropTypes.object.isRequired,
|
||||
nextAiring: PropTypes.string,
|
||||
previousAiring: PropTypes.string,
|
||||
added: PropTypes.string,
|
||||
|
@ -62,7 +62,6 @@ class SeriesIndexTable extends Component {
|
||||
component={SeriesIndexRow}
|
||||
columns={columns}
|
||||
seriesId={series.id}
|
||||
languageProfileId={series.languageProfileId}
|
||||
qualityProfileId={series.qualityProfileId}
|
||||
showBanners={showBanners}
|
||||
/>
|
||||
|
@ -1,7 +1,6 @@
|
||||
const growableColumns = [
|
||||
'network',
|
||||
'qualityProfileId',
|
||||
'languageProfileId',
|
||||
'path',
|
||||
'tags'
|
||||
];
|
||||
|
@ -4,12 +4,6 @@
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.hideLanguageProfile {
|
||||
composes: group from '~Components/Form/FormGroup.css';
|
||||
|
||||
display: none;
|
||||
}
|
||||
|
||||
.labelIcon {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
@ -35,7 +35,6 @@ function EditImportListModalContent(props) {
|
||||
onSavePress,
|
||||
onTestPress,
|
||||
onDeleteImportListPress,
|
||||
showLanguageProfile,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
@ -46,7 +45,6 @@ function EditImportListModalContent(props) {
|
||||
shouldMonitor,
|
||||
rootFolderPath,
|
||||
qualityProfileId,
|
||||
languageProfileId,
|
||||
seriesType,
|
||||
seasonFolder,
|
||||
tags,
|
||||
@ -148,18 +146,6 @@ function EditImportListModalContent(props) {
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup className={showLanguageProfile ? undefined : styles.hideLanguageProfile}>
|
||||
<FormLabel>Language Profile</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.LANGUAGE_PROFILE_SELECT}
|
||||
name="languageProfileId"
|
||||
helpText={'Language Profile list items will be added with'}
|
||||
{...languageProfileId}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>
|
||||
Series Type
|
||||
@ -279,7 +265,6 @@ EditImportListModalContent.propTypes = {
|
||||
isTesting: PropTypes.bool.isRequired,
|
||||
saveError: PropTypes.object,
|
||||
item: PropTypes.object.isRequired,
|
||||
showLanguageProfile: PropTypes.bool.isRequired,
|
||||
onInputChange: PropTypes.func.isRequired,
|
||||
onFieldChange: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired,
|
||||
|
@ -9,12 +9,10 @@ import EditImportListModalContent from './EditImportListModalContent';
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.settings.advancedSettings,
|
||||
(state) => state.settings.languageProfiles,
|
||||
createProviderSettingsSelector('importLists'),
|
||||
(advancedSettings, languageProfiles, importList) => {
|
||||
(advancedSettings, importList) => {
|
||||
return {
|
||||
advancedSettings,
|
||||
showLanguageProfile: languageProfiles.items.length > 1,
|
||||
...importList
|
||||
};
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import { sizes } from 'Helpers/Props';
|
||||
import EditLanguageProfileModalContentConnector from './EditLanguageProfileModalContentConnector';
|
||||
|
||||
function EditLanguageProfileModal({ isOpen, onModalClose, ...otherProps }) {
|
||||
return (
|
||||
<Modal
|
||||
size={sizes.MEDIUM}
|
||||
isOpen={isOpen}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<EditLanguageProfileModalContentConnector
|
||||
{...otherProps}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
EditLanguageProfileModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default EditLanguageProfileModal;
|
@ -1,43 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { clearPendingChanges } from 'Store/Actions/baseActions';
|
||||
import EditLanguageProfileModal from './EditLanguageProfileModal';
|
||||
|
||||
function mapStateToProps() {
|
||||
return {};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
clearPendingChanges
|
||||
};
|
||||
|
||||
class EditLanguageProfileModalConnector extends Component {
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onModalClose = () => {
|
||||
this.props.clearPendingChanges({ section: 'settings.languageProfiles' });
|
||||
this.props.onModalClose();
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<EditLanguageProfileModal
|
||||
{...this.props}
|
||||
onModalClose={this.onModalClose}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
EditLanguageProfileModalConnector.propTypes = {
|
||||
onModalClose: PropTypes.func.isRequired,
|
||||
clearPendingChanges: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(EditLanguageProfileModalConnector);
|
@ -1,3 +0,0 @@
|
||||
.deleteButtonContainer {
|
||||
margin-right: auto;
|
||||
}
|
@ -1,165 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Form from 'Components/Form/Form';
|
||||
import FormGroup from 'Components/Form/FormGroup';
|
||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
import FormLabel from 'Components/Form/FormLabel';
|
||||
import Button from 'Components/Link/Button';
|
||||
import SpinnerErrorButton from 'Components/Link/SpinnerErrorButton';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes, kinds } from 'Helpers/Props';
|
||||
import LanguageProfileItems from './LanguageProfileItems';
|
||||
import styles from './EditLanguageProfileModalContent.css';
|
||||
|
||||
function EditLanguageProfileModalContent(props) {
|
||||
const {
|
||||
isFetching,
|
||||
error,
|
||||
isSaving,
|
||||
saveError,
|
||||
languages,
|
||||
item,
|
||||
isInUse,
|
||||
onInputChange,
|
||||
onCutoffChange,
|
||||
onSavePress,
|
||||
onModalClose,
|
||||
onDeleteLanguageProfilePress,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
upgradeAllowed,
|
||||
cutoff,
|
||||
languages: itemLanguages
|
||||
} = item;
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
{id ? 'Edit Language Profile' : 'Add Language Profile'}
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
{
|
||||
isFetching &&
|
||||
<LoadingIndicator />
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>Unable to add a new language profile, please try again.</div>
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && !error &&
|
||||
<Form {...otherProps}>
|
||||
<FormGroup>
|
||||
<FormLabel>Name</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="name"
|
||||
{...name}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>
|
||||
Upgrades Allowed
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="upgradeAllowed"
|
||||
{...upgradeAllowed}
|
||||
helpText="If disabled languages will not be upgraded"
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
{
|
||||
upgradeAllowed.value &&
|
||||
<FormGroup>
|
||||
<FormLabel>Upgrade Until</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="cutoff"
|
||||
{...cutoff}
|
||||
value={cutoff ? cutoff.value.id : 0}
|
||||
values={languages}
|
||||
helpText="Once this language is reached Sonarr will no longer download episodes"
|
||||
onChange={onCutoffChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
}
|
||||
|
||||
<LanguageProfileItems
|
||||
languageProfileItems={itemLanguages.value}
|
||||
errors={itemLanguages.errors}
|
||||
warnings={itemLanguages.warnings}
|
||||
{...otherProps}
|
||||
/>
|
||||
|
||||
</Form>
|
||||
}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
{
|
||||
id &&
|
||||
<div
|
||||
className={styles.deleteButtonContainer}
|
||||
title={isInUse && 'Can\'t delete a language profile that is attached to a series'}
|
||||
>
|
||||
<Button
|
||||
kind={kinds.DANGER}
|
||||
isDisabled={isInUse}
|
||||
onPress={onDeleteLanguageProfilePress}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
|
||||
<Button
|
||||
onPress={onModalClose}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
<SpinnerErrorButton
|
||||
isSpinning={isSaving}
|
||||
error={saveError}
|
||||
onPress={onSavePress}
|
||||
>
|
||||
Save
|
||||
</SpinnerErrorButton>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
|
||||
EditLanguageProfileModalContent.propTypes = {
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
isSaving: PropTypes.bool.isRequired,
|
||||
saveError: PropTypes.object,
|
||||
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
item: PropTypes.object.isRequired,
|
||||
isInUse: PropTypes.bool.isRequired,
|
||||
onInputChange: PropTypes.func.isRequired,
|
||||
onCutoffChange: PropTypes.func.isRequired,
|
||||
onSavePress: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired,
|
||||
onDeleteLanguageProfilePress: PropTypes.func
|
||||
};
|
||||
|
||||
export default EditLanguageProfileModalContent;
|
@ -1,189 +0,0 @@
|
||||
import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { fetchLanguageProfileSchema, saveLanguageProfile, setLanguageProfileValue } from 'Store/Actions/settingsActions';
|
||||
import createProfileInUseSelector from 'Store/Selectors/createProfileInUseSelector';
|
||||
import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
|
||||
import EditLanguageProfileModalContent from './EditLanguageProfileModalContent';
|
||||
|
||||
function createLanguagesSelector() {
|
||||
return createSelector(
|
||||
createProviderSettingsSelector('languageProfiles'),
|
||||
(languageProfile) => {
|
||||
const languages = languageProfile.item.languages;
|
||||
if (!languages || !languages.value) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return _.reduceRight(languages.value, (result, { allowed, language }) => {
|
||||
if (allowed) {
|
||||
result.push({
|
||||
key: language.id,
|
||||
value: language.name
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}, []);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createProviderSettingsSelector('languageProfiles'),
|
||||
createLanguagesSelector(),
|
||||
createProfileInUseSelector('languageProfileId'),
|
||||
(languageProfile, languages, isInUse) => {
|
||||
return {
|
||||
languages,
|
||||
...languageProfile,
|
||||
isInUse
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
fetchLanguageProfileSchema,
|
||||
setLanguageProfileValue,
|
||||
saveLanguageProfile
|
||||
};
|
||||
|
||||
class EditLanguageProfileModalContentConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
dragIndex: null,
|
||||
dropIndex: null
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (!this.props.id && !this.props.isPopulated) {
|
||||
this.props.fetchLanguageProfileSchema();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (prevProps.isSaving && !this.props.isSaving && !this.props.saveError) {
|
||||
this.props.onModalClose();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onInputChange = ({ name, value }) => {
|
||||
this.props.setLanguageProfileValue({ name, value });
|
||||
};
|
||||
|
||||
onCutoffChange = ({ name, value }) => {
|
||||
const id = parseInt(value);
|
||||
const item = _.find(this.props.item.languages.value, (i) => i.language.id === id);
|
||||
|
||||
this.props.setLanguageProfileValue({ name, value: item.language });
|
||||
};
|
||||
|
||||
onSavePress = () => {
|
||||
this.props.saveLanguageProfile({ id: this.props.id });
|
||||
};
|
||||
|
||||
onLanguageProfileItemAllowedChange = (id, allowed) => {
|
||||
const languageProfile = _.cloneDeep(this.props.item);
|
||||
|
||||
const item = _.find(languageProfile.languages.value, (i) => i.language.id === id);
|
||||
item.allowed = allowed;
|
||||
|
||||
this.props.setLanguageProfileValue({
|
||||
name: 'languages',
|
||||
value: languageProfile.languages.value
|
||||
});
|
||||
|
||||
const cutoff = languageProfile.cutoff.value;
|
||||
|
||||
// If the cutoff isn't allowed anymore or there isn't a cutoff set one
|
||||
if (!cutoff || !_.find(languageProfile.languages.value, (i) => i.language.id === cutoff.id).allowed) {
|
||||
const firstAllowed = _.find(languageProfile.languages.value, { allowed: true });
|
||||
|
||||
this.props.setLanguageProfileValue({ name: 'cutoff', value: firstAllowed ? firstAllowed.language : null });
|
||||
}
|
||||
};
|
||||
|
||||
onLanguageProfileItemDragMove = (dragIndex, dropIndex) => {
|
||||
if (this.state.dragIndex !== dragIndex || this.state.dropIndex !== dropIndex) {
|
||||
this.setState({
|
||||
dragIndex,
|
||||
dropIndex
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onLanguageProfileItemDragEnd = ({ id }, didDrop) => {
|
||||
const {
|
||||
dragIndex,
|
||||
dropIndex
|
||||
} = this.state;
|
||||
|
||||
if (didDrop && dropIndex !== null) {
|
||||
const languageProfile = _.cloneDeep(this.props.item);
|
||||
|
||||
const languages = languageProfile.languages.value.splice(dragIndex, 1);
|
||||
languageProfile.languages.value.splice(dropIndex, 0, languages[0]);
|
||||
|
||||
this.props.setLanguageProfileValue({
|
||||
name: 'languages',
|
||||
value: languageProfile.languages.value
|
||||
});
|
||||
}
|
||||
|
||||
this.setState({
|
||||
dragIndex: null,
|
||||
dropIndex: null
|
||||
});
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
if (_.isEmpty(this.props.item.languages) && !this.props.isFetching) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<EditLanguageProfileModalContent
|
||||
{...this.state}
|
||||
{...this.props}
|
||||
onSavePress={this.onSavePress}
|
||||
onInputChange={this.onInputChange}
|
||||
onCutoffChange={this.onCutoffChange}
|
||||
onLanguageProfileItemAllowedChange={this.onLanguageProfileItemAllowedChange}
|
||||
onLanguageProfileItemDragMove={this.onLanguageProfileItemDragMove}
|
||||
onLanguageProfileItemDragEnd={this.onLanguageProfileItemDragEnd}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
EditLanguageProfileModalContentConnector.propTypes = {
|
||||
id: PropTypes.number,
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
isPopulated: PropTypes.bool.isRequired,
|
||||
isSaving: PropTypes.bool.isRequired,
|
||||
saveError: PropTypes.object,
|
||||
item: PropTypes.object.isRequired,
|
||||
setLanguageProfileValue: PropTypes.func.isRequired,
|
||||
fetchLanguageProfileSchema: PropTypes.func.isRequired,
|
||||
saveLanguageProfile: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(EditLanguageProfileModalContentConnector);
|
@ -1,31 +0,0 @@
|
||||
.languageProfile {
|
||||
composes: card from '~Components/Card.css';
|
||||
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.nameContainer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.name {
|
||||
@add-mixin truncate;
|
||||
|
||||
margin-bottom: 20px;
|
||||
font-weight: 300;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.cloneButton {
|
||||
composes: button from '~Components/Link/IconButton.css';
|
||||
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.languages {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 5px;
|
||||
pointer-events: all;
|
||||
}
|
@ -1,147 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Card from 'Components/Card';
|
||||
import Label from 'Components/Label';
|
||||
import IconButton from 'Components/Link/IconButton';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import EditLanguageProfileModalConnector from './EditLanguageProfileModalConnector';
|
||||
import styles from './LanguageProfile.css';
|
||||
|
||||
class LanguageProfile extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
isEditLanguageProfileModalOpen: false,
|
||||
isDeleteLanguageProfileModalOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onEditLanguageProfilePress = () => {
|
||||
this.setState({ isEditLanguageProfileModalOpen: true });
|
||||
};
|
||||
|
||||
onEditLanguageProfileModalClose = () => {
|
||||
this.setState({ isEditLanguageProfileModalOpen: false });
|
||||
};
|
||||
|
||||
onDeleteLanguageProfilePress = () => {
|
||||
this.setState({
|
||||
isEditLanguageProfileModalOpen: false,
|
||||
isDeleteLanguageProfileModalOpen: true
|
||||
});
|
||||
};
|
||||
|
||||
onDeleteLanguageProfileModalClose = () => {
|
||||
this.setState({ isDeleteLanguageProfileModalOpen: false });
|
||||
};
|
||||
|
||||
onConfirmDeleteLanguageProfile = () => {
|
||||
this.props.onConfirmDeleteLanguageProfile(this.props.id);
|
||||
};
|
||||
|
||||
onCloneLanguageProfilePress = () => {
|
||||
const {
|
||||
id,
|
||||
onCloneLanguageProfilePress
|
||||
} = this.props;
|
||||
|
||||
onCloneLanguageProfilePress(id);
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
upgradeAllowed,
|
||||
cutoff,
|
||||
languages,
|
||||
isDeleting
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Card
|
||||
className={styles.languageProfile}
|
||||
overlayContent={true}
|
||||
onPress={this.onEditLanguageProfilePress}
|
||||
>
|
||||
<div className={styles.nameContainer}>
|
||||
<div className={styles.name}>
|
||||
{name}
|
||||
</div>
|
||||
|
||||
<IconButton
|
||||
className={styles.cloneButton}
|
||||
title="Clone Profile"
|
||||
name={icons.CLONE}
|
||||
onPress={this.onCloneLanguageProfilePress}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.languages}>
|
||||
{
|
||||
languages.map((item) => {
|
||||
if (!item.allowed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isCutoff = upgradeAllowed && item.language.id === cutoff.id;
|
||||
|
||||
return (
|
||||
<Label
|
||||
key={item.language.id}
|
||||
kind={isCutoff ? kinds.INFO : kinds.DEFAULT}
|
||||
title={isCutoff ? 'Upgrade until this language is met or exceeded' : null}
|
||||
>
|
||||
{item.language.name}
|
||||
</Label>
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
|
||||
<EditLanguageProfileModalConnector
|
||||
id={id}
|
||||
isOpen={this.state.isEditLanguageProfileModalOpen}
|
||||
onModalClose={this.onEditLanguageProfileModalClose}
|
||||
onDeleteLanguageProfilePress={this.onDeleteLanguageProfilePress}
|
||||
/>
|
||||
|
||||
<ConfirmModal
|
||||
isOpen={this.state.isDeleteLanguageProfileModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title="Delete Language Profile"
|
||||
message={`Are you sure you want to delete the language profile '${name}'?`}
|
||||
confirmLabel="Delete"
|
||||
isSpinning={isDeleting}
|
||||
onConfirm={this.onConfirmDeleteLanguageProfile}
|
||||
onCancel={this.onDeleteLanguageProfileModalClose}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LanguageProfile.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
upgradeAllowed: PropTypes.bool.isRequired,
|
||||
cutoff: PropTypes.object.isRequired,
|
||||
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
isDeleting: PropTypes.bool.isRequired,
|
||||
onConfirmDeleteLanguageProfile: PropTypes.func.isRequired,
|
||||
onCloneLanguageProfilePress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default LanguageProfile;
|
@ -1,44 +0,0 @@
|
||||
.languageProfileItem {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
background: var(--inputBackgroundColor);
|
||||
}
|
||||
|
||||
.checkContainer {
|
||||
position: relative;
|
||||
margin-right: 4px;
|
||||
margin-bottom: 7px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.languageName {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
margin-bottom: 0;
|
||||
margin-left: 2px;
|
||||
font-weight: normal;
|
||||
line-height: 36px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dragHandle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
margin-left: auto;
|
||||
width: $dragHandleWidth;
|
||||
text-align: center;
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.dragIcon {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.isDragging {
|
||||
opacity: 0.25;
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import CheckInput from 'Components/Form/CheckInput';
|
||||
import Icon from 'Components/Icon';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import styles from './LanguageProfileItem.css';
|
||||
|
||||
class LanguageProfileItem extends Component {
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onAllowedChange = ({ value }) => {
|
||||
const {
|
||||
languageId,
|
||||
onLanguageProfileItemAllowedChange
|
||||
} = this.props;
|
||||
|
||||
onLanguageProfileItemAllowedChange(languageId, value);
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
name,
|
||||
allowed,
|
||||
isDragging,
|
||||
connectDragSource
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
styles.languageProfileItem,
|
||||
isDragging && styles.isDragging
|
||||
)}
|
||||
>
|
||||
<label
|
||||
className={styles.languageName}
|
||||
>
|
||||
<CheckInput
|
||||
containerClassName={styles.checkContainer}
|
||||
name={name}
|
||||
value={allowed}
|
||||
onChange={this.onAllowedChange}
|
||||
/>
|
||||
{name}
|
||||
</label>
|
||||
|
||||
{
|
||||
connectDragSource(
|
||||
<div className={styles.dragHandle}>
|
||||
<Icon
|
||||
className={styles.dragIcon}
|
||||
name={icons.REORDER}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LanguageProfileItem.propTypes = {
|
||||
languageId: PropTypes.number.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
allowed: PropTypes.bool.isRequired,
|
||||
sortIndex: PropTypes.number.isRequired,
|
||||
isDragging: PropTypes.bool.isRequired,
|
||||
connectDragSource: PropTypes.func,
|
||||
onLanguageProfileItemAllowedChange: PropTypes.func
|
||||
};
|
||||
|
||||
LanguageProfileItem.defaultProps = {
|
||||
// The drag preview will not connect the drag handle.
|
||||
connectDragSource: (node) => node
|
||||
};
|
||||
|
||||
export default LanguageProfileItem;
|
@ -1,4 +0,0 @@
|
||||
.dragPreview {
|
||||
width: 380px;
|
||||
opacity: 0.75;
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { DragLayer } from 'react-dnd';
|
||||
import DragPreviewLayer from 'Components/DragPreviewLayer';
|
||||
import { QUALITY_PROFILE_ITEM } from 'Helpers/dragTypes';
|
||||
import dimensions from 'Styles/Variables/dimensions.js';
|
||||
import LanguageProfileItem from './LanguageProfileItem';
|
||||
import styles from './LanguageProfileItemDragPreview.css';
|
||||
|
||||
const formGroupSmallWidth = parseInt(dimensions.formGroupSmallWidth);
|
||||
const formLabelLargeWidth = parseInt(dimensions.formLabelLargeWidth);
|
||||
const formLabelRightMarginWidth = parseInt(dimensions.formLabelRightMarginWidth);
|
||||
const dragHandleWidth = parseInt(dimensions.dragHandleWidth);
|
||||
|
||||
function collectDragLayer(monitor) {
|
||||
return {
|
||||
item: monitor.getItem(),
|
||||
itemType: monitor.getItemType(),
|
||||
currentOffset: monitor.getSourceClientOffset()
|
||||
};
|
||||
}
|
||||
|
||||
class LanguageProfileItemDragPreview extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
item,
|
||||
itemType,
|
||||
currentOffset
|
||||
} = this.props;
|
||||
|
||||
if (!currentOffset || itemType !== QUALITY_PROFILE_ITEM) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// The offset is shifted because the drag handle is on the right edge of the
|
||||
// list item and the preview is wider than the drag handle.
|
||||
|
||||
const { x, y } = currentOffset;
|
||||
const handleOffset = formGroupSmallWidth - formLabelLargeWidth - formLabelRightMarginWidth - dragHandleWidth;
|
||||
const transform = `translate3d(${x - handleOffset}px, ${y}px, 0)`;
|
||||
|
||||
const style = {
|
||||
position: 'absolute',
|
||||
WebkitTransform: transform,
|
||||
msTransform: transform,
|
||||
transform
|
||||
};
|
||||
|
||||
const {
|
||||
languageId,
|
||||
name,
|
||||
allowed,
|
||||
sortIndex
|
||||
} = item;
|
||||
|
||||
return (
|
||||
<DragPreviewLayer>
|
||||
<div
|
||||
className={styles.dragPreview}
|
||||
style={style}
|
||||
>
|
||||
<LanguageProfileItem
|
||||
languageId={languageId}
|
||||
name={name}
|
||||
allowed={allowed}
|
||||
sortIndex={sortIndex}
|
||||
isDragging={false}
|
||||
/>
|
||||
</div>
|
||||
</DragPreviewLayer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LanguageProfileItemDragPreview.propTypes = {
|
||||
item: PropTypes.object,
|
||||
itemType: PropTypes.string,
|
||||
currentOffset: PropTypes.shape({
|
||||
x: PropTypes.number.isRequired,
|
||||
y: PropTypes.number.isRequired
|
||||
})
|
||||
};
|
||||
|
||||
export default DragLayer(collectDragLayer)(LanguageProfileItemDragPreview);
|
@ -1,18 +0,0 @@
|
||||
.languageProfileItemDragSource {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.languageProfileItemPlaceholder {
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
border: 1px dotted #aaa;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.languageProfileItemPlaceholderBefore {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.languageProfileItemPlaceholderAfter {
|
||||
margin-top: 8px;
|
||||
}
|
@ -1,157 +0,0 @@
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { DragSource, DropTarget } from 'react-dnd';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import { QUALITY_PROFILE_ITEM } from 'Helpers/dragTypes';
|
||||
import LanguageProfileItem from './LanguageProfileItem';
|
||||
import styles from './LanguageProfileItemDragSource.css';
|
||||
|
||||
const languageProfileItemDragSource = {
|
||||
beginDrag({ languageId, name, allowed, sortIndex }) {
|
||||
return {
|
||||
languageId,
|
||||
name,
|
||||
allowed,
|
||||
sortIndex
|
||||
};
|
||||
},
|
||||
|
||||
endDrag(props, monitor, component) {
|
||||
props.onLanguageProfileItemDragEnd(monitor.getItem(), monitor.didDrop());
|
||||
}
|
||||
};
|
||||
|
||||
const languageProfileItemDropTarget = {
|
||||
hover(props, monitor, component) {
|
||||
const dragIndex = monitor.getItem().sortIndex;
|
||||
const hoverIndex = props.sortIndex;
|
||||
|
||||
const hoverBoundingRect = findDOMNode(component).getBoundingClientRect();
|
||||
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
|
||||
const clientOffset = monitor.getClientOffset();
|
||||
const hoverClientY = clientOffset.y - hoverBoundingRect.top;
|
||||
|
||||
// Moving up, only trigger if drag position is above 50%
|
||||
if (dragIndex < hoverIndex && hoverClientY > hoverMiddleY) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Moving down, only trigger if drag position is below 50%
|
||||
if (dragIndex > hoverIndex && hoverClientY < hoverMiddleY) {
|
||||
return;
|
||||
}
|
||||
|
||||
props.onLanguageProfileItemDragMove(dragIndex, hoverIndex);
|
||||
}
|
||||
};
|
||||
|
||||
function collectDragSource(connect, monitor) {
|
||||
return {
|
||||
connectDragSource: connect.dragSource(),
|
||||
isDragging: monitor.isDragging()
|
||||
};
|
||||
}
|
||||
|
||||
function collectDropTarget(connect, monitor) {
|
||||
return {
|
||||
connectDropTarget: connect.dropTarget(),
|
||||
isOver: monitor.isOver()
|
||||
};
|
||||
}
|
||||
|
||||
class LanguageProfileItemDragSource extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
languageId,
|
||||
name,
|
||||
allowed,
|
||||
sortIndex,
|
||||
isDragging,
|
||||
isDraggingUp,
|
||||
isDraggingDown,
|
||||
isOver,
|
||||
connectDragSource,
|
||||
connectDropTarget,
|
||||
onLanguageProfileItemAllowedChange
|
||||
} = this.props;
|
||||
|
||||
const isBefore = !isDragging && isDraggingUp && isOver;
|
||||
const isAfter = !isDragging && isDraggingDown && isOver;
|
||||
|
||||
// if (isDragging && !isOver) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
return connectDropTarget(
|
||||
<div
|
||||
className={classNames(
|
||||
styles.languageProfileItemDragSource,
|
||||
isBefore && styles.isDraggingUp,
|
||||
isAfter && styles.isDraggingDown
|
||||
)}
|
||||
>
|
||||
{
|
||||
isBefore &&
|
||||
<div
|
||||
className={classNames(
|
||||
styles.languageProfileItemPlaceholder,
|
||||
styles.languageProfileItemPlaceholderBefore
|
||||
)}
|
||||
/>
|
||||
}
|
||||
|
||||
<LanguageProfileItem
|
||||
languageId={languageId}
|
||||
name={name}
|
||||
allowed={allowed}
|
||||
sortIndex={sortIndex}
|
||||
isDragging={isDragging}
|
||||
isOver={isOver}
|
||||
connectDragSource={connectDragSource}
|
||||
onLanguageProfileItemAllowedChange={onLanguageProfileItemAllowedChange}
|
||||
/>
|
||||
|
||||
{
|
||||
isAfter &&
|
||||
<div
|
||||
className={classNames(
|
||||
styles.languageProfileItemPlaceholder,
|
||||
styles.languageProfileItemPlaceholderAfter
|
||||
)}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LanguageProfileItemDragSource.propTypes = {
|
||||
languageId: PropTypes.number.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
allowed: PropTypes.bool.isRequired,
|
||||
sortIndex: PropTypes.number.isRequired,
|
||||
isDragging: PropTypes.bool,
|
||||
isDraggingUp: PropTypes.bool,
|
||||
isDraggingDown: PropTypes.bool,
|
||||
isOver: PropTypes.bool,
|
||||
connectDragSource: PropTypes.func,
|
||||
connectDropTarget: PropTypes.func,
|
||||
onLanguageProfileItemAllowedChange: PropTypes.func.isRequired,
|
||||
onLanguageProfileItemDragMove: PropTypes.func.isRequired,
|
||||
onLanguageProfileItemDragEnd: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default DropTarget(
|
||||
QUALITY_PROFILE_ITEM,
|
||||
languageProfileItemDropTarget,
|
||||
collectDropTarget
|
||||
)(DragSource(
|
||||
QUALITY_PROFILE_ITEM,
|
||||
languageProfileItemDragSource,
|
||||
collectDragSource
|
||||
)(LanguageProfileItemDragSource));
|
@ -1,6 +0,0 @@
|
||||
.languages {
|
||||
margin-top: 10px;
|
||||
/* TODO: This should consider the number of languages in the list */
|
||||
min-height: 550px;
|
||||
user-select: none;
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import FormGroup from 'Components/Form/FormGroup';
|
||||
import FormInputHelpText from 'Components/Form/FormInputHelpText';
|
||||
import FormLabel from 'Components/Form/FormLabel';
|
||||
import LanguageProfileItemDragPreview from './LanguageProfileItemDragPreview';
|
||||
import LanguageProfileItemDragSource from './LanguageProfileItemDragSource';
|
||||
import styles from './LanguageProfileItems.css';
|
||||
|
||||
class LanguageProfileItems extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
dragIndex,
|
||||
dropIndex,
|
||||
languageProfileItems,
|
||||
errors,
|
||||
warnings,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
const isDragging = dropIndex !== null;
|
||||
const isDraggingUp = isDragging && dropIndex > dragIndex;
|
||||
const isDraggingDown = isDragging && dropIndex < dragIndex;
|
||||
|
||||
return (
|
||||
<FormGroup>
|
||||
<FormLabel>Languages</FormLabel>
|
||||
<div>
|
||||
<FormInputHelpText
|
||||
text="Languages higher in the list are more preferred. Only checked languages are wanted"
|
||||
/>
|
||||
|
||||
{
|
||||
errors.map((error, index) => {
|
||||
return (
|
||||
<FormInputHelpText
|
||||
key={index}
|
||||
text={error.message}
|
||||
isError={true}
|
||||
isCheckInput={false}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
warnings.map((warning, index) => {
|
||||
return (
|
||||
<FormInputHelpText
|
||||
key={index}
|
||||
text={warning.message}
|
||||
isWarning={true}
|
||||
isCheckInput={false}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
<div className={styles.languages}>
|
||||
{
|
||||
languageProfileItems.map(({ allowed, language }, index) => {
|
||||
return (
|
||||
<LanguageProfileItemDragSource
|
||||
key={language.id}
|
||||
languageId={language.id}
|
||||
name={language.name}
|
||||
allowed={allowed}
|
||||
sortIndex={index}
|
||||
isDragging={isDragging}
|
||||
isDraggingUp={isDraggingUp}
|
||||
isDraggingDown={isDraggingDown}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
}).reverse()
|
||||
}
|
||||
|
||||
<LanguageProfileItemDragPreview />
|
||||
</div>
|
||||
</div>
|
||||
</FormGroup>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LanguageProfileItems.propTypes = {
|
||||
dragIndex: PropTypes.number,
|
||||
dropIndex: PropTypes.number,
|
||||
languageProfileItems: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
errors: PropTypes.arrayOf(PropTypes.object),
|
||||
warnings: PropTypes.arrayOf(PropTypes.object)
|
||||
};
|
||||
|
||||
LanguageProfileItems.defaultProps = {
|
||||
errors: [],
|
||||
warnings: []
|
||||
};
|
||||
|
||||
export default LanguageProfileItems;
|
@ -1,31 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import createLanguageProfileSelector from 'Store/Selectors/createLanguageProfileSelector';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createLanguageProfileSelector(),
|
||||
(languageProfile) => {
|
||||
return {
|
||||
name: languageProfile.name
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function LanguageProfileNameConnector({ name, ...otherProps }) {
|
||||
return (
|
||||
<span>
|
||||
{name}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
LanguageProfileNameConnector.propTypes = {
|
||||
languageProfileId: PropTypes.number.isRequired,
|
||||
name: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps)(LanguageProfileNameConnector);
|
@ -1,21 +0,0 @@
|
||||
.languageProfiles {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.addLanguageProfile {
|
||||
composes: languageProfile from '~./LanguageProfile.css';
|
||||
|
||||
background-color: var(--cardAlternateBackgroundColor);
|
||||
color: var(--gray);
|
||||
text-align: center;
|
||||
font-size: 45px;
|
||||
}
|
||||
|
||||
.center {
|
||||
display: inline-block;
|
||||
padding: 5px 20px 0;
|
||||
border: 1px solid var(--borderColor);
|
||||
border-radius: 4px;
|
||||
background-color: var(--cardCenterBackgroundColor);
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Card from 'Components/Card';
|
||||
import FieldSet from 'Components/FieldSet';
|
||||
import Icon from 'Components/Icon';
|
||||
import PageSectionContent from 'Components/Page/PageSectionContent';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import EditLanguageProfileModalConnector from './EditLanguageProfileModalConnector';
|
||||
import LanguageProfile from './LanguageProfile';
|
||||
import styles from './LanguageProfiles.css';
|
||||
|
||||
class LanguageProfiles extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
isLanguageProfileModalOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onCloneLanguageProfilePress = (id) => {
|
||||
this.props.onCloneLanguageProfilePress(id);
|
||||
this.setState({ isLanguageProfileModalOpen: true });
|
||||
};
|
||||
|
||||
onEditLanguageProfilePress = () => {
|
||||
this.setState({ isLanguageProfileModalOpen: true });
|
||||
};
|
||||
|
||||
onModalClose = () => {
|
||||
this.setState({ isLanguageProfileModalOpen: false });
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
items,
|
||||
isDeleting,
|
||||
onConfirmDeleteLanguageProfile,
|
||||
onCloneLanguageProfilePress,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<FieldSet legend="Language Profiles">
|
||||
<PageSectionContent
|
||||
errorMessage="Unable to load Language Profiles"
|
||||
{...otherProps}
|
||||
>
|
||||
<div className={styles.languageProfiles}>
|
||||
{
|
||||
items.map((item) => {
|
||||
return (
|
||||
<LanguageProfile
|
||||
key={item.id}
|
||||
{...item}
|
||||
isDeleting={isDeleting}
|
||||
onConfirmDeleteLanguageProfile={onConfirmDeleteLanguageProfile}
|
||||
onCloneLanguageProfilePress={this.onCloneLanguageProfilePress}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
<Card
|
||||
className={styles.addLanguageProfile}
|
||||
onPress={this.onEditLanguageProfilePress}
|
||||
>
|
||||
<div className={styles.center}>
|
||||
<Icon
|
||||
name={icons.ADD}
|
||||
size={45}
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<EditLanguageProfileModalConnector
|
||||
isOpen={this.state.isLanguageProfileModalOpen}
|
||||
onModalClose={this.onModalClose}
|
||||
/>
|
||||
</PageSectionContent>
|
||||
</FieldSet>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LanguageProfiles.propTypes = {
|
||||
advancedSettings: PropTypes.bool.isRequired,
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
isDeleting: PropTypes.bool.isRequired,
|
||||
onConfirmDeleteLanguageProfile: PropTypes.func.isRequired,
|
||||
onCloneLanguageProfilePress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default LanguageProfiles;
|
@ -1,69 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { cloneLanguageProfile, deleteLanguageProfile, fetchLanguageProfiles } from 'Store/Actions/settingsActions';
|
||||
import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector';
|
||||
import sortByName from 'Utilities/Array/sortByName';
|
||||
import LanguageProfiles from './LanguageProfiles';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.settings.advancedSettings,
|
||||
createSortedSectionSelector('settings.languageProfiles', sortByName),
|
||||
(advancedSettings, languageProfiles) => {
|
||||
return {
|
||||
advancedSettings,
|
||||
...languageProfiles
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
dispatchFetchLanguageProfiles: fetchLanguageProfiles,
|
||||
dispatchDeleteLanguageProfile: deleteLanguageProfile,
|
||||
dispatchCloneLanguageProfile: cloneLanguageProfile
|
||||
};
|
||||
|
||||
class LanguageProfilesConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
this.props.dispatchFetchLanguageProfiles();
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onConfirmDeleteLanguageProfile = (id) => {
|
||||
this.props.dispatchDeleteLanguageProfile({ id });
|
||||
};
|
||||
|
||||
onCloneLanguageProfilePress = (id) => {
|
||||
this.props.dispatchCloneLanguageProfile({ id });
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<LanguageProfiles
|
||||
onConfirmDeleteLanguageProfile={this.onConfirmDeleteLanguageProfile}
|
||||
onCloneLanguageProfilePress={this.onCloneLanguageProfilePress}
|
||||
{...this.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LanguageProfilesConnector.propTypes = {
|
||||
dispatchFetchLanguageProfiles: PropTypes.func.isRequired,
|
||||
dispatchDeleteLanguageProfile: PropTypes.func.isRequired,
|
||||
dispatchCloneLanguageProfile: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(LanguageProfilesConnector);
|
@ -5,7 +5,6 @@ import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
|
||||
import DelayProfilesConnector from './Delay/DelayProfilesConnector';
|
||||
import LanguageProfilesConnector from './Language/LanguageProfilesConnector';
|
||||
import QualityProfilesConnector from './Quality/QualityProfilesConnector';
|
||||
import ReleaseProfilesConnector from './Release/ReleaseProfilesConnector';
|
||||
|
||||
@ -25,7 +24,6 @@ class Profiles extends Component {
|
||||
<PageContentBody>
|
||||
<DndProvider options={HTML5toTouch}>
|
||||
<QualityProfilesConnector />
|
||||
<LanguageProfilesConnector />
|
||||
<DelayProfilesConnector />
|
||||
<ReleaseProfilesConnector />
|
||||
</DndProvider>
|
||||
|
@ -3,7 +3,7 @@ import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { clearPendingChanges } from 'Store/Actions/baseActions';
|
||||
import { fetchLanguageProfileSchema, fetchUISettings, saveUISettings, setUISettingsValue } from 'Store/Actions/settingsActions';
|
||||
import { fetchUISettings, saveUISettings, setUISettingsValue } from 'Store/Actions/settingsActions';
|
||||
import createLanguagesSelector from 'Store/Selectors/createLanguagesSelector';
|
||||
import createSettingsSectionSelector from 'Store/Selectors/createSettingsSectionSelector';
|
||||
import UISettings from './UISettings';
|
||||
@ -20,11 +20,11 @@ function createFilteredLanguagesSelector() {
|
||||
}
|
||||
|
||||
const newItems = languages.items
|
||||
.filter((lang) => !FILTER_LANGUAGES.includes(lang.language.name))
|
||||
.filter((lang) => !FILTER_LANGUAGES.includes(lang.name))
|
||||
.map((item) => {
|
||||
return {
|
||||
key: item.language.id,
|
||||
value: item.language.name
|
||||
key: item.id,
|
||||
value: item.name
|
||||
};
|
||||
});
|
||||
|
||||
@ -58,8 +58,7 @@ const mapDispatchToProps = {
|
||||
dispatchSetUISettingsValue: setUISettingsValue,
|
||||
dispatchSaveUISettings: saveUISettings,
|
||||
dispatchFetchUISettings: fetchUISettings,
|
||||
dispatchClearPendingChanges: clearPendingChanges,
|
||||
dispatchFetchLanguageProfileSchema: fetchLanguageProfileSchema
|
||||
dispatchClearPendingChanges: clearPendingChanges
|
||||
};
|
||||
|
||||
class UISettingsConnector extends Component {
|
||||
@ -69,16 +68,10 @@ class UISettingsConnector extends Component {
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
isLanguagesPopulated,
|
||||
dispatchFetchUISettings,
|
||||
dispatchFetchLanguageProfileSchema
|
||||
dispatchFetchUISettings
|
||||
} = this.props;
|
||||
|
||||
dispatchFetchUISettings();
|
||||
|
||||
if (!isLanguagesPopulated) {
|
||||
dispatchFetchLanguageProfileSchema();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
@ -115,8 +108,7 @@ UISettingsConnector.propTypes = {
|
||||
dispatchSetUISettingsValue: PropTypes.func.isRequired,
|
||||
dispatchSaveUISettings: PropTypes.func.isRequired,
|
||||
dispatchFetchUISettings: PropTypes.func.isRequired,
|
||||
dispatchClearPendingChanges: PropTypes.func.isRequired,
|
||||
dispatchFetchLanguageProfileSchema: PropTypes.func.isRequired
|
||||
dispatchClearPendingChanges: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(UISettingsConnector);
|
||||
|
@ -1,97 +0,0 @@
|
||||
import { createAction } from 'redux-actions';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createFetchSchemaHandler from 'Store/Actions/Creators/createFetchSchemaHandler';
|
||||
import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler';
|
||||
import createSaveProviderHandler from 'Store/Actions/Creators/createSaveProviderHandler';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import updateSectionState from 'Utilities/State/updateSectionState';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.languageProfiles';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_LANGUAGE_PROFILES = 'settings/languageProfiles/fetchLanguageProfiles';
|
||||
export const FETCH_LANGUAGE_PROFILE_SCHEMA = 'settings/languageProfiles/fetchLanguageProfileSchema';
|
||||
export const SAVE_LANGUAGE_PROFILE = 'settings/languageProfiles/saveLanguageProfile';
|
||||
export const DELETE_LANGUAGE_PROFILE = 'settings/languageProfiles/deleteLanguageProfile';
|
||||
export const SET_LANGUAGE_PROFILE_VALUE = 'settings/languageProfiles/setLanguageProfileValue';
|
||||
export const CLONE_LANGUAGE_PROFILE = 'settings/languageProfiles/cloneLanguageProfile';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchLanguageProfiles = createThunk(FETCH_LANGUAGE_PROFILES);
|
||||
export const fetchLanguageProfileSchema = createThunk(FETCH_LANGUAGE_PROFILE_SCHEMA);
|
||||
export const saveLanguageProfile = createThunk(SAVE_LANGUAGE_PROFILE);
|
||||
export const deleteLanguageProfile = createThunk(DELETE_LANGUAGE_PROFILE);
|
||||
|
||||
export const setLanguageProfileValue = createAction(SET_LANGUAGE_PROFILE_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const cloneLanguageProfile = createAction(CLONE_LANGUAGE_PROFILE);
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
isDeleting: false,
|
||||
deleteError: null,
|
||||
isSchemaFetching: false,
|
||||
isSchemaPopulated: false,
|
||||
schemaError: null,
|
||||
schema: {},
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
items: [],
|
||||
pendingChanges: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_LANGUAGE_PROFILES]: createFetchHandler(section, '/languageprofile'),
|
||||
[FETCH_LANGUAGE_PROFILE_SCHEMA]: createFetchSchemaHandler(section, '/languageprofile/schema'),
|
||||
[SAVE_LANGUAGE_PROFILE]: createSaveProviderHandler(section, '/languageprofile'),
|
||||
[DELETE_LANGUAGE_PROFILE]: createRemoveItemHandler(section, '/languageprofile')
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_LANGUAGE_PROFILE_VALUE]: createSetSettingValueReducer(section),
|
||||
|
||||
[CLONE_LANGUAGE_PROFILE]: function(state, { payload }) {
|
||||
const id = payload.id;
|
||||
const newState = getSectionState(state, section);
|
||||
const item = newState.items.find((i) => i.id === id);
|
||||
const pendingChanges = { ...item, id: 0 };
|
||||
delete pendingChanges.id;
|
||||
|
||||
pendingChanges.name = `${pendingChanges.name} - Copy`;
|
||||
newState.pendingChanges = pendingChanges;
|
||||
|
||||
return updateSectionState(state, section, newState);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
48
frontend/src/Store/Actions/Settings/languages.js
Normal file
48
frontend/src/Store/Actions/Settings/languages.js
Normal file
@ -0,0 +1,48 @@
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.languages';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_LANGUAGES = 'settings/languages/fetchLanguages';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchLanguages = createThunk(FETCH_LANGUAGES);
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_LANGUAGES]: createFetchHandler(section, '/language')
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -34,7 +34,6 @@ export const defaultState = {
|
||||
rootFolderPath: '',
|
||||
monitor: monitorOptions[0].key,
|
||||
qualityProfileId: 0,
|
||||
languageProfileId: 0,
|
||||
seriesType: seriesTypes.STANDARD,
|
||||
seasonFolder: true,
|
||||
searchForMissingEpisodes: false,
|
||||
|
@ -43,8 +43,8 @@ export const defaultState = {
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'language',
|
||||
label: 'Language',
|
||||
name: 'languages',
|
||||
label: 'Languages',
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
|
@ -60,8 +60,8 @@ export const defaultState = {
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'language',
|
||||
label: 'Language',
|
||||
name: 'languages',
|
||||
label: 'Languages',
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
|
@ -162,7 +162,7 @@ export const actionHandlers = handleThunks({
|
||||
|
||||
props.qualityCutoffNotMet = episodeFile.qualityCutoffNotMet;
|
||||
props.languageCutoffNotMet = episodeFile.languageCutoffNotMet;
|
||||
props.language = file.language;
|
||||
props.languages = file.languages;
|
||||
props.quality = file.quality;
|
||||
props.releaseGroup = file.releaseGroup;
|
||||
|
||||
|
@ -52,8 +52,8 @@ export const defaultState = {
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'language',
|
||||
label: 'Language',
|
||||
name: 'languages',
|
||||
label: 'Languages',
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
|
@ -177,7 +177,7 @@ export const actionHandlers = handleThunks({
|
||||
seasonNumber: item.seasonNumber,
|
||||
episodeIds: (item.episodes || []).map((e) => e.id),
|
||||
quality: item.quality,
|
||||
language: item.language,
|
||||
languages: item.languages,
|
||||
releaseGroup: item.releaseGroup,
|
||||
downloadId: item.downloadId
|
||||
};
|
||||
|
@ -87,8 +87,8 @@ export const defaultState = {
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'language',
|
||||
label: 'Language',
|
||||
name: 'languages',
|
||||
label: 'Languages',
|
||||
isSortable: true,
|
||||
isVisible: false
|
||||
},
|
||||
|
@ -204,12 +204,6 @@ export const filterBuilderProps = [
|
||||
type: filterBuilderTypes.EXACT,
|
||||
valueType: filterBuilderValueTypes.QUALITY_PROFILE
|
||||
},
|
||||
{
|
||||
name: 'languageProfileId',
|
||||
label: 'Language Profile',
|
||||
type: filterBuilderTypes.EXACT,
|
||||
valueType: filterBuilderValueTypes.LANGUAGE_PROFILE
|
||||
},
|
||||
{
|
||||
name: 'nextAiring',
|
||||
label: 'Next Airing',
|
||||
|
@ -53,12 +53,6 @@ export const defaultState = {
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'languageProfileId',
|
||||
label: 'Language Profile',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'seriesType',
|
||||
label: 'Type',
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user