mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	Merge pull request #221 from Unleash/feat/stale-flag
This commit is contained in:
		
						commit
						99514009bb
					
				@ -38,7 +38,8 @@
 | 
				
			|||||||
    "prepublish": "npm run build"
 | 
					    "prepublish": "npm run build"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "main": "./index.js",
 | 
					  "main": "./index.js",
 | 
				
			||||||
  "dependencies": {},
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@babel/core": "^7.9.0",
 | 
					    "@babel/core": "^7.9.0",
 | 
				
			||||||
    "@babel/plugin-proposal-class-properties": "^7.8.3",
 | 
					    "@babel/plugin-proposal-class-properties": "^7.8.3",
 | 
				
			||||||
@ -84,6 +85,7 @@
 | 
				
			|||||||
    "react-redux": "^7.2.0",
 | 
					    "react-redux": "^7.2.0",
 | 
				
			||||||
    "react-router-dom": "^5.1.2",
 | 
					    "react-router-dom": "^5.1.2",
 | 
				
			||||||
    "react-select": "^3.1.0",
 | 
					    "react-select": "^3.1.0",
 | 
				
			||||||
 | 
					    "react-timeago": "^4.4.0",
 | 
				
			||||||
    "react-test-renderer": "^16.13.1",
 | 
					    "react-test-renderer": "^16.13.1",
 | 
				
			||||||
    "redux": "^4.0.5",
 | 
					    "redux": "^4.0.5",
 | 
				
			||||||
    "redux-devtools": "^3.5.0",
 | 
					    "redux-devtools": "^3.5.0",
 | 
				
			||||||
 | 
				
			|||||||
