mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2025-09-17 17:14:18 +02:00
Show Indexer Status on Indexer Table
This commit is contained in:
@@ -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
|
||||
|
46
frontend/src/Store/Actions/indexerStatusActions.js
Normal file
46
frontend/src/Store/Actions/indexerStatusActions.js
Normal file
@@ -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);
|
14
frontend/src/Store/Selectors/createIndexerStatusSelector.js
Normal file
14
frontend/src/Store/Selectors/createIndexerStatusSelector.js
Normal file
@@ -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;
|
Reference in New Issue
Block a user