mirror of
https://github.com/Radarr/Radarr.git
synced 2026-04-15 21:05:48 -04:00
New: Set Indexer flags in Manual Import
This commit is contained in:
@@ -282,6 +282,7 @@ FormInputGroup.propTypes = {
|
||||
includeNoChange: PropTypes.bool,
|
||||
includeNoChangeDisabled: PropTypes.bool,
|
||||
selectedValueOptions: PropTypes.object,
|
||||
indexerFlags: PropTypes.number,
|
||||
pending: PropTypes.bool,
|
||||
errors: PropTypes.arrayOf(PropTypes.object),
|
||||
warnings: PropTypes.arrayOf(PropTypes.object),
|
||||
|
||||
@@ -4,22 +4,18 @@ import { createSelector } from 'reselect';
|
||||
import AppState from 'App/State/AppState';
|
||||
import EnhancedSelectInput from './EnhancedSelectInput';
|
||||
|
||||
interface IndexerFlagsSelectInputProps {
|
||||
name: string;
|
||||
indexerFlags: number;
|
||||
onChange(payload: object): void;
|
||||
}
|
||||
|
||||
const selectIndexerFlagsValues = (selectedFlags: number) =>
|
||||
createSelector(
|
||||
(state: AppState) => state.settings.indexerFlags,
|
||||
(indexerFlags) => {
|
||||
const value = indexerFlags.items
|
||||
.filter(
|
||||
// eslint-disable-next-line no-bitwise
|
||||
(item) => (selectedFlags & item.id) === item.id
|
||||
)
|
||||
.map(({ id }) => id);
|
||||
const value = indexerFlags.items.reduce((acc: number[], { id }) => {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
if ((selectedFlags & id) === id) {
|
||||
acc.push(id);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
const values = indexerFlags.items.map(({ id, name }) => ({
|
||||
key: id,
|
||||
@@ -33,6 +29,12 @@ const selectIndexerFlagsValues = (selectedFlags: number) =>
|
||||
}
|
||||
);
|
||||
|
||||
interface IndexerFlagsSelectInputProps {
|
||||
name: string;
|
||||
indexerFlags: number;
|
||||
onChange(payload: object): void;
|
||||
}
|
||||
|
||||
function IndexerFlagsSelectInput(props: IndexerFlagsSelectInputProps) {
|
||||
const { indexerFlags, onChange } = props;
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import SelectIndexerFlagsModalContent from './SelectIndexerFlagsModalContent';
|
||||
|
||||
interface SelectIndexerFlagsModalProps {
|
||||
isOpen: boolean;
|
||||
indexerFlags: number;
|
||||
modalTitle: string;
|
||||
onIndexerFlagsSelect(indexerFlags: number): void;
|
||||
onModalClose(): void;
|
||||
}
|
||||
|
||||
function SelectIndexerFlagsModal(props: SelectIndexerFlagsModalProps) {
|
||||
const {
|
||||
isOpen,
|
||||
indexerFlags,
|
||||
modalTitle,
|
||||
onIndexerFlagsSelect,
|
||||
onModalClose,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onModalClose={onModalClose}>
|
||||
<SelectIndexerFlagsModalContent
|
||||
indexerFlags={indexerFlags}
|
||||
modalTitle={modalTitle}
|
||||
onIndexerFlagsSelect={onIndexerFlagsSelect}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default SelectIndexerFlagsModal;
|
||||
@@ -0,0 +1,7 @@
|
||||
.modalBody {
|
||||
composes: modalBody from '~Components/Modal/ModalBody.css';
|
||||
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
flex-direction: column;
|
||||
}
|
||||
7
frontend/src/InteractiveImport/IndexerFlags/SelectIndexerFlagsModalContent.css.d.ts
vendored
Normal file
7
frontend/src/InteractiveImport/IndexerFlags/SelectIndexerFlagsModalContent.css.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'modalBody': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -0,0 +1,75 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import Form from 'Components/Form/Form';
|
||||
import FormGroup from 'Components/Form/FormGroup';
|
||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
import FormLabel from 'Components/Form/FormLabel';
|
||||
import Button from 'Components/Link/Button';
|
||||
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 { inputTypes, kinds, scrollDirections } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './SelectIndexerFlagsModalContent.css';
|
||||
|
||||
interface SelectIndexerFlagsModalContentProps {
|
||||
indexerFlags: number;
|
||||
modalTitle: string;
|
||||
onIndexerFlagsSelect(indexerFlags: number): void;
|
||||
onModalClose(): void;
|
||||
}
|
||||
|
||||
function SelectIndexerFlagsModalContent(
|
||||
props: SelectIndexerFlagsModalContentProps
|
||||
) {
|
||||
const { modalTitle, onIndexerFlagsSelect, onModalClose } = props;
|
||||
const [indexerFlags, setIndexerFlags] = useState(props.indexerFlags);
|
||||
|
||||
const onIndexerFlagsChange = useCallback(
|
||||
({ value }: { value: number }) => {
|
||||
setIndexerFlags(value);
|
||||
},
|
||||
[setIndexerFlags]
|
||||
);
|
||||
|
||||
const onIndexerFlagsSelectWrapper = useCallback(() => {
|
||||
onIndexerFlagsSelect(indexerFlags);
|
||||
}, [indexerFlags, onIndexerFlagsSelect]);
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
{translate('SetIndexerFlagsModalTitle', { modalTitle })}
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody
|
||||
className={styles.modalBody}
|
||||
scrollDirection={scrollDirections.NONE}
|
||||
>
|
||||
<Form>
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('IndexerFlags')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.INDEXER_FLAGS_SELECT}
|
||||
name="indexerFlags"
|
||||
indexerFlags={indexerFlags}
|
||||
autoFocus={true}
|
||||
onChange={onIndexerFlagsChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
|
||||
|
||||
<Button kind={kinds.SUCCESS} onPress={onIndexerFlagsSelectWrapper}>
|
||||
{translate('SetIndexerFlags')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
|
||||
export default SelectIndexerFlagsModalContent;
|
||||
@@ -26,6 +26,7 @@ import usePrevious from 'Helpers/Hooks/usePrevious';
|
||||
import useSelectState from 'Helpers/Hooks/useSelectState';
|
||||
import { align, icons, kinds, scrollDirections } from 'Helpers/Props';
|
||||
import ImportMode from 'InteractiveImport/ImportMode';
|
||||
import SelectIndexerFlagsModal from 'InteractiveImport/IndexerFlags/SelectIndexerFlagsModal';
|
||||
import InteractiveImport, {
|
||||
InteractiveImportCommandOptions,
|
||||
} from 'InteractiveImport/InteractiveImport';
|
||||
@@ -59,7 +60,13 @@ import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
||||
import InteractiveImportRow from './InteractiveImportRow';
|
||||
import styles from './InteractiveImportModalContent.css';
|
||||
|
||||
type SelectType = 'select' | 'movie' | 'releaseGroup' | 'quality' | 'language';
|
||||
type SelectType =
|
||||
| 'select'
|
||||
| 'movie'
|
||||
| 'releaseGroup'
|
||||
| 'quality'
|
||||
| 'language'
|
||||
| 'indexerFlags';
|
||||
|
||||
type FilterExistingFiles = 'all' | 'new';
|
||||
|
||||
@@ -113,6 +120,15 @@ const COLUMNS = [
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'indexerFlags',
|
||||
label: React.createElement(Icon, {
|
||||
name: icons.FLAG,
|
||||
title: () => translate('IndexerFlags'),
|
||||
}),
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'rejections',
|
||||
label: React.createElement(Icon, {
|
||||
@@ -257,8 +273,18 @@ function InteractiveImportModalContent(
|
||||
}
|
||||
}
|
||||
|
||||
const showIndexerFlags = items.some((item) => item.indexerFlags);
|
||||
|
||||
if (!showIndexerFlags) {
|
||||
const indexerFlagsColumn = result.find((c) => c.name === 'indexerFlags');
|
||||
|
||||
if (indexerFlagsColumn) {
|
||||
indexerFlagsColumn.isVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}, [showMovie]);
|
||||
}, [showMovie, items]);
|
||||
|
||||
const selectedIds: number[] = useMemo(() => {
|
||||
return getSelectedIds(selectedState);
|
||||
@@ -283,6 +309,10 @@ function InteractiveImportModalContent(
|
||||
key: 'language',
|
||||
value: translate('SelectLanguage'),
|
||||
},
|
||||
{
|
||||
key: 'indexerFlags',
|
||||
value: translate('SelectIndexerFlags'),
|
||||
},
|
||||
];
|
||||
|
||||
if (allowMovieChange) {
|
||||
@@ -416,7 +446,14 @@ function InteractiveImportModalContent(
|
||||
const isSelected = selectedIds.indexOf(item.id) > -1;
|
||||
|
||||
if (isSelected) {
|
||||
const { movie, releaseGroup, quality, languages, movieFileId } = item;
|
||||
const {
|
||||
movie,
|
||||
releaseGroup,
|
||||
quality,
|
||||
languages,
|
||||
indexerFlags,
|
||||
movieFileId,
|
||||
} = item;
|
||||
|
||||
if (!movie) {
|
||||
setInteractiveImportErrorMessage(
|
||||
@@ -450,6 +487,7 @@ function InteractiveImportModalContent(
|
||||
releaseGroup,
|
||||
quality,
|
||||
languages,
|
||||
indexerFlags,
|
||||
});
|
||||
|
||||
return;
|
||||
@@ -463,6 +501,7 @@ function InteractiveImportModalContent(
|
||||
releaseGroup,
|
||||
quality,
|
||||
languages,
|
||||
indexerFlags,
|
||||
downloadId,
|
||||
movieFileId,
|
||||
});
|
||||
@@ -620,6 +659,22 @@ function InteractiveImportModalContent(
|
||||
[selectedIds, dispatch]
|
||||
);
|
||||
|
||||
const onIndexerFlagsSelect = useCallback(
|
||||
(indexerFlags: number) => {
|
||||
dispatch(
|
||||
updateInteractiveImportItems({
|
||||
ids: selectedIds,
|
||||
indexerFlags,
|
||||
})
|
||||
);
|
||||
|
||||
dispatch(reprocessInteractiveImportItems({ ids: selectedIds }));
|
||||
|
||||
setSelectModalOpen(null);
|
||||
},
|
||||
[selectedIds, dispatch]
|
||||
);
|
||||
|
||||
const errorMessage = getErrorMessage(
|
||||
error,
|
||||
translate('InteractiveImportLoadError')
|
||||
@@ -794,6 +849,14 @@ function InteractiveImportModalContent(
|
||||
onModalClose={onSelectModalClose}
|
||||
/>
|
||||
|
||||
<SelectIndexerFlagsModal
|
||||
isOpen={selectModalOpen === 'indexerFlags'}
|
||||
indexerFlags={0}
|
||||
modalTitle={modalTitle}
|
||||
onIndexerFlagsSelect={onIndexerFlagsSelect}
|
||||
onModalClose={onSelectModalClose}
|
||||
/>
|
||||
|
||||
<ConfirmModal
|
||||
isOpen={isConfirmDeleteModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
|
||||
@@ -8,11 +8,13 @@ import Column from 'Components/Table/Column';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import SelectIndexerFlagsModal from 'InteractiveImport/IndexerFlags/SelectIndexerFlagsModal';
|
||||
import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal';
|
||||
import SelectMovieModal from 'InteractiveImport/Movie/SelectMovieModal';
|
||||
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
|
||||
import SelectReleaseGroupModal from 'InteractiveImport/ReleaseGroup/SelectReleaseGroupModal';
|
||||
import Language from 'Language/Language';
|
||||
import IndexerFlags from 'Movie/IndexerFlags';
|
||||
import Movie from 'Movie/Movie';
|
||||
import MovieFormats from 'Movie/MovieFormats';
|
||||
import MovieLanguage from 'Movie/MovieLanguage';
|
||||
@@ -30,7 +32,12 @@ import translate from 'Utilities/String/translate';
|
||||
import InteractiveImportRowCellPlaceholder from './InteractiveImportRowCellPlaceholder';
|
||||
import styles from './InteractiveImportRow.css';
|
||||
|
||||
type SelectType = 'movie' | 'releaseGroup' | 'quality' | 'language';
|
||||
type SelectType =
|
||||
| 'movie'
|
||||
| 'releaseGroup'
|
||||
| 'quality'
|
||||
| 'language'
|
||||
| 'indexerFlags';
|
||||
|
||||
type SelectedChangeProps = SelectStateInputProps & {
|
||||
hasMovieFileId: boolean;
|
||||
@@ -47,6 +54,7 @@ interface InteractiveImportRowProps {
|
||||
size: number;
|
||||
customFormats?: object[];
|
||||
customFormatScore?: number;
|
||||
indexerFlags: number;
|
||||
rejections: Rejection[];
|
||||
columns: Column[];
|
||||
movieFileId?: number;
|
||||
@@ -69,6 +77,7 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
|
||||
size,
|
||||
customFormats,
|
||||
customFormatScore,
|
||||
indexerFlags,
|
||||
rejections,
|
||||
isSelected,
|
||||
modalTitle,
|
||||
@@ -84,6 +93,10 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
|
||||
() => columns.find((c) => c.name === 'movie')?.isVisible ?? false,
|
||||
[columns]
|
||||
);
|
||||
const isIndexerFlagsColumnVisible = useMemo(
|
||||
() => columns.find((c) => c.name === 'indexerFlags')?.isVisible ?? false,
|
||||
[columns]
|
||||
);
|
||||
|
||||
const [selectModalOpen, setSelectModalOpen] = useState<SelectType | null>(
|
||||
null
|
||||
@@ -223,12 +236,34 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
|
||||
[id, dispatch, setSelectModalOpen, selectRowAfterChange]
|
||||
);
|
||||
|
||||
const onSelectIndexerFlagsPress = useCallback(() => {
|
||||
setSelectModalOpen('indexerFlags');
|
||||
}, [setSelectModalOpen]);
|
||||
|
||||
const onIndexerFlagsSelect = useCallback(
|
||||
(indexerFlags: number) => {
|
||||
dispatch(
|
||||
updateInteractiveImportItem({
|
||||
id,
|
||||
indexerFlags,
|
||||
})
|
||||
);
|
||||
|
||||
dispatch(reprocessInteractiveImportItems({ ids: [id] }));
|
||||
|
||||
setSelectModalOpen(null);
|
||||
selectRowAfterChange();
|
||||
},
|
||||
[id, dispatch, setSelectModalOpen, selectRowAfterChange]
|
||||
);
|
||||
|
||||
const movieTitle = movie ? movie.title : '';
|
||||
|
||||
const showMoviePlaceholder = isSelected && !movie;
|
||||
const showReleaseGroupPlaceholder = isSelected && !releaseGroup;
|
||||
const showQualityPlaceholder = isSelected && !quality;
|
||||
const showLanguagePlaceholder = isSelected && !languages;
|
||||
const showIndexerFlagsPlaceholder = isSelected && !indexerFlags;
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
@@ -311,6 +346,28 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
|
||||
) : null}
|
||||
</TableRowCell>
|
||||
|
||||
{isIndexerFlagsColumnVisible ? (
|
||||
<TableRowCellButton
|
||||
title={translate('ClickToChangeIndexerFlags')}
|
||||
onPress={onSelectIndexerFlagsPress}
|
||||
>
|
||||
{showIndexerFlagsPlaceholder ? (
|
||||
<InteractiveImportRowCellPlaceholder isOptional={true} />
|
||||
) : (
|
||||
<>
|
||||
{indexerFlags ? (
|
||||
<Popover
|
||||
anchor={<Icon name={icons.FLAG} kind={kinds.PRIMARY} />}
|
||||
title={translate('IndexerFlags')}
|
||||
body={<IndexerFlags indexerFlags={indexerFlags} />}
|
||||
position={tooltipPositions.LEFT}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</TableRowCellButton>
|
||||
) : null}
|
||||
|
||||
<TableRowCell>
|
||||
{rejections.length ? (
|
||||
<Popover
|
||||
@@ -361,6 +418,14 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
|
||||
onLanguagesSelect={onLanguagesSelect}
|
||||
onModalClose={onSelectModalClose}
|
||||
/>
|
||||
|
||||
<SelectIndexerFlagsModal
|
||||
isOpen={selectModalOpen === 'indexerFlags'}
|
||||
indexerFlags={indexerFlags ?? 0}
|
||||
modalTitle={modalTitle}
|
||||
onIndexerFlagsSelect={onIndexerFlagsSelect}
|
||||
onModalClose={onSelectModalClose}
|
||||
/>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ export interface InteractiveImportCommandOptions {
|
||||
releaseGroup?: string;
|
||||
quality: QualityModel;
|
||||
languages: Language[];
|
||||
indexerFlags: number;
|
||||
downloadId?: string;
|
||||
movieFileId?: number;
|
||||
}
|
||||
@@ -27,6 +28,7 @@ interface InteractiveImport extends ModelBase {
|
||||
movie?: Movie;
|
||||
qualityWeight: number;
|
||||
customFormats: object[];
|
||||
indexerFlags: number;
|
||||
rejections: Rejection[];
|
||||
movieFileId?: number;
|
||||
}
|
||||
|
||||
@@ -39,8 +39,7 @@
|
||||
}
|
||||
|
||||
.rejected,
|
||||
.indexerFlags,
|
||||
.download {
|
||||
.indexerFlags {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
width: 50px;
|
||||
|
||||
@@ -11,6 +11,7 @@ import Tooltip from 'Components/Tooltip/Tooltip';
|
||||
import type DownloadProtocol from 'DownloadClient/DownloadProtocol';
|
||||
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import Language from 'Language/Language';
|
||||
import IndexerFlags from 'Movie/IndexerFlags';
|
||||
import MovieFormats from 'Movie/MovieFormats';
|
||||
import MovieLanguage from 'Movie/MovieLanguage';
|
||||
import MovieQuality from 'Movie/MovieQuality';
|
||||
@@ -90,8 +91,8 @@ interface InteractiveSearchRowProps {
|
||||
customFormats: CustomFormat[];
|
||||
customFormatScore: number;
|
||||
mappedMovieId?: number;
|
||||
indexerFlags: number;
|
||||
rejections: string[];
|
||||
indexerFlags: string[];
|
||||
downloadAllowed: boolean;
|
||||
isGrabbing: boolean;
|
||||
isGrabbed: boolean;
|
||||
@@ -125,8 +126,8 @@ function InteractiveSearchRow(props: InteractiveSearchRowProps) {
|
||||
customFormatScore,
|
||||
customFormats,
|
||||
mappedMovieId,
|
||||
indexerFlags = 0,
|
||||
rejections = [],
|
||||
indexerFlags = [],
|
||||
downloadAllowed,
|
||||
isGrabbing = false,
|
||||
isGrabbed = false,
|
||||
@@ -276,22 +277,16 @@ function InteractiveSearchRow(props: InteractiveSearchRowProps) {
|
||||
customFormats.length
|
||||
)}
|
||||
tooltip={<MovieFormats formats={customFormats} />}
|
||||
position={tooltipPositions.TOP}
|
||||
position={tooltipPositions.LEFT}
|
||||
/>
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell className={styles.indexerFlags}>
|
||||
{indexerFlags.length ? (
|
||||
{indexerFlags ? (
|
||||
<Popover
|
||||
anchor={<Icon name={icons.FLAG} kind={kinds.PRIMARY} />}
|
||||
title={translate('IndexerFlags')}
|
||||
body={
|
||||
<ul>
|
||||
{indexerFlags.map((flag, index) => {
|
||||
return <li key={index}>{flag}</li>;
|
||||
})}
|
||||
</ul>
|
||||
}
|
||||
body={<IndexerFlags indexerFlags={indexerFlags} />}
|
||||
position={tooltipPositions.LEFT}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
26
frontend/src/Movie/IndexerFlags.tsx
Normal file
26
frontend/src/Movie/IndexerFlags.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import createIndexerFlagsSelector from 'Store/Selectors/createIndexerFlagsSelector';
|
||||
|
||||
interface IndexerFlagsProps {
|
||||
indexerFlags: number;
|
||||
}
|
||||
|
||||
function IndexerFlags({ indexerFlags = 0 }: IndexerFlagsProps) {
|
||||
const allIndexerFlags = useSelector(createIndexerFlagsSelector);
|
||||
|
||||
const flags = allIndexerFlags.items.filter(
|
||||
// eslint-disable-next-line no-bitwise
|
||||
(item) => (indexerFlags & item.id) === item.id
|
||||
);
|
||||
|
||||
return flags.length ? (
|
||||
<ul>
|
||||
{flags.map((flag, index) => {
|
||||
return <li key={index}>{flag.name}</li>;
|
||||
})}
|
||||
</ul>
|
||||
) : null;
|
||||
}
|
||||
|
||||
export default IndexerFlags;
|
||||
@@ -57,3 +57,9 @@
|
||||
|
||||
width: 55px;
|
||||
}
|
||||
|
||||
.indexerFlags {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ interface CssExports {
|
||||
'dateAdded': string;
|
||||
'download': string;
|
||||
'formats': string;
|
||||
'indexerFlags': string;
|
||||
'language': string;
|
||||
'languages': string;
|
||||
'quality': string;
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Icon from 'Components/Icon';
|
||||
import IconButton from 'Components/Link/IconButton';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import Tooltip from 'Components/Tooltip/Tooltip';
|
||||
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import IndexerFlags from 'Movie/IndexerFlags';
|
||||
import MovieFormats from 'Movie/MovieFormats';
|
||||
import MovieLanguage from 'Movie/MovieLanguage';
|
||||
import MovieQuality from 'Movie/MovieQuality';
|
||||
@@ -82,6 +85,7 @@ class MovieFileEditorRow extends Component {
|
||||
qualityCutoffNotMet,
|
||||
customFormats,
|
||||
customFormatScore,
|
||||
indexerFlags,
|
||||
languages,
|
||||
dateAdded,
|
||||
columns
|
||||
@@ -143,12 +147,30 @@ class MovieFileEditorRow extends Component {
|
||||
customFormats.length
|
||||
)}
|
||||
tooltip={<MovieFormats formats={customFormats} />}
|
||||
position={tooltipPositions.TOP}
|
||||
position={tooltipPositions.LEFT}
|
||||
/>
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'indexerFlags') {
|
||||
return (
|
||||
<TableRowCell
|
||||
key={name}
|
||||
className={styles.indexerFlags}
|
||||
>
|
||||
{indexerFlags ? (
|
||||
<Popover
|
||||
anchor={<Icon name={icons.FLAG} kind={kinds.PRIMARY} />}
|
||||
title={translate('IndexerFlags')}
|
||||
body={<IndexerFlags indexerFlags={indexerFlags} />}
|
||||
position={tooltipPositions.LEFT}
|
||||
/>
|
||||
) : null}
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'languages') {
|
||||
return (
|
||||
<TableRowCell
|
||||
@@ -363,6 +385,7 @@ MovieFileEditorRow.propTypes = {
|
||||
releaseGroup: PropTypes.string,
|
||||
customFormats: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
customFormatScore: PropTypes.number.isRequired,
|
||||
indexerFlags: PropTypes.number.isRequired,
|
||||
qualityCutoffNotMet: PropTypes.bool.isRequired,
|
||||
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
mediaInfo: PropTypes.object,
|
||||
@@ -372,7 +395,8 @@ MovieFileEditorRow.propTypes = {
|
||||
};
|
||||
|
||||
MovieFileEditorRow.defaultProps = {
|
||||
customFormats: []
|
||||
customFormats: [],
|
||||
indexerFlags: 0
|
||||
};
|
||||
|
||||
export default MovieFileEditorRow;
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface MovieFile extends ModelBase {
|
||||
languages: Language[];
|
||||
quality: QualityModel;
|
||||
customFormats: CustomFormat[];
|
||||
indexerFlags: number;
|
||||
mediaInfo: MediaInfo;
|
||||
qualityCutoffNotMet: boolean;
|
||||
}
|
||||
|
||||
@@ -159,6 +159,7 @@ export const actionHandlers = handleThunks({
|
||||
quality: item.quality,
|
||||
languages: item.languages,
|
||||
releaseGroup: item.releaseGroup,
|
||||
indexerFlags: item.indexerFlags,
|
||||
downloadId: item.downloadId
|
||||
};
|
||||
});
|
||||
|
||||
@@ -104,6 +104,15 @@ export const defaultState = {
|
||||
isVisible: true,
|
||||
isSortable: true
|
||||
},
|
||||
{
|
||||
name: 'indexerFlags',
|
||||
columnLabel: () => translate('IndexerFlags'),
|
||||
label: React.createElement(Icon, {
|
||||
name: icons.FLAG,
|
||||
title: () => translate('IndexerFlags')
|
||||
}),
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'dateAdded',
|
||||
label: () => translate('Added'),
|
||||
|
||||
Reference in New Issue
Block a user