parent
b184e62fa7
commit
2bf1ce1763
@ -1,34 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
|
||||||
import Modal from 'Components/Modal/Modal';
|
|
||||||
import EpisodeFileEditorModalContentConnector from './EpisodeFileEditorModalContentConnector';
|
|
||||||
|
|
||||||
function EpisodeFileEditorModal(props) {
|
|
||||||
const {
|
|
||||||
isOpen,
|
|
||||||
onModalClose,
|
|
||||||
...otherProps
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
isOpen={isOpen}
|
|
||||||
onModalClose={onModalClose}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
isOpen &&
|
|
||||||
<EpisodeFileEditorModalContentConnector
|
|
||||||
{...otherProps}
|
|
||||||
onModalClose={onModalClose}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
EpisodeFileEditorModal.propTypes = {
|
|
||||||
isOpen: PropTypes.bool.isRequired,
|
|
||||||
onModalClose: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default EpisodeFileEditorModal;
|
|
@ -1,8 +0,0 @@
|
|||||||
.actions {
|
|
||||||
display: flex;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selectInput {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
@ -1,310 +0,0 @@
|
|||||||
import _ from 'lodash';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
|
|
||||||
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
|
||||||
import removeOldSelectedState from 'Utilities/Table/removeOldSelectedState';
|
|
||||||
import selectAll from 'Utilities/Table/selectAll';
|
|
||||||
import toggleSelected from 'Utilities/Table/toggleSelected';
|
|
||||||
import { kinds } from 'Helpers/Props';
|
|
||||||
import SelectInput from 'Components/Form/SelectInput';
|
|
||||||
import Button from 'Components/Link/Button';
|
|
||||||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
|
||||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
|
||||||
import ModalContent from 'Components/Modal/ModalContent';
|
|
||||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
|
||||||
import ModalBody from 'Components/Modal/ModalBody';
|
|
||||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
|
||||||
import Table from 'Components/Table/Table';
|
|
||||||
import TableBody from 'Components/Table/TableBody';
|
|
||||||
import SeasonNumber from 'Season/SeasonNumber';
|
|
||||||
import EpisodeFileEditorRow from './EpisodeFileEditorRow';
|
|
||||||
import styles from './EpisodeFileEditorModalContent.css';
|
|
||||||
|
|
||||||
const columns = [
|
|
||||||
{
|
|
||||||
name: 'episodeNumber',
|
|
||||||
label: 'Episode',
|
|
||||||
isVisible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'relativePath',
|
|
||||||
label: 'Relative Path',
|
|
||||||
isVisible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'airDateUtc',
|
|
||||||
label: 'Air Date',
|
|
||||||
isVisible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'language',
|
|
||||||
label: 'Language',
|
|
||||||
isVisible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'quality',
|
|
||||||
label: 'Quality',
|
|
||||||
isVisible: true
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
class EpisodeFileEditorModalContent extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
allSelected: false,
|
|
||||||
allUnselected: false,
|
|
||||||
lastToggled: null,
|
|
||||||
selectedState: {},
|
|
||||||
isConfirmDeleteModalOpen: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
|
||||||
if (hasDifferentItems(prevProps.items, this.props.items)) {
|
|
||||||
this.setState((state) => {
|
|
||||||
return removeOldSelectedState(state, prevProps.items);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Control
|
|
||||||
|
|
||||||
getSelectedIds = () => {
|
|
||||||
const selectedIds = getSelectedIds(this.state.selectedState);
|
|
||||||
|
|
||||||
return selectedIds.reduce((acc, id) => {
|
|
||||||
const matchingItem = this.props.items.find((item) => item.id === id);
|
|
||||||
|
|
||||||
if (matchingItem && !acc.includes(matchingItem.episodeFileId)) {
|
|
||||||
acc.push(matchingItem.episodeFileId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Listeners
|
|
||||||
|
|
||||||
onSelectAllChange = ({ value }) => {
|
|
||||||
this.setState(selectAll(this.state.selectedState, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
onSelectedChange = ({ id, value, shiftKey = false }) => {
|
|
||||||
this.setState((state) => {
|
|
||||||
return toggleSelected(state, this.props.items, id, value, shiftKey);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onDeletePress = () => {
|
|
||||||
this.setState({ isConfirmDeleteModalOpen: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
onConfirmDelete = () => {
|
|
||||||
this.setState({ isConfirmDeleteModalOpen: false });
|
|
||||||
this.props.onDeletePress(this.getSelectedIds());
|
|
||||||
}
|
|
||||||
|
|
||||||
onConfirmDeleteModalClose = () => {
|
|
||||||
this.setState({ isConfirmDeleteModalOpen: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
onLanguageChange = ({ value }) => {
|
|
||||||
const selectedIds = this.getSelectedIds();
|
|
||||||
|
|
||||||
if (!selectedIds.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.onLanguageChange(selectedIds, parseInt(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
onQualityChange = ({ value }) => {
|
|
||||||
const selectedIds = this.getSelectedIds();
|
|
||||||
|
|
||||||
if (!selectedIds.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.onQualityChange(selectedIds, parseInt(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
seasonNumber,
|
|
||||||
isDeleting,
|
|
||||||
isFetching,
|
|
||||||
isPopulated,
|
|
||||||
error,
|
|
||||||
items,
|
|
||||||
languages,
|
|
||||||
qualities,
|
|
||||||
seriesType,
|
|
||||||
onModalClose
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const {
|
|
||||||
allSelected,
|
|
||||||
allUnselected,
|
|
||||||
selectedState,
|
|
||||||
isConfirmDeleteModalOpen
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
const languageOptions = _.reduceRight(languages, (acc, language) => {
|
|
||||||
acc.push({
|
|
||||||
key: language.id,
|
|
||||||
value: language.name
|
|
||||||
});
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, [{ key: 'selectLanguage', value: 'Select Language', disabled: true }]);
|
|
||||||
|
|
||||||
const qualityOptions = _.reduceRight(qualities, (acc, quality) => {
|
|
||||||
acc.push({
|
|
||||||
key: quality.id,
|
|
||||||
value: quality.name
|
|
||||||
});
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, [{ key: 'selectQuality', value: 'Select Quality', disabled: true }]);
|
|
||||||
|
|
||||||
const hasSelectedFiles = this.getSelectedIds().length > 0;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ModalContent onModalClose={onModalClose}>
|
|
||||||
<ModalHeader>
|
|
||||||
Manage Episodes {seasonNumber != null && <SeasonNumber seasonNumber={seasonNumber} />}
|
|
||||||
</ModalHeader>
|
|
||||||
|
|
||||||
<ModalBody>
|
|
||||||
{
|
|
||||||
isFetching && !isPopulated ?
|
|
||||||
<LoadingIndicator /> :
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
!isFetching && error ?
|
|
||||||
<div>{error}</div> :
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
isPopulated && !items.length ?
|
|
||||||
<div>
|
|
||||||
No episode files to manage.
|
|
||||||
</div>:
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
isPopulated && items.length ?
|
|
||||||
<Table
|
|
||||||
columns={columns}
|
|
||||||
selectAll={true}
|
|
||||||
allSelected={allSelected}
|
|
||||||
allUnselected={allUnselected}
|
|
||||||
onSelectAllChange={this.onSelectAllChange}
|
|
||||||
>
|
|
||||||
<TableBody>
|
|
||||||
{
|
|
||||||
items.map((item) => {
|
|
||||||
return (
|
|
||||||
<EpisodeFileEditorRow
|
|
||||||
key={item.id}
|
|
||||||
seriesType={seriesType}
|
|
||||||
isSelected={selectedState[item.id]}
|
|
||||||
{...item}
|
|
||||||
onSelectedChange={this.onSelectedChange}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</TableBody>
|
|
||||||
</Table> :
|
|
||||||
null
|
|
||||||
}
|
|
||||||
</ModalBody>
|
|
||||||
|
|
||||||
<ModalFooter>
|
|
||||||
<div className={styles.actions}>
|
|
||||||
<SpinnerButton
|
|
||||||
kind={kinds.DANGER}
|
|
||||||
isSpinning={isDeleting}
|
|
||||||
isDisabled={!hasSelectedFiles}
|
|
||||||
onPress={this.onDeletePress}
|
|
||||||
>
|
|
||||||
Delete
|
|
||||||
</SpinnerButton>
|
|
||||||
|
|
||||||
<div className={styles.selectInput}>
|
|
||||||
<SelectInput
|
|
||||||
name="language"
|
|
||||||
value="selectLanguage"
|
|
||||||
values={languageOptions}
|
|
||||||
isDisabled={!hasSelectedFiles}
|
|
||||||
onChange={this.onLanguageChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.selectInput}>
|
|
||||||
<SelectInput
|
|
||||||
name="quality"
|
|
||||||
value="selectQuality"
|
|
||||||
values={qualityOptions}
|
|
||||||
isDisabled={!hasSelectedFiles}
|
|
||||||
onChange={this.onQualityChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
onPress={onModalClose}
|
|
||||||
>
|
|
||||||
Close
|
|
||||||
</Button>
|
|
||||||
</ModalFooter>
|
|
||||||
|
|
||||||
<ConfirmModal
|
|
||||||
isOpen={isConfirmDeleteModalOpen}
|
|
||||||
kind={kinds.DANGER}
|
|
||||||
title="Delete Selected Episode Files"
|
|
||||||
message={'Are you sure you want to delete the selected episode files?'}
|
|
||||||
confirmLabel="Delete"
|
|
||||||
onConfirm={this.onConfirmDelete}
|
|
||||||
onCancel={this.onConfirmDeleteModalClose}
|
|
||||||
/>
|
|
||||||
</ModalContent>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EpisodeFileEditorModalContent.propTypes = {
|
|
||||||
seasonNumber: PropTypes.number,
|
|
||||||
isDeleting: PropTypes.bool.isRequired,
|
|
||||||
isFetching: PropTypes.bool.isRequired,
|
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
|
||||||
error: PropTypes.object,
|
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
qualities: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
seriesType: PropTypes.string.isRequired,
|
|
||||||
onDeletePress: PropTypes.func.isRequired,
|
|
||||||
onLanguageChange: PropTypes.func.isRequired,
|
|
||||||
onQualityChange: PropTypes.func.isRequired,
|
|
||||||
onModalClose: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default EpisodeFileEditorModalContent;
|
|
@ -1,174 +0,0 @@
|
|||||||
/* eslint max-params: 0 */
|
|
||||||
import _ from 'lodash';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { createSelector } from 'reselect';
|
|
||||||
import getQualities from 'Utilities/Quality/getQualities';
|
|
||||||
import createSeriesSelector from 'Store/Selectors/createSeriesSelector';
|
|
||||||
import { deleteEpisodeFiles, updateEpisodeFiles } from 'Store/Actions/episodeFileActions';
|
|
||||||
import { fetchLanguageProfileSchema, fetchQualityProfileSchema } from 'Store/Actions/settingsActions';
|
|
||||||
import EpisodeFileEditorModalContent from './EpisodeFileEditorModalContent';
|
|
||||||
|
|
||||||
function createSchemaSelector() {
|
|
||||||
return createSelector(
|
|
||||||
(state) => state.settings.languageProfiles,
|
|
||||||
(state) => state.settings.qualityProfiles,
|
|
||||||
(languageProfiles, qualityProfiles) => {
|
|
||||||
const languages = _.map(languageProfiles.schema.languages, 'language');
|
|
||||||
const qualities = getQualities(qualityProfiles.schema.items);
|
|
||||||
|
|
||||||
let error = null;
|
|
||||||
|
|
||||||
if (languageProfiles.schemaError) {
|
|
||||||
error = 'Unable to load languages';
|
|
||||||
} else if (qualityProfiles.schemaError) {
|
|
||||||
error = 'Unable to load qualities';
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
isFetching: languageProfiles.isSchemaFetching || qualityProfiles.isSchemaFetching,
|
|
||||||
isPopulated: languageProfiles.isSchemaPopulated && qualityProfiles.isSchemaPopulated,
|
|
||||||
error,
|
|
||||||
languages,
|
|
||||||
qualities
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createMapStateToProps() {
|
|
||||||
return createSelector(
|
|
||||||
(state, { seasonNumber }) => seasonNumber,
|
|
||||||
(state) => state.episodes,
|
|
||||||
(state) => state.episodeFiles,
|
|
||||||
createSchemaSelector(),
|
|
||||||
createSeriesSelector(),
|
|
||||||
(
|
|
||||||
seasonNumber,
|
|
||||||
episodes,
|
|
||||||
episodeFiles,
|
|
||||||
schema,
|
|
||||||
series
|
|
||||||
) => {
|
|
||||||
const filtered = _.filter(episodes.items, (episode) => {
|
|
||||||
if (seasonNumber >= 0 && episode.seasonNumber !== seasonNumber) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!episode.episodeFileId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _.some(episodeFiles.items, { id: episode.episodeFileId });
|
|
||||||
});
|
|
||||||
|
|
||||||
const sorted = _.orderBy(filtered, ['seasonNumber', 'episodeNumber'], ['desc', 'desc']);
|
|
||||||
|
|
||||||
const items = _.map(sorted, (episode) => {
|
|
||||||
const episodeFile = _.find(episodeFiles.items, { id: episode.episodeFileId });
|
|
||||||
|
|
||||||
return {
|
|
||||||
relativePath: episodeFile.relativePath,
|
|
||||||
language: episodeFile.language,
|
|
||||||
quality: episodeFile.quality,
|
|
||||||
languageCutoffNotMet: episodeFile.languageCutoffNotMet,
|
|
||||||
qualityCutoffNotMet: episodeFile.qualityCutoffNotMet,
|
|
||||||
...episode
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
...schema,
|
|
||||||
items,
|
|
||||||
seriesType: series.seriesType,
|
|
||||||
isDeleting: episodeFiles.isDeleting,
|
|
||||||
isSaving: episodeFiles.isSaving
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createMapDispatchToProps(dispatch, props) {
|
|
||||||
return {
|
|
||||||
dispatchFetchLanguageProfileSchema(name, path) {
|
|
||||||
dispatch(fetchLanguageProfileSchema());
|
|
||||||
},
|
|
||||||
|
|
||||||
dispatchFetchQualityProfileSchema(name, path) {
|
|
||||||
dispatch(fetchQualityProfileSchema());
|
|
||||||
},
|
|
||||||
|
|
||||||
dispatchUpdateEpisodeFiles(updateProps) {
|
|
||||||
dispatch(updateEpisodeFiles(updateProps));
|
|
||||||
},
|
|
||||||
|
|
||||||
onDeletePress(episodeFileIds) {
|
|
||||||
dispatch(deleteEpisodeFiles({ episodeFileIds }));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
class EpisodeFileEditorModalContentConnector extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.props.dispatchFetchLanguageProfileSchema();
|
|
||||||
this.props.dispatchFetchQualityProfileSchema();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Listeners
|
|
||||||
|
|
||||||
onLanguageChange = (episodeFileIds, languageId) => {
|
|
||||||
const language = _.find(this.props.languages, { id: languageId });
|
|
||||||
|
|
||||||
this.props.dispatchUpdateEpisodeFiles({ episodeFileIds, language });
|
|
||||||
}
|
|
||||||
|
|
||||||
onQualityChange = (episodeFileIds, qualityId) => {
|
|
||||||
const quality = {
|
|
||||||
quality: _.find(this.props.qualities, { id: qualityId }),
|
|
||||||
revision: {
|
|
||||||
version: 1,
|
|
||||||
real: 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.props.dispatchUpdateEpisodeFiles({ episodeFileIds, quality });
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
dispatchFetchLanguageProfileSchema,
|
|
||||||
dispatchFetchQualityProfileSchema,
|
|
||||||
dispatchUpdateEpisodeFiles,
|
|
||||||
...otherProps
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<EpisodeFileEditorModalContent
|
|
||||||
{...otherProps}
|
|
||||||
onLanguageChange={this.onLanguageChange}
|
|
||||||
onQualityChange={this.onQualityChange}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EpisodeFileEditorModalContentConnector.propTypes = {
|
|
||||||
seriesId: PropTypes.number.isRequired,
|
|
||||||
seasonNumber: PropTypes.number,
|
|
||||||
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
qualities: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
dispatchFetchLanguageProfileSchema: PropTypes.func.isRequired,
|
|
||||||
dispatchFetchQualityProfileSchema: PropTypes.func.isRequired,
|
|
||||||
dispatchUpdateEpisodeFiles: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(createMapStateToProps, createMapDispatchToProps)(EpisodeFileEditorModalContentConnector);
|
|
@ -1,3 +0,0 @@
|
|||||||
.absoluteEpisodeNumber {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
|
||||||
import padNumber from 'Utilities/Number/padNumber';
|
|
||||||
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
|
||||||
import TableRow from 'Components/Table/TableRow';
|
|
||||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
|
||||||
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
|
|
||||||
import EpisodeLanguage from 'Episode/EpisodeLanguage';
|
|
||||||
import EpisodeQuality from 'Episode/EpisodeQuality';
|
|
||||||
import styles from './EpisodeFileEditorRow';
|
|
||||||
|
|
||||||
function EpisodeFileEditorRow(props) {
|
|
||||||
const {
|
|
||||||
id,
|
|
||||||
seriesType,
|
|
||||||
seasonNumber,
|
|
||||||
episodeNumber,
|
|
||||||
absoluteEpisodeNumber,
|
|
||||||
relativePath,
|
|
||||||
airDateUtc,
|
|
||||||
language,
|
|
||||||
quality,
|
|
||||||
qualityCutoffNotMet,
|
|
||||||
languageCutoffNotMet,
|
|
||||||
isSelected,
|
|
||||||
onSelectedChange
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TableRow>
|
|
||||||
<TableSelectCell
|
|
||||||
id={id}
|
|
||||||
isSelected={isSelected}
|
|
||||||
onSelectedChange={onSelectedChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TableRowCell>
|
|
||||||
{seasonNumber}x{padNumber(episodeNumber, 2)}
|
|
||||||
|
|
||||||
{
|
|
||||||
seriesType === 'anime' && !!absoluteEpisodeNumber &&
|
|
||||||
<span className={styles.absoluteEpisodeNumber}>
|
|
||||||
({absoluteEpisodeNumber})
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
</TableRowCell>
|
|
||||||
|
|
||||||
<TableRowCell>
|
|
||||||
{relativePath}
|
|
||||||
</TableRowCell>
|
|
||||||
|
|
||||||
<RelativeDateCellConnector
|
|
||||||
date={airDateUtc}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TableRowCell>
|
|
||||||
<EpisodeLanguage
|
|
||||||
language={language}
|
|
||||||
isCutoffNotMet={languageCutoffNotMet}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
|
|
||||||
<TableRowCell>
|
|
||||||
<EpisodeQuality
|
|
||||||
quality={quality}
|
|
||||||
isCutoffNotMet={qualityCutoffNotMet}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
EpisodeFileEditorRow.propTypes = {
|
|
||||||
id: PropTypes.number.isRequired,
|
|
||||||
seriesType: PropTypes.string.isRequired,
|
|
||||||
seasonNumber: PropTypes.number.isRequired,
|
|
||||||
episodeNumber: PropTypes.number.isRequired,
|
|
||||||
absoluteEpisodeNumber: PropTypes.number,
|
|
||||||
relativePath: PropTypes.string.isRequired,
|
|
||||||
airDateUtc: PropTypes.string.isRequired,
|
|
||||||
language: PropTypes.object.isRequired,
|
|
||||||
quality: PropTypes.object.isRequired,
|
|
||||||
qualityCutoffNotMet: PropTypes.bool.isRequired,
|
|
||||||
languageCutoffNotMet: PropTypes.bool.isRequired,
|
|
||||||
isSelected: PropTypes.bool,
|
|
||||||
onSelectedChange: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default EpisodeFileEditorRow;
|
|
Loading…
Reference in new issue