parent
6e008a8e85
commit
10e3a237ef
@ -1,133 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
||||
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import SettingsToolbar from 'Settings/SettingsToolbar';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import ImportListExclusions from './ImportListExclusions/ImportListExclusions';
|
||||
import ImportListsConnector from './ImportLists/ImportListsConnector';
|
||||
import ManageImportListsModal from './ImportLists/Manage/ManageImportListsModal';
|
||||
import ImportListOptions from './Options/ImportListOptions';
|
||||
|
||||
class ImportListSettings extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this._saveCallback = null;
|
||||
|
||||
this.state = {
|
||||
isSaving: false,
|
||||
hasPendingChanges: false,
|
||||
isManageImportListsOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
setChildSave = (saveCallback) => {
|
||||
this._saveCallback = saveCallback;
|
||||
};
|
||||
|
||||
onChildStateChange = (payload) => {
|
||||
this.setState(payload);
|
||||
};
|
||||
|
||||
setListOptionsRef = (ref) => {
|
||||
this._listOptions = ref;
|
||||
};
|
||||
|
||||
onManageImportListsPress = () => {
|
||||
this.setState({ isManageImportListsOpen: true });
|
||||
};
|
||||
|
||||
onManageImportListsModalClose = () => {
|
||||
this.setState({ isManageImportListsOpen: false });
|
||||
};
|
||||
|
||||
onHasPendingChange = (hasPendingChanges) => {
|
||||
this.setState({
|
||||
hasPendingChanges
|
||||
});
|
||||
};
|
||||
|
||||
onSavePress = () => {
|
||||
if (this._saveCallback) {
|
||||
this._saveCallback();
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
isTestingAll,
|
||||
dispatchTestAllImportLists
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
isSaving,
|
||||
hasPendingChanges,
|
||||
isManageImportListsOpen
|
||||
} = this.state;
|
||||
|
||||
return (
|
||||
<PageContent title={translate('ImportListSettings')}>
|
||||
<SettingsToolbar
|
||||
isSaving={isSaving}
|
||||
hasPendingChanges={hasPendingChanges}
|
||||
additionalButtons={
|
||||
<Fragment>
|
||||
<PageToolbarSeparator />
|
||||
|
||||
<PageToolbarButton
|
||||
label={translate('TestAllLists')}
|
||||
iconName={icons.TEST}
|
||||
isSpinning={isTestingAll}
|
||||
onPress={dispatchTestAllImportLists}
|
||||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label={translate('ManageLists')}
|
||||
iconName={icons.MANAGE}
|
||||
onPress={this.onManageImportListsPress}
|
||||
/>
|
||||
</Fragment>
|
||||
}
|
||||
onSavePress={this.onSavePress}
|
||||
/>
|
||||
|
||||
<PageContentBody>
|
||||
<ImportListsConnector />
|
||||
|
||||
<ImportListOptions
|
||||
setChildSave={this.setChildSave}
|
||||
onChildStateChange={this.onChildStateChange}
|
||||
/>
|
||||
|
||||
<ImportListExclusions />
|
||||
|
||||
<ManageImportListsModal
|
||||
isOpen={isManageImportListsOpen}
|
||||
onModalClose={this.onManageImportListsModalClose}
|
||||
/>
|
||||
</PageContentBody>
|
||||
</PageContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ImportListSettings.propTypes = {
|
||||
isTestingAll: PropTypes.bool.isRequired,
|
||||
dispatchTestAllImportLists: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default ImportListSettings;
|
@ -0,0 +1,107 @@
|
||||
import React, { useCallback, useRef, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import AppState from 'App/State/AppState';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
||||
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import SettingsToolbar from 'Settings/SettingsToolbar';
|
||||
import { testAllImportLists } from 'Store/Actions/settingsActions';
|
||||
import {
|
||||
SaveCallback,
|
||||
SettingsStateChange,
|
||||
} from 'typings/Settings/SettingsState';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import ImportListExclusions from './ImportListExclusions/ImportListExclusions';
|
||||
import ImportLists from './ImportLists/ImportLists';
|
||||
import ManageImportListsModal from './ImportLists/Manage/ManageImportListsModal';
|
||||
import ImportListOptions from './Options/ImportListOptions';
|
||||
|
||||
function ImportListSettings() {
|
||||
const dispatch = useDispatch();
|
||||
const isTestingAll = useSelector(
|
||||
(state: AppState) => state.settings.importLists.isTestingAll
|
||||
);
|
||||
|
||||
const saveOptions = useRef<() => void>();
|
||||
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [hasPendingChanges, setHasPendingChanges] = useState(false);
|
||||
const [isManageImportListsModalOpen, setIsManageImportListsModalOpen] =
|
||||
useState(false);
|
||||
|
||||
const handleSetChildSave = useCallback((saveCallback: SaveCallback) => {
|
||||
saveOptions.current = saveCallback;
|
||||
}, []);
|
||||
|
||||
const handleChildStateChange = useCallback(
|
||||
({ isSaving, hasPendingChanges }: SettingsStateChange) => {
|
||||
setIsSaving(isSaving);
|
||||
setHasPendingChanges(hasPendingChanges);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const handleManageImportListsPress = useCallback(() => {
|
||||
setIsManageImportListsModalOpen(true);
|
||||
}, []);
|
||||
|
||||
const handleManageImportListsModalClose = useCallback(() => {
|
||||
setIsManageImportListsModalOpen(false);
|
||||
}, []);
|
||||
|
||||
const handleSavePress = useCallback(() => {
|
||||
saveOptions.current?.();
|
||||
}, []);
|
||||
|
||||
const handleTestAllIndexersPress = useCallback(() => {
|
||||
dispatch(testAllImportLists());
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<PageContent title={translate('ImportListSettings')}>
|
||||
<SettingsToolbar
|
||||
isSaving={isSaving}
|
||||
hasPendingChanges={hasPendingChanges}
|
||||
additionalButtons={
|
||||
<>
|
||||
<PageToolbarSeparator />
|
||||
|
||||
<PageToolbarButton
|
||||
label={translate('TestAllLists')}
|
||||
iconName={icons.TEST}
|
||||
isSpinning={isTestingAll}
|
||||
onPress={handleTestAllIndexersPress}
|
||||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label={translate('ManageLists')}
|
||||
iconName={icons.MANAGE}
|
||||
onPress={handleManageImportListsPress}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
onSavePress={handleSavePress}
|
||||
/>
|
||||
|
||||
<PageContentBody>
|
||||
<ImportLists />
|
||||
|
||||
<ImportListOptions
|
||||
setChildSave={handleSetChildSave}
|
||||
onChildStateChange={handleChildStateChange}
|
||||
/>
|
||||
|
||||
<ImportListExclusions />
|
||||
|
||||
<ManageImportListsModal
|
||||
isOpen={isManageImportListsModalOpen}
|
||||
onModalClose={handleManageImportListsModalClose}
|
||||
/>
|
||||
</PageContentBody>
|
||||
</PageContent>
|
||||
);
|
||||
}
|
||||
|
||||
export default ImportListSettings;
|
@ -1,21 +0,0 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { testAllImportLists } from 'Store/Actions/settingsActions';
|
||||
import ImportListSettings from './ImportListSettings';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.settings.importLists.isTestingAll,
|
||||
(isTestingAll) => {
|
||||
return {
|
||||
isTestingAll
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
dispatchTestAllImportLists: testAllImportLists
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(ImportListSettings);
|
@ -1,117 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Button from 'Components/Link/Button';
|
||||
import Link from 'Components/Link/Link';
|
||||
import Menu from 'Components/Menu/Menu';
|
||||
import MenuContent from 'Components/Menu/MenuContent';
|
||||
import { sizes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AddImportListPresetMenuItem from './AddImportListPresetMenuItem';
|
||||
import styles from './AddImportListItem.css';
|
||||
|
||||
class AddImportListItem extends Component {
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onImportListSelect = () => {
|
||||
const {
|
||||
implementation,
|
||||
implementationName,
|
||||
minRefreshInterval
|
||||
} = this.props;
|
||||
|
||||
this.props.onImportListSelect({ implementation, implementationName, minRefreshInterval });
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
implementation,
|
||||
implementationName,
|
||||
minRefreshInterval,
|
||||
infoLink,
|
||||
presets,
|
||||
onImportListSelect
|
||||
} = this.props;
|
||||
|
||||
const hasPresets = !!(presets && presets.length);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={styles.list}
|
||||
>
|
||||
<Link
|
||||
className={styles.underlay}
|
||||
onPress={this.onImportListSelect}
|
||||
/>
|
||||
|
||||
<div className={styles.overlay}>
|
||||
<div className={styles.name}>
|
||||
{implementationName}
|
||||
</div>
|
||||
|
||||
<div className={styles.actions}>
|
||||
{
|
||||
hasPresets &&
|
||||
<span>
|
||||
<Button
|
||||
size={sizes.SMALL}
|
||||
onPress={this.onImportListSelect}
|
||||
>
|
||||
{translate('Custom')}
|
||||
</Button>
|
||||
|
||||
<Menu className={styles.presetsMenu}>
|
||||
<Button
|
||||
className={styles.presetsMenuButton}
|
||||
size={sizes.SMALL}
|
||||
>
|
||||
{translate('Presets')}
|
||||
</Button>
|
||||
|
||||
<MenuContent>
|
||||
{
|
||||
presets.map((preset) => {
|
||||
return (
|
||||
<AddImportListPresetMenuItem
|
||||
key={preset.name}
|
||||
name={preset.name}
|
||||
implementation={implementation}
|
||||
implementationName={implementationName}
|
||||
minRefreshInterval={minRefreshInterval}
|
||||
onPress={onImportListSelect}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
</MenuContent>
|
||||
</Menu>
|
||||
</span>
|
||||
}
|
||||
|
||||
<Button
|
||||
to={infoLink}
|
||||
size={sizes.SMALL}
|
||||
>
|
||||
{translate('MoreInfo')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AddImportListItem.propTypes = {
|
||||
implementation: PropTypes.string.isRequired,
|
||||
implementationName: PropTypes.string.isRequired,
|
||||
minRefreshInterval: PropTypes.string.isRequired,
|
||||
infoLink: PropTypes.string.isRequired,
|
||||
presets: PropTypes.arrayOf(PropTypes.object),
|
||||
onImportListSelect: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default AddImportListItem;
|
@ -0,0 +1,91 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import Button from 'Components/Link/Button';
|
||||
import Link from 'Components/Link/Link';
|
||||
import Menu from 'Components/Menu/Menu';
|
||||
import MenuContent from 'Components/Menu/MenuContent';
|
||||
import { sizes } from 'Helpers/Props';
|
||||
import { selectImportListSchema } from 'Store/Actions/settingsActions';
|
||||
import ImportList from 'typings/ImportList';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AddImportListPresetMenuItem from './AddImportListPresetMenuItem';
|
||||
import styles from './AddImportListItem.css';
|
||||
|
||||
interface AddImportListItemProps {
|
||||
implementation: string;
|
||||
implementationName: string;
|
||||
minRefreshInterval: string;
|
||||
infoLink: string;
|
||||
presets?: ImportList[];
|
||||
onImportListSelect: () => void;
|
||||
}
|
||||
|
||||
function AddImportListItem({
|
||||
implementation,
|
||||
implementationName,
|
||||
minRefreshInterval,
|
||||
infoLink,
|
||||
presets,
|
||||
onImportListSelect,
|
||||
}: AddImportListItemProps) {
|
||||
const dispatch = useDispatch();
|
||||
const hasPresets = !!(presets && presets.length);
|
||||
|
||||
const handleImportListSelect = useCallback(() => {
|
||||
dispatch(
|
||||
selectImportListSchema({
|
||||
implementation,
|
||||
implementationName,
|
||||
})
|
||||
);
|
||||
|
||||
onImportListSelect();
|
||||
}, [implementation, implementationName, dispatch, onImportListSelect]);
|
||||
|
||||
return (
|
||||
<div className={styles.list}>
|
||||
<Link className={styles.underlay} onPress={handleImportListSelect} />
|
||||
|
||||
<div className={styles.overlay}>
|
||||
<div className={styles.name}>{implementationName}</div>
|
||||
|
||||
<div className={styles.actions}>
|
||||
{hasPresets && (
|
||||
<span>
|
||||
<Button size={sizes.SMALL} onPress={handleImportListSelect}>
|
||||
{translate('Custom')}
|
||||
</Button>
|
||||
|
||||
<Menu className={styles.presetsMenu}>
|
||||
<Button className={styles.presetsMenuButton} size={sizes.SMALL}>
|
||||
{translate('Presets')}
|
||||
</Button>
|
||||
|
||||
<MenuContent>
|
||||
{presets.map((preset) => {
|
||||
return (
|
||||
<AddImportListPresetMenuItem
|
||||
key={preset.name}
|
||||
name={preset.name}
|
||||
implementation={implementation}
|
||||
implementationName={implementationName}
|
||||
minRefreshInterval={minRefreshInterval}
|
||||
onPress={onImportListSelect}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</MenuContent>
|
||||
</Menu>
|
||||
</span>
|
||||
)}
|
||||
|
||||
<Button to={infoLink} size={sizes.SMALL}>
|
||||
{translate('MoreInfo')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AddImportListItem;
|
@ -1,25 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import AddImportListModalContentConnector from './AddImportListModalContentConnector';
|
||||
|
||||
function AddImportListModal({ isOpen, onModalClose, ...otherProps }) {
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<AddImportListModalContentConnector
|
||||
{...otherProps}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
AddImportListModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default AddImportListModal;
|
@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import AddImportListModalContent, {
|
||||
AddImportListModalContentProps,
|
||||
} from './AddImportListModalContent';
|
||||
|
||||
interface AddImportListModalProps extends AddImportListModalContentProps {
|
||||
isOpen: boolean;
|
||||
}
|
||||
|
||||
function AddImportListModal({
|
||||
isOpen,
|
||||
onModalClose,
|
||||
...otherProps
|
||||
}: AddImportListModalProps) {
|
||||
return (
|
||||
<Modal isOpen={isOpen} onModalClose={onModalClose}>
|
||||
<AddImportListModalContent {...otherProps} onModalClose={onModalClose} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default AddImportListModal;
|
@ -1,115 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import FieldSet from 'Components/FieldSet';
|
||||
import Button from 'Components/Link/Button';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
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 titleCase from 'Utilities/String/titleCase';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AddImportListItem from './AddImportListItem';
|
||||
import styles from './AddImportListModalContent.css';
|
||||
|
||||
class AddImportListModalContent extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
isSchemaFetching,
|
||||
isSchemaPopulated,
|
||||
schemaError,
|
||||
listGroups,
|
||||
onImportListSelect,
|
||||
onModalClose
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
{translate('AddImportList')}
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
{
|
||||
isSchemaFetching ?
|
||||
<LoadingIndicator /> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
!isSchemaFetching && !!schemaError ?
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('AddListError')}
|
||||
</Alert> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
isSchemaPopulated && !schemaError ?
|
||||
<div>
|
||||
|
||||
<Alert kind={kinds.INFO}>
|
||||
<div>
|
||||
{translate('SupportedListsSeries')}
|
||||
</div>
|
||||
<div>
|
||||
{translate('SupportedListsMoreInfo')}
|
||||
</div>
|
||||
</Alert>
|
||||
{
|
||||
Object.keys(listGroups).map((key) => {
|
||||
return (
|
||||
<FieldSet key={key} legend={translate('TypeOfList', {
|
||||
typeOfList: titleCase(key)
|
||||
})}
|
||||
>
|
||||
<div className={styles.lists}>
|
||||
{
|
||||
listGroups[key].map((list) => {
|
||||
return (
|
||||
<AddImportListItem
|
||||
key={list.implementation}
|
||||
implementation={list.implementation}
|
||||
{...list}
|
||||
onImportListSelect={onImportListSelect}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</FieldSet>
|
||||
);
|
||||
})
|
||||
}
|
||||
</div> :
|
||||
null
|
||||
}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
onPress={onModalClose}
|
||||
>
|
||||
{translate('Close')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AddImportListModalContent.propTypes = {
|
||||
isSchemaFetching: PropTypes.bool.isRequired,
|
||||
isSchemaPopulated: PropTypes.bool.isRequired,
|
||||
schemaError: PropTypes.object,
|
||||
listGroups: PropTypes.object.isRequired,
|
||||
onImportListSelect: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default AddImportListModalContent;
|
@ -0,0 +1,108 @@
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import AppState from 'App/State/AppState';
|
||||
import Alert from 'Components/Alert';
|
||||
import FieldSet from 'Components/FieldSet';
|
||||
import Button from 'Components/Link/Button';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
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 { fetchImportListSchema } from 'Store/Actions/settingsActions';
|
||||
import ImportList from 'typings/ImportList';
|
||||
import titleCase from 'Utilities/String/titleCase';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AddImportListItem from './AddImportListItem';
|
||||
import styles from './AddImportListModalContent.css';
|
||||
|
||||
export interface AddImportListModalContentProps {
|
||||
onImportListSelect: () => void;
|
||||
onModalClose: () => void;
|
||||
}
|
||||
|
||||
function AddImportListModalContent({
|
||||
onImportListSelect,
|
||||
onModalClose,
|
||||
}: AddImportListModalContentProps) {
|
||||
const dispatch = useDispatch();
|
||||
const { isSchemaFetching, isSchemaPopulated, schemaError, schema } =
|
||||
useSelector((state: AppState) => state.settings.importLists);
|
||||
|
||||
const listGroups = useMemo(() => {
|
||||
const result = schema.reduce<Record<string, ImportList[]>>((acc, item) => {
|
||||
if (!acc[item.listType]) {
|
||||
acc[item.listType] = [];
|
||||
}
|
||||
|
||||
acc[item.listType].push(item);
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
// Sort the lists by listOrder after grouping them
|
||||
Object.keys(result).forEach((key) => {
|
||||
result[key].sort((a, b) => {
|
||||
return a.listOrder - b.listOrder;
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
}, [schema]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchImportListSchema());
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>{translate('AddImportList')}</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
{isSchemaFetching ? <LoadingIndicator /> : null}
|
||||
|
||||
{!isSchemaFetching && !!schemaError ? (
|
||||
<Alert kind={kinds.DANGER}>{translate('AddListError')}</Alert>
|
||||
) : null}
|
||||
|
||||
{isSchemaPopulated && !schemaError ? (
|
||||
<div>
|
||||
<Alert kind={kinds.INFO}>
|
||||
<div>{translate('SupportedListsSeries')}</div>
|
||||
<div>{translate('SupportedListsMoreInfo')}</div>
|
||||
</Alert>
|
||||
{Object.keys(listGroups).map((key) => {
|
||||
return (
|
||||
<FieldSet
|
||||
key={key}
|
||||
legend={translate('TypeOfList', {
|
||||
typeOfList: titleCase(key),
|
||||
})}
|
||||
>
|
||||
<div className={styles.lists}>
|
||||
{listGroups[key].map((list) => {
|
||||
return (
|
||||
<AddImportListItem
|
||||
key={list.implementation}
|
||||
{...list}
|
||||
implementation={list.implementation}
|
||||
onImportListSelect={onImportListSelect}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</FieldSet>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button onPress={onModalClose}>{translate('Close')}</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
|
||||
export default AddImportListModalContent;
|
@ -1,76 +0,0 @@
|
||||
import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { fetchImportListSchema, selectImportListSchema } from 'Store/Actions/settingsActions';
|
||||
import AddImportListModalContent from './AddImportListModalContent';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.settings.importLists,
|
||||
(importLists) => {
|
||||
const {
|
||||
isSchemaFetching,
|
||||
isSchemaPopulated,
|
||||
schemaError,
|
||||
schema
|
||||
} = importLists;
|
||||
|
||||
const listGroups = _.chain(schema)
|
||||
.sortBy((o) => o.listOrder)
|
||||
.groupBy('listType')
|
||||
.value();
|
||||
|
||||
return {
|
||||
isSchemaFetching,
|
||||
isSchemaPopulated,
|
||||
schemaError,
|
||||
listGroups
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
fetchImportListSchema,
|
||||
selectImportListSchema
|
||||
};
|
||||
|
||||
class AddImportListModalContentConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
this.props.fetchImportListSchema();
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onImportListSelect = ({ implementation, implementationName, name, minRefreshInterval }) => {
|
||||
this.props.selectImportListSchema({ implementation, implementationName, presetName: name, minRefreshInterval });
|
||||
this.props.onModalClose({ listSelected: true });
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<AddImportListModalContent
|
||||
{...this.props}
|
||||
onImportListSelect={this.onImportListSelect}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AddImportListModalContentConnector.propTypes = {
|
||||
fetchImportListSchema: PropTypes.func.isRequired,
|
||||
selectImportListSchema: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(AddImportListModalContentConnector);
|
@ -1,57 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import MenuItem from 'Components/Menu/MenuItem';
|
||||
|
||||
class AddImportListPresetMenuItem extends Component {
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onPress = () => {
|
||||
const {
|
||||
name,
|
||||
implementation,
|
||||
implementationName,
|
||||
minRefreshInterval
|
||||
} = this.props;
|
||||
|
||||
this.props.onPress({
|
||||
name,
|
||||
implementation,
|
||||
implementationName,
|
||||
minRefreshInterval
|
||||
});
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
name,
|
||||
implementation,
|
||||
implementationName,
|
||||
minRefreshInterval,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
{...otherProps}
|
||||
onPress={this.onPress}
|
||||
>
|
||||
{name}
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AddImportListPresetMenuItem.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
implementation: PropTypes.string.isRequired,
|
||||
implementationName: PropTypes.string.isRequired,
|
||||
minRefreshInterval: PropTypes.string.isRequired,
|
||||
onPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default AddImportListPresetMenuItem;
|
@ -0,0 +1,44 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import MenuItem, { MenuItemProps } from 'Components/Menu/MenuItem';
|
||||
import { selectImportListSchema } from 'Store/Actions/settingsActions';
|
||||
|
||||
interface AddImportListPresetMenuItemProps
|
||||
extends Omit<MenuItemProps, 'children'> {
|
||||
name: string;
|
||||
implementation: string;
|
||||
implementationName: string;
|
||||
minRefreshInterval: string;
|
||||
onPress: () => void;
|
||||
}
|
||||
|
||||
function AddImportListPresetMenuItem({
|
||||
name,
|
||||
implementation,
|
||||
implementationName,
|
||||
minRefreshInterval,
|
||||
onPress,
|
||||
...otherProps
|
||||
}: AddImportListPresetMenuItemProps) {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handlePress = useCallback(() => {
|
||||
dispatch(
|
||||
selectImportListSchema({
|
||||
implementation,
|
||||
implementationName,
|
||||
presetName: name,
|
||||
})
|
||||
);
|
||||
|
||||
onPress();
|
||||
}, [name, implementation, implementationName, dispatch, onPress]);
|
||||
|
||||
return (
|
||||
<MenuItem {...otherProps} onPress={handlePress}>
|
||||
{name}
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
||||
|
||||
export default AddImportListPresetMenuItem;
|
@ -1,25 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import EditImportListModalContentConnector from './EditImportListModalContentConnector';
|
||||
|
||||
function EditImportListModal({ isOpen, onModalClose, ...otherProps }) {
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<EditImportListModalContentConnector
|
||||
{...otherProps}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
EditImportListModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default EditImportListModal;
|
@ -0,0 +1,44 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import { clearPendingChanges } from 'Store/Actions/baseActions';
|
||||
import {
|
||||
cancelSaveImportList,
|
||||
cancelTestImportList,
|
||||
} from 'Store/Actions/settingsActions';
|
||||
import EditImportListModalContent, {
|
||||
EditImportListModalContentProps,
|
||||
} from './EditImportListModalContent';
|
||||
|
||||
const section = 'settings.importLists';
|
||||
|
||||
interface EditImportListModalProps extends EditImportListModalContentProps {
|
||||
isOpen: boolean;
|
||||
}
|
||||
|
||||
function EditImportListModal({
|
||||
isOpen,
|
||||
onModalClose,
|
||||
...otherProps
|
||||
}: EditImportListModalProps) {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleModalClose = useCallback(() => {
|
||||
dispatch(clearPendingChanges({ section }));
|
||||
dispatch(cancelTestImportList({ section }));
|
||||
dispatch(cancelSaveImportList({ section }));
|
||||
|
||||
onModalClose();
|
||||
}, [dispatch, onModalClose]);
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onModalClose={handleModalClose}>
|
||||
<EditImportListModalContent
|
||||
{...otherProps}
|
||||
onModalClose={handleModalClose}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default EditImportListModal;
|
@ -1,65 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { clearPendingChanges } from 'Store/Actions/baseActions';
|
||||
import { cancelSaveImportList, cancelTestImportList } from 'Store/Actions/settingsActions';
|
||||
import EditImportListModal from './EditImportListModal';
|
||||
|
||||
function createMapDispatchToProps(dispatch, props) {
|
||||
const section = 'settings.importLists';
|
||||
|
||||
return {
|
||||
dispatchClearPendingChanges() {
|
||||
dispatch(clearPendingChanges({ section }));
|
||||
},
|
||||
|
||||
dispatchCancelTestImportList() {
|
||||
dispatch(cancelTestImportList({ section }));
|
||||
},
|
||||
|
||||
dispatchCancelSaveImportList() {
|
||||
dispatch(cancelSaveImportList({ section }));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class EditImportListModalConnector extends Component {
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onModalClose = () => {
|
||||
this.props.dispatchClearPendingChanges();
|
||||
this.props.dispatchCancelTestImportList();
|
||||
this.props.dispatchCancelSaveImportList();
|
||||
this.props.onModalClose();
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
dispatchClearPendingChanges,
|
||||
dispatchCancelTestImportList,
|
||||
dispatchCancelSaveImportList,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<EditImportListModal
|
||||
{...otherProps}
|
||||
onModalClose={this.onModalClose}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
EditImportListModalConnector.propTypes = {
|
||||
onModalClose: PropTypes.func.isRequired,
|
||||
dispatchClearPendingChanges: PropTypes.func.isRequired,
|
||||
dispatchCancelTestImportList: PropTypes.func.isRequired,
|
||||
dispatchCancelSaveImportList: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(null, createMapDispatchToProps)(EditImportListModalConnector);
|
@ -1,339 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import SeriesMonitoringOptionsPopoverContent from 'AddSeries/SeriesMonitoringOptionsPopoverContent';
|
||||
import SeriesMonitorNewItemsOptionsPopoverContent from 'AddSeries/SeriesMonitorNewItemsOptionsPopoverContent';
|
||||
import SeriesTypePopoverContent from 'AddSeries/SeriesTypePopoverContent';
|
||||
import Alert from 'Components/Alert';
|
||||
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 ProviderFieldFormGroup from 'Components/Form/ProviderFieldFormGroup';
|
||||
import Icon from 'Components/Icon';
|
||||
import Button from 'Components/Link/Button';
|
||||
import SpinnerErrorButton from 'Components/Link/SpinnerErrorButton';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
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 Popover from 'Components/Tooltip/Popover';
|
||||
import { icons, inputTypes, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import AdvancedSettingsButton from 'Settings/AdvancedSettingsButton';
|
||||
import formatShortTimeSpan from 'Utilities/Date/formatShortTimeSpan';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './EditImportListModalContent.css';
|
||||
|
||||
function EditImportListModalContent(props) {
|
||||
|
||||
const {
|
||||
advancedSettings,
|
||||
isFetching,
|
||||
error,
|
||||
isSaving,
|
||||
isTesting,
|
||||
saveError,
|
||||
item,
|
||||
onInputChange,
|
||||
onFieldChange,
|
||||
onModalClose,
|
||||
onSavePress,
|
||||
onTestPress,
|
||||
onDeleteImportListPress,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
const {
|
||||
id,
|
||||
implementationName,
|
||||
name,
|
||||
enableAutomaticAdd,
|
||||
searchForMissingEpisodes,
|
||||
minRefreshInterval,
|
||||
shouldMonitor,
|
||||
rootFolderPath,
|
||||
monitorNewItems,
|
||||
qualityProfileId,
|
||||
seriesType,
|
||||
seasonFolder,
|
||||
tags,
|
||||
fields
|
||||
} = item;
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
{id ? translate('EditImportListImplementation', { implementationName }) : translate('AddImportListImplementation', { implementationName })}
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
{
|
||||
isFetching ?
|
||||
<LoadingIndicator /> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && !!error ?
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('AddListError')}
|
||||
</Alert> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && !error ?
|
||||
<Form {...otherProps}>
|
||||
|
||||
<Alert
|
||||
kind={kinds.INFO}
|
||||
className={styles.message}
|
||||
>
|
||||
{translate('ListWillRefreshEveryInterval', {
|
||||
refreshInterval: formatShortTimeSpan(minRefreshInterval.value)
|
||||
})}
|
||||
</Alert>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('Name')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="name"
|
||||
{...name}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('EnableAutomaticAdd')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="enableAutomaticAdd"
|
||||
helpText={translate('EnableAutomaticAddSeriesHelpText')}
|
||||
{...enableAutomaticAdd}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('ImportListSearchForMissingEpisodes')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="searchForMissingEpisodes"
|
||||
helpText={translate('ImportListSearchForMissingEpisodesHelpText')}
|
||||
{...searchForMissingEpisodes}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>
|
||||
{translate('Monitor')}
|
||||
|
||||
<Popover
|
||||
anchor={
|
||||
<Icon
|
||||
className={styles.labelIcon}
|
||||
name={icons.INFO}
|
||||
/>
|
||||
}
|
||||
title={translate('MonitoringOptions')}
|
||||
body={<SeriesMonitoringOptionsPopoverContent />}
|
||||
position={tooltipPositions.RIGHT}
|
||||
/>
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.MONITOR_EPISODES_SELECT}
|
||||
name="shouldMonitor"
|
||||
onChange={onInputChange}
|
||||
{...shouldMonitor}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>
|
||||
{translate('MonitorNewSeasons')}
|
||||
<Popover
|
||||
anchor={
|
||||
<Icon
|
||||
className={styles.labelIcon}
|
||||
name={icons.INFO}
|
||||
/>
|
||||
}
|
||||
title={translate('MonitorNewSeasons')}
|
||||
body={<SeriesMonitorNewItemsOptionsPopoverContent />}
|
||||
position={tooltipPositions.RIGHT}
|
||||
/>
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.MONITOR_NEW_ITEMS_SELECT}
|
||||
name="monitorNewItems"
|
||||
helpText={translate('MonitorNewSeasonsHelpText')}
|
||||
{...monitorNewItems}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('RootFolder')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.ROOT_FOLDER_SELECT}
|
||||
name="rootFolderPath"
|
||||
helpText={translate('ListRootFolderHelpText')}
|
||||
{...rootFolderPath}
|
||||
includeMissingValue={true}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('QualityProfile')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.QUALITY_PROFILE_SELECT}
|
||||
name="qualityProfileId"
|
||||
helpText={translate('ListQualityProfileHelpText')}
|
||||
{...qualityProfileId}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>
|
||||
{translate('SeriesType')}
|
||||
|
||||
<Popover
|
||||
anchor={
|
||||
<Icon
|
||||
className={styles.labelIcon}
|
||||
name={icons.INFO}
|
||||
/>
|
||||
}
|
||||
title={translate('SeriesTypes')}
|
||||
body={<SeriesTypePopoverContent />}
|
||||
position={tooltipPositions.RIGHT}
|
||||
/>
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SERIES_TYPE_SELECT}
|
||||
name="seriesType"
|
||||
onChange={onInputChange}
|
||||
{...seriesType}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('SeasonFolder')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="seasonFolder"
|
||||
onChange={onInputChange}
|
||||
{...seasonFolder}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('SonarrTags')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TAG}
|
||||
name="tags"
|
||||
helpText={translate('ListTagsHelpText')}
|
||||
{...tags}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
{
|
||||
!!fields && !!fields.length &&
|
||||
<div>
|
||||
{
|
||||
fields.map((field) => {
|
||||
return (
|
||||
<ProviderFieldFormGroup
|
||||
key={field.name}
|
||||
advancedSettings={advancedSettings}
|
||||
provider="importList"
|
||||
providerData={item}
|
||||
section="settings.importLists"
|
||||
{...field}
|
||||
onChange={onFieldChange}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
</Form> :
|
||||
null
|
||||
}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
{
|
||||
id &&
|
||||
<Button
|
||||
className={styles.deleteButton}
|
||||
kind={kinds.DANGER}
|
||||
onPress={onDeleteImportListPress}
|
||||
>
|
||||
{translate('Delete')}
|
||||
</Button>
|
||||
}
|
||||
|
||||
<AdvancedSettingsButton
|
||||
advancedSettings={advancedSettings}
|
||||
showLabel={false}
|
||||
/>
|
||||
|
||||
<SpinnerErrorButton
|
||||
isSpinning={isTesting}
|
||||
error={saveError}
|
||||
onPress={onTestPress}
|
||||
>
|
||||
{translate('Test')}
|
||||
</SpinnerErrorButton>
|
||||
|
||||
<Button
|
||||
onPress={onModalClose}
|
||||
>
|
||||
{translate('Cancel')}
|
||||
</Button>
|
||||
|
||||
<SpinnerErrorButton
|
||||
isSpinning={isSaving}
|
||||
error={saveError}
|
||||
onPress={onSavePress}
|
||||
>
|
||||
{translate('Save')}
|
||||
</SpinnerErrorButton>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
|
||||
EditImportListModalContent.propTypes = {
|
||||
advancedSettings: PropTypes.bool.isRequired,
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
isSaving: PropTypes.bool.isRequired,
|
||||
isTesting: PropTypes.bool.isRequired,
|
||||
saveError: PropTypes.object,
|
||||
item: PropTypes.object.isRequired,
|
||||
onInputChange: PropTypes.func.isRequired,
|
||||
onFieldChange: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired,
|
||||
onSavePress: PropTypes.func.isRequired,
|
||||
onTestPress: PropTypes.func.isRequired,
|
||||
onDeleteImportListPress: PropTypes.func
|
||||
};
|
||||
|
||||
export default EditImportListModalContent;
|
@ -0,0 +1,350 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import SeriesMonitoringOptionsPopoverContent from 'AddSeries/SeriesMonitoringOptionsPopoverContent';
|
||||
import SeriesMonitorNewItemsOptionsPopoverContent from 'AddSeries/SeriesMonitorNewItemsOptionsPopoverContent';
|
||||
import SeriesTypePopoverContent from 'AddSeries/SeriesTypePopoverContent';
|
||||
import { ImportListAppState } from 'App/State/SettingsAppState';
|
||||
import Alert from 'Components/Alert';
|
||||
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 ProviderFieldFormGroup from 'Components/Form/ProviderFieldFormGroup';
|
||||
import Icon from 'Components/Icon';
|
||||
import Button from 'Components/Link/Button';
|
||||
import SpinnerErrorButton from 'Components/Link/SpinnerErrorButton';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
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 Popover from 'Components/Tooltip/Popover';
|
||||
import usePrevious from 'Helpers/Hooks/usePrevious';
|
||||
import useShowAdvancedSettings from 'Helpers/Hooks/useShowAdvancedSettings';
|
||||
import { icons, inputTypes, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import AdvancedSettingsButton from 'Settings/AdvancedSettingsButton';
|
||||
import {
|
||||
saveImportList,
|
||||
setImportListFieldValue,
|
||||
setImportListValue,
|
||||
testImportList,
|
||||
} from 'Store/Actions/settingsActions';
|
||||
import { createProviderSettingsSelectorHook } from 'Store/Selectors/createProviderSettingsSelector';
|
||||
import ImportList from 'typings/ImportList';
|
||||
import { InputChanged } from 'typings/inputs';
|
||||
import formatShortTimeSpan from 'Utilities/Date/formatShortTimeSpan';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './EditImportListModalContent.css';
|
||||
|
||||
export interface EditImportListModalContentProps {
|
||||
id?: number;
|
||||
onModalClose: () => void;
|
||||
onDeleteImportListPress?: () => void;
|
||||
}
|
||||
|
||||
function EditImportListModalContent({
|
||||
id,
|
||||
onModalClose,
|
||||
onDeleteImportListPress,
|
||||
}: EditImportListModalContentProps) {
|
||||
const dispatch = useDispatch();
|
||||
const showAdvancedSettings = useShowAdvancedSettings();
|
||||
|
||||
const {
|
||||
isFetching,
|
||||
isSaving,
|
||||
isTesting = false,
|
||||
error,
|
||||
saveError,
|
||||
item,
|
||||
validationErrors,
|
||||
validationWarnings,
|
||||
} = useSelector(
|
||||
createProviderSettingsSelectorHook<ImportList, ImportListAppState>(
|
||||
'importLists',
|
||||
id
|
||||
)
|
||||
);
|
||||
|
||||
const wasSaving = usePrevious(isSaving);
|
||||
|
||||
const {
|
||||
implementationName,
|
||||
name,
|
||||
enableAutomaticAdd,
|
||||
searchForMissingEpisodes,
|
||||
minRefreshInterval,
|
||||
shouldMonitor,
|
||||
rootFolderPath,
|
||||
monitorNewItems,
|
||||
qualityProfileId,
|
||||
seriesType,
|
||||
seasonFolder,
|
||||
tags,
|
||||
fields,
|
||||
} = item;
|
||||
|
||||
const handleInputChange = useCallback(
|
||||
(change: InputChanged) => {
|
||||
// @ts-expect-error - actions are not typed
|
||||
dispatch(setImportListValue(change));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const handleFieldChange = useCallback(
|
||||
(change: InputChanged) => {
|
||||
// @ts-expect-error - actions are not typed
|
||||
dispatch(setImportListFieldValue(change));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const handleTestPress = useCallback(() => {
|
||||
dispatch(testImportList({ id }));
|
||||
}, [id, dispatch]);
|
||||
|
||||
const handleSavePress = useCallback(() => {
|
||||
dispatch(saveImportList({ id }));
|
||||
}, [id, dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (wasSaving && !isSaving && !saveError) {
|
||||
onModalClose();
|
||||
}
|
||||
}, [isSaving, wasSaving, saveError, onModalClose]);
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
{id
|
||||
? translate('EditImportListImplementation', { implementationName })
|
||||
: translate('AddImportListImplementation', { implementationName })}
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
{isFetching ? <LoadingIndicator /> : null}
|
||||
|
||||
{!isFetching && !!error ? (
|
||||
<Alert kind={kinds.DANGER}>{translate('AddListError')}</Alert>
|
||||
) : null}
|
||||
|
||||
{!isFetching && !error ? (
|
||||
<Form
|
||||
validationErrors={validationErrors}
|
||||
validationWarnings={validationWarnings}
|
||||
>
|
||||
<Alert kind={kinds.INFO} className={styles.message}>
|
||||
{translate('ListWillRefreshEveryInterval', {
|
||||
refreshInterval: formatShortTimeSpan(minRefreshInterval.value),
|
||||
})}
|
||||
</Alert>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('Name')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="name"
|
||||
{...name}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('EnableAutomaticAdd')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="enableAutomaticAdd"
|
||||
helpText={translate('EnableAutomaticAddSeriesHelpText')}
|
||||
{...enableAutomaticAdd}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>
|
||||
{translate('ImportListSearchForMissingEpisodes')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="searchForMissingEpisodes"
|
||||
helpText={translate(
|
||||
'ImportListSearchForMissingEpisodesHelpText'
|
||||
)}
|
||||
{...searchForMissingEpisodes}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>
|
||||
{translate('Monitor')}
|
||||
|
||||
<Popover
|
||||
anchor={
|
||||
<Icon className={styles.labelIcon} name={icons.INFO} />
|
||||
}
|
||||
title={translate('MonitoringOptions')}
|
||||
body={<SeriesMonitoringOptionsPopoverContent />}
|
||||
position={tooltipPositions.RIGHT}
|
||||
/>
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.MONITOR_EPISODES_SELECT}
|
||||
name="shouldMonitor"
|
||||
onChange={handleInputChange}
|
||||
{...shouldMonitor}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>
|
||||
{translate('MonitorNewSeasons')}
|
||||
<Popover
|
||||
anchor={
|
||||
<Icon className={styles.labelIcon} name={icons.INFO} />
|
||||
}
|
||||
title={translate('MonitorNewSeasons')}
|
||||
body={<SeriesMonitorNewItemsOptionsPopoverContent />}
|
||||
position={tooltipPositions.RIGHT}
|
||||
/>
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.MONITOR_NEW_ITEMS_SELECT}
|
||||
name="monitorNewItems"
|
||||
helpText={translate('MonitorNewSeasonsHelpText')}
|
||||
{...monitorNewItems}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('RootFolder')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.ROOT_FOLDER_SELECT}
|
||||
name="rootFolderPath"
|
||||
helpText={translate('ListRootFolderHelpText')}
|
||||
{...rootFolderPath}
|
||||
includeMissingValue={true}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('QualityProfile')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.QUALITY_PROFILE_SELECT}
|
||||
name="qualityProfileId"
|
||||
helpText={translate('ListQualityProfileHelpText')}
|
||||
{...qualityProfileId}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>
|
||||
{translate('SeriesType')}
|
||||
|
||||
<Popover
|
||||
anchor={
|
||||
<Icon className={styles.labelIcon} name={icons.INFO} />
|
||||
}
|
||||
title={translate('SeriesTypes')}
|
||||
body={<SeriesTypePopoverContent />}
|
||||
position={tooltipPositions.RIGHT}
|
||||
/>
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SERIES_TYPE_SELECT}
|
||||
name="seriesType"
|
||||
onChange={handleInputChange}
|
||||
{...seriesType}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('SeasonFolder')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="seasonFolder"
|
||||
onChange={handleInputChange}
|
||||
{...seasonFolder}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('SonarrTags')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TAG}
|
||||
name="tags"
|
||||
helpText={translate('ListTagsHelpText')}
|
||||
{...tags}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
{fields?.length ? (
|
||||
<div>
|
||||
{fields.map((field) => {
|
||||
return (
|
||||
<ProviderFieldFormGroup
|
||||
key={field.name}
|
||||
{...field}
|
||||
advancedSettings={showAdvancedSettings}
|
||||
provider="importList"
|
||||
providerData={item}
|
||||
onChange={handleFieldChange}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
</Form>
|
||||
) : null}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
{id && (
|
||||
<Button
|
||||
className={styles.deleteButton}
|
||||
kind={kinds.DANGER}
|
||||
onPress={onDeleteImportListPress}
|
||||
>
|
||||
{translate('Delete')}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<AdvancedSettingsButton showLabel={false} />
|
||||
|
||||
<SpinnerErrorButton
|
||||
isSpinning={isTesting}
|
||||
error={saveError}
|
||||
onPress={handleTestPress}
|
||||
>
|
||||
{translate('Test')}
|
||||
</SpinnerErrorButton>
|
||||
|
||||
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
|
||||
|
||||
<SpinnerErrorButton
|
||||
isSpinning={isSaving}
|
||||
error={saveError}
|
||||
onPress={handleSavePress}
|
||||
>
|
||||
{translate('Save')}
|
||||
</SpinnerErrorButton>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
|
||||
export default EditImportListModalContent;
|
@ -1,93 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import {
|
||||
saveImportList,
|
||||
setImportListFieldValue,
|
||||
setImportListValue,
|
||||
testImportList
|
||||
} from 'Store/Actions/settingsActions';
|
||||
import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
|
||||
import EditImportListModalContent from './EditImportListModalContent';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.settings.advancedSettings,
|
||||
createProviderSettingsSelector('importLists'),
|
||||
(advancedSettings, importList) => {
|
||||
return {
|
||||
advancedSettings,
|
||||
...importList
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
setImportListValue,
|
||||
setImportListFieldValue,
|
||||
saveImportList,
|
||||
testImportList
|
||||
};
|
||||
|
||||
class EditImportListModalContentConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (prevProps.isSaving && !this.props.isSaving && !this.props.saveError) {
|
||||
this.props.onModalClose();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onInputChange = ({ name, value }) => {
|
||||
this.props.setImportListValue({ name, value });
|
||||
};
|
||||
|
||||
onFieldChange = ({ name, value }) => {
|
||||
this.props.setImportListFieldValue({ name, value });
|
||||
};
|
||||
|
||||
onSavePress = () => {
|
||||
this.props.saveImportList({ id: this.props.id });
|
||||
};
|
||||
|
||||
onTestPress = () => {
|
||||
this.props.testImportList({ id: this.props.id });
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<EditImportListModalContent
|
||||
{...this.props}
|
||||
onSavePress={this.onSavePress}
|
||||
onTestPress={this.onTestPress}
|
||||
onInputChange={this.onInputChange}
|
||||
onFieldChange={this.onFieldChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
EditImportListModalContentConnector.propTypes = {
|
||||
id: PropTypes.number,
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
isSaving: PropTypes.bool.isRequired,
|
||||
saveError: PropTypes.object,
|
||||
item: PropTypes.object.isRequired,
|
||||
setImportListValue: PropTypes.func.isRequired,
|
||||
setImportListFieldValue: PropTypes.func.isRequired,
|
||||
saveImportList: PropTypes.func.isRequired,
|
||||
testImportList: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(EditImportListModalContentConnector);
|
@ -1,128 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Card from 'Components/Card';
|
||||
import Label from 'Components/Label';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import TagList from 'Components/TagList';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import formatShortTimeSpan from 'Utilities/Date/formatShortTimeSpan';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import EditImportListModalConnector from './EditImportListModalConnector';
|
||||
import styles from './ImportList.css';
|
||||
|
||||
class ImportList extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
isEditImportListModalOpen: false,
|
||||
isDeleteImportListModalOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onEditImportListPress = () => {
|
||||
this.setState({ isEditImportListModalOpen: true });
|
||||
};
|
||||
|
||||
onEditImportListModalClose = () => {
|
||||
this.setState({ isEditImportListModalOpen: false });
|
||||
};
|
||||
|
||||
onDeleteImportListPress = () => {
|
||||
this.setState({
|
||||
isEditImportListModalOpen: false,
|
||||
isDeleteImportListModalOpen: true
|
||||
});
|
||||
};
|
||||
|
||||
onDeleteImportListModalClose = () => {
|
||||
this.setState({ isDeleteImportListModalOpen: false });
|
||||
};
|
||||
|
||||
onConfirmDeleteImportList = () => {
|
||||
this.props.onConfirmDeleteImportList(this.props.id);
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
enableAutomaticAdd,
|
||||
tags,
|
||||
tagList,
|
||||
minRefreshInterval
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Card
|
||||
className={styles.list}
|
||||
overlayContent={true}
|
||||
onPress={this.onEditImportListPress}
|
||||
>
|
||||
<div className={styles.name}>
|
||||
{name}
|
||||
</div>
|
||||
|
||||
<div className={styles.enabled}>
|
||||
{
|
||||
enableAutomaticAdd ?
|
||||
<Label kind={kinds.SUCCESS}>
|
||||
{translate('AutomaticAdd')}
|
||||
</Label> :
|
||||
null
|
||||
}
|
||||
</div>
|
||||
|
||||
<TagList
|
||||
tags={tags}
|
||||
tagList={tagList}
|
||||
/>
|
||||
|
||||
<div className={styles.enabled}>
|
||||
<Label kind={kinds.DEFAULT} title='List Refresh Interval'>
|
||||
{`${translate('Refresh')}: ${formatShortTimeSpan(minRefreshInterval)}`}
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<EditImportListModalConnector
|
||||
id={id}
|
||||
isOpen={this.state.isEditImportListModalOpen}
|
||||
onModalClose={this.onEditImportListModalClose}
|
||||
onDeleteImportListPress={this.onDeleteImportListPress}
|
||||
/>
|
||||
|
||||
<ConfirmModal
|
||||
isOpen={this.state.isDeleteImportListModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title={translate('DeleteImportList')}
|
||||
message={translate('DeleteImportListMessageText', { name })}
|
||||
confirmLabel={translate('Delete')}
|
||||
onConfirm={this.onConfirmDeleteImportList}
|
||||
onCancel={this.onDeleteImportListModalClose}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ImportList.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
enableAutomaticAdd: PropTypes.bool.isRequired,
|
||||
tags: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
tagList: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
minRefreshInterval: PropTypes.string.isRequired,
|
||||
onConfirmDeleteImportList: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default ImportList;
|
@ -0,0 +1,104 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import Card from 'Components/Card';
|
||||
import Label from 'Components/Label';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import TagList from 'Components/TagList';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import { deleteImportList } from 'Store/Actions/settingsActions';
|
||||
import useTags from 'Tags/useTags';
|
||||
import formatShortTimeSpan from 'Utilities/Date/formatShortTimeSpan';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import EditImportListModal from './EditImportListModal';
|
||||
import styles from './ImportList.css';
|
||||
|
||||
interface ImportListProps {
|
||||
id: number;
|
||||
name: string;
|
||||
enableAutomaticAdd: boolean;
|
||||
tags: number[];
|
||||
minRefreshInterval: string;
|
||||
}
|
||||
|
||||
function ImportList({
|
||||
id,
|
||||
name,
|
||||
enableAutomaticAdd,
|
||||
tags,
|
||||
minRefreshInterval,
|
||||
}: ImportListProps) {
|
||||
const dispatch = useDispatch();
|
||||
const tagList = useTags();
|
||||
|
||||
const [isEditImportListModalOpen, setIsEditImportListModalOpen] =
|
||||
useState(false);
|
||||
|
||||
const [isDeleteImportListModalOpen, setIsDeleteImportListModalOpen] =
|
||||
useState(false);
|
||||
|
||||
const handleEditImportListPress = useCallback(() => {
|
||||
setIsEditImportListModalOpen(true);
|
||||
}, []);
|
||||
|
||||
const handleEditImportListModalClose = useCallback(() => {
|
||||
setIsEditImportListModalOpen(false);
|
||||
}, []);
|
||||
|
||||
const handleDeleteImportListPress = useCallback(() => {
|
||||
setIsEditImportListModalOpen(false);
|
||||
setIsDeleteImportListModalOpen(true);
|
||||
}, []);
|
||||
|
||||
const handleDeleteImportListModalClose = useCallback(() => {
|
||||
setIsDeleteImportListModalOpen(false);
|
||||
}, []);
|
||||
|
||||
const handleConfirmDeleteImportList = useCallback(() => {
|
||||
dispatch(deleteImportList({ id }));
|
||||
}, [id, dispatch]);
|
||||
|
||||
return (
|
||||
<Card
|
||||
className={styles.list}
|
||||
overlayContent={true}
|
||||
onPress={handleEditImportListPress}
|
||||
>
|
||||
<div className={styles.name}>{name}</div>
|
||||
|
||||
<div className={styles.enabled}>
|
||||
{enableAutomaticAdd ? (
|
||||
<Label kind={kinds.SUCCESS}>{translate('AutomaticAdd')}</Label>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<TagList tags={tags} tagList={tagList} />
|
||||
|
||||
<div className={styles.enabled}>
|
||||
<Label kind={kinds.DEFAULT} title="List Refresh Interval">
|
||||
{`${translate('Refresh')}: ${formatShortTimeSpan(
|
||||
minRefreshInterval
|
||||
)}`}
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<EditImportListModal
|
||||
id={id}
|
||||
isOpen={isEditImportListModalOpen}
|
||||
onModalClose={handleEditImportListModalClose}
|
||||
onDeleteImportListPress={handleDeleteImportListPress}
|
||||
/>
|
||||
|
||||
<ConfirmModal
|
||||
isOpen={isDeleteImportListModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title={translate('DeleteImportList')}
|
||||
message={translate('DeleteImportListMessageText', { name })}
|
||||
confirmLabel={translate('Delete')}
|
||||
onConfirm={handleConfirmDeleteImportList}
|
||||
onCancel={handleDeleteImportListModalClose}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export default ImportList;
|
@ -1,118 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Card from 'Components/Card';
|
||||
import FieldSet from 'Components/FieldSet';
|
||||
import Icon from 'Components/Icon';
|
||||
import PageSectionContent from 'Components/Page/PageSectionContent';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AddImportListModal from './AddImportListModal';
|
||||
import EditImportListModalConnector from './EditImportListModalConnector';
|
||||
import ImportList from './ImportList';
|
||||
import styles from './ImportLists.css';
|
||||
|
||||
class ImportLists extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
isAddImportListModalOpen: false,
|
||||
isEditImportListModalOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onAddImportListPress = () => {
|
||||
this.setState({ isAddImportListModalOpen: true });
|
||||
};
|
||||
|
||||
onAddImportListModalClose = ({ listSelected = false } = {}) => {
|
||||
this.setState({
|
||||
isAddImportListModalOpen: false,
|
||||
isEditImportListModalOpen: listSelected
|
||||
});
|
||||
};
|
||||
|
||||
onEditImportListModalClose = () => {
|
||||
this.setState({ isEditImportListModalOpen: false });
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
items,
|
||||
tagList,
|
||||
onConfirmDeleteImportList,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
isAddImportListModalOpen,
|
||||
isEditImportListModalOpen
|
||||
} = this.state;
|
||||
|
||||
return (
|
||||
<FieldSet legend={translate('ImportLists')} >
|
||||
<PageSectionContent
|
||||
errorMessage={translate('ImportListsLoadError')}
|
||||
{...otherProps}
|
||||
>
|
||||
<div className={styles.lists}>
|
||||
{
|
||||
items.map((item) => {
|
||||
return (
|
||||
<ImportList
|
||||
key={item.id}
|
||||
{...item}
|
||||
tagList={tagList}
|
||||
onConfirmDeleteImportList={onConfirmDeleteImportList}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
<Card
|
||||
className={styles.addList}
|
||||
onPress={this.onAddImportListPress}
|
||||
>
|
||||
<div className={styles.center}>
|
||||
<Icon
|
||||
name={icons.ADD}
|
||||
size={45}
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<AddImportListModal
|
||||
isOpen={isAddImportListModalOpen}
|
||||
onModalClose={this.onAddImportListModalClose}
|
||||
/>
|
||||
|
||||
<EditImportListModalConnector
|
||||
isOpen={isEditImportListModalOpen}
|
||||
onModalClose={this.onEditImportListModalClose}
|
||||
/>
|
||||
</PageSectionContent>
|
||||
</FieldSet>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ImportLists.propTypes = {
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
tagList: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
onConfirmDeleteImportList: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default ImportLists;
|
@ -0,0 +1,92 @@
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { ImportListAppState } from 'App/State/SettingsAppState';
|
||||
import Card from 'Components/Card';
|
||||
import FieldSet from 'Components/FieldSet';
|
||||
import Icon from 'Components/Icon';
|
||||
import PageSectionContent from 'Components/Page/PageSectionContent';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import { fetchRootFolders } from 'Store/Actions/rootFolderActions';
|
||||
import { fetchImportLists } from 'Store/Actions/settingsActions';
|
||||
import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector';
|
||||
import ImportListModel from 'typings/ImportList';
|
||||
import sortByProp from 'Utilities/Array/sortByProp';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AddImportListModal from './AddImportListModal';
|
||||
import EditImportListModal from './EditImportListModal';
|
||||
import ImportList from './ImportList';
|
||||
import styles from './ImportLists.css';
|
||||
|
||||
function ImportLists() {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const { isFetching, isPopulated, items, error } = useSelector(
|
||||
createSortedSectionSelector<ImportListModel, ImportListAppState>(
|
||||
'settings.importLists',
|
||||
sortByProp('name')
|
||||
)
|
||||
);
|
||||
|
||||
const [isAddImportListModalOpen, setIsAddImportListModalOpen] =
|
||||
useState(false);
|
||||
const [isEditImportListModalOpen, setIsEditImportListModalOpen] =
|
||||
useState(false);
|
||||
|
||||
const handleAddImportListPress = useCallback(() => {
|
||||
setIsAddImportListModalOpen(true);
|
||||
}, []);
|
||||
|
||||
const handleAddImportListModalClose = useCallback(() => {
|
||||
setIsAddImportListModalOpen(false);
|
||||
}, []);
|
||||
|
||||
const handleImportListSelect = useCallback(() => {
|
||||
setIsAddImportListModalOpen(false);
|
||||
setIsEditImportListModalOpen(true);
|
||||
}, []);
|
||||
|
||||
const handleEditImportListModalClose = useCallback(() => {
|
||||
setIsEditImportListModalOpen(false);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchImportLists());
|
||||
dispatch(fetchRootFolders());
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<FieldSet legend={translate('ImportLists')}>
|
||||
<PageSectionContent
|
||||
errorMessage={translate('ImportListsLoadError')}
|
||||
error={error}
|
||||
isFetching={isFetching}
|
||||
isPopulated={isPopulated}
|
||||
>
|
||||
<div className={styles.lists}>
|
||||
{items.map((item) => {
|
||||
return <ImportList key={item.id} {...item} />;
|
||||
})}
|
||||
|
||||
<Card className={styles.addList} onPress={handleAddImportListPress}>
|
||||
<div className={styles.center}>
|
||||
<Icon name={icons.ADD} size={45} />
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<AddImportListModal
|
||||
isOpen={isAddImportListModalOpen}
|
||||
onImportListSelect={handleImportListSelect}
|
||||
onModalClose={handleAddImportListModalClose}
|
||||
/>
|
||||
|
||||
<EditImportListModal
|
||||
isOpen={isEditImportListModalOpen}
|
||||
onModalClose={handleEditImportListModalClose}
|
||||
/>
|
||||
</PageSectionContent>
|
||||
</FieldSet>
|
||||
);
|
||||
}
|
||||
|
||||
export default ImportLists;
|
@ -1,67 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { fetchRootFolders } from 'Store/Actions/rootFolderActions';
|
||||
import { deleteImportList, fetchImportLists } from 'Store/Actions/settingsActions';
|
||||
import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector';
|
||||
import createTagsSelector from 'Store/Selectors/createTagsSelector';
|
||||
import sortByProp from 'Utilities/Array/sortByProp';
|
||||
import ImportLists from './ImportLists';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createSortedSectionSelector('settings.importLists', sortByProp('name')),
|
||||
createTagsSelector(),
|
||||
(importLists, tagList) => {
|
||||
return {
|
||||
...importLists,
|
||||
tagList
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
fetchImportLists,
|
||||
deleteImportList,
|
||||
fetchRootFolders
|
||||
};
|
||||
|
||||
class ImportListsConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
this.props.fetchImportLists();
|
||||
this.props.fetchRootFolders();
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onConfirmDeleteImportList = (id) => {
|
||||
this.props.deleteImportList({ id });
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ImportLists
|
||||
{...this.props}
|
||||
onConfirmDeleteImportList={this.onConfirmDeleteImportList}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ImportListsConnector.propTypes = {
|
||||
fetchImportLists: PropTypes.func.isRequired,
|
||||
deleteImportList: PropTypes.func.isRequired,
|
||||
fetchRootFolders: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(ImportListsConnector);
|
@ -0,0 +1,8 @@
|
||||
import { useSelector } from 'react-redux';
|
||||
import createTagsSelector from 'Store/Selectors/createTagsSelector';
|
||||
|
||||
const useTags = () => {
|
||||
return useSelector(createTagsSelector());
|
||||
};
|
||||
|
||||
export default useTags;
|
Loading…
Reference in new issue