mirror of
https://github.com/Unleash/unleash.git
synced 2025-03-18 00:19:49 +01:00
feat: add support for toggle type
This commit is contained in:
parent
60705d3993
commit
6395568d55
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const Select = ({ name, value, label, options, style, onChange }) => {
|
||||
const Select = ({ name, value, label, options, style, onChange, filled }) => {
|
||||
const wrapper = Object.assign({ width: 'auto' }, style);
|
||||
return (
|
||||
<div
|
||||
@ -13,10 +13,10 @@ const Select = ({ name, value, label, options, style, onChange }) => {
|
||||
name={name}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
style={{ width: 'auto' }}
|
||||
style={{ width: 'auto', background: filled ? '#f5f5f5' : 'none' }}
|
||||
>
|
||||
{options.map(o => (
|
||||
<option key={o.key} value={o.key}>
|
||||
<option key={o.key} value={o.key} title={o.title}>
|
||||
{o.label}
|
||||
</option>
|
||||
))}
|
||||
|
@ -47,10 +47,8 @@ exports[`renders correctly with one feature 1`] = `
|
||||
className="listItemStrategies hideLt920"
|
||||
>
|
||||
<react-mdl-Chip
|
||||
className="strategyChip"
|
||||
>
|
||||
gradualRolloutRandom
|
||||
</react-mdl-Chip>
|
||||
className="mdl-color--blue-grey-100"
|
||||
/>
|
||||
</span>
|
||||
<span />
|
||||
</react-mdl-ListItem>
|
||||
@ -102,10 +100,8 @@ exports[`renders correctly with one feature without permission 1`] = `
|
||||
className="listItemStrategies hideLt920"
|
||||
>
|
||||
<react-mdl-Chip
|
||||
className="strategyChip"
|
||||
>
|
||||
gradualRolloutRandom
|
||||
</react-mdl-Chip>
|
||||
className="mdl-color--blue-grey-100"
|
||||
/>
|
||||
</span>
|
||||
<span />
|
||||
</react-mdl-ListItem>
|
||||
|
@ -124,6 +124,12 @@ exports[`renders correctly with one feature 1`] = `
|
||||
>
|
||||
Name
|
||||
</react-mdl-MenuItem>
|
||||
<react-mdl-MenuItem
|
||||
data-target="type"
|
||||
disabled={false}
|
||||
>
|
||||
Type
|
||||
</react-mdl-MenuItem>
|
||||
<react-mdl-MenuItem
|
||||
data-target="enabled"
|
||||
disabled={false}
|
||||
@ -283,6 +289,12 @@ exports[`renders correctly with one feature without permissions 1`] = `
|
||||
>
|
||||
Name
|
||||
</react-mdl-MenuItem>
|
||||
<react-mdl-MenuItem
|
||||
data-target="type"
|
||||
disabled={false}
|
||||
>
|
||||
Type
|
||||
</react-mdl-MenuItem>
|
||||
<react-mdl-MenuItem
|
||||
data-target="enabled"
|
||||
disabled={false}
|
||||
|
@ -22,14 +22,29 @@ exports[`renders correctly with one feature 1`] = `
|
||||
|
||||
</react-mdl-CardTitle>
|
||||
<react-mdl-CardText>
|
||||
another's description
|
||||
|
||||
<a
|
||||
href="#edit"
|
||||
onClick={[Function]}
|
||||
>
|
||||
edit
|
||||
</a>
|
||||
<div>
|
||||
another's description
|
||||
|
||||
<a
|
||||
href="#edit"
|
||||
onClick={[Function]}
|
||||
>
|
||||
edit
|
||||
</a>
|
||||
</div>
|
||||
</react-mdl-CardText>
|
||||
<react-mdl-CardText
|
||||
style={
|
||||
Object {
|
||||
"paddingTop": 0,
|
||||
}
|
||||
}
|
||||
>
|
||||
<FeatureTypeSelect
|
||||
filled={true}
|
||||
onChange={[Function]}
|
||||
value="release"
|
||||
/>
|
||||
</react-mdl-CardText>
|
||||
<react-mdl-CardActions
|
||||
border={true}
|
||||
@ -137,6 +152,7 @@ exports[`renders correctly with one feature 1`] = `
|
||||
},
|
||||
},
|
||||
],
|
||||
"type": "release",
|
||||
}
|
||||
}
|
||||
features={
|
||||
@ -154,6 +170,7 @@ exports[`renders correctly with one feature 1`] = `
|
||||
},
|
||||
},
|
||||
],
|
||||
"type": "release",
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -10,12 +10,14 @@ jest.mock('../form/form-update-feature-container', () => ({
|
||||
__esModule: true,
|
||||
default: 'UpdateFeatureToggleComponent',
|
||||
}));
|
||||
jest.mock('../form/feature-type-select-container', () => 'FeatureTypeSelect');
|
||||
|
||||
test('renders correctly with one feature', () => {
|
||||
const feature = {
|
||||
name: 'Another',
|
||||
description: "another's description",
|
||||
enabled: false,
|
||||
type: 'release',
|
||||
strategies: [
|
||||
{
|
||||
name: 'gradualRolloutRandom',
|
||||
|
@ -17,7 +17,7 @@ const Feature = ({
|
||||
revive,
|
||||
hasPermission,
|
||||
}) => {
|
||||
const { name, description, enabled, strategies } = feature;
|
||||
const { name, description, enabled, type } = feature;
|
||||
const { showLastHour = false } = settings;
|
||||
const isStale = showLastHour ? metricsLastHour.isFallback : metricsLastMinute.isFallback;
|
||||
const percent =
|
||||
@ -25,17 +25,7 @@ const Feature = ({
|
||||
(showLastHour
|
||||
? calc(metricsLastHour.yes, metricsLastHour.yes + metricsLastHour.no, 0)
|
||||
: calc(metricsLastMinute.yes, metricsLastMinute.yes + metricsLastMinute.no, 0));
|
||||
|
||||
const strategiesToShow = Math.min(strategies.length, 3);
|
||||
const remainingStrategies = strategies.length - strategiesToShow;
|
||||
const strategyChips =
|
||||
strategies &&
|
||||
strategies.slice(0, strategiesToShow).map((s, i) => (
|
||||
<Chip className={styles.strategyChip} key={i}>
|
||||
{s.name}
|
||||
</Chip>
|
||||
));
|
||||
const summaryChip = remainingStrategies > 0 && <Chip className={styles.strategyChip}>+{remainingStrategies}</Chip>;
|
||||
const typeChip = <Chip className="mdl-color--blue-grey-100">{type}</Chip>;
|
||||
const featureUrl = toggleFeature === undefined ? `/archive/strategies/${name}` : `/features/strategies/${name}`;
|
||||
return (
|
||||
<ListItem twoLine>
|
||||
@ -61,10 +51,7 @@ const Feature = ({
|
||||
<span className={['mdl-list__item-sub-title', commonStyles.truncate].join(' ')}>{description}</span>
|
||||
</Link>
|
||||
</span>
|
||||
<span className={[styles.listItemStrategies, commonStyles.hideLt920].join(' ')}>
|
||||
{strategyChips}
|
||||
{summaryChip}
|
||||
</span>
|
||||
<span className={[styles.listItemStrategies, commonStyles.hideLt920].join(' ')}>{typeChip}</span>
|
||||
{revive && hasPermission(UPDATE_FEATURE) ? (
|
||||
<ListItemAction onClick={() => revive(feature.name)}>
|
||||
<Icon name="undo" />
|
||||
|
@ -33,3 +33,8 @@
|
||||
.strategyChip {
|
||||
margin-left: 8px !important;
|
||||
}
|
||||
|
||||
.typeChip {
|
||||
margin-left: 8px !important;
|
||||
background: #d3c1ff;
|
||||
}
|
@ -23,21 +23,54 @@ exports[`render the create feature page 1`] = `
|
||||
<form
|
||||
onSubmit={[MockFunction]}
|
||||
>
|
||||
<react-mdl-Grid>
|
||||
<react-mdl-Cell
|
||||
col={4}
|
||||
>
|
||||
<react-mdl-Textfield
|
||||
floatingLabel={true}
|
||||
label="Name"
|
||||
name="name"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"width": "100%",
|
||||
}
|
||||
}
|
||||
value="feature"
|
||||
/>
|
||||
</react-mdl-Cell>
|
||||
<react-mdl-Cell
|
||||
col={2}
|
||||
>
|
||||
<Connect(FeatureTypeSelectComponent)
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</react-mdl-Cell>
|
||||
<react-mdl-Cell
|
||||
col={2}
|
||||
style={
|
||||
Object {
|
||||
"paddingTop": "14px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<react-mdl-Switch
|
||||
checked={false}
|
||||
onChange={[Function]}
|
||||
>
|
||||
Disabled
|
||||
</react-mdl-Switch>
|
||||
</react-mdl-Cell>
|
||||
</react-mdl-Grid>
|
||||
<section
|
||||
style={
|
||||
Object {
|
||||
"padding": "16px",
|
||||
"padding": "0 16px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<react-mdl-Textfield
|
||||
floatingLabel={true}
|
||||
label="Name"
|
||||
name="name"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
value="feature"
|
||||
/>
|
||||
<react-mdl-Textfield
|
||||
floatingLabel={true}
|
||||
label="Description"
|
||||
@ -50,17 +83,6 @@ exports[`render the create feature page 1`] = `
|
||||
}
|
||||
value="Description"
|
||||
/>
|
||||
<div>
|
||||
<br />
|
||||
<react-mdl-Switch
|
||||
checked={false}
|
||||
onChange={[Function]}
|
||||
>
|
||||
Enabled
|
||||
</react-mdl-Switch>
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
<StrategiesSection
|
||||
addStrategy={[MockFunction]}
|
||||
configuredStrategies={Array []}
|
||||
|
@ -0,0 +1,33 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import MySelect from '../../common/select';
|
||||
|
||||
class FeatureTypeSelectComponent extends Component {
|
||||
componentDidMount() {
|
||||
if (this.props.fetchFeatureTypes) {
|
||||
this.props.fetchFeatureTypes();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { value, types, onChange, filled } = this.props;
|
||||
|
||||
const options = types.map(t => ({ key: t.id, label: t.name, title: t.description }));
|
||||
|
||||
if (!options.find(o => o.key === value)) {
|
||||
options.push({ key: value, label: value });
|
||||
}
|
||||
|
||||
return <MySelect label="Toggle type" options={options} value={value} onChange={onChange} filled={filled} />;
|
||||
}
|
||||
}
|
||||
|
||||
FeatureTypeSelectComponent.propTypes = {
|
||||
value: PropTypes.string,
|
||||
filled: PropTypes.bool,
|
||||
types: PropTypes.array.isRequired,
|
||||
fetchFeatureTypes: PropTypes.func,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default FeatureTypeSelectComponent;
|
@ -0,0 +1,11 @@
|
||||
import { connect } from 'react-redux';
|
||||
import FeatureTypeSelectComponent from './feature-type-select-component';
|
||||
import { fetchFeatureTypes } from './../../../store/feature-type/actions';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
types: state.featureTypes.toJS(),
|
||||
});
|
||||
|
||||
const FormAddContainer = connect(mapStateToProps, { fetchFeatureTypes })(FeatureTypeSelectComponent);
|
||||
|
||||
export default FormAddContainer;
|
@ -1,7 +1,8 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Textfield, Switch, Card, CardTitle, CardActions } from 'react-mdl';
|
||||
import { Textfield, Switch, Card, CardTitle, CardActions, Grid, Cell } from 'react-mdl';
|
||||
import StrategiesSection from './strategies-section-container';
|
||||
import FeatureTypeSelect from './feature-type-select-container';
|
||||
|
||||
import { FormButtons } from './../../common';
|
||||
import { styles as commonStyles } from '../../common';
|
||||
@ -37,16 +38,34 @@ class AddFeatureComponent extends Component {
|
||||
<Card shadow={0} className={commonStyles.fullwidth} style={{ overflow: 'visible' }}>
|
||||
<CardTitle style={{ paddingTop: '24px', wordBreak: 'break-all' }}>Create new feature toggle</CardTitle>
|
||||
<form onSubmit={onSubmit}>
|
||||
<section style={{ padding: '16px' }}>
|
||||
<Textfield
|
||||
floatingLabel
|
||||
label="Name"
|
||||
name="name"
|
||||
value={input.name}
|
||||
error={errors.name}
|
||||
onBlur={v => validateName(v.target.value)}
|
||||
onChange={v => setValue('name', trim(v.target.value))}
|
||||
/>
|
||||
<Grid>
|
||||
<Cell col={4}>
|
||||
<Textfield
|
||||
floatingLabel
|
||||
style={{ width: '100%' }}
|
||||
label="Name"
|
||||
name="name"
|
||||
value={input.name}
|
||||
error={errors.name}
|
||||
onBlur={v => validateName(v.target.value)}
|
||||
onChange={v => setValue('name', trim(v.target.value))}
|
||||
/>
|
||||
</Cell>
|
||||
<Cell col={2}>
|
||||
<FeatureTypeSelect value={input.type} onChange={v => setValue('type', v.target.value)} />
|
||||
</Cell>
|
||||
<Cell col={2} style={{ paddingTop: '14px' }}>
|
||||
<Switch
|
||||
checked={input.enabled}
|
||||
onChange={() => {
|
||||
setValue('enabled', !input.enabled);
|
||||
}}
|
||||
>
|
||||
{input.enabled ? 'Enabled' : 'Disabled'}
|
||||
</Switch>
|
||||
</Cell>
|
||||
</Grid>
|
||||
<section style={{ padding: '0 16px' }}>
|
||||
<Textfield
|
||||
floatingLabel
|
||||
style={{ width: '100%' }}
|
||||
@ -56,19 +75,6 @@ class AddFeatureComponent extends Component {
|
||||
value={input.description}
|
||||
onChange={v => setValue('description', v.target.value)}
|
||||
/>
|
||||
<div>
|
||||
<br />
|
||||
<Switch
|
||||
checked={input.enabled}
|
||||
onChange={() => {
|
||||
setValue('enabled', !input.enabled);
|
||||
}}
|
||||
>
|
||||
Enabled
|
||||
</Switch>
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
|
||||
{input.name ? (
|
||||
<StrategiesSection
|
||||
|
@ -13,7 +13,7 @@ class WrapperComponent extends Component {
|
||||
super(props);
|
||||
const name = loadNameFromHash();
|
||||
this.state = {
|
||||
featureToggle: { name, description: '', strategies: [], enabled: true },
|
||||
featureToggle: { name, description: '', type: 'release', strategies: [], enabled: true },
|
||||
errors: {},
|
||||
dirty: false,
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, CardText, Textfield } from 'react-mdl';
|
||||
import { Button, Textfield } from 'react-mdl';
|
||||
|
||||
import { UPDATE_FEATURE } from '../../../permissions';
|
||||
|
||||
@ -40,21 +40,21 @@ export default class UpdateDescriptionComponent extends React.Component {
|
||||
|
||||
renderRead({ description, isFeatureView, hasPermission }) {
|
||||
return (
|
||||
<CardText>
|
||||
<div>
|
||||
{description}
|
||||
{isFeatureView && hasPermission(UPDATE_FEATURE) ? (
|
||||
<a href="#edit" onClick={this.onEditMode.bind(this, description)}>
|
||||
edit
|
||||
</a>
|
||||
) : null}
|
||||
</CardText>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderEdit() {
|
||||
const { description } = this.state;
|
||||
return (
|
||||
<CardText>
|
||||
<div>
|
||||
<Textfield
|
||||
floatingLabel
|
||||
style={{ width: '100%' }}
|
||||
@ -72,7 +72,7 @@ export default class UpdateDescriptionComponent extends React.Component {
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</CardText>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -105,6 +105,9 @@ export default class FeatureListComponent extends React.Component {
|
||||
<MenuItem disabled={settings.sort === 'name'} data-target="name">
|
||||
Name
|
||||
</MenuItem>
|
||||
<MenuItem disabled={settings.sort === 'type'} data-target="type">
|
||||
Type
|
||||
</MenuItem>
|
||||
<MenuItem disabled={settings.sort === 'enabled'} data-target="enabled">
|
||||
Enabled
|
||||
</MenuItem>
|
||||
|
@ -47,6 +47,16 @@ export const mapStateToPropsConfigurable = isFeature => state => {
|
||||
});
|
||||
} else if (settings.sort === 'strategies') {
|
||||
features = features.sort((a, b) => (a.strategies.length > b.strategies.length ? -1 : 1));
|
||||
} else if (settings.sort === 'type') {
|
||||
features = features.sort((a, b) => {
|
||||
if (a.type < b.type) {
|
||||
return -1;
|
||||
}
|
||||
if (a.type > b.type) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
} else if (settings.sort === 'metrics') {
|
||||
const target = settings.showLastHour ? featureMetrics.lastHour : featureMetrics.lastMinute;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Tabs, Tab, ProgressBar, Button, Card, CardTitle, CardActions, Switch } from 'react-mdl';
|
||||
import { Tabs, Tab, ProgressBar, Button, Card, CardTitle, CardActions, Switch, CardText } from 'react-mdl';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import HistoryComponent from '../history/history-list-toggle-container';
|
||||
@ -8,6 +8,7 @@ import MetricComponent from './metric-container';
|
||||
import EditFeatureToggle from './form/form-update-feature-container';
|
||||
import EditVariants from './variant/update-variant-container';
|
||||
import ViewFeatureToggle from './form/form-view-feature-container';
|
||||
import FeatureTypeSelect from './form/feature-type-select-container';
|
||||
import UpdateDescriptionComponent from './form/update-description-component';
|
||||
import { styles as commonStyles } from '../common';
|
||||
import { CREATE_FEATURE, DELETE_FEATURE, UPDATE_FEATURE } from '../../permissions';
|
||||
@ -145,16 +146,33 @@ export default class ViewFeatureToggleComponent extends React.Component {
|
||||
|
||||
this.props.editFeatureToggle(feature);
|
||||
};
|
||||
const updateType = evt => {
|
||||
evt.preventDefault();
|
||||
const type = evt.target.value;
|
||||
let feature = { ...featureToggle, type };
|
||||
if (Array.isArray(feature.strategies)) {
|
||||
feature.strategies.forEach(s => {
|
||||
delete s.id;
|
||||
});
|
||||
}
|
||||
|
||||
this.props.editFeatureToggle(feature);
|
||||
};
|
||||
|
||||
return (
|
||||
<Card shadow={0} className={commonStyles.fullwidth} style={{ overflow: 'visible' }}>
|
||||
<CardTitle style={{ wordBreak: 'break-all', paddingBottom: 0 }}>{featureToggle.name} </CardTitle>
|
||||
<UpdateDescriptionComponent
|
||||
isFeatureView={this.isFeatureView}
|
||||
description={featureToggle.description}
|
||||
update={updateDescription}
|
||||
hasPermission={hasPermission}
|
||||
/>
|
||||
<CardText>
|
||||
<UpdateDescriptionComponent
|
||||
isFeatureView={this.isFeatureView}
|
||||
description={featureToggle.description}
|
||||
update={updateDescription}
|
||||
hasPermission={hasPermission}
|
||||
/>
|
||||
</CardText>
|
||||
<CardText style={{ paddingTop: 0 }}>
|
||||
<FeatureTypeSelect value={featureToggle.type} onChange={updateType} filled />
|
||||
</CardText>
|
||||
|
||||
<CardActions
|
||||
border
|
||||
|
13
frontend/src/data/feature-type-api.js
Normal file
13
frontend/src/data/feature-type-api.js
Normal file
@ -0,0 +1,13 @@
|
||||
import { throwIfNotSuccess } from './helper';
|
||||
|
||||
const URI = 'api/admin/feature-types';
|
||||
|
||||
function fetchAll() {
|
||||
return fetch(URI, { credentials: 'include' })
|
||||
.then(throwIfNotSuccess)
|
||||
.then(response => response.json());
|
||||
}
|
||||
|
||||
export default {
|
||||
fetchAll,
|
||||
};
|
@ -6,6 +6,7 @@ import {
|
||||
ERROR_REMOVE_FEATURE_TOGGLE,
|
||||
ERROR_UPDATE_FEATURE_TOGGLE,
|
||||
UPDATE_FEATURE_TOGGLE_STRATEGIES,
|
||||
UPDATE_FEATURE_TOGGLE,
|
||||
} from './feature-actions';
|
||||
|
||||
import { ERROR_UPDATING_STRATEGY, ERROR_CREATING_STRATEGY, ERROR_RECEIVE_STRATEGIES } from './strategy/actions';
|
||||
@ -46,6 +47,7 @@ const strategies = (state = getInitState(), action) => {
|
||||
return addErrorIfNotAlreadyInList(state, action.error.message || '403 Forbidden');
|
||||
case MUTE_ERROR:
|
||||
return state.update('list', list => list.remove(list.indexOf(action.error)));
|
||||
case UPDATE_FEATURE_TOGGLE:
|
||||
case UPDATE_FEATURE_TOGGLE_STRATEGIES:
|
||||
return addErrorIfNotAlreadyInList(state, action.info);
|
||||
default:
|
||||
|
@ -82,7 +82,11 @@ export function requestUpdateFeatureToggle(featureToggle) {
|
||||
|
||||
return api
|
||||
.update(featureToggle)
|
||||
.then(() => dispatch({ type: UPDATE_FEATURE_TOGGLE, featureToggle }))
|
||||
.then(() => {
|
||||
const info = `${featureToggle.name} successfully updated!`;
|
||||
setTimeout(() => dispatch({ type: MUTE_ERROR, error: info }), 1000);
|
||||
dispatch({ type: UPDATE_FEATURE_TOGGLE, featureToggle, info });
|
||||
})
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_UPDATE_FEATURE_TOGGLE));
|
||||
};
|
||||
}
|
||||
|
15
frontend/src/store/feature-type/actions.js
Normal file
15
frontend/src/store/feature-type/actions.js
Normal file
@ -0,0 +1,15 @@
|
||||
import api from '../../data/feature-type-api';
|
||||
import { dispatchAndThrow } from '../util';
|
||||
|
||||
export const RECEIVE_FEATURE_TYPES = 'RECEIVE_FEATURE_TYPES';
|
||||
export const ERROR_RECEIVE_FEATURE_TYPES = 'ERROR_RECEIVE_FEATURE_TYPES';
|
||||
|
||||
const receiveFeatureTypes = value => ({ type: RECEIVE_FEATURE_TYPES, value });
|
||||
|
||||
export function fetchFeatureTypes() {
|
||||
return dispatch =>
|
||||
api
|
||||
.fetchAll()
|
||||
.then(json => dispatch(receiveFeatureTypes(json)))
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_FEATURE_TYPES));
|
||||
}
|
19
frontend/src/store/feature-type/index.js
Normal file
19
frontend/src/store/feature-type/index.js
Normal file
@ -0,0 +1,19 @@
|
||||
import { List } from 'immutable';
|
||||
import { RECEIVE_FEATURE_TYPES } from './actions';
|
||||
|
||||
const DEFAULT_FEATURE_TYPES = [{ id: 'release', name: 'Release', inital: true }];
|
||||
|
||||
function getInitState() {
|
||||
return new List(DEFAULT_FEATURE_TYPES);
|
||||
}
|
||||
|
||||
const strategies = (state = getInitState(), action) => {
|
||||
switch (action.type) {
|
||||
case RECEIVE_FEATURE_TYPES:
|
||||
return new List(action.value.types);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default strategies;
|
@ -1,5 +1,6 @@
|
||||
import { combineReducers } from 'redux';
|
||||
import features from './feature-store';
|
||||
import featureTypes from './feature-type';
|
||||
import featureMetrics from './feature-metrics-store';
|
||||
import strategies from './strategy';
|
||||
import input from './input-store';
|
||||
@ -15,6 +16,7 @@ import context from './context';
|
||||
|
||||
const unleashStore = combineReducers({
|
||||
features,
|
||||
featureTypes,
|
||||
featureMetrics,
|
||||
strategies,
|
||||
input,
|
||||
|
Loading…
Reference in New Issue
Block a user