[UI Work] Add Artist, Import Artist, Calendar

pull/6/head
Qstick 7 years ago
parent a747c5f135
commit 77f1d2e64c

@ -168,7 +168,7 @@ function HistoryDetails(props) {
reasonMessage = 'File was deleted by via UI';
break;
case 'MissingFromDisk':
reasonMessage = 'Sonarr was unable to find the file on disk so it was removed';
reasonMessage = 'Lidarr was unable to find the file on disk so it was removed';
break;
case 'Upgrade':
reasonMessage = 'File was deleted to import an upgrade';

@ -79,7 +79,7 @@ class RemoveQueueItemModal extends Component {
type={inputTypes.CHECK}
name="blacklist"
value={blacklist}
helpText="Prevents Sonarr from automatically grabbing this episode again"
helpText="Prevents Lidarr from automatically grabbing this episode again"
onChange={this.onBlacklistChange}
/>
</FormGroup>

@ -79,7 +79,7 @@ class RemoveQueueItemsModal extends Component {
type={inputTypes.CHECK}
name="blacklist"
value={blacklist}
helpText="Prevents Sonarr from automatically grabbing this episode again"
helpText="Prevents Lidarr from automatically grabbing this episode again"
onChange={this.onBlacklistChange}
/>
</FormGroup>

@ -8,10 +8,10 @@ import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import TextInput from 'Components/Form/TextInput';
import PageContent from 'Components/Page/PageContent';
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
import AddNewSeriesSearchResultConnector from './AddNewSeriesSearchResultConnector';
import styles from './AddNewSeries.css';
import AddNewArtistSearchResultConnector from './AddNewArtistSearchResultConnector';
import styles from './AddNewArtist.css';
class AddNewSeries extends Component {
class AddNewArtist extends Component {
//
// Lifecycle
@ -29,7 +29,7 @@ class AddNewSeries extends Component {
const term = this.state.term;
if (term) {
this.props.onSeriesLookupChange(term);
this.props.onArtistLookupChange(term);
}
}
@ -44,7 +44,7 @@ class AddNewSeries extends Component {
term,
isFetching: true
});
this.props.onSeriesLookupChange(term);
this.props.onArtistLookupChange(term);
} else if (isFetching !== prevProps.isFetching) {
this.setState({
isFetching
@ -60,16 +60,16 @@ class AddNewSeries extends Component {
this.setState({ term: value, isFetching: hasValue }, () => {
if (hasValue) {
this.props.onSeriesLookupChange(value);
this.props.onArtistLookupChange(value);
} else {
this.props.onClearSeriesLookup();
this.props.onClearArtistLookup();
}
});
}
onClearSeriesLookupPress = () => {
onClearArtistLookupPress = () => {
this.setState({ term: '' });
this.props.onClearSeriesLookup();
this.props.onClearArtistLookup();
}
//
@ -97,7 +97,7 @@ class AddNewSeries extends Component {
<TextInput
className={styles.searchInput}
name="seriesLookup"
name="artistLookup"
value={term}
placeholder="eg. Breaking Benjamin, lidarr:####"
onChange={this.onSearchInputChange}
@ -105,7 +105,7 @@ class AddNewSeries extends Component {
<Button
className={styles.clearLookupButton}
onPress={this.onClearSeriesLookupPress}
onPress={this.onClearArtistLookupPress}
>
<Icon
name={icons.REMOVE}
@ -130,7 +130,7 @@ class AddNewSeries extends Component {
{
items.map((item) => {
return (
<AddNewSeriesSearchResultConnector
<AddNewArtistSearchResultConnector
key={item.foreignArtistId}
{...item}
/>
@ -157,7 +157,7 @@ class AddNewSeries extends Component {
!term &&
<div className={styles.message}>
<div className={styles.helpText}>It's easy to add a new artist, just start typing the name the artist you want to add.</div>
<div>You can also search using MusicBrainz ID of a show. eg. lidarr:71663</div>
<div>You can also search using MusicBrainz ID of a show. eg. lidarr:cc197bad-dc9c-440d-a5b5-d52ba2e14234</div>
</div>
}
@ -170,15 +170,15 @@ class AddNewSeries extends Component {
}
}
AddNewSeries.propTypes = {
AddNewArtist.propTypes = {
term: PropTypes.string,
isFetching: PropTypes.bool.isRequired,
error: PropTypes.object,
isAdding: PropTypes.bool.isRequired,
addError: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
onSeriesLookupChange: PropTypes.func.isRequired,
onClearSeriesLookup: PropTypes.func.isRequired
onArtistLookupChange: PropTypes.func.isRequired,
onClearArtistLookup: PropTypes.func.isRequired
};
export default AddNewSeries;
export default AddNewArtist;

@ -3,32 +3,32 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import queryString from 'query-string';
import { lookupSeries, clearAddSeries } from 'Store/Actions/addSeriesActions';
import { lookupArtist, clearAddArtist } from 'Store/Actions/addArtistActions';
import { fetchRootFolders } from 'Store/Actions/rootFolderActions';
import AddNewSeries from './AddNewSeries';
import AddNewArtist from './AddNewArtist';
function createMapStateToProps() {
return createSelector(
(state) => state.addSeries,
(state) => state.addArtist,
(state) => state.routing.location,
(addSeries, location) => {
(addArtist, location) => {
const query = queryString.parse(location.search);
return {
term: query.term,
...addSeries
...addArtist
};
}
);
}
const mapDispatchToProps = {
lookupSeries,
clearAddSeries,
lookupArtist,
clearAddArtist,
fetchRootFolders
};
class AddNewSeriesConnector extends Component {
class AddNewArtistConnector extends Component {
//
// Lifecycle
@ -36,7 +36,7 @@ class AddNewSeriesConnector extends Component {
constructor(props, context) {
super(props, context);
this._seriesLookupTimeout = null;
this._artistLookupTimeout = null;
}
componentDidMount() {
@ -44,32 +44,32 @@ class AddNewSeriesConnector extends Component {
}
componentWillUnmount() {
if (this._seriesLookupTimeout) {
clearTimeout(this._seriesLookupTimeout);
if (this._artistLookupTimeout) {
clearTimeout(this._artistLookupTimeout);
}
this.props.clearAddSeries();
this.props.clearAddArtist();
}
//
// Listeners
onSeriesLookupChange = (term) => {
if (this._seriesLookupTimeout) {
clearTimeout(this._seriesLookupTimeout);
onArtistLookupChange = (term) => {
if (this._artistLookupTimeout) {
clearTimeout(this._artistLookupTimeout);
}
if (term.trim() === '') {
this.props.clearAddSeries();
this.props.clearAddArtist();
} else {
this._seriesLookupTimeout = setTimeout(() => {
this.props.lookupSeries({ term });
this._artistLookupTimeout = setTimeout(() => {
this.props.lookupArtist({ term });
}, 300);
}
}
onClearSeriesLookup = () => {
this.props.clearAddSeries();
onClearArtistLookup = () => {
this.props.clearAddArtist();
}
//
@ -82,21 +82,21 @@ class AddNewSeriesConnector extends Component {
} = this.props;
return (
<AddNewSeries
<AddNewArtist
term={term}
{...otherProps}
onSeriesLookupChange={this.onSeriesLookupChange}
onClearSeriesLookup={this.onClearSeriesLookup}
onArtistLookupChange={this.onArtistLookupChange}
onClearArtistLookup={this.onClearArtistLookup}
/>
);
}
}
AddNewSeriesConnector.propTypes = {
AddNewArtistConnector.propTypes = {
term: PropTypes.string,
lookupSeries: PropTypes.func.isRequired,
clearAddSeries: PropTypes.func.isRequired,
lookupArtist: PropTypes.func.isRequired,
clearAddArtist: PropTypes.func.isRequired,
fetchRootFolders: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(AddNewSeriesConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(AddNewArtistConnector);

@ -1,9 +1,9 @@
import PropTypes from 'prop-types';
import React from 'react';
import Modal from 'Components/Modal/Modal';
import AddNewSeriesModalContentConnector from './AddNewSeriesModalContentConnector';
import AddNewArtistModalContentConnector from './AddNewArtistModalContentConnector';
function AddNewSeriesModal(props) {
function AddNewArtistModal(props) {
const {
isOpen,
onModalClose,
@ -15,7 +15,7 @@ function AddNewSeriesModal(props) {
isOpen={isOpen}
onModalClose={onModalClose}
>
<AddNewSeriesModalContentConnector
<AddNewArtistModalContentConnector
{...otherProps}
onModalClose={onModalClose}
/>
@ -23,9 +23,9 @@ function AddNewSeriesModal(props) {
);
}
AddNewSeriesModal.propTypes = {
AddNewArtistModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default AddNewSeriesModal;
export default AddNewArtistModal;

@ -25,23 +25,23 @@
margin-left: 8px;
}
.searchForMissingEpisodesLabelContainer {
.searchForMissingAlbumsLabelContainer {
display: flex;
margin-top: 2px;
}
.searchForMissingEpisodesLabel {
.searchForMissingAlbumsLabel {
margin-right: 8px;
font-weight: normal;
}
.searchForMissingEpisodesContainer {
.searchForMissingAlbumsContainer {
composes: container from 'Components/Form/CheckInput.css';
flex: 0 1 0;
}
.searchForMissingEpisodesInput {
.searchForMissingAlbumsInput {
composes: input from 'Components/Form/CheckInput.css';
margin-top: 0;

@ -14,11 +14,11 @@ import ModalBody from 'Components/Modal/ModalBody';
import ModalFooter from 'Components/Modal/ModalFooter';
import Popover from 'Components/Tooltip/Popover';
import ArtistPoster from 'Artist/ArtistPoster';
import SeriesMonitoringOptionsPopoverContent from 'AddArtist/SeriesMonitoringOptionsPopoverContent';
import SeriesTypePopoverContent from 'AddArtist/SeriesTypePopoverContent';
import styles from './AddNewSeriesModalContent.css';
import ArtistMonitoringOptionsPopoverContent from 'AddArtist/ArtistMonitoringOptionsPopoverContent';
// import SeriesTypePopoverContent from 'AddArtist/SeriesTypePopoverContent';
import styles from './AddNewArtistModalContent.css';
class AddNewSeriesModalContent extends Component {
class AddNewArtistModalContent extends Component {
//
// Lifecycle
@ -27,15 +27,15 @@ class AddNewSeriesModalContent extends Component {
super(props, context);
this.state = {
searchForMissingEpisodes: false
searchForMissingAlbums: false
};
}
//
// Listeners
onSearchForMissingEpisodesChange = ({ value }) => {
this.setState({ searchForMissingEpisodes: value });
onSearchForMissingAlbumsChange = ({ value }) => {
this.setState({ searchForMissingAlbums: value });
}
onQualityProfileIdChange = ({ value }) => {
@ -46,8 +46,8 @@ class AddNewSeriesModalContent extends Component {
this.props.onInputChange({ name: 'languageProfileId', value: parseInt(value) });
}
onAddSeriesPress = () => {
this.props.onAddSeriesPress(this.state.searchForMissingEpisodes);
onAddArtistPress = () => {
this.props.onAddArtistPress(this.state.searchForMissingAlbums);
}
//
@ -56,7 +56,7 @@ class AddNewSeriesModalContent extends Component {
render() {
const {
artistName,
year,
// year,
overview,
images,
isAdding,
@ -64,7 +64,7 @@ class AddNewSeriesModalContent extends Component {
monitor,
qualityProfileId,
languageProfileId,
seriesType,
// seriesType,
albumFolder,
tags,
showLanguageProfile,
@ -77,11 +77,6 @@ class AddNewSeriesModalContent extends Component {
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
{artistName}
{
!name.contains(year) &&
<span className={styles.year}>({year})</span>
}
</ModalHeader>
<ModalBody>
@ -126,13 +121,13 @@ class AddNewSeriesModalContent extends Component {
/>
}
title="Monitoring Options"
body={<SeriesMonitoringOptionsPopoverContent />}
body={<ArtistMonitoringOptionsPopoverContent />}
position={tooltipPositions.RIGHT}
/>
</FormLabel>
<FormInputGroup
type={inputTypes.MONITOR_EPISODES_SELECT}
type={inputTypes.MONITOR_ALBUMS_SELECT}
name="monitor"
onChange={onInputChange}
{...monitor}
@ -161,31 +156,6 @@ class AddNewSeriesModalContent extends Component {
/>
</FormGroup>
<FormGroup>
<FormLabel>
Series Type
<Popover
anchor={
<Icon
className={styles.labelIcon}
name={icons.INFO}
/>
}
title="Series Types"
body={<SeriesTypePopoverContent />}
position={tooltipPositions.RIGHT}
/>
</FormLabel>
<FormInputGroup
type={inputTypes.SERIES_TYPE_SELECT}
name="seriesType"
onChange={onInputChange}
{...seriesType}
/>
</FormGroup>
<FormGroup>
<FormLabel>Album Folder</FormLabel>
@ -213,17 +183,17 @@ class AddNewSeriesModalContent extends Component {
</ModalBody>
<ModalFooter className={styles.modalFooter}>
<label className={styles.searchForMissingEpisodesLabelContainer}>
<span className={styles.searchForMissingEpisodesLabel}>
Start search for missing episodes
<label className={styles.searchForMissingAlbumsLabelContainer}>
<span className={styles.searchForMissingAlbumsLabel}>
Start search for missing albums
</span>
<CheckInput
containerClassName={styles.searchForMissingEpisodesContainer}
className={styles.searchForMissingEpisodesInput}
name="searchForMissingEpisodes"
value={this.state.searchForMissingEpisodes}
onChange={this.onSearchForMissingEpisodesChange}
containerClassName={styles.searchForMissingAlbumsContainer}
className={styles.searchForMissingAlbumsInput}
name="searchForMissingAlbums"
value={this.state.searchForMissingAlbums}
onChange={this.onSearchForMissingAlbumsChange}
/>
</label>
@ -231,7 +201,7 @@ class AddNewSeriesModalContent extends Component {
className={styles.addButton}
kind={kinds.SUCCESS}
isSpinning={isAdding}
onPress={this.onAddSeriesPress}
onPress={this.onAddArtistPress}
>
Add {artistName}
</SpinnerButton>
@ -241,9 +211,9 @@ class AddNewSeriesModalContent extends Component {
}
}
AddNewSeriesModalContent.propTypes = {
AddNewArtistModalContent.propTypes = {
artistName: PropTypes.string.isRequired,
year: PropTypes.number.isRequired,
// year: PropTypes.number.isRequired,
overview: PropTypes.string,
images: PropTypes.arrayOf(PropTypes.object).isRequired,
isAdding: PropTypes.bool.isRequired,
@ -252,14 +222,14 @@ AddNewSeriesModalContent.propTypes = {
monitor: PropTypes.object.isRequired,
qualityProfileId: PropTypes.object,
languageProfileId: PropTypes.object,
seriesType: PropTypes.object.isRequired,
// seriesType: PropTypes.object.isRequired,
albumFolder: PropTypes.object.isRequired,
tags: PropTypes.object.isRequired,
showLanguageProfile: PropTypes.bool.isRequired,
isSmallScreen: PropTypes.bool.isRequired,
onModalClose: PropTypes.func.isRequired,
onInputChange: PropTypes.func.isRequired,
onAddSeriesPress: PropTypes.func.isRequired
onAddArtistPress: PropTypes.func.isRequired
};
export default AddNewSeriesModalContent;
export default AddNewArtistModalContent;

@ -2,22 +2,22 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { setAddSeriesDefault, addSeries } from 'Store/Actions/addSeriesActions';
import { setAddArtistDefault, addArtist } from 'Store/Actions/addArtistActions';
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
import selectSettings from 'Store/Selectors/selectSettings';
import AddNewSeriesModalContent from './AddNewSeriesModalContent';
import AddNewArtistModalContent from './AddNewArtistModalContent';
function createMapStateToProps() {
return createSelector(
(state) => state.addSeries,
(state) => state.addArtist,
(state) => state.settings.languageProfiles,
createDimensionsSelector(),
(addSeriesState, languageProfiles, dimensions) => {
(addArtistState, languageProfiles, dimensions) => {
const {
isAdding,
addError,
defaults
} = addSeriesState;
} = addArtistState;
const {
settings,
@ -39,20 +39,20 @@ function createMapStateToProps() {
}
const mapDispatchToProps = {
setAddSeriesDefault,
addSeries
setAddArtistDefault,
addArtist
};
class AddNewSeriesModalContentConnector extends Component {
class AddNewArtistModalContentConnector extends Component {
//
// Listeners
onInputChange = ({ name, value }) => {
this.props.setAddSeriesDefault({ [name]: value });
this.props.setAddArtistDefault({ [name]: value });
}
onAddSeriesPress = (searchForMissingEpisodes) => {
onAddArtistPress = (searchForMissingAlbums) => {
const {
foreignArtistId,
rootFolderPath,
@ -63,7 +63,7 @@ class AddNewSeriesModalContentConnector extends Component {
tags
} = this.props;
this.props.addSeries({
this.props.addArtist({
foreignArtistId,
rootFolderPath: rootFolderPath.value,
monitor: monitor.value,
@ -71,7 +71,7 @@ class AddNewSeriesModalContentConnector extends Component {
languageProfileId: languageProfileId.value,
albumFolder: albumFolder.value,
tags: tags.value,
searchForMissingEpisodes
searchForMissingAlbums
});
}
@ -80,16 +80,16 @@ class AddNewSeriesModalContentConnector extends Component {
render() {
return (
<AddNewSeriesModalContent
<AddNewArtistModalContent
{...this.props}
onInputChange={this.onInputChange}
onAddSeriesPress={this.onAddSeriesPress}
onAddArtistPress={this.onAddArtistPress}
/>
);
}
}
AddNewSeriesModalContentConnector.propTypes = {
AddNewArtistModalContentConnector.propTypes = {
foreignArtistId: PropTypes.string.isRequired,
rootFolderPath: PropTypes.object,
monitor: PropTypes.object.isRequired,
@ -98,8 +98,8 @@ AddNewSeriesModalContentConnector.propTypes = {
albumFolder: PropTypes.object.isRequired,
tags: PropTypes.object.isRequired,
onModalClose: PropTypes.func.isRequired,
setAddSeriesDefault: PropTypes.func.isRequired,
addSeries: PropTypes.func.isRequired
setAddArtistDefault: PropTypes.func.isRequired,
addArtist: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(AddNewSeriesModalContentConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(AddNewArtistModalContentConnector);

@ -6,10 +6,10 @@ import Icon from 'Components/Icon';
import Label from 'Components/Label';
import Link from 'Components/Link/Link';
import ArtistPoster from 'Artist/ArtistPoster';
import AddNewSeriesModal from './AddNewSeriesModal';
import styles from './AddNewSeriesSearchResult.css';
import AddNewArtistModal from './AddNewArtistModal';
import styles from './AddNewArtistSearchResult.css';
class AddNewSeriesSearchResult extends Component {
class AddNewArtistSearchResult extends Component {
//
// Lifecycle
@ -23,7 +23,7 @@ class AddNewSeriesSearchResult extends Component {
}
componentDidUpdate(prevProps) {
if (!prevProps.isExistingSeries && this.props.isExistingSeries) {
if (!prevProps.isExistingArtist && this.props.isExistingArtist) {
this.onAddSerisModalClose();
}
}
@ -54,11 +54,11 @@ class AddNewSeriesSearchResult extends Component {
seasonCount,
ratings,
images,
isExistingSeries,
isExistingArtist,
isSmallScreen
} = this.props;
const linkProps = isExistingSeries ? { to: `/series/${nameSlug}` } : { onPress: this.onPress };
const linkProps = isExistingArtist ? { to: `/series/${nameSlug}` } : { onPress: this.onPress };
let seasons = '1 Season';
if (seasonCount > 1) {
@ -89,12 +89,12 @@ class AddNewSeriesSearchResult extends Component {
}
{
isExistingSeries &&
isExistingArtist &&
<Icon
className={styles.alreadyExistsIcon}
name={icons.CHECK_CIRCLE}
size={36}
artistName="Already in your library"
title="Already in your library"
/>
}
</div>
@ -137,8 +137,8 @@ class AddNewSeriesSearchResult extends Component {
</div>
</div>
<AddNewSeriesModal
isOpen={this.state.isNewAddSeriesModalOpen && !isExistingSeries}
<AddNewArtistModal
isOpen={this.state.isNewAddSeriesModalOpen && !isExistingArtist}
foreignArtistId={foreignArtistId}
artistName={artistName}
year={year}
@ -151,7 +151,7 @@ class AddNewSeriesSearchResult extends Component {
}
}
AddNewSeriesSearchResult.propTypes = {
AddNewArtistSearchResult.propTypes = {
foreignArtistId: PropTypes.string.isRequired,
artistName: PropTypes.string.isRequired,
nameSlug: PropTypes.string.isRequired,
@ -162,8 +162,8 @@ AddNewSeriesSearchResult.propTypes = {
seasonCount: PropTypes.number,
ratings: PropTypes.object.isRequired,
images: PropTypes.arrayOf(PropTypes.object).isRequired,
isExistingSeries: PropTypes.bool.isRequired,
isExistingArtist: PropTypes.bool.isRequired,
isSmallScreen: PropTypes.bool.isRequired
};
export default AddNewSeriesSearchResult;
export default AddNewArtistSearchResult;

@ -1,20 +1,20 @@
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createExistingSeriesSelector from 'Store/Selectors/createExistingSeriesSelector';
import createExistingArtistSelector from 'Store/Selectors/createExistingArtistSelector';
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
import AddNewSeriesSearchResult from './AddNewSeriesSearchResult';
import AddNewArtistSearchResult from './AddNewArtistSearchResult';
function createMapStateToProps() {
return createSelector(
createExistingSeriesSelector(),
createExistingArtistSelector(),
createDimensionsSelector(),
(isExistingSeries, dimensions) => {
(isExistingArtist, dimensions) => {
return {
isExistingSeries,
isExistingArtist,
isSmallScreen: dimensions.isSmallScreen
};
}
);
}
export default connect(createMapStateToProps)(AddNewSeriesSearchResult);
export default connect(createMapStateToProps)(AddNewArtistSearchResult);

@ -0,0 +1,46 @@
import React from 'react';
import DescriptionList from 'Components/DescriptionList/DescriptionList';
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
function ArtistMonitoringOptionsPopoverContent() {
return (
<DescriptionList>
<DescriptionListItem
title="All Albums"
data="Monitor all albums except specials"
/>
<DescriptionListItem
title="Future Albums"
data="Monitor albums that have not released yet"
/>
<DescriptionListItem
title="Missing Albums"
data="Monitor albums that do not have files or have not released yet"
/>
<DescriptionListItem
title="Existing Albums"
data="Monitor albums that have files or have not released yet"
/>
<DescriptionListItem
title="First Album"
data="Monitor the first albums. All other albums will be ignored"
/>
<DescriptionListItem
title="Latest Album"
data="Monitor the latest albums and future albums"
/>
<DescriptionListItem
title="None"
data="No albums will be monitored."
/>
</DescriptionList>
);
}
export default ArtistMonitoringOptionsPopoverContent;

@ -6,10 +6,10 @@ import toggleSelected from 'Utilities/Table/toggleSelected';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
import ImportSeriesTableConnector from './ImportSeriesTableConnector';
import ImportSeriesFooterConnector from './ImportSeriesFooterConnector';
import ImportArtistTableConnector from './ImportArtistTableConnector';
import ImportArtistFooterConnector from './ImportArtistFooterConnector';
class ImportSeries extends Component {
class ImportArtist extends Component {
//
// Lifecycle
@ -98,7 +98,7 @@ class ImportSeries extends Component {
} = this.state;
return (
<PageContent title="Import Series">
<PageContent title="Import Artist">
<PageContentBodyConnector
ref={this.setContentBodyRef}
onScroll={this.onScroll}
@ -122,7 +122,7 @@ class ImportSeries extends Component {
{
!rootFoldersError && rootFoldersPopulated && !!unmappedFolders.length && contentBody &&
<ImportSeriesTableConnector
<ImportArtistTableConnector
rootFolderId={rootFolderId}
unmappedFolders={unmappedFolders}
allSelected={allSelected}
@ -141,7 +141,7 @@ class ImportSeries extends Component {
{
!rootFoldersError && rootFoldersPopulated && !!unmappedFolders.length &&
<ImportSeriesFooterConnector
<ImportArtistFooterConnector
selectedIds={this.getSelectedIds()}
showLanguageProfile={showLanguageProfile}
onInputChange={this.onInputChange}
@ -153,7 +153,7 @@ class ImportSeries extends Component {
}
}
ImportSeries.propTypes = {
ImportArtist.propTypes = {
rootFolderId: PropTypes.number.isRequired,
path: PropTypes.string,
rootFoldersFetching: PropTypes.bool.isRequired,
@ -166,8 +166,8 @@ ImportSeries.propTypes = {
onImportPress: PropTypes.func.isRequired
};
ImportSeries.defaultProps = {
ImportArtist.defaultProps = {
unmappedFolders: []
};
export default ImportSeries;
export default ImportArtist;

@ -3,20 +3,20 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { setImportSeriesValue, importSeries, clearImportSeries } from 'Store/Actions/importSeriesActions';
import { setImportArtistValue, importArtist, clearImportArtist } from 'Store/Actions/importArtistActions';
import { fetchRootFolders } from 'Store/Actions/rootFolderActions';
import { setAddSeriesDefault } from 'Store/Actions/addSeriesActions';
import { setAddArtistDefault } from 'Store/Actions/addArtistActions';
import createRouteMatchShape from 'Helpers/Props/Shapes/createRouteMatchShape';
import ImportSeries from './ImportSeries';
import ImportArtist from './ImportArtist';
function createMapStateToProps() {
return createSelector(
(state, { match }) => match,
(state) => state.rootFolders,
(state) => state.addSeries,
(state) => state.importSeries,
(state) => state.addArtist,
(state) => state.importArtist,
(state) => state.settings.languageProfiles,
(match, rootFolders, addSeries, importSeriesState, languageProfiles) => {
(match, rootFolders, addArtist, importArtistState, languageProfiles) => {
const {
isFetching: rootFoldersFetching,
isPopulated: rootFoldersPopulated,
@ -40,7 +40,7 @@ function createMapStateToProps() {
return {
...result,
...rootFolder,
items: importSeriesState.items
items: importArtistState.items
};
}
@ -50,14 +50,14 @@ function createMapStateToProps() {
}
const mapDispatchToProps = {
setImportSeriesValue,
importSeries,
clearImportSeries,
setImportArtistValue,
importArtist,
clearImportArtist,
fetchRootFolders,
setAddSeriesDefault
setAddArtistDefault
};
class ImportSeriesConnector extends Component {
class ImportArtistConnector extends Component {
//
// Lifecycle
@ -69,17 +69,17 @@ class ImportSeriesConnector extends Component {
}
componentWillUnmount() {
this.props.clearImportSeries();
this.props.clearImportArtist();
}
//
// Listeners
onInputChange = (ids, name, value) => {
this.props.setAddSeriesDefault({ [name]: value });
this.props.setAddArtistDefault({ [name]: value });
ids.forEach((id) => {
this.props.setImportSeriesValue({
this.props.setImportArtistValue({
id,
[name]: value
});
@ -87,7 +87,7 @@ class ImportSeriesConnector extends Component {
}
onImportPress = (ids) => {
this.props.importSeries({ ids });
this.props.importArtist({ ids });
}
//
@ -95,7 +95,7 @@ class ImportSeriesConnector extends Component {
render() {
return (
<ImportSeries
<ImportArtist
{...this.props}
onInputChange={this.onInputChange}
onImportPress={this.onImportPress}
@ -108,14 +108,14 @@ const routeMatchShape = createRouteMatchShape({
rootFolderId: PropTypes.string.isRequired
});
ImportSeriesConnector.propTypes = {
ImportArtistConnector.propTypes = {
match: routeMatchShape.isRequired,
rootFoldersPopulated: PropTypes.bool.isRequired,
setImportSeriesValue: PropTypes.func.isRequired,
importSeries: PropTypes.func.isRequired,
clearImportSeries: PropTypes.func.isRequired,
setImportArtistValue: PropTypes.func.isRequired,
importArtist: PropTypes.func.isRequired,
clearImportArtist: PropTypes.func.isRequired,
fetchRootFolders: PropTypes.func.isRequired,
setAddSeriesDefault: PropTypes.func.isRequired
setAddArtistDefault: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(ImportSeriesConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(ImportArtistConnector);

@ -7,11 +7,11 @@ import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import CheckInput from 'Components/Form/CheckInput';
import FormInputGroup from 'Components/Form/FormInputGroup';
import PageContentFooter from 'Components/Page/PageContentFooter';
import styles from './ImportSeriesFooter.css';
import styles from './ImportArtistFooter.css';
const MIXED = 'mixed';
class ImportSeriesFooter extends Component {
class ImportArtistFooter extends Component {
//
// Lifecycle
@ -23,7 +23,7 @@ class ImportSeriesFooter extends Component {
defaultMonitor,
defaultQualityProfileId,
defaultLanguageProfileId,
defaultSeasonFolder,
defaultAlbumFolder,
defaultSeriesType
} = props;
@ -32,7 +32,7 @@ class ImportSeriesFooter extends Component {
qualityProfileId: defaultQualityProfileId,
languageProfileId: defaultLanguageProfileId,
seriesType: defaultSeriesType,
seasonFolder: defaultSeasonFolder
albumFolder: defaultAlbumFolder
};
}
@ -41,21 +41,21 @@ class ImportSeriesFooter extends Component {
defaultMonitor,
defaultQualityProfileId,
defaultLanguageProfileId,
defaultSeriesType,
defaultSeasonFolder,
// defaultSeriesType,
defaultAlbumFolder,
isMonitorMixed,
isQualityProfileIdMixed,
isLanguageProfileIdMixed,
isSeriesTypeMixed,
isSeasonFolderMixed
// isSeriesTypeMixed,
isAlbumFolderMixed
} = this.props;
const {
monitor,
qualityProfileId,
languageProfileId,
seriesType,
seasonFolder
// seriesType,
albumFolder
} = this.state;
const newState = {};
@ -78,16 +78,10 @@ class ImportSeriesFooter extends Component {
newState.languageProfileId = defaultLanguageProfileId;
}
if (isSeriesTypeMixed && seriesType !== MIXED) {
newState.seriesType = MIXED;
} else if (!isSeriesTypeMixed && seriesType !== defaultSeriesType) {
newState.seriesType = defaultSeriesType;
}
if (isSeasonFolderMixed && seasonFolder != null) {
newState.seasonFolder = null;
} else if (!isSeasonFolderMixed && seasonFolder !== defaultSeasonFolder) {
newState.seasonFolder = defaultSeasonFolder;
if (isAlbumFolderMixed && albumFolder != null) {
newState.albumFolder = null;
} else if (!isAlbumFolderMixed && albumFolder !== defaultAlbumFolder) {
newState.albumFolder = defaultAlbumFolder;
}
if (!_.isEmpty(newState)) {
@ -110,11 +104,11 @@ class ImportSeriesFooter extends Component {
const {
selectedCount,
isImporting,
isLookingUpSeries,
isLookingUpArtist,
isMonitorMixed,
isQualityProfileIdMixed,
isLanguageProfileIdMixed,
isSeriesTypeMixed,
// isSeriesTypeMixed,
showLanguageProfile,
onImportPress
} = this.props;
@ -123,8 +117,8 @@ class ImportSeriesFooter extends Component {
monitor,
qualityProfileId,
languageProfileId,
seriesType,
seasonFolder
// seriesType,
albumFolder
} = this.state;
return (
@ -135,7 +129,7 @@ class ImportSeriesFooter extends Component {
</div>
<FormInputGroup
type={inputTypes.MONITOR_EPISODES_SELECT}
type={inputTypes.MONITOR_ALBUMS_SELECT}
name="monitor"
value={monitor}
isDisabled={!selectedCount}
@ -180,27 +174,12 @@ class ImportSeriesFooter extends Component {
<div className={styles.inputContainer}>
<div className={styles.label}>
Series Type
</div>
<FormInputGroup
type={inputTypes.SERIES_TYPE_SELECT}
name="seriesType"
value={seriesType}
isDisabled={!selectedCount}
includeMixed={isSeriesTypeMixed}
onChange={this.onInputChange}
/>
</div>
<div className={styles.inputContainer}>
<div className={styles.label}>
Season Folder
Album Folder
</div>
<CheckInput
name="seasonFolder"
value={seasonFolder}
name="albumFolder"
value={albumFolder}
isDisabled={!selectedCount}
onChange={this.onInputChange}
/>
@ -216,14 +195,14 @@ class ImportSeriesFooter extends Component {
className={styles.importButton}
kind={kinds.PRIMARY}
isSpinning={isImporting}
isDisabled={!selectedCount || isLookingUpSeries}
isDisabled={!selectedCount || isLookingUpArtist}
onPress={onImportPress}
>
Import {selectedCount} Series
Import {selectedCount} Artist(s)
</SpinnerButton>
{
isLookingUpSeries &&
isLookingUpArtist &&
<LoadingIndicator
className={styles.loading}
size={24}
@ -231,7 +210,7 @@ class ImportSeriesFooter extends Component {
}
{
isLookingUpSeries &&
isLookingUpArtist &&
'Processing Folders'
}
</div>
@ -241,23 +220,23 @@ class ImportSeriesFooter extends Component {
}
}
ImportSeriesFooter.propTypes = {
ImportArtistFooter.propTypes = {
selectedCount: PropTypes.number.isRequired,
isImporting: PropTypes.bool.isRequired,
isLookingUpSeries: PropTypes.bool.isRequired,
isLookingUpArtist: PropTypes.bool.isRequired,
defaultMonitor: PropTypes.string.isRequired,
defaultQualityProfileId: PropTypes.number,
defaultLanguageProfileId: PropTypes.number,
defaultSeriesType: PropTypes.string.isRequired,
defaultSeasonFolder: PropTypes.bool.isRequired,
defaultAlbumFolder: PropTypes.bool.isRequired,
isMonitorMixed: PropTypes.bool.isRequired,
isQualityProfileIdMixed: PropTypes.bool.isRequired,
isLanguageProfileIdMixed: PropTypes.bool.isRequired,
isSeriesTypeMixed: PropTypes.bool.isRequired,
isSeasonFolderMixed: PropTypes.bool.isRequired,
// isSeriesTypeMixed: PropTypes.bool.isRequired,
isAlbumFolderMixed: PropTypes.bool.isRequired,
showLanguageProfile: PropTypes.bool.isRequired,
onInputChange: PropTypes.func.isRequired,
onImportPress: PropTypes.func.isRequired
};
export default ImportSeriesFooter;
export default ImportArtistFooter;

@ -1,7 +1,7 @@
import _ from 'lodash';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import ImportSeriesFooter from './ImportSeriesFooter';
import ImportArtistFooter from './ImportArtistFooter';
function isMixed(items, selectedIds, defaultValue, key) {
return _.some(items, (series) => {
@ -11,21 +11,21 @@ function isMixed(items, selectedIds, defaultValue, key) {
function createMapStateToProps() {
return createSelector(
(state) => state.addSeries,
(state) => state.importSeries,
(state) => state.addArtist,
(state) => state.importArtist,
(state, { selectedIds }) => selectedIds,
(addSeries, importSeries, selectedIds) => {
(addArtist, importArtist, selectedIds) => {
const {
monitor: defaultMonitor,
qualityProfileId: defaultQualityProfileId,
languageProfileId: defaultLanguageProfileId,
seriesType: defaultSeriesType,
seasonFolder: defaultSeasonFolder
} = addSeries.defaults;
albumFolder: defaultAlbumFolder
} = addArtist.defaults;
const items = importSeries.items;
const items = importArtist.items;
const isLookingUpSeries = _.some(importSeries.items, (series) => {
const isLookingUpArtist = _.some(importArtist.items, (series) => {
return !series.isPopulated && series.error == null;
});
@ -33,25 +33,25 @@ function createMapStateToProps() {
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 isAlbumFolderMixed = isMixed(items, selectedIds, defaultAlbumFolder, 'albumFolder');
return {
selectedCount: selectedIds.length,
isImporting: importSeries.isImporting,
isLookingUpSeries,
isImporting: importArtist.isImporting,
isLookingUpArtist,
defaultMonitor,
defaultQualityProfileId,
defaultLanguageProfileId,
defaultSeriesType,
defaultSeasonFolder,
defaultAlbumFolder,
isMonitorMixed,
isQualityProfileIdMixed,
isLanguageProfileIdMixed,
isSeriesTypeMixed,
isSeasonFolderMixed
isAlbumFolderMixed
};
}
);
}
export default connect(createMapStateToProps)(ImportSeriesFooter);
export default connect(createMapStateToProps)(ImportArtistFooter);

@ -26,14 +26,14 @@
min-width: 120px;
}
.seasonFolder {
.albumFolder {
composes: headerCell from 'Components/Table/VirtualTableHeaderCell.css';
flex: 0 1 150px;
min-width: 120px;
}
.series {
.artist {
composes: headerCell from 'Components/Table/VirtualTableHeaderCell.css';
flex: 0 1 400px;

@ -6,11 +6,11 @@ import Popover from 'Components/Tooltip/Popover';
import VirtualTableHeader from 'Components/Table/VirtualTableHeader';
import VirtualTableHeaderCell from 'Components/Table/VirtualTableHeaderCell';
import VirtualTableSelectAllHeaderCell from 'Components/Table/VirtualTableSelectAllHeaderCell';
import SeriesMonitoringOptionsPopoverContent from 'AddArtist/SeriesMonitoringOptionsPopoverContent';
import SeriesTypePopoverContent from 'AddArtist/SeriesTypePopoverContent';
import styles from './ImportSeriesHeader.css';
import ArtistMonitoringOptionsPopoverContent from 'AddArtist/ArtistMonitoringOptionsPopoverContent';
// import SeriesTypePopoverContent from 'AddArtist/SeriesTypePopoverContent';
import styles from './ImportArtistHeader.css';
function ImportSeriesHeader(props) {
function ImportArtistHeader(props) {
const {
showLanguageProfile,
allSelected,
@ -47,7 +47,7 @@ function ImportSeriesHeader(props) {
/>
}
title="Monitoring Options"
body={<SeriesMonitoringOptionsPopoverContent />}
body={<ArtistMonitoringOptionsPopoverContent />}
position={tooltipPositions.RIGHT}
/>
</VirtualTableHeaderCell>
@ -70,46 +70,27 @@ function ImportSeriesHeader(props) {
}
<VirtualTableHeaderCell
className={styles.seriesType}
name="seriesType"
className={styles.albumFolder}
name="albumFolder"
>
Series Type
<Popover
anchor={
<Icon
className={styles.detailsIcon}
name={icons.INFO}
/>
}
title="Series Type"
body={<SeriesTypePopoverContent />}
position={tooltipPositions.RIGHT}
/>
</VirtualTableHeaderCell>
<VirtualTableHeaderCell
className={styles.seasonFolder}
name="seasonFolder"
>
Season Folder
Album Folder
</VirtualTableHeaderCell>
<VirtualTableHeaderCell
className={styles.series}
className={styles.artist}
name="series"
>
Series
Artist
</VirtualTableHeaderCell>
</VirtualTableHeader>
);
}
ImportSeriesHeader.propTypes = {
ImportArtistHeader.propTypes = {
showLanguageProfile: PropTypes.bool.isRequired,
allSelected: PropTypes.bool.isRequired,
allUnselected: PropTypes.bool.isRequired,
onSelectAllChange: PropTypes.func.isRequired
};
export default ImportSeriesHeader;
export default ImportArtistHeader;

@ -31,7 +31,7 @@
min-width: 120px;
}
.seasonFolder {
.albumFolder {
composes: cell from 'Components/Table/Cells/VirtualTableRowCell.css';
flex: 0 1 150px;

@ -5,20 +5,20 @@ import FormInputGroup from 'Components/Form/FormInputGroup';
import VirtualTableRow from 'Components/Table/VirtualTableRow';
import VirtualTableRowCell from 'Components/Table/Cells/VirtualTableRowCell';
import VirtualTableSelectCell from 'Components/Table/Cells/VirtualTableSelectCell';
import ImportSeriesSelectSeriesConnector from './SelectSeries/ImportSeriesSelectSeriesConnector';
import styles from './ImportSeriesRow.css';
import ImportArtistSelectArtistConnector from './SelectArtist/ImportArtistSelectArtistConnector';
import styles from './ImportArtistRow.css';
function ImportSeriesRow(props) {
function ImportArtistRow(props) {
const {
style,
id,
monitor,
qualityProfileId,
languageProfileId,
seasonFolder,
seriesType,
albumFolder,
// seriesType,
selectedSeries,
isExistingSeries,
isExistingArtist,
showLanguageProfile,
isSelected,
onSelectedChange,
@ -31,7 +31,7 @@ function ImportSeriesRow(props) {
inputClassName={styles.selectInput}
id={id}
isSelected={isSelected}
isDisabled={!selectedSeries || isExistingSeries}
isDisabled={!selectedSeries || isExistingArtist}
onSelectedChange={onSelectedChange}
/>
@ -41,7 +41,7 @@ function ImportSeriesRow(props) {
<VirtualTableRowCell className={styles.monitor}>
<FormInputGroup
type={inputTypes.MONITOR_EPISODES_SELECT}
type={inputTypes.MONITOR_ALBUMS_SELECT}
name="monitor"
value={monitor}
onChange={onInputChange}
@ -68,44 +68,35 @@ function ImportSeriesRow(props) {
/>
</VirtualTableRowCell>
<VirtualTableRowCell className={styles.seriesType}>
<FormInputGroup
type={inputTypes.SERIES_TYPE_SELECT}
name="seriesType"
value={seriesType}
onChange={onInputChange}
/>
</VirtualTableRowCell>
<VirtualTableRowCell className={styles.seasonFolder}>
<VirtualTableRowCell className={styles.albumFolder}>
<FormInputGroup
type={inputTypes.CHECK}
name="seasonFolder"
value={seasonFolder}
name="albumFolder"
value={albumFolder}
onChange={onInputChange}
/>
</VirtualTableRowCell>
<VirtualTableRowCell className={styles.series}>
<ImportSeriesSelectSeriesConnector
<ImportArtistSelectArtistConnector
id={id}
isExistingSeries={isExistingSeries}
isExistingArtist={isExistingArtist}
/>
</VirtualTableRowCell>
</VirtualTableRow>
);
}
ImportSeriesRow.propTypes = {
ImportArtistRow.propTypes = {
style: PropTypes.object.isRequired,
id: PropTypes.string.isRequired,
monitor: PropTypes.string.isRequired,
qualityProfileId: PropTypes.number.isRequired,
languageProfileId: PropTypes.number.isRequired,
seriesType: PropTypes.string.isRequired,
seasonFolder: PropTypes.bool.isRequired,
// seriesType: PropTypes.string.isRequired,
albumFolder: PropTypes.bool.isRequired,
selectedSeries: PropTypes.object,
isExistingSeries: PropTypes.bool.isRequired,
isExistingArtist: PropTypes.bool.isRequired,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
queued: PropTypes.bool.isRequired,
showLanguageProfile: PropTypes.bool.isRequired,
@ -114,8 +105,8 @@ ImportSeriesRow.propTypes = {
onInputChange: PropTypes.func.isRequired
};
ImportSeriesRow.defaultsProps = {
ImportArtistRow.defaultsProps = {
items: []
};
export default ImportSeriesRow;
export default ImportArtistRow;

@ -3,14 +3,14 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { queueLookupSeries, setImportSeriesValue } from 'Store/Actions/importSeriesActions';
import { queueLookupSeries, setImportArtistValue } from 'Store/Actions/importArtistActions';
import createAllSeriesSelector from 'Store/Selectors/createAllSeriesSelector';
import ImportSeriesRow from './ImportSeriesRow';
import ImportArtistRow from './ImportArtistRow';
function createImportSeriesItemSelector() {
function createImportArtistItemSelector() {
return createSelector(
(state, { id }) => id,
(state) => state.importSeries.items,
(state) => state.importArtist.items,
(id, items) => {
return _.find(items, { id }) || {};
}
@ -19,15 +19,15 @@ function createImportSeriesItemSelector() {
function createMapStateToProps() {
return createSelector(
createImportSeriesItemSelector(),
createImportArtistItemSelector(),
createAllSeriesSelector(),
(item, series) => {
const selectedSeries = item && item.selectedSeries;
const isExistingSeries = !!selectedSeries && _.some(series, { tvdbId: selectedSeries.tvdbId });
const isExistingArtist = !!selectedSeries && _.some(series, { foreignArtistId: selectedSeries.foreignArtistId });
return {
...item,
isExistingSeries
isExistingArtist
};
}
);
@ -35,16 +35,16 @@ function createMapStateToProps() {
const mapDispatchToProps = {
queueLookupSeries,
setImportSeriesValue
setImportArtistValue
};
class ImportSeriesRowConnector extends Component {
class ImportArtistRowConnector extends Component {
//
// Listeners
onInputChange = ({ name, value }) => {
this.props.setImportSeriesValue({
this.props.setImportArtistValue({
id: this.props.id,
[name]: value
});
@ -59,16 +59,16 @@ class ImportSeriesRowConnector extends Component {
const {
items,
monitor,
seriesType,
seasonFolder
// seriesType,
albumFolder
} = this.props;
if (!items || !monitor || !seriesType || !seasonFolder == null) {
if (!items || !monitor || !albumFolder == null) {
return null;
}
return (
<ImportSeriesRow
<ImportArtistRow
{...this.props}
onInputChange={this.onInputChange}
onSeriesSelect={this.onSeriesSelect}
@ -77,15 +77,15 @@ class ImportSeriesRowConnector extends Component {
}
}
ImportSeriesRowConnector.propTypes = {
ImportArtistRowConnector.propTypes = {
rootFolderId: PropTypes.number.isRequired,
id: PropTypes.string.isRequired,
monitor: PropTypes.string,
seriesType: PropTypes.string,
seasonFolder: PropTypes.bool,
// seriesType: PropTypes.string,
albumFolder: PropTypes.bool,
items: PropTypes.arrayOf(PropTypes.object),
queueLookupSeries: PropTypes.func.isRequired,
setImportSeriesValue: PropTypes.func.isRequired
setImportArtistValue: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(ImportSeriesRowConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(ImportArtistRowConnector);

@ -2,10 +2,10 @@ import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import VirtualTable from 'Components/Table/VirtualTable';
import ImportSeriesHeader from './ImportSeriesHeader';
import ImportSeriesRowConnector from './ImportSeriesRowConnector';
import ImportArtistHeader from './ImportArtistHeader';
import ImportArtistRowConnector from './ImportArtistRowConnector';
class ImportSeriesTable extends Component {
class ImportArtistTable extends Component {
//
// Lifecycle
@ -23,9 +23,9 @@ class ImportSeriesTable extends Component {
defaultQualityProfileId,
defaultLanguageProfileId,
defaultSeriesType,
defaultSeasonFolder,
defaultAlbumFolder,
onSeriesLookup,
onSetImportSeriesValue
onSetImportArtistValue
} = this.props;
const values = {
@ -33,7 +33,7 @@ class ImportSeriesTable extends Component {
qualityProfileId: defaultQualityProfileId,
languageProfileId: defaultLanguageProfileId,
seriesType: defaultSeriesType,
seasonFolder: defaultSeasonFolder
albumFolder: defaultAlbumFolder
};
unmappedFolders.forEach((unmappedFolder) => {
@ -41,7 +41,7 @@ class ImportSeriesTable extends Component {
onSeriesLookup(id, unmappedFolder.path);
onSetImportSeriesValue({
onSetImportArtistValue({
id,
...values
});
@ -75,12 +75,12 @@ class ImportSeriesTable extends Component {
const selectedSeries = item.selectedSeries;
const isSelected = selectedState[id];
const isExistingSeries = !!selectedSeries &&
const isExistingArtist = !!selectedSeries &&
_.some(prevProps.allSeries, { tvdbId: selectedSeries.tvdbId });
// Props doesn't have a selected series or
// the selected series is an existing series.
if ((selectedSeries && !prevItem.selectedSeries) || (isExistingSeries && !prevItem.selectedSeries)) {
if ((selectedSeries && !prevItem.selectedSeries) || (isExistingArtist && !prevItem.selectedSeries)) {
onSelectedChange({ id, value: false });
return;
@ -88,7 +88,7 @@ class ImportSeriesTable extends Component {
// State is selected, but a series isn't selected or
// the selected series is an existing series.
if (isSelected && (!selectedSeries || isExistingSeries)) {
if (isSelected && (!selectedSeries || isExistingArtist)) {
onSelectedChange({ id, value: false });
return;
@ -129,7 +129,7 @@ class ImportSeriesTable extends Component {
const item = items[rowIndex];
return (
<ImportSeriesRowConnector
<ImportArtistRowConnector
key={key}
style={style}
rootFolderId={rootFolderId}
@ -172,7 +172,7 @@ class ImportSeriesTable extends Component {
overscanRowCount={2}
rowRenderer={this.rowRenderer}
header={
<ImportSeriesHeader
<ImportArtistHeader
showLanguageProfile={showLanguageProfile}
allSelected={allSelected}
allUnselected={allUnselected}
@ -185,7 +185,7 @@ class ImportSeriesTable extends Component {
}
}
ImportSeriesTable.propTypes = {
ImportArtistTable.propTypes = {
rootFolderId: PropTypes.number.isRequired,
items: PropTypes.arrayOf(PropTypes.object),
unmappedFolders: PropTypes.arrayOf(PropTypes.object),
@ -193,7 +193,7 @@ ImportSeriesTable.propTypes = {
defaultQualityProfileId: PropTypes.number,
defaultLanguageProfileId: PropTypes.number,
defaultSeriesType: PropTypes.string.isRequired,
defaultSeasonFolder: PropTypes.bool.isRequired,
defaultAlbumFolder: PropTypes.bool.isRequired,
allSelected: PropTypes.bool.isRequired,
allUnselected: PropTypes.bool.isRequired,
selectedState: PropTypes.object.isRequired,
@ -206,8 +206,8 @@ ImportSeriesTable.propTypes = {
onSelectedChange: PropTypes.func.isRequired,
onRemoveSelectedStateItem: PropTypes.func.isRequired,
onSeriesLookup: PropTypes.func.isRequired,
onSetImportSeriesValue: PropTypes.func.isRequired,
onSetImportArtistValue: PropTypes.func.isRequired,
onScroll: PropTypes.func.isRequired
};
export default ImportSeriesTable;
export default ImportArtistTable;

@ -0,0 +1,44 @@
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { queueLookupSeries, setImportArtistValue } from 'Store/Actions/importArtistActions';
import createAllSeriesSelector from 'Store/Selectors/createAllSeriesSelector';
import ImportArtistTable from './ImportArtistTable';
function createMapStateToProps() {
return createSelector(
(state) => state.addArtist,
(state) => state.importArtist,
(state) => state.app.dimensions,
createAllSeriesSelector(),
(addArtist, importArtist, dimensions, allSeries) => {
return {
defaultMonitor: addArtist.defaults.monitor,
defaultQualityProfileId: addArtist.defaults.qualityProfileId,
defaultLanguageProfileId: addArtist.defaults.languageProfileId,
defaultSeriesType: addArtist.defaults.seriesType,
defaultAlbumFolder: addArtist.defaults.albumFolder,
items: importArtist.items,
isSmallScreen: dimensions.isSmallScreen,
allSeries
};
}
);
}
function createMapDispatchToProps(dispatch, props) {
return {
onSeriesLookup(name, path) {
dispatch(queueLookupSeries({
name,
path,
term: name
}));
},
onSetImportArtistValue(values) {
dispatch(setImportArtistValue(values));
}
};
}
export default connect(createMapStateToProps, createMapDispatchToProps)(ImportArtistTable);

@ -1,12 +1,17 @@
.titleContainer {
.artistNameContainer {
display: flex;
align-items: center;
}
.title {
.artistName {
margin-right: 5px;
}
.overview {
margin-right: 5px;
color: $disabledColor;
}
.year {
margin-left: 5px;
color: $disabledColor;

@ -0,0 +1,45 @@
import PropTypes from 'prop-types';
import React from 'react';
import { kinds } from 'Helpers/Props';
import Label from 'Components/Label';
import styles from './ImportArtistName.css';
function ImportArtistName(props) {
const {
artistName,
overview,
// year,
// network,
isExistingArtist
} = props;
return (
<div className={styles.artistNameContainer}>
<div className={styles.artistName}>
{artistName}
</div>
<div className={styles.overview}>
{overview}
</div>
{
isExistingArtist &&
<Label
kind={kinds.WARNING}
>
Existing
</Label>
}
</div>
);
}
ImportArtistName.propTypes = {
artistName: PropTypes.string.isRequired,
overview: PropTypes.string.isRequired,
// year: PropTypes.number.isRequired,
// network: PropTypes.string,
isExistingArtist: PropTypes.bool.isRequired
};
export default ImportArtistName;

@ -0,0 +1,55 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Link from 'Components/Link/Link';
import ImportArtistName from './ImportArtistName';
import styles from './ImportArtistSearchResult.css';
class ImportArtistSearchResult extends Component {
//
// Listeners
onPress = () => {
this.props.onPress(this.props.foreignArtistId);
}
//
// Render
render() {
const {
artistName,
overview,
// year,
// network,
isExistingArtist
} = this.props;
return (
<Link
className={styles.artist}
onPress={this.onPress}
>
<ImportArtistName
artistName={artistName}
overview={overview}
// year={year}
// network={network}
isExistingArtist={isExistingArtist}
/>
</Link>
);
}
}
ImportArtistSearchResult.propTypes = {
foreignArtistId: PropTypes.string.isRequired,
artistName: PropTypes.string.isRequired,
overview: PropTypes.string.isRequired,
// year: PropTypes.number.isRequired,
// network: PropTypes.string,
isExistingArtist: PropTypes.bool.isRequired,
onPress: PropTypes.func.isRequired
};
export default ImportArtistSearchResult;

@ -0,0 +1,17 @@
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createExistingArtistSelector from 'Store/Selectors/createExistingArtistSelector';
import ImportArtistSearchResult from './ImportArtistSearchResult';
function createMapStateToProps() {
return createSelector(
createExistingArtistSelector(),
(isExistingArtist) => {
return {
isExistingArtist
};
}
);
}
export default connect(createMapStateToProps)(ImportArtistSearchResult);

@ -8,9 +8,9 @@ import SpinnerIcon from 'Components/SpinnerIcon';
import Link from 'Components/Link/Link';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import TextInput from 'Components/Form/TextInput';
import ImportSeriesSearchResultConnector from './ImportSeriesSearchResultConnector';
import ImportSeriesTitle from './ImportSeriesTitle';
import styles from './ImportSeriesSelectSeries.css';
import ImportArtistSearchResultConnector from './ImportArtistSearchResultConnector';
import ImportArtistName from './ImportArtistName';
import styles from './ImportArtistSelectArtist.css';
const tetherOptions = {
skipMoveElement: true,
@ -25,7 +25,7 @@ const tetherOptions = {
targetAttachment: 'bottom center'
};
class ImportSeriesSelectSeries extends Component {
class ImportArtistSelectArtist extends Component {
//
// Lifecycle
@ -33,7 +33,7 @@ class ImportSeriesSelectSeries extends Component {
constructor(props, context) {
super(props, context);
this._seriesLookupTimeout = null;
this._artistLookupTimeout = null;
this.state = {
term: props.id,
@ -88,12 +88,12 @@ class ImportSeriesSelectSeries extends Component {
}
onSearchInputChange = ({ value }) => {
if (this._seriesLookupTimeout) {
clearTimeout(this._seriesLookupTimeout);
if (this._artistLookupTimeout) {
clearTimeout(this._artistLookupTimeout);
}
this.setState({ term: value }, () => {
this._seriesLookupTimeout = setTimeout(() => {
this._artistLookupTimeout = setTimeout(() => {
this.props.onSearchInputChange(value);
}, 200);
});
@ -111,7 +111,7 @@ class ImportSeriesSelectSeries extends Component {
render() {
const {
selectedSeries,
isExistingSeries,
isExistingArtist,
isFetching,
isPopulated,
error,
@ -146,7 +146,7 @@ class ImportSeriesSelectSeries extends Component {
}
{
isPopulated && selectedSeries && isExistingSeries &&
isPopulated && selectedSeries && isExistingArtist &&
<Icon
className={styles.warningIcon}
name={icons.WARNING}
@ -156,11 +156,12 @@ class ImportSeriesSelectSeries extends Component {
{
isPopulated && selectedSeries &&
<ImportSeriesTitle
title={selectedSeries.title}
year={selectedSeries.year}
network={selectedSeries.network}
isExistingSeries={isExistingSeries}
<ImportArtistName
artistName={selectedSeries.artistName}
overview={selectedSeries.overview}
// year={selectedSeries.year}
// network={selectedSeries.network}
isExistingArtist={isExistingArtist}
/>
}
@ -225,12 +226,13 @@ class ImportSeriesSelectSeries extends Component {
{
items.map((item) => {
return (
<ImportSeriesSearchResultConnector
key={item.tvdbId}
tvdbId={item.tvdbId}
title={item.title}
year={item.year}
network={item.network}
<ImportArtistSearchResultConnector
key={item.foreignArtistId}
foreignArtistId={item.foreignArtistId}
artistName={item.artistName}
overview={item.overview}
// year={item.year}
// network={item.network}
onPress={this.onSeriesSelect}
/>
);
@ -245,10 +247,10 @@ class ImportSeriesSelectSeries extends Component {
}
}
ImportSeriesSelectSeries.propTypes = {
ImportArtistSelectArtist.propTypes = {
id: PropTypes.string.isRequired,
selectedSeries: PropTypes.object,
isExistingSeries: PropTypes.bool.isRequired,
isExistingArtist: PropTypes.bool.isRequired,
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
error: PropTypes.object,
@ -258,11 +260,11 @@ ImportSeriesSelectSeries.propTypes = {
onSeriesSelect: PropTypes.func.isRequired
};
ImportSeriesSelectSeries.defaultProps = {
ImportArtistSelectArtist.defaultProps = {
isFetching: true,
isPopulated: false,
items: [],
queued: true
};
export default ImportSeriesSelectSeries;
export default ImportArtistSelectArtist;

@ -3,13 +3,13 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { queueLookupSeries, setImportSeriesValue } from 'Store/Actions/importSeriesActions';
import createImportSeriesItemSelector from 'Store/Selectors/createImportSeriesItemSelector';
import ImportSeriesSelectSeries from './ImportSeriesSelectSeries';
import { queueLookupSeries, setImportArtistValue } from 'Store/Actions/importArtistActions';
import createImportArtistItemSelector from 'Store/Selectors/createImportArtistItemSelector';
import ImportArtistSelectArtist from './ImportArtistSelectArtist';
function createMapStateToProps() {
return createSelector(
createImportSeriesItemSelector(),
createImportArtistItemSelector(),
(item) => {
return item;
}
@ -18,10 +18,10 @@ function createMapStateToProps() {
const mapDispatchToProps = {
queueLookupSeries,
setImportSeriesValue
setImportArtistValue
};
class ImportSeriesSelectSeriesConnector extends Component {
class ImportArtistSelectArtistConnector extends Component {
//
// Listeners
@ -33,15 +33,15 @@ class ImportSeriesSelectSeriesConnector extends Component {
});
}
onSeriesSelect = (tvdbId) => {
onSeriesSelect = (foreignArtistId) => {
const {
id,
items
} = this.props;
this.props.setImportSeriesValue({
this.props.setImportArtistValue({
id,
selectedSeries: _.find(items, { tvdbId })
selectedSeries: _.find(items, { foreignArtistId })
});
}
@ -50,7 +50,7 @@ class ImportSeriesSelectSeriesConnector extends Component {
render() {
return (
<ImportSeriesSelectSeries
<ImportArtistSelectArtist
{...this.props}
onSearchInputChange={this.onSearchInputChange}
onSeriesSelect={this.onSeriesSelect}
@ -59,13 +59,13 @@ class ImportSeriesSelectSeriesConnector extends Component {
}
}
ImportSeriesSelectSeriesConnector.propTypes = {
ImportArtistSelectArtistConnector.propTypes = {
id: PropTypes.string.isRequired,
items: PropTypes.arrayOf(PropTypes.object),
selectedSeries: PropTypes.object,
isSelected: PropTypes.bool,
queueLookupSeries: PropTypes.func.isRequired,
setImportSeriesValue: PropTypes.func.isRequired
setImportArtistValue: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(ImportSeriesSelectSeriesConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(ImportArtistSelectArtistConnector);

@ -0,0 +1,30 @@
import React, { Component } from 'react';
import { Route } from 'react-router-dom';
import Switch from 'Components/Router/Switch';
import ImportArtistSelectFolderConnector from 'AddArtist/ImportArtist/SelectFolder/ImportArtistSelectFolderConnector';
import ImportArtistConnector from 'AddArtist/ImportArtist/Import/ImportArtistConnector';
class ImportArtist extends Component {
//
// Render
render() {
return (
<Switch>
<Route
exact={true}
path="/add/import"
component={ImportArtistSelectFolderConnector}
/>
<Route
path="/add/import/:rootFolderId"
component={ImportArtistConnector}
/>
</Switch>
);
}
}
export default ImportArtist;

@ -6,9 +6,9 @@ import IconButton from 'Components/Link/IconButton';
import Link from 'Components/Link/Link';
import TableRow from 'Components/Table/TableRow';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import styles from './ImportSeriesRootFolderRow.css';
import styles from './ImportArtistRootFolderRow.css';
function ImportSeriesRootFolderRow(props) {
function ImportArtistRootFolderRow(props) {
const {
id,
path,
@ -48,7 +48,7 @@ function ImportSeriesRootFolderRow(props) {
);
}
ImportSeriesRootFolderRow.propTypes = {
ImportArtistRootFolderRow.propTypes = {
id: PropTypes.number.isRequired,
path: PropTypes.string.isRequired,
freeSpace: PropTypes.number.isRequired,
@ -56,9 +56,9 @@ ImportSeriesRootFolderRow.propTypes = {
onDeletePress: PropTypes.func.isRequired
};
ImportSeriesRootFolderRow.defaultProps = {
ImportArtistRootFolderRow.defaultProps = {
freeSpace: 0,
unmappedFolders: []
};
export default ImportSeriesRootFolderRow;
export default ImportArtistRootFolderRow;

@ -3,7 +3,7 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { deleteRootFolder } from 'Store/Actions/rootFolderActions';
import ImportSeriesRootFolderRow from './ImportSeriesRootFolderRow';
import ImportArtistRootFolderRow from './ImportArtistRootFolderRow';
function createMapStateToProps() {
return createSelector(
@ -18,7 +18,7 @@ const mapDispatchToProps = {
deleteRootFolder
};
class ImportSeriesRootFolderRowConnector extends Component {
class ImportArtistRootFolderRowConnector extends Component {
//
// Listeners
@ -32,7 +32,7 @@ class ImportSeriesRootFolderRowConnector extends Component {
render() {
return (
<ImportSeriesRootFolderRow
<ImportArtistRootFolderRow
{...this.props}
onDeletePress={this.onDeletePress}
/>
@ -40,9 +40,9 @@ class ImportSeriesRootFolderRowConnector extends Component {
}
}
ImportSeriesRootFolderRowConnector.propTypes = {
ImportArtistRootFolderRowConnector.propTypes = {
id: PropTypes.number.isRequired,
deleteRootFolder: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(ImportSeriesRootFolderRowConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(ImportArtistRootFolderRowConnector);

@ -10,8 +10,8 @@ import PageContent from 'Components/Page/PageContent';
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import ImportSeriesRootFolderRowConnector from './ImportSeriesRootFolderRowConnector';
import styles from './ImportSeriesSelectFolder.css';
import ImportArtistRootFolderRowConnector from './ImportArtistRootFolderRowConnector';
import styles from './ImportArtistSelectFolder.css';
const rootFolderColumns = [
{
@ -35,7 +35,7 @@ const rootFolderColumns = [
}
];
class ImportSeriesSelectFolder extends Component {
class ImportArtistSelectFolder extends Component {
//
// Lifecycle
@ -75,7 +75,7 @@ class ImportSeriesSelectFolder extends Component {
} = this.props;
return (
<PageContent title="Import Series">
<PageContent title="Import Artist">
<PageContentBodyConnector>
{
isFetching && !isPopulated &&
@ -91,17 +91,14 @@ class ImportSeriesSelectFolder extends Component {
!error && isPopulated &&
<div>
<div className={styles.header}>
Import series you already have
Import artist(s) you already have
</div>
<div className={styles.tips}>
Some tips to ensure the import goes smoothly:
<ul>
<li className={styles.tip}>
Make sure your files include the quality in the name. eg. <span className={styles.code}>episode.s02e15.bluray.mkv</span>
</li>
<li className={styles.tip}>
Point Sonarr to the folder containing all of your tv shows not a specific one. eg. <span className={styles.code}>"\tv shows\"</span> and not <span className={styles.code}>"\tv shows\the simpsons\"</span>
Point Lidarr to the folder containing all of your music not a specific artist. eg. <span className={styles.code}>"\music\"</span> and not <span className={styles.code}>"\music\alien ant farm\"</span>
</li>
</ul>
</div>
@ -119,7 +116,7 @@ class ImportSeriesSelectFolder extends Component {
{
items.map((rootFolder) => {
return (
<ImportSeriesRootFolderRowConnector
<ImportArtistRootFolderRowConnector
key={rootFolder.id}
id={rootFolder.id}
path={rootFolder.path}
@ -176,7 +173,7 @@ class ImportSeriesSelectFolder extends Component {
}
}
ImportSeriesSelectFolder.propTypes = {
ImportArtistSelectFolder.propTypes = {
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
error: PropTypes.object,
@ -185,4 +182,4 @@ ImportSeriesSelectFolder.propTypes = {
onDeleteRootFolderPress: PropTypes.func.isRequired
};
export default ImportSeriesSelectFolder;
export default ImportArtistSelectFolder;

@ -6,7 +6,7 @@ import { createSelector } from 'reselect';
import { push } from 'react-router-redux';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import { fetchRootFolders, addRootFolder, deleteRootFolder } from 'Store/Actions/rootFolderActions';
import ImportSeriesSelectFolder from './ImportSeriesSelectFolder';
import ImportArtistSelectFolder from './ImportArtistSelectFolder';
function createMapStateToProps() {
return createSelector(
@ -24,7 +24,7 @@ const mapDispatchToProps = {
push
};
class ImportSeriesSelectFolderConnector extends Component {
class ImportArtistSelectFolderConnector extends Component {
//
// Lifecycle
@ -65,7 +65,7 @@ class ImportSeriesSelectFolderConnector extends Component {
render() {
return (
<ImportSeriesSelectFolder
<ImportArtistSelectFolder
{...this.props}
onNewRootFolderSelect={this.onNewRootFolderSelect}
onDeleteRootFolderPress={this.onDeleteRootFolderPress}
@ -74,7 +74,7 @@ class ImportSeriesSelectFolderConnector extends Component {
}
}
ImportSeriesSelectFolderConnector.propTypes = {
ImportArtistSelectFolderConnector.propTypes = {
isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
@ -84,4 +84,4 @@ ImportSeriesSelectFolderConnector.propTypes = {
push: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(ImportSeriesSelectFolderConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(ImportArtistSelectFolderConnector);

@ -1,44 +0,0 @@
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { queueLookupSeries, setImportSeriesValue } from 'Store/Actions/importSeriesActions';
import createAllSeriesSelector from 'Store/Selectors/createAllSeriesSelector';
import ImportSeriesTable from './ImportSeriesTable';
function createMapStateToProps() {
return createSelector(
(state) => state.addSeries,
(state) => state.importSeries,
(state) => state.app.dimensions,
createAllSeriesSelector(),
(addSeries, importSeries, dimensions, allSeries) => {
return {
defaultMonitor: addSeries.defaults.monitor,
defaultQualityProfileId: addSeries.defaults.qualityProfileId,
defaultLanguageProfileId: addSeries.defaults.languageProfileId,
defaultSeriesType: addSeries.defaults.seriesType,
defaultSeasonFolder: addSeries.defaults.seasonFolder,
items: importSeries.items,
isSmallScreen: dimensions.isSmallScreen,
allSeries
};
}
);
}
function createMapDispatchToProps(dispatch, props) {
return {
onSeriesLookup(name, path) {
dispatch(queueLookupSeries({
name,
path,
term: name
}));
},
onSetImportSeriesValue(values) {
dispatch(setImportSeriesValue(values));
}
};
}
export default connect(createMapStateToProps, createMapDispatchToProps)(ImportSeriesTable);

@ -1,52 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Link from 'Components/Link/Link';
import ImportSeriesTitle from './ImportSeriesTitle';
import styles from './ImportSeriesSearchResult.css';
class ImportSeriesSearchResult extends Component {
//
// Listeners
onPress = () => {
this.props.onPress(this.props.tvdbId);
}
//
// Render
render() {
const {
title,
year,
network,
isExistingSeries
} = this.props;
return (
<Link
className={styles.series}
onPress={this.onPress}
>
<ImportSeriesTitle
title={title}
year={year}
network={network}
isExistingSeries={isExistingSeries}
/>
</Link>
);
}
}
ImportSeriesSearchResult.propTypes = {
tvdbId: PropTypes.number.isRequired,
title: PropTypes.string.isRequired,
year: PropTypes.number.isRequired,
network: PropTypes.string,
isExistingSeries: PropTypes.bool.isRequired,
onPress: PropTypes.func.isRequired
};
export default ImportSeriesSearchResult;

@ -1,17 +0,0 @@
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createExistingSeriesSelector from 'Store/Selectors/createExistingSeriesSelector';
import ImportSeriesSearchResult from './ImportSeriesSearchResult';
function createMapStateToProps() {
return createSelector(
createExistingSeriesSelector(),
(isExistingSeries) => {
return {
isExistingSeries
};
}
);
}
export default connect(createMapStateToProps)(ImportSeriesSearchResult);

@ -1,50 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import { kinds } from 'Helpers/Props';
import Label from 'Components/Label';
import styles from './ImportSeriesTitle.css';
function ImportSeriesTitle(props) {
const {
title,
year,
network,
isExistingSeries
} = props;
return (
<div className={styles.titleContainer}>
<div className={styles.title}>
{title}
{
!title.contains(year) &&
<span className={styles.year}>({year})</span>
}
</div>
{
!!network &&
<Label>{network}</Label>
}
{
isExistingSeries &&
<Label
kind={kinds.WARNING}
>
Existing
</Label>
}
</div>
);
}
ImportSeriesTitle.propTypes = {
title: PropTypes.string.isRequired,
year: PropTypes.number.isRequired,
network: PropTypes.string,
isExistingSeries: PropTypes.bool.isRequired
};
export default ImportSeriesTitle;

@ -1,30 +0,0 @@
import React, { Component } from 'react';
import { Route } from 'react-router-dom';
import Switch from 'Components/Router/Switch';
import ImportSeriesSelectFolderConnector from 'AddArtist/ImportSeries/SelectFolder/ImportSeriesSelectFolderConnector';
import ImportSeriesConnector from 'AddArtist/ImportSeries/Import/ImportSeriesConnector';
class ImportSeries extends Component {
//
// Render
render() {
return (
<Switch>
<Route
exact={true}
path="/add/import"
component={ImportSeriesSelectFolderConnector}
/>
<Route
path="/add/import/:rootFolderId"
component={ImportSeriesConnector}
/>
</Switch>
);
}
}
export default ImportSeries;

@ -1,46 +0,0 @@
import React from 'react';
import DescriptionList from 'Components/DescriptionList/DescriptionList';
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
function SeriesMonitoringOptionsPopoverContent() {
return (
<DescriptionList>
<DescriptionListItem
title="All Episodes"
data="Monitor all episodes except specials"
/>
<DescriptionListItem
title="Future Episodes"
data="Monitor episodes that have not aired yet"
/>
<DescriptionListItem
title="Missing Episodes"
data="Monitor episodes that do not have files or have not aired yet"
/>
<DescriptionListItem
title="Existing Episodes"
data="Monitor episodes that have files or have not aired yet"
/>
<DescriptionListItem
title="First Season"
data="Monitor all episodes of the first season. All other seasons will be ignored"
/>
<DescriptionListItem
title="Latest Season"
data="Monitor all episodes of the latest season and future seasons"
/>
<DescriptionListItem
title="None"
data="No episodes will be monitored."
/>
</DescriptionList>
);
}
export default SeriesMonitoringOptionsPopoverContent;

@ -1,26 +0,0 @@
import React from 'react';
import DescriptionList from 'Components/DescriptionList/DescriptionList';
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
function SeriesTypePopoverContent() {
return (
<DescriptionList>
<DescriptionListItem
title="Anime"
data="Episodes released using an absolute episode number"
/>
<DescriptionListItem
title="Daily"
data="Episodes released daily or less frequently that use year-month-day (2017-05-25)"
/>
<DescriptionListItem
title="Standard"
data="Episodes released with SxxEyy pattern"
/>
</DescriptionList>
);
}
export default SeriesTypePopoverContent;

@ -9,8 +9,8 @@ import NotFound from 'Components/NotFound';
import Switch from 'Components/Router/Switch';
import PageConnector from 'Components/Page/PageConnector';
import ArtistIndexConnector from 'Artist/Index/ArtistIndexConnector';
import AddNewSeriesConnector from 'AddArtist/AddNewSeries/AddNewSeriesConnector';
import ImportSeries from 'AddArtist/ImportSeries/ImportSeries';
import AddNewArtistConnector from 'AddArtist/AddNewArtist/AddNewArtistConnector';
import ImportArtist from 'AddArtist/ImportArtist/ImportArtist';
import SeriesEditorConnector from 'Artist/Editor/SeriesEditorConnector';
import SeasonPassConnector from 'SeasonPass/SeasonPassConnector';
import SeriesDetailsPageConnector from 'Artist/Details/SeriesDetailsPageConnector';
@ -72,12 +72,12 @@ function App({ store, history }) {
<Route
path="/add/new"
component={AddNewSeriesConnector}
component={AddNewArtistConnector}
/>
<Route
path="/add/import"
component={ImportSeries}
component={ImportArtist}
/>
<Route

@ -26,12 +26,12 @@ function AppUpdatedModalContent(props) {
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
Sonarr Updated
Lidarr Updated
</ModalHeader>
<ModalBody>
<div>
Version <span className={styles.version}>{version}</span> of Sonarr has been installed, in order to get the latest changes you'll need to reload Sonarr.
Version <span className={styles.version}>{version}</span> of Lidarr has been installed, in order to get the latest changes you'll need to reload Lidarr.
</div>
{

@ -27,11 +27,11 @@ function ConnectionLostModal(props) {
<ModalBody>
<div>
Sonarr has lost it's connection to the backend and will need to be reloaded to restore functionality.
Lidarr has lost it's connection to the backend and will need to be reloaded to restore functionality.
</div>
<div className={styles.automatic}>
Sonarr will try to connect automatically, or you can click reload below.
Lidarr will try to connect automatically, or you can click reload below.
</div>
</ModalBody>
<ModalFooter>

@ -13,14 +13,14 @@ function Agenda(props) {
<div className={styles.agenda}>
{
items.map((item, index) => {
const momentDate = moment(item.airDateUtc);
const momentDate = moment(item.releaseDate);
const showDate = index === 0 ||
!moment(items[index - 1].airDateUtc).isSame(momentDate, 'day');
!moment(items[index - 1].releaseDate).isSame(momentDate, 'day');
return (
<AgendaEventConnector
key={item.id}
episodeId={item.id}
albumId={item.id}
showDate={showDate}
{...item}
/>

@ -26,15 +26,15 @@
margin-right: 10px;
}
.seriesTitle,
.episodeTitle {
.artistName,
.albumTitle {
composes: truncate from 'Styles/Mixins/truncate.css';
flex: 0 1 300px;
margin-right: 10px;
}
.episodeTitle {
.albumTitle {
flex: 1 1 1px;
}
@ -66,18 +66,10 @@
composes: unmonitored from 'Calendar/Events/CalendarEvent.css';
}
.onAir {
composes: onAir from 'Calendar/Events/CalendarEvent.css';
}
.missing {
composes: missing from 'Calendar/Events/CalendarEvent.css';
}
.premiere {
composes: premiere from 'Calendar/Events/CalendarEvent.css';
}
.unaired {
composes: unaired from 'Calendar/Events/CalendarEvent.css';
}
@ -98,7 +90,7 @@
.date,
.time,
.seriesTitle {
.artistName {
flex: 0 0 100%;
}

@ -42,12 +42,12 @@ class AgendaEvent extends Component {
render() {
const {
id,
series,
artist,
title,
seasonNumber,
episodeNumber,
absoluteEpisodeNumber,
airDateUtc,
// seasonNumber,
// episodeNumber,
// absoluteEpisodeNumber,
releaseDate,
monitored,
hasFile,
grabbed,
@ -57,11 +57,11 @@ class AgendaEvent extends Component {
longDateFormat
} = this.props;
const startTime = moment(airDateUtc);
const endTime = startTime.add(series.runtime, 'minutes');
const startTime = moment(releaseDate);
// const endTime = startTime.add(artist.runtime, 'minutes');
const downloading = !!(queueItem || grabbed);
const isMonitored = series.monitored && monitored;
const statusStyle = getStatusStyle(episodeNumber, hasFile, downloading, startTime, endTime, isMonitored);
const isMonitored = artist.monitored && monitored;
const statusStyle = getStatusStyle(id, hasFile, downloading, startTime, isMonitored);
return (
<div>
@ -85,34 +85,25 @@ class AgendaEvent extends Component {
/>
<div className={styles.time}>
{formatTime(airDateUtc, timeFormat)} - {formatTime(endTime.toISOString(), timeFormat, { includeMinuteZero: true })}
{formatTime(releaseDate, timeFormat)}
</div>
<div className={styles.seriesTitle}>
{series.title}
<div className={styles.artistName}>
{artist.artistName}
</div>
<div className={styles.seasonEpisodeNumber}>
{seasonNumber}x{padNumber(episodeNumber, 2)}
<div className={styles.episodeSeparator}> - </div>
{
series.seriesType === 'anime' && absoluteEpisodeNumber &&
<span className={styles.absoluteEpisodeNumber}>({absoluteEpisodeNumber})</span>
}
<div className={styles.episodeSeparator}> - </div>
</div>
<div className={styles.episodeTitle}>
<div className={styles.albumTitle}>
{title}
</div>
{
!!queueItem &&
<CalendarEventQueueDetails
seriesType={series.seriesType}
seasonNumber={seasonNumber}
absoluteEpisodeNumber={absoluteEpisodeNumber}
seriesType={artist.seriesType}
// seasonNumber={seasonNumber}
// absoluteEpisodeNumber={absoluteEpisodeNumber}
{...queueItem}
/>
}
@ -121,7 +112,7 @@ class AgendaEvent extends Component {
!queueItem && grabbed &&
<Icon
name={icons.DOWNLOADING}
title="Episode is downloading"
title="Album is downloading"
/>
}
</Link>
@ -130,7 +121,7 @@ class AgendaEvent extends Component {
isOpen={this.state.isDetailsModalOpen}
episodeId={id}
episodeEntity={episodeEntities.CALENDAR}
artistId={series.id}
artistId={artist.id}
episodeTitle={title}
showOpenSeriesButton={true}
onModalClose={this.onDetailsModalClose}
@ -142,12 +133,12 @@ class AgendaEvent extends Component {
AgendaEvent.propTypes = {
id: PropTypes.number.isRequired,
series: PropTypes.object.isRequired,
artist: PropTypes.object.isRequired,
title: PropTypes.string.isRequired,
seasonNumber: PropTypes.number.isRequired,
episodeNumber: PropTypes.number.isRequired,
absoluteEpisodeNumber: PropTypes.number,
airDateUtc: PropTypes.string.isRequired,
// seasonNumber: PropTypes.number.isRequired,
// episodeNumber: PropTypes.number.isRequired,
// absoluteEpisodeNumber: PropTypes.number,
releaseDate: PropTypes.string.isRequired,
monitored: PropTypes.bool.isRequired,
hasFile: PropTypes.bool.isRequired,
grabbed: PropTypes.bool,

@ -10,9 +10,9 @@ function createMapStateToProps() {
createArtistSelector(),
createQueueItemSelector(),
createUISettingsSelector(),
(series, queueItem, uiSettings) => {
(artist, queueItem, uiSettings) => {
return {
series,
artist,
queueItem,
timeFormat: uiSettings.timeFormat,
longDateFormat: uiSettings.longDateFormat

@ -12,10 +12,10 @@ function createCalendarEventsConnector() {
(state) => state.calendar,
(date, calendar) => {
const filtered = _.filter(calendar.items, (item) => {
return moment(date).isSame(moment(item.airDateUtc), 'day');
return moment(date).isSame(moment(item.releaseDate), 'day');
});
return _.sortBy(filtered, (item) => moment(item.airDateUtc).unix());
return _.sortBy(filtered, (item) => moment(item.releaseDate).unix());
}
);
}

@ -8,19 +8,19 @@
}
.info,
.episodeInfo {
.albumInfo {
display: flex;
}
.seriesTitle,
.episodeTitle {
.artistName,
.albumTitle {
composes: truncate from 'Styles/Mixins/truncate.css';
flex: 1 0 1px;
margin-right: 10px;
}
.seriesTitle {
.artistName {
color: #3a3f51;
font-size: 14px;
}
@ -53,14 +53,6 @@
}
}
.onAir {
border-left-color: $warningColor;
&:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, transparent, transparent 5px, #eee 5px, #eee 10px);
}
}
.missing {
border-left-color: $dangerColor;
@ -69,14 +61,6 @@
}
}
.premiere {
border-left-color: $sonarrBlue;
&:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, transparent, transparent 5px, #eee 5px, #eee 10px);
}
}
.unaired {
border-left-color: $primaryColor;

@ -47,26 +47,26 @@ class CalendarEvent extends Component {
render() {
const {
id,
series,
artist,
title,
seasonNumber,
episodeNumber,
absoluteEpisodeNumber,
airDateUtc,
// seasonNumber,
// episodeNumber,
// absoluteEpisodeNumber,
releaseDate,
monitored,
hasFile,
grabbed,
queueItem,
timeFormat,
// timeFormat,
colorImpairedMode
} = this.props;
const startTime = moment(airDateUtc);
const endTime = startTime.add(series.runtime, 'minutes');
const startTime = moment(releaseDate);
// const endTime = startTime.add(artist.runtime, 'minutes');
const downloading = !!(queueItem || grabbed);
const isMonitored = series.monitored && monitored;
const statusStyle = getStatusStyle(episodeNumber, hasFile, downloading, startTime, endTime, isMonitored);
const missingAbsoluteNumber = series.seriesType === 'anime' && seasonNumber > 0 && !absoluteEpisodeNumber;
const isMonitored = artist.monitored && monitored;
const statusStyle = getStatusStyle(id, hasFile, downloading, startTime, isMonitored);
// const missingAbsoluteNumber = artist.seriesType === 'anime' && seasonNumber > 0 && !absoluteEpisodeNumber;
return (
<div>
@ -80,18 +80,10 @@ class CalendarEvent extends Component {
onPress={this.onPress}
>
<div className={styles.info}>
<div className={styles.seriesTitle}>
{series.title}
<div className={styles.artistName}>
{artist.artistName}
</div>
{
missingAbsoluteNumber &&
<Icon
name={icons.WARNING}
title="Episode does not have an absolute episode number"
/>
}
{
!!queueItem &&
<span className={styles.statusIcon}>
@ -106,28 +98,15 @@ class CalendarEvent extends Component {
<Icon
className={styles.statusIcon}
name={icons.DOWNLOADING}
title="Episode is downloading"
title="Album is downloading"
/>
}
</div>
<div className={styles.episodeInfo}>
<div className={styles.episodeTitle}>
<div className={styles.albumInfo}>
<div className={styles.albumTitle}>
{title}
</div>
<div>
{seasonNumber}x{padNumber(episodeNumber, 2)}
{
series.seriesType === 'anime' && absoluteEpisodeNumber &&
<span className={styles.absoluteEpisodeNumber}>({absoluteEpisodeNumber})</span>
}
</div>
</div>
<div>
{formatTime(airDateUtc, timeFormat)} - {formatTime(endTime.toISOString(), timeFormat, { includeMinuteZero: true })}
</div>
</Link>
@ -135,7 +114,7 @@ class CalendarEvent extends Component {
isOpen={this.state.isDetailsModalOpen}
episodeId={id}
episodeEntity={episodeEntities.CALENDAR}
artistId={series.id}
artistId={artist.id}
episodeTitle={title}
showOpenSeriesButton={true}
onModalClose={this.onDetailsModalClose}
@ -147,17 +126,17 @@ class CalendarEvent extends Component {
CalendarEvent.propTypes = {
id: PropTypes.number.isRequired,
series: PropTypes.object.isRequired,
artist: PropTypes.object.isRequired,
title: PropTypes.string.isRequired,
seasonNumber: PropTypes.number.isRequired,
episodeNumber: PropTypes.number.isRequired,
absoluteEpisodeNumber: PropTypes.number,
airDateUtc: PropTypes.string.isRequired,
// seasonNumber: PropTypes.number.isRequired,
// episodeNumber: PropTypes.number.isRequired,
// absoluteEpisodeNumber: PropTypes.number,
releaseDate: PropTypes.string.isRequired,
monitored: PropTypes.bool.isRequired,
hasFile: PropTypes.bool.isRequired,
grabbed: PropTypes.bool,
queueItem: PropTypes.object,
timeFormat: PropTypes.string.isRequired,
// timeFormat: PropTypes.string.isRequired,
colorImpairedMode: PropTypes.bool.isRequired,
onEventModalOpenToggle: PropTypes.func.isRequired
};

@ -10,9 +10,9 @@ function createMapStateToProps() {
createArtistSelector(),
createQueueItemSelector(),
createUISettingsSelector(),
(series, queueItem, uiSettings) => {
(artist, queueItem, uiSettings) => {
return {
series,
artist,
queueItem,
timeFormat: uiSettings.timeFormat,
colorImpairedMode: uiSettings.enableColorImpairedMode

@ -6,46 +6,30 @@ import styles from './Legend.css';
function Legend({ colorImpairedMode }) {
return (
<div className={styles.legend}>
<div>
<LegendItem
name="Unaired Premiere"
status="premiere"
tooltip="Premiere episode hasn't aired yet"
colorImpairedMode={colorImpairedMode}
/>
<LegendItem
status="unaired"
tooltip="Episode hasn't aired yet"
colorImpairedMode={colorImpairedMode}
/>
</div>
<div>
<LegendItem
status="downloading"
tooltip="Episode is currently downloading"
tooltip="Album is currently downloading"
colorImpairedMode={colorImpairedMode}
/>
<LegendItem
status="downloaded"
tooltip="Episode was downloaded and sorted"
tooltip="Album was downloaded and sorted"
colorImpairedMode={colorImpairedMode}
/>
</div>
<div>
<LegendItem
name="On Air"
status="onAir"
tooltip="Episode is currently airing"
status="unaired"
tooltip="Album hasn't released yet"
colorImpairedMode={colorImpairedMode}
/>
<LegendItem
status="missing"
tooltip="Episode file has not been found"
tooltip="Track file has not been found"
colorImpairedMode={colorImpairedMode}
/>
</div>
@ -53,7 +37,7 @@ function Legend({ colorImpairedMode }) {
<div>
<LegendItem
status="unmonitored"
tooltip="Episode is unmonitored"
tooltip="Album is unmonitored"
colorImpairedMode={colorImpairedMode}
/>
</div>

@ -32,10 +32,6 @@
composes: missing from 'Calendar/Events/CalendarEvent.css';
}
.premiere {
composes: premiere from 'Calendar/Events/CalendarEvent.css';
}
.unaired {
composes: unaired from 'Calendar/Events/CalendarEvent.css';
}

@ -1,6 +1,6 @@
import moment from 'moment';
function getStatusStyle(episodeNumber, hasFile, downloading, startTime, endTime, isMonitored) {
function getStatusStyle(episodeNumber, hasFile, downloading, startTime, isMonitored) {
const currentTime = moment();
if (hasFile) {
@ -15,18 +15,10 @@ function getStatusStyle(episodeNumber, hasFile, downloading, startTime, endTime,
return 'unmonitored';
}
if (currentTime.isAfter(startTime) && currentTime.isBefore(endTime)) {
return 'onAir';
}
if (endTime.isBefore(currentTime) && !hasFile) {
if (currentTime.isAfter(startTime)) {
return 'missing';
}
if (episodeNumber === 1) {
return 'premiere';
}
return 'unaired';
}

@ -22,7 +22,7 @@ function getUrls(state) {
tags
} = state;
let icalUrl = `${window.location.host}${window.Sonarr.urlBase}/feed/calendar/Sonarr.ics?`;
let icalUrl = `${window.location.host}${window.Sonarr.urlBase}/feed/calendar/Lidarr.ics?`;
if (unmonitored) {
icalUrl += 'unmonitored=true&';
@ -115,7 +115,7 @@ class CalendarLinkModalContent extends Component {
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
Sonarr Calendar Feed
Lidarr Calendar Feed
</ModalHeader>
<ModalBody>
@ -127,7 +127,7 @@ class CalendarLinkModalContent extends Component {
type={inputTypes.CHECK}
name="unmonitored"
value={unmonitored}
helpText="Include unmonitored episodes in the iCal feed"
helpText="Include unmonitored albums in the iCal feed"
onChange={this.onInputChange}
/>
</FormGroup>
@ -139,7 +139,7 @@ class CalendarLinkModalContent extends Component {
type={inputTypes.CHECK}
name="premieresOnly"
value={premieresOnly}
helpText="Only the first episode in a season will be in the feed"
helpText="Only the first album from an artist will be in the feed"
onChange={this.onInputChange}
/>
</FormGroup>
@ -163,7 +163,7 @@ class CalendarLinkModalContent extends Component {
type={inputTypes.TAG}
name="tags"
value={tags}
helpText="Feed will only contain series with at least one matching tag"
helpText="Feed will only contain artists with at least one matching tag"
onChange={this.onInputChange}
/>
</FormGroup>

@ -5,7 +5,7 @@ import Icon from 'Components/Icon';
import Link from 'Components/Link/Link';
import CaptchaInputConnector from './CaptchaInputConnector';
import CheckInput from './CheckInput';
import MonitorEpisodesSelectInput from './MonitorEpisodesSelectInput';
import MonitorAlbumsSelectInput from './MonitorAlbumsSelectInput';
import NumberInput from './NumberInput';
import OAuthInputConnector from './OAuthInputConnector';
import PasswordInput from './PasswordInput';
@ -29,8 +29,8 @@ function getComponent(type) {
case inputTypes.CHECK:
return CheckInput;
case inputTypes.MONITOR_EPISODES_SELECT:
return MonitorEpisodesSelectInput;
case inputTypes.MONITOR_ALBUMS_SELECT:
return MonitorAlbumsSelectInput;
case inputTypes.NUMBER:
return NumberInput;

@ -3,16 +3,16 @@ import React from 'react';
import SelectInput from './SelectInput';
const monitorOptions = [
{ key: 'all', value: 'All Episodes' },
{ key: 'future', value: 'Future Episodes' },
{ key: 'missing', value: 'Missing Episodes' },
{ key: 'existing', value: 'Existing Episodes' },
{ key: 'first', value: 'Only First Season' },
{ key: 'latest', value: 'Only Latest Season' },
{ key: 'all', value: 'All Albums' },
{ key: 'future', value: 'Future Albums' },
{ key: 'missing', value: 'Missing Albums' },
{ key: 'existing', value: 'Existing Albums' },
{ key: 'first', value: 'Only First Album' },
{ key: 'latest', value: 'Only Latest Album' },
{ key: 'none', value: 'None' }
];
function MonitorEpisodesSelectInput(props) {
function MonitorAlbumsSelectInput(props) {
const {
includeNoChange,
includeMixed,
@ -45,15 +45,15 @@ function MonitorEpisodesSelectInput(props) {
);
}
MonitorEpisodesSelectInput.propTypes = {
MonitorAlbumsSelectInput.propTypes = {
includeNoChange: PropTypes.bool.isRequired,
includeMixed: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired
};
MonitorEpisodesSelectInput.defaultProps = {
MonitorAlbumsSelectInput.defaultProps = {
includeNoChange: false,
includeMixed: false
};
export default MonitorEpisodesSelectInput;
export default MonitorAlbumsSelectInput;

@ -4,7 +4,7 @@ import styles from './LoadingMessage.css';
const messages = [
'Downloading more RAM',
'Now in Technicolor',
'Previously on Sonarr...',
'Previously on Lidarr...',
'Bleep Bloop.',
'Locating the required gigapixels to render...',
'Spinning up the hamster wheel...',

@ -13,7 +13,7 @@ function ErrorPage(props) {
uiSettingsError
} = props;
let errorMessage = 'Failed to load Sonarr';
let errorMessage = 'Failed to load Lidarr';
if (!isLocalStorageSupported) {
errorMessage = 'Local Storage is not supported or disabled. A plugin or private browsing may have disabled it.';

@ -111,7 +111,7 @@ class SeriesSearchInput extends Component {
} = this._autosuggest.state;
if (!suggestions.length || highlightedSectionIndex) {
this.props.onGoToAddNewSeries(value);
this.props.onGoToAddNewArtist(value);
this._autosuggest.input.blur();
return;
@ -153,7 +153,7 @@ class SeriesSearchInput extends Component {
onSuggestionSelected = (event, { suggestion, sectionIndex }) => {
if (suggestion.type === ADD_NEW_TYPE) {
this.props.onGoToAddNewSeries(this.state.value);
this.props.onGoToAddNewArtist(this.state.value);
} else {
this.goToSeries(suggestion);
}
@ -243,7 +243,7 @@ class SeriesSearchInput extends Component {
SeriesSearchInput.propTypes = {
series: PropTypes.arrayOf(PropTypes.object).isRequired,
onGoToSeries: PropTypes.func.isRequired,
onGoToAddNewSeries: PropTypes.func.isRequired,
onGoToAddNewArtist: PropTypes.func.isRequired,
bindShortcut: PropTypes.func.isRequired
};

@ -22,7 +22,7 @@ function createMapDispatchToProps(dispatch, props) {
dispatch(push(`${window.Sonarr.urlBase}/series/${titleSlug}`));
},
onGoToAddNewSeries(query) {
onGoToAddNewArtist(query) {
dispatch(push(`${window.Sonarr.urlBase}/add/new?term=${encodeURIComponent(query)}`));
}
};

@ -1,6 +1,6 @@
export const CAPTCHA = 'captcha';
export const CHECK = 'check';
export const MONITOR_EPISODES_SELECT = 'monitorEpisodesSelect';
export const MONITOR_ALBUMS_SELECT = 'monitorAlbumsSelect';
export const NUMBER = 'number';
export const OAUTH = 'oauth';
export const PASSWORD = 'password';
@ -17,7 +17,7 @@ export const TEXT_TAG = 'textTag';
export const all = [
CAPTCHA,
CHECK,
MONITOR_EPISODES_SELECT,
MONITOR_ALBUMS_SELECT,
NUMBER,
OAUTH,
PASSWORD,

@ -15,7 +15,7 @@ import ModalBody from 'Components/Modal/ModalBody';
import ModalFooter from 'Components/Modal/ModalFooter';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import SelectSeriesModal from 'InteractiveImport/Series/SelectSeriesModal';
import SelectArtistModal from 'InteractiveImport/Series/SelectArtistModal';
import SelectSeasonModal from 'InteractiveImport/Season/SelectSeasonModal';
import InteractiveImportRow from './InteractiveImportRow';
import styles from './InteractiveImportModalContent.css';
@ -78,7 +78,7 @@ class InteractiveImportModalContent extends Component {
lastToggled: null,
selectedState: {},
invalidRowsSelected: [],
isSelectSeriesModalOpen: false,
isSelectArtistModalOpen: false,
isSelectSeasonModalOpen: false
};
}
@ -127,16 +127,16 @@ class InteractiveImportModalContent extends Component {
this.props.onImportModeChange(value);
}
onSelectSeriesPress = () => {
this.setState({ isSelectSeriesModalOpen: true });
onSelectArtistPress = () => {
this.setState({ isSelectArtistModalOpen: true });
}
onSelectSeasonPress = () => {
this.setState({ isSelectSeasonModalOpen: true });
}
onSelectSeriesModalClose = () => {
this.setState({ isSelectSeriesModalOpen: false });
onSelectArtistModalClose = () => {
this.setState({ isSelectArtistModalOpen: false });
}
onSelectSeasonModalClose = () => {
@ -168,7 +168,7 @@ class InteractiveImportModalContent extends Component {
allUnselected,
selectedState,
invalidRowsSelected,
isSelectSeriesModalOpen,
isSelectArtistModalOpen,
isSelectSeasonModalOpen
} = this.state;
@ -249,7 +249,7 @@ class InteractiveImportModalContent extends Component {
}
<div className={downloadId ? styles.leftButtons : styles.centerButtons}>
<Button onPress={this.onSelectSeriesPress}>
<Button onPress={this.onSelectArtistPress}>
Select Series
</Button>
@ -278,10 +278,10 @@ class InteractiveImportModalContent extends Component {
</div>
</ModalFooter>
<SelectSeriesModal
isOpen={isSelectSeriesModalOpen}
<SelectArtistModal
isOpen={isSelectArtistModalOpen}
ids={selectedIds}
onModalClose={this.onSelectSeriesModalClose}
onModalClose={this.onSelectArtistModalClose}
/>
<SelectSeasonModal

@ -9,7 +9,7 @@ import TableRowCellButton from 'Components/Table/Cells/TableRowCellButton';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import Popover from 'Components/Tooltip/Popover';
import EpisodeQuality from 'Episode/EpisodeQuality';
import SelectSeriesModal from 'InteractiveImport/Series/SelectSeriesModal';
import SelectArtistModal from 'InteractiveImport/Series/SelectArtistModal';
import SelectSeasonModal from 'InteractiveImport/Season/SelectSeasonModal';
import SelectEpisodeModal from 'InteractiveImport/Episode/SelectEpisodeModal';
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
@ -25,7 +25,7 @@ class InteractiveImportRow extends Component {
super(props, context);
this.state = {
isSelectSeriesModalOpen: false,
isSelectArtistModalOpen: false,
isSelectSeasonModalOpen: false,
isSelectEpisodeModalOpen: false,
isSelectQualityModalOpen: false
@ -87,8 +87,8 @@ class InteractiveImportRow extends Component {
//
// Listeners
onSelectSeriesPress = () => {
this.setState({ isSelectSeriesModalOpen: true });
onSelectArtistPress = () => {
this.setState({ isSelectArtistModalOpen: true });
}
onSelectSeasonPress = () => {
@ -103,8 +103,8 @@ class InteractiveImportRow extends Component {
this.setState({ isSelectQualityModalOpen: true });
}
onSelectSeriesModalClose = (changed) => {
this.setState({ isSelectSeriesModalOpen: false });
onSelectArtistModalClose = (changed) => {
this.setState({ isSelectArtistModalOpen: false });
this.selectRowAfterChange(changed);
}
@ -141,7 +141,7 @@ class InteractiveImportRow extends Component {
} = this.props;
const {
isSelectSeriesModalOpen,
isSelectArtistModalOpen,
isSelectSeasonModalOpen,
isSelectEpisodeModalOpen,
isSelectQualityModalOpen
@ -171,7 +171,7 @@ class InteractiveImportRow extends Component {
</TableRowCell>
<TableRowCellButton
onPress={this.onSelectSeriesPress}
onPress={this.onSelectArtistPress}
>
{
showSeriesPlaceholder ? <InteractiveImportRowCellPlaceholder /> : seriesTitle
@ -238,10 +238,10 @@ class InteractiveImportRow extends Component {
}
</TableRowCell>
<SelectSeriesModal
isOpen={isSelectSeriesModalOpen}
<SelectArtistModal
isOpen={isSelectArtistModalOpen}
ids={[id]}
onModalClose={this.onSelectSeriesModalClose}
onModalClose={this.onSelectArtistModalClose}
/>
<SelectSeasonModal

@ -1,9 +1,9 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Modal from 'Components/Modal/Modal';
import SelectSeriesModalContentConnector from './SelectSeriesModalContentConnector';
import SelectArtistModalContentConnector from './SelectArtistModalContentConnector';
class SelectSeriesModal extends Component {
class SelectArtistModal extends Component {
//
// Render
@ -20,7 +20,7 @@ class SelectSeriesModal extends Component {
isOpen={isOpen}
onModalClose={onModalClose}
>
<SelectSeriesModalContentConnector
<SelectArtistModalContentConnector
{...otherProps}
onModalClose={onModalClose}
/>
@ -29,9 +29,9 @@ class SelectSeriesModal extends Component {
}
}
SelectSeriesModal.propTypes = {
SelectArtistModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default SelectSeriesModal;
export default SelectArtistModal;

@ -8,10 +8,10 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalHeader from 'Components/Modal/ModalHeader';
import ModalBody from 'Components/Modal/ModalBody';
import ModalFooter from 'Components/Modal/ModalFooter';
import SelectSeriesRow from './SelectSeriesRow';
import styles from './SelectSeriesModalContent.css';
import SelectArtistRow from './SelectArtistRow';
import styles from './SelectArtistModalContent.css';
class SelectSeriesModalContent extends Component {
class SelectArtistModalContent extends Component {
//
// Lifecycle
@ -67,7 +67,7 @@ class SelectSeriesModalContent extends Component {
items.map((item) => {
return item.title.toLowerCase().includes(filter) ?
(
<SelectSeriesRow
<SelectArtistRow
key={item.id}
id={item.id}
title={item.title}
@ -90,10 +90,10 @@ class SelectSeriesModalContent extends Component {
}
}
SelectSeriesModalContent.propTypes = {
SelectArtistModalContent.propTypes = {
items: PropTypes.arrayOf(PropTypes.object).isRequired,
onSeriesSelect: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default SelectSeriesModalContent;
export default SelectArtistModalContent;

@ -5,7 +5,7 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { updateInteractiveImportItem } from 'Store/Actions/interactiveImportActions';
import createAllSeriesSelector from 'Store/Selectors/createAllSeriesSelector';
import SelectSeriesModalContent from './SelectSeriesModalContent';
import SelectArtistModalContent from './SelectArtistModalContent';
function createMapStateToProps() {
return createSelector(
@ -22,7 +22,7 @@ const mapDispatchToProps = {
updateInteractiveImportItem
};
class SelectSeriesModalContentConnector extends Component {
class SelectArtistModalContentConnector extends Component {
//
// Listeners
@ -47,7 +47,7 @@ class SelectSeriesModalContentConnector extends Component {
render() {
return (
<SelectSeriesModalContent
<SelectArtistModalContent
{...this.props}
onSeriesSelect={this.onSeriesSelect}
/>
@ -55,11 +55,11 @@ class SelectSeriesModalContentConnector extends Component {
}
}
SelectSeriesModalContentConnector.propTypes = {
SelectArtistModalContentConnector.propTypes = {
ids: PropTypes.arrayOf(PropTypes.number).isRequired,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
updateInteractiveImportItem: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(SelectSeriesModalContentConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(SelectArtistModalContentConnector);

@ -1,9 +1,9 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Link from 'Components/Link/Link';
import styles from './SelectSeriesRow.css';
import styles from './SelectArtistRow.css';
class SelectSeriesRow extends Component {
class SelectArtistRow extends Component {
//
// Listeners
@ -28,10 +28,10 @@ class SelectSeriesRow extends Component {
}
}
SelectSeriesRow.propTypes = {
SelectArtistRow.propTypes = {
id: PropTypes.number.isRequired,
title: PropTypes.string.isRequired,
onSeriesSelect: PropTypes.func.isRequired
};
export default SelectSeriesRow;
export default SelectArtistRow;

@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { kinds } from 'Helpers/Props';
import SpinnerButton from 'Components/Link/SpinnerButton';
import MonitorEpisodesSelectInput from 'Components/Form/MonitorEpisodesSelectInput';
import MonitorAlbumsSelectInput from 'Components/Form/MonitorAlbumsSelectInput';
import SelectInput from 'Components/Form/SelectInput';
import PageContentFooter from 'Components/Page/PageContentFooter';
import styles from './SeasonPassFooter.css';
@ -106,7 +106,7 @@ class SeasonPassFooter extends Component {
Monitor Episodes
</div>
<MonitorEpisodesSelectInput
<MonitorAlbumsSelectInput
name="monitor"
value={monitor}
includeNoChange={true}

@ -50,7 +50,7 @@ class AddDownloadClientModalContent extends Component {
<div>
<Alert kind={kinds.INFO}>
<div>Sonarr supports any downloadClient that uses the Newznab standard, as well as other downloadClients listed below.</div>
<div>Lidarr supports any downloadClient that uses the Newznab standard, as well as other downloadClients listed below.</div>
<div>For more information on the individual downloadClients, clink on the info buttons.</div>
</Alert>

@ -50,7 +50,7 @@ class AddIndexerModalContent extends Component {
<div>
<Alert kind={kinds.INFO}>
<div>Sonarr supports any indexer that uses the Newznab standard, as well as other indexers listed below.</div>
<div>Lidarr supports any indexer that uses the Newznab standard, as well as other indexers listed below.</div>
<div>For more information on the individual indexers, clink on the info buttons.</div>
</Alert>

@ -103,7 +103,7 @@ class MediaManagement extends Component {
<FormInputGroup
type={inputTypes.CHECK}
name="skipFreeSpaceCheckWhenImporting"
helpText="Use when Sonarr is unable to detect free space from your series root folder"
helpText="Use when Lidarr is unable to detect free space from your series root folder"
onChange={onInputChange}
{...settings.skipFreeSpaceCheckWhenImporting}
/>
@ -121,7 +121,7 @@ class MediaManagement extends Component {
type={inputTypes.CHECK}
name="copyUsingHardlinks"
helpText="Use Hardlinks when trying to copy files from torrents that are still being seeded"
helpTextWarning="Occasionally, file locks may prevent renaming files that are being seeded. You may temporarily disable seeding and use Sonarr's rename function as a work around."
helpTextWarning="Occasionally, file locks may prevent renaming files that are being seeded. You may temporarily disable seeding and use Lidarr's rename function as a work around."
onChange={onInputChange}
{...settings.copyUsingHardlinks}
/>
@ -168,7 +168,7 @@ class MediaManagement extends Component {
<FormInputGroup
type={inputTypes.CHECK}
name="autoUnmonitorPreviouslyDownloadedEpisodes"
helpText="Episodes deleted from disk are automatically unmonitored in Sonarr"
helpText="Episodes deleted from disk are automatically unmonitored in Lidarr"
onChange={onInputChange}
{...settings.autoUnmonitorPreviouslyDownloadedEpisodes}
/>
@ -184,7 +184,7 @@ class MediaManagement extends Component {
<FormInputGroup
type={inputTypes.CHECK}
name="autoDownloadPropers"
helpText="Should Sonarr automatically upgrade to propers when available?"
helpText="Should Lidarr automatically upgrade to propers when available?"
onChange={onInputChange}
{...settings.autoDownloadPropers}
/>
@ -200,7 +200,7 @@ class MediaManagement extends Component {
<FormInputGroup
type={inputTypes.CHECK}
name="enableMediaInfo"
helpText="Extract video information such as resolution, runtime and codec information from files. This requires Sonarr to read parts of the file which may cause high disk or network activity during scans."
helpText="Extract video information such as resolution, runtime and codec information from files. This requires Lidarr to read parts of the file which may cause high disk or network activity during scans."
onChange={onInputChange}
{...settings.enableMediaInfo}
/>
@ -269,7 +269,7 @@ class MediaManagement extends Component {
<FormInputGroup
type={inputTypes.TEXT}
name="fileChmod"
helpText="Octal, applied to media files when imported/renamed by Sonarr"
helpText="Octal, applied to media files when imported/renamed by Lidarr"
onChange={onInputChange}
{...settings.fileChmod}
/>
@ -284,7 +284,7 @@ class MediaManagement extends Component {
<FormInputGroup
type={inputTypes.TEXT}
name="folderChmod"
helpText="Octal, applied to series/season folders created by Sonarr"
helpText="Octal, applied to series/season folders created by Lidarr"
values={fileDateOptions}
onChange={onInputChange}
{...settings.folderChmod}

@ -177,7 +177,7 @@ class Naming extends Component {
return (
<FieldSet
legend="Episode Naming"
legend="Track Naming"
>
{
isFetching &&
@ -193,14 +193,14 @@ class Naming extends Component {
hasSettings && !isFetching && !error &&
<Form>
<FormGroup size={sizes.MEDIUM}>
<FormLabel>Rename Episodes</FormLabel>
<FormLabel>Rename Tracks</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="renameEpisodes"
helpText="Sonarr will use the existing file name if renaming is disabled"
name="renameTracks"
helpText="Lidarr will use the existing file name if renaming is disabled"
onChange={onInputChange}
{...settings.renameEpisodes}
{...settings.renameTracks}
/>
</FormGroup>

@ -81,7 +81,7 @@ function EditLanguageProfileModalContent(props) {
{...cutoff}
value={cutoff ? cutoff.value.id : 0}
values={languages}
helpText="Once this language is reached Sonarr will no longer download episodes"
helpText="Once this language is reached Lidarr will no longer download episodes"
onChange={onCutoffChange}
/>
</FormGroup>

@ -81,7 +81,7 @@ function EditQualityProfileModalContent(props) {
{...cutoff}
value={cutoff ? cutoff.value.id : 0}
values={qualities}
helpText="Once this quality is reached Sonarr will no longer download episodes"
helpText="Once this quality is reached Lidarr will no longer download episodes"
onChange={onCutoffChange}
/>
</FormGroup>

@ -24,25 +24,25 @@ export const SET_APP_VALUE = 'SET_APP_VALUE';
export const SET_IS_SIDEBAR_VISIBLE = 'SET_IS_SIDEBAR_VISIBLE';
//
// Add Series
// Add Artist
export const LOOKUP_SERIES = 'LOOKUP_SERIES';
export const ADD_SERIES = 'ADD_SERIES';
export const SET_ADD_SERIES_VALUE = 'SET_ADD_SERIES_VALUE';
export const CLEAR_ADD_SERIES = 'CLEAR_ADD_SERIES';
export const SET_ADD_SERIES_DEFAULT = 'SET_ADD_SERIES_DEFAULT';
export const LOOKUP_ARTIST = 'LOOKUP_ARTIST';
export const ADD_ARTIST = 'ADD_ARTIST';
export const SET_ADD_ARTIST_VALUE = 'SET_ADD_ARTIST_VALUE';
export const CLEAR_ADD_ARTIST = 'CLEAR_ADD_ARTIST';
export const SET_ADD_ARTIST_DEFAULT = 'SET_ADD_ARTIST_DEFAULT';
//
// Import Series
// Import Artist
export const QUEUE_LOOKUP_SERIES = 'QUEUE_LOOKUP_SERIES';
export const START_LOOKUP_SERIES = 'START_LOOKUP_SERIES';
export const CLEAR_IMPORT_SERIES = 'CLEAR_IMPORT_SERIES';
export const SET_IMPORT_SERIES_VALUE = 'SET_IMPORT_SERIES_VALUE';
export const IMPORT_SERIES = 'IMPORT_SERIES';
export const QUEUE_LOOKUP_ARTIST = 'QUEUE_LOOKUP_ARTIST';
export const START_LOOKUP_ARTIST = 'START_LOOKUP_ARTIST';
export const CLEAR_IMPORT_ARTIST = 'CLEAR_IMPORT_ARTIST';
export const SET_IMPORT_ARTIST_VALUE = 'SET_IMPORT_ARTIST_VALUE';
export const IMPORT_ARTIST = 'IMPORT_ARTIST';
//
// Series
// Artist
export const FETCH_ARTIST = 'FETCH_ARTIST';
export const SET_ARTIST_VALUE = 'SET_ARTIST_VALUE';

@ -7,10 +7,10 @@ import { set, update, updateItem } from './baseActions';
let currentXHR = null;
let xhrCancelled = false;
const section = 'addSeries';
const section = 'addArtist';
const addSeriesActionHandlers = {
[types.LOOKUP_SERIES]: function(payload) {
const addArtistActionHandlers = {
[types.LOOKUP_ARTIST]: function(payload) {
return function(dispatch, getState) {
dispatch(set({ section, isFetching: true }));
@ -55,12 +55,12 @@ const addSeriesActionHandlers = {
};
},
[types.ADD_SERIES]: function(payload) {
[types.ADD_ARTIST]: function(payload) {
return function(dispatch, getState) {
dispatch(set({ section, isAdding: true }));
const foreignArtistId = payload.foreignArtistId;
const items = getState().addSeries.items;
const items = getState().addArtist.items;
const newSeries = getNewSeries(_.cloneDeep(_.find(items, { foreignArtistId })), payload);
const promise = $.ajax({
@ -95,4 +95,4 @@ const addSeriesActionHandlers = {
}
};
export default addSeriesActionHandlers;
export default addArtistActionHandlers;

@ -0,0 +1,15 @@
import { createAction } from 'redux-actions';
import * as types from './actionTypes';
import addArtistActionHandlers from './addArtistActionHandlers';
export const lookupArtist = addArtistActionHandlers[types.LOOKUP_ARTIST];
export const addArtist = addArtistActionHandlers[types.ADD_ARTIST];
export const clearAddArtist = createAction(types.CLEAR_ADD_ARTIST);
export const setAddArtistDefault = createAction(types.SET_ADD_ARTIST_DEFAULT);
export const setAddArtistValue = createAction(types.SET_ADD_ARTIST_VALUE, (payload) => {
return {
section: 'addArtist',
...payload
};
});

@ -1,15 +0,0 @@
import { createAction } from 'redux-actions';
import * as types from './actionTypes';
import addSeriesActionHandlers from './addSeriesActionHandlers';
export const lookupSeries = addSeriesActionHandlers[types.LOOKUP_SERIES];
export const addSeries = addSeriesActionHandlers[types.ADD_SERIES];
export const clearAddSeries = createAction(types.CLEAR_ADD_SERIES);
export const setAddSeriesDefault = createAction(types.SET_ADD_SERIES_DEFAULT);
export const setAddSeriesValue = createAction(types.SET_ADD_SERIES_VALUE, (payload) => {
return {
section: 'addSeries',
...payload
};
});

@ -4,14 +4,14 @@ import { batchActions } from 'redux-batched-actions';
import getNewSeries from 'Utilities/Series/getNewSeries';
import * as types from './actionTypes';
import { set, updateItem, removeItem } from './baseActions';
import { startLookupSeries } from './importSeriesActions';
import { startLookupSeries } from './importArtistActions';
import { fetchRootFolders } from './rootFolderActions';
const section = 'importSeries';
const section = 'importArtist';
let concurrentLookups = 0;
const importSeriesActionHandlers = {
[types.QUEUE_LOOKUP_SERIES]: function(payload) {
const importArtistActionHandlers = {
[types.QUEUE_LOOKUP_ARTIST]: function(payload) {
return function(dispatch, getState) {
const {
name,
@ -19,7 +19,7 @@ const importSeriesActionHandlers = {
term
} = payload;
const state = getState().importSeries;
const state = getState().importArtist;
const item = _.find(state.items, { id: name }) || {
id: name,
term,
@ -43,13 +43,13 @@ const importSeriesActionHandlers = {
};
},
[types.START_LOOKUP_SERIES]: function(payload) {
[types.START_LOOKUP_ARTIST]: function(payload) {
return function(dispatch, getState) {
if (concurrentLookups >= 1) {
return;
}
const state = getState().importSeries;
const state = getState().importArtist;
const queued = _.find(state.items, { queued: true });
if (!queued) {
@ -65,7 +65,7 @@ const importSeriesActionHandlers = {
}));
const promise = $.ajax({
url: '/series/lookup',
url: '/artist/lookup',
data: {
term: queued.term
}
@ -102,12 +102,12 @@ const importSeriesActionHandlers = {
};
},
[types.IMPORT_SERIES]: function(payload) {
[types.IMPORT_ARTIST]: function(payload) {
return function(dispatch, getState) {
dispatch(set({ section, isImporting: true }));
const ids = payload.ids;
const items = getState().importSeries.items;
const items = getState().importArtist.items;
const addedIds = [];
const allNewSeries = ids.reduce((acc, id) => {
@ -128,7 +128,7 @@ const importSeriesActionHandlers = {
}, []);
const promise = $.ajax({
url: '/series/import',
url: '/artist/import',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify(allNewSeries)
@ -169,4 +169,4 @@ const importSeriesActionHandlers = {
}
};
export default importSeriesActionHandlers;
export default importArtistActionHandlers;

@ -0,0 +1,16 @@
import { createAction } from 'redux-actions';
import * as types from './actionTypes';
import importArtistActionHandlers from './importArtistActionHandlers';
export const queueLookupSeries = importArtistActionHandlers[types.QUEUE_LOOKUP_ARTIST];
export const startLookupSeries = importArtistActionHandlers[types.START_LOOKUP_ARTIST];
export const importArtist = importArtistActionHandlers[types.IMPORT_ARTIST];
export const clearImportArtist = createAction(types.CLEAR_IMPORT_ARTIST);
export const setImportArtistValue = createAction(types.SET_IMPORT_ARTIST_VALUE, (payload) => {
return {
section: 'importArtist',
...payload
};
});

@ -1,16 +0,0 @@
import { createAction } from 'redux-actions';
import * as types from './actionTypes';
import importSeriesActionHandlers from './importSeriesActionHandlers';
export const queueLookupSeries = importSeriesActionHandlers[types.QUEUE_LOOKUP_SERIES];
export const startLookupSeries = importSeriesActionHandlers[types.START_LOOKUP_SERIES];
export const importSeries = importSeriesActionHandlers[types.IMPORT_SERIES];
export const clearImportSeries = createAction(types.CLEAR_IMPORT_SERIES);
export const setImportSeriesValue = createAction(types.SET_IMPORT_SERIES_VALUE, (payload) => {
return {
section: 'importSeries',
...payload
};
});

@ -1,6 +1,6 @@
import _ from 'lodash';
import persistState from 'redux-localstorage';
import * as addSeriesReducers from 'Store/Reducers/addSeriesReducers';
import * as addArtistReducers from 'Store/Reducers/addArtistReducers';
import * as episodeReducers from 'Store/Reducers/episodeReducers';
import * as artistIndexReducers from 'Store/Reducers/artistIndexReducers';
import * as seriesEditorReducers from 'Store/Reducers/seriesEditorReducers';
@ -15,7 +15,7 @@ import * as interactiveImportReducers from 'Store/Reducers/interactiveImportRedu
import * as queueReducers from 'Store/Reducers/queueReducers';
const reducers = [
addSeriesReducers,
addArtistReducers,
episodeReducers,
artistIndexReducers,
seriesEditorReducers,

@ -29,21 +29,21 @@ export const defaultState = {
};
export const persistState = [
'addSeries.defaults'
'addArtist.defaults'
];
const reducerSection = 'addSeries';
const reducerSection = 'addArtist';
const addSeriesReducers = handleActions({
const addArtistReducers = handleActions({
[types.SET]: createSetReducer(reducerSection),
[types.UPDATE]: createUpdateReducer(reducerSection),
[types.UPDATE_ITEM]: createUpdateItemReducer(reducerSection),
[types.REMOVE_ITEM]: createRemoveItemReducer(reducerSection),
[types.SET_ADD_SERIES_VALUE]: createSetSettingValueReducer(reducerSection),
[types.SET_ADD_ARTIST_VALUE]: createSetSettingValueReducer(reducerSection),
[types.SET_ADD_SERIES_DEFAULT]: function(state, { payload }) {
[types.SET_ADD_ARTIST_DEFAULT]: function(state, { payload }) {
const newState = getSectionState(state, reducerSection);
newState.defaults = {
@ -54,7 +54,7 @@ const addSeriesReducers = handleActions({
return updateSectionState(state, reducerSection, newState);
},
[types.CLEAR_ADD_SERIES]: function(state) {
[types.CLEAR_ADD_ARTIST]: function(state) {
const {
defaults,
...otherDefaultState
@ -65,4 +65,4 @@ const addSeriesReducers = handleActions({
}, defaultState);
export default addSeriesReducers;
export default addArtistReducers;

@ -15,21 +15,21 @@ export const defaultState = {
items: []
};
const reducerSection = 'importSeries';
const reducerSection = 'importArtist';
const importSeriesReducers = handleActions({
const importArtistReducers = handleActions({
[types.SET]: createSetReducer(reducerSection),
[types.UPDATE]: createUpdateReducer(reducerSection),
[types.UPDATE_ITEM]: createUpdateItemReducer(reducerSection),
[types.REMOVE_ITEM]: createRemoveItemReducer(reducerSection),
[types.CLEAR_IMPORT_SERIES]: function(state) {
[types.CLEAR_IMPORT_ARTIST]: function(state) {
return Object.assign({}, state, defaultState);
},
[types.SET_IMPORT_SERIES_VALUE]: createUpdateItemReducer(reducerSection)
[types.SET_IMPORT_ARTIST_VALUE]: createUpdateItemReducer(reducerSection)
}, defaultState);
export default importSeriesReducers;
export default importArtistReducers;

@ -2,8 +2,8 @@ import { combineReducers } from 'redux';
import { enableBatching } from 'redux-batched-actions';
import { routerReducer } from 'react-router-redux';
import app, { defaultState as defaultappState } from './appReducers';
import addSeries, { defaultState as defaultAddSeriesState } from './addSeriesReducers';
import importSeries, { defaultState as defaultImportSeriesState } from './importSeriesReducers';
import addArtist, { defaultState as defaultAddSeriesState } from './addArtistReducers';
import importArtist, { defaultState as defaultImportArtistState } from './importArtistReducers';
import series, { defaultState as defaultSeriesState } from './seriesReducers';
import seriesIndex, { defaultState as defaultSeriesIndexState } from './artistIndexReducers';
import seriesEditor, { defaultState as defaultSeriesEditorState } from './seriesEditorReducers';
@ -30,8 +30,8 @@ import organizePreview, { defaultState as defaultOrganizePreviewState } from './
export const defaultState = {
app: defaultappState,
addSeries: defaultAddSeriesState,
importSeries: defaultImportSeriesState,
addArtist: defaultAddSeriesState,
importArtist: defaultImportArtistState,
series: defaultSeriesState,
seriesIndex: defaultSeriesIndexState,
seriesEditor: defaultSeriesEditorState,
@ -59,8 +59,8 @@ export const defaultState = {
export default enableBatching(combineReducers({
app,
addSeries,
importSeries,
addArtist,
importArtist,
series,
seriesIndex,
seriesEditor,

@ -0,0 +1,15 @@
import _ from 'lodash';
import { createSelector } from 'reselect';
import createAllSeriesSelector from './createAllSeriesSelector';
function createExistingArtistSelector() {
return createSelector(
(state, { foreignArtistId }) => foreignArtistId,
createAllSeriesSelector(),
(foreignArtistId, series) => {
return _.some(series, { foreignArtistId });
}
);
}
export default createExistingArtistSelector;

@ -1,15 +0,0 @@
import _ from 'lodash';
import { createSelector } from 'reselect';
import createAllSeriesSelector from './createAllSeriesSelector';
function createExistingSeriesSelector() {
return createSelector(
(state, { tvdbId }) => tvdbId,
createAllSeriesSelector(),
(tvdbId, series) => {
return _.some(series, { tvdbId });
}
);
}
export default createExistingSeriesSelector;

@ -0,0 +1,28 @@
import _ from 'lodash';
import { createSelector } from 'reselect';
import createAllSeriesSelector from './createAllSeriesSelector';
function createImportArtistItemSelector() {
return createSelector(
(state, { id }) => id,
(state) => state.addArtist,
(state) => state.importArtist,
createAllSeriesSelector(),
(id, addArtist, importArtist, series) => {
const item = _.find(importArtist.items, { id }) || {};
const selectedSeries = item && item.selectedSeries;
const isExistingArtist = !!selectedSeries && _.some(series, { tvdbId: selectedSeries.tvdbId });
return {
defaultMonitor: addArtist.defaults.monitor,
defaultQualityProfileId: addArtist.defaults.qualityProfileId,
defaultSeriesType: addArtist.defaults.seriesType,
defaultSeasonFolder: addArtist.defaults.seasonFolder,
...item,
isExistingArtist
};
}
);
}
export default createImportArtistItemSelector;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save