diff --git a/packages/unleash-api/lib/client-metrics/ttl-list.js b/packages/unleash-api/lib/client-metrics/ttl-list.js
index 7aa141aa6d..8b046847df 100644
--- a/packages/unleash-api/lib/client-metrics/ttl-list.js
+++ b/packages/unleash-api/lib/client-metrics/ttl-list.js
@@ -29,7 +29,6 @@ module.exports = class TTLList extends EventEmitter {
let done = false;
// TODO: might use internal linkedlist
this.cache.forEachReverse((entry, index) => {
- console.log(now.format(), entry.ttl.format());
if (done) {
return;
} else if (now.isBefore(entry.ttl)) {
diff --git a/packages/unleash-api/lib/routes/metrics.js b/packages/unleash-api/lib/routes/metrics.js
index acc441813a..35640fa7b9 100644
--- a/packages/unleash-api/lib/routes/metrics.js
+++ b/packages/unleash-api/lib/routes/metrics.js
@@ -23,7 +23,7 @@ module.exports = function (app, config) {
res.json(metrics.getMetricsOverview());
});
- app.get('/toggle-metrics', (req, res) => {
+ app.get('/metrics/features', (req, res) => {
res.json(metrics.getTogglesMetrics());
});
diff --git a/packages/unleash-frontend-next/src/component/feature/feature-component.jsx b/packages/unleash-frontend-next/src/component/feature/feature-component.jsx
index 6513a922b3..8843d9b059 100644
--- a/packages/unleash-frontend-next/src/component/feature/feature-component.jsx
+++ b/packages/unleash-frontend-next/src/component/feature/feature-component.jsx
@@ -8,7 +8,7 @@ import Chip from 'react-toolbox/lib/chip';
import style from './feature.scss';
-const Feature = ({ feature, onFeatureClick, onFeatureRemove }) => {
+const Feature = ({ feature, onFeatureClick, onFeatureRemove, metrics = { yes: 0, no: 0, hasData: false } }) => {
const { name, description, enabled, strategies } = feature;
const actions = [
@@ -20,6 +20,7 @@ const Feature = ({ feature, onFeatureClick, onFeatureRemove }) => {
];
const leftActions = [
+ {metrics.yes} / {metrics.no},
onFeatureClick(feature)} checked={enabled} />,
];
diff --git a/packages/unleash-frontend-next/src/component/feature/feature.scss b/packages/unleash-frontend-next/src/component/feature/feature.scss
index 2f99d5281c..636272d55f 100644
--- a/packages/unleash-frontend-next/src/component/feature/feature.scss
+++ b/packages/unleash-frontend-next/src/component/feature/feature.scss
@@ -6,3 +6,11 @@
color: #aaa !important;
cursor: pointer;
}
+
+.yes {
+ color: green;
+}
+
+.no {
+ color: red;
+}
diff --git a/packages/unleash-frontend-next/src/component/feature/list-component.jsx b/packages/unleash-frontend-next/src/component/feature/list-component.jsx
index 8ef6b55c66..e725cba7ac 100644
--- a/packages/unleash-frontend-next/src/component/feature/list-component.jsx
+++ b/packages/unleash-frontend-next/src/component/feature/list-component.jsx
@@ -9,7 +9,9 @@ export default class FeatureListComponent extends React.Component {
onFeatureClick: PropTypes.func.isRequired,
onFeatureRemove: PropTypes.func.isRequired,
features: PropTypes.array.isRequired,
- fetchFeatureToggles: PropTypes.array.isRequired,
+ featureMetrics: PropTypes.object.isRequired,
+ fetchFeatureToggles: PropTypes.func.isRequired,
+ fetchFeatureMetrics: PropTypes.func.isRequired,
};
}
@@ -19,16 +21,24 @@ export default class FeatureListComponent extends React.Component {
componentDidMount () {
this.props.fetchFeatureToggles();
+ this.props.fetchFeatureMetrics();
+ this.timer = setInterval(() => {
+ this.props.fetchFeatureMetrics();
+ }, 5000);
+ }
+
+ componentWillUnmount () {
+ clearInterval(this.timer);
}
render () {
- const { features, onFeatureClick, onFeatureRemove } = this.props;
+ const { features, onFeatureClick, onFeatureRemove, featureMetrics } = this.props;
return (
{features.map((feature, i) =>
-
+
)}
({
features: state.features.toJS(),
+ featureMetrics: state.featureMetrics.toJS(),
});
const mapDispatchToProps = {
onFeatureClick: toggleFeature,
onFeatureRemove: removeFeatureToggle,
fetchFeatureToggles,
+ fetchFeatureMetrics,
};
const FeatureListContainer = connect(
diff --git a/packages/unleash-frontend-next/src/component/metrics/metrics-component.js b/packages/unleash-frontend-next/src/component/metrics/metrics-component.js
index 4b47bf2b42..fbe3dc49d6 100644
--- a/packages/unleash-frontend-next/src/component/metrics/metrics-component.js
+++ b/packages/unleash-frontend-next/src/component/metrics/metrics-component.js
@@ -13,7 +13,7 @@ class Metrics extends Component {
return (
- Total of {globalCount} toggles checked from {apps.length} apps ({apps.join(', ')})} />
+ Total of {globalCount} toggles } />
{clientList.map(({ name, count, ping, appName }, i) =>
{
+ dispatch({ type, error, receivedAt: Date.now() });
+ throw error;
+ };
+}
+
+export function fetchFeatureMetrics () {
+ return dispatch => {
+ dispatch({ type: START_FETCH_FEATURE_METRICS });
+
+ return api.fetchFeatureMetrics()
+ .then(json => dispatch(receiveFeatureMetrics(json)))
+ .catch(dispatchAndThrow(dispatch, ERROR_FETCH_FEATURE_TOGGLES));
+ };
+}
diff --git a/packages/unleash-frontend-next/src/store/feature-metrics-api.js b/packages/unleash-frontend-next/src/store/feature-metrics-api.js
new file mode 100644
index 0000000000..cc4d28cac1
--- /dev/null
+++ b/packages/unleash-frontend-next/src/store/feature-metrics-api.js
@@ -0,0 +1,29 @@
+const defaultErrorMessage = 'Unexptected exception when talking to unleash-api';
+
+function throwIfNotSuccess (response) {
+ if (!response.ok) {
+ if (response.status > 400 && response.status < 404) {
+ return new Promise((resolve, reject) => {
+ response.json().then(body => {
+ const errorMsg = body && body.length > 0 ? body[0].msg : defaultErrorMessage;
+ let error = new Error(errorMsg);
+ error.statusCode = response.status;
+ reject(error);
+ });
+ });
+ } else {
+ return Promise.reject(new Error(defaultErrorMessage));
+ }
+ }
+ return Promise.resolve(response);
+}
+
+function fetchFeatureMetrics () {
+ return fetch('/metrics/features')
+ .then(throwIfNotSuccess)
+ .then(response => response.json());
+}
+
+module.exports = {
+ fetchFeatureMetrics,
+};
diff --git a/packages/unleash-frontend-next/src/store/feature-metrics-store.js b/packages/unleash-frontend-next/src/store/feature-metrics-store.js
new file mode 100644
index 0000000000..77886b66a7
--- /dev/null
+++ b/packages/unleash-frontend-next/src/store/feature-metrics-store.js
@@ -0,0 +1,17 @@
+import { Map as $Map } from 'immutable';
+
+import {
+ RECEIVE_FEATURE_METRICS,
+} from './feature-metrics-actions';
+
+
+const metrics = (state = new $Map(), action) => {
+ switch (action.type) {
+ case RECEIVE_FEATURE_METRICS:
+ return new $Map(action.metrics);
+ default:
+ return state;
+ }
+};
+
+export default metrics;
diff --git a/packages/unleash-frontend-next/src/store/index.js b/packages/unleash-frontend-next/src/store/index.js
index c073cdb738..2710c6cc1e 100644
--- a/packages/unleash-frontend-next/src/store/index.js
+++ b/packages/unleash-frontend-next/src/store/index.js
@@ -1,5 +1,6 @@
import { combineReducers } from 'redux';
import features from './feature-store';
+import featureMetrics from './feature-metrics-store';
import strategies from './strategy-store';
import input from './input-store';
import history from './history-store'; // eslint-disable-line
@@ -11,6 +12,7 @@ import clientInstances from './client-instance-store';
const unleashStore = combineReducers({
features,
+ featureMetrics,
strategies,
input,
history,