diff --git a/frontend/src/component/app.jsx b/frontend/src/component/app.jsx index a52af8b78e..a905082e31 100644 --- a/frontend/src/component/app.jsx +++ b/frontend/src/component/app.jsx @@ -192,11 +192,11 @@ export default class App extends Component { - {createListItem('/features', 'Feature Toggles')} - {createListItem('/strategies', 'Strategies')} - {createListItem('/history', 'Event History')} - {createListItem('/archive', 'Archived Toggles')} - {createListItem('/applications', 'Applications')} + {createListItem('/features', 'Feature Toggles', '')} + {createListItem('/strategies', 'Strategies', '')} + {createListItem('/history', 'Event History', '')} + {createListItem('/archive', 'Archived Toggles', '')} + {createListItem('/applications', 'Applications', '')} Sign out diff --git a/frontend/src/component/archive/archive-list-component.jsx b/frontend/src/component/archive/archive-list-component.jsx index 1757dcd75a..444a2fe5ab 100644 --- a/frontend/src/component/archive/archive-list-component.jsx +++ b/frontend/src/component/archive/archive-list-component.jsx @@ -1,16 +1,21 @@ -import React, { Component } from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; import { Link } from 'react-router'; +import Feature from './../feature/feature-list-item-component'; import { Icon, Card, List, ListItem, ListItemContent, ListItemAction, Chip } from 'react-mdl'; +//import { Textfield, Menu, MenuItem, Card, CardActions, List, Chip, MenuItemWithIcon, DropdownButton } from 'react-mdl'; import { styles as commonStyles } from '../common'; import styles from './archive.scss'; -class ArchiveList extends Component { +class ArchiveList extends React.PureComponent { static propTypes = { name: PropTypes.string, - archive: PropTypes.array, + archive: PropTypes.array.isRequired, fetchArchive: PropTypes.func, - revive: PropTypes.func, + featureMetrics: PropTypes.object.isRequired, + updateSetting: PropTypes.func.isRequired, + settings: PropTypes.object, + revive: PropTypes.func.optional, }; componentDidMount() { @@ -55,8 +60,86 @@ class ArchiveList extends Component { } return display; } + + // render() { + // const { archive, featureMetrics, settings, revive } = this.props; + // archive.forEach(e => { + // e.reviveName = e.name; + // }); + // return ( + //
+ //
+ // { + // this.setFilter(e.target.value); + // }} + // label="Search" + // style={{ width: '100%' }} + // /> + //
+ // + // + // + // this.toggleMetrics()} style={{ width: '168px' }}> + // + // + // + // + // this.setSort(e.target.getAttribute('data-target'))} + // style={{ width: '168px' }} + // > + // + // Name + // + // + // Enabled + // + // + // Created + // + // + // Strategies + // + // + // Metrics + // + // + // + //
+ // + // {archive.map((feature, i) => ( + // + // ))} + // + //
+ //
+ // ); + // } + render() { - const { archive, revive } = this.props; + const { archive, featureMetrics, settings, revive } = this.props; + archive.forEach(e => { e.reviveName = e.name; }); @@ -73,57 +156,14 @@ class ArchiveList extends Component {
{archive.map((feature, i) => ( - - - {this.props.name && feature.name === this.props.name ? ( - - ) : ( - - )} - - - {this.props.name && feature.name === this.props.name ? ( - - {this.renderStrategiesInList(feature).map((strategyChip, i) => ( - {strategyChip} - ))} - - {feature.name} -
- {feature.description} -
-
- {this.renderStrategyDetail(feature)} -
- - ) : ( - - {feature.name} - - {this.renderStrategiesInList(feature).map((strategyChip, i) => ( - {strategyChip} - ))} - -
- {feature.description} -
- - )} -
- revive(feature.name)}> - - -
+ ))}
diff --git a/frontend/src/component/archive/archive-list-container.js b/frontend/src/component/archive/archive-list-container.js index 577187c6e5..88e2062fe4 100644 --- a/frontend/src/component/archive/archive-list-container.js +++ b/frontend/src/component/archive/archive-list-container.js @@ -1,15 +1,80 @@ import { connect } from 'react-redux'; -import ListComponent from './archive-list-component'; +import ArchiveList from './archive-list-component'; import { fetchArchive, revive } from './../../store/archive-actions'; +import { updateSettingForGroup } from './../../store/settings/actions'; const mapStateToProps = state => { - const archive = state.archive.get('list').toArray(); + const featureMetrics = state.featureMetrics.toJS(); + const settings = state.settings.toJS().feature || {}; + let features = state.archive.get('list').toArray(); + if (settings.filter) { + try { + const regex = new RegExp(settings.filter, 'i'); + features = features.filter( + feature => + regex.test(feature.name) || + regex.test(feature.description) || + feature.strategies.some(s => s && s.name && regex.test(s.name)) + ); + } catch (e) { + // Invalid filter regex + } + } + + if (!settings.sort) { + settings.sort = 'name'; + } + + if (settings.sort === 'enabled') { + features = features.sort( + (a, b) => + // eslint-disable-next-line + a.enabled === b.enabled ? 0 : a.enabled ? -1 : 1 + ); + } else if (settings.sort === 'created') { + features = features.sort((a, b) => (new Date(a.createdAt) > new Date(b.createdAt) ? -1 : 1)); + } else if (settings.sort === 'name') { + features = features.sort((a, b) => { + if (a.name < b.name) { + return -1; + } + if (a.name > b.name) { + return 1; + } + return 0; + }); + } else if (settings.sort === 'strategies') { + features = features.sort((a, b) => (a.strategies.length > b.strategies.length ? -1 : 1)); + } else if (settings.sort === 'metrics') { + const target = settings.showLastHour ? featureMetrics.lastHour : featureMetrics.lastMinute; + + features = features.sort((a, b) => { + if (!target[a.name]) { + return 1; + } + if (!target[b.name]) { + return -1; + } + if (target[a.name].yes > target[b.name].yes) { + return -1; + } + return 1; + }); + } return { - archive, + archive: features, + featureMetrics, + settings, }; }; -const ArchiveListContainer = connect(mapStateToProps, { fetchArchive, revive })(ListComponent); +const mapDispatchToProps = { + fetchArchive, + revive, + updateSetting: updateSettingForGroup('feature'), +}; + +const ArchiveListContainer = connect(mapStateToProps, mapDispatchToProps)(ArchiveList); export default ArchiveListContainer; diff --git a/frontend/src/component/feature/feature-list-item-component.jsx b/frontend/src/component/feature/feature-list-item-component.jsx index 6d4a831f8a..41dbc2b4a0 100644 --- a/frontend/src/component/feature/feature-list-item-component.jsx +++ b/frontend/src/component/feature/feature-list-item-component.jsx @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Link } from 'react-router'; -import { Switch, Chip, ListItem } from 'react-mdl'; +import { Switch, Chip, ListItem, ListItemAction, Icon } from 'react-mdl'; import Progress from './progress'; import { calc, styles as commonStyles } from '../common'; @@ -13,6 +13,7 @@ const Feature = ({ settings, metricsLastHour = { yes: 0, no: 0, isFallback: true }, metricsLastMinute = { yes: 0, no: 0, isFallback: true }, + revive, }) => { const { name, description, enabled, strategies } = feature; @@ -42,14 +43,19 @@ const Feature = ({ - - toggleFeature(name)} - checked={enabled} - /> - + {toggleFeature ? ( // display feature list + + toggleFeature(name)} + checked={enabled} + /> + + ) : ( + // display archive + + )} + {revive ? ( + revive(feature.name)}> + + + ) : ( + + )} ); }; @@ -73,6 +86,7 @@ Feature.propTypes = { settings: PropTypes.object, metricsLastHour: PropTypes.object, metricsLastMinute: PropTypes.object, + revive: PropTypes.func, }; export default Feature; diff --git a/frontend/src/component/feature/list-component.jsx b/frontend/src/component/feature/list-component.jsx index 269b2877a3..7b060cc0f7 100644 --- a/frontend/src/component/feature/list-component.jsx +++ b/frontend/src/component/feature/list-component.jsx @@ -13,7 +13,7 @@ export default class FeatureListComponent extends React.PureComponent { featureMetrics: PropTypes.object.isRequired, fetchFeatureToggles: PropTypes.func.isRequired, updateSetting: PropTypes.func.isRequired, - toggleFeature: PropTypes.func.isRequired, + toggleFeature: PropTypes.func, settings: PropTypes.object, };