import React, { useCallback, useState } from 'react'; import ProtocolLabel from 'Activity/Queue/ProtocolLabel'; import { useSelect } from 'App/Select/SelectContext'; import IconButton from 'Components/Link/IconButton'; import SpinnerIconButton from 'Components/Link/SpinnerIconButton'; import ProgressBar from 'Components/ProgressBar'; import RelativeDateCell from 'Components/Table/Cells/RelativeDateCell'; import TableRowCell from 'Components/Table/Cells/TableRowCell'; import TableSelectCell from 'Components/Table/Cells/TableSelectCell'; import Column from 'Components/Table/Column'; import TableRow from 'Components/Table/TableRow'; import Tooltip from 'Components/Tooltip/Tooltip'; import DownloadProtocol from 'DownloadClient/DownloadProtocol'; import EpisodeFormats from 'Episode/EpisodeFormats'; import EpisodeLanguages from 'Episode/EpisodeLanguages'; import EpisodeQuality from 'Episode/EpisodeQuality'; import { useEpisodesWithIds } from 'Episode/useEpisode'; import { icons, kinds, tooltipPositions } from 'Helpers/Props'; import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal'; import Language from 'Language/Language'; import { QualityModel } from 'Quality/Quality'; import SeriesTitleLink from 'Series/SeriesTitleLink'; import { useSingleSeries } from 'Series/useSeries'; import { useUiSettingsValues } from 'Settings/UI/useUiSettings'; import CustomFormat from 'typings/CustomFormat'; import { SelectStateInputProps } from 'typings/props'; import Queue, { QueueTrackedDownloadState, QueueTrackedDownloadStatus, StatusMessage, } from 'typings/Queue'; import formatBytes from 'Utilities/Number/formatBytes'; import formatCustomFormatScore from 'Utilities/Number/formatCustomFormatScore'; import translate from 'Utilities/String/translate'; import EpisodeCellContent from './EpisodeCellContent'; import EpisodeTitleCellContent from './EpisodeTitleCellContent'; import QueueStatusCell from './QueueStatusCell'; import RemoveQueueItemModal from './RemoveQueueItemModal'; import TimeLeftCell from './TimeLeftCell'; import { useGrabQueueItem, useRemoveQueueItem } from './useQueue'; import styles from './QueueRow.css'; interface QueueRowProps { id: number; seriesId?: number; episodeIds: number[]; downloadId: string; title: string; status: string; trackedDownloadStatus?: QueueTrackedDownloadStatus; trackedDownloadState?: QueueTrackedDownloadState; statusMessages?: StatusMessage[]; errorMessage?: string; languages: Language[]; quality: QualityModel; customFormats?: CustomFormat[]; customFormatScore: number; protocol: DownloadProtocol; indexer?: string; isFullSeason: boolean; seasonNumbers: number[]; outputPath?: string; downloadClient?: string; downloadClientHasPostImportCategory?: boolean; estimatedCompletionTime?: string; added?: string; timeLeft?: string; size: number; sizeLeft: number; isRemoving?: boolean; columns: Column[]; onQueueRowModalOpenOrClose: (isOpen: boolean) => void; } function QueueRow(props: QueueRowProps) { const { id, seriesId, episodeIds, downloadId, title, status, trackedDownloadStatus, trackedDownloadState, statusMessages, errorMessage, languages, quality, customFormats = [], customFormatScore, protocol, indexer, outputPath, downloadClient, downloadClientHasPostImportCategory, estimatedCompletionTime, isFullSeason, seasonNumbers, added, timeLeft, size, sizeLeft, columns, onQueueRowModalOpenOrClose, } = props; const series = useSingleSeries(seriesId); const episodes = useEpisodesWithIds(episodeIds); const { showRelativeDates, shortDateFormat, timeFormat } = useUiSettingsValues(); const { removeQueueItem, isRemoving } = useRemoveQueueItem(id); const { grabQueueItem, isGrabbing, grabError } = useGrabQueueItem(id); const { toggleSelected, useIsSelected } = useSelect(); const isSelected = useIsSelected(id); const [isRemoveQueueItemModalOpen, setIsRemoveQueueItemModalOpen] = useState(false); const [isInteractiveImportModalOpen, setIsInteractiveImportModalOpen] = useState(false); const handleGrabPress = useCallback(() => { grabQueueItem(); }, [grabQueueItem]); const handleInteractiveImportPress = useCallback(() => { onQueueRowModalOpenOrClose(true); setIsInteractiveImportModalOpen(true); }, [setIsInteractiveImportModalOpen, onQueueRowModalOpenOrClose]); const handleInteractiveImportModalClose = useCallback(() => { onQueueRowModalOpenOrClose(false); setIsInteractiveImportModalOpen(false); }, [setIsInteractiveImportModalOpen, onQueueRowModalOpenOrClose]); const handleRemoveQueueItemPress = useCallback(() => { onQueueRowModalOpenOrClose(true); setIsRemoveQueueItemModalOpen(true); }, [setIsRemoveQueueItemModalOpen, onQueueRowModalOpenOrClose]); const handleRemoveQueueItemModalConfirmed = useCallback(() => { onQueueRowModalOpenOrClose(false); removeQueueItem(); setIsRemoveQueueItemModalOpen(false); }, [ setIsRemoveQueueItemModalOpen, removeQueueItem, onQueueRowModalOpenOrClose, ]); const handleRemoveQueueItemModalClose = useCallback(() => { onQueueRowModalOpenOrClose(false); setIsRemoveQueueItemModalOpen(false); }, [setIsRemoveQueueItemModalOpen, onQueueRowModalOpenOrClose]); const handleSelectedChange = useCallback( ({ id, value, shiftKey = false }: SelectStateInputProps) => { toggleSelected({ id, isSelected: value, shiftKey, }); }, [toggleSelected] ); const progress = 100 - (sizeLeft / size) * 100; const showInteractiveImport = status === 'completed' && trackedDownloadStatus === 'warning'; const isPending = status === 'delay' || status === 'downloadClientUnavailable'; return ( {columns.map((column) => { const { name, isVisible } = column; if (!isVisible) { return null; } if (name === 'status') { return ( ); } if (name === 'series.sortTitle') { return ( {series ? ( ) : ( title )} ); } if (name === 'episode') { return ( ); } if (name === 'episodes.title') { return ( ); } if (name === 'episodes.airDateUtc') { if (episodes.length === 0) { return -; } if (episodes.length === 1) { return ( ); } return ( {' - '} ); } if (name === 'languages') { return ( ); } if (name === 'quality') { return ( {quality ? : null} ); } if (name === 'customFormats') { return ( ); } if (name === 'customFormatScore') { return ( } position={tooltipPositions.BOTTOM} /> ); } if (name === 'protocol') { return ( ); } if (name === 'indexer') { return {indexer}; } if (name === 'downloadClient') { return {downloadClient}; } if (name === 'title') { return {title}; } if (name === 'size') { return {formatBytes(size)}; } if (name === 'outputPath') { return {outputPath}; } if (name === 'estimatedCompletionTime') { return ( ); } if (name === 'progress') { return ( {!!progress && ( )} ); } if (name === 'added') { return ; } if (name === 'actions') { return ( {showInteractiveImport ? ( ) : null} {isPending ? ( ) : null} ); } return null; })} ); } export default QueueRow;