New: Make monitored flags clickable

This commit is contained in:
ta264 2020-08-26 22:38:48 +01:00 committed by Qstick
commit a35e773b78
12 changed files with 106 additions and 54 deletions

View file

@ -25,10 +25,6 @@ import AlbumStudioFooter from './AlbumStudioFooter';
import styles from './AlbumStudio.css'; import styles from './AlbumStudio.css';
const columns = [ const columns = [
{
name: 'monitored',
isVisible: true
},
{ {
name: 'status', name: 'status',
isVisible: true isVisible: true
@ -94,15 +90,15 @@ class AlbumStudio extends Component {
// nasty hack to fix react-virtualized jumping incorrectly // nasty hack to fix react-virtualized jumping incorrectly
// due to variable row heights // due to variable row heights
if (scrollIndex != null) { if (scrollIndex != null && scrollIndex > 0) {
if (jumpCount === 0) { if (jumpCount === 0) {
this.setState({ this.setState({
scrollIndex: scrollIndex + 1, scrollIndex: scrollIndex - 1,
jumpCount: 1 jumpCount: 1
}); });
} else if (jumpCount === 1) { } else if (jumpCount === 1) {
this.setState({ this.setState({
scrollIndex: scrollIndex - 1, scrollIndex: scrollIndex + 1,
jumpCount: 2 jumpCount: 2
}); });
} else { } else {

View file

@ -12,18 +12,13 @@
align-items: center; align-items: center;
} }
.status, .status {
.monitored {
composes: cell from '~Components/Table/Cells/TableRowCell.css'; composes: cell from '~Components/Table/Cells/TableRowCell.css';
padding: 0;
display: flex; display: flex;
align-items: center; align-items: center;
width: 20px; padding: 0;
} min-width: 60px;
.statusIcon {
width: 20px !important;
} }
.title { .title {

View file

@ -1,10 +1,8 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { icons } from 'Helpers/Props';
import Icon from 'Components/Icon';
import MonitorToggleButton from 'Components/MonitorToggleButton';
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 ArtistStatusCell from 'Artist/Index/Table/ArtistStatusCell';
import ArtistNameLink from 'Artist/ArtistNameLink'; import ArtistNameLink from 'Artist/ArtistNameLink';
import AlbumStudioAlbum from './AlbumStudioAlbum'; import AlbumStudioAlbum from './AlbumStudioAlbum';
import styles from './AlbumStudioRow.css'; import styles from './AlbumStudioRow.css';
@ -20,6 +18,7 @@ class AlbumStudioRow extends Component {
status, status,
foreignArtistId, foreignArtistId,
artistName, artistName,
artistType,
monitored, monitored,
albums, albums,
isSaving, isSaving,
@ -39,22 +38,15 @@ class AlbumStudioRow extends Component {
isDisabled={false} isDisabled={false}
/> />
<VirtualTableRowCell className={styles.monitored}> <ArtistStatusCell
<MonitorToggleButton className={styles.status}
artistType={artistType}
monitored={monitored} monitored={monitored}
size={14} status={status}
isSaving={isSaving} isSaving={isSaving}
onPress={onArtistMonitoredPress} onMonitoredPress={onArtistMonitoredPress}
component={VirtualTableRowCell}
/> />
</VirtualTableRowCell>
<VirtualTableRowCell className={styles.status}>
<Icon
className={styles.statusIcon}
name={status === 'ended' ? icons.ARTIST_ENDED : icons.ARTIST_CONTINUING}
title={status === 'ended' ? 'Ended' : 'Continuing'}
/>
</VirtualTableRowCell>
<VirtualTableRowCell className={styles.title}> <VirtualTableRowCell className={styles.title}>
<ArtistNameLink <ArtistNameLink
@ -86,6 +78,7 @@ AlbumStudioRow.propTypes = {
status: PropTypes.string.isRequired, status: PropTypes.string.isRequired,
foreignArtistId: PropTypes.string.isRequired, foreignArtistId: PropTypes.string.isRequired,
artistName: PropTypes.string.isRequired, artistName: PropTypes.string.isRequired,
artistType: PropTypes.string,
monitored: PropTypes.bool.isRequired, monitored: PropTypes.bool.isRequired,
albums: PropTypes.arrayOf(PropTypes.object).isRequired, albums: PropTypes.arrayOf(PropTypes.object).isRequired,
isSaving: PropTypes.bool.isRequired, isSaving: PropTypes.bool.isRequired,

View file

@ -1,8 +1,7 @@
.monitored,
.status { .status {
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css'; composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
width: 20px; flex: 0 0 60px;
padding: 0; padding: 0;
} }

View file

@ -234,6 +234,7 @@ class ArtistEditor extends Component {
key={item.id} key={item.id}
{...item} {...item}
columns={columns} columns={columns}
isSaving={isSaving}
isSelected={selectedState[item.id]} isSelected={selectedState[item.id]}
onSelectedChange={this.onSelectedChange} onSelectedChange={this.onSelectedChange}
/> />

View file

@ -37,7 +37,9 @@ class ArtistEditorRow extends Component {
path, path,
tags, tags,
columns, columns,
isSaving,
isSelected, isSelected,
onArtistMonitoredPress,
onSelectedChange onSelectedChange
} = this.props; } = this.props;
@ -53,6 +55,8 @@ class ArtistEditorRow extends Component {
artistType={artistType} artistType={artistType}
monitored={monitored} monitored={monitored}
status={status} status={status}
isSaving={isSaving}
onMonitoredPress={onArtistMonitoredPress}
/> />
<TableRowCell className={styles.title}> <TableRowCell className={styles.title}>
@ -109,7 +113,9 @@ ArtistEditorRow.propTypes = {
path: PropTypes.string.isRequired, path: PropTypes.string.isRequired,
tags: PropTypes.arrayOf(PropTypes.number).isRequired, tags: PropTypes.arrayOf(PropTypes.number).isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired, columns: PropTypes.arrayOf(PropTypes.object).isRequired,
isSaving: PropTypes.bool.isRequired,
isSelected: PropTypes.bool, isSelected: PropTypes.bool,
onArtistMonitoredPress: PropTypes.func.isRequired,
onSelectedChange: PropTypes.func.isRequired onSelectedChange: PropTypes.func.isRequired
}; };

View file

@ -1,9 +1,10 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React 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 createMetadataProfileSelector from 'Store/Selectors/createMetadataProfileSelector'; import createMetadataProfileSelector from 'Store/Selectors/createMetadataProfileSelector';
import createQualityProfileSelector from 'Store/Selectors/createQualityProfileSelector'; import createQualityProfileSelector from 'Store/Selectors/createQualityProfileSelector';
import { toggleArtistMonitored } from 'Store/Actions/artistActions';
import ArtistEditorRow from './ArtistEditorRow'; import ArtistEditorRow from './ArtistEditorRow';
function createMapStateToProps() { function createMapStateToProps() {
@ -19,16 +20,42 @@ function createMapStateToProps() {
); );
} }
function ArtistEditorRowConnector(props) { const mapDispatchToProps = {
toggleArtistMonitored
};
class ArtistEditorRowConnector extends Component {
//
// Listeners
onArtistMonitoredPress = () => {
const {
id,
monitored
} = this.props;
this.props.toggleArtistMonitored({
artistId: id,
monitored: !monitored
});
}
render() {
return ( return (
<ArtistEditorRow <ArtistEditorRow
{...props} {...this.props}
onArtistMonitoredPress={this.onArtistMonitoredPress}
/> />
); );
} }
}
ArtistEditorRowConnector.propTypes = { ArtistEditorRowConnector.propTypes = {
qualityProfileId: PropTypes.number.isRequired id: PropTypes.number.isRequired,
monitored: PropTypes.bool.isRequired,
qualityProfileId: PropTypes.number.isRequired,
toggleArtistMonitored: PropTypes.func.isRequired
}; };
export default connect(createMapStateToProps)(ArtistEditorRowConnector); export default connect(createMapStateToProps, mapDispatchToProps)(ArtistEditorRowConnector);

View file

@ -8,6 +8,7 @@ import createArtistSelector from 'Store/Selectors/createArtistSelector';
import createExecutingCommandsSelector from 'Store/Selectors/createExecutingCommandsSelector'; import createExecutingCommandsSelector from 'Store/Selectors/createExecutingCommandsSelector';
import createArtistQualityProfileSelector from 'Store/Selectors/createArtistQualityProfileSelector'; import createArtistQualityProfileSelector from 'Store/Selectors/createArtistQualityProfileSelector';
import createArtistMetadataProfileSelector from 'Store/Selectors/createArtistMetadataProfileSelector'; import createArtistMetadataProfileSelector from 'Store/Selectors/createArtistMetadataProfileSelector';
import { toggleArtistMonitored } from 'Store/Actions/artistActions';
import { executeCommand } from 'Store/Actions/commandActions'; import { executeCommand } from 'Store/Actions/commandActions';
import * as commandNames from 'Commands/commandNames'; import * as commandNames from 'Commands/commandNames';
@ -85,7 +86,8 @@ function createMapStateToProps() {
} }
const mapDispatchToProps = { const mapDispatchToProps = {
dispatchExecuteCommand: executeCommand dispatchExecuteCommand: executeCommand,
toggleArtistMonitored
}; };
class ArtistIndexItemConnector extends Component { class ArtistIndexItemConnector extends Component {
@ -107,6 +109,13 @@ class ArtistIndexItemConnector extends Component {
}); });
} }
onMonitoredPress = () => {
this.props.toggleArtistMonitored({
artistId: this.props.id,
monitored: !this.props.monitored
});
}
// //
// Render // Render
@ -127,6 +136,7 @@ class ArtistIndexItemConnector extends Component {
id={id} id={id}
onRefreshArtistPress={this.onRefreshArtistPress} onRefreshArtistPress={this.onRefreshArtistPress}
onSearchPress={this.onSearchPress} onSearchPress={this.onSearchPress}
onMonitoredPress={this.onMonitoredPress}
/> />
); );
} }
@ -134,8 +144,10 @@ class ArtistIndexItemConnector extends Component {
ArtistIndexItemConnector.propTypes = { ArtistIndexItemConnector.propTypes = {
id: PropTypes.number, id: PropTypes.number,
monitored: PropTypes.bool.isRequired,
component: PropTypes.elementType.isRequired, component: PropTypes.elementType.isRequired,
dispatchExecuteCommand: PropTypes.func.isRequired dispatchExecuteCommand: PropTypes.func.isRequired,
toggleArtistMonitored: PropTypes.func.isRequired
}; };
export default connect(createMapStateToProps, mapDispatchToProps)(ArtistIndexItemConnector); export default connect(createMapStateToProps, mapDispatchToProps)(ArtistIndexItemConnector);

View file

@ -94,13 +94,15 @@ class ArtistIndexRow extends Component {
path, path,
tags, tags,
images, images,
isSaving,
showBanners, showBanners,
showSearchAction, showSearchAction,
columns, columns,
isRefreshingArtist, isRefreshingArtist,
isSearchingArtist, isSearchingArtist,
onRefreshArtistPress, onRefreshArtistPress,
onSearchPress onSearchPress,
onMonitoredPress
} = this.props; } = this.props;
const { const {
@ -138,6 +140,8 @@ class ArtistIndexRow extends Component {
artistType={artistType} artistType={artistType}
monitored={monitored} monitored={monitored}
status={status} status={status}
isSaving={isSaving}
onMonitoredPress={onMonitoredPress}
component={VirtualTableRowCell} component={VirtualTableRowCell}
/> />
); );
@ -457,13 +461,15 @@ ArtistIndexRow.propTypes = {
ratings: PropTypes.object.isRequired, ratings: PropTypes.object.isRequired,
tags: PropTypes.arrayOf(PropTypes.number).isRequired, tags: PropTypes.arrayOf(PropTypes.number).isRequired,
images: PropTypes.arrayOf(PropTypes.object).isRequired, images: PropTypes.arrayOf(PropTypes.object).isRequired,
isSaving: PropTypes.bool.isRequired,
showBanners: PropTypes.bool.isRequired, showBanners: PropTypes.bool.isRequired,
showSearchAction: PropTypes.bool.isRequired, showSearchAction: PropTypes.bool.isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired, columns: PropTypes.arrayOf(PropTypes.object).isRequired,
isRefreshingArtist: PropTypes.bool.isRequired, isRefreshingArtist: PropTypes.bool.isRequired,
isSearchingArtist: PropTypes.bool.isRequired, isSearchingArtist: PropTypes.bool.isRequired,
onRefreshArtistPress: PropTypes.func.isRequired, onRefreshArtistPress: PropTypes.func.isRequired,
onSearchPress: PropTypes.func.isRequired onSearchPress: PropTypes.func.isRequired,
onMonitoredPress: PropTypes.func.isRequired
}; };
ArtistIndexRow.defaultProps = { ArtistIndexRow.defaultProps = {

View file

@ -47,7 +47,8 @@ class ArtistIndexTable extends Component {
const { const {
items, items,
columns, columns,
showBanners showBanners,
isSaving
} = this.props; } = this.props;
const artist = items[rowIndex]; const artist = items[rowIndex];
@ -66,6 +67,7 @@ class ArtistIndexTable extends Component {
qualityProfileId={artist.qualityProfileId} qualityProfileId={artist.qualityProfileId}
metadataProfileId={artist.metadataProfileId} metadataProfileId={artist.metadataProfileId}
showBanners={showBanners} showBanners={showBanners}
isSaving={isSaving}
/> />
</VirtualTableRow> </VirtualTableRow>
); );
@ -121,6 +123,7 @@ ArtistIndexTable.propTypes = {
sortKey: PropTypes.string, sortKey: PropTypes.string,
sortDirection: PropTypes.oneOf(sortDirections.all), sortDirection: PropTypes.oneOf(sortDirections.all),
showBanners: PropTypes.bool.isRequired, showBanners: PropTypes.bool.isRequired,
isSaving: PropTypes.bool.isRequired,
jumpToCharacter: PropTypes.string, jumpToCharacter: PropTypes.string,
scrollTop: PropTypes.number, scrollTop: PropTypes.number,
scroller: PropTypes.instanceOf(Element).isRequired, scroller: PropTypes.instanceOf(Element).isRequired,

View file

@ -4,6 +4,13 @@
width: 60px; width: 60px;
} }
.monitorToggle {
composes: toggleButton from '~Components/MonitorToggleButton.css';
margin: 0;
width: 20px !important;
}
.statusIcon { .statusIcon {
width: 20px !important; width: 20px !important;
} }

View file

@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import Icon from 'Components/Icon'; import Icon from 'Components/Icon';
import MonitorToggleButton from 'Components/MonitorToggleButton';
import VirtualTableRowCell from 'Components/Table/Cells/TableRowCell'; import VirtualTableRowCell from 'Components/Table/Cells/TableRowCell';
import styles from './ArtistStatusCell.css'; import styles from './ArtistStatusCell.css';
@ -11,6 +12,8 @@ function ArtistStatusCell(props) {
artistType, artistType,
monitored, monitored,
status, status,
isSaving,
onMonitoredPress,
component: Component, component: Component,
...otherProps ...otherProps
} = props; } = props;
@ -22,10 +25,12 @@ function ArtistStatusCell(props) {
className={className} className={className}
{...otherProps} {...otherProps}
> >
<Icon <MonitorToggleButton
className={styles.statusIcon} className={styles.monitorToggle}
name={monitored ? icons.MONITORED : icons.UNMONITORED} monitored={monitored}
title={monitored ? 'Artist is monitored' : 'Artist is unmonitored'} size={14}
isSaving={isSaving}
onPress={onMonitoredPress}
/> />
<Icon <Icon
@ -42,6 +47,8 @@ ArtistStatusCell.propTypes = {
artistType: PropTypes.string, artistType: PropTypes.string,
monitored: PropTypes.bool.isRequired, monitored: PropTypes.bool.isRequired,
status: PropTypes.string.isRequired, status: PropTypes.string.isRequired,
isSaving: PropTypes.bool.isRequired,
onMonitoredPress: PropTypes.func.isRequired,
component: PropTypes.elementType component: PropTypes.elementType
}; };