More Cleanup

This commit is contained in:
Qstick
2020-10-19 01:07:21 -04:00
parent d4e12aa276
commit ad04d0d261
550 changed files with 326 additions and 31626 deletions

View File

@@ -1,101 +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 SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import translate from 'Utilities/String/translate';
import DownloadClientsConnector from './DownloadClients/DownloadClientsConnector';
import DownloadClientOptionsConnector from './Options/DownloadClientOptionsConnector';
import RemotePathMappingsConnector from './RemotePathMappings/RemotePathMappingsConnector';
class DownloadClientSettings extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this._saveCallback = null;
this.state = {
isSaving: false,
hasPendingChanges: false
};
}
//
// Listeners
onChildMounted = (saveCallback) => {
this._saveCallback = saveCallback;
}
onChildStateChange = (payload) => {
this.setState(payload);
}
onSavePress = () => {
if (this._saveCallback) {
this._saveCallback();
}
}
//
// Render
render() {
const {
isTestingAll,
dispatchTestAllDownloadClients
} = this.props;
const {
isSaving,
hasPendingChanges
} = this.state;
return (
<PageContent title={translate('DownloadClientSettings')}>
<SettingsToolbarConnector
isSaving={isSaving}
hasPendingChanges={hasPendingChanges}
additionalButtons={
<Fragment>
<PageToolbarSeparator />
<PageToolbarButton
label={translate('TestAllClients')}
iconName={icons.TEST}
isSpinning={isTestingAll}
onPress={dispatchTestAllDownloadClients}
/>
</Fragment>
}
onSavePress={this.onSavePress}
/>
<PageContentBody>
<DownloadClientsConnector />
<DownloadClientOptionsConnector
onChildMounted={this.onChildMounted}
onChildStateChange={this.onChildStateChange}
/>
<RemotePathMappingsConnector />
</PageContentBody>
</PageContent>
);
}
}
DownloadClientSettings.propTypes = {
isTestingAll: PropTypes.bool.isRequired,
dispatchTestAllDownloadClients: PropTypes.func.isRequired
};
export default DownloadClientSettings;

View File

@@ -1,21 +0,0 @@
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { testAllDownloadClients } from 'Store/Actions/settingsActions';
import DownloadClientSettings from './DownloadClientSettings';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.downloadClients.isTestingAll,
(isTestingAll) => {
return {
isTestingAll
};
}
);
}
const mapDispatchToProps = {
dispatchTestAllDownloadClients: testAllDownloadClients
};
export default connect(createMapStateToProps, mapDispatchToProps)(DownloadClientSettings);

View File

@@ -1,44 +0,0 @@
.downloadClient {
composes: card from '~Components/Card.css';
position: relative;
width: 300px;
height: 100px;
}
.underlay {
@add-mixin cover;
}
.overlay {
@add-mixin linkOverlay;
padding: 10px;
}
.name {
text-align: center;
font-weight: lighter;
font-size: 24px;
}
.actions {
margin-top: 20px;
text-align: right;
}
.presetsMenu {
composes: menu from '~Components/Menu/Menu.css';
display: inline-block;
margin: 0 5px;
}
.presetsMenuButton {
composes: button from '~Components/Link/Button.css';
&::after {
margin-left: 5px;
content: '\25BE';
}
}

View File

@@ -1,111 +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 AddDownloadClientPresetMenuItem from './AddDownloadClientPresetMenuItem';
import styles from './AddDownloadClientItem.css';
class AddDownloadClientItem extends Component {
//
// Listeners
onDownloadClientSelect = () => {
const {
implementation
} = this.props;
this.props.onDownloadClientSelect({ implementation });
}
//
// Render
render() {
const {
implementation,
implementationName,
infoLink,
presets,
onDownloadClientSelect
} = this.props;
const hasPresets = !!presets && !!presets.length;
return (
<div
className={styles.downloadClient}
>
<Link
className={styles.underlay}
onPress={this.onDownloadClientSelect}
/>
<div className={styles.overlay}>
<div className={styles.name}>
{implementationName}
</div>
<div className={styles.actions}>
{
hasPresets &&
<span>
<Button
size={sizes.SMALL}
onPress={this.onDownloadClientSelect}
>
Custom
</Button>
<Menu className={styles.presetsMenu}>
<Button
className={styles.presetsMenuButton}
size={sizes.SMALL}
>
Presets
</Button>
<MenuContent>
{
presets.map((preset) => {
return (
<AddDownloadClientPresetMenuItem
key={preset.name}
name={preset.name}
implementation={implementation}
onPress={onDownloadClientSelect}
/>
);
})
}
</MenuContent>
</Menu>
</span>
}
<Button
to={infoLink}
size={sizes.SMALL}
>
{translate('MoreInfo')}
</Button>
</div>
</div>
</div>
);
}
}
AddDownloadClientItem.propTypes = {
implementation: PropTypes.string.isRequired,
implementationName: PropTypes.string.isRequired,
infoLink: PropTypes.string.isRequired,
presets: PropTypes.arrayOf(PropTypes.object),
onDownloadClientSelect: PropTypes.func.isRequired
};
export default AddDownloadClientItem;

View File

@@ -1,25 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import Modal from 'Components/Modal/Modal';
import AddDownloadClientModalContentConnector from './AddDownloadClientModalContentConnector';
function AddDownloadClientModal({ isOpen, onModalClose, ...otherProps }) {
return (
<Modal
isOpen={isOpen}
onModalClose={onModalClose}
>
<AddDownloadClientModalContentConnector
{...otherProps}
onModalClose={onModalClose}
/>
</Modal>
);
}
AddDownloadClientModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default AddDownloadClientModal;

