New: Improved Indexer disabled popover

pull/1485/head
Qstick 1 year ago
parent 0e82899958
commit 6482509a1d

@ -0,0 +1,11 @@
.title {
composes: title from '~Components/DescriptionList/DescriptionListItemTitle.css';
width: 90px;
}
.description {
composes: title from '~Components/DescriptionList/DescriptionListItemDescription.css';
margin-left: 110px;
}

@ -0,0 +1,8 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'description': string;
'title': string;
}
export const cssExports: CssExports;
export default cssExports;

@ -0,0 +1,51 @@
import React from 'react';
import DescriptionList from 'Components/DescriptionList/DescriptionList';
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
import formatDateTime from 'Utilities/Date/formatDateTime';
import translate from 'Utilities/String/translate';
import styles from './DisabledIndexerInfo.css';
interface DisabledIndexerInfoProps {
mostRecentFailure: Date;
disabledTill: Date;
initialFailure: Date;
longDateFormat: string;
timeFormat: string;
}
function DisabledIndexerInfo(props: DisabledIndexerInfoProps) {
const {
mostRecentFailure,
disabledTill,
initialFailure,
longDateFormat,
timeFormat,
} = props;
return (
<DescriptionList>
<DescriptionListItem
titleClassName={styles.title}
descriptionClassName={styles.description}
title={translate('InitialFailure')}
data={formatDateTime(initialFailure, longDateFormat, timeFormat)}
/>
<DescriptionListItem
titleClassName={styles.title}
descriptionClassName={styles.description}
title={translate('LastFailure')}
data={formatDateTime(mostRecentFailure, longDateFormat, timeFormat)}
/>
<DescriptionListItem
titleClassName={styles.title}
descriptionClassName={styles.description}
title={translate('DisabledUntil')}
data={formatDateTime(disabledTill, longDateFormat, timeFormat)}
/>
</DescriptionList>
);
}
export default DisabledIndexerInfo;

