diff --git a/frontend/src/__mocks__/react-mdl.js b/frontend/src/__mocks__/react-mdl.js index dde54f173c..c1ddf6d0c8 100644 --- a/frontend/src/__mocks__/react-mdl.js +++ b/frontend/src/__mocks__/react-mdl.js @@ -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', diff --git a/frontend/src/component/app.jsx b/frontend/src/component/app.jsx index a52af8b78e..a905082e31 100644 --- a/frontend/src/component/app.jsx +++ b/frontend/src/component/app.jsx @@ -192,11 +192,11 @@ export default class App extends Component { - {createListItem('/features', 'Feature Toggles')} - {createListItem('/strategies', 'Strategies')} - {createListItem('/history', 'Event History')} - {createListItem('/archive', 'Archived Toggles')} - {createListItem('/applications', 'Applications')} + {createListItem('/features', 'Feature Toggles', '')} + {createListItem('/strategies', 'Strategies', '')} + {createListItem('/history', 'Event History', '')} + {createListItem('/archive', 'Archived Toggles', '')} + {createListItem('/applications', 'Applications', '')} Sign out diff --git a/frontend/src/component/archive/__tests__/.eslintrc b/frontend/src/component/archive/__tests__/.eslintrc deleted file mode 100644 index eba2077219..0000000000 --- a/frontend/src/component/archive/__tests__/.eslintrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "env": { - "jest": true - } -} diff --git a/frontend/src/component/archive/__tests__/__snapshots__/archive-list-component-test.jsx.snap b/frontend/src/component/archive/__tests__/__snapshots__/archive-list-component-test.jsx.snap deleted file mode 100644 index 76efcd1391..0000000000 --- a/frontend/src/component/archive/__tests__/__snapshots__/archive-list-component-test.jsx.snap +++ /dev/null @@ -1,149 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders correctly with archived toggles 1`] = ` - -
-
- - - - Toggle name - - - Revive - - -
- - - - - - - - adin-pay-confirm-disabled - - - - default - - - -
- Disables the confirm-functionality from API -
-
-
- - - -
- - - - - - - adin-pay-platform-sch-payment - - - - default - - - -
- Enables use of schibsted payment from order-payment-management -
-
-
- - - -
-
-
-
-
-
-`; - -exports[`renders correctly with no archived toggles 1`] = ` - -
- -
- No archived feature toggles, go see - - active toggles here - -
-
-`; diff --git a/frontend/src/component/archive/__tests__/archive-list-component-test.jsx b/frontend/src/component/archive/__tests__/archive-list-component-test.jsx deleted file mode 100644 index 3b38afe2ad..0000000000 --- a/frontend/src/component/archive/__tests__/archive-list-component-test.jsx +++ /dev/null @@ -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().toJSON(); - expect(tree).toMatchSnapshot(); -}); - -test('renders correctly with archived toggles', () => { - const tree = renderer.create().toJSON(); - expect(tree).toMatchSnapshot(); -}); diff --git a/frontend/src/component/archive/archive-list-component.jsx b/frontend/src/component/archive/archive-list-component.jsx deleted file mode 100644 index 1757dcd75a..0000000000 --- a/frontend/src/component/archive/archive-list-component.jsx +++ /dev/null @@ -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 = ( - - {feature.strategies.map((s, i) => ( - - {s.name} - {Object.keys(s.parameters).map((p, j) => {s.parameters[p]})} - - ))} - - ); - - 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) => ( - - {s.name} - - )); - const remaining = ( - - +{remainingStrategies} - - ); - 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 ( - - {archive && archive.length > 0 ? ( -
-
- - - Toggle name - Revive - -
- - {archive.map((feature, i) => ( - - - {this.props.name && feature.name === this.props.name ? ( - - ) : ( - - )} - - - {this.props.name && feature.name === this.props.name ? ( - - {this.renderStrategiesInList(feature).map((strategyChip, i) => ( - {strategyChip} - ))} - - {feature.name} -
- {feature.description} -
-
- {this.renderStrategyDetail(feature)} -
- - ) : ( - - {feature.name} - - {this.renderStrategiesInList(feature).map((strategyChip, i) => ( - {strategyChip} - ))} - -
- {feature.description} -
- - )} -
- revive(feature.name)}> - - -
- ))} -
-
-
-
- ) : ( -
- -
- No archived feature toggles, go see active toggles here -
- )} -
- ); - } -} - -export default ArchiveList; diff --git a/frontend/src/component/archive/archive-list-container.js b/frontend/src/component/archive/archive-list-container.js index 577187c6e5..5c12f58e06 100644 --- a/frontend/src/component/archive/archive-list-container.js +++ b/frontend/src/component/archive/archive-list-container.js @@ -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; diff --git a/frontend/src/component/archive/view-container.js b/frontend/src/component/archive/view-container.js new file mode 100644 index 0000000000..6457722619 --- /dev/null +++ b/frontend/src/component/archive/view-container.js @@ -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); diff --git a/frontend/src/component/feature/__tests__/__snapshots__/feature-list-item-component-test.jsx.snap b/frontend/src/component/feature/__tests__/__snapshots__/feature-list-item-component-test.jsx.snap index 1bc9ad72fc..fe9c8e6a76 100644 --- a/frontend/src/component/feature/__tests__/__snapshots__/feature-list-item-component-test.jsx.snap +++ b/frontend/src/component/feature/__tests__/__snapshots__/feature-list-item-component-test.jsx.snap @@ -22,6 +22,7 @@ exports[`renders correctly with one feature 1`] = ` > @@ -51,5 +52,6 @@ exports[`renders correctly with one feature 1`] = ` gradualRolloutRandom + `; diff --git a/frontend/src/component/feature/feature-list-item-component.jsx b/frontend/src/component/feature/feature-list-item-component.jsx index 6d4a831f8a..47221a1428 100644 --- a/frontend/src/component/feature/feature-list-item-component.jsx +++ b/frontend/src/component/feature/feature-list-item-component.jsx @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Link } from 'react-router'; -import { Switch, Chip, ListItem } from 'react-mdl'; +import { Switch, Chip, ListItem, ListItemAction, Icon } from 'react-mdl'; import Progress from './progress'; import { calc, styles as commonStyles } from '../common'; @@ -13,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 = ({ )); const summaryChip = remainingStrategies > 0 && +{remainingStrategies}; - + const featureUrl = toggleFeature === undefined ? `/archive/strategies/${name}` : `/features/strategies/${name}`; return ( @@ -44,6 +42,7 @@ const Feature = ({ toggleFeature(name)} @@ -51,10 +50,7 @@ const Feature = ({ /> - + {name} {description} @@ -63,6 +59,13 @@ const Feature = ({ {strategyChips} {summaryChip} + {revive ? ( + revive(feature.name)}> + + + ) : ( + + )} ); }; @@ -73,6 +76,7 @@ Feature.propTypes = { settings: PropTypes.object, metricsLastHour: PropTypes.object, metricsLastMinute: PropTypes.object, + revive: PropTypes.func, }; export default Feature; diff --git a/frontend/src/component/feature/form/form-update-feature-container.jsx b/frontend/src/component/feature/form/form-update-feature-container.jsx index 58c755487e..f4b0f08637 100644 --- a/frontend/src/component/feature/form/form-update-feature-container.jsx +++ b/frontend/src/component/feature/form/form-update-feature-container.jsx @@ -45,7 +45,7 @@ const prepare = (methods, dispatch) => { methods.onCancel = evt => { evt.preventDefault(); methods.clear(); - window.history.back(); + hashHistory.push(`/features`); }; methods.addStrategy = v => { diff --git a/frontend/src/component/feature/form/form-view-feature-component.jsx b/frontend/src/component/feature/form/form-view-feature-component.jsx new file mode 100644 index 0000000000..3fa862c5a6 --- /dev/null +++ b/frontend/src/component/feature/form/form-view-feature-component.jsx @@ -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 ( +
+ +
+ +
+ ); + } +} + +ViewFeatureComponent.propTypes = { + input: PropTypes.object, + onCancel: PropTypes.func.isRequired, + initCallRequired: PropTypes.bool, + init: PropTypes.func, +}; + +export default ViewFeatureComponent; diff --git a/frontend/src/component/feature/form/form-view-feature-container.jsx b/frontend/src/component/feature/form/form-view-feature-container.jsx new file mode 100644 index 0000000000..3ed8e9605b --- /dev/null +++ b/frontend/src/component/feature/form/form-view-feature-container.jsx @@ -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); diff --git a/frontend/src/component/feature/form/strategies-add.jsx b/frontend/src/component/feature/form/strategies-add.jsx index aac8731fb5..429022e2cf 100644 --- a/frontend/src/component/feature/form/strategies-add.jsx +++ b/frontend/src/component/feature/form/strategies-add.jsx @@ -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, }; diff --git a/frontend/src/component/feature/form/strategies-list.jsx b/frontend/src/component/feature/form/strategies-list.jsx index 26a3eecc34..b6f8936c2c 100644 --- a/frontend/src/component/feature/form/strategies-list.jsx +++ b/frontend/src/component/feature/form/strategies-list.jsx @@ -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)} /> )); diff --git a/frontend/src/component/feature/form/strategies-section.jsx b/frontend/src/component/feature/form/strategies-section.jsx index e580fc9006..ed3c24605b 100644 --- a/frontend/src/component/feature/form/strategies-section.jsx +++ b/frontend/src/component/feature/form/strategies-section.jsx @@ -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 (
- } /> + {this.props.addStrategy ? ( + } /> + ) : ( + + )}
); diff --git a/frontend/src/component/feature/form/strategy-configure.jsx b/frontend/src/component/feature/form/strategy-configure.jsx index 8311121b0e..da816b4ac4 100644 --- a/frontend/src/component/feature/form/strategy-configure.jsx +++ b/frontend/src/component/feature/form/strategy-configure.jsx @@ -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 { - + {this.props.removeStrategy ? ( + + ) : ( + + )} {connectDragSource( diff --git a/frontend/src/component/feature/list-component.jsx b/frontend/src/component/feature/list-component.jsx index 269b2877a3..3b38518ddc 100644 --- a/frontend/src/component/feature/list-component.jsx +++ b/frontend/src/component/feature/list-component.jsx @@ -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 (
@@ -108,6 +116,7 @@ export default class FeatureListComponent extends React.PureComponent { metricsLastMinute={featureMetrics.lastMinute[feature.name]} feature={feature} toggleFeature={toggleFeature} + revive={revive} /> ))} diff --git a/frontend/src/component/feature/list-container.jsx b/frontend/src/component/feature/list-container.jsx index 412b50376c..3ca68741f1 100644 --- a/frontend/src/component/feature/list-container.jsx +++ b/frontend/src/component/feature/list-container.jsx @@ -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, diff --git a/frontend/src/component/feature/view-component.jsx b/frontend/src/component/feature/view-component.jsx index 4f2546fe33..2d287456fd 100644 --- a/frontend/src/component/feature/view-component.jsx +++ b/frontend/src/component/feature/view-component.jsx @@ -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 ; } else if (TABS[activeTab] === TABS.strategies) { - return ; + if (this.isFeatureView) { + return ; + } + return ; } else { return ; } } 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 { {featureToggle.name} - setValue('description', v)} - onBlur={updateFeatureToggle} - /> + {this.isFeatureView ? ( + setValue('description', v)} + onBlur={updateFeatureToggle} + /> + ) : ( + + )} toggleFeature(featureToggle.name)} @@ -142,9 +173,16 @@ export default class ViewFeatureToggleComponent extends React.Component { {featureToggle.enabled ? 'Enabled' : 'Disabled'} - + + {this.isFeatureView ? ( + + ) : ( + + )}
- + diff --git a/frontend/src/page/archive/show.js b/frontend/src/page/archive/show.js new file mode 100644 index 0000000000..674e303ac0 --- /dev/null +++ b/frontend/src/page/archive/show.js @@ -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 ; + } +}