mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	Merge pull request #121 from corinnekrych/archive.revisited
Archive.revisited
This commit is contained in:
		
						commit
						4b64762671
					
				
							
								
								
									
										1
									
								
								frontend/src/__mocks__/react-mdl.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								frontend/src/__mocks__/react-mdl.js
									
									
									
									
										vendored
									
									
								
							@ -1,5 +1,6 @@
 | 
				
			|||||||
module.exports = {
 | 
					module.exports = {
 | 
				
			||||||
    Card: 'react-mdl-Card',
 | 
					    Card: 'react-mdl-Card',
 | 
				
			||||||
 | 
					    CardActions: 'react-mdl-CardActions',
 | 
				
			||||||
    CardTitle: 'react-mdl-CardTitle',
 | 
					    CardTitle: 'react-mdl-CardTitle',
 | 
				
			||||||
    CardText: 'react-mdl-CardText',
 | 
					    CardText: 'react-mdl-CardText',
 | 
				
			||||||
    CardMenu: 'react-mdl-CardMenu',
 | 
					    CardMenu: 'react-mdl-CardMenu',
 | 
				
			||||||
 | 
				
			|||||||
@ -192,11 +192,11 @@ export default class App extends Component {
 | 
				
			|||||||
                                <FooterSection type="middle">
 | 
					                                <FooterSection type="middle">
 | 
				
			||||||
                                    <FooterDropDownSection title="Menu">
 | 
					                                    <FooterDropDownSection title="Menu">
 | 
				
			||||||
                                        <FooterLinkList>
 | 
					                                        <FooterLinkList>
 | 
				
			||||||
                                            {createListItem('/features', 'Feature Toggles')}
 | 
					                                            {createListItem('/features', 'Feature Toggles', '')}
 | 
				
			||||||
                                            {createListItem('/strategies', 'Strategies')}
 | 
					                                            {createListItem('/strategies', 'Strategies', '')}
 | 
				
			||||||
                                            {createListItem('/history', 'Event History')}
 | 
					                                            {createListItem('/history', 'Event History', '')}
 | 
				
			||||||
                                            {createListItem('/archive', 'Archived Toggles')}
 | 
					                                            {createListItem('/archive', 'Archived Toggles', '')}
 | 
				
			||||||
                                            {createListItem('/applications', 'Applications')}
 | 
					                                            {createListItem('/applications', 'Applications', '')}
 | 
				
			||||||
                                            <a href="/api/admin/user/logout">Sign out</a>
 | 
					                                            <a href="/api/admin/user/logout">Sign out</a>
 | 
				
			||||||
                                        </FooterLinkList>
 | 
					                                        </FooterLinkList>
 | 
				
			||||||
                                    </FooterDropDownSection>
 | 
					                                    </FooterDropDownSection>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
    "env": {
 | 
					 | 
				
			||||||
        "jest": true
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,149 +0,0 @@
 | 
				
			|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
exports[`renders correctly with archived toggles 1`] = `
 | 
					 | 
				
			||||||
<react-mdl-Card
 | 
					 | 
				
			||||||
  className="fullwidth"
 | 
					 | 
				
			||||||
  shadow={0}
 | 
					 | 
				
			||||||
>
 | 
					 | 
				
			||||||
  <div>
 | 
					 | 
				
			||||||
    <div
 | 
					 | 
				
			||||||
      style={
 | 
					 | 
				
			||||||
        Object {
 | 
					 | 
				
			||||||
          "position": "relative",
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      <react-mdl-List>
 | 
					 | 
				
			||||||
        <react-mdl-ListItem
 | 
					 | 
				
			||||||
          className="archiveList"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <span
 | 
					 | 
				
			||||||
            className="listItemToggle"
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            Toggle name
 | 
					 | 
				
			||||||
          </span>
 | 
					 | 
				
			||||||
          <span
 | 
					 | 
				
			||||||
            className="listItemRevive"
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            Revive
 | 
					 | 
				
			||||||
          </span>
 | 
					 | 
				
			||||||
        </react-mdl-ListItem>
 | 
					 | 
				
			||||||
        <hr />
 | 
					 | 
				
			||||||
        <react-mdl-List>
 | 
					 | 
				
			||||||
          <react-mdl-ListItem
 | 
					 | 
				
			||||||
            twoLine={true}
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <react-mdl-ListItemAction>
 | 
					 | 
				
			||||||
              <react-mdl-Icon
 | 
					 | 
				
			||||||
                name="keyboard_arrow_right"
 | 
					 | 
				
			||||||
              />
 | 
					 | 
				
			||||||
            </react-mdl-ListItemAction>
 | 
					 | 
				
			||||||
            <react-mdl-ListItemContent>
 | 
					 | 
				
			||||||
              <a
 | 
					 | 
				
			||||||
                className="listLink truncate"
 | 
					 | 
				
			||||||
                onClick={[Function]}
 | 
					 | 
				
			||||||
                style={Object {}}
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                adin-pay-confirm-disabled
 | 
					 | 
				
			||||||
                <span>
 | 
					 | 
				
			||||||
                  <span
 | 
					 | 
				
			||||||
                    className="strategiesList hideLt920"
 | 
					 | 
				
			||||||
                  >
 | 
					 | 
				
			||||||
                    <react-mdl-Chip
 | 
					 | 
				
			||||||
                      className="strategyChip"
 | 
					 | 
				
			||||||
                    >
 | 
					 | 
				
			||||||
                      default
 | 
					 | 
				
			||||||
                    </react-mdl-Chip>
 | 
					 | 
				
			||||||
                  </span>
 | 
					 | 
				
			||||||
                </span>
 | 
					 | 
				
			||||||
                <div
 | 
					 | 
				
			||||||
                  className="mdl-list__item-sub-title"
 | 
					 | 
				
			||||||
                >
 | 
					 | 
				
			||||||
                  Disables the confirm-functionality from API
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              </a>
 | 
					 | 
				
			||||||
            </react-mdl-ListItemContent>
 | 
					 | 
				
			||||||
            <react-mdl-ListItemAction
 | 
					 | 
				
			||||||
              onClick={[Function]}
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              <react-mdl-Icon
 | 
					 | 
				
			||||||
                name="undo"
 | 
					 | 
				
			||||||
              />
 | 
					 | 
				
			||||||
            </react-mdl-ListItemAction>
 | 
					 | 
				
			||||||
          </react-mdl-ListItem>
 | 
					 | 
				
			||||||
          <react-mdl-ListItem
 | 
					 | 
				
			||||||
            twoLine={true}
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <react-mdl-ListItemAction>
 | 
					 | 
				
			||||||
              <react-mdl-Icon
 | 
					 | 
				
			||||||
                name="keyboard_arrow_right"
 | 
					 | 
				
			||||||
              />
 | 
					 | 
				
			||||||
            </react-mdl-ListItemAction>
 | 
					 | 
				
			||||||
            <react-mdl-ListItemContent>
 | 
					 | 
				
			||||||
              <a
 | 
					 | 
				
			||||||
                className="listLink truncate"
 | 
					 | 
				
			||||||
                onClick={[Function]}
 | 
					 | 
				
			||||||
                style={Object {}}
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                adin-pay-platform-sch-payment
 | 
					 | 
				
			||||||
                <span>
 | 
					 | 
				
			||||||
                  <span
 | 
					 | 
				
			||||||
                    className="strategiesList hideLt920"
 | 
					 | 
				
			||||||
                  >
 | 
					 | 
				
			||||||
                    <react-mdl-Chip
 | 
					 | 
				
			||||||
                      className="strategyChip"
 | 
					 | 
				
			||||||
                    >
 | 
					 | 
				
			||||||
                      default
 | 
					 | 
				
			||||||
                    </react-mdl-Chip>
 | 
					 | 
				
			||||||
                  </span>
 | 
					 | 
				
			||||||
                </span>
 | 
					 | 
				
			||||||
                <div
 | 
					 | 
				
			||||||
                  className="mdl-list__item-sub-title"
 | 
					 | 
				
			||||||
                >
 | 
					 | 
				
			||||||
                  Enables use of schibsted payment from order-payment-management
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              </a>
 | 
					 | 
				
			||||||
            </react-mdl-ListItemContent>
 | 
					 | 
				
			||||||
            <react-mdl-ListItemAction
 | 
					 | 
				
			||||||
              onClick={[Function]}
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              <react-mdl-Icon
 | 
					 | 
				
			||||||
                name="undo"
 | 
					 | 
				
			||||||
              />
 | 
					 | 
				
			||||||
            </react-mdl-ListItemAction>
 | 
					 | 
				
			||||||
          </react-mdl-ListItem>
 | 
					 | 
				
			||||||
        </react-mdl-List>
 | 
					 | 
				
			||||||
      </react-mdl-List>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
</react-mdl-Card>
 | 
					 | 
				
			||||||
`;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
exports[`renders correctly with no archived toggles 1`] = `
 | 
					 | 
				
			||||||
<react-mdl-Card
 | 
					 | 
				
			||||||
  className="fullwidth"
 | 
					 | 
				
			||||||
  shadow={0}
 | 
					 | 
				
			||||||
>
 | 
					 | 
				
			||||||
  <div
 | 
					 | 
				
			||||||
    className="emptyState"
 | 
					 | 
				
			||||||
  >
 | 
					 | 
				
			||||||
    <react-mdl-Icon
 | 
					 | 
				
			||||||
      className="mdl-color-text--grey-300"
 | 
					 | 
				
			||||||
      name="archive"
 | 
					 | 
				
			||||||
      style={
 | 
					 | 
				
			||||||
        Object {
 | 
					 | 
				
			||||||
          "fontSize": "56px",
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    />
 | 
					 | 
				
			||||||
    <br />
 | 
					 | 
				
			||||||
    No archived feature toggles, go see 
 | 
					 | 
				
			||||||
    <a
 | 
					 | 
				
			||||||
      onClick={[Function]}
 | 
					 | 
				
			||||||
      style={Object {}}
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      active toggles here
 | 
					 | 
				
			||||||
    </a>
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
</react-mdl-Card>
 | 
					 | 
				
			||||||
`;
 | 
					 | 
				
			||||||
@ -1,35 +0,0 @@
 | 
				
			|||||||
import React from 'react';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import ArchiveList from '../archive-list-component';
 | 
					 | 
				
			||||||
import renderer from 'react-test-renderer';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
jest.mock('react-mdl');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const archive = [
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        name: 'adin-pay-confirm-disabled',
 | 
					 | 
				
			||||||
        description: 'Disables the confirm-functionality from API',
 | 
					 | 
				
			||||||
        enabled: false,
 | 
					 | 
				
			||||||
        strategies: [{ name: 'default', parameters: {} }],
 | 
					 | 
				
			||||||
        createdAt: '2016-10-25T15:38:28.573Z',
 | 
					 | 
				
			||||||
        reviveName: 'adin-pay-confirm-disabled',
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        name: 'adin-pay-platform-sch-payment',
 | 
					 | 
				
			||||||
        description: 'Enables use of schibsted payment from order-payment-management',
 | 
					 | 
				
			||||||
        enabled: true,
 | 
					 | 
				
			||||||
        strategies: [{ name: 'default', parameters: {} }],
 | 
					 | 
				
			||||||
        createdAt: '2016-08-03T12:41:35.631Z',
 | 
					 | 
				
			||||||
        reviveName: 'adin-pay-platform-sch-payment',
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
test('renders correctly with no archived toggles', () => {
 | 
					 | 
				
			||||||
    const tree = renderer.create(<ArchiveList fetchArchive={jest.fn()} archive={[]} />).toJSON();
 | 
					 | 
				
			||||||
    expect(tree).toMatchSnapshot();
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
test('renders correctly with archived toggles', () => {
 | 
					 | 
				
			||||||
    const tree = renderer.create(<ArchiveList fetchArchive={jest.fn()} archive={archive} />).toJSON();
 | 
					 | 
				
			||||||
    expect(tree).toMatchSnapshot();
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
@ -1,144 +0,0 @@
 | 
				
			|||||||
import React, { Component } from 'react';
 | 
					 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					 | 
				
			||||||
import { Link } from 'react-router';
 | 
					 | 
				
			||||||
import { Icon, Card, List, ListItem, ListItemContent, ListItemAction, Chip } from 'react-mdl';
 | 
					 | 
				
			||||||
import { styles as commonStyles } from '../common';
 | 
					 | 
				
			||||||
import styles from './archive.scss';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ArchiveList extends Component {
 | 
					 | 
				
			||||||
    static propTypes = {
 | 
					 | 
				
			||||||
        name: PropTypes.string,
 | 
					 | 
				
			||||||
        archive: PropTypes.array,
 | 
					 | 
				
			||||||
        fetchArchive: PropTypes.func,
 | 
					 | 
				
			||||||
        revive: PropTypes.func,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    componentDidMount() {
 | 
					 | 
				
			||||||
        this.props.fetchArchive();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    renderStrategyDetail(feature) {
 | 
					 | 
				
			||||||
        let strategiesList = (
 | 
					 | 
				
			||||||
            <span>
 | 
					 | 
				
			||||||
                {feature.strategies.map((s, i) => (
 | 
					 | 
				
			||||||
                    <span style={{ marginLeft: `8px` }} key={i}>
 | 
					 | 
				
			||||||
                        <strong>{s.name}</strong>
 | 
					 | 
				
			||||||
                        {Object.keys(s.parameters).map((p, j) => <i key={j}> {s.parameters[p]}</i>)}
 | 
					 | 
				
			||||||
                    </span>
 | 
					 | 
				
			||||||
                ))}
 | 
					 | 
				
			||||||
            </span>
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return strategiesList;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    renderStrategiesInList(feature) {
 | 
					 | 
				
			||||||
        let display = [];
 | 
					 | 
				
			||||||
        if (feature.strategies && feature.strategies.length > 0) {
 | 
					 | 
				
			||||||
            const strategiesToShow = Math.min(feature.strategies.length, 3);
 | 
					 | 
				
			||||||
            const remainingStrategies = feature.strategies.length - strategiesToShow;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            const strategyChips =
 | 
					 | 
				
			||||||
                feature.strategies &&
 | 
					 | 
				
			||||||
                feature.strategies.slice(0, strategiesToShow).map((s, i) => (
 | 
					 | 
				
			||||||
                    <span key={i} className={[styles.strategiesList, commonStyles.hideLt920].join(' ')}>
 | 
					 | 
				
			||||||
                        <Chip className={styles.strategyChip}>{s.name}</Chip>
 | 
					 | 
				
			||||||
                    </span>
 | 
					 | 
				
			||||||
                ));
 | 
					 | 
				
			||||||
            const remaining = (
 | 
					 | 
				
			||||||
                <span className={[styles.strategiesList, commonStyles.hideLt920].join(' ')}>
 | 
					 | 
				
			||||||
                    <Chip className={styles.strategyChip}>+{remainingStrategies}</Chip>
 | 
					 | 
				
			||||||
                </span>
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            if (remainingStrategies > 0) {
 | 
					 | 
				
			||||||
                display.push(remaining);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            display.push(strategyChips);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return display;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    render() {
 | 
					 | 
				
			||||||
        const { archive, revive } = this.props;
 | 
					 | 
				
			||||||
        archive.forEach(e => {
 | 
					 | 
				
			||||||
            e.reviveName = e.name;
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        return (
 | 
					 | 
				
			||||||
            <Card shadow={0} className={commonStyles.fullwidth}>
 | 
					 | 
				
			||||||
                {archive && archive.length > 0 ? (
 | 
					 | 
				
			||||||
                    <div>
 | 
					 | 
				
			||||||
                        <div style={{ position: 'relative' }}>
 | 
					 | 
				
			||||||
                            <List>
 | 
					 | 
				
			||||||
                                <ListItem className={styles.archiveList}>
 | 
					 | 
				
			||||||
                                    <span className={styles.listItemToggle}>Toggle name</span>
 | 
					 | 
				
			||||||
                                    <span className={styles.listItemRevive}>Revive</span>
 | 
					 | 
				
			||||||
                                </ListItem>
 | 
					 | 
				
			||||||
                                <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>
 | 
					 | 
				
			||||||
                                    ))}
 | 
					 | 
				
			||||||
                                </List>
 | 
					 | 
				
			||||||
                            </List>
 | 
					 | 
				
			||||||
                        </div>
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                ) : (
 | 
					 | 
				
			||||||
                    <div className={commonStyles.emptyState}>
 | 
					 | 
				
			||||||
                        <Icon name="archive" className="mdl-color-text--grey-300" style={{ fontSize: '56px' }} />
 | 
					 | 
				
			||||||
                        <br />
 | 
					 | 
				
			||||||
                        No archived feature toggles, go see <Link to="/features">active toggles here</Link>
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                )}
 | 
					 | 
				
			||||||
            </Card>
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default ArchiveList;
 | 
					 | 
				
			||||||
@ -1,15 +1,16 @@
 | 
				
			|||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
import ListComponent from './archive-list-component';
 | 
					import FeatureListComponent from './../feature/list-component';
 | 
				
			||||||
import { fetchArchive, revive } from './../../store/archive-actions';
 | 
					import { fetchArchive, revive } from './../../store/archive-actions';
 | 
				
			||||||
 | 
					import { updateSettingForGroup } from './../../store/settings/actions';
 | 
				
			||||||
 | 
					import { mapStateToPropsConfigurable } from '../feature/list-container';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mapStateToProps = state => {
 | 
					const mapStateToProps = mapStateToPropsConfigurable(false);
 | 
				
			||||||
    const archive = state.archive.get('list').toArray();
 | 
					const mapDispatchToProps = {
 | 
				
			||||||
 | 
					    fetchArchive,
 | 
				
			||||||
    return {
 | 
					    revive,
 | 
				
			||||||
        archive,
 | 
					    updateSetting: updateSettingForGroup('feature'),
 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ArchiveListContainer = connect(mapStateToProps, { fetchArchive, revive })(ListComponent);
 | 
					const ArchiveListContainer = connect(mapStateToProps, mapDispatchToProps)(FeatureListComponent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default ArchiveListContainer;
 | 
					export default ArchiveListContainer;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										18
									
								
								frontend/src/component/archive/view-container.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								frontend/src/component/archive/view-container.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					import { fetchArchive, revive } from './../../store/archive-actions';
 | 
				
			||||||
 | 
					import ViewToggleComponent from './../feature/view-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default connect(
 | 
				
			||||||
 | 
					    (state, props) => ({
 | 
				
			||||||
 | 
					        features: state.archive.get('list').toArray(),
 | 
				
			||||||
 | 
					        featureToggle: state.archive
 | 
				
			||||||
 | 
					            .get('list')
 | 
				
			||||||
 | 
					            .toArray()
 | 
				
			||||||
 | 
					            .find(toggle => toggle.name === props.featureToggleName),
 | 
				
			||||||
 | 
					        activeTab: props.activeTab,
 | 
				
			||||||
 | 
					    }),
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        fetchArchive,
 | 
				
			||||||
 | 
					        revive,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					)(ViewToggleComponent);
 | 
				
			||||||
@ -22,6 +22,7 @@ exports[`renders correctly with one feature 1`] = `
 | 
				
			|||||||
  >
 | 
					  >
 | 
				
			||||||
    <react-mdl-Switch
 | 
					    <react-mdl-Switch
 | 
				
			||||||
      checked={false}
 | 
					      checked={false}
 | 
				
			||||||
 | 
					      disabled={true}
 | 
				
			||||||
      onChange={[Function]}
 | 
					      onChange={[Function]}
 | 
				
			||||||
      title="Toggle Another"
 | 
					      title="Toggle Another"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
@ -51,5 +52,6 @@ exports[`renders correctly with one feature 1`] = `
 | 
				
			|||||||
      gradualRolloutRandom
 | 
					      gradualRolloutRandom
 | 
				
			||||||
    </react-mdl-Chip>
 | 
					    </react-mdl-Chip>
 | 
				
			||||||
  </span>
 | 
					  </span>
 | 
				
			||||||
 | 
					  <span />
 | 
				
			||||||
</react-mdl-ListItem>
 | 
					</react-mdl-ListItem>
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import { Link } from 'react-router';
 | 
					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 Progress from './progress';
 | 
				
			||||||
import { calc, styles as commonStyles } from '../common';
 | 
					import { calc, styles as commonStyles } from '../common';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -13,12 +13,11 @@ const Feature = ({
 | 
				
			|||||||
    settings,
 | 
					    settings,
 | 
				
			||||||
    metricsLastHour = { yes: 0, no: 0, isFallback: true },
 | 
					    metricsLastHour = { yes: 0, no: 0, isFallback: true },
 | 
				
			||||||
    metricsLastMinute = { yes: 0, no: 0, isFallback: true },
 | 
					    metricsLastMinute = { yes: 0, no: 0, isFallback: true },
 | 
				
			||||||
 | 
					    revive,
 | 
				
			||||||
}) => {
 | 
					}) => {
 | 
				
			||||||
    const { name, description, enabled, strategies } = feature;
 | 
					    const { name, description, enabled, strategies } = feature;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    const { showLastHour = false } = settings;
 | 
					    const { showLastHour = false } = settings;
 | 
				
			||||||
    const isStale = showLastHour ? metricsLastHour.isFallback : metricsLastMinute.isFallback;
 | 
					    const isStale = showLastHour ? metricsLastHour.isFallback : metricsLastMinute.isFallback;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    const percent =
 | 
					    const percent =
 | 
				
			||||||
        1 *
 | 
					        1 *
 | 
				
			||||||
        (showLastHour
 | 
					        (showLastHour
 | 
				
			||||||
@ -27,7 +26,6 @@ const Feature = ({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const strategiesToShow = Math.min(strategies.length, 3);
 | 
					    const strategiesToShow = Math.min(strategies.length, 3);
 | 
				
			||||||
    const remainingStrategies = strategies.length - strategiesToShow;
 | 
					    const remainingStrategies = strategies.length - strategiesToShow;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    const strategyChips =
 | 
					    const strategyChips =
 | 
				
			||||||
        strategies &&
 | 
					        strategies &&
 | 
				
			||||||
        strategies.slice(0, strategiesToShow).map((s, i) => (
 | 
					        strategies.slice(0, strategiesToShow).map((s, i) => (
 | 
				
			||||||
@ -36,7 +34,7 @@ const Feature = ({
 | 
				
			|||||||
            </Chip>
 | 
					            </Chip>
 | 
				
			||||||
        ));
 | 
					        ));
 | 
				
			||||||
    const summaryChip = remainingStrategies > 0 && <Chip className={styles.strategyChip}>+{remainingStrategies}</Chip>;
 | 
					    const summaryChip = remainingStrategies > 0 && <Chip className={styles.strategyChip}>+{remainingStrategies}</Chip>;
 | 
				
			||||||
 | 
					    const featureUrl = toggleFeature === undefined ? `/archive/strategies/${name}` : `/features/strategies/${name}`;
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <ListItem twoLine>
 | 
					        <ListItem twoLine>
 | 
				
			||||||
            <span className={styles.listItemMetric}>
 | 
					            <span className={styles.listItemMetric}>
 | 
				
			||||||
@ -44,6 +42,7 @@ const Feature = ({
 | 
				
			|||||||
            </span>
 | 
					            </span>
 | 
				
			||||||
            <span className={styles.listItemToggle}>
 | 
					            <span className={styles.listItemToggle}>
 | 
				
			||||||
                <Switch
 | 
					                <Switch
 | 
				
			||||||
 | 
					                    disabled={toggleFeature !== undefined}
 | 
				
			||||||
                    title={`Toggle ${name}`}
 | 
					                    title={`Toggle ${name}`}
 | 
				
			||||||
                    key="left-actions"
 | 
					                    key="left-actions"
 | 
				
			||||||
                    onChange={() => toggleFeature(name)}
 | 
					                    onChange={() => toggleFeature(name)}
 | 
				
			||||||
@ -51,10 +50,7 @@ const Feature = ({
 | 
				
			|||||||
                />
 | 
					                />
 | 
				
			||||||
            </span>
 | 
					            </span>
 | 
				
			||||||
            <span className={['mdl-list__item-primary-content', styles.listItemLink].join(' ')}>
 | 
					            <span className={['mdl-list__item-primary-content', styles.listItemLink].join(' ')}>
 | 
				
			||||||
                <Link
 | 
					                <Link to={featureUrl} className={[commonStyles.listLink, commonStyles.truncate].join(' ')}>
 | 
				
			||||||
                    to={`/features/strategies/${name}`}
 | 
					 | 
				
			||||||
                    className={[commonStyles.listLink, commonStyles.truncate].join(' ')}
 | 
					 | 
				
			||||||
                >
 | 
					 | 
				
			||||||
                    {name}
 | 
					                    {name}
 | 
				
			||||||
                    <span className={['mdl-list__item-sub-title', commonStyles.truncate].join(' ')}>{description}</span>
 | 
					                    <span className={['mdl-list__item-sub-title', commonStyles.truncate].join(' ')}>{description}</span>
 | 
				
			||||||
                </Link>
 | 
					                </Link>
 | 
				
			||||||
@ -63,6 +59,13 @@ const Feature = ({
 | 
				
			|||||||
                {strategyChips}
 | 
					                {strategyChips}
 | 
				
			||||||
                {summaryChip}
 | 
					                {summaryChip}
 | 
				
			||||||
            </span>
 | 
					            </span>
 | 
				
			||||||
 | 
					            {revive ? (
 | 
				
			||||||
 | 
					                <ListItemAction onClick={() => revive(feature.name)}>
 | 
				
			||||||
 | 
					                    <Icon name="undo" />
 | 
				
			||||||
 | 
					                </ListItemAction>
 | 
				
			||||||
 | 
					            ) : (
 | 
				
			||||||
 | 
					                <span />
 | 
				
			||||||
 | 
					            )}
 | 
				
			||||||
        </ListItem>
 | 
					        </ListItem>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -73,6 +76,7 @@ Feature.propTypes = {
 | 
				
			|||||||
    settings: PropTypes.object,
 | 
					    settings: PropTypes.object,
 | 
				
			||||||
    metricsLastHour: PropTypes.object,
 | 
					    metricsLastHour: PropTypes.object,
 | 
				
			||||||
    metricsLastMinute: PropTypes.object,
 | 
					    metricsLastMinute: PropTypes.object,
 | 
				
			||||||
 | 
					    revive: PropTypes.func,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default Feature;
 | 
					export default Feature;
 | 
				
			||||||
 | 
				
			|||||||
@ -45,7 +45,7 @@ const prepare = (methods, dispatch) => {
 | 
				
			|||||||
    methods.onCancel = evt => {
 | 
					    methods.onCancel = evt => {
 | 
				
			||||||
        evt.preventDefault();
 | 
					        evt.preventDefault();
 | 
				
			||||||
        methods.clear();
 | 
					        methods.clear();
 | 
				
			||||||
        window.history.back();
 | 
					        hashHistory.push(`/features`);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    methods.addStrategy = v => {
 | 
					    methods.addStrategy = v => {
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					import React, { Component } from 'react';
 | 
				
			||||||
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
 | 
					import StrategiesSection from './strategies-section-container';
 | 
				
			||||||
 | 
					import { Button, Icon } from 'react-mdl';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ViewFeatureComponent extends Component {
 | 
				
			||||||
 | 
					    render() {
 | 
				
			||||||
 | 
					        const { input, onCancel } = this.props;
 | 
				
			||||||
 | 
					        const configuredStrategies = input.strategies || [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return (
 | 
				
			||||||
 | 
					            <section style={{ padding: '16px' }}>
 | 
				
			||||||
 | 
					                <StrategiesSection configuredStrategies={configuredStrategies} />
 | 
				
			||||||
 | 
					                <br />
 | 
				
			||||||
 | 
					                <Button type="cancel" ripple raised onClick={onCancel} style={{ float: 'right' }}>
 | 
				
			||||||
 | 
					                    <Icon name="cancel" />    Cancel
 | 
				
			||||||
 | 
					                </Button>
 | 
				
			||||||
 | 
					            </section>
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ViewFeatureComponent.propTypes = {
 | 
				
			||||||
 | 
					    input: PropTypes.object,
 | 
				
			||||||
 | 
					    onCancel: PropTypes.func.isRequired,
 | 
				
			||||||
 | 
					    initCallRequired: PropTypes.bool,
 | 
				
			||||||
 | 
					    init: PropTypes.func,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ViewFeatureComponent;
 | 
				
			||||||
@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					import { createMapper, createActions } from '../../input-helpers';
 | 
				
			||||||
 | 
					import ViewFeatureToggleComponent from './form-view-feature-component';
 | 
				
			||||||
 | 
					import { hashHistory } from 'react-router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ID = 'view-feature-toggle';
 | 
				
			||||||
 | 
					function getId(props) {
 | 
				
			||||||
 | 
					    return [ID, props.featureToggle.name];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// TODO: need to scope to the active featureToggle
 | 
				
			||||||
 | 
					// best is to emulate the "input-storage"?
 | 
				
			||||||
 | 
					const mapStateToProps = createMapper({
 | 
				
			||||||
 | 
					    id: getId,
 | 
				
			||||||
 | 
					    getDefault: (state, ownProps) => {
 | 
				
			||||||
 | 
					        ownProps.featureToggle.strategies.forEach((strategy, index) => {
 | 
				
			||||||
 | 
					            strategy.id = Math.round(Math.random() * 1000000 * (1 + index));
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        return ownProps.featureToggle;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    prepare: props => {
 | 
				
			||||||
 | 
					        props.editmode = true;
 | 
				
			||||||
 | 
					        return props;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const prepare = methods => {
 | 
				
			||||||
 | 
					    methods.onCancel = evt => {
 | 
				
			||||||
 | 
					        evt.preventDefault();
 | 
				
			||||||
 | 
					        methods.clear();
 | 
				
			||||||
 | 
					        hashHistory.push(`/archive`);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    return methods;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const actions = createActions({
 | 
				
			||||||
 | 
					    id: getId,
 | 
				
			||||||
 | 
					    prepare,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default connect(mapStateToProps, actions)(ViewFeatureToggleComponent);
 | 
				
			||||||
@ -5,7 +5,7 @@ import { Menu, MenuItem, IconButton } from 'react-mdl';
 | 
				
			|||||||
class AddStrategy extends React.Component {
 | 
					class AddStrategy extends React.Component {
 | 
				
			||||||
    static propTypes = {
 | 
					    static propTypes = {
 | 
				
			||||||
        strategies: PropTypes.array.isRequired,
 | 
					        strategies: PropTypes.array.isRequired,
 | 
				
			||||||
        addStrategy: PropTypes.func.isRequired,
 | 
					        addStrategy: PropTypes.func,
 | 
				
			||||||
        fetchStrategies: PropTypes.func.isRequired,
 | 
					        fetchStrategies: PropTypes.func.isRequired,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -9,9 +9,9 @@ class StrategiesList extends React.Component {
 | 
				
			|||||||
    static propTypes = {
 | 
					    static propTypes = {
 | 
				
			||||||
        strategies: PropTypes.array.isRequired,
 | 
					        strategies: PropTypes.array.isRequired,
 | 
				
			||||||
        configuredStrategies: PropTypes.array.isRequired,
 | 
					        configuredStrategies: PropTypes.array.isRequired,
 | 
				
			||||||
        updateStrategy: PropTypes.func.isRequired,
 | 
					        updateStrategy: PropTypes.func,
 | 
				
			||||||
        removeStrategy: PropTypes.func.isRequired,
 | 
					        removeStrategy: PropTypes.func,
 | 
				
			||||||
        moveStrategy: PropTypes.func.isRequired,
 | 
					        moveStrategy: PropTypes.func,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render() {
 | 
					    render() {
 | 
				
			||||||
@ -27,8 +27,8 @@ class StrategiesList extends React.Component {
 | 
				
			|||||||
                key={strategy.id}
 | 
					                key={strategy.id}
 | 
				
			||||||
                strategy={strategy}
 | 
					                strategy={strategy}
 | 
				
			||||||
                moveStrategy={moveStrategy}
 | 
					                moveStrategy={moveStrategy}
 | 
				
			||||||
                removeStrategy={removeStrategy.bind(null, i)}
 | 
					                removeStrategy={removeStrategy ? removeStrategy.bind(null, i) : null}
 | 
				
			||||||
                updateStrategy={updateStrategy.bind(null, i)}
 | 
					                updateStrategy={updateStrategy ? updateStrategy.bind(null, i) : null}
 | 
				
			||||||
                strategyDefinition={strategies.find(s => s.name === strategy.name)}
 | 
					                strategyDefinition={strategies.find(s => s.name === strategy.name)}
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
        ));
 | 
					        ));
 | 
				
			||||||
 | 
				
			|||||||
@ -8,9 +8,9 @@ import { HeaderTitle } from '../../common';
 | 
				
			|||||||
class StrategiesSectionComponent extends React.Component {
 | 
					class StrategiesSectionComponent extends React.Component {
 | 
				
			||||||
    static propTypes = {
 | 
					    static propTypes = {
 | 
				
			||||||
        strategies: PropTypes.array.isRequired,
 | 
					        strategies: PropTypes.array.isRequired,
 | 
				
			||||||
        addStrategy: PropTypes.func.isRequired,
 | 
					        addStrategy: PropTypes.func,
 | 
				
			||||||
        removeStrategy: PropTypes.func.isRequired,
 | 
					        removeStrategy: PropTypes.func,
 | 
				
			||||||
        updateStrategy: PropTypes.func.isRequired,
 | 
					        updateStrategy: PropTypes.func,
 | 
				
			||||||
        fetchStrategies: PropTypes.func.isRequired,
 | 
					        fetchStrategies: PropTypes.func.isRequired,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -25,7 +25,11 @@ class StrategiesSectionComponent extends React.Component {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
            <div>
 | 
					            <div>
 | 
				
			||||||
                <HeaderTitle title="Activation strategies" actions={<AddStrategy {...this.props} />} />
 | 
					                {this.props.addStrategy ? (
 | 
				
			||||||
 | 
					                    <HeaderTitle title="Activation strategies" actions={<AddStrategy {...this.props} />} />
 | 
				
			||||||
 | 
					                ) : (
 | 
				
			||||||
 | 
					                    <span />
 | 
				
			||||||
 | 
					                )}
 | 
				
			||||||
                <StrategiesList {...this.props} />
 | 
					                <StrategiesList {...this.props} />
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
				
			|||||||
@ -46,10 +46,10 @@ class StrategyConfigure extends React.Component {
 | 
				
			|||||||
    /* eslint-enable */
 | 
					    /* eslint-enable */
 | 
				
			||||||
    static propTypes = {
 | 
					    static propTypes = {
 | 
				
			||||||
        strategy: PropTypes.object.isRequired,
 | 
					        strategy: PropTypes.object.isRequired,
 | 
				
			||||||
        strategyDefinition: PropTypes.object.isRequired,
 | 
					        strategyDefinition: PropTypes.object,
 | 
				
			||||||
        updateStrategy: PropTypes.func.isRequired,
 | 
					        updateStrategy: PropTypes.func,
 | 
				
			||||||
        removeStrategy: PropTypes.func.isRequired,
 | 
					        removeStrategy: PropTypes.func,
 | 
				
			||||||
        moveStrategy: PropTypes.func.isRequired,
 | 
					        moveStrategy: PropTypes.func,
 | 
				
			||||||
        isDragging: PropTypes.bool.isRequired,
 | 
					        isDragging: PropTypes.bool.isRequired,
 | 
				
			||||||
        connectDragPreview: PropTypes.func.isRequired,
 | 
					        connectDragPreview: PropTypes.func.isRequired,
 | 
				
			||||||
        connectDragSource: PropTypes.func.isRequired,
 | 
					        connectDragSource: PropTypes.func.isRequired,
 | 
				
			||||||
@ -170,7 +170,11 @@ class StrategyConfigure extends React.Component {
 | 
				
			|||||||
                        <Link title="View strategy" to={`/strategies/view/${name}`} className={styles.editLink}>
 | 
					                        <Link title="View strategy" to={`/strategies/view/${name}`} className={styles.editLink}>
 | 
				
			||||||
                            <Icon name="link" />
 | 
					                            <Icon name="link" />
 | 
				
			||||||
                        </Link>
 | 
					                        </Link>
 | 
				
			||||||
                        <IconButton title="Remove strategy from toggle" name="delete" onClick={this.handleRemove} />
 | 
					                        {this.props.removeStrategy ? (
 | 
				
			||||||
 | 
					                            <IconButton title="Remove strategy from toggle" name="delete" onClick={this.handleRemove} />
 | 
				
			||||||
 | 
					                        ) : (
 | 
				
			||||||
 | 
					                            <span />
 | 
				
			||||||
 | 
					                        )}
 | 
				
			||||||
                        {connectDragSource(
 | 
					                        {connectDragSource(
 | 
				
			||||||
                            <span className={styles.reorderIcon}>
 | 
					                            <span className={styles.reorderIcon}>
 | 
				
			||||||
                                <Icon name="reorder" />
 | 
					                                <Icon name="reorder" />
 | 
				
			||||||
 | 
				
			|||||||
@ -7,13 +7,15 @@ import { Icon, FABButton, Textfield, Menu, MenuItem, Card, CardActions, List } f
 | 
				
			|||||||
import { MenuItemWithIcon, DropdownButton, styles as commonStyles } from '../common';
 | 
					import { MenuItemWithIcon, DropdownButton, styles as commonStyles } from '../common';
 | 
				
			||||||
import styles from './feature.scss';
 | 
					import styles from './feature.scss';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class FeatureListComponent extends React.PureComponent {
 | 
					export default class FeatureListComponent extends React.Component {
 | 
				
			||||||
    static propTypes = {
 | 
					    static propTypes = {
 | 
				
			||||||
        features: PropTypes.array.isRequired,
 | 
					        features: PropTypes.array.isRequired,
 | 
				
			||||||
        featureMetrics: PropTypes.object.isRequired,
 | 
					        featureMetrics: PropTypes.object.isRequired,
 | 
				
			||||||
        fetchFeatureToggles: PropTypes.func.isRequired,
 | 
					        fetchFeatureToggles: PropTypes.func,
 | 
				
			||||||
 | 
					        fetchArchive: PropTypes.func,
 | 
				
			||||||
 | 
					        revive: PropTypes.func,
 | 
				
			||||||
        updateSetting: PropTypes.func.isRequired,
 | 
					        updateSetting: PropTypes.func.isRequired,
 | 
				
			||||||
        toggleFeature: PropTypes.func.isRequired,
 | 
					        toggleFeature: PropTypes.func,
 | 
				
			||||||
        settings: PropTypes.object,
 | 
					        settings: PropTypes.object,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -22,7 +24,11 @@ export default class FeatureListComponent extends React.PureComponent {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    componentDidMount() {
 | 
					    componentDidMount() {
 | 
				
			||||||
        this.props.fetchFeatureToggles();
 | 
					        if (this.props.fetchFeatureToggles) {
 | 
				
			||||||
 | 
					            this.props.fetchFeatureToggles();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            this.props.fetchArchive();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    toggleMetrics() {
 | 
					    toggleMetrics() {
 | 
				
			||||||
@ -38,8 +44,10 @@ export default class FeatureListComponent extends React.PureComponent {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render() {
 | 
					    render() {
 | 
				
			||||||
        const { features, toggleFeature, featureMetrics, settings } = this.props;
 | 
					        const { features, toggleFeature, featureMetrics, settings, revive } = this.props;
 | 
				
			||||||
 | 
					        features.forEach(e => {
 | 
				
			||||||
 | 
					            e.reviveName = e.name;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
            <div>
 | 
					            <div>
 | 
				
			||||||
                <div className={styles.toolbar}>
 | 
					                <div className={styles.toolbar}>
 | 
				
			||||||
@ -108,6 +116,7 @@ export default class FeatureListComponent extends React.PureComponent {
 | 
				
			|||||||
                                metricsLastMinute={featureMetrics.lastMinute[feature.name]}
 | 
					                                metricsLastMinute={featureMetrics.lastMinute[feature.name]}
 | 
				
			||||||
                                feature={feature}
 | 
					                                feature={feature}
 | 
				
			||||||
                                toggleFeature={toggleFeature}
 | 
					                                toggleFeature={toggleFeature}
 | 
				
			||||||
 | 
					                                revive={revive}
 | 
				
			||||||
                            />
 | 
					                            />
 | 
				
			||||||
                        ))}
 | 
					                        ))}
 | 
				
			||||||
                    </List>
 | 
					                    </List>
 | 
				
			||||||
 | 
				
			|||||||
@ -4,10 +4,10 @@ import { updateSettingForGroup } from '../../store/settings/actions';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import FeatureListComponent from './list-component';
 | 
					import FeatureListComponent from './list-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mapStateToProps = state => {
 | 
					export const mapStateToPropsConfigurable = isFeature => state => {
 | 
				
			||||||
    const featureMetrics = state.featureMetrics.toJS();
 | 
					    const featureMetrics = state.featureMetrics.toJS();
 | 
				
			||||||
    const settings = state.settings.toJS().feature || {};
 | 
					    const settings = state.settings.toJS().feature || {};
 | 
				
			||||||
    let features = state.features.toJS();
 | 
					    let features = isFeature ? state.features.toJS() : state.archive.get('list').toArray();
 | 
				
			||||||
    if (settings.filter) {
 | 
					    if (settings.filter) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            const regex = new RegExp(settings.filter, 'i');
 | 
					            const regex = new RegExp(settings.filter, 'i');
 | 
				
			||||||
@ -69,7 +69,7 @@ const mapStateToProps = state => {
 | 
				
			|||||||
        settings,
 | 
					        settings,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					const mapStateToProps = mapStateToPropsConfigurable(true);
 | 
				
			||||||
const mapDispatchToProps = {
 | 
					const mapDispatchToProps = {
 | 
				
			||||||
    toggleFeature,
 | 
					    toggleFeature,
 | 
				
			||||||
    fetchFeatureToggles,
 | 
					    fetchFeatureToggles,
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@ import { hashHistory, Link } from 'react-router';
 | 
				
			|||||||
import HistoryComponent from '../history/history-list-toggle-container';
 | 
					import HistoryComponent from '../history/history-list-toggle-container';
 | 
				
			||||||
import MetricComponent from './metric-container';
 | 
					import MetricComponent from './metric-container';
 | 
				
			||||||
import EditFeatureToggle from './form/form-update-feature-container';
 | 
					import EditFeatureToggle from './form/form-update-feature-container';
 | 
				
			||||||
 | 
					import ViewFeatureToggle from './form/form-view-feature-container';
 | 
				
			||||||
import { styles as commonStyles } from '../common';
 | 
					import { styles as commonStyles } from '../common';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const TABS = {
 | 
					const TABS = {
 | 
				
			||||||
@ -15,24 +16,32 @@ const TABS = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class ViewFeatureToggleComponent extends React.Component {
 | 
					export default class ViewFeatureToggleComponent extends React.Component {
 | 
				
			||||||
 | 
					    isFeatureView;
 | 
				
			||||||
    constructor(props) {
 | 
					    constructor(props) {
 | 
				
			||||||
        super(props);
 | 
					        super(props);
 | 
				
			||||||
 | 
					        this.isFeatureView = !!props.fetchFeatureToggles;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static propTypes = {
 | 
					    static propTypes = {
 | 
				
			||||||
        activeTab: PropTypes.string.isRequired,
 | 
					        activeTab: PropTypes.string.isRequired,
 | 
				
			||||||
        featureToggleName: PropTypes.string.isRequired,
 | 
					        featureToggleName: PropTypes.string.isRequired,
 | 
				
			||||||
        features: PropTypes.array.isRequired,
 | 
					        features: PropTypes.array.isRequired,
 | 
				
			||||||
        toggleFeature: PropTypes.func.isRequired,
 | 
					        toggleFeature: PropTypes.func,
 | 
				
			||||||
        removeFeatureToggle: PropTypes.func.isRequired,
 | 
					        removeFeatureToggle: PropTypes.func,
 | 
				
			||||||
        fetchFeatureToggles: PropTypes.func.isRequired,
 | 
					        revive: PropTypes.func,
 | 
				
			||||||
        editFeatureToggle: PropTypes.func.isRequired,
 | 
					        fetchArchive: PropTypes.func,
 | 
				
			||||||
 | 
					        fetchFeatureToggles: PropTypes.func,
 | 
				
			||||||
 | 
					        editFeatureToggle: PropTypes.func,
 | 
				
			||||||
        featureToggle: PropTypes.object,
 | 
					        featureToggle: PropTypes.object,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    componentWillMount() {
 | 
					    componentWillMount() {
 | 
				
			||||||
        if (this.props.features.length === 0) {
 | 
					        if (this.props.features.length === 0) {
 | 
				
			||||||
            this.props.fetchFeatureToggles();
 | 
					            if (this.isFeatureView) {
 | 
				
			||||||
 | 
					                this.props.fetchFeatureToggles();
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                this.props.fetchArchive();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -42,14 +51,18 @@ export default class ViewFeatureToggleComponent extends React.Component {
 | 
				
			|||||||
        if (TABS[activeTab] === TABS.history) {
 | 
					        if (TABS[activeTab] === TABS.history) {
 | 
				
			||||||
            return <HistoryComponent toggleName={featureToggleName} />;
 | 
					            return <HistoryComponent toggleName={featureToggleName} />;
 | 
				
			||||||
        } else if (TABS[activeTab] === TABS.strategies) {
 | 
					        } else if (TABS[activeTab] === TABS.strategies) {
 | 
				
			||||||
            return <EditFeatureToggle featureToggle={featureToggle} />;
 | 
					            if (this.isFeatureView) {
 | 
				
			||||||
 | 
					                return <EditFeatureToggle featureToggle={featureToggle} />;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return <ViewFeatureToggle featureToggle={featureToggle} />;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            return <MetricComponent featureToggle={featureToggle} />;
 | 
					            return <MetricComponent featureToggle={featureToggle} />;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    goToTab(tabName, featureToggleName) {
 | 
					    goToTab(tabName, featureToggleName) {
 | 
				
			||||||
        hashHistory.push(`/features/${tabName}/${featureToggleName}`);
 | 
					        let view = this.props.fetchFeatureToggles ? 'features' : 'archive';
 | 
				
			||||||
 | 
					        hashHistory.push(`/${view}/${tabName}/${featureToggleName}`);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render() {
 | 
					    render() {
 | 
				
			||||||
@ -57,6 +70,7 @@ export default class ViewFeatureToggleComponent extends React.Component {
 | 
				
			|||||||
            featureToggle,
 | 
					            featureToggle,
 | 
				
			||||||
            features,
 | 
					            features,
 | 
				
			||||||
            activeTab,
 | 
					            activeTab,
 | 
				
			||||||
 | 
					            revive,
 | 
				
			||||||
            // setValue,
 | 
					            // setValue,
 | 
				
			||||||
            featureToggleName,
 | 
					            featureToggleName,
 | 
				
			||||||
            toggleFeature,
 | 
					            toggleFeature,
 | 
				
			||||||
@ -94,6 +108,10 @@ export default class ViewFeatureToggleComponent extends React.Component {
 | 
				
			|||||||
                hashHistory.push('/features');
 | 
					                hashHistory.push('/features');
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					        const reviveToggle = () => {
 | 
				
			||||||
 | 
					            revive(featureToggle.name);
 | 
				
			||||||
 | 
					            hashHistory.push('/features');
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
        const updateFeatureToggle = () => {
 | 
					        const updateFeatureToggle = () => {
 | 
				
			||||||
            let feature = { ...featureToggle };
 | 
					            let feature = { ...featureToggle };
 | 
				
			||||||
            if (Array.isArray(feature.strategies)) {
 | 
					            if (Array.isArray(feature.strategies)) {
 | 
				
			||||||
@ -113,16 +131,28 @@ export default class ViewFeatureToggleComponent extends React.Component {
 | 
				
			|||||||
            <Card shadow={0} className={commonStyles.fullwidth} style={{ overflow: 'visible' }}>
 | 
					            <Card shadow={0} className={commonStyles.fullwidth} style={{ overflow: 'visible' }}>
 | 
				
			||||||
                <CardTitle style={{ paddingTop: '24px', wordBreak: 'break-all' }}>{featureToggle.name}</CardTitle>
 | 
					                <CardTitle style={{ paddingTop: '24px', wordBreak: 'break-all' }}>{featureToggle.name}</CardTitle>
 | 
				
			||||||
                <CardText>
 | 
					                <CardText>
 | 
				
			||||||
                    <Textfield
 | 
					                    {this.isFeatureView ? (
 | 
				
			||||||
                        floatingLabel
 | 
					                        <Textfield
 | 
				
			||||||
                        style={{ width: '100%' }}
 | 
					                            floatingLabel
 | 
				
			||||||
                        rows={1}
 | 
					                            style={{ width: '100%' }}
 | 
				
			||||||
                        label="Description"
 | 
					                            rows={1}
 | 
				
			||||||
                        required
 | 
					                            label="Description"
 | 
				
			||||||
                        value={featureToggle.description}
 | 
					                            required
 | 
				
			||||||
                        onChange={v => setValue('description', v)}
 | 
					                            value={featureToggle.description}
 | 
				
			||||||
                        onBlur={updateFeatureToggle}
 | 
					                            onChange={v => setValue('description', v)}
 | 
				
			||||||
                    />
 | 
					                            onBlur={updateFeatureToggle}
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                    ) : (
 | 
				
			||||||
 | 
					                        <Textfield
 | 
				
			||||||
 | 
					                            disabled
 | 
				
			||||||
 | 
					                            floatingLabel
 | 
				
			||||||
 | 
					                            style={{ width: '100%' }}
 | 
				
			||||||
 | 
					                            rows={1}
 | 
				
			||||||
 | 
					                            label="Description"
 | 
				
			||||||
 | 
					                            required
 | 
				
			||||||
 | 
					                            value={featureToggle.description}
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                    )}
 | 
				
			||||||
                </CardText>
 | 
					                </CardText>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <CardActions
 | 
					                <CardActions
 | 
				
			||||||
@ -135,6 +165,7 @@ export default class ViewFeatureToggleComponent extends React.Component {
 | 
				
			|||||||
                >
 | 
					                >
 | 
				
			||||||
                    <span style={{ paddingRight: '24px' }}>
 | 
					                    <span style={{ paddingRight: '24px' }}>
 | 
				
			||||||
                        <Switch
 | 
					                        <Switch
 | 
				
			||||||
 | 
					                            disabled={this.isFeatureView}
 | 
				
			||||||
                            ripple
 | 
					                            ripple
 | 
				
			||||||
                            checked={featureToggle.enabled}
 | 
					                            checked={featureToggle.enabled}
 | 
				
			||||||
                            onChange={() => toggleFeature(featureToggle.name)}
 | 
					                            onChange={() => toggleFeature(featureToggle.name)}
 | 
				
			||||||
@ -142,9 +173,16 @@ export default class ViewFeatureToggleComponent extends React.Component {
 | 
				
			|||||||
                            {featureToggle.enabled ? 'Enabled' : 'Disabled'}
 | 
					                            {featureToggle.enabled ? 'Enabled' : 'Disabled'}
 | 
				
			||||||
                        </Switch>
 | 
					                        </Switch>
 | 
				
			||||||
                    </span>
 | 
					                    </span>
 | 
				
			||||||
                    <Button onClick={removeToggle} style={{ flexShrink: 0 }}>
 | 
					
 | 
				
			||||||
                        Archive
 | 
					                    {this.isFeatureView ? (
 | 
				
			||||||
                    </Button>
 | 
					                        <Button onClick={removeToggle} style={{ flexShrink: 0 }}>
 | 
				
			||||||
 | 
					                            Archive
 | 
				
			||||||
 | 
					                        </Button>
 | 
				
			||||||
 | 
					                    ) : (
 | 
				
			||||||
 | 
					                        <Button onClick={reviveToggle} style={{ flexShrink: 0 }}>
 | 
				
			||||||
 | 
					                            Revive
 | 
				
			||||||
 | 
					                        </Button>
 | 
				
			||||||
 | 
					                    )}
 | 
				
			||||||
                </CardActions>
 | 
					                </CardActions>
 | 
				
			||||||
                <hr />
 | 
					                <hr />
 | 
				
			||||||
                <Tabs
 | 
					                <Tabs
 | 
				
			||||||
 | 
				
			|||||||
@ -23,6 +23,7 @@ import CreateStrategies from './page/strategies/create';
 | 
				
			|||||||
import HistoryPage from './page/history';
 | 
					import HistoryPage from './page/history';
 | 
				
			||||||
import HistoryTogglePage from './page/history/toggle';
 | 
					import HistoryTogglePage from './page/history/toggle';
 | 
				
			||||||
import Archive from './page/archive';
 | 
					import Archive from './page/archive';
 | 
				
			||||||
 | 
					import ShowArchive from './page/archive/show';
 | 
				
			||||||
import Applications from './page/applications';
 | 
					import Applications from './page/applications';
 | 
				
			||||||
import ApplicationView from './page/applications/view';
 | 
					import ApplicationView from './page/applications/view';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -68,7 +69,7 @@ ReactDOM.render(
 | 
				
			|||||||
                </Route>
 | 
					                </Route>
 | 
				
			||||||
                <Route pageTitle="Archived Toggles" link="/archive">
 | 
					                <Route pageTitle="Archived Toggles" link="/archive">
 | 
				
			||||||
                    <Route pageTitle="Archived Toggles" path="/archive" component={Archive} />
 | 
					                    <Route pageTitle="Archived Toggles" path="/archive" component={Archive} />
 | 
				
			||||||
                    <Route pageTitle=":name" path="/archive/:name" component={Archive} />
 | 
					                    <Route pageTitle=":name" path="/archive/:activeTab/:name" component={ShowArchive} />
 | 
				
			||||||
                </Route>
 | 
					                </Route>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <Route pageTitle="Applications" link="/applications">
 | 
					                <Route pageTitle="Applications" link="/applications">
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										14
									
								
								frontend/src/page/archive/show.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								frontend/src/page/archive/show.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					import React, { PureComponent } from 'react';
 | 
				
			||||||
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
 | 
					import ViewFeatureToggle from './../../component/archive/view-container';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class Features extends PureComponent {
 | 
				
			||||||
 | 
					    static propTypes = {
 | 
				
			||||||
 | 
					        params: PropTypes.object.isRequired,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    render() {
 | 
				
			||||||
 | 
					        const { params } = this.props;
 | 
				
			||||||
 | 
					        return <ViewFeatureToggle featureToggleName={params.name} activeTab={params.activeTab} />;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user