New: Clone indexer button

Closes #3546
This commit is contained in:
Mark McDowall 2020-03-01 12:56:58 -08:00 committed by Qstick
parent f338941cfc
commit e6f5d535e9
5 changed files with 79 additions and 10 deletions

View File

@ -4,6 +4,11 @@
width: 290px; width: 290px;
} }
.nameContainer {
display: flex;
justify-content: space-between;
}
.name { .name {
@add-mixin truncate; @add-mixin truncate;
@ -12,6 +17,12 @@
font-size: 24px; font-size: 24px;
} }
.cloneButton {
composes: button from '~Components/Link/IconButton.css';
height: 36px;
}
.enabled { .enabled {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;

View File

@ -1,8 +1,9 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { kinds } from 'Helpers/Props'; import { icons, kinds } from 'Helpers/Props';
import Card from 'Components/Card'; import Card from 'Components/Card';
import Label from 'Components/Label'; import Label from 'Components/Label';
import IconButton from 'Components/Link/IconButton';
import ConfirmModal from 'Components/Modal/ConfirmModal'; import ConfirmModal from 'Components/Modal/ConfirmModal';
import EditIndexerModalConnector from './EditIndexerModalConnector'; import EditIndexerModalConnector from './EditIndexerModalConnector';
import styles from './Indexer.css'; import styles from './Indexer.css';
@ -47,6 +48,15 @@ class Indexer extends Component {
this.props.onConfirmDeleteIndexer(this.props.id); this.props.onConfirmDeleteIndexer(this.props.id);
} }
onCloneIndexerPress = () => {
const {
id,
onCloneIndexerPress
} = this.props;
onCloneIndexerPress(id);
}
// //
// Render // Render
@ -67,10 +77,19 @@ class Indexer extends Component {
overlayContent={true} overlayContent={true}
onPress={this.onEditIndexerPress} onPress={this.onEditIndexerPress}
> >
<div className={styles.nameContainer}>
<div className={styles.name}> <div className={styles.name}>
{name} {name}
</div> </div>
<IconButton
className={styles.cloneButton}
title="Clone Profile"
name={icons.CLONE}
onPress={this.onCloneIndexerPress}
/>
</div>
<div className={styles.enabled}> <div className={styles.enabled}>
{ {
@ -134,6 +153,7 @@ Indexer.propTypes = {
enableInteractiveSearch: PropTypes.bool.isRequired, enableInteractiveSearch: PropTypes.bool.isRequired,
supportsRss: PropTypes.bool.isRequired, supportsRss: PropTypes.bool.isRequired,
supportsSearch: PropTypes.bool.isRequired, supportsSearch: PropTypes.bool.isRequired,
onCloneIndexerPress: PropTypes.func.isRequired,
onConfirmDeleteIndexer: PropTypes.func.isRequired onConfirmDeleteIndexer: PropTypes.func.isRequired
}; };

View File

@ -31,6 +31,11 @@ class Indexers extends Component {
this.setState({ isAddIndexerModalOpen: true }); this.setState({ isAddIndexerModalOpen: true });
} }
onCloneIndexerPress = (id) => {
this.props.dispatchCloneIndexer({ id });
this.setState({ isEditIndexerModalOpen: true });
}
onAddIndexerModalClose = ({ indexerSelected = false } = {}) => { onAddIndexerModalClose = ({ indexerSelected = false } = {}) => {
this.setState({ this.setState({
isAddIndexerModalOpen: false, isAddIndexerModalOpen: false,
@ -48,6 +53,7 @@ class Indexers extends Component {
render() { render() {
const { const {
items, items,
dispatchCloneIndexer,
onConfirmDeleteIndexer, onConfirmDeleteIndexer,
...otherProps ...otherProps
} = this.props; } = this.props;
@ -70,6 +76,7 @@ class Indexers extends Component {
<Indexer <Indexer
key={item.id} key={item.id}
{...item} {...item}
onCloneIndexerPress={this.onCloneIndexerPress}
onConfirmDeleteIndexer={onConfirmDeleteIndexer} onConfirmDeleteIndexer={onConfirmDeleteIndexer}
/> />
); );
@ -108,6 +115,7 @@ Indexers.propTypes = {
isFetching: PropTypes.bool.isRequired, isFetching: PropTypes.bool.isRequired,
error: PropTypes.object, error: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired, items: PropTypes.arrayOf(PropTypes.object).isRequired,
dispatchCloneIndexer: PropTypes.func.isRequired,
onConfirmDeleteIndexer: PropTypes.func.isRequired onConfirmDeleteIndexer: PropTypes.func.isRequired
}; };

View File

@ -4,7 +4,7 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import sortByName from 'Utilities/Array/sortByName'; import sortByName from 'Utilities/Array/sortByName';
import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector'; import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector';
import { fetchIndexers, deleteIndexer } from 'Store/Actions/settingsActions'; import { fetchIndexers, deleteIndexer, cloneIndexer } from 'Store/Actions/settingsActions';
import Indexers from './Indexers'; import Indexers from './Indexers';
function createMapStateToProps() { function createMapStateToProps() {
@ -15,8 +15,9 @@ function createMapStateToProps() {
} }
const mapDispatchToProps = { const mapDispatchToProps = {
fetchIndexers, dispatchFetchIndexers: fetchIndexers,
deleteIndexer dispatchDeleteIndexer: deleteIndexer,
dispatchCloneIndexer: cloneIndexer
}; };
class IndexersConnector extends Component { class IndexersConnector extends Component {
@ -25,14 +26,14 @@ class IndexersConnector extends Component {
// Lifecycle // Lifecycle
componentDidMount() { componentDidMount() {
this.props.fetchIndexers(); this.props.dispatchFetchIndexers();
} }
// //
// Listeners // Listeners
onConfirmDeleteIndexer = (id) => { onConfirmDeleteIndexer = (id) => {
this.props.deleteIndexer({ id }); this.props.dispatchDeleteIndexer({ id });
} }
// //
@ -49,8 +50,9 @@ class IndexersConnector extends Component {
} }
IndexersConnector.propTypes = { IndexersConnector.propTypes = {
fetchIndexers: PropTypes.func.isRequired, dispatchFetchIndexers: PropTypes.func.isRequired,
deleteIndexer: PropTypes.func.isRequired dispatchDeleteIndexer: PropTypes.func.isRequired,
dispatchCloneIndexer: PropTypes.func.isRequired
}; };
export default connect(createMapStateToProps, mapDispatchToProps)(IndexersConnector); export default connect(createMapStateToProps, mapDispatchToProps)(IndexersConnector);

View File

@ -1,5 +1,7 @@
import { createAction } from 'redux-actions'; import { createAction } from 'redux-actions';
import { createThunk } from 'Store/thunks'; import { createThunk } from 'Store/thunks';
import getSectionState from 'Utilities/State/getSectionState';
import updateSectionState from 'Utilities/State/updateSectionState';
import selectProviderSchema from 'Utilities/State/selectProviderSchema'; import selectProviderSchema from 'Utilities/State/selectProviderSchema';
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer'; import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
import createSetProviderFieldValueReducer from 'Store/Actions/Creators/Reducers/createSetProviderFieldValueReducer'; import createSetProviderFieldValueReducer from 'Store/Actions/Creators/Reducers/createSetProviderFieldValueReducer';
@ -21,6 +23,7 @@ const section = 'settings.indexers';
export const FETCH_INDEXERS = 'settings/indexers/fetchIndexers'; export const FETCH_INDEXERS = 'settings/indexers/fetchIndexers';
export const FETCH_INDEXER_SCHEMA = 'settings/indexers/fetchIndexerSchema'; export const FETCH_INDEXER_SCHEMA = 'settings/indexers/fetchIndexerSchema';
export const SELECT_INDEXER_SCHEMA = 'settings/indexers/selectIndexerSchema'; export const SELECT_INDEXER_SCHEMA = 'settings/indexers/selectIndexerSchema';
export const CLONE_INDEXER = 'settings/indexers/cloneIndexer';
export const SET_INDEXER_VALUE = 'settings/indexers/setIndexerValue'; export const SET_INDEXER_VALUE = 'settings/indexers/setIndexerValue';
export const SET_INDEXER_FIELD_VALUE = 'settings/indexers/setIndexerFieldValue'; export const SET_INDEXER_FIELD_VALUE = 'settings/indexers/setIndexerFieldValue';
export const SAVE_INDEXER = 'settings/indexers/saveIndexer'; export const SAVE_INDEXER = 'settings/indexers/saveIndexer';
@ -36,6 +39,7 @@ export const TEST_ALL_INDEXERS = 'settings/indexers/testAllIndexers';
export const fetchIndexers = createThunk(FETCH_INDEXERS); export const fetchIndexers = createThunk(FETCH_INDEXERS);
export const fetchIndexerSchema = createThunk(FETCH_INDEXER_SCHEMA); export const fetchIndexerSchema = createThunk(FETCH_INDEXER_SCHEMA);
export const selectIndexerSchema = createAction(SELECT_INDEXER_SCHEMA); export const selectIndexerSchema = createAction(SELECT_INDEXER_SCHEMA);
export const cloneIndexer = createAction(CLONE_INDEXER);
export const saveIndexer = createThunk(SAVE_INDEXER); export const saveIndexer = createThunk(SAVE_INDEXER);
export const cancelSaveIndexer = createThunk(CANCEL_SAVE_INDEXER); export const cancelSaveIndexer = createThunk(CANCEL_SAVE_INDEXER);
@ -112,6 +116,30 @@ export default {
return selectedSchema; return selectedSchema;
}); });
},
[CLONE_INDEXER]: function(state, { payload }) {
const id = payload.id;
const newState = getSectionState(state, section);
const item = newState.items.find((i) => i.id === id);
// Use selectedSchema so `createProviderSettingsSelector` works properly
const selectedSchema = { ...item };
delete selectedSchema.id;
delete selectedSchema.name;
selectedSchema.fields = selectedSchema.fields.map((field) => {
return { ...field };
});
newState.selectedSchema = selectedSchema;
// Set the name in pendingChanges
newState.pendingChanges = {
name: `${item.name} - Copy`
};
return updateSectionState(state, section, newState);
} }
} }