New: Clear all history from History page

This commit is contained in:
Qstick
2021-04-22 23:43:58 -04:00
parent aa6bda7226
commit eb328d7c22
10 changed files with 98 additions and 17 deletions

View File

@@ -1,5 +1,6 @@
export const APPLICATION_UPDATE = 'ApplicationUpdate'; export const APPLICATION_UPDATE = 'ApplicationUpdate';
export const BACKUP = 'Backup'; export const BACKUP = 'Backup';
export const CLEAR_HISTORY = 'ClearHistory';
export const CLEAR_LOGS = 'ClearLog'; export const CLEAR_LOGS = 'ClearLog';
export const DELETE_LOG_FILES = 'DeleteLogFiles'; export const DELETE_LOG_FILES = 'DeleteLogFiles';
export const DELETE_UPDATE_LOG_FILES = 'DeleteUpdateLogFiles'; export const DELETE_UPDATE_LOG_FILES = 'DeleteUpdateLogFiles';

View File

@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react'; import React, { Component } from 'react';
import LoadingIndicator from 'Components/Loading/LoadingIndicator'; import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import FilterMenu from 'Components/Menu/FilterMenu'; import FilterMenu from 'Components/Menu/FilterMenu';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import PageContent from 'Components/Page/PageContent'; import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody'; import PageContentBody from 'Components/Page/PageContentBody';
import PageToolbar from 'Components/Page/Toolbar/PageToolbar'; import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
@@ -11,13 +12,40 @@ import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody'; import TableBody from 'Components/Table/TableBody';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper'; import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import TablePager from 'Components/Table/TablePager'; 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 translate from 'Utilities/String/translate';
import HistoryOptionsConnector from './HistoryOptionsConnector'; import HistoryOptionsConnector from './HistoryOptionsConnector';
import HistoryRowConnector from './HistoryRowConnector'; import HistoryRowConnector from './HistoryRowConnector';
class History extends Component { 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 // Render
@@ -25,9 +53,10 @@ class History extends Component {
const { const {
isFetching, isFetching,
isPopulated, isPopulated,
isHistoryClearing,
error, error,
isMoviesFetching, isIndexersFetching,
isMoviesPopulated, isIndexersPopulated,
indexersError, indexersError,
items, items,
columns, columns,
@@ -36,11 +65,12 @@ class History extends Component {
totalRecords, totalRecords,
onFilterSelect, onFilterSelect,
onFirstPagePress, onFirstPagePress,
onClearHistoryPress,
...otherProps ...otherProps
} = this.props; } = this.props;
const isFetchingAny = isFetching || isMoviesFetching; const isFetchingAny = isFetching || isIndexersFetching;
const isAllPopulated = isPopulated && (isMoviesPopulated || !items.length); const isAllPopulated = isPopulated && (isIndexersPopulated || !items.length);
const hasError = error || indexersError; const hasError = error || indexersError;
return ( return (
@@ -53,6 +83,12 @@ class History extends Component {
isSpinning={isFetching} isSpinning={isFetching}
onPress={onFirstPagePress} onPress={onFirstPagePress}
/> />
<PageToolbarButton
label={translate('Clear')}
iconName={icons.DELETE}
isSpinning={isHistoryClearing}
onPress={this.onClearHistoryPress}
/>
</PageToolbarSection> </PageToolbarSection>
<PageToolbarSection alignContent={align.RIGHT}> <PageToolbarSection alignContent={align.RIGHT}>
@@ -131,6 +167,16 @@ class History extends Component {
</div> </div>
} }
</PageContentBody> </PageContentBody>
<ConfirmModal
isOpen={this.state.isClearHistoryModalOpen}
kind={kinds.DANGER}
title={translate('ClearHistory')}
message={translate('ClearHistoryMessageText')}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmClearHistory}
onCancel={this.onClearHistoryModalClose}
/>
</PageContent> </PageContent>
); );
} }
@@ -139,9 +185,10 @@ class History extends Component {
History.propTypes = { History.propTypes = {
isFetching: PropTypes.bool.isRequired, isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired, isPopulated: PropTypes.bool.isRequired,
isHistoryClearing: PropTypes.bool.isRequired,
error: PropTypes.object, error: PropTypes.object,
isMoviesFetching: PropTypes.bool.isRequired, isIndexersFetching: PropTypes.bool.isRequired,
isMoviesPopulated: PropTypes.bool.isRequired, isIndexersPopulated: PropTypes.bool.isRequired,
indexersError: PropTypes.object, indexersError: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired, items: PropTypes.arrayOf(PropTypes.object).isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired, columns: PropTypes.arrayOf(PropTypes.object).isRequired,
@@ -149,7 +196,8 @@ History.propTypes = {
filters: PropTypes.arrayOf(PropTypes.object).isRequired, filters: PropTypes.arrayOf(PropTypes.object).isRequired,
totalRecords: PropTypes.number, totalRecords: PropTypes.number,
onFilterSelect: PropTypes.func.isRequired, onFilterSelect: PropTypes.func.isRequired,
onFirstPagePress: PropTypes.func.isRequired onFirstPagePress: PropTypes.func.isRequired,
onClearHistoryPress: PropTypes.func.isRequired
}; };
export default History; export default History;

View File

@@ -2,8 +2,11 @@ import PropTypes from 'prop-types';
import React, { Component } 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 * as commandNames from 'Commands/commandNames';
import withCurrentPage from 'Components/withCurrentPage'; import withCurrentPage from 'Components/withCurrentPage';
import { executeCommand } from 'Store/Actions/commandActions';
import * as historyActions from 'Store/Actions/historyActions'; import * as historyActions from 'Store/Actions/historyActions';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator'; import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
import History from './History'; import History from './History';
@@ -11,11 +14,13 @@ function createMapStateToProps() {
return createSelector( return createSelector(
(state) => state.history, (state) => state.history,
(state) => state.indexers, (state) => state.indexers,
(history, indexers) => { createCommandExecutingSelector(commandNames.CLEAR_HISTORY),
(history, indexers, isHistoryClearing) => {
return { return {
isMoviesFetching: indexers.isFetching, isIndexersFetching: indexers.isFetching,
isMoviesPopulated: indexers.isPopulated, isIndexersPopulated: indexers.isPopulated,
indexersError: indexers.error, indexersError: indexers.error,
isHistoryClearing,
...history ...history
}; };
} }
@@ -23,6 +28,7 @@ function createMapStateToProps() {
} }
const mapDispatchToProps = { const mapDispatchToProps = {
executeCommand,
...historyActions ...historyActions
}; };
@@ -47,6 +53,12 @@ class HistoryConnector extends Component {
} }
} }
componentDidUpdate(prevProps) {
if (prevProps.isHistoryClearing && !this.props.isHistoryClearing) {
this.props.gotoHistoryFirstPage();
}
}
componentWillUnmount() { componentWillUnmount() {
unregisterPagePopulator(this.repopulate); unregisterPagePopulator(this.repopulate);
this.props.clearHistory(); this.props.clearHistory();
@@ -90,6 +102,10 @@ class HistoryConnector extends Component {
this.props.setHistoryFilter({ selectedFilterKey }); this.props.setHistoryFilter({ selectedFilterKey });
} }
onClearHistoryPress = () => {
this.props.executeCommand({ name: commandNames.CLEAR_HISTORY });
}
onTableOptionChange = (payload) => { onTableOptionChange = (payload) => {
this.props.setHistoryTableOption(payload); this.props.setHistoryTableOption(payload);
@@ -112,6 +128,7 @@ class HistoryConnector extends Component {
onSortPress={this.onSortPress} onSortPress={this.onSortPress}
onFilterSelect={this.onFilterSelect} onFilterSelect={this.onFilterSelect}
onTableOptionChange={this.onTableOptionChange} onTableOptionChange={this.onTableOptionChange}
onClearHistoryPress={this.onClearHistoryPress}
{...this.props} {...this.props}
/> />
); );
@@ -122,6 +139,8 @@ HistoryConnector.propTypes = {
useCurrentPage: PropTypes.bool.isRequired, useCurrentPage: PropTypes.bool.isRequired,
items: PropTypes.arrayOf(PropTypes.object).isRequired, items: PropTypes.arrayOf(PropTypes.object).isRequired,
fetchHistory: PropTypes.func.isRequired, fetchHistory: PropTypes.func.isRequired,
clearHistory: PropTypes.func.isRequired,
isHistoryClearing: PropTypes.bool.isRequired,
gotoHistoryFirstPage: PropTypes.func.isRequired, gotoHistoryFirstPage: PropTypes.func.isRequired,
gotoHistoryPreviousPage: PropTypes.func.isRequired, gotoHistoryPreviousPage: PropTypes.func.isRequired,
gotoHistoryNextPage: PropTypes.func.isRequired, gotoHistoryNextPage: PropTypes.func.isRequired,
@@ -130,7 +149,7 @@ HistoryConnector.propTypes = {
setHistorySort: PropTypes.func.isRequired, setHistorySort: PropTypes.func.isRequired,
setHistoryFilter: PropTypes.func.isRequired, setHistoryFilter: PropTypes.func.isRequired,
setHistoryTableOption: PropTypes.func.isRequired, setHistoryTableOption: PropTypes.func.isRequired,
clearHistory: PropTypes.func.isRequired executeCommand: PropTypes.func.isRequired
}; };
export default withCurrentPage( export default withCurrentPage(

View File

@@ -51,8 +51,6 @@ class HistoryRow extends Component {
}); });
} }
console.log(categories);
this.props.onSearchPress(data.query, indexer.id, categories); this.props.onSearchPress(data.query, indexer.id, categories);
} }