@ -81,3 +81,8 @@
 | 
				
			|||||||
    text-transform: none;
 | 
					    text-transform: none;
 | 
				
			||||||
    font-weight: normal;
 | 
					    font-weight: normal;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.toggleName {
 | 
				
			||||||
 | 
					    color: #37474f !important;
 | 
				
			||||||
 | 
					    font-weight: 500;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -140,8 +140,8 @@ IconLink.propTypes = {
 | 
				
			|||||||
    icon: PropTypes.string,
 | 
					    icon: PropTypes.string,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const DropdownButton = ({ label, id }) => (
 | 
					export const DropdownButton = ({ label, id, className }) => (
 | 
				
			||||||
    <Button id={id} className={styles.dropdownButton}>
 | 
					    <Button id={id} className={className || styles.dropdownButton}>
 | 
				
			||||||
        {label}
 | 
					        {label}
 | 
				
			||||||
        <Icon name="arrow_drop_down" className="mdl-color-text--grey-600" />
 | 
					        <Icon name="arrow_drop_down" className="mdl-color-text--grey-600" />
 | 
				
			||||||
    </Button>
 | 
					    </Button>
 | 
				
			||||||
 | 
				
			|||||||
@ -34,8 +34,23 @@ exports[`renders correctly with one feature 1`] = `
 | 
				
			|||||||
      className="listLink truncate"
 | 
					      className="listLink truncate"
 | 
				
			||||||
      href="/features/strategies/Another"
 | 
					      href="/features/strategies/Another"
 | 
				
			||||||
      onClick={[Function]}
 | 
					      onClick={[Function]}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <span
 | 
				
			||||||
 | 
					        className="toggleName"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        Another
 | 
					        Another
 | 
				
			||||||
 | 
					         
 | 
				
			||||||
 | 
					      </span>
 | 
				
			||||||
 | 
					      <small
 | 
				
			||||||
 | 
					        className="mdl-color-text--blue-grey-300"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <time
 | 
				
			||||||
 | 
					          dateTime="2018-02-04T20:27:52.127Z"
 | 
				
			||||||
 | 
					          title="2018-02-04T20:27:52.127Z"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          3 years ago
 | 
				
			||||||
 | 
					        </time>
 | 
				
			||||||
 | 
					      </small>
 | 
				
			||||||
      <span
 | 
					      <span
 | 
				
			||||||
        className="mdl-list__item-sub-title truncate"
 | 
					        className="mdl-list__item-sub-title truncate"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
@ -47,7 +62,7 @@ exports[`renders correctly with one feature 1`] = `
 | 
				
			|||||||
    className="listItemStrategies hideLt920"
 | 
					    className="listItemStrategies hideLt920"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <react-mdl-Chip
 | 
					    <react-mdl-Chip
 | 
				
			||||||
      className="mdl-color--blue-grey-100"
 | 
					      className="typeChip"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
  </span>
 | 
					  </span>
 | 
				
			||||||
  <span />
 | 
					  <span />
 | 
				
			||||||
@ -87,8 +102,23 @@ exports[`renders correctly with one feature without permission 1`] = `
 | 
				
			|||||||
      className="listLink truncate"
 | 
					      className="listLink truncate"
 | 
				
			||||||
      href="/features/strategies/Another"
 | 
					      href="/features/strategies/Another"
 | 
				
			||||||
      onClick={[Function]}
 | 
					      onClick={[Function]}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <span
 | 
				
			||||||
 | 
					        className="toggleName"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        Another
 | 
					        Another
 | 
				
			||||||
 | 
					         
 | 
				
			||||||
 | 
					      </span>
 | 
				
			||||||
 | 
					      <small
 | 
				
			||||||
 | 
					        className="mdl-color-text--blue-grey-300"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <time
 | 
				
			||||||
 | 
					          dateTime="2018-02-04T20:27:52.127Z"
 | 
				
			||||||
 | 
					          title="2018-02-04T20:27:52.127Z"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          3 years ago
 | 
				
			||||||
 | 
					        </time>
 | 
				
			||||||
 | 
					      </small>
 | 
				
			||||||
      <span
 | 
					      <span
 | 
				
			||||||
        className="mdl-list__item-sub-title truncate"
 | 
					        className="mdl-list__item-sub-title truncate"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
@ -100,7 +130,7 @@ exports[`renders correctly with one feature without permission 1`] = `
 | 
				
			|||||||
    className="listItemStrategies hideLt920"
 | 
					    className="listItemStrategies hideLt920"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <react-mdl-Chip
 | 
					    <react-mdl-Chip
 | 
				
			||||||
      className="mdl-color--blue-grey-100"
 | 
					      className="typeChip"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
  </span>
 | 
					  </span>
 | 
				
			||||||
  <span />
 | 
					  <span />
 | 
				
			||||||
 | 
				
			|||||||
@ -136,6 +136,12 @@ exports[`renders correctly with one feature 1`] = `
 | 
				
			|||||||
        >
 | 
					        >
 | 
				
			||||||
          Enabled
 | 
					          Enabled
 | 
				
			||||||
        </react-mdl-MenuItem>
 | 
					        </react-mdl-MenuItem>
 | 
				
			||||||
 | 
					        <react-mdl-MenuItem
 | 
				
			||||||
 | 
					          data-target="stale"
 | 
				
			||||||
 | 
					          disabled={false}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          Stale
 | 
				
			||||||
 | 
					        </react-mdl-MenuItem>
 | 
				
			||||||
        <react-mdl-MenuItem
 | 
					        <react-mdl-MenuItem
 | 
				
			||||||
          data-target="created"
 | 
					          data-target="created"
 | 
				
			||||||
          disabled={false}
 | 
					          disabled={false}
 | 
				
			||||||
@ -301,6 +307,12 @@ exports[`renders correctly with one feature without permissions 1`] = `
 | 
				
			|||||||
        >
 | 
					        >
 | 
				
			||||||
          Enabled
 | 
					          Enabled
 | 
				
			||||||
        </react-mdl-MenuItem>
 | 
					        </react-mdl-MenuItem>
 | 
				
			||||||
 | 
					        <react-mdl-MenuItem
 | 
				
			||||||
 | 
					          data-target="stale"
 | 
				
			||||||
 | 
					          disabled={false}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          Stale
 | 
				
			||||||
 | 
					        </react-mdl-MenuItem>
 | 
				
			||||||
        <react-mdl-MenuItem
 | 
					        <react-mdl-MenuItem
 | 
				
			||||||
          data-target="created"
 | 
					          data-target="created"
 | 
				
			||||||
          disabled={false}
 | 
					          disabled={false}
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,19 @@ exports[`renders correctly with one feature 1`] = `
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
>
 | 
					>
 | 
				
			||||||
 | 
					  <react-mdl-Chip
 | 
				
			||||||
 | 
					    className="mdl-color--light-green-500 mdl-color-text--white mdl-shadow--2dp"
 | 
				
			||||||
 | 
					    style={
 | 
				
			||||||
 | 
					      Object {
 | 
				
			||||||
 | 
					        "position": "absolute",
 | 
				
			||||||
 | 
					        "right": "4px",
 | 
				
			||||||
 | 
					        "top": "4px",
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    title="Feature toggle is active."
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
 | 
					    Active
 | 
				
			||||||
 | 
					  </react-mdl-Chip>
 | 
				
			||||||
  <react-mdl-CardTitle
 | 
					  <react-mdl-CardTitle
 | 
				
			||||||
    style={
 | 
					    style={
 | 
				
			||||||
      Object {
 | 
					      Object {
 | 
				
			||||||
@ -73,6 +86,39 @@ exports[`renders correctly with one feature 1`] = `
 | 
				
			|||||||
      </react-mdl-Switch>
 | 
					      </react-mdl-Switch>
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
 | 
					      <span>
 | 
				
			||||||
 | 
					        <react-mdl-Button
 | 
				
			||||||
 | 
					          className="mdl-button"
 | 
				
			||||||
 | 
					          id="update_status"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          Status
 | 
				
			||||||
 | 
					          <react-mdl-Icon
 | 
				
			||||||
 | 
					            className="mdl-color-text--grey-600"
 | 
				
			||||||
 | 
					            name="arrow_drop_down"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </react-mdl-Button>
 | 
				
			||||||
 | 
					        <react-mdl-Menu
 | 
				
			||||||
 | 
					          onClick={[Function]}
 | 
				
			||||||
 | 
					          style={
 | 
				
			||||||
 | 
					            Object {
 | 
				
			||||||
 | 
					              "width": "168px",
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          target="update_status"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <react-mdl-MenuItem
 | 
				
			||||||
 | 
					            data-target="active"
 | 
				
			||||||
 | 
					            disabled={true}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            Set toggle Active
 | 
				
			||||||
 | 
					          </react-mdl-MenuItem>
 | 
				
			||||||
 | 
					          <react-mdl-MenuItem
 | 
				
			||||||
 | 
					            data-target="stale"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            Mark toggle as Stale
 | 
				
			||||||
 | 
					          </react-mdl-MenuItem>
 | 
				
			||||||
 | 
					        </react-mdl-Menu>
 | 
				
			||||||
 | 
					      </span>
 | 
				
			||||||
      <a
 | 
					      <a
 | 
				
			||||||
        href="/features/copy/Another"
 | 
					        href="/features/copy/Another"
 | 
				
			||||||
        onClick={[Function]}
 | 
					        onClick={[Function]}
 | 
				
			||||||
 | 
				
			|||||||
@ -2,9 +2,11 @@ import React from 'react';
 | 
				
			|||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import { Link } from 'react-router-dom';
 | 
					import { Link } from 'react-router-dom';
 | 
				
			||||||
import { Switch, Chip, ListItem, ListItemAction, Icon } from 'react-mdl';
 | 
					import { Switch, Chip, ListItem, ListItemAction, Icon } from 'react-mdl';
 | 
				
			||||||
 | 
					import TimeAgo from 'react-timeago';
 | 
				
			||||||
import Progress from './progress';
 | 
					import Progress from './progress';
 | 
				
			||||||
import { UPDATE_FEATURE } from '../../permissions';
 | 
					import { UPDATE_FEATURE } from '../../permissions';
 | 
				
			||||||
import { calc, styles as commonStyles } from '../common';
 | 
					import { calc, styles as commonStyles } from '../common';
 | 
				
			||||||
 | 
					import StatusComponent from './status-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import styles from './feature.scss';
 | 
					import styles from './feature.scss';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -17,7 +19,7 @@ const Feature = ({
 | 
				
			|||||||
    revive,
 | 
					    revive,
 | 
				
			||||||
    hasPermission,
 | 
					    hasPermission,
 | 
				
			||||||
}) => {
 | 
					}) => {
 | 
				
			||||||
    const { name, description, enabled, type } = feature;
 | 
					    const { name, description, enabled, type, stale, createdAt } = 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 =
 | 
				
			||||||
@ -25,7 +27,6 @@ const Feature = ({
 | 
				
			|||||||
        (showLastHour
 | 
					        (showLastHour
 | 
				
			||||||
            ? calc(metricsLastHour.yes, metricsLastHour.yes + metricsLastHour.no, 0)
 | 
					            ? calc(metricsLastHour.yes, metricsLastHour.yes + metricsLastHour.no, 0)
 | 
				
			||||||
            : calc(metricsLastMinute.yes, metricsLastMinute.yes + metricsLastMinute.no, 0));
 | 
					            : calc(metricsLastMinute.yes, metricsLastMinute.yes + metricsLastMinute.no, 0));
 | 
				
			||||||
    const typeChip = <Chip className="mdl-color--blue-grey-100">{type}</Chip>;
 | 
					 | 
				
			||||||
    const featureUrl = toggleFeature === undefined ? `/archive/strategies/${name}` : `/features/strategies/${name}`;
 | 
					    const featureUrl = toggleFeature === undefined ? `/archive/strategies/${name}` : `/features/strategies/${name}`;
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <ListItem twoLine>
 | 
					        <ListItem twoLine>
 | 
				
			||||||
@ -47,11 +48,17 @@ 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 to={featureUrl} className={[commonStyles.listLink, commonStyles.truncate].join(' ')}>
 | 
					                <Link to={featureUrl} className={[commonStyles.listLink, commonStyles.truncate].join(' ')}>
 | 
				
			||||||
                    {name}
 | 
					                    <span className={commonStyles.toggleName}>{name} </span>
 | 
				
			||||||
 | 
					                    <small className="mdl-color-text--blue-grey-300">
 | 
				
			||||||
 | 
					                        <TimeAgo date={createdAt} />
 | 
				
			||||||
 | 
					                    </small>
 | 
				
			||||||
                    <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>
 | 
				
			||||||
            </span>
 | 
					            </span>
 | 
				
			||||||
            <span className={[styles.listItemStrategies, commonStyles.hideLt920].join(' ')}>{typeChip}</span>
 | 
					            <span className={[styles.listItemStrategies, commonStyles.hideLt920].join(' ')}>
 | 
				
			||||||
 | 
					                <StatusComponent stale={stale} showActive={false} />
 | 
				
			||||||
 | 
					                <Chip className={styles.typeChip}>{type}</Chip>
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
            {revive && hasPermission(UPDATE_FEATURE) ? (
 | 
					            {revive && hasPermission(UPDATE_FEATURE) ? (
 | 
				
			||||||
                <ListItemAction onClick={() => revive(feature.name)}>
 | 
					                <ListItemAction onClick={() => revive(feature.name)}>
 | 
				
			||||||
                    <Icon name="undo" />
 | 
					                    <Icon name="undo" />
 | 
				
			||||||
 | 
				
			|||||||
@ -35,6 +35,7 @@
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.typeChip {
 | 
					.typeChip {
 | 
				
			||||||
    margin-left: 8px !important;
 | 
					    margin: 0 8px !important;
 | 
				
			||||||
    background: #d3c1ff;
 | 
					    box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12);
 | 
				
			||||||
 | 
					    background-color: #b0bec5 !important;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -111,6 +111,9 @@ export default class FeatureListComponent extends React.Component {
 | 
				
			|||||||
                            <MenuItem disabled={settings.sort === 'enabled'} data-target="enabled">
 | 
					                            <MenuItem disabled={settings.sort === 'enabled'} data-target="enabled">
 | 
				
			||||||
                                Enabled
 | 
					                                Enabled
 | 
				
			||||||
                            </MenuItem>
 | 
					                            </MenuItem>
 | 
				
			||||||
 | 
					                            <MenuItem disabled={settings.sort === 'stale'} data-target="stale">
 | 
				
			||||||
 | 
					                                Stale
 | 
				
			||||||
 | 
					                            </MenuItem>
 | 
				
			||||||
                            <MenuItem disabled={settings.sort === 'created'} data-target="created">
 | 
					                            <MenuItem disabled={settings.sort === 'created'} data-target="created">
 | 
				
			||||||
                                Created
 | 
					                                Created
 | 
				
			||||||
                            </MenuItem>
 | 
					                            </MenuItem>
 | 
				
			||||||
 | 
				
			|||||||
@ -33,6 +33,11 @@ export const mapStateToPropsConfigurable = isFeature => state => {
 | 
				
			|||||||
            // eslint-disable-next-line
 | 
					            // eslint-disable-next-line
 | 
				
			||||||
            a.enabled === b.enabled ? 0 : a.enabled ? -1 : 1
 | 
					            a.enabled === b.enabled ? 0 : a.enabled ? -1 : 1
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					    } else if (settings.sort === 'stale') {
 | 
				
			||||||
 | 
					        features = features.sort((a, b) =>
 | 
				
			||||||
 | 
					            // eslint-disable-next-line
 | 
				
			||||||
 | 
					            a.stale === b.stale ? 0 : a.stale ? -1 : 1
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
    } else if (settings.sort === 'created') {
 | 
					    } else if (settings.sort === 'created') {
 | 
				
			||||||
        features = features.sort((a, b) => (new Date(a.createdAt) > new Date(b.createdAt) ? -1 : 1));
 | 
					        features = features.sort((a, b) => (new Date(a.createdAt) > new Date(b.createdAt) ? -1 : 1));
 | 
				
			||||||
    } else if (settings.sort === 'name') {
 | 
					    } else if (settings.sort === 'name') {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										28
									
								
								frontend/src/component/feature/status-component.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								frontend/src/component/feature/status-component.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { Chip } from 'react-mdl';
 | 
				
			||||||
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function StatusComponent({ stale, style, showActive = true }) {
 | 
				
			||||||
 | 
					    if (!stale && !showActive) {
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const className = stale
 | 
				
			||||||
 | 
					        ? 'mdl-color--red mdl-color-text--white mdl-shadow--2dp'
 | 
				
			||||||
 | 
					        : 'mdl-color--light-green-500 mdl-color-text--white mdl-shadow--2dp';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const title = stale ? 'Feature toggle is deprecated.' : 'Feature toggle is active.';
 | 
				
			||||||
 | 
					    const value = stale ? 'Stale' : 'Active';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <Chip style={style} title={title} className={className}>
 | 
				
			||||||
 | 
					            {value}
 | 
				
			||||||
 | 
					        </Chip>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					StatusComponent.propTypes = {
 | 
				
			||||||
 | 
					    stale: PropTypes.bool.isRequired,
 | 
				
			||||||
 | 
					    style: PropTypes.object,
 | 
				
			||||||
 | 
					    showActive: PropTypes.bool,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										37
									
								
								frontend/src/component/feature/status-update-component.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								frontend/src/component/feature/status-update-component.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { Menu, MenuItem } from 'react-mdl';
 | 
				
			||||||
 | 
					import { DropdownButton } from '../common';
 | 
				
			||||||
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function StatusUpdateComponent({ stale, updateStale }) {
 | 
				
			||||||
 | 
					    function setStatus(field) {
 | 
				
			||||||
 | 
					        if (field === 'active') {
 | 
				
			||||||
 | 
					            updateStale(false);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            updateStale(true);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <span>
 | 
				
			||||||
 | 
					            <DropdownButton className="mdl-button" id="update_status" label="Status" />
 | 
				
			||||||
 | 
					            <Menu
 | 
				
			||||||
 | 
					                target="update_status"
 | 
				
			||||||
 | 
					                onClick={e => setStatus(e.target.getAttribute('data-target'))}
 | 
				
			||||||
 | 
					                style={{ width: '168px' }}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					                <MenuItem disabled={!stale} data-target="active">
 | 
				
			||||||
 | 
					                    Set toggle Active
 | 
				
			||||||
 | 
					                </MenuItem>
 | 
				
			||||||
 | 
					                <MenuItem disabled={stale} data-target="stale">
 | 
				
			||||||
 | 
					                    Mark toggle as Stale
 | 
				
			||||||
 | 
					                </MenuItem>
 | 
				
			||||||
 | 
					            </Menu>
 | 
				
			||||||
 | 
					        </span>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					StatusUpdateComponent.propTypes = {
 | 
				
			||||||
 | 
					    stale: PropTypes.bool.isRequired,
 | 
				
			||||||
 | 
					    updateStale: PropTypes.func.isRequired,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -12,6 +12,8 @@ import FeatureTypeSelect from './form/feature-type-select-container';
 | 
				
			|||||||
import UpdateDescriptionComponent from './form/update-description-component';
 | 
					import UpdateDescriptionComponent from './form/update-description-component';
 | 
				
			||||||
import { styles as commonStyles } from '../common';
 | 
					import { styles as commonStyles } from '../common';
 | 
				
			||||||
import { CREATE_FEATURE, DELETE_FEATURE, UPDATE_FEATURE } from '../../permissions';
 | 
					import { CREATE_FEATURE, DELETE_FEATURE, UPDATE_FEATURE } from '../../permissions';
 | 
				
			||||||
 | 
					import StatusComponent from './status-component';
 | 
				
			||||||
 | 
					import StatusUpdateComponent from './status-update-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const TABS = {
 | 
					const TABS = {
 | 
				
			||||||
    strategies: 0,
 | 
					    strategies: 0,
 | 
				
			||||||
@ -32,6 +34,7 @@ export default class ViewFeatureToggleComponent extends React.Component {
 | 
				
			|||||||
        featureToggleName: PropTypes.string.isRequired,
 | 
					        featureToggleName: PropTypes.string.isRequired,
 | 
				
			||||||
        features: PropTypes.array.isRequired,
 | 
					        features: PropTypes.array.isRequired,
 | 
				
			||||||
        toggleFeature: PropTypes.func,
 | 
					        toggleFeature: PropTypes.func,
 | 
				
			||||||
 | 
					        setStale: PropTypes.func,
 | 
				
			||||||
        removeFeatureToggle: PropTypes.func,
 | 
					        removeFeatureToggle: PropTypes.func,
 | 
				
			||||||
        revive: PropTypes.func,
 | 
					        revive: PropTypes.func,
 | 
				
			||||||
        fetchArchive: PropTypes.func,
 | 
					        fetchArchive: PropTypes.func,
 | 
				
			||||||
@ -159,8 +162,20 @@ export default class ViewFeatureToggleComponent extends React.Component {
 | 
				
			|||||||
            this.props.editFeatureToggle(feature);
 | 
					            this.props.editFeatureToggle(feature);
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const updateStale = stale => {
 | 
				
			||||||
 | 
					            this.props.setStale(stale, featureToggleName);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
            <Card shadow={0} className={commonStyles.fullwidth} style={{ overflow: 'visible' }}>
 | 
					            <Card shadow={0} className={commonStyles.fullwidth} style={{ overflow: 'visible' }}>
 | 
				
			||||||
 | 
					                <StatusComponent
 | 
				
			||||||
 | 
					                    stale={featureToggle.stale}
 | 
				
			||||||
 | 
					                    style={{
 | 
				
			||||||
 | 
					                        position: 'absolute',
 | 
				
			||||||
 | 
					                        right: '4px',
 | 
				
			||||||
 | 
					                        top: '4px',
 | 
				
			||||||
 | 
					                    }}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
                <CardTitle style={{ wordBreak: 'break-all', paddingBottom: 0 }}>{featureToggle.name} </CardTitle>
 | 
					                <CardTitle style={{ wordBreak: 'break-all', paddingBottom: 0 }}>{featureToggle.name} </CardTitle>
 | 
				
			||||||
                <CardText>
 | 
					                <CardText>
 | 
				
			||||||
                    <UpdateDescriptionComponent
 | 
					                    <UpdateDescriptionComponent
 | 
				
			||||||
@ -201,6 +216,7 @@ export default class ViewFeatureToggleComponent extends React.Component {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                    {this.isFeatureView ? (
 | 
					                    {this.isFeatureView ? (
 | 
				
			||||||
                        <div>
 | 
					                        <div>
 | 
				
			||||||
 | 
					                            <StatusUpdateComponent stale={featureToggle.stale} updateStale={updateStale} />
 | 
				
			||||||
                            <Link
 | 
					                            <Link
 | 
				
			||||||
                                to={`/features/copy/${featureToggle.name}`}
 | 
					                                to={`/features/copy/${featureToggle.name}`}
 | 
				
			||||||
                                title="Create new feature toggle by cloning configuration"
 | 
					                                title="Create new feature toggle by cloning configuration"
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ import { connect } from 'react-redux';
 | 
				
			|||||||
import {
 | 
					import {
 | 
				
			||||||
    fetchFeatureToggles,
 | 
					    fetchFeatureToggles,
 | 
				
			||||||
    toggleFeature,
 | 
					    toggleFeature,
 | 
				
			||||||
 | 
					    setStale,
 | 
				
			||||||
    removeFeatureToggle,
 | 
					    removeFeatureToggle,
 | 
				
			||||||
    editFeatureToggle,
 | 
					    editFeatureToggle,
 | 
				
			||||||
} from './../../store/feature-actions';
 | 
					} from './../../store/feature-actions';
 | 
				
			||||||
@ -20,6 +21,7 @@ export default connect(
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        fetchFeatureToggles,
 | 
					        fetchFeatureToggles,
 | 
				
			||||||
        toggleFeature,
 | 
					        toggleFeature,
 | 
				
			||||||
 | 
					        setStale,
 | 
				
			||||||
        removeFeatureToggle,
 | 
					        removeFeatureToggle,
 | 
				
			||||||
        editFeatureToggle,
 | 
					        editFeatureToggle,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -62,6 +62,17 @@ function toggle(enable, name) {
 | 
				
			|||||||
    }).then(throwIfNotSuccess);
 | 
					    }).then(throwIfNotSuccess);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function setStale(isStale, name) {
 | 
				
			||||||
 | 
					    const action = isStale ? 'on' : 'off';
 | 
				
			||||||
 | 
					    return fetch(`${URI}/${name}/stale/${action}`, {
 | 
				
			||||||
 | 
					        method: 'POST',
 | 
				
			||||||
 | 
					        headers,
 | 
				
			||||||
 | 
					        credentials: 'include',
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					        .then(throwIfNotSuccess)
 | 
				
			||||||
 | 
					        .then(response => response.json());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function remove(featureToggleName) {
 | 
					function remove(featureToggleName) {
 | 
				
			||||||
    return fetch(`${URI}/${featureToggleName}`, {
 | 
					    return fetch(`${URI}/${featureToggleName}`, {
 | 
				
			||||||
        method: 'DELETE',
 | 
					        method: 'DELETE',
 | 
				
			||||||
@ -75,5 +86,6 @@ export default {
 | 
				
			|||||||
    validate,
 | 
					    validate,
 | 
				
			||||||
    update,
 | 
					    update,
 | 
				
			||||||
    toggle,
 | 
					    toggle,
 | 
				
			||||||
 | 
					    setStale,
 | 
				
			||||||
    remove,
 | 
					    remove,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -26,6 +26,13 @@ export function toggleFeature(enable, name) {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function setStale(stale, name) {
 | 
				
			||||||
 | 
					    debug('Set stale property on feature toggle ', name);
 | 
				
			||||||
 | 
					    return dispatch => {
 | 
				
			||||||
 | 
					        dispatch(requestSetStaleFeatureToggle(stale, name));
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function editFeatureToggle(featureToggle) {
 | 
					export function editFeatureToggle(featureToggle) {
 | 
				
			||||||
    debug('Update feature toggle ', featureToggle);
 | 
					    debug('Update feature toggle ', featureToggle);
 | 
				
			||||||
    return dispatch => {
 | 
					    return dispatch => {
 | 
				
			||||||
@ -76,6 +83,21 @@ export function requestToggleFeatureToggle(enable, name) {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function requestSetStaleFeatureToggle(stale, name) {
 | 
				
			||||||
 | 
					    return dispatch => {
 | 
				
			||||||
 | 
					        dispatch({ type: START_UPDATE_FEATURE_TOGGLE });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return api
 | 
				
			||||||
 | 
					            .setStale(stale, name)
 | 
				
			||||||
 | 
					            .then(featureToggle => {
 | 
				
			||||||
 | 
					                const info = `${name} marked as ${stale ? 'Stale' : 'Active'}.`;
 | 
				
			||||||
 | 
					                setTimeout(() => dispatch({ type: MUTE_ERROR, error: info }), 1000);
 | 
				
			||||||
 | 
					                dispatch({ type: UPDATE_FEATURE_TOGGLE, featureToggle, info });
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(dispatchAndThrow(dispatch, ERROR_UPDATE_FEATURE_TOGGLE));
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function requestUpdateFeatureToggle(featureToggle) {
 | 
					export function requestUpdateFeatureToggle(featureToggle) {
 | 
				
			||||||
    return dispatch => {
 | 
					    return dispatch => {
 | 
				
			||||||
        dispatch({ type: START_UPDATE_FEATURE_TOGGLE });
 | 
					        dispatch({ type: START_UPDATE_FEATURE_TOGGLE });
 | 
				
			||||||
 | 
				
			|||||||
@ -7965,6 +7965,11 @@ react-test-renderer@^16.0.0-0, react-test-renderer@^16.13.1:
 | 
				
			|||||||
    react-is "^16.8.6"
 | 
					    react-is "^16.8.6"
 | 
				
			||||||
    scheduler "^0.19.1"
 | 
					    scheduler "^0.19.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					react-timeago@^4.4.0:
 | 
				
			||||||
 | 
					  version "4.4.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/react-timeago/-/react-timeago-4.4.0.tgz#4520dd9ba63551afc4d709819f52b14b9343ba2b"
 | 
				
			||||||
 | 
					  integrity sha512-Zj8RchTqZEH27LAANemzMR2RpotbP2aMd+UIajfYMZ9KW4dMcViUVKzC7YmqfiqlFfz8B0bjDw2xUBjmcxDngA==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
react-transition-group@^4.3.0:
 | 
					react-transition-group@^4.3.0:
 | 
				
			||||||
  version "4.4.1"
 | 
					  version "4.4.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9"
 | 
					  resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9"
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user