From 57206da77bea5918466ca24713d17e3f196411c9 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Mon, 30 Jan 2023 19:11:10 -0800 Subject: [PATCH] Remove Artists Editor (cherry picked from commit 67232290e5fb94c96734a8ca59aad0f7de79fa20) --- frontend/src/App/AppRoutes.js | 11 +- frontend/src/Artist/Editor/ArtistEditor.js | 281 ------------- .../Artist/Editor/ArtistEditorConnector.js | 97 ----- .../ArtistEditorFilterModalConnector.js | 24 -- .../src/Artist/Editor/ArtistEditorFooter.css | 70 ---- .../Artist/Editor/ArtistEditorFooter.css.d.ts | 14 - .../src/Artist/Editor/ArtistEditorFooter.js | 382 ------------------ .../Artist/Editor/ArtistEditorFooterLabel.css | 8 - .../Editor/ArtistEditorFooterLabel.css.d.ts | 8 - .../Artist/Editor/ArtistEditorFooterLabel.js | 40 -- frontend/src/Artist/Editor/ArtistEditorRow.js | 168 -------- .../Artist/Editor/ArtistEditorRowConnector.js | 61 --- .../Editor/AudioTags/RetagArtistModal.js | 31 -- .../AudioTags/RetagArtistModalContent.css | 8 - .../RetagArtistModalContent.css.d.ts | 8 - .../AudioTags/RetagArtistModalContent.js | 74 ---- .../RetagArtistModalContentConnector.js | 67 --- .../Artist/Editor/Delete/DeleteArtistModal.js | 31 -- .../Delete/DeleteArtistModalContent.css | 13 - .../Delete/DeleteArtistModalContent.css.d.ts | 9 - .../Editor/Delete/DeleteArtistModalContent.js | 124 ------ .../DeleteArtistModalContentConnector.js | 45 --- .../Editor/Organize/OrganizeArtistModal.js | 31 -- .../Organize/OrganizeArtistModalContent.css | 8 - .../OrganizeArtistModalContent.css.d.ts | 8 - .../Organize/OrganizeArtistModalContent.js | 75 ---- .../OrganizeArtistModalContentConnector.js | 67 --- frontend/src/Artist/Editor/Tags/TagsModal.js | 31 -- .../Artist/Editor/Tags/TagsModalContent.css | 12 - .../Editor/Tags/TagsModalContent.css.d.ts | 9 - .../Artist/Editor/Tags/TagsModalContent.js | 194 --------- .../Editor/Tags/TagsModalContentConnector.js | 36 -- .../Components/Page/Sidebar/PageSidebar.js | 4 - .../src/Store/Actions/artistEditorActions.js | 259 ------------ frontend/src/Store/Actions/index.js | 2 - src/NzbDrone.Core/Localization/Core/en.json | 1 - 36 files changed, 9 insertions(+), 2302 deletions(-) delete mode 100644 frontend/src/Artist/Editor/ArtistEditor.js delete mode 100644 frontend/src/Artist/Editor/ArtistEditorConnector.js delete mode 100644 frontend/src/Artist/Editor/ArtistEditorFilterModalConnector.js delete mode 100644 frontend/src/Artist/Editor/ArtistEditorFooter.css delete mode 100644 frontend/src/Artist/Editor/ArtistEditorFooter.css.d.ts delete mode 100644 frontend/src/Artist/Editor/ArtistEditorFooter.js delete mode 100644 frontend/src/Artist/Editor/ArtistEditorFooterLabel.css delete mode 100644 frontend/src/Artist/Editor/ArtistEditorFooterLabel.css.d.ts delete mode 100644 frontend/src/Artist/Editor/ArtistEditorFooterLabel.js delete mode 100644 frontend/src/Artist/Editor/ArtistEditorRow.js delete mode 100644 frontend/src/Artist/Editor/ArtistEditorRowConnector.js delete mode 100644 frontend/src/Artist/Editor/AudioTags/RetagArtistModal.js delete mode 100644 frontend/src/Artist/Editor/AudioTags/RetagArtistModalContent.css delete mode 100644 frontend/src/Artist/Editor/AudioTags/RetagArtistModalContent.css.d.ts delete mode 100644 frontend/src/Artist/Editor/AudioTags/RetagArtistModalContent.js delete mode 100644 frontend/src/Artist/Editor/AudioTags/RetagArtistModalContentConnector.js delete mode 100644 frontend/src/Artist/Editor/Delete/DeleteArtistModal.js delete mode 100644 frontend/src/Artist/Editor/Delete/DeleteArtistModalContent.css delete mode 100644 frontend/src/Artist/Editor/Delete/DeleteArtistModalContent.css.d.ts delete mode 100644 frontend/src/Artist/Editor/Delete/DeleteArtistModalContent.js delete mode 100644 frontend/src/Artist/Editor/Delete/DeleteArtistModalContentConnector.js delete mode 100644 frontend/src/Artist/Editor/Organize/OrganizeArtistModal.js delete mode 100644 frontend/src/Artist/Editor/Organize/OrganizeArtistModalContent.css delete mode 100644 frontend/src/Artist/Editor/Organize/OrganizeArtistModalContent.css.d.ts delete mode 100644 frontend/src/Artist/Editor/Organize/OrganizeArtistModalContent.js delete mode 100644 frontend/src/Artist/Editor/Organize/OrganizeArtistModalContentConnector.js delete mode 100644 frontend/src/Artist/Editor/Tags/TagsModal.js delete mode 100644 frontend/src/Artist/Editor/Tags/TagsModalContent.css delete mode 100644 frontend/src/Artist/Editor/Tags/TagsModalContent.css.d.ts delete mode 100644 frontend/src/Artist/Editor/Tags/TagsModalContent.js delete mode 100644 frontend/src/Artist/Editor/Tags/TagsModalContentConnector.js delete mode 100644 frontend/src/Store/Actions/artistEditorActions.js diff --git a/frontend/src/App/AppRoutes.js b/frontend/src/App/AppRoutes.js index 54913f632..af938fd83 100644 --- a/frontend/src/App/AppRoutes.js +++ b/frontend/src/App/AppRoutes.js @@ -7,7 +7,6 @@ import QueueConnector from 'Activity/Queue/QueueConnector'; import AlbumDetailsPageConnector from 'Album/Details/AlbumDetailsPageConnector'; import AlbumStudioConnector from 'AlbumStudio/AlbumStudioConnector'; import ArtistDetailsPageConnector from 'Artist/Details/ArtistDetailsPageConnector'; -import ArtistEditorConnector from 'Artist/Editor/ArtistEditorConnector'; import ArtistIndex from 'Artist/Index/ArtistIndex'; import CalendarPageConnector from 'Calendar/CalendarPageConnector'; import NotFound from 'Components/NotFound'; @@ -78,7 +77,15 @@ function AppRoutes(props) { { + return ( + + ); + }} /> { - return getSelectedIds(this.state.selectedState); - }; - - // - // Listeners - - onSelectAllChange = ({ value }) => { - this.setState(selectAll(this.state.selectedState, value)); - }; - - onSelectedChange = ({ id, value, shiftKey = false }) => { - this.setState((state) => { - return toggleSelected(state, this.props.items, id, value, shiftKey); - }); - }; - - onSaveSelected = (changes) => { - this.props.onSaveSelected({ - artistIds: this.getSelectedIds(), - ...changes - }); - }; - - onOrganizeArtistPress = () => { - this.setState({ isOrganizingArtistModalOpen: true }); - }; - - onOrganizeArtistModalClose = (organized) => { - this.setState({ isOrganizingArtistModalOpen: false }); - - if (organized === true) { - this.onSelectAllChange({ value: false }); - } - }; - - onRetagArtistPress = () => { - this.setState({ isRetaggingArtistModalOpen: true }); - }; - - onRetagArtistModalClose = (organized) => { - this.setState({ isRetaggingArtistModalOpen: false }); - - if (organized === true) { - this.onSelectAllChange({ value: false }); - } - }; - - // - // Render - - render() { - const { - isFetching, - isPopulated, - error, - totalItems, - items, - columns, - selectedFilterKey, - filters, - customFilters, - sortKey, - sortDirection, - isSaving, - saveError, - isDeleting, - deleteError, - isOrganizingArtist, - isRetaggingArtist, - onTableOptionChange, - onSortPress, - onFilterSelect - } = this.props; - - const { - allSelected, - allUnselected, - selectedState - } = this.state; - - const selectedArtistIds = this.getSelectedIds(); - - return ( - - - - - - - - - - - - - - - - { - isFetching && !isPopulated && - - } - - { - !isFetching && !!error && -
{getErrorMessage(error, 'Failed to load artist from API')}
- } - - { - !error && isPopulated && !!items.length && -
- - - { - items.map((item) => { - return ( - - ); - }) - } - -
-
- } - - { - !error && isPopulated && !items.length && - - } -
- - column.name === 'metadataProfileId').isVisible} - onSaveSelected={this.onSaveSelected} - onOrganizeArtistPress={this.onOrganizeArtistPress} - onRetagArtistPress={this.onRetagArtistPress} - /> - - - - - -
- ); - } -} - -ArtistEditor.propTypes = { - isFetching: PropTypes.bool.isRequired, - isPopulated: PropTypes.bool.isRequired, - 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, - filters: PropTypes.arrayOf(PropTypes.object).isRequired, - customFilters: PropTypes.arrayOf(PropTypes.object).isRequired, - isSaving: PropTypes.bool.isRequired, - saveError: PropTypes.object, - isDeleting: PropTypes.bool.isRequired, - deleteError: PropTypes.object, - isOrganizingArtist: PropTypes.bool.isRequired, - isRetaggingArtist: PropTypes.bool.isRequired, - onTableOptionChange: PropTypes.func.isRequired, - onSortPress: PropTypes.func.isRequired, - onFilterSelect: PropTypes.func.isRequired, - onSaveSelected: PropTypes.func.isRequired -}; - -export default ArtistEditor; diff --git a/frontend/src/Artist/Editor/ArtistEditorConnector.js b/frontend/src/Artist/Editor/ArtistEditorConnector.js deleted file mode 100644 index b2da4abd5..000000000 --- a/frontend/src/Artist/Editor/ArtistEditorConnector.js +++ /dev/null @@ -1,97 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; -import * as commandNames from 'Commands/commandNames'; -import { saveArtistEditor, setArtistEditorFilter, setArtistEditorSort, setArtistEditorTableOption } from 'Store/Actions/artistEditorActions'; -import { executeCommand } from 'Store/Actions/commandActions'; -import { fetchRootFolders } from 'Store/Actions/settingsActions'; -import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector'; -import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector'; -import ArtistEditor from './ArtistEditor'; - -function createMapStateToProps() { - return createSelector( - createClientSideCollectionSelector('artist', 'artistEditor'), - createCommandExecutingSelector(commandNames.RENAME_ARTIST), - createCommandExecutingSelector(commandNames.RETAG_ARTIST), - (artist, isOrganizingArtist, isRetaggingArtist) => { - return { - isOrganizingArtist, - isRetaggingArtist, - ...artist - }; - } - ); -} - -const mapDispatchToProps = { - dispatchSetArtistEditorSort: setArtistEditorSort, - dispatchSetArtistEditorFilter: setArtistEditorFilter, - dispatchSetArtistEditorTableOption: setArtistEditorTableOption, - dispatchSaveArtistEditor: saveArtistEditor, - dispatchFetchRootFolders: fetchRootFolders, - dispatchExecuteCommand: executeCommand -}; - -class ArtistEditorConnector extends Component { - - // - // Lifecycle - - componentDidMount() { - this.props.dispatchFetchRootFolders(); - } - - // - // Listeners - - onSortPress = (sortKey) => { - this.props.dispatchSetArtistEditorSort({ sortKey }); - }; - - onFilterSelect = (selectedFilterKey) => { - this.props.dispatchSetArtistEditorFilter({ selectedFilterKey }); - }; - - onTableOptionChange = (payload) => { - this.props.dispatchSetArtistEditorTableOption(payload); - }; - - onSaveSelected = (payload) => { - this.props.dispatchSaveArtistEditor(payload); - }; - - onMoveSelected = (payload) => { - this.props.dispatchExecuteCommand({ - name: commandNames.MOVE_ARTIST, - ...payload - }); - }; - - // - // Render - - render() { - return ( - - ); - } -} - -ArtistEditorConnector.propTypes = { - dispatchSetArtistEditorSort: PropTypes.func.isRequired, - dispatchSetArtistEditorFilter: PropTypes.func.isRequired, - dispatchSetArtistEditorTableOption: PropTypes.func.isRequired, - dispatchSaveArtistEditor: PropTypes.func.isRequired, - dispatchFetchRootFolders: PropTypes.func.isRequired, - dispatchExecuteCommand: PropTypes.func.isRequired -}; - -export default connect(createMapStateToProps, mapDispatchToProps)(ArtistEditorConnector); diff --git a/frontend/src/Artist/Editor/ArtistEditorFilterModalConnector.js b/frontend/src/Artist/Editor/ArtistEditorFilterModalConnector.js deleted file mode 100644 index 2e84a07ee..000000000 --- a/frontend/src/Artist/Editor/ArtistEditorFilterModalConnector.js +++ /dev/null @@ -1,24 +0,0 @@ -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; -import FilterModal from 'Components/Filter/FilterModal'; -import { setArtistEditorFilter } from 'Store/Actions/artistEditorActions'; - -function createMapStateToProps() { - return createSelector( - (state) => state.artist.items, - (state) => state.artistEditor.filterBuilderProps, - (sectionItems, filterBuilderProps) => { - return { - sectionItems, - filterBuilderProps, - customFilterType: 'artistEditor' - }; - } - ); -} - -const mapDispatchToProps = { - dispatchSetFilter: setArtistEditorFilter -}; - -export default connect(createMapStateToProps, mapDispatchToProps)(FilterModal); diff --git a/frontend/src/Artist/Editor/ArtistEditorFooter.css b/frontend/src/Artist/Editor/ArtistEditorFooter.css deleted file mode 100644 index 3785f88d3..000000000 --- a/frontend/src/Artist/Editor/ArtistEditorFooter.css +++ /dev/null @@ -1,70 +0,0 @@ -.inputContainer { - margin-right: 20px; - min-width: 150px; -} - -.buttonContainer { - display: flex; - justify-content: flex-end; - flex-grow: 1; -} - -.buttonContainerContent { - flex-grow: 0; -} - -.buttons { - display: flex; - justify-content: flex-end; - flex-grow: 1; -} - -.organizeSelectedButton, -.tagsButton { - composes: button from '~Components/Link/SpinnerButton.css'; - - margin-right: 10px; - height: 35px; -} - -.deleteSelectedButton { - composes: button from '~Components/Link/SpinnerButton.css'; - - margin-left: 50px; - height: 35px; -} - -@media only screen and (max-width: $breakpointExtraLarge) { - .deleteSelectedButton { - margin-left: 0; - } -} - -@media only screen and (max-width: $breakpointLarge) { - .buttonContainer { - justify-content: flex-start; - margin-top: 10px; - } -} - -@media only screen and (max-width: $breakpointSmall) { - .inputContainer { - margin-right: 0; - } - - .buttonContainer { - justify-content: flex-start; - } - - .buttonContainerContent { - flex-grow: 1; - } - - .buttons { - justify-content: space-between; - } - - .selectedArtistLabel { - text-align: left; - } -} diff --git a/frontend/src/Artist/Editor/ArtistEditorFooter.css.d.ts b/frontend/src/Artist/Editor/ArtistEditorFooter.css.d.ts deleted file mode 100644 index 6dbc89510..000000000 --- a/frontend/src/Artist/Editor/ArtistEditorFooter.css.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'buttonContainer': string; - 'buttonContainerContent': string; - 'buttons': string; - 'deleteSelectedButton': string; - 'inputContainer': string; - 'organizeSelectedButton': string; - 'selectedArtistLabel': string; - 'tagsButton': string; -} -export const cssExports: CssExports; -export default cssExports; diff --git a/frontend/src/Artist/Editor/ArtistEditorFooter.js b/frontend/src/Artist/Editor/ArtistEditorFooter.js deleted file mode 100644 index eff8605b9..000000000 --- a/frontend/src/Artist/Editor/ArtistEditorFooter.js +++ /dev/null @@ -1,382 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import MoveArtistModal from 'Artist/MoveArtist/MoveArtistModal'; -import FormInputGroup from 'Components/Form/FormInputGroup'; -import MetadataProfileSelectInputConnector from 'Components/Form/MetadataProfileSelectInputConnector'; -import MonitorNewItemsSelectInput from 'Components/Form/MonitorNewItemsSelectInput'; -import QualityProfileSelectInputConnector from 'Components/Form/QualityProfileSelectInputConnector'; -import RootFolderSelectInputConnector from 'Components/Form/RootFolderSelectInputConnector'; -import SpinnerButton from 'Components/Link/SpinnerButton'; -import PageContentFooter from 'Components/Page/PageContentFooter'; -import { inputTypes, kinds } from 'Helpers/Props'; -import translate from 'Utilities/String/translate'; -import ArtistEditorFooterLabel from './ArtistEditorFooterLabel'; -import DeleteArtistModal from './Delete/DeleteArtistModal'; -import TagsModal from './Tags/TagsModal'; -import styles from './ArtistEditorFooter.css'; - -const NO_CHANGE = 'noChange'; - -class ArtistEditorFooter extends Component { - - // - // Lifecycle - - constructor(props, context) { - super(props, context); - - this.state = { - monitored: NO_CHANGE, - monitorNewItems: NO_CHANGE, - qualityProfileId: NO_CHANGE, - metadataProfileId: NO_CHANGE, - rootFolderPath: NO_CHANGE, - savingTags: false, - isDeleteArtistModalOpen: false, - isTagsModalOpen: false, - isConfirmMoveModalOpen: false, - destinationRootFolder: null - }; - } - - componentDidUpdate(prevProps) { - const { - isSaving, - saveError - } = this.props; - - if (prevProps.isSaving && !isSaving && !saveError) { - this.setState({ - monitored: NO_CHANGE, - monitorNewItems: NO_CHANGE, - qualityProfileId: NO_CHANGE, - metadataProfileId: NO_CHANGE, - rootFolderPath: NO_CHANGE, - savingTags: false - }); - } - } - - // - // Listeners - - onInputChange = ({ name, value }) => { - this.setState({ [name]: value }); - - if (value === NO_CHANGE) { - return; - } - - switch (name) { - case 'rootFolderPath': - this.setState({ - isConfirmMoveModalOpen: true, - destinationRootFolder: value - }); - break; - case 'monitored': - this.props.onSaveSelected({ [name]: value === 'monitored' }); - break; - default: - this.props.onSaveSelected({ [name]: value }); - } - }; - - onApplyTagsPress = (tags, applyTags) => { - this.setState({ - savingTags: true, - isTagsModalOpen: false - }); - - this.props.onSaveSelected({ - tags, - applyTags - }); - }; - - onDeleteSelectedPress = () => { - this.setState({ isDeleteArtistModalOpen: true }); - }; - - onDeleteArtistModalClose = () => { - this.setState({ isDeleteArtistModalOpen: false }); - }; - - onTagsPress = () => { - this.setState({ isTagsModalOpen: true }); - }; - - onTagsModalClose = () => { - this.setState({ isTagsModalOpen: false }); - }; - - onSaveRootFolderPress = () => { - this.setState({ - isConfirmMoveModalOpen: false, - destinationRootFolder: null - }); - - this.props.onSaveSelected({ rootFolderPath: this.state.destinationRootFolder }); - }; - - onMoveArtistPress = () => { - this.setState({ - isConfirmMoveModalOpen: false, - destinationRootFolder: null - }); - - this.props.onSaveSelected({ - rootFolderPath: this.state.destinationRootFolder, - moveFiles: true - }); - }; - - // - // Render - - render() { - const { - artistIds, - selectedCount, - isSaving, - isDeleting, - isOrganizingArtist, - isRetaggingArtist, - columns, - onOrganizeArtistPress, - onRetagArtistPress - } = this.props; - - const { - monitored, - monitorNewItems, - qualityProfileId, - metadataProfileId, - rootFolderPath, - savingTags, - isTagsModalOpen, - isDeleteArtistModalOpen, - isConfirmMoveModalOpen, - destinationRootFolder - } = this.state; - - const monitoredOptions = [ - { key: NO_CHANGE, value: translate('NoChange'), disabled: true }, - { key: 'monitored', value: 'Monitored' }, - { key: 'unmonitored', value: 'Unmonitored' } - ]; - - return ( - -
- - - -
- -
- - - -
- - { - columns.map((column) => { - const { - name, - isVisible - } = column; - - if (!isVisible) { - return null; - } - - if (name === 'qualityProfileId') { - return ( -
- - - -
- ); - } - - if (name === 'metadataProfileId') { - return ( -
- - - -
- ); - } - - if (name === 'path') { - return ( -
- - - -
- ); - } - - return null; - }) - } - -
-
- - -
-
- - Rename Files - - - - Write Metadata Tags - - - - Set Lidarr Tags - -
- - - Delete - -
-
-
- - - - - - - -
- ); - } -} - -ArtistEditorFooter.propTypes = { - artistIds: PropTypes.arrayOf(PropTypes.number).isRequired, - selectedCount: PropTypes.number.isRequired, - isSaving: PropTypes.bool.isRequired, - saveError: PropTypes.object, - isDeleting: PropTypes.bool.isRequired, - deleteError: PropTypes.object, - isOrganizingArtist: PropTypes.bool.isRequired, - isRetaggingArtist: PropTypes.bool.isRequired, - showMetadataProfile: PropTypes.bool.isRequired, - columns: PropTypes.arrayOf(PropTypes.object).isRequired, - onSaveSelected: PropTypes.func.isRequired, - onOrganizeArtistPress: PropTypes.func.isRequired, - onRetagArtistPress: PropTypes.func.isRequired -}; - -export default ArtistEditorFooter; diff --git a/frontend/src/Artist/Editor/ArtistEditorFooterLabel.css b/frontend/src/Artist/Editor/ArtistEditorFooterLabel.css deleted file mode 100644 index 9b4b40be6..000000000 --- a/frontend/src/Artist/Editor/ArtistEditorFooterLabel.css +++ /dev/null @@ -1,8 +0,0 @@ -.label { - margin-bottom: 3px; - font-weight: bold; -} - -.savingIcon { - margin-left: 8px; -} diff --git a/frontend/src/Artist/Editor/ArtistEditorFooterLabel.css.d.ts b/frontend/src/Artist/Editor/ArtistEditorFooterLabel.css.d.ts deleted file mode 100644 index 06f814a94..000000000 --- a/frontend/src/Artist/Editor/ArtistEditorFooterLabel.css.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'label': string; - 'savingIcon': string; -} -export const cssExports: CssExports; -export default cssExports; diff --git a/frontend/src/Artist/Editor/ArtistEditorFooterLabel.js b/frontend/src/Artist/Editor/ArtistEditorFooterLabel.js deleted file mode 100644 index 1d02bd3db..000000000 --- a/frontend/src/Artist/Editor/ArtistEditorFooterLabel.js +++ /dev/null @@ -1,40 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import SpinnerIcon from 'Components/SpinnerIcon'; -import { icons } from 'Helpers/Props'; -import styles from './ArtistEditorFooterLabel.css'; - -function ArtistEditorFooterLabel(props) { - const { - className, - label, - isSaving - } = props; - - return ( -
- {label} - - { - isSaving && - - } -
- ); -} - -ArtistEditorFooterLabel.propTypes = { - className: PropTypes.string.isRequired, - label: PropTypes.string.isRequired, - isSaving: PropTypes.bool.isRequired -}; - -ArtistEditorFooterLabel.defaultProps = { - className: styles.label -}; - -export default ArtistEditorFooterLabel; diff --git a/frontend/src/Artist/Editor/ArtistEditorRow.js b/frontend/src/Artist/Editor/ArtistEditorRow.js deleted file mode 100644 index 56d72c34c..000000000 --- a/frontend/src/Artist/Editor/ArtistEditorRow.js +++ /dev/null @@ -1,168 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import ArtistNameLink from 'Artist/ArtistNameLink'; -import ArtistStatusCell from 'Artist/Index/Table/ArtistStatusCell'; -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 monitorNewItemsOptions from 'Utilities/Artist/monitorNewItemsOptions'; -import formatBytes from 'Utilities/Number/formatBytes'; - -class ArtistEditorRow extends Component { - - // - // Render - - render() { - const { - id, - status, - foreignArtistId, - artistName, - artistType, - monitored, - monitorNewItems, - metadataProfile, - qualityProfile, - path, - statistics, - tags, - columns, - isSaving, - isSelected, - onArtistMonitoredPress, - onSelectedChange - } = this.props; - - const monitorNewItemsName = monitorNewItemsOptions.find((o) => o.key === monitorNewItems)?.value; - - return ( - - - - { - columns.map((column) => { - const { - name, - isVisible - } = column; - - if (!isVisible) { - return null; - } - - if (name === 'status') { - return ( - - ); - } - - if (name === 'sortName') { - return ( - - - - ); - } - - if (name === 'monitorNewItems') { - return ( - - {monitorNewItemsName ?? 'Unknown'} - - ); - } - - if (name === 'qualityProfileId') { - return ( - - {qualityProfile.name} - - ); - } - - if (name === 'metadataProfileId') { - return ( - - {metadataProfile.name} - - ); - } - - if (name === 'path') { - return ( - - {path} - - ); - } - - if (name === 'sizeOnDisk') { - return ( - - {formatBytes(statistics.sizeOnDisk)} - - ); - } - - if (name === 'tags') { - return ( - - - - ); - } - - return null; - }) - } - - ); - } -} - -ArtistEditorRow.propTypes = { - id: PropTypes.number.isRequired, - status: PropTypes.string.isRequired, - foreignArtistId: PropTypes.string.isRequired, - artistName: PropTypes.string.isRequired, - artistType: PropTypes.string, - monitored: PropTypes.bool.isRequired, - monitorNewItems: PropTypes.string.isRequired, - 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, - isSaving: PropTypes.bool.isRequired, - isSelected: PropTypes.bool, - onArtistMonitoredPress: PropTypes.func.isRequired, - onSelectedChange: PropTypes.func.isRequired -}; - -ArtistEditorRow.defaultProps = { - tags: [], - statistics: {} -}; - -export default ArtistEditorRow; diff --git a/frontend/src/Artist/Editor/ArtistEditorRowConnector.js b/frontend/src/Artist/Editor/ArtistEditorRowConnector.js deleted file mode 100644 index 4ab082b52..000000000 --- a/frontend/src/Artist/Editor/ArtistEditorRowConnector.js +++ /dev/null @@ -1,61 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; -import { toggleArtistMonitored } from 'Store/Actions/artistActions'; -import createMetadataProfileSelector from 'Store/Selectors/createMetadataProfileSelector'; -import createQualityProfileSelector from 'Store/Selectors/createQualityProfileSelector'; -import ArtistEditorRow from './ArtistEditorRow'; - -function createMapStateToProps() { - return createSelector( - createMetadataProfileSelector(), - createQualityProfileSelector(), - (metadataProfile, qualityProfile) => { - return { - metadataProfile, - qualityProfile - }; - } - ); -} - -const mapDispatchToProps = { - toggleArtistMonitored -}; - -class ArtistEditorRowConnector extends Component { - - // - // Listeners - - onArtistMonitoredPress = () => { - const { - id, - monitored - } = this.props; - - this.props.toggleArtistMonitored({ - artistId: id, - monitored: !monitored - }); - }; - - render() { - return ( - - ); - } -} - -ArtistEditorRowConnector.propTypes = { - id: PropTypes.number.isRequired, - monitored: PropTypes.bool.isRequired, - qualityProfileId: PropTypes.number.isRequired, - toggleArtistMonitored: PropTypes.func.isRequired -}; - -export default connect(createMapStateToProps, mapDispatchToProps)(ArtistEditorRowConnector); diff --git a/frontend/src/Artist/Editor/AudioTags/RetagArtistModal.js b/frontend/src/Artist/Editor/AudioTags/RetagArtistModal.js deleted file mode 100644 index 636ca6618..000000000 --- a/frontend/src/Artist/Editor/AudioTags/RetagArtistModal.js +++ /dev/null @@ -1,31 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import Modal from 'Components/Modal/Modal'; -import RetagArtistModalContentConnector from './RetagArtistModalContentConnector'; - -function RetagArtistModal(props) { - const { - isOpen, - onModalClose, - ...otherProps - } = props; - - return ( - - - - ); -} - -RetagArtistModal.propTypes = { - isOpen: PropTypes.bool.isRequired, - onModalClose: PropTypes.func.isRequired -}; - -export default RetagArtistModal; diff --git a/frontend/src/Artist/Editor/AudioTags/RetagArtistModalContent.css b/frontend/src/Artist/Editor/AudioTags/RetagArtistModalContent.css deleted file mode 100644 index 02c52edc8..000000000 --- a/frontend/src/Artist/Editor/AudioTags/RetagArtistModalContent.css +++ /dev/null @@ -1,8 +0,0 @@ -.retagIcon { - margin-left: 5px; -} - -.message { - margin-top: 20px; - margin-bottom: 10px; -} diff --git a/frontend/src/Artist/Editor/AudioTags/RetagArtistModalContent.css.d.ts b/frontend/src/Artist/Editor/AudioTags/RetagArtistModalContent.css.d.ts deleted file mode 100644 index c2556006e..000000000 --- a/frontend/src/Artist/Editor/AudioTags/RetagArtistModalContent.css.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'message': string; - 'retagIcon': string; -} -export const cssExports: CssExports; -export default cssExports; diff --git a/frontend/src/Artist/Editor/AudioTags/RetagArtistModalContent.js b/frontend/src/Artist/Editor/AudioTags/RetagArtistModalContent.js deleted file mode 100644 index 7f632ad57..000000000 --- a/frontend/src/Artist/Editor/AudioTags/RetagArtistModalContent.js +++ /dev/null @@ -1,74 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import Alert from 'Components/Alert'; -import Icon from 'Components/Icon'; -import Button from 'Components/Link/Button'; -import ModalBody from 'Components/Modal/ModalBody'; -import ModalContent from 'Components/Modal/ModalContent'; -import ModalFooter from 'Components/Modal/ModalFooter'; -import ModalHeader from 'Components/Modal/ModalHeader'; -import { icons, kinds } from 'Helpers/Props'; -import translate from 'Utilities/String/translate'; -import styles from './RetagArtistModalContent.css'; - -function RetagArtistModalContent(props) { - const { - artistNames, - onModalClose, - onRetagArtistPress - } = props; - - return ( - - - Retag Selected Artist - - - - - Tip: To preview the tags that will be written... select "Cancel" then click any artist name and use the - - - -
- Are you sure you want to re-tag all files in the {artistNames.length} selected artist? -
-
    - { - artistNames.map((artistName) => { - return ( -
  • - {artistName} -
  • - ); - }) - } -
-
- - - - - - -
- ); -} - -RetagArtistModalContent.propTypes = { - artistNames: PropTypes.arrayOf(PropTypes.string).isRequired, - onModalClose: PropTypes.func.isRequired, - onRetagArtistPress: PropTypes.func.isRequired -}; - -export default RetagArtistModalContent; diff --git a/frontend/src/Artist/Editor/AudioTags/RetagArtistModalContentConnector.js b/frontend/src/Artist/Editor/AudioTags/RetagArtistModalContentConnector.js deleted file mode 100644 index 83e9fc06d..000000000 --- a/frontend/src/Artist/Editor/AudioTags/RetagArtistModalContentConnector.js +++ /dev/null @@ -1,67 +0,0 @@ -import _ from 'lodash'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; -import * as commandNames from 'Commands/commandNames'; -import { executeCommand } from 'Store/Actions/commandActions'; -import createAllArtistSelector from 'Store/Selectors/createAllArtistSelector'; -import RetagArtistModalContent from './RetagArtistModalContent'; - -function createMapStateToProps() { - return createSelector( - (state, { artistIds }) => artistIds, - createAllArtistSelector(), - (artistIds, allArtists) => { - const artist = _.intersectionWith(allArtists, artistIds, (s, id) => { - return s.id === id; - }); - - const sortedArtist = _.orderBy(artist, 'sortName'); - const artistNames = _.map(sortedArtist, 'artistName'); - - return { - artistNames - }; - } - ); -} - -const mapDispatchToProps = { - executeCommand -}; - -class RetagArtistModalContentConnector extends Component { - - // - // Listeners - - onRetagArtistPress = () => { - this.props.executeCommand({ - name: commandNames.RETAG_ARTIST, - artistIds: this.props.artistIds - }); - - this.props.onModalClose(true); - }; - - // - // Render - - render(props) { - return ( - - ); - } -} - -RetagArtistModalContentConnector.propTypes = { - artistIds: PropTypes.arrayOf(PropTypes.number).isRequired, - onModalClose: PropTypes.func.isRequired, - executeCommand: PropTypes.func.isRequired -}; - -export default connect(createMapStateToProps, mapDispatchToProps)(RetagArtistModalContentConnector); diff --git a/frontend/src/Artist/Editor/Delete/DeleteArtistModal.js b/frontend/src/Artist/Editor/Delete/DeleteArtistModal.js deleted file mode 100644 index 11fd79d5d..000000000 --- a/frontend/src/Artist/Editor/Delete/DeleteArtistModal.js +++ /dev/null @@ -1,31 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import Modal from 'Components/Modal/Modal'; -import DeleteArtistModalContentConnector from './DeleteArtistModalContentConnector'; - -function DeleteArtistModal(props) { - const { - isOpen, - onModalClose, - ...otherProps - } = props; - - return ( - - - - ); -} - -DeleteArtistModal.propTypes = { - isOpen: PropTypes.bool.isRequired, - onModalClose: PropTypes.func.isRequired -}; - -export default DeleteArtistModal; diff --git a/frontend/src/Artist/Editor/Delete/DeleteArtistModalContent.css b/frontend/src/Artist/Editor/Delete/DeleteArtistModalContent.css deleted file mode 100644 index 02a0514be..000000000 --- a/frontend/src/Artist/Editor/Delete/DeleteArtistModalContent.css +++ /dev/null @@ -1,13 +0,0 @@ -.message { - margin-top: 20px; - margin-bottom: 10px; -} - -.pathContainer { - margin-left: 5px; -} - -.path { - margin-left: 5px; - color: var(--dangerColor); -} diff --git a/frontend/src/Artist/Editor/Delete/DeleteArtistModalContent.css.d.ts b/frontend/src/Artist/Editor/Delete/DeleteArtistModalContent.css.d.ts deleted file mode 100644 index bcc2e2492..000000000 --- a/frontend/src/Artist/Editor/Delete/DeleteArtistModalContent.css.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'message': string; - 'path': string; - 'pathContainer': string; -} -export const cssExports: CssExports; -export default cssExports; diff --git a/frontend/src/Artist/Editor/Delete/DeleteArtistModalContent.js b/frontend/src/Artist/Editor/Delete/DeleteArtistModalContent.js deleted file mode 100644 index 6e04fc7e6..000000000 --- a/frontend/src/Artist/Editor/Delete/DeleteArtistModalContent.js +++ /dev/null @@ -1,124 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import FormGroup from 'Components/Form/FormGroup'; -import FormInputGroup from 'Components/Form/FormInputGroup'; -import FormLabel from 'Components/Form/FormLabel'; -import Button from 'Components/Link/Button'; -import ModalBody from 'Components/Modal/ModalBody'; -import ModalContent from 'Components/Modal/ModalContent'; -import ModalFooter from 'Components/Modal/ModalFooter'; -import ModalHeader from 'Components/Modal/ModalHeader'; -import { inputTypes, kinds } from 'Helpers/Props'; -import translate from 'Utilities/String/translate'; -import styles from './DeleteArtistModalContent.css'; - -class DeleteArtistModalContent extends Component { - - // - // Lifecycle - - constructor(props, context) { - super(props, context); - - this.state = { - deleteFiles: false - }; - } - - // - // Listeners - - onDeleteFilesChange = ({ value }) => { - this.setState({ deleteFiles: value }); - }; - - onDeleteArtistConfirmed = () => { - const deleteFiles = this.state.deleteFiles; - - this.setState({ deleteFiles: false }); - this.props.onDeleteSelectedPress(deleteFiles); - }; - - // - // Render - - render() { - const { - artist, - onModalClose - } = this.props; - const deleteFiles = this.state.deleteFiles; - - return ( - - - {translate('DeleteArtist')} - - - -
- - {`Delete Artist Folder${artist.length > 1 ? 's' : ''}`} - - 1 ? 's' : ''} and all contents`} - kind={kinds.DANGER} - onChange={this.onDeleteFilesChange} - /> - -
- -
- {`Are you sure you want to delete ${artist.length} selected artist${artist.length > 1 ? 's' : ''}${deleteFiles ? ' and all contents' : ''}?`} -
- -
    - { - artist.map((s) => { - return ( -
  • - {s.artistName} - - { - deleteFiles && - - - - - {s.path} - - - } -
  • - ); - }) - } -
-
- - - - - - -
- ); - } -} - -DeleteArtistModalContent.propTypes = { - artist: PropTypes.arrayOf(PropTypes.object).isRequired, - onModalClose: PropTypes.func.isRequired, - onDeleteSelectedPress: PropTypes.func.isRequired -}; - -export default DeleteArtistModalContent; diff --git a/frontend/src/Artist/Editor/Delete/DeleteArtistModalContentConnector.js b/frontend/src/Artist/Editor/Delete/DeleteArtistModalContentConnector.js deleted file mode 100644 index e3b0fa0fd..000000000 --- a/frontend/src/Artist/Editor/Delete/DeleteArtistModalContentConnector.js +++ /dev/null @@ -1,45 +0,0 @@ -import _ from 'lodash'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; -import { bulkDeleteArtist } from 'Store/Actions/artistEditorActions'; -import createAllArtistSelector from 'Store/Selectors/createAllArtistSelector'; -import DeleteArtistModalContent from './DeleteArtistModalContent'; - -function createMapStateToProps() { - return createSelector( - (state, { artistIds }) => artistIds, - createAllArtistSelector(), - (artistIds, allArtists) => { - const selectedArtist = _.intersectionWith(allArtists, artistIds, (s, id) => { - return s.id === id; - }); - - const sortedArtist = _.orderBy(selectedArtist, 'sortName'); - const artist = _.map(sortedArtist, (s) => { - return { - artistName: s.artistName, - path: s.path - }; - }); - - return { - artist - }; - } - ); -} - -function createMapDispatchToProps(dispatch, props) { - return { - onDeleteSelectedPress(deleteFiles) { - dispatch(bulkDeleteArtist({ - artistIds: props.artistIds, - deleteFiles - })); - - props.onModalClose(); - } - }; -} - -export default connect(createMapStateToProps, createMapDispatchToProps)(DeleteArtistModalContent); diff --git a/frontend/src/Artist/Editor/Organize/OrganizeArtistModal.js b/frontend/src/Artist/Editor/Organize/OrganizeArtistModal.js deleted file mode 100644 index 412396355..000000000 --- a/frontend/src/Artist/Editor/Organize/OrganizeArtistModal.js +++ /dev/null @@ -1,31 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import Modal from 'Components/Modal/Modal'; -import OrganizeArtistModalContentConnector from './OrganizeArtistModalContentConnector'; - -function OrganizeArtistModal(props) { - const { - isOpen, - onModalClose, - ...otherProps - } = props; - - return ( - - - - ); -} - -OrganizeArtistModal.propTypes = { - isOpen: PropTypes.bool.isRequired, - onModalClose: PropTypes.func.isRequired -}; - -export default OrganizeArtistModal; diff --git a/frontend/src/Artist/Editor/Organize/OrganizeArtistModalContent.css b/frontend/src/Artist/Editor/Organize/OrganizeArtistModalContent.css deleted file mode 100644 index 0b896f4ef..000000000 --- a/frontend/src/Artist/Editor/Organize/OrganizeArtistModalContent.css +++ /dev/null @@ -1,8 +0,0 @@ -.renameIcon { - margin-left: 5px; -} - -.message { - margin-top: 20px; - margin-bottom: 10px; -} diff --git a/frontend/src/Artist/Editor/Organize/OrganizeArtistModalContent.css.d.ts b/frontend/src/Artist/Editor/Organize/OrganizeArtistModalContent.css.d.ts deleted file mode 100644 index ae2303476..000000000 --- a/frontend/src/Artist/Editor/Organize/OrganizeArtistModalContent.css.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'message': string; - 'renameIcon': string; -} -export const cssExports: CssExports; -export default cssExports; diff --git a/frontend/src/Artist/Editor/Organize/OrganizeArtistModalContent.js b/frontend/src/Artist/Editor/Organize/OrganizeArtistModalContent.js deleted file mode 100644 index 8185a403a..000000000 --- a/frontend/src/Artist/Editor/Organize/OrganizeArtistModalContent.js +++ /dev/null @@ -1,75 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import Alert from 'Components/Alert'; -import Icon from 'Components/Icon'; -import Button from 'Components/Link/Button'; -import ModalBody from 'Components/Modal/ModalBody'; -import ModalContent from 'Components/Modal/ModalContent'; -import ModalFooter from 'Components/Modal/ModalFooter'; -import ModalHeader from 'Components/Modal/ModalHeader'; -import { icons, kinds } from 'Helpers/Props'; -import translate from 'Utilities/String/translate'; -import styles from './OrganizeArtistModalContent.css'; - -function OrganizeArtistModalContent(props) { - const { - artistNames, - onModalClose, - onOrganizeArtistPress - } = props; - - return ( - - - {translate('OrganizeSelectedArtists')} - - - - - Tip: To preview a rename, select "Cancel", then select any artist name and use the - - - -
- Are you sure you want to organize all files in the {artistNames.length} selected artist? -
- -
    - { - artistNames.map((artistName) => { - return ( -
  • - {artistName} -
  • - ); - }) - } -
-
- - - - - - -
- ); -} - -OrganizeArtistModalContent.propTypes = { - artistNames: PropTypes.arrayOf(PropTypes.string).isRequired, - onModalClose: PropTypes.func.isRequired, - onOrganizeArtistPress: PropTypes.func.isRequired -}; - -export default OrganizeArtistModalContent; diff --git a/frontend/src/Artist/Editor/Organize/OrganizeArtistModalContentConnector.js b/frontend/src/Artist/Editor/Organize/OrganizeArtistModalContentConnector.js deleted file mode 100644 index 3fad07da0..000000000 --- a/frontend/src/Artist/Editor/Organize/OrganizeArtistModalContentConnector.js +++ /dev/null @@ -1,67 +0,0 @@ -import _ from 'lodash'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; -import * as commandNames from 'Commands/commandNames'; -import { executeCommand } from 'Store/Actions/commandActions'; -import createAllArtistSelector from 'Store/Selectors/createAllArtistSelector'; -import OrganizeArtistModalContent from './OrganizeArtistModalContent'; - -function createMapStateToProps() { - return createSelector( - (state, { artistIds }) => artistIds, - createAllArtistSelector(), - (artistIds, allArtists) => { - const artist = _.intersectionWith(allArtists, artistIds, (s, id) => { - return s.id === id; - }); - - const sortedArtist = _.orderBy(artist, 'sortName'); - const artistNames = _.map(sortedArtist, 'artistName'); - - return { - artistNames - }; - } - ); -} - -const mapDispatchToProps = { - executeCommand -}; - -class OrganizeArtistModalContentConnector extends Component { - - // - // Listeners - - onOrganizeArtistPress = () => { - this.props.executeCommand({ - name: commandNames.RENAME_ARTIST, - artistIds: this.props.artistIds - }); - - this.props.onModalClose(true); - }; - - // - // Render - - render(props) { - return ( - - ); - } -} - -OrganizeArtistModalContentConnector.propTypes = { - artistIds: PropTypes.arrayOf(PropTypes.number).isRequired, - onModalClose: PropTypes.func.isRequired, - executeCommand: PropTypes.func.isRequired -}; - -export default connect(createMapStateToProps, mapDispatchToProps)(OrganizeArtistModalContentConnector); diff --git a/frontend/src/Artist/Editor/Tags/TagsModal.js b/frontend/src/Artist/Editor/Tags/TagsModal.js deleted file mode 100644 index 0f6c2d7ec..000000000 --- a/frontend/src/Artist/Editor/Tags/TagsModal.js +++ /dev/null @@ -1,31 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import Modal from 'Components/Modal/Modal'; -import TagsModalContentConnector from './TagsModalContentConnector'; - -function TagsModal(props) { - const { - isOpen, - onModalClose, - ...otherProps - } = props; - - return ( - - - - ); -} - -TagsModal.propTypes = { - isOpen: PropTypes.bool.isRequired, - onModalClose: PropTypes.func.isRequired -}; - -export default TagsModal; diff --git a/frontend/src/Artist/Editor/Tags/TagsModalContent.css b/frontend/src/Artist/Editor/Tags/TagsModalContent.css deleted file mode 100644 index 63be9aadd..000000000 --- a/frontend/src/Artist/Editor/Tags/TagsModalContent.css +++ /dev/null @@ -1,12 +0,0 @@ -.renameIcon { - margin-left: 5px; -} - -.message { - margin-top: 20px; - margin-bottom: 10px; -} - -.result { - padding-top: 4px; -} diff --git a/frontend/src/Artist/Editor/Tags/TagsModalContent.css.d.ts b/frontend/src/Artist/Editor/Tags/TagsModalContent.css.d.ts deleted file mode 100644 index 9b4321dcc..000000000 --- a/frontend/src/Artist/Editor/Tags/TagsModalContent.css.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'message': string; - 'renameIcon': string; - 'result': string; -} -export const cssExports: CssExports; -export default cssExports; diff --git a/frontend/src/Artist/Editor/Tags/TagsModalContent.js b/frontend/src/Artist/Editor/Tags/TagsModalContent.js deleted file mode 100644 index 5245ba097..000000000 --- a/frontend/src/Artist/Editor/Tags/TagsModalContent.js +++ /dev/null @@ -1,194 +0,0 @@ -import _ from 'lodash'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import Form from 'Components/Form/Form'; -import FormGroup from 'Components/Form/FormGroup'; -import FormInputGroup from 'Components/Form/FormInputGroup'; -import FormLabel from 'Components/Form/FormLabel'; -import Label from 'Components/Label'; -import Button from 'Components/Link/Button'; -import ModalBody from 'Components/Modal/ModalBody'; -import ModalContent from 'Components/Modal/ModalContent'; -import ModalFooter from 'Components/Modal/ModalFooter'; -import ModalHeader from 'Components/Modal/ModalHeader'; -import { inputTypes, kinds, sizes } from 'Helpers/Props'; -import translate from 'Utilities/String/translate'; -import styles from './TagsModalContent.css'; - -class TagsModalContent extends Component { - - // - // Lifecycle - - constructor(props, context) { - super(props, context); - - this.state = { - tags: [], - applyTags: 'add' - }; - } - - // - // Lifecycle - - onInputChange = ({ name, value }) => { - this.setState({ [name]: value }); - }; - - onApplyTagsPress = () => { - const { - tags, - applyTags - } = this.state; - - this.props.onApplyTagsPress(tags, applyTags); - }; - - // - // Render - - render() { - const { - artistTags, - tagList, - onModalClose - } = this.props; - - const { - tags, - applyTags - } = this.state; - - const applyTagsOptions = [ - { key: 'add', value: translate('Add') }, - { key: 'remove', value: translate('Remove') }, - { key: 'replace', value: translate('Replace') } - ]; - - return ( - - - Tags - - - -
- - - {translate('Tags')} - - - - - - - - {translate('ApplyTags')} - - - - - - - - {translate('Result')} - - -
- { - artistTags.map((t) => { - const tag = _.find(tagList, { id: t }); - - if (!tag) { - return null; - } - - const removeTag = (applyTags === 'remove' && tags.indexOf(t) > -1) || - (applyTags === 'replace' && tags.indexOf(t) === -1); - - return ( - - ); - }) - } - - { - (applyTags === 'add' || applyTags === 'replace') && - tags.map((t) => { - const tag = _.find(tagList, { id: t }); - - if (!tag) { - return null; - } - - if (artistTags.indexOf(t) > -1) { - return null; - } - - return ( - - ); - }) - } -
-
-
-
- - - - - - -
- ); - } -} - -TagsModalContent.propTypes = { - artistTags: PropTypes.arrayOf(PropTypes.number).isRequired, - tagList: PropTypes.arrayOf(PropTypes.object).isRequired, - onModalClose: PropTypes.func.isRequired, - onApplyTagsPress: PropTypes.func.isRequired -}; - -export default TagsModalContent; diff --git a/frontend/src/Artist/Editor/Tags/TagsModalContentConnector.js b/frontend/src/Artist/Editor/Tags/TagsModalContentConnector.js deleted file mode 100644 index 6741e8b5c..000000000 --- a/frontend/src/Artist/Editor/Tags/TagsModalContentConnector.js +++ /dev/null @@ -1,36 +0,0 @@ -import _ from 'lodash'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; -import createAllArtistSelector from 'Store/Selectors/createAllArtistSelector'; -import createTagsSelector from 'Store/Selectors/createTagsSelector'; -import TagsModalContent from './TagsModalContent'; - -function createMapStateToProps() { - return createSelector( - (state, { artistIds }) => artistIds, - createAllArtistSelector(), - createTagsSelector(), - (artistIds, allArtists, tagList) => { - const artist = _.intersectionWith(allArtists, artistIds, (s, id) => { - return s.id === id; - }); - - const artistTags = _.uniq(_.concat(..._.map(artist, 'tags'))); - - return { - artistTags, - tagList - }; - } - ); -} - -function createMapDispatchToProps(dispatch, props) { - return { - onAction() { - // Do something - } - }; -} - -export default connect(createMapStateToProps, createMapDispatchToProps)(TagsModalContent); diff --git a/frontend/src/Components/Page/Sidebar/PageSidebar.js b/frontend/src/Components/Page/Sidebar/PageSidebar.js index 583a604bd..7eed54e68 100644 --- a/frontend/src/Components/Page/Sidebar/PageSidebar.js +++ b/frontend/src/Components/Page/Sidebar/PageSidebar.js @@ -29,10 +29,6 @@ const links = [ title: () => translate('AddNew'), to: '/add/search' }, - { - title: () => translate('MassEditor'), - to: '/artisteditor' - }, { title: () => translate('AlbumStudio'), to: '/albumstudio' diff --git a/frontend/src/Store/Actions/artistEditorActions.js b/frontend/src/Store/Actions/artistEditorActions.js deleted file mode 100644 index 15bd8f542..000000000 --- a/frontend/src/Store/Actions/artistEditorActions.js +++ /dev/null @@ -1,259 +0,0 @@ -import { createAction } from 'redux-actions'; -import { batchActions } from 'redux-batched-actions'; -import { filterBuilderTypes, filterBuilderValueTypes, sortDirections } from 'Helpers/Props'; -import { createThunk, handleThunks } from 'Store/thunks'; -import createAjaxRequest from 'Utilities/createAjaxRequest'; -import translate from 'Utilities/String/translate'; -import { filterPredicates, filters, sortPredicates } from './artistActions'; -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 - -export const section = 'artistEditor'; - -// -// State - -export const defaultState = { - isSaving: false, - saveError: null, - isDeleting: false, - deleteError: null, - sortKey: 'sortName', - sortDirection: sortDirections.ASCENDING, - secondarySortKey: 'sortName', - secondarySortDirection: sortDirections.ASCENDING, - selectedFilterKey: 'all', - filters, - filterPredicates, - - columns: [ - { - name: 'status', - columnLabel: () => translate('Status'), - isSortable: true, - isVisible: true, - isModifiable: false - }, - { - name: 'sortName', - label: () => translate('Name'), - isSortable: true, - isVisible: true - }, - { - name: 'monitorNewItems', - label: () => translate('MonitorNewItems'), - isSortable: true, - isVisible: true - }, - { - name: 'qualityProfileId', - label: () => translate('QualityProfile'), - isSortable: true, - isVisible: true - }, - { - name: 'metadataProfileId', - label: () => translate('MetadataProfile'), - isSortable: true, - isVisible: true - }, - { - name: 'path', - label: () => translate('Path'), - isSortable: true, - isVisible: true - }, - { - name: 'sizeOnDisk', - label: () => translate('SizeOnDisk'), - isSortable: true, - isVisible: false - }, - { - name: 'tags', - label: () => translate('Tags'), - isSortable: true, - isVisible: true - } - ], - - filterBuilderProps: [ - { - name: 'monitored', - label: () => translate('Monitored'), - type: filterBuilderTypes.EXACT, - valueType: filterBuilderValueTypes.BOOL - }, - { - name: 'status', - label: () => translate('Status'), - type: filterBuilderTypes.EXACT, - valueType: filterBuilderValueTypes.ARTIST_STATUS - }, - { - name: 'qualityProfileId', - label: () => translate('QualityProfile'), - type: filterBuilderTypes.EXACT, - valueType: filterBuilderValueTypes.QUALITY_PROFILE - }, - { - name: 'metadataProfileId', - label: () => translate('MetadataProfile'), - type: filterBuilderTypes.EXACT, - valueType: filterBuilderValueTypes.METADATA_PROFILE - }, - { - name: 'path', - label: () => translate('Path'), - type: filterBuilderTypes.STRING - }, - { - name: 'rootFolderPath', - label: () => translate('RootFolderPath'), - type: filterBuilderTypes.EXACT - }, - { - name: 'sizeOnDisk', - label: () => translate('SizeOnDisk'), - type: filterBuilderTypes.NUMBER, - valueType: filterBuilderValueTypes.BYTES - }, - { - name: 'tags', - label: () => translate('Tags'), - type: filterBuilderTypes.ARRAY, - valueType: filterBuilderValueTypes.TAG - } - ], - - sortPredicates -}; - -export const persistState = [ - 'artistEditor.sortKey', - 'artistEditor.sortDirection', - 'artistEditor.selectedFilterKey', - 'artistEditor.customFilters', - 'artistEditor.columns' -]; - -// -// Actions Types - -export const SET_ARTIST_EDITOR_SORT = 'artistEditor/setArtistEditorSort'; -export const SET_ARTIST_EDITOR_FILTER = 'artistEditor/setArtistEditorFilter'; -export const SAVE_ARTIST_EDITOR = 'artistEditor/saveArtistEditor'; -export const BULK_DELETE_ARTIST = 'artistEditor/bulkDeleteArtist'; -export const SET_ARTIST_EDITOR_TABLE_OPTION = 'artistEditor/setArtistEditorTableOption'; - -// -// Action Creators - -export const setArtistEditorSort = createAction(SET_ARTIST_EDITOR_SORT); -export const setArtistEditorFilter = createAction(SET_ARTIST_EDITOR_FILTER); -export const saveArtistEditor = createThunk(SAVE_ARTIST_EDITOR); -export const bulkDeleteArtist = createThunk(BULK_DELETE_ARTIST); -export const setArtistEditorTableOption = createAction(SET_ARTIST_EDITOR_TABLE_OPTION); - -// -// Action Handlers - -export const actionHandlers = handleThunks({ - [SAVE_ARTIST_EDITOR]: function(getState, payload, dispatch) { - dispatch(set({ - section, - isSaving: true - })); - - const promise = createAjaxRequest({ - url: '/artist/editor', - method: 'PUT', - data: JSON.stringify(payload), - dataType: 'json' - }).request; - - promise.done((data) => { - dispatch(batchActions([ - ...data.map((artist) => { - - const { - images, - rootFolderPath, - statistics, - ...propsToUpdate - } = artist; - - return updateItem({ - id: artist.id, - section: 'artist', - ...propsToUpdate - }); - }), - - set({ - section, - isSaving: false, - saveError: null - }) - ])); - }); - - promise.fail((xhr) => { - dispatch(set({ - section, - isSaving: false, - saveError: xhr - })); - }); - }, - - [BULK_DELETE_ARTIST]: function(getState, payload, dispatch) { - dispatch(set({ - section, - isDeleting: true - })); - - const promise = createAjaxRequest({ - url: '/artist/editor', - method: 'DELETE', - data: JSON.stringify(payload), - dataType: 'json' - }).request; - - promise.done(() => { - // SignalR will take care of removing the artist from the collection - - dispatch(set({ - section, - isDeleting: false, - deleteError: null - })); - }); - - promise.fail((xhr) => { - dispatch(set({ - section, - isDeleting: false, - deleteError: xhr - })); - }); - } -}); - -// -// Reducers - -export const reducers = createHandleActions({ - - [SET_ARTIST_EDITOR_TABLE_OPTION]: createSetTableOptionReducer(section), - [SET_ARTIST_EDITOR_SORT]: createSetClientSideCollectionSortReducer(section), - [SET_ARTIST_EDITOR_FILTER]: createSetClientSideCollectionFilterReducer(section) - -}, defaultState, section); diff --git a/frontend/src/Store/Actions/index.js b/frontend/src/Store/Actions/index.js index 577c19c6b..d82b9790f 100644 --- a/frontend/src/Store/Actions/index.js +++ b/frontend/src/Store/Actions/index.js @@ -3,7 +3,6 @@ import * as albumHistory from './albumHistoryActions'; import * as albumStudio from './albumStudioActions'; import * as app from './appActions'; import * as artist from './artistActions'; -import * as artistEditor from './artistEditorActions'; import * as artistHistory from './artistHistoryActions'; import * as artistIndex from './artistIndexActions'; import * as blocklist from './blocklistActions'; @@ -49,7 +48,6 @@ export default [ releases, albumStudio, artist, - artistEditor, artistHistory, artistIndex, search, diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 541b6436e..312b22db2 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -575,7 +575,6 @@ "MarkAsFailedMessageText": "Are you sure you want to mark '{0}' as failed?", "MassAlbumsCutoffUnmetWarning": "Are you sure you want to search for all '{0}' Cutoff Unmet albums?", "MassAlbumsSearchWarning": "Are you sure you want to search for all '{0}' missing albums?", - "MassEditor": "Mass Editor", "MaximumLimits": "Maximum Limits", "MaximumSize": "Maximum Size", "MaximumSizeHelpText": "Maximum size for a release to be grabbed in MB. Set to zero to set to unlimited.",