Mass Editor size and options

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
test-rebase
Qstick 4 years ago committed by nitsua
parent cb07186970
commit ac4a82abf4

@ -6,10 +6,13 @@ import FilterMenu from 'Components/Menu/FilterMenu';
import PageContent from 'Components/Page/PageContent';
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import { align, sortDirections } from 'Helpers/Props';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import { align, icons, sortDirections } from 'Helpers/Props';
import getErrorMessage from 'Utilities/Object/getErrorMessage';
import getSelectedIds from 'Utilities/Table/getSelectedIds';
import selectAll from 'Utilities/Table/selectAll';
@ -73,9 +76,14 @@ class AuthorEditor extends Component {
allUnselected: false,
lastToggled: null,
selectedState: {},
<<<<<<< HEAD:frontend/src/Author/Editor/AuthorEditor.js
isOrganizingAuthorModalOpen: false,
isRetaggingAuthorModalOpen: false,
columns: getColumns(props.showMetadataProfile)
=======
isOrganizingArtistModalOpen: false,
isRetaggingArtistModalOpen: false
>>>>>>> Mass Editor size and options:frontend/src/Artist/Editor/ArtistEditor.js
};
}
@ -155,6 +163,7 @@ class AuthorEditor extends Component {
error,
totalItems,
items,
columns,
selectedFilterKey,
filters,
customFilters,
@ -164,9 +173,15 @@ class AuthorEditor extends Component {
saveError,
isDeleting,
deleteError,
<<<<<<< HEAD:frontend/src/Author/Editor/AuthorEditor.js
isOrganizingAuthor,
isRetaggingAuthor,
showMetadataProfile,
=======
isOrganizingArtist,
isRetaggingArtist,
onTableOptionChange,
>>>>>>> Mass Editor size and options:frontend/src/Artist/Editor/ArtistEditor.js
onSortPress,
onFilterSelect
} = this.props;
@ -174,8 +189,7 @@ class AuthorEditor extends Component {
const {
allSelected,
allUnselected,
selectedState,
columns
selectedState
} = this.state;
const selectedAuthorIds = this.getSelectedIds();
@ -185,6 +199,18 @@ class AuthorEditor extends Component {
<PageToolbar>
<PageToolbarSection />
<PageToolbarSection alignContent={align.RIGHT}>
<TableOptionsModalWrapper
columns={columns}
onTableOptionChange={onTableOptionChange}
>
<PageToolbarButton
label="Options"
iconName={icons.TABLE}
/>
</TableOptionsModalWrapper>
<PageToolbarSeparator />
<FilterMenu
alignMenu={align.RIGHT}
selectedFilterKey={selectedFilterKey}
@ -252,9 +278,16 @@ class AuthorEditor extends Component {
saveError={saveError}
isDeleting={isDeleting}
deleteError={deleteError}
<<<<<<< HEAD:frontend/src/Author/Editor/AuthorEditor.js
isOrganizingAuthor={isOrganizingAuthor}
isRetaggingAuthor={isRetaggingAuthor}
showMetadataProfile={showMetadataProfile}
=======
isOrganizingArtist={isOrganizingArtist}
isRetaggingArtist={isRetaggingArtist}
columns={columns}
showMetadataProfile={columns.find((column) => column.name === 'metadataProfileId').isVisible}
>>>>>>> Mass Editor size and options:frontend/src/Artist/Editor/ArtistEditor.js
onSaveSelected={this.onSaveSelected}
onOrganizeAuthorPress={this.onOrganizeAuthorPress}
onRetagAuthorPress={this.onRetagAuthorPress}
@ -283,6 +316,7 @@ AuthorEditor.propTypes = {
error: PropTypes.object,
totalItems: PropTypes.number.isRequired,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
sortKey: PropTypes.string,
sortDirection: PropTypes.oneOf(sortDirections.all),
selectedFilterKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
@ -292,9 +326,15 @@ AuthorEditor.propTypes = {
saveError: PropTypes.object,
isDeleting: PropTypes.bool.isRequired,
deleteError: PropTypes.object,
<<<<<<< HEAD:frontend/src/Author/Editor/AuthorEditor.js
isOrganizingAuthor: PropTypes.bool.isRequired,
isRetaggingAuthor: PropTypes.bool.isRequired,
showMetadataProfile: PropTypes.bool.isRequired,
=======
isOrganizingArtist: PropTypes.bool.isRequired,
isRetaggingArtist: PropTypes.bool.isRequired,
onTableOptionChange: PropTypes.func.isRequired,
>>>>>>> Mass Editor size and options:frontend/src/Artist/Editor/ArtistEditor.js
onSortPress: PropTypes.func.isRequired,
onFilterSelect: PropTypes.func.isRequired,
onSaveSelected: PropTypes.func.isRequired

@ -3,7 +3,7 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import * as commandNames from 'Commands/commandNames';
import { saveAuthorEditor, setAuthorEditorFilter, setAuthorEditorSort } from 'Store/Actions/authorEditorActions';
import { saveAuthorEditor, setAuthorEditorFilter, setAuthorEditorSort, setAuthorEditorTableOption } from 'Store/Actions/authorEditorActions';
import { executeCommand } from 'Store/Actions/commandActions';
import { fetchRootFolders } from 'Store/Actions/settingsActions';
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
@ -12,15 +12,13 @@ import AuthorEditor from './AuthorEditor';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.metadataProfiles,
createClientSideCollectionSelector('authors', 'authorEditor'),
createCommandExecutingSelector(commandNames.RENAME_AUTHOR),
createCommandExecutingSelector(commandNames.RETAG_AUTHOR),
(metadataProfiles, author, isOrganizingAuthor, isRetaggingAuthor) => {
(author, isOrganizingAuthor, isRetaggingAuthor) => {
return {
isOrganizingAuthor,
isRetaggingAuthor,
showMetadataProfile: metadataProfiles.items.length > 1,
...author
};
}
@ -30,6 +28,7 @@ function createMapStateToProps() {
const mapDispatchToProps = {
dispatchSetAuthorEditorSort: setAuthorEditorSort,
dispatchSetAuthorEditorFilter: setAuthorEditorFilter,
dispatchSetAuthorEditorTableOption: setAuthorEditorTableOption,
dispatchSaveAuthorEditor: saveAuthorEditor,
dispatchFetchRootFolders: fetchRootFolders,
dispatchExecuteCommand: executeCommand
@ -55,6 +54,10 @@ class AuthorEditorConnector extends Component {
this.props.dispatchSetAuthorEditorFilter({ selectedFilterKey });
}
onTableOptionChange = (payload) => {
this.props.dispatchSetArtistEditorTableOption(payload);
}
onSaveSelected = (payload) => {
this.props.dispatchSaveAuthorEditor(payload);
}
@ -76,14 +79,16 @@ class AuthorEditorConnector extends Component {
onSortPress={this.onSortPress}
onFilterSelect={this.onFilterSelect}
onSaveSelected={this.onSaveSelected}
onTableOptionChange={this.onTableOptionChange}
/>
);
}
}
AuthorEditorConnector.propTypes = {
ArtistEditorConnector.propTypes = {
dispatchSetAuthorEditorSort: PropTypes.func.isRequired,
dispatchSetAuthorEditorFilter: PropTypes.func.isRequired,
dispatchSetAuthorEditorTableOption: PropTypes.func.isRequired,
dispatchSaveAuthorEditor: PropTypes.func.isRequired,
dispatchFetchRootFolders: PropTypes.func.isRequired,
dispatchExecuteCommand: PropTypes.func.isRequired

@ -138,7 +138,7 @@ class AuthorEditorFooter extends Component {
isDeleting,
isOrganizingAuthor,
isRetaggingAuthor,
showMetadataProfile,
columns,
onOrganizeAuthorPress,
onRetagAuthorPress
} = this.props;
@ -178,56 +178,110 @@ class AuthorEditorFooter extends Component {
/>
</div>
<div className={styles.inputContainer}>
<AuthorEditorFooterLabel
label="Quality Profile"
isSaving={isSaving && qualityProfileId !== NO_CHANGE}
/>
<QualityProfileSelectInputConnector
name="qualityProfileId"
value={qualityProfileId}
includeNoChange={true}
isDisabled={!selectedCount}
onChange={this.onInputChange}
/>
</div>
{
showMetadataProfile &&
<div className={styles.inputContainer}>
<AuthorEditorFooterLabel
label="Metadata Profile"
isSaving={isSaving && metadataProfileId !== NO_CHANGE}
/>
<MetadataProfileSelectInputConnector
name="metadataProfileId"
value={metadataProfileId}
includeNoChange={true}
includeNone={true}
isDisabled={!selectedCount}
onChange={this.onInputChange}
/>
</div>
columns.map((column) => {
const {
name,
isVisible
} = column;
if (!isVisible) {
return null;
}
if (name === 'qualityProfileId') {
return (
<div
key={name}
className={styles.inputContainer}
>
<AuthorEditorFooterLabel
label="Quality Profile"
isSaving={isSaving && qualityProfileId !== NO_CHANGE}
/>
<QualityProfileSelectInputConnector
name="qualityProfileId"
value={qualityProfileId}
includeNoChange={true}
isDisabled={!selectedCount}
onChange={this.onInputChange}
/>
</div>
);
}
if (name === 'metadataProfileId') {
return (
<div
key={name}
className={styles.inputContainer}
>
<AuthorEditorFooterLabel
label="Metadata Profile"
isSaving={isSaving && metadataProfileId !== NO_CHANGE}
/>
<MetadataProfileSelectInputConnector
name="metadataProfileId"
value={metadataProfileId}
includeNoChange={true}
isDisabled={!selectedCount}
onChange={this.onInputChange}
/>
</div>
);
}
if (name === 'bookFolder') {
return (
<div
key={name}
className={styles.inputContainer}
>
<AuthorEditorFooterLabel
label="Book Folder"
isSaving={isSaving && bookFolder !== NO_CHANGE}
/>
<SelectInput
name="bookFolder"
value={bookFolder}
values={bookFolderOptions}
isDisabled={!selectedCount}
onChange={this.onInputChange}
/>
</div>
);
}
if (name === 'path') {
return (
<div
key={name}
className={styles.inputContainer}
>
<AuthorEditorFooterLabel
label="Root Folder"
isSaving={isSaving && rootFolderPath !== NO_CHANGE}
/>
<RootFolderSelectInputConnector
name="rootFolderPath"
value={rootFolderPath}
includeNoChange={true}
isDisabled={!selectedCount}
selectedValueOptions={{ includeFreeSpace: false }}
onChange={this.onInputChange}
/>
</div>
);
}
return null;
})
}
<div className={styles.inputContainer}>
<AuthorEditorFooterLabel
label="Root Folder"
isSaving={isSaving && rootFolderPath !== NO_CHANGE}
/>
<RootFolderSelectInputConnector
name="rootFolderPath"
value={rootFolderPath}
includeNoChange={true}
isDisabled={!selectedCount}
selectedValueOptions={{ includeFreeSpace: false }}
onChange={this.onInputChange}
/>
</div>
<div className={styles.buttonContainer}>
<div className={styles.buttonContainerContent}>
<AuthorEditorFooterLabel
@ -315,6 +369,7 @@ AuthorEditorFooter.propTypes = {
isOrganizingAuthor: PropTypes.bool.isRequired,
isRetaggingAuthor: PropTypes.bool.isRequired,
showMetadataProfile: PropTypes.bool.isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
onSaveSelected: PropTypes.func.isRequired,
onOrganizeAuthorPress: PropTypes.func.isRequired,
onRetagAuthorPress: PropTypes.func.isRequired

@ -1,4 +1,3 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import AuthorNameLink from 'Author/AuthorNameLink';
@ -8,6 +7,7 @@ import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import TableRow from 'Components/Table/TableRow';
import TagListConnector from 'Components/TagListConnector';
import formatBytes from 'Utilities/Number/formatBytes';
import styles from './AuthorEditorRow.css';
class AuthorEditorRow extends Component {
@ -34,6 +34,7 @@ class AuthorEditorRow extends Component {
metadataProfile,
qualityProfile,
path,
statistics,
tags,
columns,
isSelected,
@ -48,39 +49,105 @@ class AuthorEditorRow extends Component {
onSelectedChange={onSelectedChange}
/>
<AuthorStatusCell
authorType={authorType}
monitored={monitored}
status={status}
/>
{
columns.map((column) => {
const {
name,
isVisible
} = column;
<TableRowCell>
<AuthorNameLink
titleSlug={titleSlug}
authorName={authorName}
/>
</TableRowCell>
if (!isVisible) {
return null;
}
<TableRowCell>
{qualityProfile.name}
</TableRowCell>
if (name === 'status') {
return (
<AuthorStatusCell
key={name}
authorType={authorType}
monitored={monitored}
status={status}
isSaving={isSaving}
onMonitoredPress={onAuthorMonitoredPress}
/>
);
}
{
_.find(columns, { name: 'metadataProfileId' }).isVisible &&
<TableRowCell>
{metadataProfile.name}
</TableRowCell>
}
if (name === 'sortName') {
return (
<TableRowCell
key={name}
className={styles.title}
>
<ArtistNameLink
foreignAuthorId={foreignAuthorId}
authorName={authorName}
/>
</TableRowCell>
);
}
if (name === 'qualityProfileId') {
return (
<TableRowCell key={name}>
{qualityProfile.name}
</TableRowCell>
);
}
<TableRowCell>
{path}
</TableRowCell>
if (name === 'metadataProfileId') {
return (
<TableRowCell key={name}>
{metadataProfile.name}
</TableRowCell>
);
}
<TableRowCell>
<TagListConnector
tags={tags}
/>
</TableRowCell>
if (name === 'bookFolder') {
return (
<TableRowCell
key={name}
className={styles.bookFolder}
>
<CheckInput
name="bookFolder"
value={bookFolder}
isDisabled={true}
onChange={this.onBookFolderChange}
/>
</TableRowCell>
);
}
if (name === 'path') {
return (
<TableRowCell key={name}>
{path}
</TableRowCell>
);
}
if (name === 'sizeOnDisk') {
return (
<TableRowCell key={name}>
{formatBytes(statistics.sizeOnDisk)}
</TableRowCell>
);
}
if (name === 'tags') {
return (
<TableRowCell key={name}>
<TagListConnector
tags={tags}
/>
</TableRowCell>
);
}
return null;
})
}
</TableRow>
);
}
@ -96,6 +163,7 @@ AuthorEditorRow.propTypes = {
metadataProfile: PropTypes.object.isRequired,
qualityProfile: PropTypes.object.isRequired,
path: PropTypes.string.isRequired,
statistics: PropTypes.object.isRequired,
tags: PropTypes.arrayOf(PropTypes.number).isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
isSelected: PropTypes.bool,

@ -8,6 +8,7 @@ import { set, updateItem } from './baseActions';
import createHandleActions from './Creators/createHandleActions';
import createSetClientSideCollectionFilterReducer from './Creators/Reducers/createSetClientSideCollectionFilterReducer';
import createSetClientSideCollectionSortReducer from './Creators/Reducers/createSetClientSideCollectionSortReducer';
import createSetTableOptionReducer from './Creators/Reducers/createSetTableOptionReducer';
//
// Variables
@ -30,6 +31,58 @@ export const defaultState = {
filters,
filterPredicates,
columns: [
{
name: 'status',
columnLabel: 'Status',
isSortable: true,
isVisible: true,
isModifiable: false
},
{
name: 'sortName',
label: 'Name',
isSortable: true,
isVisible: true
},
{
name: 'qualityProfileId',
label: 'Quality Profile',
isSortable: true,
isVisible: true
},
{
name: 'metadataProfileId',
label: 'Metadata Profile',
isSortable: true,
isVisible: false
},
{
name: 'albumFolder',
label: 'Album Folder',
isSortable: true,
isVisible: true
},
{
name: 'path',
label: 'Path',
isSortable: true,
isVisible: true
},
{
name: 'sizeOnDisk',
label: 'Size on Disk',
isSortable: true,
isVisible: false
},
{
name: 'tags',
label: 'Tags',
isSortable: false,
isVisible: true
}
],
filterBuilderProps: [
{
name: 'monitored',
@ -65,6 +118,12 @@ export const defaultState = {
label: 'Root Folder Path',
type: filterBuilderTypes.EXACT
},
{
name: 'sizeOnDisk',
label: 'Size on Disk',
type: filterBuilderTypes.NUMBER,
valueType: filterBuilderValueTypes.BYTES
},
{
name: 'tags',
label: 'Tags',
@ -90,6 +149,7 @@ export const SET_AUTHOR_EDITOR_SORT = 'authorEditor/setAuthorEditorSort';
export const SET_AUTHOR_EDITOR_FILTER = 'authorEditor/setAuthorEditorFilter';
export const SAVE_AUTHOR_EDITOR = 'authorEditor/saveAuthorEditor';
export const BULK_DELETE_AUTHOR = 'authorEditor/bulkDeleteAuthor';
export const SET_AUTHOR_EDITOR_TABLE_OPTION = 'authorEditor/setAuthorEditorTableOption';
//
// Action Creators
@ -98,6 +158,7 @@ export const setAuthorEditorSort = createAction(SET_AUTHOR_EDITOR_SORT);
export const setAuthorEditorFilter = createAction(SET_AUTHOR_EDITOR_FILTER);
export const saveAuthorEditor = createThunk(SAVE_AUTHOR_EDITOR);
export const bulkDeleteAuthor = createThunk(BULK_DELETE_AUTHOR);
export const setAuthorEditorTableOption = createAction(SET_AUTHOR_EDITOR_TABLE_OPTION);
//
// Action Handlers
@ -181,6 +242,7 @@ export const actionHandlers = handleThunks({
export const reducers = createHandleActions({
[SET_AUTHOR_EDITOR_TABLE_OPTION]: createSetTableOptionReducer(section),
[SET_AUTHOR_EDITOR_SORT]: createSetClientSideCollectionSortReducer(section),
[SET_AUTHOR_EDITOR_FILTER]: createSetClientSideCollectionFilterReducer(section)

Loading…
Cancel
Save