@ -30,9 +30,8 @@ interface IndexerIndexRowProps {
function IndexerIndexRow(props: IndexerIndexRowProps) {
const { indexerId, columns, isSelectMode } = props;
const { indexer, appProfile } = useSelector(
createIndexerIndexItemSelector(props.indexerId)
);
const { indexer, appProfile, status, longDateFormat, timeFormat } =
useSelector(createIndexerIndexItemSelector(props.indexerId));
const {
id,
@ -44,7 +43,6 @@ function IndexerIndexRow(props: IndexerIndexRowProps) {
protocol,
privacy,
priority,
status,
fields,
added,
capabilities,
@ -123,6 +121,8 @@ function IndexerIndexRow(props: IndexerIndexRowProps) {
enabled={enable}
redirect={redirect}
status={status}
longDateFormat={longDateFormat}
timeFormat={timeFormat}
component={VirtualTableRowCell}
/>
);

@ -7,3 +7,7 @@
.statusIcon {
width: 20px !important;
}
.indexerStatusTooltip {
display: flex;
}

@ -1,6 +1,7 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'indexerStatusTooltip': string;
'status': string;
'statusIcon': string;
}

@ -1,9 +1,11 @@
import React from 'react';
import Icon from 'Components/Icon';
import VirtualTableRowCell from 'Components/Table/Cells/TableRowCell';
import { icons, kinds } from 'Helpers/Props';
import Popover from 'Components/Tooltip/Popover';
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import { IndexerStatus } from 'Indexer/Indexer';
import formatDateTime from 'Utilities/Date/formatDateTime';
import translate from 'Utilities/String/translate';
import DisabledIndexerInfo from './DisabledIndexerInfo';
import styles from './IndexerStatusCell.css';
interface IndexerStatusCellProps {
@ -11,6 +13,8 @@ interface IndexerStatusCellProps {
enabled: boolean;
redirect: boolean;
status: IndexerStatus;
longDateFormat: string;
timeFormat: string;
component?: React.ElementType;
}
@ -20,6 +24,8 @@ function IndexerStatusCell(props: IndexerStatusCellProps) {
enabled,
redirect,
status,
longDateFormat,
timeFormat,
component: Component = VirtualTableRowCell,
...otherProps
} = props;
@ -41,13 +47,29 @@ function IndexerStatusCell(props: IndexerStatusCellProps) {
/>
}
{status ? (
<Icon
className={styles.statusIcon}
kind={kinds.DANGER}
name={icons.WARNING}
title={`Indexer is Disabled due to failures until ${formatDateTime(
status.disabledTill
)}`}
<Popover
className={styles.indexerStatusTooltip}
canFlip={true}
anchor={
<Icon
className={styles.statusIcon}
kind={kinds.DANGER}
name={icons.WARNING}
/>
}
title={translate('IndexerDisabled')}
body={
<div>
<DisabledIndexerInfo
mostRecentFailure={status.mostRecentFailure}
initialFailure={status.initialFailure}
disabledTill={status.disabledTill}
longDateFormat={longDateFormat}
timeFormat={timeFormat}
/>
</div>
}
position={tooltipPositions.BOTTOM}
/>
) : null}
</Component>

@ -2,12 +2,16 @@ import { createSelector } from 'reselect';
import Indexer from 'Indexer/Indexer';
import createIndexerAppProfileSelector from 'Store/Selectors/createIndexerAppProfileSelector';
import createIndexerSelector from 'Store/Selectors/createIndexerSelector';
import createIndexerStatusSelector from 'Store/Selectors/createIndexerStatusSelector';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
function createIndexerIndexItemSelector(indexerId: number) {
return createSelector(
createIndexerSelector(indexerId),
createIndexerAppProfileSelector(indexerId),
(indexer: Indexer, appProfile) => {
createIndexerStatusSelector(indexerId),
createUISettingsSelector(),
(indexer: Indexer, appProfile, status, uiSettings) => {
// If a series is deleted this selector may fire before the parent
// selectors, which will result in an undefined series, if that happens
// we want to return early here and again in the render function to avoid
@ -20,6 +24,9 @@ function createIndexerIndexItemSelector(indexerId: number) {
return {
indexer,
appProfile,
status,
longDateFormat: uiSettings.longDateFormat,
timeFormat: uiSettings.timeFormat,
};
}
);

@ -2,6 +2,8 @@ import ModelBase from 'App/ModelBase';
export interface IndexerStatus extends ModelBase {
disabledTill: Date;
initialFailure: Date;
mostRecentFailure: Date;
}
export interface IndexerCategory extends ModelBase {

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

@ -116,6 +116,7 @@
"Details": "Details",
"DevelopmentSettings": "Development Settings",
"Disabled": "Disabled",
"DisabledUntil": "Disabled Until",
"Discord": "Discord",
"Docker": "Docker",
"Donations": "Donations",
@ -190,6 +191,7 @@
"IndexerAlreadySetup": "At least one instance of indexer is already setup",
"IndexerAuth": "Indexer Auth",
"IndexerDetails": "Indexer Details",
"IndexerDisabled": "Indexer Disabled",
"IndexerFlags": "Indexer Flags",
"IndexerHealthCheckNoIndexers": "No indexers enabled, Prowlarr will not return search results",
"IndexerInfo": "Indexer Info",
@ -216,6 +218,7 @@
"IndexerVipCheckExpiredClientMessage": "Indexer VIP benefits have expired: {0}",
"IndexerVipCheckExpiringClientMessage": "Indexer VIP benefits expiring soon: {0}",
"Info": "Info",
"InitialFailure": "Initial Failure",
"InstanceName": "Instance Name",
"InstanceNameHelpText": "Instance name in tab and for Syslog app name",
"InteractiveSearch": "Interactive Search",
@ -224,6 +227,7 @@
"Language": "Language",
"LastDuration": "Last Duration",
"LastExecution": "Last Execution",
"LastFailure": "Last Failure",
"LastWriteTime": "Last Write Time",
"LaunchBrowserHelpText": " Open a web browser and navigate to the Prowlarr homepage on app start.",
"Level": "Level",

@ -10,6 +10,8 @@ namespace Prowlarr.Api.V1.Indexers
{
public int IndexerId { get; set; }
public DateTime? DisabledTill { get; set; }
public DateTime? MostRecentFailure { get; set; }
public DateTime? InitialFailure { get; set; }
}
public static class IndexerStatusResourceMapper
@ -24,7 +26,9 @@ namespace Prowlarr.Api.V1.Indexers
return new IndexerStatusResource
{
IndexerId = model.ProviderId,
DisabledTill = model.DisabledTill
DisabledTill = model.DisabledTill,
MostRecentFailure = model.MostRecentFailure,
InitialFailure = model.InitialFailure,
};
}

Loading…
Cancel
Save