parent
17aab235a5
commit
0ff3101511
@ -1,33 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import { sizes } from 'Helpers/Props';
|
||||
import SeriesHistoryModalContentConnector from './SeriesHistoryModalContentConnector';
|
||||
|
||||
function SeriesHistoryModal(props) {
|
||||
const {
|
||||
isOpen,
|
||||
onModalClose,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
size={sizes.EXTRA_EXTRA_LARGE}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<SeriesHistoryModalContentConnector
|
||||
{...otherProps}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
SeriesHistoryModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default SeriesHistoryModal;
|
@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import { sizes } from 'Helpers/Props';
|
||||
import SeriesHistoryModalContent, {
|
||||
SeriesHistoryModalContentProps,
|
||||
} from './SeriesHistoryModalContent';
|
||||
|
||||
interface SeriesHistoryModalProps extends SeriesHistoryModalContentProps {
|
||||
isOpen: boolean;
|
||||
}
|
||||
|
||||
function SeriesHistoryModal({
|
||||
isOpen,
|
||||
onModalClose,
|
||||
...otherProps
|
||||
}: SeriesHistoryModalProps) {
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
size={sizes.EXTRA_EXTRA_LARGE}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<SeriesHistoryModalContent {...otherProps} onModalClose={onModalClose} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default SeriesHistoryModal;
|
@ -1,154 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import Icon from 'Components/Icon';
|
||||
import Button from 'Components/Link/Button';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import formatSeason from 'Season/formatSeason';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import SeriesHistoryRowConnector from './SeriesHistoryRowConnector';
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: 'eventType',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'episode',
|
||||
label: () => translate('Episode'),
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'sourceTitle',
|
||||
label: () => translate('SourceTitle'),
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'languages',
|
||||
label: () => translate('Languages'),
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'quality',
|
||||
label: () => translate('Quality'),
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'customFormats',
|
||||
label: () => translate('CustomFormats'),
|
||||
isSortable: false,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'customFormatScore',
|
||||
label: React.createElement(Icon, {
|
||||
name: icons.SCORE,
|
||||
title: () => translate('CustomFormatScore')
|
||||
}),
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'date',
|
||||
label: () => translate('Date'),
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'actions',
|
||||
isVisible: true
|
||||
}
|
||||
];
|
||||
|
||||
class SeriesHistoryModalContent extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
seasonNumber,
|
||||
isFetching,
|
||||
isPopulated,
|
||||
error,
|
||||
items,
|
||||
onMarkAsFailedPress,
|
||||
onModalClose
|
||||
} = this.props;
|
||||
|
||||
const fullSeries = seasonNumber == null;
|
||||
const hasItems = !!items.length;
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
{seasonNumber == null ?
|
||||
translate('History') :
|
||||
translate('HistoryModalHeaderSeason', { season: formatSeason(seasonNumber) })
|
||||
}
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
{
|
||||
isFetching &&
|
||||
<LoadingIndicator />
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<Alert kind={kinds.DANGER}>{translate('HistoryLoadError')}</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
isPopulated && !hasItems && !error &&
|
||||
<div>{translate('NoHistory')}</div>
|
||||
}
|
||||
|
||||
{
|
||||
isPopulated && hasItems && !error &&
|
||||
<Table columns={columns}>
|
||||
<TableBody>
|
||||
{
|
||||
items.map((item) => {
|
||||
return (
|
||||
<SeriesHistoryRowConnector
|
||||
key={item.id}
|
||||
fullSeries={fullSeries}
|
||||
{...item}
|
||||
onMarkAsFailedPress={onMarkAsFailedPress}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
</TableBody>
|
||||
</Table>
|
||||
}
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button onPress={onModalClose}>
|
||||
{translate('Close')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SeriesHistoryModalContent.propTypes = {
|
||||
seasonNumber: PropTypes.number,
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
isPopulated: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
onMarkAsFailedPress: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default SeriesHistoryModalContent;
|
@ -0,0 +1,170 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import AppState from 'App/State/AppState';
|
||||
import Alert from 'Components/Alert';
|
||||
import Icon from 'Components/Icon';
|
||||
import Button from 'Components/Link/Button';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import Column from 'Components/Table/Column';
|
||||
import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import formatSeason from 'Season/formatSeason';
|
||||
import {
|
||||
clearSeriesHistory,
|
||||
fetchSeriesHistory,
|
||||
seriesHistoryMarkAsFailed,
|
||||
} from 'Store/Actions/seriesHistoryActions';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import SeriesHistoryRow from './SeriesHistoryRow';
|
||||
|
||||
const columns: Column[] = [
|
||||
{
|
||||
name: 'eventType',
|
||||
label: '',
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'episode',
|
||||
label: () => translate('Episode'),
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'sourceTitle',
|
||||
label: () => translate('SourceTitle'),
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'languages',
|
||||
label: () => translate('Languages'),
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'quality',
|
||||
label: () => translate('Quality'),
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'customFormats',
|
||||
label: () => translate('CustomFormats'),
|
||||
isSortable: false,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'customFormatScore',
|
||||
label: React.createElement(Icon, {
|
||||
name: icons.SCORE,
|
||||
title: () => translate('CustomFormatScore'),
|
||||
}),
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'date',
|
||||
label: () => translate('Date'),
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'actions',
|
||||
label: '',
|
||||
isVisible: true,
|
||||
},
|
||||
];
|
||||
|
||||
export interface SeriesHistoryModalContentProps {
|
||||
seriesId: number;
|
||||
seasonNumber?: number;
|
||||
onModalClose: () => void;
|
||||
}
|
||||
|
||||
function SeriesHistoryModalContent({
|
||||
seriesId,
|
||||
seasonNumber,
|
||||
onModalClose,
|
||||
}: SeriesHistoryModalContentProps) {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const { isFetching, isPopulated, error, items } = useSelector(
|
||||
(state: AppState) => state.seriesHistory
|
||||
);
|
||||
|
||||
const fullSeries = seasonNumber == null;
|
||||
const hasItems = !!items.length;
|
||||
|
||||
const handleMarkAsFailedPress = useCallback(
|
||||
(historyId: number) => {
|
||||
dispatch(
|
||||
seriesHistoryMarkAsFailed({
|
||||
historyId,
|
||||
seriesId,
|
||||
seasonNumber,
|
||||
})
|
||||
);
|
||||
},
|
||||
[seriesId, seasonNumber, dispatch]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
fetchSeriesHistory({
|
||||
seriesId,
|
||||
seasonNumber,
|
||||
})
|
||||
);
|
||||
|
||||
return () => {
|
||||
dispatch(clearSeriesHistory());
|
||||
};
|
||||
}, [seriesId, seasonNumber, dispatch]);
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
{seasonNumber == null
|
||||
? translate('History')
|
||||
: translate('HistoryModalHeaderSeason', {
|
||||
season: formatSeason(seasonNumber)!,
|
||||
})}
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
{isFetching && !isPopulated ? <LoadingIndicator /> : null}
|
||||
|
||||
{!isFetching && !!error ? (
|
||||
<Alert kind={kinds.DANGER}>{translate('HistoryLoadError')}</Alert>
|
||||
) : null}
|
||||
|
||||
{isPopulated && !hasItems && !error ? (
|
||||
<div>{translate('NoHistory')}</div>
|
||||
) : null}
|
||||
|
||||
{isPopulated && hasItems && !error ? (
|
||||
<Table columns={columns}>
|
||||
<TableBody>
|
||||
{items.map((item) => {
|
||||
return (
|
||||
<SeriesHistoryRow
|
||||
key={item.id}
|
||||
fullSeries={fullSeries}
|
||||
{...item}
|
||||
onMarkAsFailedPress={handleMarkAsFailedPress}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
) : null}
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button onPress={onModalClose}>{translate('Close')}</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
|
||||
export default SeriesHistoryModalContent;
|
@ -1,81 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { clearSeriesHistory, fetchSeriesHistory, seriesHistoryMarkAsFailed } from 'Store/Actions/seriesHistoryActions';
|
||||
import SeriesHistoryModalContent from './SeriesHistoryModalContent';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.seriesHistory,
|
||||
(seriesHistory) => {
|
||||
return seriesHistory;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
fetchSeriesHistory,
|
||||
clearSeriesHistory,
|
||||
seriesHistoryMarkAsFailed
|
||||
};
|
||||
|
||||
class SeriesHistoryModalContentConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
seriesId,
|
||||
seasonNumber
|
||||
} = this.props;
|
||||
|
||||
this.props.fetchSeriesHistory({
|
||||
seriesId,
|
||||
seasonNumber
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.clearSeriesHistory();
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onMarkAsFailedPress = (historyId) => {
|
||||
const {
|
||||
seriesId,
|
||||
seasonNumber
|
||||
} = this.props;
|
||||
|
||||
this.props.seriesHistoryMarkAsFailed({
|
||||
historyId,
|
||||
seriesId,
|
||||
seasonNumber
|
||||
});
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<SeriesHistoryModalContent
|
||||
{...this.props}
|
||||
onMarkAsFailedPress={this.onMarkAsFailedPress}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SeriesHistoryModalContentConnector.propTypes = {
|
||||
seriesId: PropTypes.number.isRequired,
|
||||
seasonNumber: PropTypes.number,
|
||||
fetchSeriesHistory: PropTypes.func.isRequired,
|
||||
clearSeriesHistory: PropTypes.func.isRequired,
|
||||
seriesHistoryMarkAsFailed: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(SeriesHistoryModalContentConnector);
|
@ -1,204 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import HistoryDetails from 'Activity/History/Details/HistoryDetails';
|
||||
import HistoryEventTypeCell from 'Activity/History/HistoryEventTypeCell';
|
||||
import Icon from 'Components/Icon';
|
||||
import IconButton from 'Components/Link/IconButton';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import RelativeDateCell from 'Components/Table/Cells/RelativeDateCell';
|
||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import EpisodeFormats from 'Episode/EpisodeFormats';
|
||||
import EpisodeLanguages from 'Episode/EpisodeLanguages';
|
||||
import EpisodeNumber from 'Episode/EpisodeNumber';
|
||||
import EpisodeQuality from 'Episode/EpisodeQuality';
|
||||
import SeasonEpisodeNumber from 'Episode/SeasonEpisodeNumber';
|
||||
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import formatCustomFormatScore from 'Utilities/Number/formatCustomFormatScore';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './SeriesHistoryRow.css';
|
||||
|
||||
function getTitle(eventType) {
|
||||
switch (eventType) {
|
||||
case 'grabbed': return 'Grabbed';
|
||||
case 'seriesFolderImported': return 'Series Folder Imported';
|
||||
case 'downloadFolderImported': return 'Download Folder Imported';
|
||||
case 'downloadFailed': return 'Download Failed';
|
||||
case 'episodeFileDeleted': return 'Episode File Deleted';
|
||||
case 'episodeFileRenamed': return 'Episode File Renamed';
|
||||
default: return 'Unknown';
|
||||
}
|
||||
}
|
||||
|
||||
class SeriesHistoryRow extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
isMarkAsFailedModalOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onMarkAsFailedPress = () => {
|
||||
this.setState({ isMarkAsFailedModalOpen: true });
|
||||
};
|
||||
|
||||
onConfirmMarkAsFailed = () => {
|
||||
this.props.onMarkAsFailedPress(this.props.id);
|
||||
this.setState({ isMarkAsFailedModalOpen: false });
|
||||
};
|
||||
|
||||
onMarkAsFailedModalClose = () => {
|
||||
this.setState({ isMarkAsFailedModalOpen: false });
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
eventType,
|
||||
sourceTitle,
|
||||
languages,
|
||||
quality,
|
||||
qualityCutoffNotMet,
|
||||
customFormats,
|
||||
date,
|
||||
data,
|
||||
downloadId,
|
||||
fullSeries,
|
||||
series,
|
||||
episode,
|
||||
customFormatScore
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
isMarkAsFailedModalOpen
|
||||
} = this.state;
|
||||
|
||||
const EpisodeComponent = fullSeries ? SeasonEpisodeNumber : EpisodeNumber;
|
||||
|
||||
if (!series || !episode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
<HistoryEventTypeCell
|
||||
eventType={eventType}
|
||||
data={data}
|
||||
/>
|
||||
|
||||
<TableRowCell key={name}>
|
||||
<EpisodeComponent
|
||||
seasonNumber={episode.seasonNumber}
|
||||
episodeNumber={episode.episodeNumber}
|
||||
absoluteEpisodeNumber={episode.absoluteEpisodeNumber}
|
||||
seriesType={series.seriesType}
|
||||
alternateTitles={series.alternateTitles}
|
||||
sceneSeasonNumber={episode.sceneSeasonNumber}
|
||||
sceneEpisodeNumber={episode.sceneEpisodeNumber}
|
||||
sceneAbsoluteEpisodeNumber={episode.sceneAbsoluteEpisodeNumber}
|
||||
/>
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell className={styles.sourceTitle}>
|
||||
{sourceTitle}
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell>
|
||||
<EpisodeLanguages languages={languages} />
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell>
|
||||
<EpisodeQuality
|
||||
quality={quality}
|
||||
isCutoffNotMet={qualityCutoffNotMet}
|
||||
/>
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell>
|
||||
<EpisodeFormats formats={customFormats} />
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell>
|
||||
{formatCustomFormatScore(customFormatScore, customFormats.length)}
|
||||
</TableRowCell>
|
||||
|
||||
<RelativeDateCell
|
||||
date={date}
|
||||
includeSeconds={true}
|
||||
includeTime={true}
|
||||
/>
|
||||
|
||||
<TableRowCell className={styles.actions}>
|
||||
<Popover
|
||||
anchor={
|
||||
<Icon
|
||||
name={icons.INFO}
|
||||
/>
|
||||
}
|
||||
title={getTitle(eventType)}
|
||||
body={
|
||||
<HistoryDetails
|
||||
eventType={eventType}
|
||||
sourceTitle={sourceTitle}
|
||||
data={data}
|
||||
downloadId={downloadId}
|
||||
/>
|
||||
}
|
||||
position={tooltipPositions.LEFT}
|
||||
/>
|
||||
|
||||
{
|
||||
eventType === 'grabbed' &&
|
||||
<IconButton
|
||||
title={translate('MarkAsFailed')}
|
||||
name={icons.REMOVE}
|
||||
size={14}
|
||||
onPress={this.onMarkAsFailedPress}
|
||||
/>
|
||||
}
|
||||
</TableRowCell>
|
||||
|
||||
<ConfirmModal
|
||||
isOpen={isMarkAsFailedModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title={translate('MarkAsFailed')}
|
||||
message={translate('MarkAsFailedConfirmation', { sourceTitle })}
|
||||
confirmLabel={translate('MarkAsFailed')}
|
||||
onConfirm={this.onConfirmMarkAsFailed}
|
||||
onCancel={this.onMarkAsFailedModalClose}
|
||||
/>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SeriesHistoryRow.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
eventType: PropTypes.string.isRequired,
|
||||
sourceTitle: PropTypes.string.isRequired,
|
||||
languages: PropTypes.arrayOf(PropTypes.object),
|
||||
quality: PropTypes.object.isRequired,
|
||||
qualityCutoffNotMet: PropTypes.bool.isRequired,
|
||||
customFormats: PropTypes.arrayOf(PropTypes.object),
|
||||
date: PropTypes.string.isRequired,
|
||||
data: PropTypes.object.isRequired,
|
||||
downloadId: PropTypes.string,
|
||||
fullSeries: PropTypes.bool.isRequired,
|
||||
series: PropTypes.object.isRequired,
|
||||
episode: PropTypes.object.isRequired,
|
||||
customFormatScore: PropTypes.number.isRequired,
|
||||
onMarkAsFailedPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default SeriesHistoryRow;
|
@ -0,0 +1,183 @@
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import HistoryDetails from 'Activity/History/Details/HistoryDetails';
|
||||
import HistoryEventTypeCell from 'Activity/History/HistoryEventTypeCell';
|
||||
import Icon from 'Components/Icon';
|
||||
import IconButton from 'Components/Link/IconButton';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import RelativeDateCell from 'Components/Table/Cells/RelativeDateCell';
|
||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import EpisodeFormats from 'Episode/EpisodeFormats';
|
||||
import EpisodeLanguages from 'Episode/EpisodeLanguages';
|
||||
import EpisodeNumber from 'Episode/EpisodeNumber';
|
||||
import EpisodeQuality from 'Episode/EpisodeQuality';
|
||||
import SeasonEpisodeNumber from 'Episode/SeasonEpisodeNumber';
|
||||
import useEpisode from 'Episode/useEpisode';
|
||||
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import Language from 'Language/Language';
|
||||
import { QualityModel } from 'Quality/Quality';
|
||||
import useSeries from 'Series/useSeries';
|
||||
import CustomFormat from 'typings/CustomFormat';
|
||||
import { HistoryData, HistoryEventType } from 'typings/History';
|
||||
import formatCustomFormatScore from 'Utilities/Number/formatCustomFormatScore';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './SeriesHistoryRow.css';
|
||||
|
||||
interface SeriesHistoryRowProps {
|
||||
id: number;
|
||||
seriesId: number;
|
||||
episodeId: number;
|
||||
eventType: HistoryEventType;
|
||||
sourceTitle: string;
|
||||
languages?: Language[];
|
||||
quality: QualityModel;
|
||||
qualityCutoffNotMet: boolean;
|
||||
customFormats?: CustomFormat[];
|
||||
date: string;
|
||||
data: HistoryData;
|
||||
downloadId?: string;
|
||||
fullSeries: boolean;
|
||||
customFormatScore: number;
|
||||
onMarkAsFailedPress: (historyId: number) => void;
|
||||
}
|
||||
|
||||
function SeriesHistoryRow({
|
||||
id,
|
||||
seriesId,
|
||||
episodeId,
|
||||
eventType,
|
||||
sourceTitle,
|
||||
languages = [],
|
||||
quality,
|
||||
qualityCutoffNotMet,
|
||||
customFormats = [],
|
||||
date,
|
||||
data,
|
||||
downloadId,
|
||||
fullSeries,
|
||||
customFormatScore,
|
||||
onMarkAsFailedPress,
|
||||
}: SeriesHistoryRowProps) {
|
||||
const series = useSeries(seriesId);
|
||||
const episode = useEpisode(episodeId, 'episodes');
|
||||
|
||||
const [isMarkAsFailedModalOpen, setIsMarkAsFailedModalOpen] = useState(false);
|
||||
|
||||
const EpisodeComponent = fullSeries ? SeasonEpisodeNumber : EpisodeNumber;
|
||||
|
||||
const title = useMemo(() => {
|
||||
switch (eventType) {
|
||||
case 'grabbed':
|
||||
return 'Grabbed';
|
||||
case 'seriesFolderImported':
|
||||
return 'Series Folder Imported';
|
||||
case 'downloadFolderImported':
|
||||
return 'Download Folder Imported';
|
||||
case 'downloadFailed':
|
||||
return 'Download Failed';
|
||||
case 'episodeFileDeleted':
|
||||
return 'Episode File Deleted';
|
||||
case 'episodeFileRenamed':
|
||||
return 'Episode File Renamed';
|
||||
default:
|
||||
return 'Unknown';
|
||||
}
|
||||
}, [eventType]);
|
||||
|
||||
const handleMarkAsFailedPress = useCallback(() => {
|
||||
setIsMarkAsFailedModalOpen(true);
|
||||
}, []);
|
||||
|
||||
const handleConfirmMarkAsFailed = useCallback(() => {
|
||||
onMarkAsFailedPress(id);
|
||||
setIsMarkAsFailedModalOpen(false);
|
||||
}, [id, onMarkAsFailedPress]);
|
||||
|
||||
const handleMarkAsFailedModalClose = useCallback(() => {
|
||||
setIsMarkAsFailedModalOpen(false);
|
||||
}, []);
|
||||
|
||||
if (!series || !episode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
<HistoryEventTypeCell eventType={eventType} data={data} />
|
||||
|
||||
<TableRowCell>
|
||||
<EpisodeComponent
|
||||
seasonNumber={episode.seasonNumber}
|
||||
episodeNumber={episode.episodeNumber}
|
||||
absoluteEpisodeNumber={episode.absoluteEpisodeNumber}
|
||||
seriesType={series.seriesType}
|
||||
alternateTitles={series.alternateTitles}
|
||||
sceneSeasonNumber={episode.sceneSeasonNumber}
|
||||
sceneEpisodeNumber={episode.sceneEpisodeNumber}
|
||||
sceneAbsoluteEpisodeNumber={episode.sceneAbsoluteEpisodeNumber}
|
||||
/>
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell className={styles.sourceTitle}>{sourceTitle}</TableRowCell>
|
||||
|
||||
<TableRowCell>
|
||||
<EpisodeLanguages languages={languages} />
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell>
|
||||
<EpisodeQuality
|
||||
quality={quality}
|
||||
isCutoffNotMet={qualityCutoffNotMet}
|
||||
/>
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell>
|
||||
<EpisodeFormats formats={customFormats} />
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell>
|
||||
{formatCustomFormatScore(customFormatScore, customFormats.length)}
|
||||
</TableRowCell>
|
||||
|
||||
<RelativeDateCell date={date} includeSeconds={true} includeTime={true} />
|
||||
|
||||
<TableRowCell className={styles.actions}>
|
||||
<Popover
|
||||
anchor={<Icon name={icons.INFO} />}
|
||||
title={title}
|
||||
body={
|
||||
<HistoryDetails
|
||||
eventType={eventType}
|
||||
sourceTitle={sourceTitle}
|
||||
data={data}
|
||||
downloadId={downloadId}
|
||||
/>
|
||||
}
|
||||
position={tooltipPositions.LEFT}
|
||||
/>
|
||||
|
||||
{eventType === 'grabbed' ? (
|
||||
<IconButton
|
||||
title={translate('MarkAsFailed')}
|
||||
name={icons.REMOVE}
|
||||
size={14}
|
||||
onPress={handleMarkAsFailedPress}
|
||||
/>
|
||||
) : null}
|
||||
</TableRowCell>
|
||||
|
||||
<ConfirmModal
|
||||
isOpen={isMarkAsFailedModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title={translate('MarkAsFailed')}
|
||||
message={translate('MarkAsFailedConfirmation', { sourceTitle })}
|
||||
confirmLabel={translate('MarkAsFailed')}
|
||||
onConfirm={handleConfirmMarkAsFailed}
|
||||
onCancel={handleMarkAsFailedModalClose}
|
||||
/>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
|
||||
export default SeriesHistoryRow;
|
@ -1,26 +0,0 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { fetchHistory, markAsFailed } from 'Store/Actions/historyActions';
|
||||
import createEpisodeSelector from 'Store/Selectors/createEpisodeSelector';
|
||||
import createSeriesSelector from 'Store/Selectors/createSeriesSelector';
|
||||
import SeriesHistoryRow from './SeriesHistoryRow';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createSeriesSelector(),
|
||||
createEpisodeSelector(),
|
||||
(series, episode) => {
|
||||
return {
|
||||
series,
|
||||
episode
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
fetchHistory,
|
||||
markAsFailed
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(SeriesHistoryRow);
|
Loading…
Reference in new issue