diff --git a/frontend/.eslintrc b/frontend/.eslintrc index 56bf2c48ee..3f3e372e9e 100644 --- a/frontend/.eslintrc +++ b/frontend/.eslintrc @@ -5,6 +5,15 @@ "finn-prettier" ], "rules": { - "no-shadow": 0 + "no-shadow": 0, + "prettier/prettier": [ + 2, + { + "tabWidth": 4, + "singleQuote": true, + "trailingComma": "es5", + "printWidth": 120 + } + ] } } diff --git a/frontend/src/.eslintrc b/frontend/src/.eslintrc index 1fb58d9e15..cff5326d7b 100644 --- a/frontend/src/.eslintrc +++ b/frontend/src/.eslintrc @@ -10,7 +10,7 @@ "env": { "browser": true, "commonjs": true, - "es6": true + "es6": true }, "globals": { "process": false @@ -23,6 +23,15 @@ }, "rules": { "no-shadow": 0, - "react/sort-comp": 0 + "react/sort-comp": 0, + "prettier/prettier": [ + 2, + { + "tabWidth": 4, + "singleQuote": true, + "trailingComma": "es5", + "printWidth": 120 + } + ] } } diff --git a/frontend/src/component/app.jsx b/frontend/src/component/app.jsx index 8eb5e51a57..69af6f7aaf 100644 --- a/frontend/src/component/app.jsx +++ b/frontend/src/component/app.jsx @@ -89,18 +89,10 @@ export default class App extends Component { return ( {result.map((entry, index) => ( - 0 ? 'mdl-layout--large-screen-only' : '' - } - > + 0 ? 'mdl-layout--large-screen-only' : ''}> {index > 0 ? ' › ' : null} {entry.name} @@ -113,21 +105,13 @@ export default class App extends Component { render() { const shouldUpdateScroll = (prevRouterProps, { location }) => { - if ( - prevRouterProps && - location.pathname !== prevRouterProps.location.pathname - ) { + if (prevRouterProps && location.pathname !== prevRouterProps.location.pathname) { return location.action === 'POP'; } else { return [0, 0]; } }; - const createListItem = ( - path, - caption, - icon, - isDrawerNavigation = false - ) => { + const createListItem = (path, caption, icon, isDrawerNavigation = false) => { const linkColor = isDrawerNavigation && this.context.router.isActive(path) ? 'mdl-color-text--black' @@ -137,20 +121,11 @@ export default class App extends Component { ? 'mdl-color-text--black' : 'mdl-color-text--grey-600'; return ( - + {icon && ( )} {caption} @@ -168,79 +143,32 @@ export default class App extends Component { - - - - Unleash - + + + Unleash
- {createListItem( - '/features', - 'Feature Toggles', - 'list', - true - )} - {createListItem( - '/strategies', - 'Strategies', - 'extension', - true - )} - {createListItem( - '/history', - 'Event History', - 'history', - true - )} - {createListItem( - '/archive', - 'Archived Toggles', - 'archive', - true - )} - {createListItem( - '/applications', - 'Applications', - 'apps', - true - )} + {createListItem('/features', 'Feature Toggles', 'list', true)} + {createListItem('/strategies', 'Strategies', 'extension', true)} + {createListItem('/history', 'Event History', 'history', true)} + {createListItem('/archive', 'Archived Toggles', 'archive', true)} + {createListItem('/applications', 'Applications', 'apps', true)}
GitHub
- + @@ -252,54 +180,27 @@ 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')} - - Node.js - - - Java - - - Go - + Node.js + Java + Go - + GitHub - + A product by FINN.no diff --git a/frontend/src/component/application/__tests__/application-edit-component-test.js b/frontend/src/component/application/__tests__/application-edit-component-test.js index 21295c3d91..5875a8c68b 100644 --- a/frontend/src/component/application/__tests__/application-edit-component-test.js +++ b/frontend/src/component/application/__tests__/application-edit-component-test.js @@ -6,9 +6,7 @@ import renderer from 'react-test-renderer'; jest.mock('react-mdl'); test('renders correctly if no application', () => { - const tree = renderer - .create() - .toJSON(); + const tree = renderer.create().toJSON(); expect(tree).toMatchSnapshot(); }); diff --git a/frontend/src/component/application/application-edit-component.js b/frontend/src/component/application/application-edit-component.js index 9c38b7d2de..98c40f33b5 100644 --- a/frontend/src/component/application/application-edit-component.js +++ b/frontend/src/component/application/application-edit-component.js @@ -61,16 +61,7 @@ class ClientApplications extends PureComponent { return ; } const { application, storeApplicationMetaData } = this.props; - const { - appName, - instances, - strategies, - seenToggles, - url, - description, - icon = 'apps', - color, - } = application; + const { appName, instances, strategies, seenToggles, url, description, icon = 'apps', color } = application; const content = this.state.activeTab === 0 ? ( @@ -83,17 +74,8 @@ class ClientApplications extends PureComponent { ({ name, description, enabled, notFound }, i) => notFound ? ( - - - {name} - + + {name} ) : ( @@ -101,22 +83,12 @@ class ClientApplications extends PureComponent { - +
} - subtitle={shorten( - description, - 60 - )} + subtitle={shorten(description, 60)} > - - {shorten(name, 50)} - + {shorten(name, 50)} ) @@ -131,33 +103,14 @@ class ClientApplications extends PureComponent { ({ name, description, notFound }, i) => notFound ? ( - - - {name} - + + {name} ) : ( - - - {shorten(name, 50)} - + + {shorten(name, 50)} ) @@ -168,32 +121,20 @@ class ClientApplications extends PureComponent {
{instances.length} Instances registered

- {instances.map( - ( - { - instanceId, - clientIp, - lastSeen, - sdkVersion, - }, - i - ) => ( - - - {clientIp} last seen at{' '} - {formatFullDateTime(lastSeen)} -
- } - > - {instanceId}{' '} - {sdkVersion ? `(${sdkVersion})` : ''} - - - ) - )} + {instances.map(({ instanceId, clientIp, lastSeen, sdkVersion }, i) => ( + + + {clientIp} last seen at {formatFullDateTime(lastSeen)} +
+ } + > + {instanceId} {sdkVersion ? `(${sdkVersion})` : ''} + + + ))} @@ -206,46 +147,26 @@ class ClientApplications extends PureComponent { - storeApplicationMetaData( - appName, - 'url', - e.target.value - )} + onBlur={e => storeApplicationMetaData(appName, 'url', e.target.value)} />
- storeApplicationMetaData( - appName, - 'description', - e.target.value - )} + onBlur={e => storeApplicationMetaData(appName, 'description', e.target.value)} /> - storeApplicationMetaData( - appName, - 'icon', - e.target.value - )} + onBlur={e => storeApplicationMetaData(appName, 'icon', e.target.value)} /> - storeApplicationMetaData( - appName, - 'color', - e.target.value - )} + onBlur={e => storeApplicationMetaData(appName, 'color', e.target.value)} /> @@ -253,13 +174,7 @@ class ClientApplications extends PureComponent { return ( - + {appName} {description && {description}} diff --git a/frontend/src/component/application/application-edit-container.js b/frontend/src/component/application/application-edit-container.js index cec2829e40..b3b2d66989 100644 --- a/frontend/src/component/application/application-edit-container.js +++ b/frontend/src/component/application/application-edit-container.js @@ -1,9 +1,6 @@ import { connect } from 'react-redux'; import ApplicationEdit from './application-edit-component'; -import { - fetchApplication, - storeApplicationMetaData, -} from '../../store/application/actions'; +import { fetchApplication, storeApplicationMetaData } from '../../store/application/actions'; const mapStateToProps = (state, props) => { let application = state.applications.getIn(['apps', props.appName]); diff --git a/frontend/src/component/application/application-list-container.js b/frontend/src/component/application/application-list-container.js index 270ea9ed8f..d213878e05 100644 --- a/frontend/src/component/application/application-list-container.js +++ b/frontend/src/component/application/application-list-container.js @@ -2,9 +2,7 @@ import { connect } from 'react-redux'; import ApplicationList from './application-list-component'; import { fetchAll } from '../../store/application/actions'; -const mapStateToProps = state => ({ - applications: state.applications.get('list').toJS(), -}); +const mapStateToProps = state => ({ applications: state.applications.get('list').toJS() }); const Container = connect(mapStateToProps, { fetchAll })(ApplicationList); 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 index e3bb99e079..9a0b363fec 100644 --- 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 @@ -102,8 +102,7 @@ exports[`renders correctly with no archived toggles 1`] = ` } />
- No archived feature toggles, go see - + No archived feature toggles, go see { - const tree = renderer - .create() - .toJSON(); + const tree = renderer.create().toJSON(); expect(tree).toMatchSnapshot(); }); test('renders correctly with archived toggles', () => { - const tree = renderer - .create() - .toJSON(); + const tree = renderer.create().toJSON(); expect(tree).toMatchSnapshot(); }); diff --git a/frontend/src/component/archive/archive-container.js b/frontend/src/component/archive/archive-container.js index 748f6dd2bb..3d2ea58d3e 100644 --- a/frontend/src/component/archive/archive-container.js +++ b/frontend/src/component/archive/archive-container.js @@ -10,8 +10,6 @@ const mapStateToProps = state => { }; }; -const ArchiveListContainer = connect(mapStateToProps, { fetchArchive, revive })( - ListComponent -); +const ArchiveListContainer = connect(mapStateToProps, { fetchArchive, revive })(ListComponent); export default ArchiveListContainer; diff --git a/frontend/src/component/archive/archive-list-component.jsx b/frontend/src/component/archive/archive-list-component.jsx index a09e6d6da6..2a0976151a 100644 --- a/frontend/src/component/archive/archive-list-component.jsx +++ b/frontend/src/component/archive/archive-list-component.jsx @@ -17,20 +17,12 @@ class ArchiveList extends Component { {archive.length > 0 ? (
- + ( - revive(reviveName)} - /> + revive(reviveName)} /> )} > Revive @@ -50,14 +42,9 @@ class ArchiveList extends Component {
) : (
- +
- No archived feature toggles, go see{' '} - active toggles here + No archived feature toggles, go see active toggles here
)}
diff --git a/frontend/src/component/client-instance/__tests__/client-instance-component-test.jsx b/frontend/src/component/client-instance/__tests__/client-instance-component-test.jsx index a614499750..0bb3801d94 100644 --- a/frontend/src/component/client-instance/__tests__/client-instance-component-test.jsx +++ b/frontend/src/component/client-instance/__tests__/client-instance-component-test.jsx @@ -6,14 +6,7 @@ import renderer from 'react-test-renderer'; jest.mock('react-mdl'); test('renders correctly with no clientInstances', () => { - const tree = renderer - .create( - - ) - .toJSON(); + const tree = renderer.create().toJSON(); expect(tree).toMatchSnapshot(); }); diff --git a/frontend/src/component/client-instance/client-instance-component.js b/frontend/src/component/client-instance/client-instance-component.js index 295337a2cc..39f143fc31 100644 --- a/frontend/src/component/client-instance/client-instance-component.js +++ b/frontend/src/component/client-instance/client-instance-component.js @@ -16,11 +16,7 @@ class ClientStrategies extends Component { const source = this.props.clientInstances; return ( - + Instance ID Application name IP diff --git a/frontend/src/component/client-instance/client-instance-container.js b/frontend/src/component/client-instance/client-instance-container.js index 8a6bfb8fca..f150c6d948 100644 --- a/frontend/src/component/client-instance/client-instance-container.js +++ b/frontend/src/component/client-instance/client-instance-container.js @@ -2,12 +2,8 @@ import { connect } from 'react-redux'; import ClientInstances from './client-instance-component'; import { fetchClientInstances } from '../../store/client-instance-actions'; -const mapStateToProps = state => ({ - clientInstances: state.clientInstances.toJS(), -}); +const mapStateToProps = state => ({ clientInstances: state.clientInstances.toJS() }); -const StrategiesContainer = connect(mapStateToProps, { fetchClientInstances })( - ClientInstances -); +const StrategiesContainer = connect(mapStateToProps, { fetchClientInstances })(ClientInstances); export default StrategiesContainer; diff --git a/frontend/src/component/common/index.js b/frontend/src/component/common/index.js index 2e8cbfe677..15ff789736 100644 --- a/frontend/src/component/common/index.js +++ b/frontend/src/component/common/index.js @@ -1,44 +1,22 @@ import React from 'react'; import { Link } from 'react-router'; -import { - List, - ListItem, - ListItemContent, - Button, - Icon, - Switch, - MenuItem, -} from 'react-mdl'; +import { List, ListItem, ListItemContent, Button, Icon, Switch, MenuItem } from 'react-mdl'; import styles from './common.scss'; export { styles }; -export const shorten = (str, len = 50) => - str && str.length > len ? `${str.substring(0, len)}...` : str; +export const shorten = (str, len = 50) => (str && str.length > len ? `${str.substring(0, len)}...` : str); export const AppsLinkList = ({ apps }) => ( {apps.length > 0 && apps.map(({ appName, description = '-', icon = 'apps' }) => ( - + - + {appName} - + {description} @@ -62,9 +40,7 @@ export const HeaderTitle = ({ title, actions, subtitle }) => ( {subtitle && {subtitle}} - {actions && ( -
{actions}
- )} + {actions &&
{actions}
} ); @@ -84,24 +60,13 @@ export const FormButtons = ({ submitText = 'Create', onCancel }) => ( {submitText}   - ); -export const SwitchWithLabel = ({ - onChange, - checked, - children, - ...switchProps -}) => ( +export const SwitchWithLabel = ({ onChange, checked, children, ...switchProps }) => ( {children} @@ -141,12 +106,7 @@ export function getIcon(type) { } export const IconLink = ({ url, icon }) => ( -
+ ); @@ -158,17 +118,8 @@ export const DropdownButton = ({ label, id }) => ( ); -export const MenuItemWithIcon = ({ - icon, - label, - disabled, - ...menuItemProps -}) => ( - +export const MenuItemWithIcon = ({ icon, label, disabled, ...menuItemProps }) => ( + {label} @@ -176,11 +127,7 @@ export const MenuItemWithIcon = ({ const badNumbers = [NaN, Infinity, -Infinity]; export function calc(value, total, decimal) { - if ( - typeof value !== 'number' || - typeof total !== 'number' || - typeof decimal !== 'number' - ) { + if (typeof value !== 'number' || typeof total !== 'number' || typeof decimal !== 'number') { return null; } diff --git a/frontend/src/component/common/util.js b/frontend/src/component/common/util.js index a58f003fc5..dd404fff2f 100644 --- a/frontend/src/component/common/util.js +++ b/frontend/src/component/common/util.js @@ -7,5 +7,4 @@ const dateTimeOptions = { second: '2-digit', }; -export const formatFullDateTime = v => - new Date(v).toLocaleString('nb-NO', dateTimeOptions); +export const formatFullDateTime = v => new Date(v).toLocaleString('nb-NO', dateTimeOptions); diff --git a/frontend/src/component/error/error-component.jsx b/frontend/src/component/error/error-component.jsx index 6cc453fb87..898b24a1d2 100644 --- a/frontend/src/component/error/error-component.jsx +++ b/frontend/src/component/error/error-component.jsx @@ -8,13 +8,7 @@ const ErrorComponent = ({ errors, ...props }) => { const error = showError ? errors[0] : undefined; const muteError = () => props.muteError(error); return ( - + {error} ); diff --git a/frontend/src/component/feature/feature-list-item-component.jsx b/frontend/src/component/feature/feature-list-item-component.jsx index 35c53223ce..23991b5479 100644 --- a/frontend/src/component/feature/feature-list-item-component.jsx +++ b/frontend/src/component/feature/feature-list-item-component.jsx @@ -17,23 +17,13 @@ const Feature = ({ const { name, description, enabled, strategies } = feature; const { showLastHour = false } = settings; - const isStale = showLastHour - ? metricsLastHour.isFallback - : metricsLastMinute.isFallback; + const isStale = showLastHour ? metricsLastHour.isFallback : metricsLastMinute.isFallback; const percent = 1 * (showLastHour - ? calc( - metricsLastHour.yes, - metricsLastHour.yes + metricsLastHour.no, - 0 - ) - : calc( - metricsLastMinute.yes, - metricsLastMinute.yes + metricsLastMinute.no, - 0 - )); + ? calc(metricsLastHour.yes, metricsLastHour.yes + metricsLastHour.no, 0) + : calc(metricsLastMinute.yes, metricsLastMinute.yes + metricsLastMinute.no, 0)); const strategiesToShow = Math.min(strategies.length, 3); const remainingStrategies = strategies.length - strategiesToShow; @@ -45,18 +35,12 @@ const Feature = ({ {s.name} )); - const summaryChip = remainingStrategies > 0 && ( - +{remainingStrategies} - ); + const summaryChip = remainingStrategies > 0 && +{remainingStrategies}; return ( - + - + {name} - - {description} - + {description} - + {strategyChips} {summaryChip} diff --git a/frontend/src/component/feature/form-add-container.jsx b/frontend/src/component/feature/form-add-container.jsx index 065898d605..8c3cc49b51 100644 --- a/frontend/src/component/feature/form-add-container.jsx +++ b/frontend/src/component/feature/form-add-container.jsx @@ -1,9 +1,6 @@ import { connect } from 'react-redux'; import { hashHistory } from 'react-router'; -import { - createFeatureToggles, - validateName, -} from '../../store/feature-actions'; +import { createFeatureToggles, validateName } from '../../store/feature-actions'; import { createMapper, createActions } from '../input-helpers'; import FormAddComponent from './form-add-component'; diff --git a/frontend/src/component/feature/form/index.jsx b/frontend/src/component/feature/form/index.jsx index 0a94be3213..a1290022d9 100644 --- a/frontend/src/component/feature/form/index.jsx +++ b/frontend/src/component/feature/form/index.jsx @@ -92,10 +92,7 @@ class AddFeatureToggleComponent extends Component { />
- + ); diff --git a/frontend/src/component/feature/form/strategies-add.jsx b/frontend/src/component/feature/form/strategies-add.jsx index a4f389267a..a75de9fdc9 100644 --- a/frontend/src/component/feature/form/strategies-add.jsx +++ b/frontend/src/component/feature/form/strategies-add.jsx @@ -10,9 +10,7 @@ class AddStrategy extends React.Component { }; addStrategy = strategyName => { - const selectedStrategy = this.props.strategies.find( - s => s.name === strategyName - ); + const selectedStrategy = this.props.strategies.find(s => s.name === strategyName); const parameters = {}; selectedStrategy.parameters.forEach(({ name }) => { @@ -37,14 +35,7 @@ class AddStrategy extends React.Component { backgroundColor: 'rgb(247, 248, 255)', }; return ( -
+
- + Add Strategy: {this.props.strategies.map(s => ( - this.addStrategy(s.name)} - > + this.addStrategy(s.name)}> {s.name} ))} diff --git a/frontend/src/component/feature/form/strategies-list.jsx b/frontend/src/component/feature/form/strategies-list.jsx index 40a892a93d..26a3eecc34 100644 --- a/frontend/src/component/feature/form/strategies-list.jsx +++ b/frontend/src/component/feature/form/strategies-list.jsx @@ -15,13 +15,7 @@ class StrategiesList extends React.Component { }; render() { - const { - strategies, - configuredStrategies, - moveStrategy, - removeStrategy, - updateStrategy, - } = this.props; + const { strategies, configuredStrategies, moveStrategy, removeStrategy, updateStrategy } = this.props; if (!configuredStrategies || configuredStrategies.length === 0) { return No strategies added; @@ -35,14 +29,10 @@ class StrategiesList extends React.Component { moveStrategy={moveStrategy} removeStrategy={removeStrategy.bind(null, i)} updateStrategy={updateStrategy.bind(null, i)} - strategyDefinition={strategies.find( - s => s.name === strategy.name - )} + strategyDefinition={strategies.find(s => s.name === strategy.name)} /> )); - return ( -
{blocks}
- ); + return
{blocks}
; } } diff --git a/frontend/src/component/feature/form/strategies-section.jsx b/frontend/src/component/feature/form/strategies-section.jsx index b5fbd2b6f0..54ea82fd06 100644 --- a/frontend/src/component/feature/form/strategies-section.jsx +++ b/frontend/src/component/feature/form/strategies-section.jsx @@ -25,10 +25,7 @@ class StrategiesSection extends React.Component { return (
- } - /> + } />
); diff --git a/frontend/src/component/feature/form/strategy-configure.jsx b/frontend/src/component/feature/form/strategy-configure.jsx index b3fc6a694c..8311121b0e 100644 --- a/frontend/src/component/feature/form/strategy-configure.jsx +++ b/frontend/src/component/feature/form/strategy-configure.jsx @@ -1,16 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { - Textfield, - Button, - Card, - CardTitle, - CardText, - CardActions, - CardMenu, - IconButton, - Icon, -} from 'react-mdl'; +import { Textfield, Button, Card, CardTitle, CardText, CardActions, CardMenu, IconButton, Icon } from 'react-mdl'; import { DragSource, DropTarget } from 'react-dnd'; import { Link } from 'react-router'; import StrategyInputPercentage from './strategy-input-percentage'; @@ -91,25 +81,17 @@ class StrategyConfigure extends React.Component { return parameters.map(({ name, type, description, required }) => { let value = this.props.strategy.parameters[name]; if (type === 'percentage') { - if ( - value == null || - (typeof value === 'string' && value === '') - ) { + if (value == null || (typeof value === 'string' && value === '')) { this.setConfig(name, 50); } return (
- {description && ( -

{description}

- )} + {description &&

{description}

}
); } else if (type === 'list') { @@ -122,14 +104,8 @@ class StrategyConfigure extends React.Component { } return (
- - {description && ( -

{description}

- )} + + {description &&

{description}

}
); } else if (type === 'number') { @@ -143,15 +119,10 @@ class StrategyConfigure extends React.Component { style={{ width: '100%' }} name={name} label={name} - onChange={this.handleConfigChange.bind( - this, - name - )} + onChange={this.handleConfigChange.bind(this, name)} value={value} /> - {description && ( -

{description}

- )} + {description &&

{description}

}
); } else { @@ -164,15 +135,10 @@ class StrategyConfigure extends React.Component { required={required} name={name} label={name} - onChange={this.handleConfigChange.bind( - this, - name - )} + onChange={this.handleConfigChange.bind(this, name)} value={value} /> - {description && ( -

{description}

- )} + {description &&

{description}

}
); } @@ -182,31 +148,18 @@ class StrategyConfigure extends React.Component { } render() { - const { - isDragging, - connectDragPreview, - connectDragSource, - connectDropTarget, - } = this.props; + const { isDragging, connectDragPreview, connectDragSource, connectDropTarget } = this.props; let item; if (this.props.strategyDefinition) { - const inputFields = this.renderInputFields( - this.props.strategyDefinition - ); + const inputFields = this.renderInputFields(this.props.strategyDefinition); const { name } = this.props.strategy; item = ( - +  {name} - - {this.props.strategyDefinition.description} - + {this.props.strategyDefinition.description} {inputFields && ( {inputFields} @@ -214,18 +167,10 @@ class StrategyConfigure extends React.Component { )} - + - + {connectDragSource( @@ -241,17 +186,10 @@ class StrategyConfigure extends React.Component { "{name}" deleted? The strategy "{name}" does not exist on this server. - - Want to create it now? - + Want to create it now? - @@ -259,9 +197,7 @@ class StrategyConfigure extends React.Component { ); } - return connectDropTarget( - connectDragPreview(
{item}
) - ); + return connectDropTarget(connectDragPreview(
{item}
)); } } diff --git a/frontend/src/component/feature/form/strategy-input-list.jsx b/frontend/src/component/feature/form/strategy-input-list.jsx index 25abbe75a4..6bd01c3c35 100644 --- a/frontend/src/component/feature/form/strategy-input-list.jsx +++ b/frontend/src/component/feature/form/strategy-input-list.jsx @@ -46,10 +46,7 @@ export default class InputList extends Component { onClose(index) { const { name, list, setConfig } = this.props; list[index] = null; - setConfig( - name, - list.length === 1 ? '' : list.filter(Boolean).join(',') - ); + setConfig(name, list.length === 1 ? '' : list.filter(Boolean).join(',')); } render() { @@ -58,11 +55,7 @@ export default class InputList extends Component {

{name}

{list.map((entryValue, index) => ( - this.onClose(index)} - > + this.onClose(index)}> {entryValue} ))} @@ -79,11 +72,7 @@ export default class InputList extends Component {
diff --git a/frontend/src/component/feature/form/strategy-input-percentage.jsx b/frontend/src/component/feature/form/strategy-input-percentage.jsx index 158da010c6..44596b5ca8 100644 --- a/frontend/src/component/feature/form/strategy-input-percentage.jsx +++ b/frontend/src/component/feature/form/strategy-input-percentage.jsx @@ -13,13 +13,6 @@ export default ({ name, value, onChange }) => (
{name}: {value}%
- + ); diff --git a/frontend/src/component/feature/list-component.jsx b/frontend/src/component/feature/list-component.jsx index aebc128f18..af04fb57a7 100644 --- a/frontend/src/component/feature/list-component.jsx +++ b/frontend/src/component/feature/list-component.jsx @@ -2,22 +2,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import Feature from './feature-list-item-component'; import { Link } from 'react-router'; -import { - Icon, - FABButton, - Textfield, - Menu, - MenuItem, - Card, - CardActions, - List, -} from 'react-mdl'; +import { Icon, FABButton, Textfield, Menu, MenuItem, Card, CardActions, List } from 'react-mdl'; -import { - MenuItemWithIcon, - DropdownButton, - styles as commonStyles, -} from '../common'; +import { MenuItemWithIcon, DropdownButton, styles as commonStyles } from '../common'; import styles from './feature.scss'; export default class FeatureListComponent extends React.PureComponent { @@ -47,10 +34,7 @@ export default class FeatureListComponent extends React.PureComponent { } toggleMetrics() { - this.props.updateSetting( - 'showLastHour', - !this.props.settings.showLastHour - ); + this.props.updateSetting('showLastHour', !this.props.settings.showLastHour); } setFilter(v) { @@ -62,12 +46,7 @@ export default class FeatureListComponent extends React.PureComponent { } render() { - const { - features, - toggleFeature, - featureMetrics, - settings, - } = this.props; + const { features, toggleFeature, featureMetrics, settings } = this.props; return (
@@ -81,32 +60,16 @@ export default class FeatureListComponent extends React.PureComponent { label="Search" style={{ width: '100%' }} /> - +
- + - - this.toggleMetrics()} - style={{ width: '168px' }} - > + + this.toggleMetrics()} style={{ width: '168px' }}> - + - this.setSort( - e.target.getAttribute('data-target') - )} + onClick={e => this.setSort(e.target.getAttribute('data-target'))} style={{ width: '168px' }} > - + Name - + Enabled - + Created - + Strategies - + Metrics @@ -170,12 +112,8 @@ export default class FeatureListComponent extends React.PureComponent { diff --git a/frontend/src/component/feature/list-container.jsx b/frontend/src/component/feature/list-container.jsx index 5c99df31b4..5847deae30 100644 --- a/frontend/src/component/feature/list-container.jsx +++ b/frontend/src/component/feature/list-container.jsx @@ -1,8 +1,5 @@ import { connect } from 'react-redux'; -import { - toggleFeature, - fetchFeatureToggles, -} from '../../store/feature-actions'; +import { toggleFeature, fetchFeatureToggles } from '../../store/feature-actions'; import { fetchFeatureMetrics } from '../../store/feature-metrics-actions'; import { updateSettingForGroup } from '../../store/settings/actions'; @@ -33,9 +30,7 @@ const mapStateToProps = state => { a.enabled === b.enabled ? 0 : a.enabled ? -1 : 1 ); } else if (settings.sort === 'created') { - features = features.sort( - (a, b) => (new Date(a.createdAt) > new Date(b.createdAt) ? -1 : 1) - ); + features = features.sort((a, b) => (new Date(a.createdAt) > new Date(b.createdAt) ? -1 : 1)); } else if (settings.sort === 'name') { features = features.sort((a, b) => { if (a.name < b.name) { @@ -47,13 +42,9 @@ const mapStateToProps = state => { return 0; }); } else if (settings.sort === 'strategies') { - features = features.sort( - (a, b) => (a.strategies.length > b.strategies.length ? -1 : 1) - ); + features = features.sort((a, b) => (a.strategies.length > b.strategies.length ? -1 : 1)); } else if (settings.sort === 'metrics') { - const target = settings.showLastHour - ? featureMetrics.lastHour - : featureMetrics.lastMinute; + const target = settings.showLastHour ? featureMetrics.lastHour : featureMetrics.lastMinute; features = features.sort((a, b) => { if (!target[a.name]) { @@ -83,8 +74,6 @@ const mapDispatchToProps = { updateSetting: updateSettingForGroup('feature'), }; -const FeatureListContainer = connect(mapStateToProps, mapDispatchToProps)( - FeatureListComponent -); +const FeatureListContainer = connect(mapStateToProps, mapDispatchToProps)(FeatureListComponent); export default FeatureListContainer; diff --git a/frontend/src/component/feature/metric-component.jsx b/frontend/src/component/feature/metric-component.jsx index f5a32d1e25..407c93c10a 100644 --- a/frontend/src/component/feature/metric-component.jsx +++ b/frontend/src/component/feature/metric-component.jsx @@ -12,10 +12,7 @@ const StrategyChipItem = ({ strategy }) => ( - + {strategy.name} @@ -25,9 +22,7 @@ const StrategyChipItem = ({ strategy }) => ( const StrategiesList = ({ strategies }) => (
With {strategies.length > 1 ? 'strategies' : 'strategy'}{' '} - {strategies.map((strategy, i) => ( - - ))} + {strategies.map((strategy, i) => )}
); @@ -59,10 +54,8 @@ export default class MetricComponent extends React.Component { seenApps = [], } = metrics; - const lastHourPercent = - 1 * calc(lastHour.yes, lastHour.yes + lastHour.no, 0); - const lastMinutePercent = - 1 * calc(lastMinute.yes, lastMinute.yes + lastMinute.no, 0); + const lastHourPercent = 1 * calc(lastHour.yes, lastHour.yes + lastHour.no, 0); + const lastMinutePercent = 1 * calc(lastMinute.yes, lastMinute.yes + lastMinute.no, 0); return (
@@ -75,9 +68,7 @@ export default class MetricComponent extends React.Component { animatePercentageText /> {lastMinute.isFallback ? ( -

- No metrics available -

+

No metrics available

) : (

Last minute @@ -86,14 +77,9 @@ export default class MetricComponent extends React.Component { )} - + {lastHour.isFallback ? ( -

- No metrics available -

+

No metrics available

) : (

Last hour @@ -115,20 +101,14 @@ export default class MetricComponent extends React.Component { />

- - Not used in an app in the last hour. - - This might be due to your client - implementation is not reporting usage. + Not used in an app in the last hour. + This might be due to your client implementation is not reporting usage.
)} - - Created{' '} - {formatFullDateTime(featureToggle.createdAt)} - + Created {formatFullDateTime(featureToggle.createdAt)}
diff --git a/frontend/src/component/feature/metric-container.jsx b/frontend/src/component/feature/metric-container.jsx index 55cef55bea..6058ae41c3 100644 --- a/frontend/src/component/feature/metric-container.jsx +++ b/frontend/src/component/feature/metric-container.jsx @@ -1,9 +1,6 @@ import { connect } from 'react-redux'; -import { - fetchFeatureMetrics, - fetchSeenApps, -} from '../../store/feature-metrics-actions'; +import { fetchFeatureMetrics, fetchSeenApps } from '../../store/feature-metrics-actions'; import MatricComponent from './metric-component'; @@ -18,10 +15,7 @@ function getMetricsForToggle(state, toggleName) { } if (state.featureMetrics.hasIn(['lastHour', toggleName])) { result.lastHour = state.featureMetrics.getIn(['lastHour', toggleName]); - result.lastMinute = state.featureMetrics.getIn([ - 'lastMinute', - toggleName, - ]); + result.lastMinute = state.featureMetrics.getIn(['lastMinute', toggleName]); } return result; } diff --git a/frontend/src/component/feature/progress.jsx b/frontend/src/component/feature/progress.jsx index f0538e2c33..9b476dfc9a 100644 --- a/frontend/src/component/feature/progress.jsx +++ b/frontend/src/component/feature/progress.jsx @@ -41,9 +41,7 @@ class Progress extends Component { const TOTAL_ANIMATION_TIME = 5000; const diff = start > target ? -(start - target) : target - start; const perCycle = TOTAL_ANIMATION_TIME / diff; - const cyclesCounter = Math.round( - Math.abs(TOTAL_ANIMATION_TIME / perCycle) - ); + const cyclesCounter = Math.round(Math.abs(TOTAL_ANIMATION_TIME / perCycle)); const perCycleTime = Math.round(Math.abs(perCycle)); return { @@ -95,9 +93,7 @@ class Progress extends Component { const diameter = Math.PI * 2 * radius; const progressStyle = { strokeDasharray: `${diameter}px ${diameter}px`, - strokeDashoffset: `${(100 - this.state.percentage) / - 100 * - diameter}px`, + strokeDashoffset: `${(100 - this.state.percentage) / 100 * diameter}px`, }; return isFallback ? ( @@ -113,9 +109,7 @@ class Progress extends Component { ) : ( { @@ -106,16 +94,8 @@ export default class ViewFeatureToggleComponent extends React.Component { }; return ( - - - {featureToggle.name} - + + {featureToggle.name} {featureToggle.description} - this.goToTab('view', featureToggleName)} - > - Metrics - - this.goToTab('edit', featureToggleName)} - > - Edit - - - this.goToTab('history', featureToggleName)} - > - History - + this.goToTab('view', featureToggleName)}>Metrics + this.goToTab('edit', featureToggleName)}>Edit + this.goToTab('history', featureToggleName)}>History {tabContent} diff --git a/frontend/src/component/feature/view-container.jsx b/frontend/src/component/feature/view-container.jsx index 10fc279335..8310b6bf14 100644 --- a/frontend/src/component/feature/view-container.jsx +++ b/frontend/src/component/feature/view-container.jsx @@ -1,19 +1,13 @@ import { connect } from 'react-redux'; -import { - fetchFeatureToggles, - toggleFeature, - removeFeatureToggle, -} from '../../store/feature-actions'; +import { fetchFeatureToggles, toggleFeature, removeFeatureToggle } from '../../store/feature-actions'; import ViewToggleComponent from './view-component'; export default connect( (state, props) => ({ features: state.features.toJS(), - featureToggle: state.features - .toJS() - .find(toggle => toggle.name === props.featureToggleName), + featureToggle: state.features.toJS().find(toggle => toggle.name === props.featureToggleName), activeTab: props.activeTab, }), { diff --git a/frontend/src/component/history/history-container.js b/frontend/src/component/history/history-container.js index 9b7ae8f719..0197b14bca 100644 --- a/frontend/src/component/history/history-container.js +++ b/frontend/src/component/history/history-container.js @@ -9,8 +9,6 @@ const mapStateToProps = state => { }; }; -const HistoryListContainer = connect(mapStateToProps, { fetchHistory })( - HistoryComponent -); +const HistoryListContainer = connect(mapStateToProps, { fetchHistory })(HistoryComponent); export default HistoryListContainer; diff --git a/frontend/src/component/history/history-item-diff.jsx b/frontend/src/component/history/history-item-diff.jsx index 5504f552f6..a88aeb0ef6 100644 --- a/frontend/src/component/history/history-item-diff.jsx +++ b/frontend/src/component/history/history-item-diff.jsx @@ -84,18 +84,12 @@ class HistoryItem extends PureComponent { changes = entry.diffs.map(buildDiff); } else { // Just show the data if there is no diff yet. - changes = ( -
- {JSON.stringify(entry.data, null, 2)} -
- ); + changes =
{JSON.stringify(entry.data, null, 2)}
; } return (
-                
-                    {changes.length === 0 ? '(no changes)' : changes}
-                
+                {changes.length === 0 ? '(no changes)' : changes}
             
); } diff --git a/frontend/src/component/history/history-list-component.jsx b/frontend/src/component/history/history-list-component.jsx index 7039b0195b..e04de07a81 100644 --- a/frontend/src/component/history/history-list-component.jsx +++ b/frontend/src/component/history/history-list-component.jsx @@ -2,11 +2,7 @@ import React, { Component } from 'react'; import HistoryItemDiff from './history-item-diff'; import HistoryItemJson from './history-item-json'; import { Table, TableHeader } from 'react-mdl'; -import { - DataTableHeader, - SwitchWithLabel, - styles as commonStyles, -} from '../common'; +import { DataTableHeader, SwitchWithLabel, styles as commonStyles } from '../common'; import { formatFullDateTime } from '../common/util'; import styles from './history.scss'; @@ -26,11 +22,7 @@ class HistoryList extends Component { const truncateTableCell = v => ( {v} @@ -39,9 +31,7 @@ class HistoryList extends Component { let entries; if (showData) { - entries = history.map(entry => ( - - )); + entries = history.map(entry => ); } else { entries = ( - + Type - + User Diff - + Time
@@ -93,10 +66,7 @@ class HistoryList extends Component { + Full events } diff --git a/frontend/src/component/input-helpers.js b/frontend/src/component/input-helpers.js index e870c03f92..6f6811cdcb 100644 --- a/frontend/src/component/input-helpers.js +++ b/frontend/src/component/input-helpers.js @@ -52,44 +52,23 @@ export function createActions({ id, prepare = v => v }) { }, setValue(key, value) { - dispatch( - createSet({ id: getId(id, ownProps), key, value }) - ); + dispatch(createSet({ id: getId(id, ownProps), key, value })); }, pushToList(key, value) { - dispatch( - createPush({ id: getId(id, ownProps), key, value }) - ); + dispatch(createPush({ id: getId(id, ownProps), key, value })); }, removeFromList(key, index) { - dispatch( - createPop({ id: getId(id, ownProps), key, index }) - ); + dispatch(createPop({ id: getId(id, ownProps), key, index })); }, moveItem(key, index, toIndex) { - dispatch( - createMove({ - id: getId(id, ownProps), - key, - index, - toIndex, - }) - ); + dispatch(createMove({ id: getId(id, ownProps), key, index, toIndex })); }, updateInList(key, index, newValue, merge = false) { - dispatch( - createUp({ - id: getId(id, ownProps), - key, - index, - newValue, - merge, - }) - ); + dispatch(createUp({ id: getId(id, ownProps), key, index, newValue, merge })); }, incValue(key) { diff --git a/frontend/src/component/strategies/add-container.js b/frontend/src/component/strategies/add-container.js index 79d5cb3f53..0d533acb27 100644 --- a/frontend/src/component/strategies/add-container.js +++ b/frontend/src/component/strategies/add-container.js @@ -13,19 +13,12 @@ const prepare = (methods, dispatch) => { // clean const parameters = (input.parameters || []) .filter(name => !!name) - .map( - ({ - name, - type = 'string', - description = '', - required = false, - }) => ({ - name, - type, - description, - required, - }) - ); + .map(({ name, type = 'string', description = '', required = false }) => ({ + name, + type, + description, + required, + })); createStrategy({ name: input.name, diff --git a/frontend/src/component/strategies/add-strategy.jsx b/frontend/src/component/strategies/add-strategy.jsx index 6d0773e7b2..2f31583755 100644 --- a/frontend/src/component/strategies/add-strategy.jsx +++ b/frontend/src/component/strategies/add-strategy.jsx @@ -1,15 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { - Textfield, - IconButton, - Menu, - MenuItem, - Checkbox, - Grid, - Cell, -} from 'react-mdl'; +import { Textfield, IconButton, Menu, MenuItem, Checkbox, Grid, Cell } from 'react-mdl'; import { FormButtons } from '../common'; const trim = value => { @@ -25,13 +17,7 @@ function gerArrayWithEntries(num) { } const Parameter = ({ set, input = {}, index }) => ( -
+
( style={{ borderRadius: '2px', cursor: 'pointer', - boxShadow: - '0 2px 2px 0 rgba(0,0,0,.04),0 3px 1px -2px rgba(0,0,0,.1),0 1px 5px 0 rgba(0,0,0,.12)', + boxShadow: '0 2px 2px 0 rgba(0,0,0,.04),0 3px 1px -2px rgba(0,0,0,.1),0 1px 5px 0 rgba(0,0,0,.12)', marginLeft: '10px', border: '1px solid #f1f1f1', backgroundColor: 'white', @@ -55,22 +40,13 @@ const Parameter = ({ set, input = {}, index }) => ( }} > {input.type || 'string'} - evt.preventDefault()} - /> + evt.preventDefault()} /> - set({ type: 'string' })}> - string - - set({ type: 'percentage' })}> - percentage - + set({ type: 'string' })}>string + set({ type: 'percentage' })}>percentage set({ type: 'list' })}>list - set({ type: 'number' })}> - number - + set({ type: 'number' })}>number
(

Edit strategy

- Be carefull! Changing a strategy definition might also require - changes to the implementation in the clients. + Be carefull! Changing a strategy definition might also require changes to the implementation in the clients.

); @@ -110,12 +85,7 @@ const CreateHeader = () => ( const Parameters = ({ input = [], count = 0, updateInList }) => (
{gerArrayWithEntries(count).map((v, i) => ( - updateInList('parameters', i, v, true)} - index={i} - input={input[i]} - /> + updateInList('parameters', i, v, true)} index={i} input={input[i]} /> ))}
); @@ -139,24 +109,13 @@ class AddStrategy extends Component { if (this.props.initCallRequired === true) { this.props.init(this.props.input); if (this.props.input.parameters) { - this.props.setValue( - '_params', - this.props.input.parameters.length - ); + this.props.setValue('_params', this.props.input.parameters.length); } } } render() { - const { - input, - setValue, - updateInList, - incValue, - onCancel, - editmode = false, - onSubmit, - } = this.props; + const { input, setValue, updateInList, incValue, onCancel, editmode = false, onSubmit } = this.props; return ( @@ -170,8 +129,7 @@ class AddStrategy extends Component { required disabled={editmode} pattern="^[0-9a-zA-Z\.\-]+$" - onChange={({ target }) => - setValue('name', trim(target.value))} + onChange={({ target }) => setValue('name', trim(target.value))} value={input.name} />
@@ -181,15 +139,10 @@ class AddStrategy extends Component { rows={1} label="Description" name="description" - onChange={({ target }) => - setValue('description', target.value)} + onChange={({ target }) => setValue('description', target.value)} value={input.description} /> - +
- +
diff --git a/frontend/src/component/strategies/edit-container.js b/frontend/src/component/strategies/edit-container.js index b02b650037..52ea626ed5 100644 --- a/frontend/src/component/strategies/edit-container.js +++ b/frontend/src/component/strategies/edit-container.js @@ -28,19 +28,12 @@ const prepare = (methods, dispatch) => { // clean const parameters = (input.parameters || []) .filter(name => !!name) - .map( - ({ - name, - type = 'string', - description = '', - required = false, - }) => ({ - name, - type, - description, - required, - }) - ); + .map(({ name, type = 'string', description = '', required = false }) => ({ + name, + type, + description, + required, + })); updateStrategy({ name: input.name, diff --git a/frontend/src/component/strategies/list-component.jsx b/frontend/src/component/strategies/list-component.jsx index 83f699fe76..90278ca07e 100644 --- a/frontend/src/component/strategies/list-component.jsx +++ b/frontend/src/component/strategies/list-component.jsx @@ -2,14 +2,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { Link } from 'react-router'; -import { - List, - ListItem, - ListItemContent, - IconButton, - Grid, - Cell, -} from 'react-mdl'; +import { List, ListItem, ListItemContent, IconButton, Grid, Cell } from 'react-mdl'; import { HeaderTitle } from '../common'; class StrategiesListComponent extends Component { @@ -33,10 +26,7 @@ class StrategiesListComponent extends Component { - this.context.router.push( - '/strategies/create' - )} + onClick={() => this.context.router.push('/strategies/create')} title="Add new strategy" /> } @@ -45,24 +35,15 @@ class StrategiesListComponent extends Component { {strategies.length > 0 ? ( strategies.map((strategy, i) => ( - - + + {strategy.name} {strategy.editable === false ? ( '' ) : ( - - removeStrategy(strategy)} - /> + removeStrategy(strategy)} /> )} )) diff --git a/frontend/src/component/strategies/list-container.jsx b/frontend/src/component/strategies/list-container.jsx index ec5c4c6ac0..51b6f69381 100644 --- a/frontend/src/component/strategies/list-container.jsx +++ b/frontend/src/component/strategies/list-container.jsx @@ -20,8 +20,6 @@ const mapDispatchToProps = dispatch => ({ fetchStrategies: () => fetchStrategies()(dispatch), }); -const StrategiesListContainer = connect(mapStateToProps, mapDispatchToProps)( - StrategiesListComponent -); +const StrategiesListContainer = connect(mapStateToProps, mapDispatchToProps)(StrategiesListComponent); export default StrategiesListContainer; diff --git a/frontend/src/component/strategies/show-strategy-component.js b/frontend/src/component/strategies/show-strategy-component.js index e1d362cc79..6899e4f096 100644 --- a/frontend/src/component/strategies/show-strategy-component.js +++ b/frontend/src/component/strategies/show-strategy-component.js @@ -13,15 +13,8 @@ class ShowStrategyComponent extends PureComponent { renderParameters(params) { if (params) { return params.map(({ name, type, description, required }, i) => ( - - + + {name} ({type}) diff --git a/frontend/src/component/strategies/strategy-details-component.jsx b/frontend/src/component/strategies/strategy-details-component.jsx index 2fd3eb4f7b..967830be70 100644 --- a/frontend/src/component/strategies/strategy-details-component.jsx +++ b/frontend/src/component/strategies/strategy-details-component.jsx @@ -54,9 +54,7 @@ export default class StrategyDetails extends Component { } render() { - const activeTabId = TABS[this.props.activeTab] - ? TABS[this.props.activeTab] - : TABS.view; + const activeTabId = TABS[this.props.activeTab] ? TABS[this.props.activeTab] : TABS.view; const strategy = this.props.strategy; if (!strategy) { return ; @@ -67,17 +65,12 @@ export default class StrategyDetails extends Component { return ( - + {strategy.editable === false ? ( '' ) : ( - this.goToTab('view')}> - Details - + this.goToTab('view')}>Details this.goToTab('edit')}>Edit )} diff --git a/frontend/src/component/strategies/strategy-details-container.js b/frontend/src/component/strategies/strategy-details-container.js index 08a404c6de..0f3eabef5e 100644 --- a/frontend/src/component/strategies/strategy-details-container.js +++ b/frontend/src/component/strategies/strategy-details-container.js @@ -5,17 +5,10 @@ import { fetchAll } from '../../store/application/actions'; import { fetchFeatureToggles } from '../../store/feature-actions'; const mapStateToProps = (state, props) => { - let strategy = state.strategies - .get('list') - .find(n => n.name === props.strategyName); - const applications = state.applications - .get('list') - .filter(app => app.strategies.includes(props.strategyName)); + let strategy = state.strategies.get('list').find(n => n.name === props.strategyName); + const applications = state.applications.get('list').filter(app => app.strategies.includes(props.strategyName)); const toggles = state.features.filter( - toggle => - toggle - .get('strategies') - .findIndex(s => s.name === props.strategyName) > -1 + toggle => toggle.get('strategies').findIndex(s => s.name === props.strategyName) > -1 ); return { diff --git a/frontend/src/component/user/show-user-component.jsx b/frontend/src/component/user/show-user-component.jsx index 952fa2163e..6223f37e30 100644 --- a/frontend/src/component/user/show-user-component.jsx +++ b/frontend/src/component/user/show-user-component.jsx @@ -15,11 +15,7 @@ export default class ShowUserComponent extends React.Component { render() { return ( - + diff --git a/frontend/src/component/user/user-component.jsx b/frontend/src/component/user/user-component.jsx index 4e63056180..b2dfd6639a 100644 --- a/frontend/src/component/user/user-component.jsx +++ b/frontend/src/component/user/user-component.jsx @@ -39,25 +39,17 @@ class EditUserComponent extends React.Component { render() { return (
- +

Action required

-

- You have to specify a username to use Unleash. This - will allow us to track your changes. -

+

You have to specify a username to use Unleash. This will allow us to track your changes.

- this.props.updateUserName(e.target.value)} + onChange={e => this.props.updateUserName(e.target.value)} />