mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	add simple metrics ui
This commit is contained in:
		
							parent
							
								
									e4f826a5a2
								
							
						
					
					
						commit
						b375cb839a
					
				| @ -2,5 +2,8 @@ | ||||
|     "extends": [ | ||||
|         "finn", | ||||
|         "finn/node" | ||||
|     ] | ||||
|     ], | ||||
|     "rules": { | ||||
|         "no-shadow": 0 | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,31 @@ | ||||
| import React, { Component } from 'react'; | ||||
| import { List, ListItem, ListSubHeader, ListDivider } from 'react-toolbox/lib/list'; | ||||
| import Chip from 'react-toolbox/lib/chip'; | ||||
| 
 | ||||
| class Metrics extends Component { | ||||
| 
 | ||||
|     componentDidMount () { | ||||
|         this.props.fetchMetrics(); | ||||
|     } | ||||
| 
 | ||||
|     render () { | ||||
|         const { globalCount, apps, clientList } = this.props; | ||||
| 
 | ||||
|         return ( | ||||
|             <List> | ||||
|                 <ListSubHeader caption={<span>Total of {globalCount} toggles checked from {apps.length} apps ({apps.join(', ')})</span>} /> | ||||
|                 <ListDivider /> | ||||
|                 {clientList.map(({ name, count, ping, appName }, i) => | ||||
|                     <ListItem | ||||
|                         leftActions={[<Chip>{count}</Chip>]} | ||||
|                         key={name + i} | ||||
|                         caption={appName} | ||||
|                         legend={`${name} pinged ${ping}`} /> | ||||
|                 )} | ||||
|             </List> | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| export default Metrics; | ||||
| @ -0,0 +1,39 @@ | ||||
| import { connect } from 'react-redux'; | ||||
| import Metrics from './metrics-component'; | ||||
| import { fetchMetrics } from '../../store/metrics-actions'; | ||||
| 
 | ||||
| const mapStateToProps = (state) => { | ||||
|     const globalCount = state.metrics.get('globalCount'); | ||||
|     const apps = state.metrics.get('apps').toArray(); | ||||
|     const clients = state.metrics.get('clients').toJS(); | ||||
| 
 | ||||
|     const clientList = Object | ||||
|         .keys(clients) | ||||
|         .map((k) => { | ||||
|             const client = clients[k]; | ||||
|             return { | ||||
|                 name: k, | ||||
|                 appName: client.appName, | ||||
|                 count: client.count, | ||||
|                 ping: new Date(client.ping), | ||||
|             }; | ||||
|         }) | ||||
|         .sort((a, b) => (a.ping > b.ping ? -1 : 1)); | ||||
| 
 | ||||
| 
 | ||||
|     /* | ||||
|         Possible stuff to ask/answer: | ||||
|         * toggles in use but not in unleash-server | ||||
|             * nr of toggles using fallbackValue | ||||
|         * strategies implemented but not used | ||||
|     */ | ||||
|     return { | ||||
|         globalCount, | ||||
|         apps, | ||||
|         clientList, | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| const MetricsContainer = connect(mapStateToProps, { fetchMetrics })(Metrics); | ||||
| 
 | ||||
| export default MetricsContainer; | ||||
| @ -14,10 +14,11 @@ export default class UnleashNav extends Component { | ||||
| 
 | ||||
|         return ( | ||||
|                 <List selectable ripple className={style.navigation}> | ||||
|                     {createListItem('/features', 'Feature Toggles')} | ||||
|                     {createListItem('/features', 'Feature toggles')} | ||||
|                     {createListItem('/strategies', 'Strategies')} | ||||
|                     {createListItem('/history', 'Event History')} | ||||
|                     {createListItem('/archive', 'Archived Toggles')} | ||||
|                     {createListItem('/history', 'Event history')} | ||||
|                     {createListItem('/archive', 'Archived toggles')} | ||||
|                     {createListItem('/metrics', 'Client metrics')} | ||||
| 
 | ||||
|                     <ListDivider /> | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										20
									
								
								packages/unleash-frontend-next/src/data/metrics-api.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								packages/unleash-frontend-next/src/data/metrics-api.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| const URI = '/metrics'; | ||||
| 
 | ||||
| function throwIfNotSuccess (response) { | ||||
|     if (!response.ok) { | ||||
|         let error = new Error('API call failed'); | ||||
|         error.status = response.status; | ||||
|         throw error; | ||||
|     } | ||||
|     return response; | ||||
| } | ||||
| 
 | ||||
| function fetchAll () { | ||||
|     return fetch(URI) | ||||
|         .then(throwIfNotSuccess) | ||||
|         .then(response => response.json()); | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
|     fetchAll, | ||||
| }; | ||||
| @ -15,6 +15,7 @@ import Strategies from './page/strategies'; | ||||
| import CreateStrategies from './page/strategies/create'; | ||||
| import HistoryPage from './page/history'; | ||||
| import Archive from './page/archive'; | ||||
| import Metrics from './page/metrics'; | ||||
| 
 | ||||
| const unleashStore = createStore( | ||||
|     store, | ||||
| @ -35,6 +36,7 @@ ReactDOM.render( | ||||
|                 <Route path="/strategies/create" component={CreateStrategies} /> | ||||
|                 <Route path="/history" component={HistoryPage} /> | ||||
|                 <Route path="/archive" component={Archive} /> | ||||
|                 <Route path="/metrics" component={Metrics} /> | ||||
|             </Route> | ||||
|         </Router> | ||||
|     </Provider>, document.getElementById('app')); | ||||
|  | ||||
							
								
								
									
										6
									
								
								packages/unleash-frontend-next/src/page/metrics/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								packages/unleash-frontend-next/src/page/metrics/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| import React from 'react'; | ||||
| import Metrics from '../../component/metrics/metrics-container'; | ||||
| 
 | ||||
| const render = () => <Metrics />; | ||||
| 
 | ||||
| export default render; | ||||
| @ -5,6 +5,7 @@ import input from './input-store'; | ||||
| import history from './history-store'; // eslint-disable-line
 | ||||
| import archive from './archive-store'; | ||||
| import error from './error-store'; | ||||
| import metrics from './metrics-store'; | ||||
| 
 | ||||
| const unleashStore = combineReducers({ | ||||
|     features, | ||||
| @ -13,6 +14,7 @@ const unleashStore = combineReducers({ | ||||
|     history, | ||||
|     archive, | ||||
|     error, | ||||
|     metrics, | ||||
| }); | ||||
| 
 | ||||
| export default unleashStore; | ||||
|  | ||||
							
								
								
									
										20
									
								
								packages/unleash-frontend-next/src/store/metrics-actions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								packages/unleash-frontend-next/src/store/metrics-actions.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| import api from '../data/metrics-api'; | ||||
| 
 | ||||
| export const RECEIVE_METRICS        = 'RECEIVE_METRICS'; | ||||
| export const ERROR_RECEIVE_METRICS  = 'ERROR_RECEIVE_METRICS'; | ||||
| 
 | ||||
| const receiveMetrics = (json) => ({ | ||||
|     type: RECEIVE_METRICS, | ||||
|     value: json, | ||||
| }); | ||||
| 
 | ||||
| const errorReceiveMetrics = (statusCode) => ({ | ||||
|     type: ERROR_RECEIVE_METRICS, | ||||
|     statusCode, | ||||
| }); | ||||
| 
 | ||||
| export function fetchMetrics () { | ||||
|     return dispatch => api.fetchAll() | ||||
|         .then(json => dispatch(receiveMetrics(json))) | ||||
|         .catch(error => dispatch(errorReceiveMetrics(error))); | ||||
| } | ||||
							
								
								
									
										21
									
								
								packages/unleash-frontend-next/src/store/metrics-store.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								packages/unleash-frontend-next/src/store/metrics-store.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| import { fromJS } from 'immutable'; | ||||
| import { RECEIVE_METRICS } from './metrics-actions'; | ||||
| 
 | ||||
| function getInitState () { | ||||
|     return fromJS({ | ||||
|         totalCount: 0, | ||||
|         apps: [], | ||||
|         clients: {}, | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| const historyStore = (state = getInitState(), action) => { | ||||
|     switch (action.type) { | ||||
|         case RECEIVE_METRICS: | ||||
|             return fromJS(action.value); | ||||
|         default: | ||||
|             return state; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| export default historyStore; | ||||
| @ -73,6 +73,10 @@ module.exports = { | ||||
|                 target: 'http://localhost:4242', | ||||
|                 secure: false, | ||||
|             }, | ||||
|             '/metrics': { | ||||
|                 target: 'http://localhost:4242', | ||||
|                 secure: false, | ||||
|             }, | ||||
|         }, | ||||
|     }, | ||||
| }; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user