parent
ff16043a06
commit
99d315979e
@ -0,0 +1,8 @@
|
||||
.link {
|
||||
composes: link from '~Components/Link/Link.css';
|
||||
|
||||
&:hover {
|
||||
color: var(--linkHoverColor);
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'link': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
@ -0,0 +1,44 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import Link from 'Components/Link/Link';
|
||||
import IndexerInfoModal from './Info/IndexerInfoModal';
|
||||
import styles from './IndexerTitleLink.css';
|
||||
|
||||
interface IndexerTitleLinkProps {
|
||||
indexerName: string;
|
||||
indexerId: number;
|
||||
}
|
||||
|
||||
function IndexerTitleLink(props: IndexerTitleLinkProps) {
|
||||
const { indexerName, indexerId } = props;
|
||||
|
||||
const [isIndexerInfoModalOpen, setIsIndexerInfoModalOpen] = useState(false);
|
||||
|
||||
const onIndexerInfoPress = useCallback(() => {
|
||||
setIsIndexerInfoModalOpen(true);
|
||||
}, [setIsIndexerInfoModalOpen]);
|
||||
|
||||
const onIndexerInfoModalClose = useCallback(() => {
|
||||
setIsIndexerInfoModalOpen(false);
|
||||
}, [setIsIndexerInfoModalOpen]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Link className={styles.link} onPress={onIndexerInfoPress}>
|
||||
{indexerName}
|
||||
</Link>
|
||||
|
||||
<IndexerInfoModal
|
||||
indexerId={indexerId}
|
||||
isOpen={isIndexerInfoModalOpen}
|
||||
onModalClose={onIndexerInfoModalClose}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
IndexerTitleLink.propTypes = {
|
||||
indexerName: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default IndexerTitleLink;
|
@ -1,27 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import { sizes } from 'Helpers/Props';
|
||||
import IndexerInfoModalContentConnector from './IndexerInfoModalContentConnector';
|
||||
|
||||
function IndexerInfoModal({ isOpen, onModalClose, ...otherProps }) {
|
||||
return (
|
||||
<Modal
|
||||
size={sizes.MEDIUM}
|
||||
isOpen={isOpen}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<IndexerInfoModalContentConnector
|
||||
{...otherProps}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
IndexerInfoModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default IndexerInfoModal;
|
@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import { sizes } from 'Helpers/Props';
|
||||
import IndexerInfoModalContent from './IndexerInfoModalContent';
|
||||
|
||||
interface IndexerInfoModalProps {
|
||||
isOpen: boolean;
|
||||
indexerId: number;
|
||||
onModalClose(): void;
|
||||
}
|
||||
|
||||
function IndexerInfoModal(props: IndexerInfoModalProps) {
|
||||
const { isOpen, onModalClose, indexerId } = props;
|
||||
|
||||
return (
|
||||
<Modal size={sizes.MEDIUM} isOpen={isOpen} onModalClose={onModalClose}>
|
||||
<IndexerInfoModalContent
|
||||
indexerId={indexerId}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default IndexerInfoModal;
|
@ -1,126 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
||||
import DescriptionListItemDescription from 'Components/DescriptionList/DescriptionListItemDescription';
|
||||
import DescriptionListItemTitle from 'Components/DescriptionList/DescriptionListItemTitle';
|
||||
import FieldSet from 'Components/FieldSet';
|
||||
import Link from 'Components/Link/Link';
|
||||
import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './IndexerInfoModalContent.css';
|
||||
|
||||
function IndexerInfoModalContent(props) {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
encoding,
|
||||
language,
|
||||
indexerUrls,
|
||||
fields,
|
||||
protocol,
|
||||
capabilities,
|
||||
onModalClose
|
||||
} = props;
|
||||
|
||||
const baseUrl = fields.find((field) => field.name === 'baseUrl')?.value ?? indexerUrls[0];
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
{`${name}`}
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
<FieldSet legend={translate('IndexerDetails')}>
|
||||
<div className={styles.groups}>
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('Id')}
|
||||
data={id}
|
||||
/>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('Description')}
|
||||
data={description ? description : '-'}
|
||||
/>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('Encoding')}
|
||||
data={encoding ? encoding : '-'}
|
||||
/>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('Language')}
|
||||
data={language ?? '-'}
|
||||
/>
|
||||
<DescriptionListItemTitle>{translate('IndexerSite')}</DescriptionListItemTitle>
|
||||
<DescriptionListItemDescription>
|
||||
<Link to={baseUrl}>{baseUrl}</Link>
|
||||
</DescriptionListItemDescription>
|
||||
<DescriptionListItemTitle>{`${protocol === 'usenet' ? 'Newznab' : 'Torznab'} Url`}</DescriptionListItemTitle>
|
||||
<DescriptionListItemDescription>
|
||||
{`${window.location.origin}${window.Prowlarr.urlBase}/${id}/api`}
|
||||
</DescriptionListItemDescription>
|
||||
</DescriptionList>
|
||||
</div>
|
||||
</FieldSet>
|
||||
<FieldSet legend={translate('SearchCapabilities')}>
|
||||
<div className={styles.groups}>
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('RawSearchSupported')}
|
||||
data={capabilities.supportsRawSearch ? translate('Yes') : translate('No')}
|
||||
/>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('SearchTypes')}
|
||||
data={capabilities.searchParams.length === 0 ? translate('NotSupported') : capabilities.searchParams[0]}
|
||||
/>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('TVSearchTypes')}
|
||||
data={capabilities.tvSearchParams.length === 0 ? translate('NotSupported') : capabilities.tvSearchParams.join(', ')}
|
||||
/>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('MovieSearchTypes')}
|
||||
data={capabilities.movieSearchParams.length === 0 ? translate('NotSupported') : capabilities.movieSearchParams.join(', ')}
|
||||
/>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('BookSearchTypes')}
|
||||
data={capabilities.bookSearchParams.length === 0 ? translate('NotSupported') : capabilities.bookSearchParams.join(', ')}
|
||||
/>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('MusicSearchTypes')}
|
||||
data={capabilities.musicSearchParams.length === 0 ? translate('NotSupported') : capabilities.musicSearchParams.join(', ')}
|
||||
/>
|
||||
</DescriptionList>
|
||||
</div>
|
||||
</FieldSet>
|
||||
</ModalBody>
|
||||
</ModalContent >
|
||||
);
|
||||
}
|
||||
|
||||
IndexerInfoModalContent.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
description: PropTypes.string.isRequired,
|
||||
encoding: PropTypes.string.isRequired,
|
||||
language: PropTypes.string.isRequired,
|
||||
indexerUrls: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
fields: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
protocol: PropTypes.string.isRequired,
|
||||
capabilities: PropTypes.object.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default IndexerInfoModalContent;
|
@ -0,0 +1,200 @@
|
||||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
||||
import DescriptionListItemDescription from 'Components/DescriptionList/DescriptionListItemDescription';
|
||||
import DescriptionListItemTitle from 'Components/DescriptionList/DescriptionListItemTitle';
|
||||
import FieldSet from 'Components/FieldSet';
|
||||
import Label from 'Components/Label';
|
||||
import Button from 'Components/Link/Button';
|
||||
import Link from 'Components/Link/Link';
|
||||
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 { kinds } from 'Helpers/Props';
|
||||
import Indexer from 'Indexer/Indexer';
|
||||
import createIndexerSelector from 'Store/Selectors/createIndexerSelector';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './IndexerInfoModalContent.css';
|
||||
|
||||
function createIndexerInfoItemSelector(indexerId: number) {
|
||||
return createSelector(
|
||||
createIndexerSelector(indexerId),
|
||||
(indexer: Indexer) => {
|
||||
return {
|
||||
indexer,
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
interface IndexerInfoModalContentProps {
|
||||
indexerId: number;
|
||||
onModalClose(): void;
|
||||
}
|
||||
|
||||
function IndexerInfoModalContent(props: IndexerInfoModalContentProps) {
|
||||
const { indexer } = useSelector(
|
||||
createIndexerInfoItemSelector(props.indexerId)
|
||||
);
|
||||
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
encoding,
|
||||
language,
|
||||
indexerUrls,
|
||||
fields,
|
||||
protocol,
|
||||
capabilities,
|
||||
} = indexer;
|
||||
|
||||
const { onModalClose } = props;
|
||||
|
||||
const baseUrl =
|
||||
fields.find((field) => field.name === 'baseUrl')?.value ??
|
||||
(Array.isArray(indexerUrls) ? indexerUrls[0] : undefined);
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>{`${name}`}</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
<FieldSet legend={translate('IndexerDetails')}>
|
||||
<div>
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('Id')}
|
||||
data={id}
|
||||
/>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('Description')}
|
||||
data={description ? description : '-'}
|
||||
/>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('Encoding')}
|
||||
data={encoding ? encoding : '-'}
|
||||
/>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('Language')}
|
||||
data={language ?? '-'}
|
||||
/>
|
||||
<DescriptionListItemTitle>
|
||||
{translate('IndexerSite')}
|
||||
</DescriptionListItemTitle>
|
||||
<DescriptionListItemDescription>
|
||||
<Link to={baseUrl}>{baseUrl.replace('api.', '')}</Link>
|
||||
</DescriptionListItemDescription>
|
||||
<DescriptionListItemTitle>{`${
|
||||
protocol === 'usenet' ? 'Newznab' : 'Torznab'
|
||||
} Url`}</DescriptionListItemTitle>
|
||||
<DescriptionListItemDescription>
|
||||
{`${window.location.origin}${window.Prowlarr.urlBase}/${id}/api`}
|
||||
</DescriptionListItemDescription>
|
||||
</DescriptionList>
|
||||
</div>
|
||||
</FieldSet>
|
||||
<FieldSet legend={translate('SearchCapabilities')}>
|
||||
<div>
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('RawSearchSupported')}
|
||||
data={
|
||||
capabilities.supportsRawSearch
|
||||
? translate('Yes')
|
||||
: translate('No')
|
||||
}
|
||||
/>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('SearchTypes')}
|
||||
data={
|
||||
capabilities.searchParams.length === 0 ? (
|
||||
translate('NotSupported')
|
||||
) : (
|
||||
<Label kind={kinds.PRIMARY}>
|
||||
{capabilities.searchParams[0]}
|
||||
</Label>
|
||||
)
|
||||
}
|
||||
/>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('TVSearchTypes')}
|
||||
data={
|
||||
capabilities.tvSearchParams.length === 0
|
||||
? translate('NotSupported')
|
||||
: capabilities.tvSearchParams.map((p) => {
|
||||
return (
|
||||
<Label key={p} kind={kinds.PRIMARY}>
|
||||
{p}
|
||||
</Label>
|
||||
);
|
||||
})
|
||||
}
|
||||
/>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('MovieSearchTypes')}
|
||||
data={
|
||||
capabilities.movieSearchParams.length === 0
|
||||
? translate('NotSupported')
|
||||
: capabilities.movieSearchParams.map((p) => {
|
||||
return (
|
||||
<Label key={p} kind={kinds.PRIMARY}>
|
||||
{p}
|
||||
</Label>
|
||||
);
|
||||
})
|
||||
}
|
||||
/>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('BookSearchTypes')}
|
||||
data={
|
||||
capabilities.bookSearchParams.length === 0
|
||||
? translate('NotSupported')
|
||||
: capabilities.bookSearchParams.map((p) => {
|
||||
return (
|
||||
<Label key={p} kind={kinds.PRIMARY}>
|
||||
{p}
|
||||
</Label>
|
||||
);
|
||||
})
|
||||
}
|
||||
/>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('MusicSearchTypes')}
|
||||
data={
|
||||
capabilities.musicSearchParams.length === 0
|
||||
? translate('NotSupported')
|
||||
: capabilities.musicSearchParams.map((p) => {
|
||||
return (
|
||||
<Label key={p} kind={kinds.PRIMARY}>
|
||||
{p}
|
||||
</Label>
|
||||
);
|
||||
})
|
||||
}
|
||||
/>
|
||||
</DescriptionList>
|
||||
</div>
|
||||
</FieldSet>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button onPress={onModalClose}>{translate('Close')}</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
|
||||
export default IndexerInfoModalContent;
|
@ -1,40 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import createIndexerSelector from 'Store/Selectors/createIndexerSelector';
|
||||
import IndexerInfoModalContent from './IndexerInfoModalContent';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.settings.advancedSettings,
|
||||
createIndexerSelector(),
|
||||
(advancedSettings, indexer) => {
|
||||
return {
|
||||
advancedSettings,
|
||||
...indexer
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
class IndexerInfoModalContentConnector extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<IndexerInfoModalContent
|
||||
{...this.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
IndexerInfoModalContentConnector.propTypes = {
|
||||
indexerId: PropTypes.number,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps)(IndexerInfoModalContentConnector);
|
Loading…
Reference in new issue