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

cleans up the filter and sorting toolbar + fab for new feature toggle… (#61)

* cleans up the filter and sorting toolbar + fab for new feature toggle + makes name default sorting
This commit is contained in:
Vegard Sandvold 2017-02-04 19:30:06 +01:00 committed by GitHub
parent 92eaed85d1
commit 5242e2aa0d
6 changed files with 117 additions and 130 deletions

View File

@ -27,6 +27,17 @@
margin: 0;
}
.listLink {
color: #212121;
text-decoration: none;
font-weight: normal;
display: block;
}
.listLink:hover {
color: #000;
}
@media (max-width: 920px) {
.hideLt920 {
display: none;
@ -74,4 +85,9 @@
flex-direction: column;
justify-content: center;
min-height: 200px;
}
}
.dropdownButton {
text-transform: none;
font-weight: normal;
}

View File

@ -5,7 +5,7 @@ import styles from './common.scss';
const {
List, ListItem, ListItemContent,
Button, Icon,
Switch,
Switch, MenuItem,
} = require('react-mdl');
const { Link } = require('react-router');
@ -112,6 +112,20 @@ export const ExternalIconLink = ({ url, children }) => (
</IconLink>
);
export const DropdownButton = ({ label, id }) => (
<Button id={id} className={styles.dropdownButton}>
{label}
<Icon name="arrow_drop_down" className="mdl-color-text--grey-600"/>
</Button>
);
export const MenuItemWithIcon = ({ icon, label, disabled, ...menuItemProps }) => (
<MenuItem disabled={disabled} style={{ display: 'flex', alignItems: 'center' }} {...menuItemProps}>
<Icon name={icon} style={{ paddingRight: '16px' }}/>
{label}
</MenuItem>
);
const badNumbers = [NaN, Infinity, -Infinity];
export function calc (value, total, decimal) {
if (typeof value !== 'number' ||

View File

@ -1,6 +1,6 @@
import React, { PropTypes } from 'react';
import { Link } from 'react-router';
import { Switch, Icon, Chip } from 'react-mdl';
import { Switch, Icon, Chip, ListItem } from 'react-mdl';
import Progress from './progress';
import { calc, styles as commonStyles } from '../common';
@ -27,13 +27,13 @@ const Feature = ({
const remainingStrategies = strategies.length - strategiesToShow;
const strategyChips = strategies && strategies.slice(0, strategiesToShow).map((s, i) =>
<Chip className={styles.iconListItemChip} key={i}>{s.name}</Chip>);
<Chip className={styles.strategyChip} key={i}>{s.name}</Chip>);
const summaryChip = remainingStrategies > 0 &&
<Chip className={styles.iconListItemChip}>+{remainingStrategies}</Chip>;
<Chip className={styles.strategyChip}>+{remainingStrategies}</Chip>;
return (
<li key={name} className="mdl-list__item mdl-list__item--two-line">
<span className={styles.iconListItemProgress}>
<ListItem twoLine>
<span className={styles.listItemMetric}>
<div style={{ width: '40px', textAlign: 'center' }}>
{
isStale ?
@ -46,26 +46,29 @@ const Feature = ({
}
</div>
</span>
<span className={styles.iconListItemToggle} style={{ flexShrink: 0 }}>
<span className={styles.listItemToggle}>
<Switch title={`Toggle ${name}`} key="left-actions" onChange={() => toggleFeature(name)} checked={enabled} />
</span>
<span className="mdl-list__item-primary-content" style={{ minWidth: 0 }}>
<Link to={`/features/view/${name}`} className={[styles.link, commonStyles.truncate].join(' ')}>
<span className={['mdl-list__item-primary-content', styles.listItemLink].join(' ')}>
<Link to={`/features/view/${name}`} className={[commonStyles.listLink, commonStyles.truncate].join(' ')}>
{name}
<span className={['mdl-list__item-sub-title', commonStyles.truncate].join(' ')}>{description}</span>
</Link>
</span>
<span className={commonStyles.hideLt920} style={{ flexShrink: 0 }}>
<span className={[styles.listItemStrategies, commonStyles.hideLt920].join(' ')}>
{strategyChips}
{summaryChip}
</span>
</li>
</ListItem>
);
};
Feature.propTypes = {
feature: PropTypes.object,
toggleFeature: PropTypes.func,
settings: PropTypes.object,
metricsLastHour: PropTypes.object,
metricsLastMinute: PropTypes.object,
};
export default Feature;

View File

@ -1,56 +1,34 @@
.action {
color: #aaa !important;
cursor: pointer;
.toolbar {
position: relative;
padding: 0 104px 16px 24px;
}
.yes {
color: green;
.toolbarButton {
position: absolute;
top: 56px;
right: 24px;
z-index: 2;
}
.no {
color: red;
}
.link {
color: #212121;
text-decoration: none;
font-weight: normal;
display: block;
}
.link:hover {
color: #000;
}
.iconListItemProgress {
.listItemMetric {
float: left;
margin-right: 16px;
}
.iconListItemToggle {
float: left;
.listItemToggle {
margin-right: 16px;
width: 40px;
flex-shrink: 0;
}
.iconListItemChip {
.listItemLink {
min-width: 0;
}
.listItemStrategies {
flex-shrink: 0;
}
.strategyChip {
margin-left: 8px !important;
}
.topList {
display: flex;
margin: 8px;
}
.topListItem0 {
flex: 1;
flex-grow: 0;
}
.topListItem {
flex: 1;
}
.topListItem2 {
flex: 2;
}

View File

@ -1,9 +1,9 @@
import React, { PropTypes } from 'react';
import Feature from './feature-list-item-component';
import { Link } from 'react-router';
import { Icon, Chip, ChipContact, IconButton, FABButton, Textfield, Menu, MenuItem, Grid, Cell } from 'react-mdl';
import { Icon, FABButton, Textfield, Menu, MenuItem, Card, CardActions, List } from 'react-mdl';
import { 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 {
@ -15,6 +15,8 @@ export default class FeatureListComponent extends React.PureComponent {
featureMetrics: PropTypes.object.isRequired,
fetchFeatureToggles: PropTypes.func.isRequired,
fetchFeatureMetrics: PropTypes.func.isRequired,
updateSetting: PropTypes.func.isRequired,
settings: React.PropTypes.object,
};
}
@ -49,73 +51,54 @@ export default class FeatureListComponent extends React.PureComponent {
render () {
const { features, toggleFeature, featureMetrics, settings } = this.props;
return (
<Grid className="mdl-color--white">
<Cell col={12}>
<div className={styles.topList}>
<Chip onClick={() => this.toggleMetrics()} className={styles.topListItem0}>
{ settings.showLastHour &&
<ChipContact className="mdl-color--teal mdl-color-text--white">
<Icon name="hourglass_full" style={{ fontSize: '16px' }} />
</ChipContact> }
{ '1 hour' }
</Chip>
&nbsp;
<Chip onClick={() => this.toggleMetrics()} className={styles.topListItem0}>
{ !settings.showLastHour &&
<ChipContact className="mdl-color--teal mdl-color-text--white">
<Icon name="hourglass_empty" style={{ fontSize: '16px' }} />
</ChipContact> }
{ '1 minute' }
</Chip>
<div className={styles.topListItem2} style={{ margin: '-10px 10px 0 10px' }}>
<Textfield
floatingLabel
value={settings.filter}
onChange={(e) => { this.setFilter(e.target.value); }}
label="Filter toggles"
style={{ width: '100%' }}
/>
</div>
<div style={{ position: 'relative' }} className={styles.topListItem0}>
<IconButton name="sort" id="demo-menu-top-right" colored title="Sort" />
<Menu target="demo-menu-top-right" valign="bottom" align="right" ripple onClick={
(e) => this.setSort(e.target.getAttribute('data-target'))}>
<MenuItem disabled>Filter by:</MenuItem>
<MenuItem disabled={!settings.sort || settings.sort === 'nosort'} data-target="nosort">Default</MenuItem>
<MenuItem disabled={settings.sort === 'name'} data-target="name">Name</MenuItem>
<MenuItem disabled={settings.sort === 'enabled'} data-target="enabled">Enabled</MenuItem>
<MenuItem disabled={settings.sort === 'appName'} data-target="appName">Application name</MenuItem>
<MenuItem disabled={settings.sort === 'created'} data-target="created">Created</MenuItem>
<MenuItem disabled={settings.sort === 'strategies'} data-target="strategies">Strategies</MenuItem>
<MenuItem disabled={settings.sort === 'metrics'} data-target="metrics">Metrics</MenuItem>
</Menu>
</div>
<Link to="/features/create" className={styles.topListItem0}>
<IconButton ripple raised name="add" component="span" style={{ color: 'black' }}/>
</Link>
</div>
<ul className={['mdl-list', commonStyles.list].join(' ')}>
{features.map((feature, i) =>
<Feature key={i}
settings={settings}
metricsLastHour={featureMetrics.lastHour[feature.name]}
metricsLastMinute={featureMetrics.lastMinute[feature.name]}
feature={feature}
toggleFeature={toggleFeature}/>
)}
</ul>
<hr />
<Link to="/features/create" className={styles.topListItem0}>
<FABButton ripple component="span" mini>
<Icon name="add" />
</FABButton>
</Link>
</Cell>
</Grid>
return (<div>
<div className={styles.toolbar}>
<Textfield
floatingLabel
value={settings.filter}
onChange={(e) => { this.setFilter(e.target.value); }}
label="Search"
style={{ width: '100%' }}
/>
<Link to="/features/create" className={styles.toolbarButton}>
<FABButton accent title="Create feature toggle">
<Icon name="add"/>
</FABButton>
</Link>
</div>
<Card shadow={0} className={commonStyles.fullwidth}>
<CardActions>
<DropdownButton id="metric" label={`Last ${settings.showLastHour ? 'hour' : 'minute'}`}/>
<Menu target="metric" onClick={() => this.toggleMetrics()}
style={{ width: '168px' }}>
<MenuItemWithIcon icon="hourglass_empty" disabled={!settings.showLastHour} data-target="minute"
label="Last minute"/>
<MenuItemWithIcon icon="hourglass_full" disabled={settings.showLastHour} data-target="hour"
label="Last hour"/>
</Menu>
<DropdownButton id="sorting" label={`By ${settings.sort}`}/>
<Menu target="sorting" onClick={(e) => this.setSort(e.target.getAttribute('data-target'))}
style={{ width: '168px' }}>
<MenuItem disabled={!settings.sort || settings.sort === 'name'} data-target="name">Name</MenuItem>
<MenuItem disabled={settings.sort === 'enabled'} data-target="enabled">Enabled</MenuItem>
<MenuItem disabled={settings.sort === 'created'} data-target="created">Created</MenuItem>
<MenuItem disabled={settings.sort === 'strategies'} data-target="strategies">Strategies</MenuItem>
<MenuItem disabled={settings.sort === 'metrics'} data-target="metrics">Metrics</MenuItem>
</Menu>
</CardActions>
<hr className={commonStyles.divider}/>
<List className={commonStyles.list}>
{features.map((feature, i) =>
<Feature key={i}
settings={settings}
metricsLastHour={featureMetrics.lastHour[feature.name]}
metricsLastMinute={featureMetrics.lastMinute[feature.name]}
feature={feature}
toggleFeature={toggleFeature}/>
)}
</List>
</Card>
</div>
);
}
}

View File

@ -27,13 +27,6 @@ const mapStateToProps = (state) => {
// eslint-disable-next-line
a.enabled === b.enabled ? 0 : a.enabled ? -1 : 1
));
} else if (settings.sort === 'appName') {
// AppName
// features = features.sort((a, b) => {
// if (a.appName < b.appName) { return -1; }
// if (a.appName > b.appName) { return 1; }
// return 0;
// });
} else if (settings.sort === 'created') {
features = features.sort((a, b) => (
new Date(a.createdAt) > new Date(b.createdAt) ? -1 : 1