mirror of https://github.com/lidarr/Lidarr
Fixed: UI Selector, Rendering Improvements
This commit is contained in:
parent
38723d0753
commit
7cf39e6a30
|
@ -21,7 +21,7 @@ import ArtistIndexBannerOptionsModal from './Banners/Options/ArtistIndexBannerOp
|
|||
import ArtistIndexBannersConnector from './Banners/ArtistIndexBannersConnector';
|
||||
import ArtistIndexOverviewOptionsModal from './Overview/Options/ArtistIndexOverviewOptionsModal';
|
||||
import ArtistIndexOverviewsConnector from './Overview/ArtistIndexOverviewsConnector';
|
||||
import ArtistIndexFooter from './ArtistIndexFooter';
|
||||
import ArtistIndexFooterConnector from './ArtistIndexFooterConnector';
|
||||
import ArtistIndexFilterMenu from './Menus/ArtistIndexFilterMenu';
|
||||
import ArtistIndexSortMenu from './Menus/ArtistIndexSortMenu';
|
||||
import ArtistIndexViewMenu from './Menus/ArtistIndexViewMenu';
|
||||
|
@ -358,9 +358,7 @@ class ArtistIndex extends Component {
|
|||
{...otherProps}
|
||||
/>
|
||||
|
||||
<ArtistIndexFooter
|
||||
artist={items}
|
||||
/>
|
||||
<ArtistIndexFooterConnector />
|
||||
</div>
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
|||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
||||
import createArtistClientSideCollectionItemsSelector from 'Store/Selectors/createArtistClientSideCollectionItemsSelector';
|
||||
import dimensions from 'Styles/Variables/dimensions';
|
||||
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
||||
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
||||
|
@ -46,7 +46,7 @@ function getScrollTop(view, scrollTop, isSmallScreen) {
|
|||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createClientSideCollectionSelector('artist', 'artistIndex'),
|
||||
createArtistClientSideCollectionItemsSelector('artistIndex'),
|
||||
createCommandExecutingSelector(commandNames.REFRESH_ARTIST),
|
||||
createCommandExecutingSelector(commandNames.RSS_SYNC),
|
||||
createDimensionsSelector(),
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import createDeepEqualSelector from 'Store/Selectors/createDeepEqualSelector';
|
||||
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
||||
import ArtistIndexFooter from './ArtistIndexFooter';
|
||||
|
||||
function createUnoptimizedSelector() {
|
||||
return createSelector(
|
||||
createClientSideCollectionSelector('artist', 'artistIndex'),
|
||||
(artist) => {
|
||||
return artist.items.map((s) => {
|
||||
const {
|
||||
monitored,
|
||||
status,
|
||||
statistics
|
||||
} = s;
|
||||
|
||||
return {
|
||||
monitored,
|
||||
status,
|
||||
statistics
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function createArtistSelector() {
|
||||
return createDeepEqualSelector(
|
||||
createUnoptimizedSelector(),
|
||||
(artist) => artist
|
||||
);
|
||||
}
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createArtistSelector(),
|
||||
(artist) => {
|
||||
return {
|
||||
artist
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(createMapStateToProps)(ArtistIndexFooter);
|
|
@ -6,9 +6,9 @@ import { connect } from 'react-redux';
|
|||
import { createSelector } from 'reselect';
|
||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
||||
import createExecutingCommandsSelector from 'Store/Selectors/createExecutingCommandsSelector';
|
||||
import createQualityProfileSelector from 'Store/Selectors/createQualityProfileSelector';
|
||||
import createLanguageProfileSelector from 'Store/Selectors/createLanguageProfileSelector';
|
||||
import createMetadataProfileSelector from 'Store/Selectors/createMetadataProfileSelector';
|
||||
import createArtistQualityProfileSelector from 'Store/Selectors/createArtistQualityProfileSelector';
|
||||
import createArtistLanguageProfileSelector from 'Store/Selectors/createArtistLanguageProfileSelector';
|
||||
import createArtistMetadataProfileSelector from 'Store/Selectors/createArtistMetadataProfileSelector';
|
||||
import { executeCommand } from 'Store/Actions/commandActions';
|
||||
import * as commandNames from 'Commands/commandNames';
|
||||
|
||||
|
@ -35,9 +35,9 @@ function selectShowSearchAction() {
|
|||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createArtistSelector(),
|
||||
createQualityProfileSelector(),
|
||||
createLanguageProfileSelector(),
|
||||
createMetadataProfileSelector(),
|
||||
createArtistQualityProfileSelector(),
|
||||
createArtistLanguageProfileSelector(),
|
||||
createArtistMetadataProfileSelector(),
|
||||
selectShowSearchAction(),
|
||||
createExecutingCommandsSelector(),
|
||||
(
|
||||
|
@ -89,7 +89,7 @@ function createMapStateToProps() {
|
|||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
executeCommand
|
||||
dispatchExecuteCommand: executeCommand
|
||||
};
|
||||
|
||||
class ArtistIndexItemConnector extends Component {
|
||||
|
@ -98,14 +98,14 @@ class ArtistIndexItemConnector extends Component {
|
|||
// Listeners
|
||||
|
||||
onRefreshArtistPress = () => {
|
||||
this.props.executeCommand({
|
||||
this.props.dispatchExecuteCommand({
|
||||
name: commandNames.REFRESH_ARTIST,
|
||||
artistId: this.props.id
|
||||
});
|
||||
}
|
||||
|
||||
onSearchPress = () => {
|
||||
this.props.executeCommand({
|
||||
this.props.dispatchExecuteCommand({
|
||||
name: commandNames.ARTIST_SEARCH,
|
||||
artistId: this.props.id
|
||||
});
|
||||
|
@ -139,7 +139,7 @@ class ArtistIndexItemConnector extends Component {
|
|||
ArtistIndexItemConnector.propTypes = {
|
||||
id: PropTypes.number,
|
||||
component: PropTypes.func.isRequired,
|
||||
executeCommand: PropTypes.func.isRequired
|
||||
dispatchExecuteCommand: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(ArtistIndexItemConnector);
|
||||
|
|
|
@ -13,7 +13,8 @@ function ErrorPage(props) {
|
|||
qualityProfilesError,
|
||||
languageProfilesError,
|
||||
metadataProfilesError,
|
||||
uiSettingsError
|
||||
uiSettingsError,
|
||||
systemStatusError
|
||||
} = props;
|
||||
|
||||
let errorMessage = 'Failed to load Lidarr';
|
||||
|
@ -34,6 +35,8 @@ function ErrorPage(props) {
|
|||
errorMessage = getErrorMessage(metadataProfilesError, 'Failed to load metadata profiles from API');
|
||||
} else if (uiSettingsError) {
|
||||
errorMessage = getErrorMessage(uiSettingsError, 'Failed to load UI settings from API');
|
||||
} else if (systemStatusError) {
|
||||
errorMessage = getErrorMessage(uiSettingsError, 'Failed to load system status from API');
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -58,7 +61,8 @@ ErrorPage.propTypes = {
|
|||
qualityProfilesError: PropTypes.object,
|
||||
languageProfilesError: PropTypes.object,
|
||||
metadataProfilesError: PropTypes.object,
|
||||
uiSettingsError: PropTypes.object
|
||||
uiSettingsError: PropTypes.object,
|
||||
systemStatusError: PropTypes.object
|
||||
};
|
||||
|
||||
export default ErrorPage;
|
||||
|
|
|
@ -27,69 +27,124 @@ function testLocalStorage() {
|
|||
}
|
||||
}
|
||||
|
||||
const selectAppProps = createSelector(
|
||||
(state) => state.app.isSidebarVisible,
|
||||
(state) => state.app.version,
|
||||
(state) => state.app.isUpdated,
|
||||
(state) => state.app.isDisconnected,
|
||||
(isSidebarVisible, version, isUpdated, isDisconnected) => {
|
||||
return {
|
||||
isSidebarVisible,
|
||||
version,
|
||||
isUpdated,
|
||||
isDisconnected
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
const selectIsPopulated = createSelector(
|
||||
(state) => state.artist.isPopulated,
|
||||
(state) => state.customFilters.isPopulated,
|
||||
(state) => state.tags.isPopulated,
|
||||
(state) => state.settings.ui.isPopulated,
|
||||
(state) => state.settings.qualityProfiles.isPopulated,
|
||||
(state) => state.settings.languageProfiles.isPopulated,
|
||||
(state) => state.settings.metadataProfiles.isPopulated,
|
||||
(state) => state.settings.importLists.isPopulated,
|
||||
(state) => state.system.status.isPopulated,
|
||||
(
|
||||
artistIsPopulated,
|
||||
customFiltersIsPopulated,
|
||||
tagsIsPopulated,
|
||||
uiSettingsIsPopulated,
|
||||
qualityProfilesIsPopulated,
|
||||
languageProfilesIsPopulated,
|
||||
metadataProfilesIsPopulated,
|
||||
importListsIsPopulated,
|
||||
systemStatusIsPopulated
|
||||
) => {
|
||||
return (
|
||||
artistIsPopulated &&
|
||||
customFiltersIsPopulated &&
|
||||
tagsIsPopulated &&
|
||||
uiSettingsIsPopulated &&
|
||||
qualityProfilesIsPopulated &&
|
||||
languageProfilesIsPopulated &&
|
||||
metadataProfilesIsPopulated &&
|
||||
importListsIsPopulated &&
|
||||
systemStatusIsPopulated
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const selectErrors = createSelector(
|
||||
(state) => state.artist.error,
|
||||
(state) => state.customFilters.error,
|
||||
(state) => state.tags.error,
|
||||
(state) => state.settings.ui.error,
|
||||
(state) => state.settings.qualityProfiles.error,
|
||||
(state) => state.settings.languageProfiles.error,
|
||||
(state) => state.settings.metadataProfiles.error,
|
||||
(state) => state.settings.importLists.error,
|
||||
(state) => state.system.status.error,
|
||||
(
|
||||
artistError,
|
||||
customFiltersError,
|
||||
tagsError,
|
||||
uiSettingsError,
|
||||
qualityProfilesError,
|
||||
languageProfilesError,
|
||||
metadataProfilesError,
|
||||
importListsError,
|
||||
systemStatusError
|
||||
) => {
|
||||
const hasError = !!(
|
||||
artistError ||
|
||||
customFiltersError ||
|
||||
tagsError ||
|
||||
uiSettingsError ||
|
||||
qualityProfilesError ||
|
||||
languageProfilesError ||
|
||||
metadataProfilesError ||
|
||||
importListsError ||
|
||||
systemStatusError
|
||||
);
|
||||
|
||||
return {
|
||||
hasError,
|
||||
artistError,
|
||||
customFiltersError,
|
||||
tagsError,
|
||||
uiSettingsError,
|
||||
qualityProfilesError,
|
||||
languageProfilesError,
|
||||
metadataProfilesError,
|
||||
importListsError,
|
||||
systemStatusError
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.artist,
|
||||
(state) => state.customFilters,
|
||||
(state) => state.tags,
|
||||
(state) => state.settings.ui,
|
||||
(state) => state.settings.qualityProfiles,
|
||||
(state) => state.settings.languageProfiles,
|
||||
(state) => state.settings.metadataProfiles,
|
||||
(state) => state.settings.importLists,
|
||||
(state) => state.app,
|
||||
(state) => state.settings.ui.item.enableColorImpairedMode,
|
||||
selectIsPopulated,
|
||||
selectErrors,
|
||||
selectAppProps,
|
||||
createDimensionsSelector(),
|
||||
(
|
||||
artist,
|
||||
customFilters,
|
||||
tags,
|
||||
uiSettings,
|
||||
qualityProfiles,
|
||||
languageProfiles,
|
||||
metadataProfiles,
|
||||
importLists,
|
||||
enableColorImpairedMode,
|
||||
isPopulated,
|
||||
errors,
|
||||
app,
|
||||
dimensions
|
||||
) => {
|
||||
const isPopulated = (
|
||||
artist.isPopulated &&
|
||||
customFilters.isPopulated &&
|
||||
tags.isPopulated &&
|
||||
qualityProfiles.isPopulated &&
|
||||
languageProfiles.isPopulated &&
|
||||
metadataProfiles.isPopulated &&
|
||||
importLists.isPopulated &&
|
||||
uiSettings.isPopulated
|
||||
);
|
||||
|
||||
const hasError = !!(
|
||||
artist.error ||
|
||||
customFilters.error ||
|
||||
tags.error ||
|
||||
qualityProfiles.error ||
|
||||
languageProfiles.error ||
|
||||
metadataProfiles.error ||
|
||||
importLists.error ||
|
||||
uiSettings.error
|
||||
);
|
||||
|
||||
return {
|
||||
...app,
|
||||
...errors,
|
||||
isPopulated,
|
||||
hasError,
|
||||
artistError: artist.error,
|
||||
customFiltersError: tags.error,
|
||||
tagsError: tags.error,
|
||||
qualityProfilesError: qualityProfiles.error,
|
||||
languageProfilesError: languageProfiles.error,
|
||||
metadataProfilesError: metadataProfiles.error,
|
||||
importListsError: importLists.error,
|
||||
uiSettingsError: uiSettings.error,
|
||||
isSmallScreen: dimensions.isSmallScreen,
|
||||
isSidebarVisible: app.isSidebarVisible,
|
||||
enableColorImpairedMode: uiSettings.item.enableColorImpairedMode,
|
||||
version: app.version,
|
||||
isUpdated: app.isUpdated,
|
||||
isDisconnected: app.isDisconnected
|
||||
enableColorImpairedMode
|
||||
};
|
||||
}
|
||||
);
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import { createSelector } from 'reselect';
|
||||
import createDeepEqualSelector from './createDeepEqualSelector';
|
||||
import createClientSideCollectionSelector from './createClientSideCollectionSelector';
|
||||
|
||||
function createUnoptimizedSelector(uiSection) {
|
||||
return createSelector(
|
||||
createClientSideCollectionSelector('artist', uiSection),
|
||||
(artist) => {
|
||||
const items = artist.items.map((s) => {
|
||||
const {
|
||||
id,
|
||||
sortName
|
||||
} = s;
|
||||
|
||||
return {
|
||||
id,
|
||||
sortName
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
...artist,
|
||||
items
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function createArtistClientSideCollectionItemsSelector(uiSection) {
|
||||
return createDeepEqualSelector(
|
||||
createUnoptimizedSelector(uiSection),
|
||||
(artist) => artist
|
||||
);
|
||||
}
|
||||
|
||||
export default createArtistClientSideCollectionItemsSelector;
|
|
@ -0,0 +1,16 @@
|
|||
import { createSelector } from 'reselect';
|
||||
import createArtistSelector from './createArtistSelector';
|
||||
|
||||
function createArtistLanguageProfileSelector() {
|
||||
return createSelector(
|
||||
(state) => state.settings.languageProfiles.items,
|
||||
createArtistSelector(),
|
||||
(languageProfiles, artist) => {
|
||||
return languageProfiles.find((profile) => {
|
||||
return profile.id === artist.languageProfileId;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default createArtistLanguageProfileSelector;
|
|
@ -0,0 +1,16 @@
|
|||
import { createSelector } from 'reselect';
|
||||
import createArtistSelector from './createArtistSelector';
|
||||
|
||||
function createArtistMetadataProfileSelector() {
|
||||
return createSelector(
|
||||
(state) => state.settings.metadataProfiles.items,
|
||||
createArtistSelector(),
|
||||
(metadataProfiles, artist) => {
|
||||
return metadataProfiles.find((profile) => {
|
||||
return profile.id === artist.metadataProfileId;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default createArtistMetadataProfileSelector;
|
|
@ -0,0 +1,16 @@
|
|||
import { createSelector } from 'reselect';
|
||||
import createArtistSelector from './createArtistSelector';
|
||||
|
||||
function createArtistQualityProfileSelector() {
|
||||
return createSelector(
|
||||
(state) => state.settings.qualityProfiles.items,
|
||||
createArtistSelector(),
|
||||
(qualityProfiles, artist) => {
|
||||
return qualityProfiles.find((profile) => {
|
||||
return profile.id === artist.qualityProfileId;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default createArtistQualityProfileSelector;
|
|
@ -0,0 +1,9 @@
|
|||
import { createSelectorCreator, defaultMemoize } from 'reselect';
|
||||
import _ from 'lodash';
|
||||
|
||||
const createDeepEqualSelector = createSelectorCreator(
|
||||
defaultMemoize,
|
||||
_.isEqual
|
||||
);
|
||||
|
||||
export default createDeepEqualSelector;
|
|
@ -1,4 +1,3 @@
|
|||
import _ from 'lodash';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
function createLanguageProfileSelector() {
|
||||
|
@ -6,7 +5,9 @@ function createLanguageProfileSelector() {
|
|||
(state, { languageProfileId }) => languageProfileId,
|
||||
(state) => state.settings.languageProfiles.items,
|
||||
(languageProfileId, languageProfiles) => {
|
||||
return _.find(languageProfiles, { id: languageProfileId });
|
||||
return languageProfiles.find((profile) => {
|
||||
return profile.id === languageProfileId;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import _ from 'lodash';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
function createMetadataProfileSelector() {
|
||||
|
@ -6,7 +5,9 @@ function createMetadataProfileSelector() {
|
|||
(state, { metadataProfileId }) => metadataProfileId,
|
||||
(state) => state.settings.metadataProfiles.items,
|
||||
(metadataProfileId, metadataProfiles) => {
|
||||
return _.find(metadataProfiles, { id: metadataProfileId });
|
||||
return metadataProfiles.find((profile) => {
|
||||
return profile.id === metadataProfileId;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import _ from 'lodash';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
function createQualityProfileSelector() {
|
||||
|
@ -6,7 +5,9 @@ function createQualityProfileSelector() {
|
|||
(state, { qualityProfileId }) => qualityProfileId,
|
||||
(state) => state.settings.qualityProfiles.items,
|
||||
(qualityProfileId, qualityProfiles) => {
|
||||
return _.find(qualityProfiles, { id: qualityProfileId });
|
||||
return qualityProfiles.find((profile) => {
|
||||
return profile.id === qualityProfileId;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue