1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-31 00:16:47 +01:00

Merge pull request #121 from corinnekrych/archive.revisited

Archive.revisited
This commit is contained in:
ckrych 2018-03-28 13:50:02 +02:00 committed by GitHub
commit 4b64762671
22 changed files with 234 additions and 401 deletions

View File

@ -1,5 +1,6 @@
module.exports = {
Card: 'react-mdl-Card',
CardActions: 'react-mdl-CardActions',
CardTitle: 'react-mdl-CardTitle',
CardText: 'react-mdl-CardText',
CardMenu: 'react-mdl-CardMenu',

View File

@ -192,11 +192,11 @@ export default class App extends Component {
<FooterSection type="middle">
<FooterDropDownSection title="Menu">
<FooterLinkList>
{createListItem('/features', 'Feature Toggles')}
{createListItem('/strategies', 'Strategies')}
{createListItem('/history', 'Event History')}
{createListItem('/archive', 'Archived Toggles')}
{createListItem('/applications', 'Applications')}
{createListItem('/features', 'Feature Toggles', '')}
{createListItem('/strategies', 'Strategies', '')}
{createListItem('/history', 'Event History', '')}
{createListItem('/archive', 'Archived Toggles', '')}
{createListItem('/applications', 'Applications', '')}
<a href="/api/admin/user/logout">Sign out</a>
</FooterLinkList>
</FooterDropDownSection>

View File

@ -1,5 +0,0 @@
{
"env": {
"jest": true
}
}

View File

@ -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>
`;

View File

@ -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();
});

View File

@ -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;

View File

@ -1,15 +1,16 @@
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 { updateSettingForGroup } from './../../store/settings/actions';
import { mapStateToPropsConfigurable } from '../feature/list-container';
const mapStateToProps = state => {
const archive = state.archive.get('list').toArray();
return {
archive,
};
const mapStateToProps = mapStateToPropsConfigurable(false);
const mapDispatchToProps = {
fetchArchive,
revive,
updateSetting: updateSettingForGroup('feature'),
};
const ArchiveListContainer = connect(mapStateToProps, { fetchArchive, revive })(ListComponent);
const ArchiveListContainer = connect(mapStateToProps, mapDispatchToProps)(FeatureListComponent);
export default ArchiveListContainer;

View 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);

View File

@ -22,6 +22,7 @@ exports[`renders correctly with one feature 1`] = `
>
<react-mdl-Switch
checked={false}
disabled={true}
onChange={[Function]}
title="Toggle Another"
/>
@ -51,5 +52,6 @@ exports[`renders correctly with one feature 1`] = `
gradualRolloutRandom
</react-mdl-Chip>
</span>
<span />
</react-mdl-ListItem>
`;

View File

@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router';
import { Switch, Chip, ListItem } from 'react-mdl';
import { Switch, Chip, ListItem, ListItemAction, Icon } from 'react-mdl';
import Progress from './progress';
import { calc, styles as commonStyles } from '../common';
@ -13,12 +13,11 @@ const Feature = ({
settings,
metricsLastHour = { yes: 0, no: 0, isFallback: true },
metricsLastMinute = { yes: 0, no: 0, isFallback: true },
revive,
}) => {
const { name, description, enabled, strategies } = feature;
const { showLastHour = false } = settings;
const isStale = showLastHour ? metricsLastHour.isFallback : metricsLastMinute.isFallback;
const percent =
1 *
(showLastHour
@ -27,7 +26,6 @@ const Feature = ({
const strategiesToShow = Math.min(strategies.length, 3);
const remainingStrategies = strategies.length - strategiesToShow;
const strategyChips =
strategies &&
strategies.slice(0, strategiesToShow).map((s, i) => (
@ -36,7 +34,7 @@ const Feature = ({
</Chip>
));
const summaryChip = remainingStrategies > 0 && <Chip className={styles.strategyChip}>+{remainingStrategies}</Chip>;
const featureUrl = toggleFeature === undefined ? `/archive/strategies/${name}` : `/features/strategies/${name}`;
return (
<ListItem twoLine>
<span className={styles.listItemMetric}>
@ -44,6 +42,7 @@ const Feature = ({
</span>
<span className={styles.listItemToggle}>
<Switch
disabled={toggleFeature !== undefined}
title={`Toggle ${name}`}
key="left-actions"
onChange={() => toggleFeature(name)}
@ -51,10 +50,7 @@ const Feature = ({
/>
</span>
<span className={['mdl-list__item-primary-content', styles.listItemLink].join(' ')}>
<Link
to={`/features/strategies/${name}`}
className={[commonStyles.listLink, commonStyles.truncate].join(' ')}
>
<Link to={featureUrl} className={[commonStyles.listLink, commonStyles.truncate].join(' ')}>
{name}
<span className={['mdl-list__item-sub-title', commonStyles.truncate].join(' ')}>{description}</span>
</Link>
@ -63,6 +59,13 @@ const Feature = ({
{strategyChips}
{summaryChip}
</span>
{revive ? (
<ListItemAction onClick={() => revive(feature.name)}>
<Icon name="undo" />
</ListItemAction>
) : (
<span />
)}
</ListItem>
);
};
@ -73,6 +76,7 @@ Feature.propTypes = {
settings: PropTypes.object,
metricsLastHour: PropTypes.object,
metricsLastMinute: PropTypes.object,
revive: PropTypes.func,
};
export default Feature;

View File

@ -45,7 +45,7 @@ const prepare = (methods, dispatch) => {
methods.onCancel = evt => {
evt.preventDefault();
methods.clear();
window.history.back();
hashHistory.push(`/features`);
};
methods.addStrategy = v => {

View File

@ -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" />&nbsp;&nbsp;&nbsp; Cancel
</Button>
</section>
);
}
}
ViewFeatureComponent.propTypes = {
input: PropTypes.object,
onCancel: PropTypes.func.isRequired,
initCallRequired: PropTypes.bool,
init: PropTypes.func,
};
export default ViewFeatureComponent;

View File

@ -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);

View File

@ -5,7 +5,7 @@ import { Menu, MenuItem, IconButton } from 'react-mdl';
class AddStrategy extends React.Component {
static propTypes = {
strategies: PropTypes.array.isRequired,
addStrategy: PropTypes.func.isRequired,
addStrategy: PropTypes.func,
fetchStrategies: PropTypes.func.isRequired,
};

View File

@ -9,9 +9,9 @@ class StrategiesList extends React.Component {
static propTypes = {
strategies: PropTypes.array.isRequired,
configuredStrategies: PropTypes.array.isRequired,
updateStrategy: PropTypes.func.isRequired,
removeStrategy: PropTypes.func.isRequired,
moveStrategy: PropTypes.func.isRequired,
updateStrategy: PropTypes.func,
removeStrategy: PropTypes.func,
moveStrategy: PropTypes.func,
};
render() {
@ -27,8 +27,8 @@ class StrategiesList extends React.Component {
key={strategy.id}
strategy={strategy}
moveStrategy={moveStrategy}
removeStrategy={removeStrategy.bind(null, i)}
updateStrategy={updateStrategy.bind(null, i)}
removeStrategy={removeStrategy ? removeStrategy.bind(null, i) : null}
updateStrategy={updateStrategy ? updateStrategy.bind(null, i) : null}
strategyDefinition={strategies.find(s => s.name === strategy.name)}
/>
));

View File

@ -8,9 +8,9 @@ import { HeaderTitle } from '../../common';
class StrategiesSectionComponent extends React.Component {
static propTypes = {
strategies: PropTypes.array.isRequired,
addStrategy: PropTypes.func.isRequired,
removeStrategy: PropTypes.func.isRequired,
updateStrategy: PropTypes.func.isRequired,
addStrategy: PropTypes.func,
removeStrategy: PropTypes.func,
updateStrategy: PropTypes.func,
fetchStrategies: PropTypes.func.isRequired,
};
@ -25,7 +25,11 @@ class StrategiesSectionComponent extends React.Component {
return (
<div>
<HeaderTitle title="Activation strategies" actions={<AddStrategy {...this.props} />} />
{this.props.addStrategy ? (
<HeaderTitle title="Activation strategies" actions={<AddStrategy {...this.props} />} />
) : (
<span />
)}
<StrategiesList {...this.props} />
</div>
);

View File

@ -46,10 +46,10 @@ class StrategyConfigure extends React.Component {
/* eslint-enable */
static propTypes = {
strategy: PropTypes.object.isRequired,
strategyDefinition: PropTypes.object.isRequired,
updateStrategy: PropTypes.func.isRequired,
removeStrategy: PropTypes.func.isRequired,
moveStrategy: PropTypes.func.isRequired,
strategyDefinition: PropTypes.object,
updateStrategy: PropTypes.func,
removeStrategy: PropTypes.func,
moveStrategy: PropTypes.func,
isDragging: PropTypes.bool.isRequired,
connectDragPreview: 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}>
<Icon name="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(
<span className={styles.reorderIcon}>
<Icon name="reorder" />

View File

@ -7,13 +7,15 @@ import { Icon, FABButton, Textfield, Menu, MenuItem, Card, CardActions, List } f
import { MenuItemWithIcon, DropdownButton, styles as commonStyles } from '../common';
import styles from './feature.scss';
export default class FeatureListComponent extends React.PureComponent {
export default class FeatureListComponent extends React.Component {
static propTypes = {
features: PropTypes.array.isRequired,
featureMetrics: PropTypes.object.isRequired,
fetchFeatureToggles: PropTypes.func.isRequired,
fetchFeatureToggles: PropTypes.func,
fetchArchive: PropTypes.func,
revive: PropTypes.func,
updateSetting: PropTypes.func.isRequired,
toggleFeature: PropTypes.func.isRequired,
toggleFeature: PropTypes.func,
settings: PropTypes.object,
};
@ -22,7 +24,11 @@ export default class FeatureListComponent extends React.PureComponent {
};
componentDidMount() {
this.props.fetchFeatureToggles();
if (this.props.fetchFeatureToggles) {
this.props.fetchFeatureToggles();
} else {
this.props.fetchArchive();
}
}
toggleMetrics() {
@ -38,8 +44,10 @@ export default class FeatureListComponent extends React.PureComponent {
}
render() {
const { features, toggleFeature, featureMetrics, settings } = this.props;
const { features, toggleFeature, featureMetrics, settings, revive } = this.props;
features.forEach(e => {
e.reviveName = e.name;
});
return (
<div>
<div className={styles.toolbar}>
@ -108,6 +116,7 @@ export default class FeatureListComponent extends React.PureComponent {
metricsLastMinute={featureMetrics.lastMinute[feature.name]}
feature={feature}
toggleFeature={toggleFeature}
revive={revive}
/>
))}
</List>

View File

@ -4,10 +4,10 @@ import { updateSettingForGroup } from '../../store/settings/actions';
import FeatureListComponent from './list-component';
const mapStateToProps = state => {
export const mapStateToPropsConfigurable = isFeature => state => {
const featureMetrics = state.featureMetrics.toJS();
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) {
try {
const regex = new RegExp(settings.filter, 'i');
@ -69,7 +69,7 @@ const mapStateToProps = state => {
settings,
};
};
const mapStateToProps = mapStateToPropsConfigurable(true);
const mapDispatchToProps = {
toggleFeature,
fetchFeatureToggles,

View File

@ -6,6 +6,7 @@ import { hashHistory, Link } from 'react-router';
import HistoryComponent from '../history/history-list-toggle-container';
import MetricComponent from './metric-container';
import EditFeatureToggle from './form/form-update-feature-container';
import ViewFeatureToggle from './form/form-view-feature-container';
import { styles as commonStyles } from '../common';
const TABS = {
@ -15,24 +16,32 @@ const TABS = {
};
export default class ViewFeatureToggleComponent extends React.Component {
isFeatureView;
constructor(props) {
super(props);
this.isFeatureView = !!props.fetchFeatureToggles;
}
static propTypes = {
activeTab: PropTypes.string.isRequired,
featureToggleName: PropTypes.string.isRequired,
features: PropTypes.array.isRequired,
toggleFeature: PropTypes.func.isRequired,
removeFeatureToggle: PropTypes.func.isRequired,
fetchFeatureToggles: PropTypes.func.isRequired,
editFeatureToggle: PropTypes.func.isRequired,
toggleFeature: PropTypes.func,
removeFeatureToggle: PropTypes.func,
revive: PropTypes.func,
fetchArchive: PropTypes.func,
fetchFeatureToggles: PropTypes.func,
editFeatureToggle: PropTypes.func,
featureToggle: PropTypes.object,
};
componentWillMount() {
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) {
return <HistoryComponent toggleName={featureToggleName} />;
} else if (TABS[activeTab] === TABS.strategies) {
return <EditFeatureToggle featureToggle={featureToggle} />;
if (this.isFeatureView) {
return <EditFeatureToggle featureToggle={featureToggle} />;
}
return <ViewFeatureToggle featureToggle={featureToggle} />;
} else {
return <MetricComponent featureToggle={featureToggle} />;
}
}
goToTab(tabName, featureToggleName) {
hashHistory.push(`/features/${tabName}/${featureToggleName}`);
let view = this.props.fetchFeatureToggles ? 'features' : 'archive';
hashHistory.push(`/${view}/${tabName}/${featureToggleName}`);
}
render() {
@ -57,6 +70,7 @@ export default class ViewFeatureToggleComponent extends React.Component {
featureToggle,
features,
activeTab,
revive,
// setValue,
featureToggleName,
toggleFeature,
@ -94,6 +108,10 @@ export default class ViewFeatureToggleComponent extends React.Component {
hashHistory.push('/features');
}
};
const reviveToggle = () => {
revive(featureToggle.name);
hashHistory.push('/features');
};
const updateFeatureToggle = () => {
let feature = { ...featureToggle };
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' }}>
<CardTitle style={{ paddingTop: '24px', wordBreak: 'break-all' }}>{featureToggle.name}</CardTitle>
<CardText>
<Textfield
floatingLabel
style={{ width: '100%' }}
rows={1}
label="Description"
required
value={featureToggle.description}
onChange={v => setValue('description', v)}
onBlur={updateFeatureToggle}
/>
{this.isFeatureView ? (
<Textfield
floatingLabel
style={{ width: '100%' }}
rows={1}
label="Description"
required
value={featureToggle.description}
onChange={v => setValue('description', v)}
onBlur={updateFeatureToggle}
/>
) : (
<Textfield
disabled
floatingLabel
style={{ width: '100%' }}
rows={1}
label="Description"
required
value={featureToggle.description}
/>
)}
</CardText>
<CardActions
@ -135,6 +165,7 @@ export default class ViewFeatureToggleComponent extends React.Component {
>
<span style={{ paddingRight: '24px' }}>
<Switch
disabled={this.isFeatureView}
ripple
checked={featureToggle.enabled}
onChange={() => toggleFeature(featureToggle.name)}
@ -142,9 +173,16 @@ export default class ViewFeatureToggleComponent extends React.Component {
{featureToggle.enabled ? 'Enabled' : 'Disabled'}
</Switch>
</span>
<Button onClick={removeToggle} style={{ flexShrink: 0 }}>
Archive
</Button>
{this.isFeatureView ? (
<Button onClick={removeToggle} style={{ flexShrink: 0 }}>
Archive
</Button>
) : (
<Button onClick={reviveToggle} style={{ flexShrink: 0 }}>
Revive
</Button>
)}
</CardActions>
<hr />
<Tabs

View File

@ -23,6 +23,7 @@ import CreateStrategies from './page/strategies/create';
import HistoryPage from './page/history';
import HistoryTogglePage from './page/history/toggle';
import Archive from './page/archive';
import ShowArchive from './page/archive/show';
import Applications from './page/applications';
import ApplicationView from './page/applications/view';
@ -68,7 +69,7 @@ ReactDOM.render(
</Route>
<Route pageTitle="Archived Toggles" link="/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 pageTitle="Applications" link="/applications">

View 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} />;
}
}