diff --git a/frontend/src/Commands/commandNames.js b/frontend/src/Commands/commandNames.js index ac6fd2b27..7028d46cd 100644 --- a/frontend/src/Commands/commandNames.js +++ b/frontend/src/Commands/commandNames.js @@ -1,5 +1,6 @@ export const APPLICATION_UPDATE = 'ApplicationUpdate'; export const BACKUP = 'Backup'; +export const CLEAR_HISTORY = 'ClearHistory'; export const CLEAR_LOGS = 'ClearLog'; export const DELETE_LOG_FILES = 'DeleteLogFiles'; export const DELETE_UPDATE_LOG_FILES = 'DeleteUpdateLogFiles'; diff --git a/frontend/src/History/History.js b/frontend/src/History/History.js index 9cb71c1df..c4fb34fe4 100644 --- a/frontend/src/History/History.js +++ b/frontend/src/History/History.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import LoadingIndicator from 'Components/Loading/LoadingIndicator'; import FilterMenu from 'Components/Menu/FilterMenu'; +import ConfirmModal from 'Components/Modal/ConfirmModal'; import PageContent from 'Components/Page/PageContent'; import PageContentBody from 'Components/Page/PageContentBody'; import PageToolbar from 'Components/Page/Toolbar/PageToolbar'; @@ -11,13 +12,40 @@ import Table from 'Components/Table/Table'; import TableBody from 'Components/Table/TableBody'; import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper'; import TablePager from 'Components/Table/TablePager'; -import { align, icons } from 'Helpers/Props'; +import { align, icons, kinds } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; import HistoryOptionsConnector from './HistoryOptionsConnector'; import HistoryRowConnector from './HistoryRowConnector'; class History extends Component { + // + // Lifecycle + + constructor(props, context) { + super(props, context); + + this.state = { + isClearHistoryModalOpen: false + }; + } + + // + // Listeners + + onClearHistoryPress = () => { + this.setState({ isClearHistoryModalOpen: true }); + } + + onClearHistoryModalClose = () => { + this.setState({ isClearHistoryModalOpen: false }); + } + + onConfirmClearHistory = () => { + this.setState({ isClearHistoryModalOpen: false }); + this.props.onClearHistoryPress(); + } + // // Render @@ -25,9 +53,10 @@ class History extends Component { const { isFetching, isPopulated, + isHistoryClearing, error, - isMoviesFetching, - isMoviesPopulated, + isIndexersFetching, + isIndexersPopulated, indexersError, items, columns, @@ -36,11 +65,12 @@ class History extends Component { totalRecords, onFilterSelect, onFirstPagePress, + onClearHistoryPress, ...otherProps } = this.props; - const isFetchingAny = isFetching || isMoviesFetching; - const isAllPopulated = isPopulated && (isMoviesPopulated || !items.length); + const isFetchingAny = isFetching || isIndexersFetching; + const isAllPopulated = isPopulated && (isIndexersPopulated || !items.length); const hasError = error || indexersError; return ( @@ -53,6 +83,12 @@ class History extends Component { isSpinning={isFetching} onPress={onFirstPagePress} /> + @@ -131,6 +167,16 @@ class History extends Component { } + + ); } @@ -139,9 +185,10 @@ class History extends Component { History.propTypes = { isFetching: PropTypes.bool.isRequired, isPopulated: PropTypes.bool.isRequired, + isHistoryClearing: PropTypes.bool.isRequired, error: PropTypes.object, - isMoviesFetching: PropTypes.bool.isRequired, - isMoviesPopulated: PropTypes.bool.isRequired, + isIndexersFetching: PropTypes.bool.isRequired, + isIndexersPopulated: PropTypes.bool.isRequired, indexersError: PropTypes.object, items: PropTypes.arrayOf(PropTypes.object).isRequired, columns: PropTypes.arrayOf(PropTypes.object).isRequired, @@ -149,7 +196,8 @@ History.propTypes = { filters: PropTypes.arrayOf(PropTypes.object).isRequired, totalRecords: PropTypes.number, onFilterSelect: PropTypes.func.isRequired, - onFirstPagePress: PropTypes.func.isRequired + onFirstPagePress: PropTypes.func.isRequired, + onClearHistoryPress: PropTypes.func.isRequired }; export default History; diff --git a/frontend/src/History/HistoryConnector.js b/frontend/src/History/HistoryConnector.js index bd4308afc..cede42e57 100644 --- a/frontend/src/History/HistoryConnector.js +++ b/frontend/src/History/HistoryConnector.js @@ -2,8 +2,11 @@ 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 withCurrentPage from 'Components/withCurrentPage'; +import { executeCommand } from 'Store/Actions/commandActions'; import * as historyActions from 'Store/Actions/historyActions'; +import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector'; import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator'; import History from './History'; @@ -11,11 +14,13 @@ function createMapStateToProps() { return createSelector( (state) => state.history, (state) => state.indexers, - (history, indexers) => { + createCommandExecutingSelector(commandNames.CLEAR_HISTORY), + (history, indexers, isHistoryClearing) => { return { - isMoviesFetching: indexers.isFetching, - isMoviesPopulated: indexers.isPopulated, + isIndexersFetching: indexers.isFetching, + isIndexersPopulated: indexers.isPopulated, indexersError: indexers.error, + isHistoryClearing, ...history }; } @@ -23,6 +28,7 @@ function createMapStateToProps() { } const mapDispatchToProps = { + executeCommand, ...historyActions }; @@ -47,6 +53,12 @@ class HistoryConnector extends Component { } } + componentDidUpdate(prevProps) { + if (prevProps.isHistoryClearing && !this.props.isHistoryClearing) { + this.props.gotoHistoryFirstPage(); + } + } + componentWillUnmount() { unregisterPagePopulator(this.repopulate); this.props.clearHistory(); @@ -90,6 +102,10 @@ class HistoryConnector extends Component { this.props.setHistoryFilter({ selectedFilterKey }); } + onClearHistoryPress = () => { + this.props.executeCommand({ name: commandNames.CLEAR_HISTORY }); + } + onTableOptionChange = (payload) => { this.props.setHistoryTableOption(payload); @@ -112,6 +128,7 @@ class HistoryConnector extends Component { onSortPress={this.onSortPress} onFilterSelect={this.onFilterSelect} onTableOptionChange={this.onTableOptionChange} + onClearHistoryPress={this.onClearHistoryPress} {...this.props} /> ); @@ -122,6 +139,8 @@ HistoryConnector.propTypes = { useCurrentPage: PropTypes.bool.isRequired, items: PropTypes.arrayOf(PropTypes.object).isRequired, fetchHistory: PropTypes.func.isRequired, + clearHistory: PropTypes.func.isRequired, + isHistoryClearing: PropTypes.bool.isRequired, gotoHistoryFirstPage: PropTypes.func.isRequired, gotoHistoryPreviousPage: PropTypes.func.isRequired, gotoHistoryNextPage: PropTypes.func.isRequired, @@ -130,7 +149,7 @@ HistoryConnector.propTypes = { setHistorySort: PropTypes.func.isRequired, setHistoryFilter: PropTypes.func.isRequired, setHistoryTableOption: PropTypes.func.isRequired, - clearHistory: PropTypes.func.isRequired + executeCommand: PropTypes.func.isRequired }; export default withCurrentPage( diff --git a/frontend/src/History/HistoryRow.js b/frontend/src/History/HistoryRow.js index 9f66e7194..d45fd3770 100644 --- a/frontend/src/History/HistoryRow.js +++ b/frontend/src/History/HistoryRow.js @@ -51,8 +51,6 @@ class HistoryRow extends Component { }); } - console.log(categories); - this.props.onSearchPress(data.query, indexer.id, categories); } diff --git a/frontend/src/Search/SearchFooterConnector.js b/frontend/src/Search/SearchFooterConnector.js index f5647fe77..c4afc5979 100644 --- a/frontend/src/Search/SearchFooterConnector.js +++ b/frontend/src/Search/SearchFooterConnector.js @@ -34,7 +34,6 @@ class SearchFooterConnector extends Component { // Listeners onInputChange = ({ name, value }) => { - console.log(name, value); this.props.setSearchDefault({ [name]: value }); } diff --git a/frontend/src/Store/Actions/releaseActions.js b/frontend/src/Store/Actions/releaseActions.js index d1dc5237d..b9272ef9c 100644 --- a/frontend/src/Store/Actions/releaseActions.js +++ b/frontend/src/Store/Actions/releaseActions.js @@ -108,7 +108,6 @@ export const defaultState = { sortPredicates: { age: function(item) { - console.log(item); return item.ageMinutes; }, diff --git a/src/NzbDrone.Core/History/CleanupHistoryCommand.cs b/src/NzbDrone.Core/History/Commands/CleanupHistoryCommand.cs similarity index 100% rename from src/NzbDrone.Core/History/CleanupHistoryCommand.cs rename to src/NzbDrone.Core/History/Commands/CleanupHistoryCommand.cs diff --git a/src/NzbDrone.Core/History/Commands/ClearHistoryCommand.cs b/src/NzbDrone.Core/History/Commands/ClearHistoryCommand.cs new file mode 100644 index 000000000..c5c8ba14a --- /dev/null +++ b/src/NzbDrone.Core/History/Commands/ClearHistoryCommand.cs @@ -0,0 +1,9 @@ +using NzbDrone.Core.Messaging.Commands; + +namespace NzbDrone.Core.History +{ + public class ClearHistoryCommand : Command + { + public override bool SendUpdatesToClient => true; + } +} diff --git a/src/NzbDrone.Core/History/HistoryService.cs b/src/NzbDrone.Core/History/HistoryService.cs index 0f9c56f88..86a7dccb0 100644 --- a/src/NzbDrone.Core/History/HistoryService.cs +++ b/src/NzbDrone.Core/History/HistoryService.cs @@ -31,7 +31,8 @@ namespace NzbDrone.Core.History IHandle, IHandle, IHandle, - IExecute + IExecute, + IExecute { private readonly IHistoryRepository _historyRepository; private readonly IConfigService _configService; @@ -197,5 +198,10 @@ namespace NzbDrone.Core.History { Cleanup(); } + + public void Execute(ClearHistoryCommand message) + { + _historyRepository.Purge(vacuum: true); + } } } diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 7cd380757..9d2938823 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -47,6 +47,8 @@ "CertificateValidationHelpText": "Change how strict HTTPS certification validation is", "ChangeHasNotBeenSavedYet": "Change has not been saved yet", "Clear": "Clear", + "ClearHistory": "Clear History", + "ClearHistoryMessageText": "Are you sure you want to clear all Prowlarr history?", "ClientPriority": "Client Priority", "CloneIndexer": "Clone Indexer", "Close": "Close",