[UI Work] Add Artist, Import Artist, Calendar

This commit is contained in:
Qstick 2017-09-07 23:09:52 -04:00
parent a747c5f135
commit 77f1d2e64c
109 changed files with 891 additions and 1082 deletions

View file

@ -168,7 +168,7 @@ function HistoryDetails(props) {
reasonMessage = 'File was deleted by via UI'; reasonMessage = 'File was deleted by via UI';
break; break;
case 'MissingFromDisk': 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; break;
case 'Upgrade': case 'Upgrade':
reasonMessage = 'File was deleted to import an upgrade'; reasonMessage = 'File was deleted to import an upgrade';

View file

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

View file

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

View file

@ -8,10 +8,10 @@ import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import TextInput from 'Components/Form/TextInput'; import TextInput from 'Components/Form/TextInput';
import PageContent from 'Components/Page/PageContent'; import PageContent from 'Components/Page/PageContent';
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector'; import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
import AddNewSeriesSearchResultConnector from './AddNewSeriesSearchResultConnector'; import AddNewArtistSearchResultConnector from './AddNewArtistSearchResultConnector';
import styles from './AddNewSeries.css'; import styles from './AddNewArtist.css';
class AddNewSeries extends Component { class AddNewArtist extends Component {
// //
// Lifecycle // Lifecycle
@ -29,7 +29,7 @@ class AddNewSeries extends Component {
const term = this.state.term; const term = this.state.term;
if (term) { if (term) {
this.props.onSeriesLookupChange(term); this.props.onArtistLookupChange(term);
} }
} }
@ -44,7 +44,7 @@ class AddNewSeries extends Component {
term, term,
isFetching: true isFetching: true
}); });
this.props.onSeriesLookupChange(term); this.props.onArtistLookupChange(term);
} else if (isFetching !== prevProps.isFetching) { } else if (isFetching !== prevProps.isFetching) {
this.setState({ this.setState({
isFetching isFetching
@ -60,16 +60,16 @@ class AddNewSeries extends Component {
this.setState({ term: value, isFetching: hasValue }, () => { this.setState({ term: value, isFetching: hasValue }, () => {
if (hasValue) { if (hasValue) {
this.props.onSeriesLookupChange(value); this.props.onArtistLookupChange(value);
} else { } else {
this.props.onClearSeriesLookup(); this.props.onClearArtistLookup();
} }
}); });
} }
onClearSeriesLookupPress = () => { onClearArtistLookupPress = () => {
this.setState({ term: '' }); this.setState({ term: '' });
this.props.onClearSeriesLookup(); this.props.onClearArtistLookup();
} }
// //
@ -97,7 +97,7 @@ class AddNewSeries extends Component {
<TextInput <TextInput
className={styles.searchInput} className={styles.searchInput}
name="seriesLookup" name="artistLookup"
value={term} value={term}
placeholder="eg. Breaking Benjamin, lidarr:####" placeholder="eg. Breaking Benjamin, lidarr:####"
onChange={this.onSearchInputChange} onChange={this.onSearchInputChange}
@ -105,7 +105,7 @@ class AddNewSeries extends Component {
<Button <Button
className={styles.clearLookupButton} className={styles.clearLookupButton}
onPress={this.onClearSeriesLookupPress} onPress={this.onClearArtistLookupPress}
> >
<Icon <Icon
name={icons.REMOVE} name={icons.REMOVE}
@ -130,7 +130,7 @@ class AddNewSeries extends Component {
{ {
items.map((item) => { items.map((item) => {
return ( return (
<AddNewSeriesSearchResultConnector <AddNewArtistSearchResultConnector
key={item.foreignArtistId} key={item.foreignArtistId}
{...item} {...item}
/> />
@ -157,7 +157,7 @@ class AddNewSeries extends Component {
!term && !term &&
<div className={styles.message}> <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 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> </div>
} }
@ -170,15 +170,15 @@ class AddNewSeries extends Component {
} }
} }
AddNewSeries.propTypes = { AddNewArtist.propTypes = {
term: PropTypes.string, term: PropTypes.string,
isFetching: PropTypes.bool.isRequired, isFetching: PropTypes.bool.isRequired,
error: PropTypes.object, error: PropTypes.object,
isAdding: PropTypes.bool.isRequired, isAdding: PropTypes.bool.isRequired,
addError: PropTypes.object, addError: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired, items: PropTypes.arrayOf(PropTypes.object).isRequired,
onSeriesLookupChange: PropTypes.func.isRequired, onArtistLookupChange: PropTypes.func.isRequired,
onClearSeriesLookup: PropTypes.func.isRequired onClearArtistLookup: PropTypes.func.isRequired
}; };
export default AddNewSeries; export default AddNewArtist;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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);

View file

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

View file

@ -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;

View file

@ -1,4 +1,4 @@
.series { .artist {
padding: 10px 20px; padding: 10px 20px;
width: 100%; width: 100%;

View file

@ -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;

View file

@ -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);

View file

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

View file

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

View file

@ -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;

View file

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

View file

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

View file

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

View file

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

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

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

View file

@ -26,12 +26,12 @@ function AppUpdatedModalContent(props) {
return ( return (
<ModalContent onModalClose={onModalClose}> <ModalContent onModalClose={onModalClose}>
<ModalHeader> <ModalHeader>
Sonarr Updated Lidarr Updated
</ModalHeader> </ModalHeader>
<ModalBody> <ModalBody>
<div> <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> </div>
{ {

View file

@ -27,11 +27,11 @@ function ConnectionLostModal(props) {
<ModalBody> <ModalBody>
<div> <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>
<div className={styles.automatic}> <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> </div>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>

View file

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

View file

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

View file

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

View file

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

View file

@ -12,10 +12,10 @@ function createCalendarEventsConnector() {
(state) => state.calendar, (state) => state.calendar,
(date, calendar) => { (date, calendar) => {
const filtered = _.filter(calendar.items, (item) => { 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());
} }
); );
} }

View file

@ -8,19 +8,19 @@
} }
.info, .info,
.episodeInfo { .albumInfo {
display: flex; display: flex;
} }
.seriesTitle, .artistName,
.episodeTitle { .albumTitle {
composes: truncate from 'Styles/Mixins/truncate.css'; composes: truncate from 'Styles/Mixins/truncate.css';
flex: 1 0 1px; flex: 1 0 1px;
margin-right: 10px; margin-right: 10px;
} }
.seriesTitle { .artistName {
color: #3a3f51; color: #3a3f51;
font-size: 14px; 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 { .missing {
border-left-color: $dangerColor; 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 { .unaired {
border-left-color: $primaryColor; border-left-color: $primaryColor;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -22,7 +22,7 @@ function getUrls(state) {
tags tags
} = state; } = 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) { if (unmonitored) {
icalUrl += 'unmonitored=true&'; icalUrl += 'unmonitored=true&';
@ -115,7 +115,7 @@ class CalendarLinkModalContent extends Component {
return ( return (
<ModalContent onModalClose={onModalClose}> <ModalContent onModalClose={onModalClose}>
<ModalHeader> <ModalHeader>
Sonarr Calendar Feed Lidarr Calendar Feed
</ModalHeader> </ModalHeader>
<ModalBody> <ModalBody>
@ -127,7 +127,7 @@ class CalendarLinkModalContent extends Component {
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="unmonitored" name="unmonitored"
value={unmonitored} value={unmonitored}
helpText="Include unmonitored episodes in the iCal feed" helpText="Include unmonitored albums in the iCal feed"
onChange={this.onInputChange} onChange={this.onInputChange}
/> />
</FormGroup> </FormGroup>
@ -139,7 +139,7 @@ class CalendarLinkModalContent extends Component {
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="premieresOnly" name="premieresOnly"
value={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} onChange={this.onInputChange}
/> />
</FormGroup> </FormGroup>
@ -163,7 +163,7 @@ class CalendarLinkModalContent extends Component {
type={inputTypes.TAG} type={inputTypes.TAG}
name="tags" name="tags"
value={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} onChange={this.onInputChange}
/> />
</FormGroup> </FormGroup>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -50,7 +50,7 @@ class AddDownloadClientModalContent extends Component {
<div> <div>
<Alert kind={kinds.INFO}> <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> <div>For more information on the individual downloadClients, clink on the info buttons.</div>
</Alert> </Alert>

View file

@ -50,7 +50,7 @@ class AddIndexerModalContent extends Component {
<div> <div>
<Alert kind={kinds.INFO}> <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> <div>For more information on the individual indexers, clink on the info buttons.</div>
</Alert> </Alert>

View file

@ -103,7 +103,7 @@ class MediaManagement extends Component {
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="skipFreeSpaceCheckWhenImporting" 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} onChange={onInputChange}
{...settings.skipFreeSpaceCheckWhenImporting} {...settings.skipFreeSpaceCheckWhenImporting}
/> />
@ -121,7 +121,7 @@ class MediaManagement extends Component {
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="copyUsingHardlinks" name="copyUsingHardlinks"
helpText="Use Hardlinks when trying to copy files from torrents that are still being seeded" 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} onChange={onInputChange}
{...settings.copyUsingHardlinks} {...settings.copyUsingHardlinks}
/> />
@ -168,7 +168,7 @@ class MediaManagement extends Component {
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="autoUnmonitorPreviouslyDownloadedEpisodes" name="autoUnmonitorPreviouslyDownloadedEpisodes"
helpText="Episodes deleted from disk are automatically unmonitored in Sonarr" helpText="Episodes deleted from disk are automatically unmonitored in Lidarr"
onChange={onInputChange} onChange={onInputChange}
{...settings.autoUnmonitorPreviouslyDownloadedEpisodes} {...settings.autoUnmonitorPreviouslyDownloadedEpisodes}
/> />
@ -184,7 +184,7 @@ class MediaManagement extends Component {
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="autoDownloadPropers" name="autoDownloadPropers"
helpText="Should Sonarr automatically upgrade to propers when available?" helpText="Should Lidarr automatically upgrade to propers when available?"
onChange={onInputChange} onChange={onInputChange}
{...settings.autoDownloadPropers} {...settings.autoDownloadPropers}
/> />
@ -200,7 +200,7 @@ class MediaManagement extends Component {
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="enableMediaInfo" 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} onChange={onInputChange}
{...settings.enableMediaInfo} {...settings.enableMediaInfo}
/> />
@ -269,7 +269,7 @@ class MediaManagement extends Component {
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="fileChmod" 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} onChange={onInputChange}
{...settings.fileChmod} {...settings.fileChmod}
/> />
@ -284,7 +284,7 @@ class MediaManagement extends Component {
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="folderChmod" name="folderChmod"
helpText="Octal, applied to series/season folders created by Sonarr" helpText="Octal, applied to series/season folders created by Lidarr"
values={fileDateOptions} values={fileDateOptions}
onChange={onInputChange} onChange={onInputChange}
{...settings.folderChmod} {...settings.folderChmod}

View file

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

View file

@ -81,7 +81,7 @@ function EditLanguageProfileModalContent(props) {
{...cutoff} {...cutoff}
value={cutoff ? cutoff.value.id : 0} value={cutoff ? cutoff.value.id : 0}
values={languages} 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} onChange={onCutoffChange}
/> />
</FormGroup> </FormGroup>

View file

@ -81,7 +81,7 @@ function EditQualityProfileModalContent(props) {
{...cutoff} {...cutoff}
value={cutoff ? cutoff.value.id : 0} value={cutoff ? cutoff.value.id : 0}
values={qualities} 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} onChange={onCutoffChange}
/> />
</FormGroup> </FormGroup>

View file

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

View file

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

View file

@ -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
};
});

View file

@ -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
};
});

View file

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

View file

@ -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
};
});

View file

@ -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
};
});

View file

@ -1,6 +1,6 @@
import _ from 'lodash'; import _ from 'lodash';
import persistState from 'redux-localstorage'; 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 episodeReducers from 'Store/Reducers/episodeReducers';
import * as artistIndexReducers from 'Store/Reducers/artistIndexReducers'; import * as artistIndexReducers from 'Store/Reducers/artistIndexReducers';
import * as seriesEditorReducers from 'Store/Reducers/seriesEditorReducers'; 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'; import * as queueReducers from 'Store/Reducers/queueReducers';
const reducers = [ const reducers = [
addSeriesReducers, addArtistReducers,
episodeReducers, episodeReducers,
artistIndexReducers, artistIndexReducers,
seriesEditorReducers, seriesEditorReducers,

View file

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

View file

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

View file

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

View file

@ -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;

View file

@ -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;

View file

@ -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