1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

Merge pull request #32 from Unleash/strategies-in-metrics-view

Strategies in metrics view
This commit is contained in:
Sveinung Røsaker 2017-01-02 09:50:57 +01:00 committed by GitHub
commit 5659567766
6 changed files with 138 additions and 42 deletions

View File

@ -64,7 +64,7 @@ export const TogglesLinkList = ({ toggles }) => (
{toggles.length > 0 && toggles.map(({ name, description = '-', icon = 'toggle' }) => ( {toggles.length > 0 && toggles.map(({ name, description = '-', icon = 'toggle' }) => (
<ListItem twoLine key={name}> <ListItem twoLine key={name}>
<ListItemContent avatar={icon} subtitle={description}> <ListItemContent avatar={icon} subtitle={description}>
<Link key={name} to={`/features/edit/${name}`}> <Link key={name} to={`/features/view/${name}`}>
{name} {name}
</Link> </Link>
</ListItemContent> </ListItemContent>

View File

@ -8,20 +8,7 @@ import { DragSource, DropTarget } from 'react-dnd';
import { Link } from 'react-router'; import { Link } from 'react-router';
import StrategyInputPercentage from './strategy-input-percentage'; import StrategyInputPercentage from './strategy-input-percentage';
import StrategyInputList from './strategy-input-list'; import StrategyInputList from './strategy-input-list';
import styles from './strategy.scss';
const style = {
flex: '1',
minWidth: '300px',
maxWidth: '100%',
margin: '5px 20px 15px 0px',
};
const helpText = {
color: 'rgba(0,0,0, 0.54)',
fontSize: '12px',
lineHeight: '14px',
};
const dragSource = { const dragSource = {
beginDrag (props) { beginDrag (props) {
@ -105,7 +92,7 @@ class StrategyConfigure extends React.Component {
name={name} name={name}
onChange={this.handleConfigChange.bind(this, name)} onChange={this.handleConfigChange.bind(this, name)}
value={1 * value} /> value={1 * value} />
{description && <p style={helpText}>{description}</p>} {description && <p className={styles.helpText}>{description}</p>}
</div> </div>
); );
} else if (type === 'list') { } else if (type === 'list') {
@ -119,7 +106,7 @@ class StrategyConfigure extends React.Component {
return ( return (
<div key={name}> <div key={name}>
<StrategyInputList name={name} list={list} setConfig={this.setConfig} /> <StrategyInputList name={name} list={list} setConfig={this.setConfig} />
{description && <p style={helpText}>{description}</p>} {description && <p className={styles.helpText}>{description}</p>}
</div> </div>
); );
} else if (type === 'number') { } else if (type === 'number') {
@ -136,7 +123,7 @@ class StrategyConfigure extends React.Component {
onChange={this.handleConfigChange.bind(this, name)} onChange={this.handleConfigChange.bind(this, name)}
value={value} value={value}
/> />
{description && <p style={helpText}>{description}</p>} {description && <p className={styles.helpText}>{description}</p>}
</div> </div>
); );
} else { } else {
@ -152,7 +139,7 @@ class StrategyConfigure extends React.Component {
onChange={this.handleConfigChange.bind(this, name)} onChange={this.handleConfigChange.bind(this, name)}
value={value} value={value}
/> />
{description && <p style={helpText}>{description}</p>} {description && <p className={styles.helpText}>{description}</p>}
</div> </div>
); );
} }
@ -169,8 +156,8 @@ class StrategyConfigure extends React.Component {
const inputFields = this.renderInputFields(this.props.strategyDefinition); const inputFields = this.renderInputFields(this.props.strategyDefinition);
const { name } = this.props.strategy; const { name } = this.props.strategy;
item = ( item = (
<Card shadow={0} style={{ background: '#f2f9fc', width: '100%', display: 'block', opacity: isDragging ? '0.1' : '1' }}> <Card shadow={0} className={styles.card} style={{ opacity: isDragging ? '0.1' : '1' }}>
<CardTitle style={{ color: '#fff', height: '65px', background: '#607d8b' }}> <CardTitle className={styles.cardTitle}>
<Icon name="extension" />&nbsp;{name} <Icon name="extension" />&nbsp;{name}
</CardTitle> </CardTitle>
<CardText> <CardText>
@ -182,27 +169,23 @@ class StrategyConfigure extends React.Component {
</CardActions> </CardActions>
} }
<CardMenu style={{ color: '#fff' }}> <CardMenu className="mdl-color-text--white">
<Link <Link
title="View strategy" title="View strategy"
to={`/strategies/view/${name}`} to={`/strategies/view/${name}`}
style={{ color: '#fff', display: 'inline-block', verticalAlign: 'bottom', marginRight: '5px' }}> className={styles.editLink}>
<Icon name="link" /> <Icon name="link" />
</Link> </Link>
<IconButton title="Remove strategy from toggle" name="delete" onClick={this.handleRemove} /> <IconButton title="Remove strategy from toggle" name="delete" onClick={this.handleRemove} />
{connectDragSource( {connectDragSource(
<span style={{ <span className={styles.reorderIcon}><Icon name="reorder" /></span>)}
cursor: 'pointer',
display: 'inline-block',
verticalAlign: 'bottom',
}}><Icon name="reorder" /></span>)}
</CardMenu> </CardMenu>
</Card> </Card>
); );
} else { } else {
const { name } = this.props.strategy; const { name } = this.props.strategy;
item = ( item = (
<Card shadow={0} style={style}> <Card shadow={0} className={styles.card}>
<CardTitle>"{name}" deleted?</CardTitle> <CardTitle>"{name}" deleted?</CardTitle>
<CardText> <CardText>
The strategy "{name}" does not exist on this server. The strategy "{name}" does not exist on this server.
@ -217,7 +200,7 @@ class StrategyConfigure extends React.Component {
} }
return (connectDropTarget(connectDragPreview( return (connectDropTarget(connectDragPreview(
<div style={style}>{item}</div> <div className={styles.item}>{item}</div>
))); )));
} }
} }

View File

@ -0,0 +1,58 @@
.item {
flex: 1;
min-width: 300px;
max-width: 100%;
margin: 5px 0px 15px 35px;
position: relative;
z-index: 1;
};
.card {
width: 100%;
display: block;
background-color: #f2f9fc;
}
.item:first-child {
margin-left: 0;
}
.item:not(:first-child):after {
content: " OR ";
position: absolute;
left: -30px;
top: 45%;
color: #ccc;
width: 25px;
line-height: 32px;
font-size: 14px;
text-align: center;
height: 100%;
z-index: 2;
}
.cardTitle {
color: #fff;
height: 65px;
background-color: #607d8b !important;
}
.helpText {
color: rgba(0,0,0, 0.54);
font-size: 12px;
line-height: 14px;
};
.editLink {
color: #fff;
display: inline-block;
vertical-align: bottom;
margin-right: 5px;
}
.reorderIcon {
cursor: pointer;
display: inline-block;
vertical-align: bottom;
}

View File

@ -1,8 +1,25 @@
import React, { PropTypes } from 'react'; import React, { PropTypes } from 'react';
import { Grid, Cell, Icon } from 'react-mdl'; import { Grid, Cell, Icon, Chip, ChipContact } from 'react-mdl';
import Progress from './progress'; import Progress from './progress';
import { Link } from 'react-router';
import { AppsLinkList, SwitchWithLabel, calc } from '../common'; import { AppsLinkList, SwitchWithLabel, calc } from '../common';
import styles from './metrics.scss';
const StrategyChipItem = ({ strategy }) => (
<Chip className={styles.chip}>
<ChipContact className="mdl-color--blue-grey mdl-color-text--white">
<Icon style={{ marginTop: '3px' }} name="link" />
</ChipContact>
<Link to={`/strategies/view/${strategy.name}`} className="mdl-color-text--blue-grey">{strategy.name}</Link>
</Chip>
);
// TODO what about "missing" strategies here?
const StrategiesList = ({ strategies }) => (
<div style={{ verticalAlign: 'middle' }}>With {strategies.length > 1 ? 'strategies' : 'strategy'} {
strategies.map((strategy, i) => <StrategyChipItem key={i} strategy={strategy} />)
}</div>
);
export default class MetricComponent extends React.Component { export default class MetricComponent extends React.Component {
static propTypes () { static propTypes () {
@ -39,16 +56,17 @@ export default class MetricComponent extends React.Component {
const lastMinutePercent = 1 * calc(lastMinute.yes, lastMinute.yes + lastMinute.no, 0); const lastMinutePercent = 1 * calc(lastMinute.yes, lastMinute.yes + lastMinute.no, 0);
return (<div> return (<div>
<div style={{ paddingTop: '4px' }}>
<SwitchWithLabel <SwitchWithLabel
checked={featureToggle.enabled} checked={featureToggle.enabled}
onChange={() => toggleFeature(featureToggle)}>Toggle {featureToggle.name}</SwitchWithLabel> onChange={() => toggleFeature(featureToggle)}>Toggle {featureToggle.name}</SwitchWithLabel>
<hr /> </div>
<hr style={{ borderColor: '#e0e0e0' }} />
<Grid style={{ textAlign: 'center' }}> <Grid style={{ textAlign: 'center' }}>
<Cell tablet={4} col={3} phone={12}> <Cell tablet={4} col={3} phone={12}>
{ {
lastMinute.isFallback ? lastMinute.isFallback ?
<Icon style={{ width: '100px', height: '100px', fontSize: '100px', color: '#ccc' }} <Icon className={styles.problemIcon} name="report problem" title="No metrics avaiable" /> :
name="report problem" title="No metrics avaiable" /> :
<div> <div>
<Progress animatePercentageText strokeWidth={10} percentage={lastMinutePercent} width="50" /> <Progress animatePercentageText strokeWidth={10} percentage={lastMinutePercent} width="50" />
</div> </div>
@ -58,8 +76,7 @@ export default class MetricComponent extends React.Component {
<Cell col={3} tablet={4} phone={12}> <Cell col={3} tablet={4} phone={12}>
{ {
lastHour.isFallback ? lastHour.isFallback ?
<Icon style={{ width: '100px', height: '100px', fontSize: '100px', color: '#ccc' }} <Icon className={styles.problemIcon} name="report problem" title="No metrics avaiable" /> :
name="report problem" title="No metrics avaiable" /> :
<div> <div>
<Progress strokeWidth={10} percentage={lastHourPercent} width="50" /> <Progress strokeWidth={10} percentage={lastHourPercent} width="50" />
</div> </div>
@ -70,8 +87,7 @@ export default class MetricComponent extends React.Component {
{seenApps.length > 0 ? {seenApps.length > 0 ?
(<div><strong>Seen in applications:</strong></div>) : (<div><strong>Seen in applications:</strong></div>) :
<div> <div>
<Icon style={{ width: '100px', height: '100px', fontSize: '100px', color: '#ccc' }} <Icon className={styles.problemIcon} name="report problem" title="Not used in a app in the last hour" />
name="report problem" title="Not used in a app in the last hour" />
<div><small><strong>Not used in a app in the last hour.</strong> <div><small><strong>Not used in a app in the last hour.</strong>
This might be due to your client implementation is not reporting usage.</small></div> This might be due to your client implementation is not reporting usage.</small></div>
</div> </div>
@ -79,6 +95,8 @@ export default class MetricComponent extends React.Component {
<AppsLinkList apps={seenApps} /> <AppsLinkList apps={seenApps} />
</Cell> </Cell>
</Grid> </Grid>
<hr style={{ borderColor: '#e0e0e0' }} />
<StrategiesList strategies={featureToggle.strategies}/>
</div>); </div>);
} }
} }

View File

@ -0,0 +1,37 @@
.chip {
display: inline-block;
vertical-align: middle;
margin-left: 30px;
position: relative;
z-index: 1;
overflow: visible;
}
.chip:first-child {
margin-left: 0;
}
.chip:not(:first-child):after {
content: " OR ";
position: absolute;
left: -27px;
top: 0;
color: #ccc;
width: 25px;
line-height: 32px;
font-size: 14px;
text-align: center;
height: 100%;
z-index: 2;
}
.chip:first-child:before {
content: ''
}
.problemIcon {
width: 100px;
height: 100px;
font-size: 100px !important;
color: #ccc;
}

View File

@ -83,7 +83,7 @@ export default class ViewFeatureToggleComponent extends React.Component {
Created {(new Date(featureToggle.createdAt)).toLocaleString('nb-NO')} Created {(new Date(featureToggle.createdAt)).toLocaleString('nb-NO')}
</small> </small>
</h4> </h4>
<div>{featureToggle.description}</div> <div className="mdl-color-text--grey"><small>{featureToggle.description}</small></div>
<Tabs activeTab={activeTabId} ripple style={{ marginBottom: '10px' }}> <Tabs activeTab={activeTabId} ripple style={{ marginBottom: '10px' }}>
<Tab onClick={() => this.goToTab('view', featureToggleName)}>Metrics</Tab> <Tab onClick={() => this.goToTab('view', featureToggleName)}>Metrics</Tab>
<Tab onClick={() => this.goToTab('edit', featureToggleName)}>Edit</Tab> <Tab onClick={() => this.goToTab('edit', featureToggleName)}>Edit</Tab>