View File

@@ -1,5 +0,0 @@
.downloadClients {
display: flex;
justify-content: center;
flex-wrap: wrap;
}

View File

@@ -1,122 +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 translate from 'Utilities/String/translate';
import AddDownloadClientItem from './AddDownloadClientItem';
import styles from './AddDownloadClientModalContent.css';
class AddDownloadClientModalContent extends Component {
//
// Render
render() {
const {
isSchemaFetching,
isSchemaPopulated,
schemaError,
usenetDownloadClients,
torrentDownloadClients,
onDownloadClientSelect,
onModalClose
} = this.props;
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
Add DownloadClient
</ModalHeader>
<ModalBody>
{
isSchemaFetching &&
<LoadingIndicator />
}
{
!isSchemaFetching && !!schemaError &&
<div>
{translate('UnableToAddANewDownloadClientPleaseTryAgain')}
</div>
}
{
isSchemaPopulated && !schemaError &&
<div>
<Alert kind={kinds.INFO}>
<div>
{translate('RadarrSupportsAnyDownloadClient')}
</div>
<div>
{translate('ForMoreInformationOnTheIndividualDownloadClients')}
</div>
</Alert>
<FieldSet legend={translate('Usenet')}>
<div className={styles.downloadClients}>
{
usenetDownloadClients.map((downloadClient) => {
return (
<AddDownloadClientItem
key={downloadClient.implementation}
implementation={downloadClient.implementation}
{...downloadClient}
onDownloadClientSelect={onDownloadClientSelect}
/>
);
})
}
</div>
</FieldSet>
<FieldSet legend={translate('Torrents')}>
<div className={styles.downloadClients}>
{
torrentDownloadClients.map((downloadClient) => {
return (
<AddDownloadClientItem
key={downloadClient.implementation}
implementation={downloadClient.implementation}
{...downloadClient}
onDownloadClientSelect={onDownloadClientSelect}
/>
);
})
}
</div>
</FieldSet>
</div>
}
</ModalBody>
<ModalFooter>
<Button
onPress={onModalClose}
>
{translate('Close')}
</Button>
</ModalFooter>
</ModalContent>
);
}
}
AddDownloadClientModalContent.propTypes = {
isSchemaFetching: PropTypes.bool.isRequired,
isSchemaPopulated: PropTypes.bool.isRequired,
schemaError: PropTypes.object,
usenetDownloadClients: PropTypes.arrayOf(PropTypes.object).isRequired,
torrentDownloadClients: PropTypes.arrayOf(PropTypes.object).isRequired,
onDownloadClientSelect: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default AddDownloadClientModalContent;

View File

@@ -1,75 +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 { fetchDownloadClientSchema, selectDownloadClientSchema } from 'Store/Actions/settingsActions';
import AddDownloadClientModalContent from './AddDownloadClientModalContent';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.downloadClients,
(downloadClients) => {
const {
isSchemaFetching,
isSchemaPopulated,
schemaError,
schema
} = downloadClients;
const usenetDownloadClients = _.filter(schema, { protocol: 'usenet' });
const torrentDownloadClients = _.filter(schema, { protocol: 'torrent' });
return {
isSchemaFetching,
isSchemaPopulated,
schemaError,
usenetDownloadClients,
torrentDownloadClients
};
}
);
}
const mapDispatchToProps = {
fetchDownloadClientSchema,
selectDownloadClientSchema
};
class AddDownloadClientModalContentConnector extends Component {
//
// Lifecycle
componentDidMount() {
this.props.fetchDownloadClientSchema();
}
//
// Listeners
onDownloadClientSelect = ({ implementation }) => {
this.props.selectDownloadClientSchema({ implementation });
this.props.onModalClose({ downloadClientSelected: true });
}
//
// Render
render() {
return (
<AddDownloadClientModalContent
{...this.props}
onDownloadClientSelect={this.onDownloadClientSelect}
/>
);
}
}
AddDownloadClientModalContentConnector.propTypes = {
fetchDownloadClientSchema: PropTypes.func.isRequired,
selectDownloadClientSchema: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(AddDownloadClientModalContentConnector);

View File

@@ -1,49 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import MenuItem from 'Components/Menu/MenuItem';
class AddDownloadClientPresetMenuItem extends Component {
//
// Listeners
onPress = () => {
const {
name,
implementation
} = this.props;
this.props.onPress({
name,
implementation
});
}
//
// Render
render() {
const {
name,
implementation,
...otherProps
} = this.props;
return (
<MenuItem
{...otherProps}
onPress={this.onPress}
>
{name}
</MenuItem>
);
}
}
AddDownloadClientPresetMenuItem.propTypes = {
name: PropTypes.string.isRequired,
implementation: PropTypes.string.isRequired,
onPress: PropTypes.func.isRequired
};
export default AddDownloadClientPresetMenuItem;

View File

@@ -1,19 +0,0 @@
.downloadClient {
composes: card from '~Components/Card.css';
width: 290px;
}
.name {
@add-mixin truncate;
margin-bottom: 20px;
font-weight: 300;
font-size: 24px;
}
.enabled {
display: flex;
flex-wrap: wrap;
margin-top: 5px;
}

View File

@@ -1,126 +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 { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import EditDownloadClientModalConnector from './EditDownloadClientModalConnector';
import styles from './DownloadClient.css';
class DownloadClient extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
isEditDownloadClientModalOpen: false,
isDeleteDownloadClientModalOpen: false
};
}
//
// Listeners
onEditDownloadClientPress = () => {
this.setState({ isEditDownloadClientModalOpen: true });
}
onEditDownloadClientModalClose = () => {
this.setState({ isEditDownloadClientModalOpen: false });
}
onDeleteDownloadClientPress = () => {
this.setState({
isEditDownloadClientModalOpen: false,
isDeleteDownloadClientModalOpen: true
});
}
onDeleteDownloadClientModalClose= () => {
this.setState({ isDeleteDownloadClientModalOpen: false });
}
onConfirmDeleteDownloadClient = () => {
this.props.onConfirmDeleteDownloadClient(this.props.id);
}
//
// Render
render() {
const {
id,
name,
enable,
priority
} = this.props;
return (
<Card
className={styles.downloadClient}
overlayContent={true}
onPress={this.onEditDownloadClientPress}
>
<div className={styles.name}>
{name}
</div>
<div className={styles.enabled}>
{
enable ?
<Label kind={kinds.SUCCESS}>
Enabled
</Label> :
<Label
kind={kinds.DISABLED}
outline={true}
>
Disabled
</Label>
}
{
priority > 1 &&
<Label
kind={kinds.DISABLED}
outline={true}
>
Priority: {priority}
</Label>
}
</div>
<EditDownloadClientModalConnector
id={id}
isOpen={this.state.isEditDownloadClientModalOpen}
onModalClose={this.onEditDownloadClientModalClose}
onDeleteDownloadClientPress={this.onDeleteDownloadClientPress}
/>
<ConfirmModal
isOpen={this.state.isDeleteDownloadClientModalOpen}
kind={kinds.DANGER}
title={translate('DeleteDownloadClient')}
message={translate('DeleteDownloadClientMessageText', [name])}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteDownloadClient}
onCancel={this.onDeleteDownloadClientModalClose}
/>
</Card>
);
}
}
DownloadClient.propTypes = {
id: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
enable: PropTypes.bool.isRequired,
priority: PropTypes.number.isRequired,
onConfirmDeleteDownloadClient: PropTypes.func.isRequired
};
export default DownloadClient;

