mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat(archive): reuse Feature
This commit is contained in:
		
							parent
							
								
									7d7ca48259
								
							
						
					
					
						commit
						98bf15bdbf
					
				@ -192,11 +192,11 @@ export default class App extends Component {
 | 
			
		||||
                                <FooterSection type="middle">
 | 
			
		||||
                                    <FooterDropDownSection title="Menu">
 | 
			
		||||
                                        <FooterLinkList>
 | 
			
		||||
                                            {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', '')}
 | 
			
		||||
                                            <a href="/api/admin/user/logout">Sign out</a>
 | 
			
		||||
                                        </FooterLinkList>
 | 
			
		||||
                                    </FooterDropDownSection>
 | 
			
		||||
 | 
			
		||||
@ -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 (
 | 
			
		||||
    //         <div>
 | 
			
		||||
    //             <div className={styles.toolbar}>
 | 
			
		||||
    //                 <Textfield
 | 
			
		||||
    //                     floatingLabel
 | 
			
		||||
    //                     value={settings.filter}
 | 
			
		||||
    //                     onChange={e => {
 | 
			
		||||
    //                         this.setFilter(e.target.value);
 | 
			
		||||
    //                     }}
 | 
			
		||||
    //                     label="Search"
 | 
			
		||||
    //                     style={{ width: '100%' }}
 | 
			
		||||
    //                 />
 | 
			
		||||
    //             </div>
 | 
			
		||||
    //             <Card shadow={0} className={commonStyles.fullwidth} style={{ overflow: 'visible' }}>
 | 
			
		||||
    //                 <CardActions>
 | 
			
		||||
    //                     <DropdownButton id="metric" label={`Last ${settings.showLastHour ? 'hour' : 'minute'}`} />
 | 
			
		||||
    //                     <Menu target="metric" onClick={() => this.toggleMetrics()} style={{ width: '168px' }}>
 | 
			
		||||
    //                         <MenuItemWithIcon
 | 
			
		||||
    //                             icon="hourglass_empty"
 | 
			
		||||
    //                             disabled={!settings.showLastHour}
 | 
			
		||||
    //                             data-target="minute"
 | 
			
		||||
    //                             label="Last minute"
 | 
			
		||||
    //                         />
 | 
			
		||||
    //                         <MenuItemWithIcon
 | 
			
		||||
    //                             icon="hourglass_full"
 | 
			
		||||
    //                             disabled={settings.showLastHour}
 | 
			
		||||
    //                             data-target="hour"
 | 
			
		||||
    //                             label="Last hour"
 | 
			
		||||
    //                         />
 | 
			
		||||
    //                     </Menu>
 | 
			
		||||
    //                     <DropdownButton id="sorting" label={`By ${settings.sort}`} />
 | 
			
		||||
    //                     <Menu
 | 
			
		||||
    //                         target="sorting"
 | 
			
		||||
    //                         onClick={e => this.setSort(e.target.getAttribute('data-target'))}
 | 
			
		||||
    //                         style={{ width: '168px' }}
 | 
			
		||||
    //                     >
 | 
			
		||||
    //                         <MenuItem disabled={settings.sort === 'name'} data-target="name">
 | 
			
		||||
    //                             Name
 | 
			
		||||
    //                         </MenuItem>
 | 
			
		||||
    //                         <MenuItem disabled={settings.sort === 'enabled'} data-target="enabled">
 | 
			
		||||
    //                             Enabled
 | 
			
		||||
    //                         </MenuItem>
 | 
			
		||||
    //                         <MenuItem disabled={settings.sort === 'created'} data-target="created">
 | 
			
		||||
    //                             Created
 | 
			
		||||
    //                         </MenuItem>
 | 
			
		||||
    //                         <MenuItem disabled={settings.sort === 'strategies'} data-target="strategies">
 | 
			
		||||
    //                             Strategies
 | 
			
		||||
    //                         </MenuItem>
 | 
			
		||||
    //                         <MenuItem disabled={settings.sort === 'metrics'} data-target="metrics">
 | 
			
		||||
    //                             Metrics
 | 
			
		||||
    //                         </MenuItem>
 | 
			
		||||
    //                     </Menu>
 | 
			
		||||
    //                 </CardActions>
 | 
			
		||||
    //                 <hr />
 | 
			
		||||
    //                 <List>
 | 
			
		||||
    //                     {archive.map((feature, i) => (
 | 
			
		||||
    //                         <Feature
 | 
			
		||||
    //                             key={i}
 | 
			
		||||
    //                             settings={settings}
 | 
			
		||||
    //                             metricsLastHour={featureMetrics.lastHour[feature.name]}
 | 
			
		||||
    //                             metricsLastMinute={featureMetrics.lastMinute[feature.name]}
 | 
			
		||||
    //                             feature={feature}
 | 
			
		||||
    //                             revive={revive}
 | 
			
		||||
    //                         />
 | 
			
		||||
    //                     ))}
 | 
			
		||||
    //                 </List>
 | 
			
		||||
    //             </Card>
 | 
			
		||||
    //         </div>
 | 
			
		||||
    //     );
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    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 {
 | 
			
		||||
                                <hr />
 | 
			
		||||
                                <List>
 | 
			
		||||
                                    {archive.map((feature, i) => (
 | 
			
		||||
                                        <ListItem key={i} twoLine>
 | 
			
		||||
                                            <ListItemAction>
 | 
			
		||||
                                                {this.props.name && feature.name === this.props.name ? (
 | 
			
		||||
                                                    <Icon name="keyboard_arrow_down" />
 | 
			
		||||
                                                ) : (
 | 
			
		||||
                                                    <Icon name="keyboard_arrow_right" />
 | 
			
		||||
                                                )}
 | 
			
		||||
                                            </ListItemAction>
 | 
			
		||||
                                            <ListItemContent>
 | 
			
		||||
                                                {this.props.name && feature.name === this.props.name ? (
 | 
			
		||||
                                                    <Link
 | 
			
		||||
                                                        to={`/archive`}
 | 
			
		||||
                                                        className={[commonStyles.listLink, commonStyles.truncate].join(
 | 
			
		||||
                                                            ' '
 | 
			
		||||
                                                        )}
 | 
			
		||||
                                                    >
 | 
			
		||||
                                                        {this.renderStrategiesInList(feature).map((strategyChip, i) => (
 | 
			
		||||
                                                            <span key={i}>{strategyChip}</span>
 | 
			
		||||
                                                        ))}
 | 
			
		||||
 | 
			
		||||
                                                        {feature.name}
 | 
			
		||||
                                                        <div className={'mdl-list__item-sub-title'}>
 | 
			
		||||
                                                            {feature.description}
 | 
			
		||||
                                                        </div>
 | 
			
		||||
                                                        <div className={'mdl-list__item-sub-title'}>
 | 
			
		||||
                                                            {this.renderStrategyDetail(feature)}
 | 
			
		||||
                                                        </div>
 | 
			
		||||
                                                    </Link>
 | 
			
		||||
                                                ) : (
 | 
			
		||||
                                                    <Link
 | 
			
		||||
                                                        to={`/archive/${feature.name}`}
 | 
			
		||||
                                                        className={[commonStyles.listLink, commonStyles.truncate].join(
 | 
			
		||||
                                                            ' '
 | 
			
		||||
                                                        )}
 | 
			
		||||
                                                    >
 | 
			
		||||
                                                        {feature.name}
 | 
			
		||||
 | 
			
		||||
                                                        {this.renderStrategiesInList(feature).map((strategyChip, i) => (
 | 
			
		||||
                                                            <span key={i}>{strategyChip}</span>
 | 
			
		||||
                                                        ))}
 | 
			
		||||
 | 
			
		||||
                                                        <div className={'mdl-list__item-sub-title'}>
 | 
			
		||||
                                                            {feature.description}
 | 
			
		||||
                                                        </div>
 | 
			
		||||
                                                    </Link>
 | 
			
		||||
                                                )}
 | 
			
		||||
                                            </ListItemContent>
 | 
			
		||||
                                            <ListItemAction onClick={() => revive(feature.name)}>
 | 
			
		||||
                                                <Icon name="undo" />
 | 
			
		||||
                                            </ListItemAction>
 | 
			
		||||
                                        </ListItem>
 | 
			
		||||
                                        <Feature
 | 
			
		||||
                                            key={i}
 | 
			
		||||
                                            settings={settings}
 | 
			
		||||
                                            metricsLastHour={featureMetrics.lastHour[feature.name]}
 | 
			
		||||
                                            metricsLastMinute={featureMetrics.lastMinute[feature.name]}
 | 
			
		||||
                                            feature={feature}
 | 
			
		||||
                                            revive={revive}
 | 
			
		||||
                                        />
 | 
			
		||||
                                    ))}
 | 
			
		||||
                                </List>
 | 
			
		||||
                            </List>
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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 = ({
 | 
			
		||||
            <span className={styles.listItemMetric}>
 | 
			
		||||
                <Progress strokeWidth={15} percentage={percent} isFallback={isStale} />
 | 
			
		||||
            </span>
 | 
			
		||||
            <span className={styles.listItemToggle}>
 | 
			
		||||
                <Switch
 | 
			
		||||
                    title={`Toggle ${name}`}
 | 
			
		||||
                    key="left-actions"
 | 
			
		||||
                    onChange={() => toggleFeature(name)}
 | 
			
		||||
                    checked={enabled}
 | 
			
		||||
                />
 | 
			
		||||
            </span>
 | 
			
		||||
            {toggleFeature ? ( // display feature list
 | 
			
		||||
                <span className={styles.listItemToggle}>
 | 
			
		||||
                    <Switch
 | 
			
		||||
                        title={`Toggle ${name}`}
 | 
			
		||||
                        key="left-actions"
 | 
			
		||||
                        onChange={() => toggleFeature(name)}
 | 
			
		||||
                        checked={enabled}
 | 
			
		||||
                    />
 | 
			
		||||
                </span>
 | 
			
		||||
            ) : (
 | 
			
		||||
                // display archive
 | 
			
		||||
                <span />
 | 
			
		||||
            )}
 | 
			
		||||
            <span className={['mdl-list__item-primary-content', styles.listItemLink].join(' ')}>
 | 
			
		||||
                <Link
 | 
			
		||||
                    to={`/features/strategies/${name}`}
 | 
			
		||||
@ -63,6 +69,13 @@ const Feature = ({
 | 
			
		||||
                {strategyChips}
 | 
			
		||||
                {summaryChip}
 | 
			
		||||
            </span>
 | 
			
		||||
            {revive ? (
 | 
			
		||||
                <ListItemAction onClick={() => revive(feature.name)}>
 | 
			
		||||
                    <Icon name="undo" />
 | 
			
		||||
                </ListItemAction>
 | 
			
		||||
            ) : (
 | 
			
		||||
                <span />
 | 
			
		||||
            )}
 | 
			
		||||
        </ListItem>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
@ -73,6 +86,7 @@ Feature.propTypes = {
 | 
			
		||||
    settings: PropTypes.object,
 | 
			
		||||
    metricsLastHour: PropTypes.object,
 | 
			
		||||
    metricsLastMinute: PropTypes.object,
 | 
			
		||||
    revive: PropTypes.func,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default Feature;
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user