View File

@@ -34,7 +34,6 @@ class SearchFooterConnector extends Component {
// Listeners // Listeners
onInputChange = ({ name, value }) => { onInputChange = ({ name, value }) => {
console.log(name, value);
this.props.setSearchDefault({ [name]: value }); this.props.setSearchDefault({ [name]: value });
} }

View File

@@ -108,7 +108,6 @@ export const defaultState = {
sortPredicates: { sortPredicates: {
age: function(item) { age: function(item) {
console.log(item);
return item.ageMinutes; return item.ageMinutes;
}, },

View File

@@ -0,0 +1,9 @@
using NzbDrone.Core.Messaging.Commands;
namespace NzbDrone.Core.History
{
public class ClearHistoryCommand : Command
{
public override bool SendUpdatesToClient => true;
}
}

View File

@@ -31,7 +31,8 @@ namespace NzbDrone.Core.History
IHandle<IndexerQueryEvent>, IHandle<IndexerQueryEvent>,
IHandle<IndexerDownloadEvent>, IHandle<IndexerDownloadEvent>,
IHandle<IndexerAuthEvent>, IHandle<IndexerAuthEvent>,
IExecute<CleanUpHistoryCommand> IExecute<CleanUpHistoryCommand>,
IExecute<ClearHistoryCommand>
{ {
private readonly IHistoryRepository _historyRepository; private readonly IHistoryRepository _historyRepository;
private readonly IConfigService _configService; private readonly IConfigService _configService;
@@ -197,5 +198,10 @@ namespace NzbDrone.Core.History
{ {
Cleanup(); Cleanup();
} }
public void Execute(ClearHistoryCommand message)
{
_historyRepository.Purge(vacuum: true);
}
} }
} }

View File

@@ -47,6 +47,8 @@
"CertificateValidationHelpText": "Change how strict HTTPS certification validation is", "CertificateValidationHelpText": "Change how strict HTTPS certification validation is",
"ChangeHasNotBeenSavedYet": "Change has not been saved yet", "ChangeHasNotBeenSavedYet": "Change has not been saved yet",
"Clear": "Clear", "Clear": "Clear",
"ClearHistory": "Clear History",
"ClearHistoryMessageText": "Are you sure you want to clear all Prowlarr history?",
"ClientPriority": "Client Priority", "ClientPriority": "Client Priority",
"CloneIndexer": "Clone Indexer", "CloneIndexer": "Clone Indexer",
"Close": "Close", "Close": "Close",