View File

@@ -1,20 +0,0 @@
.downloadClients {
display: flex;
flex-wrap: wrap;
}
.addDownloadClient {
composes: downloadClient from '~./DownloadClient.css';
background-color: $cardAlternateBackgroundColor;
color: $gray;
text-align: center;
}
.center {
display: inline-block;
padding: 5px 20px 0;
border: 1px solid $borderColor;
border-radius: 4px;
background-color: $white;
}

View File

@@ -1,115 +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 AddDownloadClientModal from './AddDownloadClientModal';
import DownloadClient from './DownloadClient';
import EditDownloadClientModalConnector from './EditDownloadClientModalConnector';
import styles from './DownloadClients.css';
class DownloadClients extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
isAddDownloadClientModalOpen: false,
isEditDownloadClientModalOpen: false
};
}
//
// Listeners
onAddDownloadClientPress = () => {
this.setState({ isAddDownloadClientModalOpen: true });
}
onAddDownloadClientModalClose = ({ downloadClientSelected = false } = {}) => {
this.setState({
isAddDownloadClientModalOpen: false,
isEditDownloadClientModalOpen: downloadClientSelected
});
}
onEditDownloadClientModalClose = () => {
this.setState({ isEditDownloadClientModalOpen: false });
}
//
// Render
render() {
const {
items,
onConfirmDeleteDownloadClient,
...otherProps
} = this.props;
const {
isAddDownloadClientModalOpen,
isEditDownloadClientModalOpen
} = this.state;
return (
<FieldSet legend={translate('DownloadClients')}>
<PageSectionContent
errorMessage={translate('UnableToLoadDownloadClients')}
{...otherProps}
>
<div className={styles.downloadClients}>
{
items.map((item) => {
return (
<DownloadClient
key={item.id}
{...item}
onConfirmDeleteDownloadClient={onConfirmDeleteDownloadClient}
/>
);
})
}
<Card
className={styles.addDownloadClient}
onPress={this.onAddDownloadClientPress}
>
<div className={styles.center}>
<Icon
name={icons.ADD}
size={45}
/>
</div>
</Card>
</div>
<AddDownloadClientModal
isOpen={isAddDownloadClientModalOpen}
onModalClose={this.onAddDownloadClientModalClose}
/>
<EditDownloadClientModalConnector
isOpen={isEditDownloadClientModalOpen}
onModalClose={this.onEditDownloadClientModalClose}
/>
</PageSectionContent>
</FieldSet>
);
}
}
DownloadClients.propTypes = {
isFetching: PropTypes.bool.isRequired,
error: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
onConfirmDeleteDownloadClient: PropTypes.func.isRequired
};
export default DownloadClients;

View File

