diff --git a/frontend/src/component/app.jsx b/frontend/src/component/app.jsx index 6687523056..da7081e7c9 100644 --- a/frontend/src/component/app.jsx +++ b/frontend/src/component/app.jsx @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import { Layout, Drawer, Header, Navigation, Content, Footer, FooterSection, FooterDropDownSection, FooterLinkList, - Grid, Cell + Grid, Cell, } from 'react-mdl'; import style from './styles.scss'; import ErrorContainer from './error/error-container'; @@ -9,10 +9,7 @@ import ErrorContainer from './error/error-container'; import UserContainer from './user/user-container'; import ShowUserContainer from './user/show-user-container'; - - export default class App extends Component { - constructor (props) { super(props); this.state = { drawerActive: false }; @@ -40,7 +37,7 @@ export default class App extends Component { render () { const createListItem = (path, caption) => {caption} ; @@ -62,6 +59,7 @@ export default class App extends Component { {createListItem('/history', 'Event history')} {createListItem('/archive', 'Archived toggles')}
+ {createListItem('/applications', 'Applications')} {createListItem('/metrics', 'Client metrics')} {createListItem('/client-strategies', 'Client strategies')} {createListItem('/client-instances', 'Client instances')} @@ -86,6 +84,7 @@ export default class App extends Component { + {createListItem('/applications', 'Applications')} {createListItem('/metrics', 'Client metrics')} {createListItem('/client-strategies', 'Client strategies')} {createListItem('/client-instances', 'Client instances')} diff --git a/frontend/src/component/application/application-edit-component.js b/frontend/src/component/application/application-edit-component.js new file mode 100644 index 0000000000..fa679fe2f2 --- /dev/null +++ b/frontend/src/component/application/application-edit-component.js @@ -0,0 +1,57 @@ +import React, { Component } from 'react'; + +import { Link } from 'react-router'; +import { Grid, Cell } from 'react-mdl'; + +class ClientStrategies extends Component { + + componentDidMount () { + this.props.fetchApplication(this.props.appName); + } + + render () { + if (!this.props.application) { + return
Loading application info...
; + } + const { + appName, + instances, + strategies, + seenToggles, + } = this.props.application; + + return ( +
+
{appName}
+ + + +
Instances
+
    + {instances.map(({ instanceId }, i) =>
  1. {instanceId}
  2. )} +
+
+ +
Strategies
+
    + {/*strategies.map((name, i) =>
  1. {name}
  2. )*/} +
+
+ +
Toggles
+
    + {seenToggles.map((name, i) =>
  1. + + {name} + +
  2. )} +
+
+
+
+ ); + } +} + + +export default ClientStrategies; diff --git a/frontend/src/component/application/application-edit-container.js b/frontend/src/component/application/application-edit-container.js new file mode 100644 index 0000000000..fa76680372 --- /dev/null +++ b/frontend/src/component/application/application-edit-container.js @@ -0,0 +1,17 @@ +import { connect } from 'react-redux'; +import ApplicationEdit from './application-edit-component'; +import { fetchApplication } from '../../store/application/actions'; + +const mapStateToProps = (state, props) => { + let application = state.applications.getIn(['apps', props.appName]); + if (application) { + application = application.toJS(); + } + return { + application, + }; +}; + +const Constainer = connect(mapStateToProps, { fetchApplication })(ApplicationEdit); + +export default Constainer; diff --git a/frontend/src/component/application/application-list-component.js b/frontend/src/component/application/application-list-component.js index 796183b17c..ccf44e7a48 100644 --- a/frontend/src/component/application/application-list-component.js +++ b/frontend/src/component/application/application-list-component.js @@ -1,20 +1,27 @@ import React, { Component } from 'react'; +import { Link } from 'react-router'; class ClientStrategies extends Component { componentDidMount () { - this.props.fetchApplications(); + this.props.fetchAll(); } render () { - if (!this.props.applications) { - return null; - } - const source = this.props.applications.map(item => item.appName).join(', '); + const { + applications, + } = this.props; + if (!applications) { + return
loading...
; + } return (
- {source} + {applications.map(item => ( + + Link: {item.appName} + + ))}
); } diff --git a/frontend/src/component/application/application-list-container.js b/frontend/src/component/application/application-list-container.js index 9d0322ef94..519527955d 100644 --- a/frontend/src/component/application/application-list-container.js +++ b/frontend/src/component/application/application-list-container.js @@ -1,9 +1,9 @@ import { connect } from 'react-redux'; import ApplicationList from './application-list-component'; -import { fetchApplications } from '../../store/application/actions'; +import { fetchAll } from '../../store/application/actions'; -const mapStateToProps = (state) => ({ applications: state.applications.toJS() }); +const mapStateToProps = (state) => ({ applications: state.applications.get('list').toJS() }); -const StrategiesContainer = connect(mapStateToProps, { fetchApplications })(ApplicationList); +const Container = connect(mapStateToProps, { fetchAll })(ApplicationList); -export default StrategiesContainer; +export default Container; diff --git a/frontend/src/component/feature/view-edit-container.jsx b/frontend/src/component/feature/view-edit-container.jsx index b2bdd7067a..7acadef46a 100644 --- a/frontend/src/component/feature/view-edit-container.jsx +++ b/frontend/src/component/feature/view-edit-container.jsx @@ -27,6 +27,7 @@ class EditFeatureToggleWrapper extends React.Component { this.props.fetchSeenApps(); this.props.fetchFeatureMetrics(); setInterval(() => { + this.props.fetchSeenApps(); this.props.fetchFeatureMetrics(); }, 5000); } diff --git a/frontend/src/data/applications-api.js b/frontend/src/data/applications-api.js index c79ae79156..21a6487c1e 100644 --- a/frontend/src/data/applications-api.js +++ b/frontend/src/data/applications-api.js @@ -8,6 +8,13 @@ function fetchAll () { .then(response => response.json()); } +function fetchApplication (appName) { + return fetch(`${URI}/${appName}`, { headers }) + .then(throwIfNotSuccess) + .then(response => response.json()); +} + module.exports = { + fetchApplication, fetchAll, }; diff --git a/frontend/src/index.jsx b/frontend/src/index.jsx index 94ff41fff6..905c9c3dfd 100644 --- a/frontend/src/index.jsx +++ b/frontend/src/index.jsx @@ -18,6 +18,7 @@ import HistoryPage from './page/history'; import HistoryTogglePage from './page/history/toggle'; import Archive from './page/archive'; import Applications from './page/applications'; +import ApplicationView from './page/applications/view'; import ClientStrategies from './page/client-strategies'; const unleashStore = createStore( @@ -41,6 +42,7 @@ ReactDOM.render( + diff --git a/frontend/src/page/applications/view.js b/frontend/src/page/applications/view.js new file mode 100644 index 0000000000..e4bc3b2405 --- /dev/null +++ b/frontend/src/page/applications/view.js @@ -0,0 +1,6 @@ +import React from 'react'; +import ApplicationEditComponent from '../../component/application/application-edit-container'; + +const render = ({ params }) => ; + +export default render; diff --git a/frontend/src/store/application/actions.js b/frontend/src/store/application/actions.js index faeec7fb01..311c5d6b10 100644 --- a/frontend/src/store/application/actions.js +++ b/frontend/src/store/application/actions.js @@ -1,20 +1,34 @@ import api from '../../data/applications-api'; -export const RECEIVE_APPLICATINS = 'RECEIVE_APPLICATINS'; -export const ERROR_RECEIVE_APPLICATINS = 'ERROR_RECEIVE_APPLICATINS'; +export const RECEIVE_ALL_APPLICATIONS = 'RECEIVE_ALL_APPLICATIONS'; +export const ERROR_RECEIVE_ALL_APPLICATIONS = 'ERROR_RECEIVE_ALL_APPLICATIONS'; -const recieveApplications = (json) => ({ - type: RECEIVE_APPLICATINS, +export const RECEIVE_APPLICATION = 'RECEIVE_APPLICATION'; + +const recieveAllApplications = (json) => ({ + type: RECEIVE_ALL_APPLICATIONS, + value: json, +}); + +const recieveApplication = (json) => ({ + type: RECEIVE_APPLICATION, value: json, }); const errorReceiveApplications = (statusCode) => ({ - type: ERROR_RECEIVE_APPLICATINS, + type: ERROR_RECEIVE_ALL_APPLICATIONS, statusCode, }); -export function fetchApplications () { +export function fetchAll () { return dispatch => api.fetchAll() - .then(json => dispatch(recieveApplications(json))) + .then(json => dispatch(recieveAllApplications(json))) .catch(error => dispatch(errorReceiveApplications(error))); } + +export function fetchApplication (appName) { + return dispatch => api.fetchApplication(appName) + .then(json => dispatch(recieveApplication(json))) + .catch(error => dispatch(errorReceiveApplications(error))); +} + diff --git a/frontend/src/store/application/index.js b/frontend/src/store/application/index.js index 7036f73ec8..b2daa39146 100644 --- a/frontend/src/store/application/index.js +++ b/frontend/src/store/application/index.js @@ -1,14 +1,16 @@ -import { fromJS } from 'immutable'; -import { RECEIVE_APPLICATINS } from './actions'; +import { fromJS, List, Map } from 'immutable'; +import { RECEIVE_ALL_APPLICATIONS, RECEIVE_APPLICATION } from './actions'; function getInitState () { - return fromJS([]); + return fromJS({ list: [], apps: {} }); } const store = (state = getInitState(), action) => { switch (action.type) { - case RECEIVE_APPLICATINS: - return fromJS(action.value.applications); + case RECEIVE_APPLICATION: + return state.setIn(['apps', action.value.appName], new Map(action.value)); + case RECEIVE_ALL_APPLICATIONS: + return state.set('list', new List(action.value.applications)); default: return state; }