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": [ |     "extends": [ | ||||||
|         "finn", |         "finn", | ||||||
|         "finn/node" |         "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 ( |         return ( | ||||||
|                 <List selectable ripple className={style.navigation}> |                 <List selectable ripple className={style.navigation}> | ||||||
|                     {createListItem('/features', 'Feature Toggles')} |                     {createListItem('/features', 'Feature toggles')} | ||||||
|                     {createListItem('/strategies', 'Strategies')} |                     {createListItem('/strategies', 'Strategies')} | ||||||
|                     {createListItem('/history', 'Event History')} |                     {createListItem('/history', 'Event history')} | ||||||
|                     {createListItem('/archive', 'Archived Toggles')} |                     {createListItem('/archive', 'Archived toggles')} | ||||||
|  |                     {createListItem('/metrics', 'Client metrics')} | ||||||
| 
 | 
 | ||||||
|                     <ListDivider /> |                     <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 CreateStrategies from './page/strategies/create'; | ||||||
| import HistoryPage from './page/history'; | import HistoryPage from './page/history'; | ||||||
| import Archive from './page/archive'; | import Archive from './page/archive'; | ||||||
|  | import Metrics from './page/metrics'; | ||||||
| 
 | 
 | ||||||
| const unleashStore = createStore( | const unleashStore = createStore( | ||||||
|     store, |     store, | ||||||
| @ -35,6 +36,7 @@ ReactDOM.render( | |||||||
|                 <Route path="/strategies/create" component={CreateStrategies} /> |                 <Route path="/strategies/create" component={CreateStrategies} /> | ||||||
|                 <Route path="/history" component={HistoryPage} /> |                 <Route path="/history" component={HistoryPage} /> | ||||||
|                 <Route path="/archive" component={Archive} /> |                 <Route path="/archive" component={Archive} /> | ||||||
|  |                 <Route path="/metrics" component={Metrics} /> | ||||||
|             </Route> |             </Route> | ||||||
|         </Router> |         </Router> | ||||||
|     </Provider>, document.getElementById('app')); |     </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 history from './history-store'; // eslint-disable-line
 | ||||||
| import archive from './archive-store'; | import archive from './archive-store'; | ||||||
| import error from './error-store'; | import error from './error-store'; | ||||||
|  | import metrics from './metrics-store'; | ||||||
| 
 | 
 | ||||||
| const unleashStore = combineReducers({ | const unleashStore = combineReducers({ | ||||||
|     features, |     features, | ||||||
| @ -13,6 +14,7 @@ const unleashStore = combineReducers({ | |||||||
|     history, |     history, | ||||||
|     archive, |     archive, | ||||||
|     error, |     error, | ||||||
|  |     metrics, | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| export default unleashStore; | 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', |                 target: 'http://localhost:4242', | ||||||
|                 secure: false, |                 secure: false, | ||||||
|             }, |             }, | ||||||
|  |             '/metrics': { | ||||||
|  |                 target: 'http://localhost:4242', | ||||||
|  |                 secure: false, | ||||||
|  |             }, | ||||||
|         }, |         }, | ||||||
|     }, |     }, | ||||||
| }; | }; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user