@@ -1,56 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { deleteDownloadClient, fetchDownloadClients } from 'Store/Actions/settingsActions';
import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector';
import sortByName from 'Utilities/Array/sortByName';
import DownloadClients from './DownloadClients';
function createMapStateToProps() {
return createSelector(
createSortedSectionSelector('settings.downloadClients', sortByName),
(downloadClients) => downloadClients
);
}
const mapDispatchToProps = {
fetchDownloadClients,
deleteDownloadClient
};
class DownloadClientsConnector extends Component {
//
// Lifecycle
componentDidMount() {
this.props.fetchDownloadClients();
}
//
// Listeners
onConfirmDeleteDownloadClient = (id) => {
this.props.deleteDownloadClient({ id });
}
//
// Render
render() {
return (
<DownloadClients
{...this.props}
onConfirmDeleteDownloadClient={this.onConfirmDeleteDownloadClient}
/>
);
}
}
DownloadClientsConnector.propTypes = {
fetchDownloadClients: PropTypes.func.isRequired,
deleteDownloadClient: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(DownloadClientsConnector);

View File

@@ -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 EditDownloadClientModalContentConnector from './EditDownloadClientModalContentConnector';
function EditDownloadClientModal({ isOpen, onModalClose, ...otherProps }) {
return (
<Modal
size={sizes.MEDIUM}
isOpen={isOpen}
onModalClose={onModalClose}
>
<EditDownloadClientModalContentConnector
{...otherProps}
onModalClose={onModalClose}
/>
</Modal>
);
}
EditDownloadClientModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default EditDownloadClientModal;

View File

@@ -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 { cancelSaveDownloadClient, cancelTestDownloadClient } from 'Store/Actions/settingsActions';
import EditDownloadClientModal from './EditDownloadClientModal';
function createMapDispatchToProps(dispatch, props) {
const section = 'settings.downloadClients';
return {
dispatchClearPendingChanges() {
dispatch(clearPendingChanges({ section }));
},
dispatchCancelTestDownloadClient() {
dispatch(cancelTestDownloadClient({ section }));
},
dispatchCancelSaveDownloadClient() {
dispatch(cancelSaveDownloadClient({ section }));
}
};
}
class EditDownloadClientModalConnector extends Component {
//
// Listeners
onModalClose = () => {
this.props.dispatchClearPendingChanges();
this.props.dispatchCancelTestDownloadClient();
this.props.dispatchCancelSaveDownloadClient();
this.props.onModalClose();
}
//
// Render
render() {
const {
dispatchClearPendingChanges,
dispatchCancelTestDownloadClient,
dispatchCancelSaveDownloadClient,
...otherProps
} = this.props;
return (
<EditDownloadClientModal
{...otherProps}
onModalClose={this.onModalClose}
/>
);
}
}
EditDownloadClientModalConnector.propTypes = {
onModalClose: PropTypes.func.isRequired,
dispatchClearPendingChanges: PropTypes.func.isRequired,
dispatchCancelTestDownloadClient: PropTypes.func.isRequired,
dispatchCancelSaveDownloadClient: PropTypes.func.isRequired
};
export default connect(null, createMapDispatchToProps)(EditDownloadClientModalConnector);

View File

@@ -1,11 +0,0 @@
.deleteButton {
composes: button from '~Components/Link/Button.css';
margin-right: auto;
}
.message {
composes: alert from '~Components/Alert.css';
margin-bottom: 30px;
}

View File

@@ -1,197 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
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 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 { inputTypes, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './EditDownloadClientModalContent.css';
class EditDownloadClientModalContent extends Component {
//
// Render
render() {
const {
advancedSettings,
isFetching,
error,
isSaving,
isTesting,
saveError,
item,
onInputChange,
onFieldChange,
onModalClose,
onSavePress,
onTestPress,
onDeleteDownloadClientPress,
...otherProps
} = this.props;
const {
id,
implementationName,
name,
enable,
priority,
fields,
message
} = item;
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
{`${id ? 'Edit' : 'Add'} Download Client - ${implementationName}`}
</ModalHeader>
<ModalBody>
{
isFetching &&
<LoadingIndicator />
}
{
!isFetching && !!error &&
<div>
{translate('UnableToAddANewDownloadClientPleaseTryAgain')}
</div>
}
{
!isFetching && !error &&
<Form {...otherProps}>
{
!!message &&
<Alert
className={styles.message}
kind={message.value.type}
>
{message.value.message}
</Alert>
}
<FormGroup>
<FormLabel>{translate('Name')}</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="name"
{...name}
onChange={onInputChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>{translate('Enable')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="enable"
{...enable}
onChange={onInputChange}
/>
</FormGroup>
{
fields.map((field) => {
return (
<ProviderFieldFormGroup
key={field.name}
advancedSettings={advancedSettings}
provider="downloadClient"
providerData={item}
{...field}
onChange={onFieldChange}
/>
);
})
}
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>{translate('ClientPriority')}</FormLabel>
<FormInputGroup
type={inputTypes.NUMBER}
name="priority"
helpText={translate('PriorityHelpText')}
min={1}
max={50}
{...priority}
onChange={onInputChange}
/>
</FormGroup>
</Form>
}
</ModalBody>
<ModalFooter>
{
id &&
<Button
className={styles.deleteButton}
kind={kinds.DANGER}
onPress={onDeleteDownloadClientPress}
>
{translate('Delete')}
</Button>
}
<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>
);
}
}
EditDownloadClientModalContent.propTypes = {
advancedSettings: PropTypes.bool.isRequired,
isFetching: PropTypes.bool.isRequired,
error: PropTypes.object,
isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object,
isTesting: PropTypes.bool.isRequired,
item: PropTypes.object.isRequired,
onInputChange: PropTypes.func.isRequired,
onFieldChange: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired,
onSavePress: PropTypes.func.isRequired,
onTestPress: PropTypes.func.isRequired,
onDeleteDownloadClientPress: PropTypes.func
};
export default EditDownloadClientModalContent;

View File

@@ -1,88 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { saveDownloadClient, setDownloadClientFieldValue, setDownloadClientValue, testDownloadClient } from 'Store/Actions/settingsActions';
import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
import EditDownloadClientModalContent from './EditDownloadClientModalContent';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.advancedSettings,
createProviderSettingsSelector('downloadClients'),
(advancedSettings, downloadClient) => {
return {
advancedSettings,
...downloadClient
};
}
);
}
const mapDispatchToProps = {
setDownloadClientValue,
setDownloadClientFieldValue,
saveDownloadClient,
testDownloadClient
};
class EditDownloadClientModalContentConnector extends Component {
//
// Lifecycle
componentDidUpdate(prevProps, prevState) {
if (prevProps.isSaving && !this.props.isSaving && !this.props.saveError) {
this.props.onModalClose();
}
}
//
// Listeners
onInputChange = ({ name, value }) => {
this.props.setDownloadClientValue({ name, value });
}
onFieldChange = ({ name, value }) => {
this.props.setDownloadClientFieldValue({ name, value });
}
onSavePress = () => {
this.props.saveDownloadClient({ id: this.props.id });
}
onTestPress = () => {
this.props.testDownloadClient({ id: this.props.id });
}
//
// Render
render() {
return (
<EditDownloadClientModalContent
{...this.props}
onSavePress={this.onSavePress}
onTestPress={this.onTestPress}
onInputChange={this.onInputChange}
onFieldChange={this.onFieldChange}
/>
);
}
}
EditDownloadClientModalContentConnector.propTypes = {
id: PropTypes.number,
isFetching: PropTypes.bool.isRequired,
isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object,
item: PropTypes.object.isRequired,
setDownloadClientValue: PropTypes.func.isRequired,
setDownloadClientFieldValue: PropTypes.func.isRequired,
saveDownloadClient: PropTypes.func.isRequired,
testDownloadClient: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(EditDownloadClientModalContentConnector);

View File

@@ -1,138 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import FieldSet from 'Components/FieldSet';
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 LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { inputTypes, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
function DownloadClientOptions(props) {
const {
advancedSettings,
isFetching,
error,
settings,
hasSettings,
onInputChange
} = props;
return (
<div>
{
isFetching &&
<LoadingIndicator />
}
{
!isFetching && error &&
<div>
{translate('UnableToLoadDownloadClientOptions')}
</div>
}
{
hasSettings && !isFetching && !error &&
<div>
<FieldSet legend={translate('CompletedDownloadHandling')}>
<Form>
<FormGroup size={sizes.MEDIUM}>
<FormLabel>{translate('Enable')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="enableCompletedDownloadHandling"
helpText={translate('EnableCompletedDownloadHandlingHelpText')}
onChange={onInputChange}
{...settings.enableCompletedDownloadHandling}
/>
</FormGroup>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
size={sizes.MEDIUM}
>
<FormLabel>{translate('Remove')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="removeCompletedDownloads"
helpText={translate('RemoveCompletedDownloadsHelpText')}
onChange={onInputChange}
{...settings.removeCompletedDownloads}
/>
</FormGroup>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
size={sizes.MEDIUM}
>
<FormLabel>{translate('CheckForFinishedDownloadsInterval')}</FormLabel>
<FormInputGroup
type={inputTypes.NUMBER}
name="checkForFinishedDownloadInterval"
min={0}
max={120}
unit="minutes"
helpText={translate('HelpText')}
onChange={onInputChange}
{...settings.checkForFinishedDownloadInterval}
/>
</FormGroup>
</Form>
</FieldSet>
<FieldSet
legend={translate('FailedDownloadHandling')}
>
<Form>
<FormGroup size={sizes.MEDIUM}>
<FormLabel>{translate('Redownload')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="autoRedownloadFailed"
helpText={translate('AutoRedownloadFailedHelpText')}
onChange={onInputChange}
{...settings.autoRedownloadFailed}
/>
</FormGroup>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
size={sizes.MEDIUM}
>
<FormLabel>{translate('Remove')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="removeFailedDownloads"
helpText={translate('RemoveFailedDownloadsHelpText')}
onChange={onInputChange}
{...settings.removeFailedDownloads}
/>
</FormGroup>
</Form>
</FieldSet>
</div>
}
</div>
);
}
DownloadClientOptions.propTypes = {
advancedSettings: PropTypes.bool.isRequired,
isFetching: PropTypes.bool.isRequired,
error: PropTypes.object,
settings: PropTypes.object.isRequired,
hasSettings: PropTypes.bool.isRequired,
onInputChange: PropTypes.func.isRequired
};
export default DownloadClientOptions;

View File

@@ -1,101 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { clearPendingChanges } from 'Store/Actions/baseActions';
import { fetchDownloadClientOptions, saveDownloadClientOptions, setDownloadClientOptionsValue } from 'Store/Actions/settingsActions';
import createSettingsSectionSelector from 'Store/Selectors/createSettingsSectionSelector';
import DownloadClientOptions from './DownloadClientOptions';
const SECTION = 'downloadClientOptions';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.advancedSettings,
createSettingsSectionSelector(SECTION),
(advancedSettings, sectionSettings) => {
return {
advancedSettings,
...sectionSettings
};
}
);
}
const mapDispatchToProps = {
dispatchFetchDownloadClientOptions: fetchDownloadClientOptions,
dispatchSetDownloadClientOptionsValue: setDownloadClientOptionsValue,
dispatchSaveDownloadClientOptions: saveDownloadClientOptions,
dispatchClearPendingChanges: clearPendingChanges
};
class DownloadClientOptionsConnector extends Component {
//
// Lifecycle
componentDidMount() {
const {
dispatchFetchDownloadClientOptions,
dispatchSaveDownloadClientOptions,
onChildMounted
} = this.props;
dispatchFetchDownloadClientOptions();
onChildMounted(dispatchSaveDownloadClientOptions);
}
componentDidUpdate(prevProps) {
const {
hasPendingChanges,
isSaving,
onChildStateChange
} = this.props;
if (
prevProps.isSaving !== isSaving ||
prevProps.hasPendingChanges !== hasPendingChanges
) {
onChildStateChange({
isSaving,
hasPendingChanges
});
}
}
componentWillUnmount() {
this.props.dispatchClearPendingChanges({ section: `settings.${SECTION}` });
}
//
// Listeners
onInputChange = ({ name, value }) => {
this.props.dispatchSetDownloadClientOptionsValue({ name, value });
}
//
// Render
render() {
return (
<DownloadClientOptions
onInputChange={this.onInputChange}
{...this.props}
/>
);
}
}
DownloadClientOptionsConnector.propTypes = {
isSaving: PropTypes.bool.isRequired,
hasPendingChanges: PropTypes.bool.isRequired,
dispatchFetchDownloadClientOptions: PropTypes.func.isRequired,
dispatchSetDownloadClientOptionsValue: PropTypes.func.isRequired,
dispatchSaveDownloadClientOptions: PropTypes.func.isRequired,
dispatchClearPendingChanges: PropTypes.func.isRequired,
onChildMounted: PropTypes.func.isRequired,
onChildStateChange: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(DownloadClientOptionsConnector);

View File

@@ -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 EditRemotePathMappingModalContentConnector from './EditRemotePathMappingModalContentConnector';
function EditRemotePathMappingModal({ isOpen, onModalClose, ...otherProps }) {
return (
<Modal
size={sizes.MEDIUM}
isOpen={isOpen}
onModalClose={onModalClose}
>
<EditRemotePathMappingModalContentConnector
{...otherProps}
onModalClose={onModalClose}
/>
</Modal>
);
}
EditRemotePathMappingModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default EditRemotePathMappingModal;

View File

@@ -1,43 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { clearPendingChanges } from 'Store/Actions/baseActions';
import EditRemotePathMappingModal from './EditRemotePathMappingModal';
function mapStateToProps() {
return {};
}
const mapDispatchToProps = {
clearPendingChanges
};
class EditRemotePathMappingModalConnector extends Component {
//
// Listeners
onModalClose = () => {
this.props.clearPendingChanges({ section: 'settings.remotePathMappings' });
this.props.onModalClose();
}
//
// Render
render() {
return (
<EditRemotePathMappingModal
{...this.props}
onModalClose={this.onModalClose}
/>
);
}
}
EditRemotePathMappingModalConnector.propTypes = {
onModalClose: PropTypes.func.isRequired,
clearPendingChanges: PropTypes.func.isRequired
};
export default connect(mapStateToProps, mapDispatchToProps)(EditRemotePathMappingModalConnector);

View File

@@ -1,11 +0,0 @@
.body {
composes: modalBody from '~Components/Modal/ModalBody.css';
flex: 1 1 430px;
}
.deleteButton {
composes: button from '~Components/Link/Button.css';
margin-right: auto;
}

View File

@@ -1,153 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import Button from 'Components/Link/Button';
import 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 { inputTypes, kinds } from 'Helpers/Props';
import { stringSettingShape } from 'Helpers/Props/Shapes/settingShape';
import translate from 'Utilities/String/translate';
import styles from './EditRemotePathMappingModalContent.css';
function EditRemotePathMappingModalContent(props) {
const {
id,
isFetching,
error,
isSaving,
saveError,
item,
downloadClientHosts,
onInputChange,
onSavePress,
onModalClose,
onDeleteRemotePathMappingPress,
...otherProps
} = props;
const {
host,
remotePath,
localPath
} = item;
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
{id ? translate('EditRemotePathMapping') : translate('AddRemotePathMapping')}
</ModalHeader>
<ModalBody className={styles.body}>
{
isFetching &&
<LoadingIndicator />
}
{
!isFetching && !!error &&
<div>
{translate('UnableToAddANewRemotePathMappingPleaseTryAgain')}
</div>
}
{
!isFetching && !error &&
<Form {...otherProps}>
<FormGroup>
<FormLabel>{translate('Host')}</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="host"
helpText={translate('SettingsRemotePathMappingHostHelpText')}
{...host}
values={downloadClientHosts}
onChange={onInputChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>{translate('SettingsRemotePathMappingRemotePath')}</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="remotePath"
helpText={translate('SettingsRemotePathMappingRemotePathHelpText')}
{...remotePath}
onChange={onInputChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>{translate('SettingsRemotePathMappingLocalPath')}</FormLabel>
<FormInputGroup
type={inputTypes.PATH}
name="localPath"
helpText={translate('SettingsRemotePathMappingLocalPathHelpText')}
{...localPath}
onChange={onInputChange}
/>
</FormGroup>
</Form>
}
</ModalBody>
<ModalFooter>
{
id &&
<Button
className={styles.deleteButton}
kind={kinds.DANGER}
onPress={onDeleteRemotePathMappingPress}
>
{translate('Delete')}
</Button>
}
<Button
onPress={onModalClose}
>
{translate('Cancel')}
</Button>
<SpinnerErrorButton
isSpinning={isSaving}
error={saveError}
onPress={onSavePress}
>
{translate('Save')}
</SpinnerErrorButton>
</ModalFooter>
</ModalContent>
);
}
const remotePathMappingShape = {
host: PropTypes.shape(stringSettingShape).isRequired,
remotePath: PropTypes.shape(stringSettingShape).isRequired,
localPath: PropTypes.shape(stringSettingShape).isRequired
};
EditRemotePathMappingModalContent.propTypes = {
id: PropTypes.number,
isFetching: PropTypes.bool.isRequired,
error: PropTypes.object,
isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object,
item: PropTypes.shape(remotePathMappingShape).isRequired,
downloadClientHosts: PropTypes.arrayOf(PropTypes.object).isRequired,
onInputChange: PropTypes.func.isRequired,
onSavePress: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired,
onDeleteRemotePathMappingPress: PropTypes.func
};
export default EditRemotePathMappingModalContent;

View File

@@ -1,148 +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 { saveRemotePathMapping, setRemotePathMappingValue } from 'Store/Actions/settingsActions';
import selectSettings from 'Store/Selectors/selectSettings';
import EditRemotePathMappingModalContent from './EditRemotePathMappingModalContent';
const newRemotePathMapping = {
host: '',
remotePath: '',
localPath: ''
};
const selectDownloadClientHosts = createSelector(
(state) => state.settings.downloadClients.items,
(downloadClients) => {
const hosts = downloadClients.reduce((acc, downloadClient) => {
const name = downloadClient.name;
const host = downloadClient.fields.find((field) => {
return field.name === 'host';
});
if (host) {
const group = acc[host.value] = acc[host.value] || [];
group.push(name);
}
return acc;
}, {});
return Object.keys(hosts).map((host) => {
return {
key: host,
value: host,
hint: `${hosts[host].join(', ')}`
};
});
}
);
function createRemotePathMappingSelector() {
return createSelector(
(state, { id }) => id,
(state) => state.settings.remotePathMappings,
selectDownloadClientHosts,
(id, remotePathMappings, downloadClientHosts) => {
const {
isFetching,
error,
isSaving,
saveError,
pendingChanges,
items
} = remotePathMappings;
const mapping = id ? _.find(items, { id }) : newRemotePathMapping;
const settings = selectSettings(mapping, pendingChanges, saveError);
return {
id,
isFetching,
error,
isSaving,
saveError,
item: settings.settings,
...settings,
downloadClientHosts
};
}
);
}
function createMapStateToProps() {
return createSelector(
createRemotePathMappingSelector(),
(remotePathMapping) => {
return {
...remotePathMapping
};
}
);
}
const mapDispatchToProps = {
dispatchSetRemotePathMappingValue: setRemotePathMappingValue,
dispatchSaveRemotePathMapping: saveRemotePathMapping
};
class EditRemotePathMappingModalContentConnector extends Component {
//
// Lifecycle
componentDidMount() {
if (!this.props.id) {
Object.keys(newRemotePathMapping).forEach((name) => {
this.props.dispatchSetRemotePathMappingValue({
name,
value: newRemotePathMapping[name]
});
});
}
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.isSaving && !this.props.isSaving && !this.props.saveError) {
this.props.onModalClose();
}
}
//
// Listeners
onInputChange = ({ name, value }) => {
this.props.dispatchSetRemotePathMappingValue({ name, value });
}
onSavePress = () => {
this.props.dispatchSaveRemotePathMapping({ id: this.props.id });
}
//
// Render
render() {
return (
<EditRemotePathMappingModalContent
{...this.props}
onSavePress={this.onSavePress}
onInputChange={this.onInputChange}
/>
);
}
}
EditRemotePathMappingModalContentConnector.propTypes = {
id: PropTypes.number,
isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object,
item: PropTypes.object.isRequired,
dispatchSetRemotePathMappingValue: PropTypes.func.isRequired,
dispatchSaveRemotePathMapping: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(EditRemotePathMappingModalContentConnector);

View File

@@ -1,23 +0,0 @@
.remotePathMapping {
display: flex;
align-items: stretch;
margin-bottom: 10px;
height: 30px;
border-bottom: 1px solid $borderColor;
line-height: 30px;
}
.host {
flex: 0 0 300px;
}
.path {
flex: 0 0 400px;
}
.actions {
display: flex;
justify-content: flex-end;
flex: 1 0 auto;
padding-right: 10px;
}

View File

@@ -1,115 +0,0 @@
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Icon from 'Components/Icon';
import Link from 'Components/Link/Link';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import { icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import EditRemotePathMappingModalConnector from './EditRemotePathMappingModalConnector';
import styles from './RemotePathMapping.css';
class RemotePathMapping extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
isEditRemotePathMappingModalOpen: false,
isDeleteRemotePathMappingModalOpen: false
};
}
//
// Listeners
onEditRemotePathMappingPress = () => {
this.setState({ isEditRemotePathMappingModalOpen: true });
}
onEditRemotePathMappingModalClose = () => {
this.setState({ isEditRemotePathMappingModalOpen: false });
}
onDeleteRemotePathMappingPress = () => {
this.setState({
isEditRemotePathMappingModalOpen: false,
isDeleteRemotePathMappingModalOpen: true
});
}
onDeleteRemotePathMappingModalClose = () => {
this.setState({ isDeleteRemotePathMappingModalOpen: false });
}
onConfirmDeleteRemotePathMapping = () => {
this.props.onConfirmDeleteRemotePathMapping(this.props.id);
}
//
// Render
render() {
const {
id,
host,
remotePath,
localPath
} = this.props;
return (
<div
className={classNames(
styles.remotePathMapping
)}
>
<div className={styles.host}>{host}</div>
<div className={styles.path}>{remotePath}</div>
<div className={styles.path}>{localPath}</div>
<div className={styles.actions}>
<Link
onPress={this.onEditRemotePathMappingPress}
>
<Icon name={icons.EDIT} />
</Link>
</div>
<EditRemotePathMappingModalConnector
id={id}
isOpen={this.state.isEditRemotePathMappingModalOpen}
onModalClose={this.onEditRemotePathMappingModalClose}
onDeleteRemotePathMappingPress={this.onDeleteRemotePathMappingPress}
/>
<ConfirmModal
isOpen={this.state.isDeleteRemotePathMappingModalOpen}
kind={kinds.DANGER}
title={translate('DeleteDelayProfile')}
message={translate('AreYouSureYouWantToDeleteThisRemotePathMapping')}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteRemotePathMapping}
onCancel={this.onDeleteRemotePathMappingModalClose}
/>
</div>
);
}
}
RemotePathMapping.propTypes = {
id: PropTypes.number.isRequired,
host: PropTypes.string.isRequired,
remotePath: PropTypes.string.isRequired,
localPath: PropTypes.string.isRequired,
onConfirmDeleteRemotePathMapping: PropTypes.func.isRequired
};
RemotePathMapping.defaultProps = {
// The drag preview will not connect the drag handle.
connectDragSource: (node) => node
};
export default RemotePathMapping;

View File

@@ -1,23 +0,0 @@
.remotePathMappingsHeader {
display: flex;
margin-bottom: 10px;
font-weight: bold;
}
.host {
flex: 0 0 300px;
}
.path {
flex: 0 0 400px;
}
.addRemotePathMapping {
display: flex;
justify-content: flex-end;
padding-right: 10px;
}
.addButton {
text-align: center;
}

View File

@@ -1,101 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import FieldSet from 'Components/FieldSet';
import Icon from 'Components/Icon';
import Link from 'Components/Link/Link';
import PageSectionContent from 'Components/Page/PageSectionContent';
import { icons } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import EditRemotePathMappingModalConnector from './EditRemotePathMappingModalConnector';
import RemotePathMapping from './RemotePathMapping';
import styles from './RemotePathMappings.css';
class RemotePathMappings extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
isAddRemotePathMappingModalOpen: false
};
}
//
// Listeners
onAddRemotePathMappingPress = () => {
this.setState({ isAddRemotePathMappingModalOpen: true });
}
onModalClose = () => {
this.setState({ isAddRemotePathMappingModalOpen: false });
}
//
// Render
render() {
const {
items,
onConfirmDeleteRemotePathMapping,
...otherProps
} = this.props;
return (
<FieldSet legend={translate('RemotePathMappings')}>
<PageSectionContent
errorMessage={translate('UnableToLoadRemotePathMappings')}
{...otherProps}
>
<div className={styles.remotePathMappingsHeader}>
<div className={styles.host}>Host</div>
<div className={styles.path}>Remote Path</div>
<div className={styles.path}>Local Path</div>
</div>
<div>
{
items.map((item, index) => {
return (
<RemotePathMapping
key={item.id}
{...item}
{...otherProps}
index={index}
onConfirmDeleteRemotePathMapping={onConfirmDeleteRemotePathMapping}
/>
);
})
}
</div>
<div className={styles.addRemotePathMapping}>
<Link
className={styles.addButton}
onPress={this.onAddRemotePathMappingPress}
>
<Icon name={icons.ADD} />
</Link>
</div>
<EditRemotePathMappingModalConnector
isOpen={this.state.isAddRemotePathMappingModalOpen}
onModalClose={this.onModalClose}
/>
</PageSectionContent>
</FieldSet>
);
}
}
RemotePathMappings.propTypes = {
isFetching: PropTypes.bool.isRequired,
error: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
onConfirmDeleteRemotePathMapping: PropTypes.func.isRequired
};
export default RemotePathMappings;

View File

@@ -1,59 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { deleteRemotePathMapping, fetchRemotePathMappings } from 'Store/Actions/settingsActions';
import RemotePathMappings from './RemotePathMappings';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.remotePathMappings,
(remotePathMappings) => {
return {
...remotePathMappings
};
}
);
}
const mapDispatchToProps = {
fetchRemotePathMappings,
deleteRemotePathMapping
};
class RemotePathMappingsConnector extends Component {
//
// Lifecycle
componentDidMount() {
this.props.fetchRemotePathMappings();
}
//
// Listeners
onConfirmDeleteRemotePathMapping = (id) => {
this.props.deleteRemotePathMapping({ id });
}
//
// Render
render() {
return (
<RemotePathMappings
{...this.state}
{...this.props}
onConfirmDeleteRemotePathMapping={this.onConfirmDeleteRemotePathMapping}
/>
);
}
}
RemotePathMappingsConnector.propTypes = {
fetchRemotePathMappings: PropTypes.func.isRequired,
deleteRemotePathMapping: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(RemotePathMappingsConnector);