diff --git a/frontend/package.json b/frontend/package.json index bc0112f599..0291b9784f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -67,7 +67,7 @@ "identity-obj-proxy": "^3.0.0", "immutable": "^3.8.1", "jest": "^26.6.3", - "lodash": "^4.17.15", + "lodash": "^4.17.20", "mini-css-extract-plugin": "^0.9.0", "node-fetch": "^2.6.1", "node-sass": "^4.5.3", diff --git a/frontend/src/component/common/common.module.scss b/frontend/src/component/common/common.module.scss index 36b0466ca5..62d9f0b801 100644 --- a/frontend/src/component/common/common.module.scss +++ b/frontend/src/component/common/common.module.scss @@ -8,6 +8,10 @@ width: 100%; } +.sectionPadding { + padding: 0 16px; +} + .horisontalScroll { overflow-x: scroll; -webkit-overflow-scrolling: touch; diff --git a/frontend/src/component/common/index.js b/frontend/src/component/common/index.js index 58d6dd6ab4..e603c4c34a 100644 --- a/frontend/src/component/common/index.js +++ b/frontend/src/component/common/index.js @@ -34,9 +34,9 @@ export const HeaderTitle = ({ title, actions, subtitle }) => (
diff --git a/frontend/src/component/common/util.js b/frontend/src/component/common/util.js index b395f4e7a6..78f024d2e1 100644 --- a/frontend/src/component/common/util.js +++ b/frontend/src/component/common/util.js @@ -104,3 +104,5 @@ export const modalStyles = { transform: 'translate(-50%, -50%)', }, }; + +export const updateIndexInArray = (array, index, newValue) => array.map((v, i) => (i === index ? newValue : v)); diff --git a/frontend/src/component/feature/create/__tests__/__snapshots__/add-feature-component-test.jsx.snap b/frontend/src/component/feature/create/__tests__/__snapshots__/add-feature-component-test.jsx.snap index 94d8a69403..1e7d6ede48 100644 --- a/frontend/src/component/feature/create/__tests__/__snapshots__/add-feature-component-test.jsx.snap +++ b/frontend/src/component/feature/create/__tests__/__snapshots__/add-feature-component-test.jsx.snap @@ -28,75 +28,72 @@ exports[`render the create feature page 1`] = ` col={4} > - - - Disabled - -
+
+ + Disabled + feature toggle + +
+
+ +
setValue('name', trim(v.target.value))} /> - + setValue('type', v.target.value)} /> - - { - setValue('enabled', !input.enabled); - }} - > - {input.enabled ? 'Enabled' : 'Disabled'} - - -
+
setValue('project', v.target.value)} />
-
+
setValue('description', v.target.value)} />
+
+ { + setValue('enabled', !input.enabled); + }} + > + {input.enabled ? 'Enabled' : 'Disabled'} feature toggle + +
+
+ setValue('strategies', s)} + editable + /> +
diff --git a/frontend/src/component/feature/create/add-feature-container.jsx b/frontend/src/component/feature/create/add-feature-container.jsx index 7330ec6d94..0204dee4b6 100644 --- a/frontend/src/component/feature/create/add-feature-container.jsx +++ b/frontend/src/component/feature/create/add-feature-container.jsx @@ -61,7 +61,10 @@ class WrapperComponent extends Component { evt.preventDefault(); const { createFeatureToggles, history } = this.props; const { featureToggle } = this.state; - featureToggle.strategies = [defaultStrategy]; + + if (featureToggle.strategies < 1) { + featureToggle.strategies = [defaultStrategy]; + } createFeatureToggles(featureToggle).then(() => history.push(`/features/strategies/${featureToggle.name}`)); }; @@ -78,6 +81,7 @@ class WrapperComponent extends Component { onCancel={this.onCancel} validateName={this.validateName} setValue={this.setValue} + setStrategies={this.setStrategies} input={this.state.featureToggle} errors={this.state.errors} /> diff --git a/frontend/src/component/feature/strategy/input-list.jsx b/frontend/src/component/feature/strategy/input-list.jsx index 6bb6b3176a..7da5065ea1 100644 --- a/frontend/src/component/feature/strategy/input-list.jsx +++ b/frontend/src/component/feature/strategy/input-list.jsx @@ -31,7 +31,7 @@ export default class InputList extends Component { const newValues = value.split(/,\s*/).filter(a => !list.includes(a)); if (newValues.length > 0) { const newList = list.concat(newValues).filter(a => a); - setConfig(name, newList.join(','), true); + setConfig(name, newList.join(',')); } this.textInput.inputRef.value = ''; } @@ -40,7 +40,7 @@ export default class InputList extends Component { onClose(index) { const { name, list, setConfig } = this.props; list[index] = null; - setConfig(name, list.length === 1 ? '' : list.filter(Boolean).join(','), true); + setConfig(name, list.length === 1 ? '' : list.filter(Boolean).join(',')); } render() { diff --git a/frontend/src/component/feature/strategy/loading-strategy.jsx b/frontend/src/component/feature/strategy/loading-strategy.jsx new file mode 100644 index 0000000000..107793d160 --- /dev/null +++ b/frontend/src/component/feature/strategy/loading-strategy.jsx @@ -0,0 +1,9 @@ +import React from 'react'; + +export default function LoadingStrategy() { + return ( +
+

Loading definition...

+
+ ); +} diff --git a/frontend/src/component/feature/strategy/strategies-add.jsx b/frontend/src/component/feature/strategy/strategies-add.jsx index 30edc9e967..0836707da1 100644 --- a/frontend/src/component/feature/strategy/strategies-add.jsx +++ b/frontend/src/component/feature/strategy/strategies-add.jsx @@ -21,6 +21,7 @@ class AddStrategy extends React.Component { strategies: PropTypes.array.isRequired, addStrategy: PropTypes.func, featureToggleName: PropTypes.string.isRequired, + disabled: PropTypes.bool, }; addStrategy(strategyName) { @@ -45,10 +46,11 @@ class AddStrategy extends React.Component { render() { const menuStyle = { - maxHeight: '300px', + maxHeight: '400px', overflowY: 'auto', backgroundColor: 'rgb(247, 248, 255)', }; + const { disabled = false } = this.props; return (
diff --git a/frontend/src/component/feature/strategy/strategies-list-add-component.jsx b/frontend/src/component/feature/strategy/strategies-list-add-component.jsx new file mode 100644 index 0000000000..6838b38380 --- /dev/null +++ b/frontend/src/component/feature/strategy/strategies-list-add-component.jsx @@ -0,0 +1,96 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; +import arrayMove from 'array-move'; + +import ConfigureStrategy from './strategy-configure-container'; +import AddStrategy from './strategies-add'; +import { HeaderTitle } from '../../common'; +import { updateIndexInArray } from '../../common/util'; +import styles from './strategy.module.scss'; + +const StrategiesList = props => { + const updateStrategy = index => strategy => { + const newStrategy = { ...strategy }; + const newStrategies = updateIndexInArray(props.configuredStrategies, index, newStrategy); + props.saveStrategies(newStrategies); + }; + + const saveStrategy = () => () => { + // not needed for create flow + }; + + const addStrategy = strategy => { + const strategies = [...props.configuredStrategies]; + strategies.push({ ...strategy }); + props.saveStrategies(strategies); + }; + + const moveStrategy = async (index, toIndex) => { + const strategies = arrayMove(props.configuredStrategies, index, toIndex); + await props.saveStrategies(strategies); + }; + + const removeStrategy = index => async () => { + props.saveStrategies(props.configuredStrategies.filter((_, i) => i !== index)); + }; + + const { strategies, configuredStrategies, featureToggleName } = props; + + const hasName = featureToggleName && featureToggleName.length > 1; + + const blocks = configuredStrategies.map((strategy, i) => ( + s.name === strategy.name)} + editable + movable + /> + )); + return ( + +
+ + } + /> +
+ {blocks.length > 0 ? ( + blocks + ) : ( +

+ An activation strategy allows you to control how a feature toggle is enabled in your + applications. If you do not specify any activation strategies you will get the "default" + strategy. +

+ )} +
+
+
+ ); +}; + +StrategiesList.propTypes = { + strategies: PropTypes.array.isRequired, + configuredStrategies: PropTypes.array.isRequired, + featureToggleName: PropTypes.string.isRequired, + saveStrategies: PropTypes.func, +}; + +export default StrategiesList; diff --git a/frontend/src/component/feature/strategy/strategies-list-add-container.jsx b/frontend/src/component/feature/strategy/strategies-list-add-container.jsx new file mode 100644 index 0000000000..8a89139fb4 --- /dev/null +++ b/frontend/src/component/feature/strategy/strategies-list-add-container.jsx @@ -0,0 +1,8 @@ +import { connect } from 'react-redux'; +import StrategiesList from './strategies-list-add-component'; + +const mapStateToProps = state => ({ + strategies: state.strategies.get('list').toArray(), +}); + +export default connect(mapStateToProps, undefined)(StrategiesList); diff --git a/frontend/src/component/feature/strategy/strategies-list-component.jsx b/frontend/src/component/feature/strategy/strategies-list-component.jsx new file mode 100644 index 0000000000..5eb4285569 --- /dev/null +++ b/frontend/src/component/feature/strategy/strategies-list-component.jsx @@ -0,0 +1,162 @@ +import React, { useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; + +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; +import { cloneDeep } from 'lodash'; +import arrayMove from 'array-move'; +import { Button, Icon } from 'react-mdl'; + +import ConfigureStrategy from './strategy-configure-container'; +import AddStrategy from './strategies-add'; +import { HeaderTitle } from '../../common'; +import { updateIndexInArray } from '../../common/util'; +import styles from './strategy.module.scss'; + +const cleanStrategy = strategy => ({ + name: strategy.name, + parameters: cloneDeep(strategy.parameters), + constraints: cloneDeep(strategy.constraints || []), +}); + +const StrategiesList = props => { + const [editableStrategies, updateEditableStrategies] = useState(cloneDeep(props.configuredStrategies)); + const dirty = editableStrategies.some(p => p.dirty); + + useEffect(() => { + if (!dirty) { + updateEditableStrategies(cloneDeep(props.configuredStrategies)); + } + }, [props.configuredStrategies]); + + const updateStrategy = index => (strategy, dirty = true) => { + const newStrategy = { ...strategy, dirty }; + const newStrategies = updateIndexInArray(editableStrategies, index, newStrategy); + updateEditableStrategies(newStrategies); + }; + + const saveStrategy = index => async () => { + const strategies = [...props.configuredStrategies]; + const strategy = editableStrategies[index]; + const cleanedStrategy = cleanStrategy(strategy); + + if (strategy.new) { + strategies.push(cleanedStrategy); + } else { + strategies[index] = cleanedStrategy; + } + + // store in server + await props.saveStrategies(strategies); + + // update local state + updateStrategy(index)(cleanedStrategy, false); + }; + + const addStrategy = strategy => { + const strategies = [...editableStrategies]; + strategies.push({ ...strategy, dirty: true, new: true }); + updateEditableStrategies(strategies); + }; + + const moveStrategy = async (index, toIndex) => { + if (!dirty) { + // console.log(`move strategy from ${index} to ${toIndex}`); + const strategies = arrayMove(editableStrategies, index, toIndex); + await props.saveStrategies(strategies); + updateEditableStrategies(strategies); + } + }; + + const removeStrategy = index => async () => { + // eslint-disable-next-line no-alert + if (window.confirm('Are you sure you want to remove this activation strategy?')) { + const strategy = editableStrategies[index]; + if (!strategy.new) { + await props.saveStrategies(props.configuredStrategies.filter((_, i) => i !== index)); + } + + updateEditableStrategies(editableStrategies.filter((_, i) => i !== index)); + } + }; + + const clearAll = () => { + updateEditableStrategies(cloneDeep(props.configuredStrategies)); + }; + + const saveAll = async () => { + const cleanedStrategies = editableStrategies.map(cleanStrategy); + await props.saveStrategies(cleanedStrategies); + updateEditableStrategies(cleanedStrategies); + }; + + const { strategies, configuredStrategies, featureToggleName, editable } = props; + + if (!configuredStrategies || configuredStrategies.length === 0) { + return ( +

+ No activation strategies selected. +

+ ); + } + + const resolveStrategyDefinition = strategyName => { + if (!strategies || strategies.length === 0) { + return { name: 'Loading' }; + } + return strategies.find(s => s.name === strategyName); + }; + + const blocks = editableStrategies.map((strategy, i) => ( + + )); + return ( + + {editable && ( + + } + /> + )} +
{blocks}
+
+ +   + +
+
+ ); +}; + +StrategiesList.propTypes = { + strategies: PropTypes.array.isRequired, + configuredStrategies: PropTypes.array.isRequired, + featureToggleName: PropTypes.string.isRequired, + saveStrategies: PropTypes.func, + editable: PropTypes.bool, +}; + +export default StrategiesList; diff --git a/frontend/src/component/feature/strategy/strategies-list-container.jsx b/frontend/src/component/feature/strategy/strategies-list-container.jsx new file mode 100644 index 0000000000..3dbb754d6a --- /dev/null +++ b/frontend/src/component/feature/strategy/strategies-list-container.jsx @@ -0,0 +1,8 @@ +import { connect } from 'react-redux'; +import StrategiesList from './strategies-list-component'; + +const mapStateToProps = state => ({ + strategies: state.strategies.get('list').toArray(), +}); + +export default connect(mapStateToProps, undefined)(StrategiesList); diff --git a/frontend/src/component/feature/strategy/strategies-list.jsx b/frontend/src/component/feature/strategy/strategies-list.jsx deleted file mode 100644 index 64ecf2b0b8..0000000000 --- a/frontend/src/component/feature/strategy/strategies-list.jsx +++ /dev/null @@ -1,76 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import ConfigureStrategy from './strategy-configure-container'; -import { DndProvider } from 'react-dnd'; -import { HTML5Backend } from 'react-dnd-html5-backend'; - -const randomKeys = length => Array.from({ length }, () => Math.random()); - -class StrategiesList extends React.Component { - static propTypes = { - strategies: PropTypes.array.isRequired, - configuredStrategies: PropTypes.array.isRequired, - featureToggleName: PropTypes.string.isRequired, - updateStrategy: PropTypes.func, - removeStrategy: PropTypes.func, - moveStrategy: PropTypes.func, - editable: PropTypes.bool, - }; - - constructor(props) { - super(); - // temporal hack, until strategies get UIDs - this.state = { keys: randomKeys(props.configuredStrategies.length) }; - } - - moveStrategy = async (index, toIndex) => { - await this.props.moveStrategy(index, toIndex); - this.setState({ keys: randomKeys(this.props.configuredStrategies.length) }); - }; - removeStrategy = async index => { - await this.props.removeStrategy(index); - this.setState({ keys: randomKeys(this.props.configuredStrategies.length) }); - }; - - componentDidUpdate(props) { - const { keys } = this.state; - if (keys.length < props.configuredStrategies.length) { - // eslint-disable-next-line react/no-did-update-set-state - this.setState({ keys: randomKeys(props.configuredStrategies.length) }); - } - } - - render() { - const { strategies, configuredStrategies, updateStrategy, featureToggleName, editable } = this.props; - - const { keys } = this.state; - if (!configuredStrategies || configuredStrategies.length === 0) { - return ( -

- No activation strategies selected. -

- ); - } - - const blocks = configuredStrategies.map((strategy, i) => ( - s.name === strategy.name)} - editable={editable} - /> - )); - return ( - -
{blocks}
-
- ); - } -} - -export default StrategiesList; diff --git a/frontend/src/component/feature/strategy/strategy-configure-component.jsx b/frontend/src/component/feature/strategy/strategy-configure-component.jsx index 8775d46a91..fcb8eb11fd 100644 --- a/frontend/src/component/feature/strategy/strategy-configure-component.jsx +++ b/frontend/src/component/feature/strategy/strategy-configure-component.jsx @@ -8,6 +8,7 @@ import DefaultStrategy from './default-strategy'; import GeneralStrategy from './general-strategy'; import UserWithIdStrategy from './user-with-id-strategy'; import UnknownStrategy from './unknown-strategy'; +import LoadingStrategy from './loading-strategy'; import styles from './strategy.module.scss'; @@ -18,61 +19,35 @@ export default class StrategyConfigureComponent extends React.Component { index: PropTypes.number.isRequired, strategyDefinition: PropTypes.object, updateStrategy: PropTypes.func, + saveStrategy: PropTypes.func, removeStrategy: PropTypes.func, moveStrategy: PropTypes.func, isDragging: PropTypes.bool.isRequired, hovered: PropTypes.bool, + movable: PropTypes.bool, connectDragPreview: PropTypes.func.isRequired, connectDragSource: PropTypes.func.isRequired, connectDropTarget: PropTypes.func.isRequired, editable: PropTypes.bool, }; - constructor(props) { - super(); - this.state = { - constraints: props.strategy.constraints ? [...props.strategy.constraints] : [], - parameters: { ...props.strategy.parameters }, - edit: false, - dirty: false, - index: props.index, - }; - } - updateParameters = parameters => { - const { constraints } = this.state; - const updatedStrategy = Object.assign({}, this.props.strategy, { - parameters, - constraints, - }); + const { strategy } = this.props; + const updatedStrategy = { ...strategy, parameters }; this.props.updateStrategy(updatedStrategy); }; updateConstraints = constraints => { - this.setState({ constraints, dirty: true }); + const { strategy } = this.props; + const updatedStrategy = { ...strategy, constraints }; + this.props.updateStrategy(updatedStrategy); }; - updateParameter = async (field, value, forceUp = false) => { - const { parameters } = this.state; + updateParameter = async (field, value) => { + const { strategy } = this.props; + const parameters = { ...strategy.parameters }; parameters[field] = value; - if (forceUp) { - await this.updateParameters(parameters); - this.setState({ parameters, dirty: false }); - } else { - this.setState({ parameters, dirty: true }); - } - }; - - onSave = evt => { - evt.preventDefault(); - const { parameters } = this.state; this.updateParameters(parameters); - this.setState({ edit: false, dirty: false }); - }; - - handleRemove = evt => { - evt.preventDefault(); - this.props.removeStrategy(); }; resolveInputType() { @@ -81,6 +56,8 @@ export default class StrategyConfigureComponent extends React.Component { return UnknownStrategy; } switch (strategyDefinition.name) { + case 'Loading': + return LoadingStrategy; case 'default': return DefaultStrategy; case 'flexibleRollout': @@ -93,7 +70,6 @@ export default class StrategyConfigureComponent extends React.Component { } render() { - const { dirty, parameters } = this.state; const { isDragging, hovered, @@ -104,11 +80,14 @@ export default class StrategyConfigureComponent extends React.Component { strategyDefinition, strategy, index, + removeStrategy, + saveStrategy, + movable, } = this.props; - const { name } = strategy; + const { name, dirty, parameters } = strategy; - const description = strategyDefinition ? strategyDefinition.description : 'Uknown'; + const description = strategyDefinition ? strategyDefinition.description : 'Unknown'; const InputType = this.resolveInputType(name); const cardClasses = [styles.card]; @@ -143,7 +122,7 @@ export default class StrategyConfigureComponent extends React.Component { editable={editable} />
diff --git a/frontend/src/component/feature/strategy/strategy-input-props.js b/frontend/src/component/feature/strategy/strategy-input-props.js index ad80363906..b36515efdc 100644 --- a/frontend/src/component/feature/strategy/strategy-input-props.js +++ b/frontend/src/component/feature/strategy/strategy-input-props.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; export default { strategyDefinition: PropTypes.shape({ + name: PropTypes.string, parameters: PropTypes.array, }).isRequired, parameters: PropTypes.object.isRequired, diff --git a/frontend/src/component/feature/strategy/strategy.module.scss b/frontend/src/component/feature/strategy/strategy.module.scss index b8a7cb8fcf..8f343a5d29 100644 --- a/frontend/src/component/feature/strategy/strategy.module.scss +++ b/frontend/src/component/feature/strategy/strategy.module.scss @@ -1,7 +1,7 @@ .item { flex: 1; min-width: 400px; - max-width: 100%; + max-width: 537px; margin: 5px 0 5px 5px; position: relative; z-index: 1; @@ -85,15 +85,25 @@ cursor: pointer; display: inline-block; vertical-align: bottom; + + &.disabled { + cursor: default; + color: silver; + } } - -.paddingDesktop { +.strategyList { + display: flex; + flex-wrap: wrap; padding: 10px; } +.strategyListAdd { + background-color: #f9f9f9; +} + @media (max-width: 500px) { - .paddingDesktop { + .strategyList { padding: 0; } } diff --git a/frontend/src/component/feature/strategy/unknown-strategy.jsx b/frontend/src/component/feature/strategy/unknown-strategy.jsx index 4373b642bd..47ba46752a 100644 --- a/frontend/src/component/feature/strategy/unknown-strategy.jsx +++ b/frontend/src/component/feature/strategy/unknown-strategy.jsx @@ -1,9 +1,9 @@ import React from 'react'; -import strategyInputProps from './strategy-input-props'; +import PropTypes from 'prop-types'; import { Link } from 'react-router-dom'; -export default function UknownStrategy({ strategy }) { +export default function UnknownStrategy({ strategy }) { const { name } = strategy; return (
@@ -13,4 +13,8 @@ export default function UknownStrategy({ strategy }) { ); } -UknownStrategy.propTypes = strategyInputProps; +UnknownStrategy.propTypes = { + strategy: PropTypes.shape({ + name: PropTypes.string, + }).isRequired, +}; diff --git a/frontend/src/component/feature/view/__tests__/__snapshots__/update-strategies-component-test.jsx.snap b/frontend/src/component/feature/view/__tests__/__snapshots__/update-strategies-component-test.jsx.snap index 9b0de07dff..b3bacd516f 100644 --- a/frontend/src/component/feature/view/__tests__/__snapshots__/update-strategies-component-test.jsx.snap +++ b/frontend/src/component/feature/view/__tests__/__snapshots__/update-strategies-component-test.jsx.snap @@ -1,3 +1,27 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`render the create feature page 1`] = `""`; +exports[`render the create feature page 1`] = ` +
+ +
+`; diff --git a/frontend/src/component/feature/view/update-strategies-component.jsx b/frontend/src/component/feature/view/update-strategies-component.jsx index d364af3985..3ae49d067d 100644 --- a/frontend/src/component/feature/view/update-strategies-component.jsx +++ b/frontend/src/component/feature/view/update-strategies-component.jsx @@ -1,19 +1,14 @@ import React from 'react'; import PropTypes from 'prop-types'; -import StrategiesList from '../strategy/strategies-list'; -import AddStrategy from '../strategy/strategies-add'; -import { HeaderTitle } from '../../common'; - -import styles from '../strategy/strategy.module.scss'; +import StrategiesList from '../strategy/strategies-list-container'; +// TODO: do we still need this wrapper? function UpdateStrategiesComponent(props) { - const { editable, configuredStrategies, strategies } = props; + const { configuredStrategies } = props; if (!configuredStrategies || configuredStrategies.length === 0) return null; - if (!strategies || strategies.length === 0) return null; return ( -
- {editable && } />} +
); @@ -23,10 +18,6 @@ UpdateStrategiesComponent.propTypes = { featureToggleName: PropTypes.string.isRequired, strategies: PropTypes.array, configuredStrategies: PropTypes.array.isRequired, - addStrategy: PropTypes.func.isRequired, - removeStrategy: PropTypes.func.isRequired, - moveStrategy: PropTypes.func.isRequired, - updateStrategy: PropTypes.func.isRequired, editable: PropTypes.bool, }; diff --git a/frontend/src/component/feature/view/update-strategies-container.jsx b/frontend/src/component/feature/view/update-strategies-container.jsx index 3e4fc80c6f..1b63833a90 100644 --- a/frontend/src/component/feature/view/update-strategies-container.jsx +++ b/frontend/src/component/feature/view/update-strategies-container.jsx @@ -1,6 +1,5 @@ /* eslint-disable no-console */ import { connect } from 'react-redux'; -import arrayMove from 'array-move'; import { requestUpdateFeatureToggleStrategies } from '../../../store/feature-toggle/actions'; import UpdateStrategiesComponent from './update-strategies-component'; @@ -8,39 +7,11 @@ import UpdateStrategiesComponent from './update-strategies-component'; const mapStateToProps = (state, ownProps) => ({ featureToggleName: ownProps.featureToggle.name, configuredStrategies: ownProps.featureToggle.strategies, - strategies: state.strategies.get('list').toArray(), }); const mapDispatchToProps = (dispatch, ownProps) => ({ - addStrategy: s => { - console.log(`add ${s}`); + saveStrategies: strategies => { const featureToggle = ownProps.featureToggle; - const strategies = featureToggle.strategies.concat(s); - return requestUpdateFeatureToggleStrategies(featureToggle, strategies)(dispatch); - }, - - removeStrategy: index => { - console.log(`remove ${index}`); - const featureToggle = ownProps.featureToggle; - const strategies = featureToggle.strategies.filter((_, i) => i !== index); - return requestUpdateFeatureToggleStrategies(featureToggle, strategies)(dispatch); - }, - - moveStrategy: (index, toIndex) => { - // methods.moveItem('strategies', index, toIndex); - console.log(`move strategy from ${index} to ${toIndex}`); - console.log(ownProps.featureToggle); - const featureToggle = ownProps.featureToggle; - const strategies = arrayMove(featureToggle.strategies, index, toIndex); - return requestUpdateFeatureToggleStrategies(featureToggle, strategies)(dispatch); - }, - - updateStrategy: (index, s) => { - // methods.updateInList('strategies', index, n); - console.log(`update strtegy at index ${index} with ${JSON.stringify(s)}`); - const featureToggle = ownProps.featureToggle; - const strategies = featureToggle.strategies.concat(); - strategies[index] = s; return requestUpdateFeatureToggleStrategies(featureToggle, strategies)(dispatch); }, }); diff --git a/frontend/src/component/strategies/__tests__/__snapshots__/list-component-test.jsx.snap b/frontend/src/component/strategies/__tests__/__snapshots__/list-component-test.jsx.snap index 6d2d7bb21a..fbfcb06972 100644 --- a/frontend/src/component/strategies/__tests__/__snapshots__/list-component-test.jsx.snap +++ b/frontend/src/component/strategies/__tests__/__snapshots__/list-component-test.jsx.snap @@ -13,10 +13,10 @@ exports[`renders correctly with one strategy 1`] = `
@@ -104,10 +104,10 @@ exports[`renders correctly with one strategy without permissions 1`] = `
diff --git a/frontend/src/component/strategies/__tests__/__snapshots__/strategy-details-component-test.jsx.snap b/frontend/src/component/strategies/__tests__/__snapshots__/strategy-details-component-test.jsx.snap index a7fee260d9..2dd87b1e64 100644 --- a/frontend/src/component/strategies/__tests__/__snapshots__/strategy-details-component-test.jsx.snap +++ b/frontend/src/component/strategies/__tests__/__snapshots__/strategy-details-component-test.jsx.snap @@ -10,10 +10,10 @@ exports[`renders correctly with one strategy 1`] = `
diff --git a/frontend/src/component/tag-types/__tests__/__snapshots__/tag-type-list-component-test.js.snap b/frontend/src/component/tag-types/__tests__/__snapshots__/tag-type-list-component-test.js.snap index 6fc6f78ffb..77fc364546 100644 --- a/frontend/src/component/tag-types/__tests__/__snapshots__/tag-type-list-component-test.js.snap +++ b/frontend/src/component/tag-types/__tests__/__snapshots__/tag-type-list-component-test.js.snap @@ -13,10 +13,10 @@ exports[`renders a list with elements correctly 1`] = `
@@ -92,10 +92,10 @@ exports[`renders an empty list correctly 1`] = `
diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 06662296e6..7c63a50cd2 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -6533,7 +6533,7 @@ lodash@^4.0.0, lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14 resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== -lodash@^4.17.19: +lodash@^4.17.19, lodash@^4.17.20: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==