1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-20 00:08:02 +01:00

add seen apps

This commit is contained in:
sveisvei 2016-12-05 14:19:19 +01:00
parent b95564f2cf
commit d2ea5db48c
4 changed files with 85 additions and 27 deletions

View File

@ -1,5 +1,6 @@
import React, { PropTypes } from 'react'; import React, { PropTypes } from 'react';
import { Grid, Cell, Icon, Switch } from 'react-mdl'; import { Grid, Cell, Icon, Switch } from 'react-mdl';
import { Link } from 'react-router';
import percentLib from 'percent'; import percentLib from 'percent';
import Progress from './progress'; import Progress from './progress';
@ -7,7 +8,7 @@ import Progress from './progress';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import EditFeatureToggle from './form-edit-container.jsx'; import EditFeatureToggle from './form-edit-container.jsx';
import { fetchFeatureToggles, toggleFeature } from '../../store/feature-actions'; import { fetchFeatureToggles, toggleFeature } from '../../store/feature-actions';
import { fetchFeatureMetrics } from '../../store/feature-metrics-actions'; import { fetchFeatureMetrics, fetchSeenApps } from '../../store/feature-metrics-actions';
class EditFeatureToggleWrapper extends React.Component { class EditFeatureToggleWrapper extends React.Component {
@ -23,6 +24,7 @@ class EditFeatureToggleWrapper extends React.Component {
if (this.props.features.length === 0) { if (this.props.features.length === 0) {
this.props.fetchFeatureToggles(); this.props.fetchFeatureToggles();
} }
this.props.fetchSeenApps();
this.props.fetchFeatureMetrics(); this.props.fetchFeatureMetrics();
setInterval(() => { setInterval(() => {
this.props.fetchFeatureMetrics(); this.props.fetchFeatureMetrics();
@ -34,14 +36,17 @@ class EditFeatureToggleWrapper extends React.Component {
toggleFeature, toggleFeature,
features, features,
featureToggleName, featureToggleName,
metrics = { metrics = {},
lastHour: { yes: 0, no: 0, isFallback: true },
lastMinute: { yes: 0, no: 0, isFallback: true },
},
} = this.props; } = this.props;
const lastHourPercent = 1 * percentLib.calc(metrics.lastHour.yes, metrics.lastHour.yes + metrics.lastHour.no, 0); const {
const lastMinutePercent = 1 * percentLib.calc(metrics.lastMinute.yes, metrics.lastMinute.yes + metrics.lastMinute.no, 0); lastHour = { yes: 0, no: 0, isFallback: true },
lastMinute = { yes: 0, no: 0, isFallback: true },
seenApps = [],
} = metrics;
const lastHourPercent = 1 * percentLib.calc(lastHour.yes, lastHour.yes + lastHour.no, 0);
const lastMinutePercent = 1 * percentLib.calc(lastMinute.yes, lastMinute.yes + lastMinute.no, 0);
const featureToggle = features.find(toggle => toggle.name === featureToggleName); const featureToggle = features.find(toggle => toggle.name === featureToggleName);
@ -56,38 +61,50 @@ class EditFeatureToggleWrapper extends React.Component {
<div> <div>
<h4>{featureToggle.name} <small>{featureToggle.enabled ? 'is enabled' : 'is disabled'}</small></h4> <h4>{featureToggle.name} <small>{featureToggle.enabled ? 'is enabled' : 'is disabled'}</small></h4>
<hr /> <hr />
<div style={{ maxWidth: '150px' }} > <div style={{ maxWidth: '200px' }} >
<Switch style={{ cursor: 'pointer' }} onChange={() => toggleFeature(featureToggle)} checked={featureToggle.enabled}> <Switch style={{ cursor: 'pointer' }} onChange={() => toggleFeature(featureToggle)} checked={featureToggle.enabled}>
Toggle {featureToggle.name} Toggle {featureToggle.name}
</Switch> </Switch>
</div> </div>
<hr /> <hr />
<Grid> <Grid style={{ textAlign: 'center' }}>
<Cell col={3} style={{ textAlign: 'center' }}> <Cell col={3}>
{ {
metrics.lastMinute.isFallback ? lastMinute.isFallback ?
<Icon style={{ width: '100px', height: '100px', fontSize: '100px', color: '#ccc' }} name="report problem" title="No metrics avaiable" /> : <Icon style={{ width: '100px', height: '100px', fontSize: '100px', color: '#ccc' }} name="report problem" title="No metrics avaiable" /> :
<div> <div>
<Progress strokeWidth={10} percentage={lastMinutePercent} width="50" /> <Progress strokeWidth={10} percentage={lastMinutePercent} width="50" />
</div> </div>
} }
<p><strong>Last minute:</strong> Yes {metrics.lastMinute.yes}, No: {metrics.lastMinute.no}</p> <p><strong>Last minute:</strong> Yes {lastMinute.yes}, No: {lastMinute.no}</p>
</Cell> </Cell>
<Cell col={3} style={{ textAlign: 'center' }}> <Cell col={3}>
{ {
metrics.lastHour.isFallback ? lastHour.isFallback ?
<Icon style={{ width: '100px', height: '100px', fontSize: '100px', color: '#ccc' }} name="report problem" title="No metrics avaiable" /> : <Icon style={{ width: '100px', height: '100px', fontSize: '100px', color: '#ccc' }} 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>
} }
<p><strong>Last hour:</strong> Yes {metrics.lastHour.yes}, No: {metrics.lastHour.no}</p> <p><strong>Last hour:</strong> Yes {lastHour.yes}, No: {lastHour.no}</p>
</Cell> </Cell>
<Cell col={3}> <Cell col={3}>
<p>add apps</p> {seenApps.length > 0 ?
(<div><strong>Seen in applications:</strong></div>) :
<div>
<Icon style={{ width: '100px', height: '100px', fontSize: '100px', color: '#ccc' }} 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> This might be due to your client implementation is not reporting usage.</small></div>
</div>
}
{seenApps.length > 0 && seenApps.map((appName) => (
<Link key={appName} to={`/applications/${appName}`}>
{appName}
</Link>
))}
<p>add instances count?</p>
</Cell> </Cell>
<Cell col={3}> <Cell col={3}>
<p>add instances</p> <p>add history</p>
</Cell> </Cell>
</Grid> </Grid>
<hr /> <hr />
@ -102,12 +119,16 @@ function getMetricsForToggle (state, toggleName) {
if (!toggleName) { if (!toggleName) {
return; return;
} }
if (state.featureMetrics.hasIn(['lastHour', toggleName])) { const result = {};
return {
lastHour: state.featureMetrics.getIn(['lastHour', toggleName]), if (state.featureMetrics.hasIn(['seenApps', toggleName])) {
lastMinute: state.featureMetrics.getIn(['lastMinute', toggleName]), result.seenApps = state.featureMetrics.getIn(['seenApps', toggleName]);
};
} }
if (state.featureMetrics.hasIn(['lastHour', toggleName])) {
result.lastHour = state.featureMetrics.getIn(['lastHour', toggleName]);
result.lastMinute = state.featureMetrics.getIn(['lastMinute', toggleName]);
}
return result;
} }
@ -118,4 +139,5 @@ export default connect((state, props) => ({
fetchFeatureMetrics, fetchFeatureMetrics,
fetchFeatureToggles, fetchFeatureToggles,
toggleFeature, toggleFeature,
fetchSeenApps,
})(EditFeatureToggleWrapper); })(EditFeatureToggleWrapper);

View File

@ -8,6 +8,15 @@ function fetchFeatureMetrics () {
.then(response => response.json()); .then(response => response.json());
} }
const seenURI = '/api/client/seen-apps';
function fetchSeenApps () {
return fetch(seenURI)
.then(throwIfNotSuccess)
.then(response => response.json());
}
module.exports = { module.exports = {
fetchFeatureMetrics, fetchFeatureMetrics,
fetchSeenApps,
}; };

View File

@ -4,10 +4,22 @@ export const START_FETCH_FEATURE_METRICS = 'START_FETCH_FEATURE_METRICS';
export const RECEIVE_FEATURE_METRICS = 'RECEIVE_FEATURE_METRICS'; export const RECEIVE_FEATURE_METRICS = 'RECEIVE_FEATURE_METRICS';
export const ERROR_FETCH_FEATURE_TOGGLES = 'ERROR_FETCH_FEATURE_TOGGLES'; export const ERROR_FETCH_FEATURE_TOGGLES = 'ERROR_FETCH_FEATURE_TOGGLES';
export const START_FETCH_SEEN_APP = 'START_FETCH_SEEN_APP';
export const RECEIVE_SEEN_APPS = 'RECEIVE_SEEN_APPS';
export const ERROR_FETCH_SEEN_APP = 'ERROR_FETCH_SEEN_APP';
function receiveFeatureMetrics (json) { function receiveFeatureMetrics (json) {
return { return {
type: RECEIVE_FEATURE_METRICS, type: RECEIVE_FEATURE_METRICS,
metrics: json, value: json,
receivedAt: Date.now(),
};
}
function receiveSeenApps (json) {
return {
type: RECEIVE_SEEN_APPS,
value: json,
receivedAt: Date.now(), receivedAt: Date.now(),
}; };
} }
@ -21,10 +33,21 @@ function dispatchAndThrow (dispatch, type) {
export function fetchFeatureMetrics () { export function fetchFeatureMetrics () {
return dispatch => { return dispatch => {
dispatch({ type: START_FETCH_FEATURE_METRICS }); dispatch({ type: START_FETCH_SEEN_APP });
return api.fetchFeatureMetrics() return api.fetchFeatureMetrics()
.then(json => dispatch(receiveFeatureMetrics(json))) .then(json => dispatch(receiveFeatureMetrics(json)))
.catch(dispatchAndThrow(dispatch, ERROR_FETCH_SEEN_APP));
};
}
export function fetchSeenApps () {
return dispatch => {
dispatch({ type: START_FETCH_FEATURE_METRICS });
return api.fetchSeenApps()
.then(json => dispatch(receiveSeenApps(json)))
.catch(dispatchAndThrow(dispatch, ERROR_FETCH_FEATURE_TOGGLES)); .catch(dispatchAndThrow(dispatch, ERROR_FETCH_FEATURE_TOGGLES));
}; };
} }

View File

@ -2,15 +2,19 @@ import { Map as $Map, fromJS } from 'immutable';
import { import {
RECEIVE_FEATURE_METRICS, RECEIVE_FEATURE_METRICS,
RECEIVE_SEEN_APPS,
} from './feature-metrics-actions'; } from './feature-metrics-actions';
const metrics = (state = fromJS({ lastHour: {}, lastMinute: {} }), action) => { const metrics = (state = fromJS({ lastHour: {}, lastMinute: {}, seenApps: {} }), action) => {
switch (action.type) { switch (action.type) {
case RECEIVE_SEEN_APPS:
console.log('RECEIVE_SEEN_APPS', action.value);
return state.set('seenApps', new $Map(action.value));
case RECEIVE_FEATURE_METRICS: case RECEIVE_FEATURE_METRICS:
return state.withMutations((ctx) => { return state.withMutations((ctx) => {
ctx.set('lastHour', new $Map(action.metrics.lastHour)); ctx.set('lastHour', new $Map(action.value.lastHour));
ctx.set('lastMinute', new $Map(action.metrics.lastMinute)); ctx.set('lastMinute', new $Map(action.value.lastMinute));
return ctx; return ctx;
}); });
default: default: