mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2025-09-17 17:14:18 +02:00
Fix indexer url info
This commit is contained in:
@@ -1,8 +1,6 @@
|
|||||||
import { uniqBy } from 'lodash';
|
import { uniqBy } from 'lodash';
|
||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useState } from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
|
||||||
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
|
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
import { createSelector } from 'reselect';
|
|
||||||
import Alert from 'Components/Alert';
|
import Alert from 'Components/Alert';
|
||||||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
||||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
||||||
@@ -26,23 +24,12 @@ import DeleteIndexerModal from 'Indexer/Delete/DeleteIndexerModal';
|
|||||||
import EditIndexerModalConnector from 'Indexer/Edit/EditIndexerModalConnector';
|
import EditIndexerModalConnector from 'Indexer/Edit/EditIndexerModalConnector';
|
||||||
import PrivacyLabel from 'Indexer/Index/Table/PrivacyLabel';
|
import PrivacyLabel from 'Indexer/Index/Table/PrivacyLabel';
|
||||||
import Indexer, { IndexerCapabilities } from 'Indexer/Indexer';
|
import Indexer, { IndexerCapabilities } from 'Indexer/Indexer';
|
||||||
import { createIndexerSelectorForHook } from 'Store/Selectors/createIndexerSelector';
|
import useIndexer from 'Indexer/useIndexer';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import IndexerHistory from './History/IndexerHistory';
|
import IndexerHistory from './History/IndexerHistory';
|
||||||
import styles from './IndexerInfoModalContent.css';
|
import styles from './IndexerInfoModalContent.css';
|
||||||
|
|
||||||
function createIndexerInfoItemSelector(indexerId: number) {
|
const TABS = ['details', 'categories', 'history', 'stats'];
|
||||||
return createSelector(
|
|
||||||
createIndexerSelectorForHook(indexerId),
|
|
||||||
(indexer?: Indexer) => {
|
|
||||||
return {
|
|
||||||
indexer,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const tabs = ['details', 'categories', 'history', 'stats'];
|
|
||||||
|
|
||||||
interface IndexerInfoModalContentProps {
|
interface IndexerInfoModalContentProps {
|
||||||
indexerId: number;
|
indexerId: number;
|
||||||
@@ -51,9 +38,7 @@ interface IndexerInfoModalContentProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function IndexerInfoModalContent(props: IndexerInfoModalContentProps) {
|
function IndexerInfoModalContent(props: IndexerInfoModalContentProps) {
|
||||||
const { indexerId, onCloneIndexerPress } = props;
|
const { indexerId, onModalClose, onCloneIndexerPress } = props;
|
||||||
|
|
||||||
const { indexer } = useSelector(createIndexerInfoItemSelector(indexerId));
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
@@ -67,53 +52,53 @@ function IndexerInfoModalContent(props: IndexerInfoModalContentProps) {
|
|||||||
protocol,
|
protocol,
|
||||||
privacy,
|
privacy,
|
||||||
capabilities = {} as IndexerCapabilities,
|
capabilities = {} as IndexerCapabilities,
|
||||||
} = indexer as Indexer;
|
} = useIndexer(indexerId) as Indexer;
|
||||||
|
|
||||||
const { onModalClose } = props;
|
const [selectedTab, setSelectedTab] = useState(TABS[0]);
|
||||||
|
|
||||||
const baseUrl =
|
|
||||||
fields.find((field) => field.name === 'baseUrl')?.value ??
|
|
||||||
(Array.isArray(indexerUrls) ? indexerUrls[0] : undefined);
|
|
||||||
|
|
||||||
const vipExpiration =
|
|
||||||
fields.find((field) => field.name === 'vipExpiration')?.value ?? undefined;
|
|
||||||
|
|
||||||
const [selectedTab, setSelectedTab] = useState(tabs[0]);
|
|
||||||
const [isEditIndexerModalOpen, setIsEditIndexerModalOpen] = useState(false);
|
const [isEditIndexerModalOpen, setIsEditIndexerModalOpen] = useState(false);
|
||||||
const [isDeleteIndexerModalOpen, setIsDeleteIndexerModalOpen] =
|
const [isDeleteIndexerModalOpen, setIsDeleteIndexerModalOpen] =
|
||||||
useState(false);
|
useState(false);
|
||||||
|
|
||||||
const onTabSelect = useCallback(
|
const handleTabSelect = useCallback(
|
||||||
(index: number) => {
|
(selectedIndex: number) => {
|
||||||
const selectedTab = tabs[index];
|
const selectedTab = TABS[selectedIndex];
|
||||||
setSelectedTab(selectedTab);
|
setSelectedTab(selectedTab);
|
||||||
},
|
},
|
||||||
[setSelectedTab]
|
[setSelectedTab]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onEditIndexerPress = useCallback(() => {
|
const handleEditIndexerPress = useCallback(() => {
|
||||||
setIsEditIndexerModalOpen(true);
|
setIsEditIndexerModalOpen(true);
|
||||||
}, [setIsEditIndexerModalOpen]);
|
}, [setIsEditIndexerModalOpen]);
|
||||||
|
|
||||||
const onEditIndexerModalClose = useCallback(() => {
|
const handleEditIndexerModalClose = useCallback(() => {
|
||||||
setIsEditIndexerModalOpen(false);
|
setIsEditIndexerModalOpen(false);
|
||||||
}, [setIsEditIndexerModalOpen]);
|
}, [setIsEditIndexerModalOpen]);
|
||||||
|
|
||||||
const onDeleteIndexerPress = useCallback(() => {
|
const handleDeleteIndexerPress = useCallback(() => {
|
||||||
setIsEditIndexerModalOpen(false);
|
setIsEditIndexerModalOpen(false);
|
||||||
setIsDeleteIndexerModalOpen(true);
|
setIsDeleteIndexerModalOpen(true);
|
||||||
}, [setIsDeleteIndexerModalOpen]);
|
}, [setIsDeleteIndexerModalOpen]);
|
||||||
|
|
||||||
const onDeleteIndexerModalClose = useCallback(() => {
|
const handleDeleteIndexerModalClose = useCallback(() => {
|
||||||
setIsDeleteIndexerModalOpen(false);
|
setIsDeleteIndexerModalOpen(false);
|
||||||
onModalClose();
|
onModalClose();
|
||||||
}, [setIsDeleteIndexerModalOpen, onModalClose]);
|
}, [setIsDeleteIndexerModalOpen, onModalClose]);
|
||||||
|
|
||||||
const onCloneIndexerPressWrapper = useCallback(() => {
|
const handleCloneIndexerPressWrapper = useCallback(() => {
|
||||||
onCloneIndexerPress(id);
|
onCloneIndexerPress(id);
|
||||||
onModalClose();
|
onModalClose();
|
||||||
}, [id, onCloneIndexerPress, onModalClose]);
|
}, [id, onCloneIndexerPress, onModalClose]);
|
||||||
|
|
||||||
|
const baseUrl =
|
||||||
|
fields.find((field) => field.name === 'baseUrl')?.value ??
|
||||||
|
(Array.isArray(indexerUrls) ? indexerUrls[0] : undefined);
|
||||||
|
|
||||||
|
const indexerUrl = baseUrl?.replace(/(:\/\/)api\./, '$1');
|
||||||
|
|
||||||
|
const vipExpiration =
|
||||||
|
fields.find((field) => field.name === 'vipExpiration')?.value ?? undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalContent onModalClose={onModalClose}>
|
<ModalContent onModalClose={onModalClose}>
|
||||||
<ModalHeader>{`${name}`}</ModalHeader>
|
<ModalHeader>{`${name}`}</ModalHeader>
|
||||||
@@ -121,8 +106,8 @@ function IndexerInfoModalContent(props: IndexerInfoModalContentProps) {
|
|||||||
<ModalBody>
|
<ModalBody>
|
||||||
<Tabs
|
<Tabs
|
||||||
className={styles.tabs}
|
className={styles.tabs}
|
||||||
selectedIndex={tabs.indexOf(selectedTab)}
|
selectedIndex={TABS.indexOf(selectedTab)}
|
||||||
onSelect={onTabSelect}
|
onSelect={handleTabSelect}
|
||||||
>
|
>
|
||||||
<TabList className={styles.tabList}>
|
<TabList className={styles.tabList}>
|
||||||
<Tab className={styles.tab} selectedClassName={styles.selectedTab}>
|
<Tab className={styles.tab} selectedClassName={styles.selectedTab}>
|
||||||
@@ -178,10 +163,8 @@ function IndexerInfoModalContent(props: IndexerInfoModalContentProps) {
|
|||||||
{translate('IndexerSite')}
|
{translate('IndexerSite')}
|
||||||
</DescriptionListItemTitle>
|
</DescriptionListItemTitle>
|
||||||
<DescriptionListItemDescription>
|
<DescriptionListItemDescription>
|
||||||
{baseUrl ? (
|
{indexerUrl ? (
|
||||||
<Link to={baseUrl}>
|
<Link to={indexerUrl}>{indexerUrl}</Link>
|
||||||
{baseUrl.replace(/(:\/\/)api\./, '$1')}
|
|
||||||
</Link>
|
|
||||||
) : (
|
) : (
|
||||||
'-'
|
'-'
|
||||||
)}
|
)}
|
||||||
@@ -365,16 +348,16 @@ function IndexerInfoModalContent(props: IndexerInfoModalContentProps) {
|
|||||||
<Button
|
<Button
|
||||||
className={styles.deleteButton}
|
className={styles.deleteButton}
|
||||||
kind={kinds.DANGER}
|
kind={kinds.DANGER}
|
||||||
onPress={onDeleteIndexerPress}
|
onPress={handleDeleteIndexerPress}
|
||||||
>
|
>
|
||||||
{translate('Delete')}
|
{translate('Delete')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button onPress={onCloneIndexerPressWrapper}>
|
<Button onPress={handleCloneIndexerPressWrapper}>
|
||||||
{translate('Clone')}
|
{translate('Clone')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Button onPress={onEditIndexerPress}>{translate('Edit')}</Button>
|
<Button onPress={handleEditIndexerPress}>{translate('Edit')}</Button>
|
||||||
<Button onPress={onModalClose}>{translate('Close')}</Button>
|
<Button onPress={onModalClose}>{translate('Close')}</Button>
|
||||||
</div>
|
</div>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
@@ -382,14 +365,14 @@ function IndexerInfoModalContent(props: IndexerInfoModalContentProps) {
|
|||||||
<EditIndexerModalConnector
|
<EditIndexerModalConnector
|
||||||
isOpen={isEditIndexerModalOpen}
|
isOpen={isEditIndexerModalOpen}
|
||||||
id={id}
|
id={id}
|
||||||
onModalClose={onEditIndexerModalClose}
|
onModalClose={handleEditIndexerModalClose}
|
||||||
onDeleteIndexerPress={onDeleteIndexerPress}
|
onDeleteIndexerPress={handleDeleteIndexerPress}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DeleteIndexerModal
|
<DeleteIndexerModal
|
||||||
isOpen={isDeleteIndexerModalOpen}
|
isOpen={isDeleteIndexerModalOpen}
|
||||||
indexerId={id}
|
indexerId={id}
|
||||||
onModalClose={onDeleteIndexerModalClose}
|
onModalClose={handleDeleteIndexerModalClose}
|
||||||
/>
|
/>
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
);
|
);
|
||||||
|
19
frontend/src/Indexer/useIndexer.ts
Normal file
19
frontend/src/Indexer/useIndexer.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
import AppState from 'App/State/AppState';
|
||||||
|
|
||||||
|
export function createIndexerSelector(indexerId?: number) {
|
||||||
|
return createSelector(
|
||||||
|
(state: AppState) => state.indexers.itemMap,
|
||||||
|
(state: AppState) => state.indexers.items,
|
||||||
|
(itemMap, allIndexers) => {
|
||||||
|
return indexerId ? allIndexers[itemMap[indexerId]] : undefined;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function useIndexer(indexerId?: number) {
|
||||||
|
return useSelector(createIndexerSelector(indexerId));
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useIndexer;
|
Reference in New Issue
Block a user