New: UI Updates, Tag manager, More custom filters (#437)

* New: UI Updates, Tag manager, More custom filters

* fixup! Fix ScanFixture Unit Tests

* Fixed: Sentry Errors from UI don't have release, branch, environment

* Changed: Bump Mobile Detect for New Device Detection

* Fixed: Build on changes to package.json

* fixup! Add MetadataProfile filter option

* fixup! Tag Note, Blacklist, Manual Import

* fixup: Remove connectSection

* fixup: root folder comment
This commit is contained in:
Qstick 2018-08-07 20:57:15 -04:00 committed by GitHub
commit 6581b3a2c5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
198 changed files with 3057 additions and 888 deletions

View file

@ -59,9 +59,7 @@ class DownloadClients extends Component {
} = this.state;
return (
<FieldSet
legend="Download Clients"
>
<FieldSet legend="Download Clients">
<PageSectionContent
errorMessage="Unable to load download clients"
{...otherProps}

View file

@ -1,11 +1,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import { sizes } from 'Helpers/Props';
import Modal from 'Components/Modal/Modal';
import EditDownloadClientModalContentConnector from './EditDownloadClientModalContentConnector';
function EditDownloadClientModal({ isOpen, onModalClose, ...otherProps }) {
return (
<Modal
size={sizes.MEDIUM}
isOpen={isOpen}
onModalClose={onModalClose}
>

View file

@ -1,15 +1,15 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
import { setDownloadClientValue, setDownloadClientFieldValue, saveDownloadClient, testDownloadClient } from 'Store/Actions/settingsActions';
import connectSection from 'Store/connectSection';
import EditDownloadClientModalContent from './EditDownloadClientModalContent';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.advancedSettings,
createProviderSettingsSelector(),
createProviderSettingsSelector('downloadClients'),
(advancedSettings, downloadClient) => {
return {
advancedSettings,
@ -85,10 +85,4 @@ EditDownloadClientModalContentConnector.propTypes = {
onModalClose: PropTypes.func.isRequired
};
export default connectSection(
createMapStateToProps,
mapDispatchToProps,
undefined,
undefined,
{ section: 'downloadClients' }
)(EditDownloadClientModalContentConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(EditDownloadClientModalContentConnector);

View file

@ -33,9 +33,7 @@ function DownloadClientOptions(props) {
{
hasSettings && !isFetching && !error &&
<div>
<FieldSet
legend="Completed Download Handling"
>
<FieldSet legend="Completed Download Handling">
<Form>
<FormGroup size={sizes.MEDIUM}>
<FormLabel>Enable</FormLabel>

View file

@ -1,16 +1,18 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createSettingsSectionSelector from 'Store/Selectors/createSettingsSectionSelector';
import { fetchDownloadClientOptions, setDownloadClientOptionsValue, saveDownloadClientOptions } from 'Store/Actions/settingsActions';
import { clearPendingChanges } from 'Store/Actions/baseActions';
import connectSection from 'Store/connectSection';
import DownloadClientOptions from './DownloadClientOptions';
const SECTION = 'downloadClientOptions';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.advancedSettings,
createSettingsSectionSelector(),
createSettingsSectionSelector(SECTION),
(advancedSettings, sectionSettings) => {
return {
advancedSettings,
@ -62,7 +64,7 @@ class DownloadClientOptionsConnector extends Component {
}
componentWillUnmount() {
this.props.dispatchClearPendingChanges({ section: this.props.section });
this.props.dispatchClearPendingChanges({ section: SECTION });
}
//
@ -86,7 +88,6 @@ class DownloadClientOptionsConnector extends Component {
}
DownloadClientOptionsConnector.propTypes = {
section: PropTypes.string.isRequired,
isSaving: PropTypes.bool.isRequired,
hasPendingChanges: PropTypes.bool.isRequired,
dispatchFetchDownloadClientOptions: PropTypes.func.isRequired,
@ -97,10 +98,4 @@ DownloadClientOptionsConnector.propTypes = {
onChildStateChange: PropTypes.func.isRequired
};
export default connectSection(
createMapStateToProps,
mapDispatchToProps,
undefined,
undefined,
{ section: 'settings.downloadClientOptions' }
)(DownloadClientOptionsConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(DownloadClientOptionsConnector);

View file

@ -1,11 +1,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import { sizes } from 'Helpers/Props';
import Modal from 'Components/Modal/Modal';
import EditRemotePathMappingModalContentConnector from './EditRemotePathMappingModalContentConnector';
function EditRemotePathMappingModal({ isOpen, onModalClose, ...otherProps }) {
return (
<Modal
size={sizes.MEDIUM}
isOpen={isOpen}
onModalClose={onModalClose}
>

View file

@ -44,9 +44,7 @@ class RemotePathMappings extends Component {
} = this.props;
return (
<FieldSet
legend="Remote Path Mappings"
>
<FieldSet legend="Remote Path Mappings">
<PageSectionContent
errorMessage="Unable to load Remote Path Mappings"
{...otherProps}

View file

@ -49,7 +49,8 @@ function BackupSettings(props) {
<FormInputGroup
type={inputTypes.NUMBER}
name="backupInterval"
helpText="Interval in days"
unit="days"
helpText="Interval to backup the Lidarr DB and settings"
onChange={onInputChange}
{...backupInterval}
/>
@ -64,7 +65,8 @@ function BackupSettings(props) {
<FormInputGroup
type={inputTypes.NUMBER}
name="backupRetention"
helpText="Retention in days. Automatic backups older the retention will be cleaned up automatically"
unit="days"
helpText="Automatic backups older than the retention will be cleaned up automatically"
onChange={onInputChange}
{...backupRetention}
/>

View file

@ -1,6 +1,7 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createSettingsSectionSelector from 'Store/Selectors/createSettingsSectionSelector';
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
@ -9,14 +10,15 @@ import { setGeneralSettingsValue, saveGeneralSettings, fetchGeneralSettings } fr
import { clearPendingChanges } from 'Store/Actions/baseActions';
import { executeCommand } from 'Store/Actions/commandActions';
import { restart } from 'Store/Actions/systemActions';
import connectSection from 'Store/connectSection';
import * as commandNames from 'Commands/commandNames';
import GeneralSettings from './GeneralSettings';
const SECTION = 'general';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.advancedSettings,
createSettingsSectionSelector(),
createSettingsSectionSelector(SECTION),
createCommandsSelector(),
createSystemStatusSelector(),
(advancedSettings, sectionSettings, commands, systemStatus) => {
@ -59,7 +61,7 @@ class GeneralSettingsConnector extends Component {
}
componentWillUnmount() {
this.props.clearPendingChanges({ section: this.props.section });
this.props.clearPendingChanges({ section: SECTION });
}
//
@ -98,7 +100,6 @@ class GeneralSettingsConnector extends Component {
}
GeneralSettingsConnector.propTypes = {
section: PropTypes.string.isRequired,
isResettingApiKey: PropTypes.bool.isRequired,
setGeneralSettingsValue: PropTypes.func.isRequired,
saveGeneralSettings: PropTypes.func.isRequired,
@ -108,10 +109,4 @@ GeneralSettingsConnector.propTypes = {
clearPendingChanges: PropTypes.func.isRequired
};
export default connectSection(
createMapStateToProps,
mapDispatchToProps,
undefined,
undefined,
{ section: 'settings.general' }
)(GeneralSettingsConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(GeneralSettingsConnector);

View file

@ -1,9 +1,9 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
import { setImportListValue, setImportListFieldValue, saveImportList, testImportList } from 'Store/Actions/settingsActions';
import connectSection from 'Store/connectSection';
import EditImportListModalContent from './EditImportListModalContent';
function createMapStateToProps() {
@ -11,7 +11,7 @@ function createMapStateToProps() {
(state) => state.settings.advancedSettings,
(state) => state.settings.languageProfiles,
(state) => state.settings.metadataProfiles,
createProviderSettingsSelector(),
createProviderSettingsSelector('importLists'),
(advancedSettings, languageProfiles, metadataProfiles, importList) => {
return {
advancedSettings,
@ -89,10 +89,4 @@ EditImportListModalContentConnector.propTypes = {
onModalClose: PropTypes.func.isRequired
};
export default connectSection(
createMapStateToProps,
mapDispatchToProps,
undefined,
undefined,
{ section: 'importLists' }
)(EditImportListModalContentConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(EditImportListModalContentConnector);

View file

@ -1,11 +1,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import { sizes } from 'Helpers/Props';
import Modal from 'Components/Modal/Modal';
import EditIndexerModalContentConnector from './EditIndexerModalContentConnector';
function EditIndexerModal({ isOpen, onModalClose, ...otherProps }) {
return (
<Modal
size={sizes.MEDIUM}
isOpen={isOpen}
onModalClose={onModalClose}
>

View file

@ -96,7 +96,7 @@ function EditIndexerModalContent(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="enableAutomaticSearch"
helpText={supportsSearch.value && 'Will be used when automatic searches are performed via the UI or by Lidarr'}
helpText={supportsSearch.value ? 'Will be used when automatic searches are performed via the UI or by Lidarr' : undefined}
helpTextWarning={supportsSearch.value ? undefined : 'Search is not supported with this indexer'}
isDisabled={!supportsSearch.value}
{...enableAutomaticSearch}
@ -110,7 +110,7 @@ function EditIndexerModalContent(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="enableInteractiveSearch"
helpText={supportsSearch.value && 'Will be used when interactive search is used'}
helpText={supportsSearch.value ? 'Will be used when interactive search is used' : undefined}
helpTextWarning={supportsSearch.value ? undefined : 'Search is not supported with this indexer'}
isDisabled={!supportsSearch.value}
{...enableInteractiveSearch}

View file

@ -1,15 +1,15 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
import { setIndexerValue, setIndexerFieldValue, saveIndexer, testIndexer } from 'Store/Actions/settingsActions';
import connectSection from 'Store/connectSection';
import EditIndexerModalContent from './EditIndexerModalContent';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.advancedSettings,
createProviderSettingsSelector(),
createProviderSettingsSelector('indexers'),
(advancedSettings, indexer) => {
return {
advancedSettings,
@ -85,10 +85,4 @@ EditIndexerModalContentConnector.propTypes = {
onModalClose: PropTypes.func.isRequired
};
export default connectSection(
createMapStateToProps,
mapDispatchToProps,
undefined,
undefined,
{ section: 'indexers' }
)(EditIndexerModalContentConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(EditIndexerModalContentConnector);

View file

@ -59,9 +59,7 @@ class Indexers extends Component {
} = this.state;
return (
<FieldSet
legend="Indexers"
>
<FieldSet legend="Indexers">
<PageSectionContent
errorMessage="Unable to load Indexers"
{...otherProps}

View file

@ -19,9 +19,7 @@ function IndexerOptions(props) {
} = props;
return (
<FieldSet
legend="Options"
>
<FieldSet legend="Options">
{
isFetching &&
<LoadingIndicator />
@ -42,6 +40,7 @@ function IndexerOptions(props) {
type={inputTypes.NUMBER}
name="minimumAge"
min={0}
unit="minutes"
helpText="Usenet only: Minimum age in minutes of NZBs before they are grabbed. Use this to give new releases time to propagate to your usenet provider."
onChange={onInputChange}
{...settings.minimumAge}
@ -55,6 +54,7 @@ function IndexerOptions(props) {
type={inputTypes.NUMBER}
name="maximumSize"
min={0}
unit="MB"
helpText="Maximum size for a release to be grabbed in MB. Set to zero to set to unlimited."
onChange={onInputChange}
{...settings.maximumSize}
@ -68,6 +68,7 @@ function IndexerOptions(props) {
type={inputTypes.NUMBER}
name="retention"
min={0}
unit="days"
helpText="Usenet only: Set to zero to set for unlimited retention"
onChange={onInputChange}
{...settings.retention}
@ -84,6 +85,7 @@ function IndexerOptions(props) {
type={inputTypes.NUMBER}
name="rssSyncInterval"
min={0}
unit="minutes"
helpText="Interval in minutes. Set to zero to disable (this will stop all automatic release grabbing)"
helpTextWarning="This will apply to all indexers, please follow the rules set forth by them"
helpLink="https://github.com/Lidarr/Lidarr/wiki/RSS-Sync"

View file

@ -1,16 +1,18 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createSettingsSectionSelector from 'Store/Selectors/createSettingsSectionSelector';
import { fetchIndexerOptions, setIndexerOptionsValue, saveIndexerOptions } from 'Store/Actions/settingsActions';
import { clearPendingChanges } from 'Store/Actions/baseActions';
import connectSection from 'Store/connectSection';
import IndexerOptions from './IndexerOptions';
const SECTION = 'indexerOptions';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.advancedSettings,
createSettingsSectionSelector(),
createSettingsSectionSelector(SECTION),
(advancedSettings, sectionSettings) => {
return {
advancedSettings,
@ -62,7 +64,7 @@ class IndexerOptionsConnector extends Component {
}
componentWillUnmount() {
this.props.dispatchClearPendingChanges({ section: this.props.section });
this.props.dispatchClearPendingChanges({ section: SECTION });
}
//
@ -86,7 +88,6 @@ class IndexerOptionsConnector extends Component {
}
IndexerOptionsConnector.propTypes = {
section: PropTypes.string.isRequired,
isSaving: PropTypes.bool.isRequired,
hasPendingChanges: PropTypes.bool.isRequired,
dispatchFetchIndexerOptions: PropTypes.func.isRequired,
@ -97,10 +98,4 @@ IndexerOptionsConnector.propTypes = {
onChildStateChange: PropTypes.func.isRequired
};
export default connectSection(
createMapStateToProps,
mapDispatchToProps,
undefined,
undefined,
{ section: 'settings.indexerOptions' }
)(IndexerOptionsConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(IndexerOptionsConnector);

View file

@ -1,11 +1,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import { sizes } from 'Helpers/Props';
import Modal from 'Components/Modal/Modal';
import EditRestrictionModalContentConnector from './EditRestrictionModalContentConnector';
function EditRestrictionModal({ isOpen, onModalClose, ...otherProps }) {
return (
<Modal
size={sizes.MEDIUM}
isOpen={isOpen}
onModalClose={onModalClose}
>

View file

@ -45,9 +45,7 @@ class Restrictions extends Component {
} = this.props;
return (
<FieldSet
legend="Restrictions"
>
<FieldSet legend="Restrictions">
<PageSectionContent
errorMessage="Unable to load Restrictions"
{...otherProps}

View file

@ -64,9 +64,7 @@ class MediaManagement extends Component {
{
advancedSettings &&
<FieldSet
legend="Folders"
>
<FieldSet legend="Folders">
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}

View file

@ -1,19 +1,21 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createSettingsSectionSelector from 'Store/Selectors/createSettingsSectionSelector';
import createSystemStatusSelector from 'Store/Selectors/createSystemStatusSelector';
import { fetchMediaManagementSettings, setMediaManagementSettingsValue, saveMediaManagementSettings, saveNamingSettings } from 'Store/Actions/settingsActions';
import { clearPendingChanges } from 'Store/Actions/baseActions';
import connectSection from 'Store/connectSection';
import MediaManagement from './MediaManagement';
const SECTION = 'mediaManagement';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.advancedSettings,
(state) => state.settings.naming,
createSettingsSectionSelector(),
createSettingsSectionSelector(SECTION),
createSystemStatusSelector(),
(advancedSettings, namingSettings, sectionSettings, systemStatus) => {
return {
@ -44,7 +46,7 @@ class MediaManagementConnector extends Component {
}
componentWillUnmount() {
this.props.clearPendingChanges({ section: this.props.section });
this.props.clearPendingChanges({ section: SECTION });
}
//
@ -74,7 +76,6 @@ class MediaManagementConnector extends Component {
}
MediaManagementConnector.propTypes = {
section: PropTypes.string.isRequired,
fetchMediaManagementSettings: PropTypes.func.isRequired,
setMediaManagementSettingsValue: PropTypes.func.isRequired,
saveMediaManagementSettings: PropTypes.func.isRequired,
@ -82,10 +83,4 @@ MediaManagementConnector.propTypes = {
clearPendingChanges: PropTypes.func.isRequired
};
export default connectSection(
createMapStateToProps,
mapDispatchToProps,
undefined,
undefined,
{ section: 'settings.mediaManagement' }
)(MediaManagementConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(MediaManagementConnector);

View file

@ -113,9 +113,7 @@ class Naming extends Component {
}
return (
<FieldSet
legend="Track Naming"
>
<FieldSet legend="Track Naming">
{
isFetching &&
<LoadingIndicator />

View file

@ -1,18 +1,20 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createSettingsSectionSelector from 'Store/Selectors/createSettingsSectionSelector';
import { fetchNamingSettings, setNamingSettingsValue, fetchNamingExamples } from 'Store/Actions/settingsActions';
import { clearPendingChanges } from 'Store/Actions/baseActions';
import connectSection from 'Store/connectSection';
import Naming from './Naming';
const SECTION = 'naming';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.advancedSettings,
(state) => state.settings.namingExamples,
createSettingsSectionSelector(),
createSettingsSectionSelector(SECTION),
(advancedSettings, examples, sectionSettings) => {
return {
advancedSettings,
@ -48,7 +50,7 @@ class NamingConnector extends Component {
}
componentWillUnmount() {
this.props.clearPendingChanges({ section: this.props.section });
this.props.clearPendingChanges({ section: SECTION });
}
//
@ -86,17 +88,10 @@ class NamingConnector extends Component {
}
NamingConnector.propTypes = {
section: PropTypes.string.isRequired,
fetchNamingSettings: PropTypes.func.isRequired,
setNamingSettingsValue: PropTypes.func.isRequired,
fetchNamingExamples: PropTypes.func.isRequired,
clearPendingChanges: PropTypes.func.isRequired
};
export default connectSection(
createMapStateToProps,
mapDispatchToProps,
undefined,
undefined,
{ section: 'settings.naming' }
)(NamingConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(NamingConnector);

View file

@ -163,8 +163,8 @@ class NamingModal extends Component {
];
const qualityTokens = [
{ token: '{Quality Full}', example: 'HDTV 720p Proper' },
{ token: '{Quality Title}', example: 'HDTV 720p' }
{ token: '{Quality Full}', example: 'FLAC Proper' },
{ token: '{Quality Title}', example: 'FLAC' }
];
const mediaInfoTokens = [

View file

@ -1,11 +1,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import { sizes } from 'Helpers/Props';
import Modal from 'Components/Modal/Modal';
import EditMetadataModalContentConnector from './EditMetadataModalContentConnector';
function EditMetadataModal({ isOpen, onModalClose, ...otherProps }) {
return (
<Modal
size={sizes.MEDIUM}
isOpen={isOpen}
onModalClose={onModalClose}
>

View file

@ -13,9 +13,7 @@ function Metadatas(props) {
} = props;
return (
<FieldSet
legend="Metadata Consumers"
>
<FieldSet legend="Metadata Consumers">
<PageSectionContent
errorMessage="Unable to load Metadata"
{...otherProps}

View file

@ -36,9 +36,7 @@ function MetadataProvider(props) {
<Form>
{
advancedSettings &&
<FieldSet
legend="Metadata Provider Source"
>
<FieldSet legend="Metadata Provider Source">
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}

View file

@ -1,16 +1,18 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createSettingsSectionSelector from 'Store/Selectors/createSettingsSectionSelector';
import { setMetadataProviderValue, saveMetadataProvider, fetchMetadataProvider } from 'Store/Actions/settingsActions';
import { clearPendingChanges } from 'Store/Actions/baseActions';
import connectSection from 'Store/connectSection';
import MetadataProvider from './MetadataProvider';
const SECTION = 'metadataProvider';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.advancedSettings,
createSettingsSectionSelector(),
createSettingsSectionSelector(SECTION),
(advancedSettings, sectionSettings) => {
return {
advancedSettings,
@ -43,7 +45,7 @@ class MetadataProviderConnector extends Component {
}
componentWillUnmount() {
this.props.clearPendingChanges({ section: this.props.section });
this.props.clearPendingChanges({ section: SECTION });
}
//
@ -74,7 +76,6 @@ class MetadataProviderConnector extends Component {
}
MetadataProviderConnector.propTypes = {
section: PropTypes.string.isRequired,
hasPendingChanges: PropTypes.bool.isRequired,
setMetadataProviderValue: PropTypes.func.isRequired,
saveMetadataProvider: PropTypes.func.isRequired,
@ -83,10 +84,4 @@ MetadataProviderConnector.propTypes = {
onHasPendingChange: PropTypes.func.isRequired
};
export default connectSection(
createMapStateToProps,
mapDispatchToProps,
undefined,
{ withRef: true },
{ section: 'settings.metadataProvider' }
)(MetadataProviderConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(MetadataProviderConnector);

View file

@ -1,11 +1,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import { sizes } from 'Helpers/Props';
import Modal from 'Components/Modal/Modal';
import EditNotificationModalContentConnector from './EditNotificationModalContentConnector';
function EditNotificationModal({ isOpen, onModalClose, ...otherProps }) {
return (
<Modal
size={sizes.MEDIUM}
isOpen={isOpen}
onModalClose={onModalClose}
>

View file

@ -1,15 +1,15 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
import { setNotificationValue, setNotificationFieldValue, saveNotification, testNotification } from 'Store/Actions/settingsActions';
import connectSection from 'Store/connectSection';
import EditNotificationModalContent from './EditNotificationModalContent';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.advancedSettings,
createProviderSettingsSelector(),
createProviderSettingsSelector('notifications'),
(advancedSettings, notification) => {
return {
advancedSettings,
@ -85,10 +85,4 @@ EditNotificationModalContentConnector.propTypes = {
onModalClose: PropTypes.func.isRequired
};
export default connectSection(
createMapStateToProps,
mapDispatchToProps,
undefined,
undefined,
{ section: 'notifications' }
)(EditNotificationModalContentConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(EditNotificationModalContentConnector);

View file

@ -59,9 +59,7 @@ class Notifications extends Component {
} = this.state;
return (
<FieldSet
legend="Connections"
>
<FieldSet legend="Connections">
<PageSectionContent
errorMessage="Unable to load Notifications"
{...otherProps}

View file

@ -66,9 +66,7 @@ class DelayProfiles extends Component {
return (
<Measure onMeasure={this.onMeasure}>
<FieldSet
legend="Delay Profiles"
>
<FieldSet legend="Delay Profiles">
<PageSectionContent
errorMessage="Unable to load Delay Profiles"
{...otherProps}

View file

@ -1,11 +1,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import { sizes } from 'Helpers/Props';
import Modal from 'Components/Modal/Modal';
import EditDelayProfileModalContentConnector from './EditDelayProfileModalContentConnector';
function EditDelayProfileModal({ isOpen, onModalClose, ...otherProps }) {
return (
<Modal
size={sizes.MEDIUM}
isOpen={isOpen}
onModalClose={onModalClose}
>

View file

@ -85,6 +85,7 @@ function EditDelayProfileModalContent(props) {
<FormInputGroup
type={inputTypes.NUMBER}
name="usenetDelay"
unit="minutes"
{...usenetDelay}
helpText="Delay in minutes to wait before grabbing a release from Usenet"
onChange={onInputChange}
@ -100,6 +101,7 @@ function EditDelayProfileModalContent(props) {
<FormInputGroup
type={inputTypes.NUMBER}
name="torrentDelay"
unit="minutes"
{...torrentDelay}
helpText="Delay in minutes to wait before grabbing a torrent"
onChange={onInputChange}

View file

@ -1,11 +1,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import { sizes } from 'Helpers/Props';
import Modal from 'Components/Modal/Modal';
import EditLanguageProfileModalContentConnector from './EditLanguageProfileModalContentConnector';
function EditLanguageProfileModal({ isOpen, onModalClose, ...otherProps }) {
return (
<Modal
size={sizes.MEDIUM}
isOpen={isOpen}
onModalClose={onModalClose}
>

View file

@ -1,16 +1,16 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createProfileInUseSelector from 'Store/Selectors/createProfileInUseSelector';
import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
import { fetchLanguageProfileSchema, setLanguageProfileValue, saveLanguageProfile } from 'Store/Actions/settingsActions';
import connectSection from 'Store/connectSection';
import EditLanguageProfileModalContent from './EditLanguageProfileModalContent';
function createLanguagesSelector() {
return createSelector(
createProviderSettingsSelector(),
createProviderSettingsSelector('languageProfiles'),
(languageProfile) => {
const languages = languageProfile.item.languages;
if (!languages || !languages.value) {
@ -33,7 +33,7 @@ function createLanguagesSelector() {
function createMapStateToProps() {
return createSelector(
createProviderSettingsSelector(),
createProviderSettingsSelector('languageProfiles'),
createLanguagesSelector(),
createProfileInUseSelector('languageProfileId'),
(languageProfile, languages, isInUse) => {
@ -186,10 +186,4 @@ EditLanguageProfileModalContentConnector.propTypes = {
onModalClose: PropTypes.func.isRequired
};
export default connectSection(
createMapStateToProps,
mapDispatchToProps,
undefined,
undefined,
{ section: 'languageProfiles' }
)(EditLanguageProfileModalContentConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(EditLanguageProfileModalContentConnector);

View file

@ -51,9 +51,7 @@ class LanguageProfiles extends Component {
} = this.props;
return (
<FieldSet
legend="Language Profiles"
>
<FieldSet legend="Language Profiles">
<PageSectionContent
errorMessage="Unable to load Language Profiles"
{...otherProps}

View file

@ -1,11 +1,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import { sizes } from 'Helpers/Props';
import Modal from 'Components/Modal/Modal';
import EditMetadataProfileModalContentConnector from './EditMetadataProfileModalContentConnector';
function EditMetadataProfileModal({ isOpen, onModalClose, ...otherProps }) {
return (
<Modal
size={sizes.MEDIUM}
isOpen={isOpen}
onModalClose={onModalClose}
>

View file

@ -1,16 +1,16 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createProfileInUseSelector from 'Store/Selectors/createProfileInUseSelector';
import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
import { fetchMetadataProfileSchema, setMetadataProfileValue, saveMetadataProfile } from 'Store/Actions/settingsActions';
import connectSection from 'Store/connectSection';
import EditMetadataProfileModalContent from './EditMetadataProfileModalContent';
function createPrimaryAlbumTypesSelector() {
return createSelector(
createProviderSettingsSelector(),
createProviderSettingsSelector('metadataProfiles'),
(metadataProfile) => {
const primaryAlbumTypes = metadataProfile.item.primaryAlbumTypes;
if (!primaryAlbumTypes || !primaryAlbumTypes.value) {
@ -79,7 +79,7 @@ function createReleaseStatusesSelector() {
function createMapStateToProps() {
return createSelector(
createProviderSettingsSelector(),
createProviderSettingsSelector('metadataProfiles'),
createPrimaryAlbumTypesSelector(),
createSecondaryAlbumTypesSelector(),
createReleaseStatusesSelector(),
@ -210,10 +210,4 @@ EditMetadataProfileModalContentConnector.propTypes = {
onModalClose: PropTypes.func.isRequired
};
export default connectSection(
createMapStateToProps,
mapDispatchToProps,
undefined,
undefined,
{ section: 'metadataProfiles' }
)(EditMetadataProfileModalContentConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(EditMetadataProfileModalContentConnector);

View file

@ -51,9 +51,7 @@ class MetadataProfiles extends Component {
} = this.props;
return (
<FieldSet
legend="Metadata Profiles"
>
<FieldSet legend="Metadata Profiles">
<PageSectionContent
errorMessage="Unable to load Metadata Profiles"
{...otherProps}

View file

@ -145,7 +145,7 @@ class EditQualityProfileModalContent extends Component {
<div className={styles.formGroupsContainer}>
<div className={styles.formGroupWrapper}>
<FormGroup size={sizes.EXTRA_SMALL}>
<FormLabel size={sizes.small}>
<FormLabel size={sizes.SMALL}>
Name
</FormLabel>
@ -158,7 +158,7 @@ class EditQualityProfileModalContent extends Component {
</FormGroup>
<FormGroup size={sizes.EXTRA_SMALL}>
<FormLabel size={sizes.small}>
<FormLabel size={sizes.SMALL}>
Cutoff
</FormLabel>

View file

@ -1,11 +1,11 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createProfileInUseSelector from 'Store/Selectors/createProfileInUseSelector';
import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
import { fetchQualityProfileSchema, setQualityProfileValue, saveQualityProfile } from 'Store/Actions/settingsActions';
import connectSection from 'Store/connectSection';
import EditQualityProfileModalContent from './EditQualityProfileModalContent';
function getQualityItemGroupId(qualityProfile) {
@ -33,7 +33,7 @@ function parseIndex(index) {
function createQualitiesSelector() {
return createSelector(
createProviderSettingsSelector(),
createProviderSettingsSelector('qualityProfiles'),
(qualityProfile) => {
const items = qualityProfile.item.items;
if (!items || !items.value) {
@ -63,7 +63,7 @@ function createQualitiesSelector() {
function createMapStateToProps() {
return createSelector(
createProviderSettingsSelector(),
createProviderSettingsSelector('qualityProfiles'),
createQualitiesSelector(),
createProfileInUseSelector('qualityProfileId'),
(qualityProfile, qualities, isInUse) => {
@ -439,10 +439,4 @@ EditQualityProfileModalContentConnector.propTypes = {
onModalClose: PropTypes.func.isRequired
};
export default connectSection(
createMapStateToProps,
mapDispatchToProps,
undefined,
undefined,
{ section: 'qualityProfiles' }
)(EditQualityProfileModalContentConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(EditQualityProfileModalContentConnector);

View file

@ -51,9 +51,7 @@ class QualityProfiles extends Component {
} = this.props;
return (
<FieldSet
legend="Quality Profiles"
>
<FieldSet legend="Quality Profiles">
<PageSectionContent
errorMessage="Unable to load Quality Profiles"
{...otherProps}c={true}

View file

@ -17,9 +17,7 @@ class QualityDefinitions extends Component {
} = this.props;
return (
<FieldSet
legend="Quality Definitions"
>
<FieldSet legend="Quality Definitions">
<PageSectionContent
errorMessage="Unable to load Quality Definitions"
{...otherProps}

View file

@ -101,6 +101,17 @@ function Settings() {
Create metadata files when tracks are imported or artist are refreshed
</div>
<Link
className={styles.link}
to="/settings/tags"
>
Tags
</Link>
<div className={styles.summary}>
Manage artist, profile, restriction, and notification tags
</div>
<Link
className={styles.link}
to="/settings/general"

View file

@ -0,0 +1,33 @@
import PropTypes from 'prop-types';
import React from 'react';
import { sizes } from 'Helpers/Props';
import Modal from 'Components/Modal/Modal';
import TagDetailsModalContentConnector from './TagDetailsModalContentConnector';
function TagDetailsModal(props) {
const {
isOpen,
onModalClose,
...otherProps
} = props;
return (
<Modal
size={sizes.SMALL}
isOpen={isOpen}
onModalClose={onModalClose}
>
<TagDetailsModalContentConnector
{...otherProps}
onModalClose={onModalClose}
/>
</Modal>
);
}
TagDetailsModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default TagDetailsModal;

View file

@ -0,0 +1,26 @@
.items {
display: flex;
flex-wrap: wrap;
}
.item {
flex: 0 0 100%;
}
.restriction {
margin-bottom: 5px;
padding-bottom: 5px;
border-bottom: 1px solid $borderColor;
&:last-child {
margin: 0;
padding: 0;
border-bottom: none;
}
}
.deleteButton {
composes: button from 'Components/Link/Button.css';
margin-right: auto;
}

View file

@ -0,0 +1,163 @@
import PropTypes from 'prop-types';
import React from 'react';
import split from 'Utilities/String/split';
import { kinds } from 'Helpers/Props';
import FieldSet from 'Components/FieldSet';
import Button from 'Components/Link/Button';
import Label from 'Components/Label';
import ModalContent from 'Components/Modal/ModalContent';
import ModalHeader from 'Components/Modal/ModalHeader';
import ModalBody from 'Components/Modal/ModalBody';
import ModalFooter from 'Components/Modal/ModalFooter';
import styles from './TagDetailsModalContent.css';
function TagDetailsModalContent(props) {
const {
label,
isTagUsed,
artist,
delayProfiles,
notifications,
restrictions,
onModalClose,
onDeleteTagPress
} = props;
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
Tag Details - {label}
</ModalHeader>
<ModalBody>
{
!isTagUsed &&
<div>Tag is not used and can be deleted</div>
}
{
!!artist.length &&
<FieldSet legend="Artists">
{
artist.map((item) => {
return (
<div key={item.id}>
{item.artistName}
</div>
);
})
}
</FieldSet>
}
{
!!delayProfiles.length &&
<FieldSet legend="Delay Profiles">
{
delayProfiles.map((item) => {
return (
<div key={item.id}>
{item.name}
</div>
);
})
}
</FieldSet>
}
{
!!notifications.length &&
<FieldSet legend="Connections">
{
notifications.map((item) => {
return (
<div key={item.id}>
{item.name}
</div>
);
})
}
</FieldSet>
}
{
!!restrictions.length &&
<FieldSet legend="Restrictions">
{
restrictions.map((item) => {
return (
<div
key={item.id}
className={styles.restriction}
>
<div>
{
split(item.required).map((r) => {
return (
<Label
key={r}
kind={kinds.SUCCESS}
>
{r}
</Label>
);
})
}
</div>
<div>
{
split(item.ignored).map((i) => {
return (
<Label
key={i}
kind={kinds.DANGER}
>
{i}
</Label>
);
})
}
</div>
</div>
);
})
}
</FieldSet>
}
</ModalBody>
<ModalFooter>
{
<Button
className={styles.deleteButton}
kind={kinds.DANGER}
isDisabled={isTagUsed}
onPress={onDeleteTagPress}
>
Delete
</Button>
}
<Button
onPress={onModalClose}
>
Close
</Button>
</ModalFooter>
</ModalContent>
);
}
TagDetailsModalContent.propTypes = {
label: PropTypes.string.isRequired,
isTagUsed: PropTypes.bool.isRequired,
artist: PropTypes.arrayOf(PropTypes.object).isRequired,
delayProfiles: PropTypes.arrayOf(PropTypes.object).isRequired,
notifications: PropTypes.arrayOf(PropTypes.object).isRequired,
restrictions: PropTypes.arrayOf(PropTypes.object).isRequired,
onModalClose: PropTypes.func.isRequired,
onDeleteTagPress: PropTypes.func.isRequired
};
export default TagDetailsModalContent;

View file

@ -0,0 +1,61 @@
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createAllArtistSelector from 'Store/Selectors/createAllArtistSelector';
import TagDetailsModalContent from './TagDetailsModalContent';
function findMatchingItems(ids, items) {
return items.filter((s) => {
return ids.includes(s.id);
});
}
function createMatchingArtistSelector() {
return createSelector(
(state, { artistIds }) => artistIds,
createAllArtistSelector(),
findMatchingItems
);
}
function createMatchingDelayProfilesSelector() {
return createSelector(
(state, { delayProfileIds }) => delayProfileIds,
(state) => state.settings.delayProfiles.items,
findMatchingItems
);
}
function createMatchingNotificationsSelector() {
return createSelector(
(state, { notificationIds }) => notificationIds,
(state) => state.settings.notifications.items,
findMatchingItems
);
}
function createMatchingRestrictionsSelector() {
return createSelector(
(state, { restrictionIds }) => restrictionIds,
(state) => state.settings.restrictions.items,
findMatchingItems
);
}
function createMapStateToProps() {
return createSelector(
createMatchingArtistSelector(),
createMatchingDelayProfilesSelector(),
createMatchingNotificationsSelector(),
createMatchingRestrictionsSelector(),
(artist, delayProfiles, notifications, restrictions) => {
return {
artist,
delayProfiles,
notifications,
restrictions
};
}
);
}
export default connect(createMapStateToProps)(TagDetailsModalContent);

View file

@ -0,0 +1,11 @@
.tag {
composes: card from 'Components/Card.css';
width: 150px;
}
.label {
margin-bottom: 20px;
font-weight: 300;
font-size: 24px;
}

View file

@ -0,0 +1,166 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { kinds } from 'Helpers/Props';
import Card from 'Components/Card';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import TagDetailsModal from './Details/TagDetailsModal';
import styles from './Tag.css';
class Tag extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
isDetailsModalOpen: false,
isDeleteTagModalOpen: false
};
}
//
// Listeners
onShowDetailsPress = () => {
this.setState({ isDetailsModalOpen: true });
}
onDetailsModalClose = () => {
this.setState({ isDetailsModalOpen: false });
}
onDeleteTagPress = () => {
this.setState({
isDetailsModalOpen: false,
isDeleteTagModalOpen: true
});
}
onDeleteTagModalClose= () => {
this.setState({ isDeleteTagModalOpen: false });
}
onConfirmDeleteTag = () => {
this.props.onConfirmDeleteTag({ id: this.props.id });
}
//
// Render
render() {
const {
label,
delayProfileIds,
notificationIds,
restrictionIds,
artistIds
} = this.props;
const {
isDetailsModalOpen,
isDeleteTagModalOpen
} = this.state;
const isTagUsed = !!(
delayProfileIds.length ||
notificationIds.length ||
restrictionIds.length ||
artistIds.length
);
return (
<Card
className={styles.tag}
overlayContent={true}
onPress={this.onShowDetailsPress}
>
<div className={styles.label}>
{label}
</div>
{
isTagUsed &&
<div>
{
!!artistIds.length &&
<div>
{artistIds.length} artists
</div>
}
{
!!delayProfileIds.length &&
<div>
{delayProfileIds.length} delay profile{delayProfileIds.length > 1 && 's'}
</div>
}
{
!!notificationIds.length &&
<div>
{notificationIds.length} connection{notificationIds.length > 1 && 's'}
</div>
}
{
!!restrictionIds.length &&
<div>
{restrictionIds.length} restriction{restrictionIds.length > 1 && 's'}
</div>
}
</div>
}
{
!isTagUsed &&
<div>
No links
</div>
}
<TagDetailsModal
label={label}
isTagUsed={isTagUsed}
artistIds={artistIds}
delayProfileIds={delayProfileIds}
notificationIds={notificationIds}
restrictionIds={restrictionIds}
isOpen={isDetailsModalOpen}
onModalClose={this.onDetailsModalClose}
onDeleteTagPress={this.onDeleteTagPress}
/>
<ConfirmModal
isOpen={isDeleteTagModalOpen}
kind={kinds.DANGER}
title="Delete Tag"
message={`Are you sure you want to delete the tag '${label}'?`}
confirmLabel="Delete"
onConfirm={this.onConfirmDeleteTag}
onCancel={this.onDeleteTagModalClose}
/>
</Card>
);
}
}
Tag.propTypes = {
id: PropTypes.number.isRequired,
label: PropTypes.string.isRequired,
delayProfileIds: PropTypes.arrayOf(PropTypes.number).isRequired,
notificationIds: PropTypes.arrayOf(PropTypes.number).isRequired,
restrictionIds: PropTypes.arrayOf(PropTypes.number).isRequired,
artistIds: PropTypes.arrayOf(PropTypes.number).isRequired,
onConfirmDeleteTag: PropTypes.func.isRequired
};
Tag.defaultProps = {
delayProfileIds: [],
notificationIds: [],
restrictionIds: [],
artistIds: []
};
export default Tag;

View file

@ -0,0 +1,22 @@
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createTagDetailsSelector from 'Store/Selectors/createTagDetailsSelector';
import { deleteTag } from 'Store/Actions/tagActions';
import Tag from './Tag';
function createMapStateToProps() {
return createSelector(
createTagDetailsSelector(),
(tagDetails) => {
return {
...tagDetails
};
}
);
}
const mapStateToProps = {
onConfirmDeleteTag: deleteTag
};
export default connect(createMapStateToProps, mapStateToProps)(Tag);

View file

@ -0,0 +1,21 @@
import React from 'react';
import PageContent from 'Components/Page/PageContent';
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import TagsConnector from './TagsConnector';
function TagSettings() {
return (
<PageContent title="Tags">
<SettingsToolbarConnector
showSave={false}
/>
<PageContentBodyConnector>
<TagsConnector />
</PageContentBodyConnector>
</PageContent>
);
}
export default TagSettings;

View file

@ -0,0 +1,4 @@
.tags {
display: flex;
flex-wrap: wrap;
}

View file

@ -0,0 +1,50 @@
import PropTypes from 'prop-types';
import React from 'react';
import FieldSet from 'Components/FieldSet';
import PageSectionContent from 'Components/Page/PageSectionContent';
import TagConnector from './TagConnector';
import Link from 'Components/Link/Link';
import styles from './Tags.css';
function Tags(props) {
const {
items,
...otherProps
} = props;
if (!items.length) {
return (
<div>No tags have been added yet. Add tags to link artists with delay profiles, restrictions, or notifications. Click <Link to='https://github.com/lidarr/Lidarr/wiki/Tags'>here</Link> to find out more about tags in Lidarr.</div>
);
}
return (
<FieldSet
legend="Tags"
>
<PageSectionContent
errorMessage="Unable to load Tags"
{...otherProps}
>
<div className={styles.tags}>
{
items.map((item) => {
return (
<TagConnector
key={item.id}
{...item}
/>
);
})
}
</div>
</PageSectionContent>
</FieldSet>
);
}
Tags.propTypes = {
items: PropTypes.arrayOf(PropTypes.object).isRequired
};
export default Tags;

View file

@ -0,0 +1,72 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { fetchTagDetails } from 'Store/Actions/tagActions';
import { fetchDelayProfiles, fetchNotifications, fetchRestrictions } from 'Store/Actions/settingsActions';
import Tags from './Tags';
function createMapStateToProps() {
return createSelector(
(state) => state.tags,
(tags) => {
const isFetching = tags.isFetching || tags.details.isFetching;
const error = tags.error || tags.details.error;
const isPopulated = tags.isPopulated && tags.details.isPopulated;
return {
...tags,
isFetching,
error,
isPopulated
};
}
);
}
const mapDispatchToProps = {
dispatchFetchTagDetails: fetchTagDetails,
dispatchFetchDelayProfiles: fetchDelayProfiles,
dispatchFetchNotifications: fetchNotifications,
dispatchFetchRestrictions: fetchRestrictions
};
class MetadatasConnector extends Component {
//
// Lifecycle
componentDidMount() {
const {
dispatchFetchTagDetails,
dispatchFetchDelayProfiles,
dispatchFetchNotifications,
dispatchFetchRestrictions
} = this.props;
dispatchFetchTagDetails();
dispatchFetchDelayProfiles();
dispatchFetchNotifications();
dispatchFetchRestrictions();
}
//
// Render
render() {
return (
<Tags
{...this.props}
/>
);
}
}
MetadatasConnector.propTypes = {
dispatchFetchTagDetails: PropTypes.func.isRequired,
dispatchFetchDelayProfiles: PropTypes.func.isRequired,
dispatchFetchNotifications: PropTypes.func.isRequired,
dispatchFetchRestrictions: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(MetadatasConnector);

View file

@ -82,9 +82,7 @@ class UISettings extends Component {
id="uiSettings"
{...otherProps}
>
<FieldSet
legend="Calendar"
>
<FieldSet legend="Calendar">
<FormGroup>
<FormLabel>First Day of Week</FormLabel>

View file

@ -1,16 +1,18 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createSettingsSectionSelector from 'Store/Selectors/createSettingsSectionSelector';
import { setUISettingsValue, saveUISettings, fetchUISettings } from 'Store/Actions/settingsActions';
import { clearPendingChanges } from 'Store/Actions/baseActions';
import connectSection from 'Store/connectSection';
import UISettings from './UISettings';
const SECTION = 'ui';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.advancedSettings,
createSettingsSectionSelector(),
createSettingsSectionSelector(SECTION),
(advancedSettings, sectionSettings) => {
return {
advancedSettings,
@ -37,7 +39,7 @@ class UISettingsConnector extends Component {
}
componentWillUnmount() {
this.props.clearPendingChanges({ section: this.props.section });
this.props.clearPendingChanges({ section: SECTION });
}
//
@ -66,17 +68,10 @@ class UISettingsConnector extends Component {
}
UISettingsConnector.propTypes = {
section: PropTypes.string.isRequired,
setUISettingsValue: PropTypes.func.isRequired,
saveUISettings: PropTypes.func.isRequired,
fetchUISettings: PropTypes.func.isRequired,
clearPendingChanges: PropTypes.func.isRequired
};
export default connectSection(
createMapStateToProps,
mapDispatchToProps,
undefined,
undefined,
{ section: 'settings.ui' }
)(UISettingsConnector);
export default connect(createMapStateToProps, mapDispatchToProps)(UISettingsConnector);