Show Indexer Status on Indexer Table

pull/7/head
Qstick 3 years ago
parent a41ae141cd
commit 56d5356f1e

@ -6,6 +6,7 @@ import { createSelector } from 'reselect';
import { saveDimensions, setIsSidebarVisible } from 'Store/Actions/appActions';
import { fetchCustomFilters } from 'Store/Actions/customFilterActions';
import { fetchIndexers } from 'Store/Actions/indexerActions';
import { fetchIndexerStatus } from 'Store/Actions/indexerStatusActions';
import { fetchIndexerCategories, fetchIndexerFlags, fetchLanguages, fetchUISettings } from 'Store/Actions/settingsActions';
import { fetchStatus } from 'Store/Actions/systemActions';
import { fetchTags } from 'Store/Actions/tagActions';
@ -48,6 +49,7 @@ const selectIsPopulated = createSelector(
(state) => state.settings.ui.isPopulated,
(state) => state.settings.languages.isPopulated,
(state) => state.indexers.isPopulated,
(state) => state.indexerStatus.isPopulated,
(state) => state.settings.indexerCategories.isPopulated,
(state) => state.settings.indexerFlags.isPopulated,
(state) => state.system.status.isPopulated,
@ -57,6 +59,7 @@ const selectIsPopulated = createSelector(
uiSettingsIsPopulated,
languagesIsPopulated,
indexersIsPopulated,
indexerStatusIsPopulated,
indexerCategoriesIsPopulated,
indexerFlagsIsPopulated,
systemStatusIsPopulated
@ -67,6 +70,7 @@ const selectIsPopulated = createSelector(
uiSettingsIsPopulated &&
languagesIsPopulated &&
indexersIsPopulated &&
indexerStatusIsPopulated &&
indexerCategoriesIsPopulated &&
indexerFlagsIsPopulated &&
systemStatusIsPopulated
@ -80,6 +84,7 @@ const selectErrors = createSelector(
(state) => state.settings.ui.error,
(state) => state.settings.languages.error,
(state) => state.indexers.error,
(state) => state.indexerStatus.error,
(state) => state.settings.indexerCategories.error,
(state) => state.settings.indexerFlags.error,
(state) => state.system.status.error,
@ -89,6 +94,7 @@ const selectErrors = createSelector(
uiSettingsError,
languagesError,
indexersError,
indexerStatusError,
indexerCategoriesError,
indexerFlagsError,
systemStatusError
@ -99,6 +105,7 @@ const selectErrors = createSelector(
uiSettingsError ||
languagesError ||
indexersError ||
indexerStatusError ||
indexerCategoriesError ||
indexerFlagsError ||
systemStatusError
@ -111,6 +118,7 @@ const selectErrors = createSelector(
uiSettingsError,
languagesError,
indexersError,
indexerStatusError,
indexerCategoriesError,
indexerFlagsError,
systemStatusError
@ -157,6 +165,9 @@ function createMapDispatchToProps(dispatch, props) {
dispatchFetchIndexers() {
dispatch(fetchIndexers());
},
dispatchFetchIndexerStatus() {
dispatch(fetchIndexerStatus());
},
dispatchFetchIndexerCategories() {
dispatch(fetchIndexerCategories());
},
@ -197,6 +208,7 @@ class PageConnector extends Component {
this.props.dispatchFetchTags();
this.props.dispatchFetchLanguages();
this.props.dispatchFetchIndexers();
this.props.dispatchFetchIndexerStatus();
this.props.dispatchFetchIndexerCategories();
this.props.dispatchFetchIndexerFlags();
this.props.dispatchFetchUISettings();
@ -221,6 +233,7 @@ class PageConnector extends Component {
dispatchFetchTags,
dispatchFetchLanguages,
dispatchFetchIndexers,
dispatchFetchIndexerStatus,
dispatchFetchIndexerCategories,
dispatchFetchIndexerFlags,
dispatchFetchUISettings,
@ -260,6 +273,7 @@ PageConnector.propTypes = {
dispatchFetchTags: PropTypes.func.isRequired,
dispatchFetchLanguages: PropTypes.func.isRequired,
dispatchFetchIndexers: PropTypes.func.isRequired,
dispatchFetchIndexerStatus: PropTypes.func.isRequired,
dispatchFetchIndexerCategories: PropTypes.func.isRequired,
dispatchFetchIndexerFlags: PropTypes.func.isRequired,
dispatchFetchUISettings: PropTypes.func.isRequired,

@ -6,6 +6,8 @@ import * as commandNames from 'Commands/commandNames';
import { executeCommand } from 'Store/Actions/commandActions';
import createExecutingCommandsSelector from 'Store/Selectors/createExecutingCommandsSelector';
import createIndexerSelector from 'Store/Selectors/createIndexerSelector';
import createIndexerStatusSelector from 'Store/Selectors/createIndexerStatusSelector';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
function selectShowSearchAction() {
return createSelector(
@ -19,12 +21,16 @@ function selectShowSearchAction() {
function createMapStateToProps() {
return createSelector(
createIndexerSelector(),
createIndexerStatusSelector(),
selectShowSearchAction(),
createExecutingCommandsSelector(),
createUISettingsSelector(),
(
movie,
status,
showSearchAction,
executingCommands
executingCommands,
uiSettings
) => {
// If a movie is deleted this selector may fire before the parent
@ -32,6 +38,8 @@ function createMapStateToProps() {
// we want to return early here and again in the render function to avoid
// trying to show a movie that has no information available.
console.log(status);
if (!movie) {
return {};
}
@ -52,9 +60,12 @@ function createMapStateToProps() {
return {
...movie,
status,
showSearchAction,
isRefreshingMovie,
isSearchingMovie
isSearchingMovie,
longDateFormat: uiSettings.longDateFormat,
timeFormat: uiSettings.timeFormat
};
}
);

@ -3,12 +3,16 @@ import React from 'react';
import Icon from 'Components/Icon';
import VirtualTableRowCell from 'Components/Table/Cells/TableRowCell';
import { icons, kinds } from 'Helpers/Props';
import formatDateTime from 'Utilities/Date/formatDateTime';
import styles from './IndexerStatusCell.css';
function IndexerStatusCell(props) {
const {
className,
enabled,
status,
longDateFormat,
timeFormat,
component: Component,
...otherProps
} = props;
@ -26,6 +30,15 @@ function IndexerStatusCell(props) {
title={enabled ? 'Indexer is Enabled' : 'Indexer is Disabled'}
/>
}
{
status &&
<Icon
className={styles.statusIcon}
kind={kinds.DANGER}
name={icons.WARNING}
title={`Indexer is Disabled due to failures until ${formatDateTime(status.disabledTill, longDateFormat, timeFormat)}`}
/>
}
</Component>
);
}
@ -33,6 +46,9 @@ function IndexerStatusCell(props) {
IndexerStatusCell.propTypes = {
className: PropTypes.string.isRequired,
enabled: PropTypes.bool.isRequired,
status: PropTypes.object,
longDateFormat: PropTypes.string.isRequired,
timeFormat: PropTypes.string.isRequired,
component: PropTypes.elementType
};

@ -68,9 +68,12 @@ class MovieIndexRow extends Component {
protocol,
privacy,
priority,
status,
added,
capabilities,
columns,
longDateFormat,
timeFormat,
isMovieEditorActive,
isSelected,
onSelectedChange
@ -113,6 +116,8 @@ class MovieIndexRow extends Component {
className={styles[column.name]}
enabled={enableRss || enableAutomaticSearch || enableInteractiveSearch}
status={status}
longDateFormat={longDateFormat}
timeFormat={timeFormat}
component={VirtualTableRowCell}
/>
);
@ -253,6 +258,7 @@ MovieIndexRow.propTypes = {
enableRss: PropTypes.bool.isRequired,
enableAutomaticSearch: PropTypes.bool.isRequired,
enableInteractiveSearch: PropTypes.bool.isRequired,
status: PropTypes.object,
capabilities: PropTypes.object.isRequired,
added: PropTypes.string.isRequired,
tags: PropTypes.arrayOf(PropTypes.number).isRequired,
@ -260,7 +266,9 @@ MovieIndexRow.propTypes = {
isSearchingMovie: PropTypes.bool.isRequired,
isMovieEditorActive: PropTypes.bool.isRequired,
isSelected: PropTypes.bool,
onSelectedChange: PropTypes.func.isRequired
onSelectedChange: PropTypes.func.isRequired,
longDateFormat: PropTypes.string.isRequired,
timeFormat: PropTypes.string.isRequired
};
MovieIndexRow.defaultProps = {

@ -6,6 +6,7 @@ import * as history from './historyActions';
import * as indexers from './indexerActions';
import * as indexerIndex from './indexerIndexActions';
import * as indexerStats from './indexerStatsActions';
import * as indexerStatus from './indexerStatusActions';
import * as movies from './movieActions';
import * as oAuth from './oAuthActions';
import * as paths from './pathActions';
@ -29,6 +30,7 @@ export default [
indexers,
indexerIndex,
indexerStats,
indexerStatus,
settings,
system,
tags

@ -0,0 +1,46 @@
import { createThunk, handleThunks } from 'Store/thunks';
import createFetchHandler from './Creators/createFetchHandler';
import createHandleActions from './Creators/createHandleActions';
//
// Variables
export const section = 'indexerStatus';
//
// State
export const defaultState = {
isFetching: false,
isPopulated: false,
error: null,
items: [],
details: {
isFetching: false,
isPopulated: false,
error: null,
items: []
}
};
//
// Actions Types
export const FETCH_INDEXER_STATUS = 'indexerStatus/fetchIndexerStatus';
//
// Action Creators
export const fetchIndexerStatus = createThunk(FETCH_INDEXER_STATUS);
//
// Action Handlers
export const actionHandlers = handleThunks({
[FETCH_INDEXER_STATUS]: createFetchHandler(section, '/indexerStatus')
});
//
// Reducers
export const reducers = createHandleActions({}, defaultState, section);

@ -0,0 +1,14 @@
import _ from 'lodash';
import { createSelector } from 'reselect';
function createIndexerStatusSelector() {
return createSelector(
(state, { indexerId }) => indexerId,
(state) => state.indexerStatus.items,
(indexerId, indexerStatus) => {
return _.find(indexerStatus, { indexerId });
}
);
}
export default createIndexerStatusSelector;

@ -20,6 +20,7 @@ namespace Prowlarr.Api.V1.Indexers
public IndexerCapabilityResource Capabilities { get; set; }
public int Priority { get; set; }
public DateTime Added { get; set; }
public IndexerStatusResource Status { get; set; }
}
public class IndexerResourceMapper : ProviderResourceMapper<IndexerResource, IndexerDefinition>

@ -0,0 +1,23 @@
using System.Collections.Generic;
using NzbDrone.Core.Indexers;
using Prowlarr.Http;
namespace Prowlarr.Api.V1.Indexers
{
public class IndexerStatusModule : ProwlarrRestModule<IndexerStatusResource>
{
private readonly IIndexerStatusService _indexerStatusService;
public IndexerStatusModule(IIndexerStatusService indexerStatusService)
{
_indexerStatusService = indexerStatusService;
GetResourceAll = GetAll;
}
private List<IndexerStatusResource> GetAll()
{
return _indexerStatusService.GetBlockedProviders().ToResource();
}
}
}

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Indexers;
using Prowlarr.Http.REST;
namespace Prowlarr.Api.V1.Indexers
{
public class IndexerStatusResource : RestResource
{
public int IndexerId { get; set; }
public DateTime? DisabledTill { get; set; }
}
public static class IndexerStatusResourceMapper
{
public static IndexerStatusResource ToResource(this IndexerStatus model)
{
if (model == null)
{
return null;
}
return new IndexerStatusResource
{
IndexerId = model.ProviderId,
DisabledTill = model.DisabledTill
};
}
public static List<IndexerStatusResource> ToResource(this IEnumerable<IndexerStatus> models)
{
return models.Select(ToResource).ToList();
}
}
}
Loading…
Cancel
Save