fetch environments in App container for active link routing

This commit is contained in:
cyril lopez 2017-07-17 17:44:19 +02:00
parent 92308fccbf
commit 74e90d271b
15 changed files with 94 additions and 92 deletions

View File

@ -14,7 +14,7 @@ class PluginLeftMenu extends React.Component { // eslint-disable-line react/pref
return (
<div className={`${styles.pluginLeftMenu} col-md-3`}>
{map(this.props.sections, (section, index) => (
<PluginLeftMenuSection key={index} section={section} />
<PluginLeftMenuSection key={index} section={section} environments={this.props.environments} />
))}
</div>
);
@ -22,6 +22,7 @@ class PluginLeftMenu extends React.Component { // eslint-disable-line react/pref
}
PluginLeftMenu.propTypes = {
environments: React.PropTypes.array,
sections: React.PropTypes.array.isRequired,
};

View File

@ -7,13 +7,22 @@
import React from 'react';
import { Link } from 'react-router';
import { FormattedMessage } from 'react-intl';
import { includes, isEmpty } from 'lodash';
import styles from './styles.scss';
import config from './config.json';
class PluginLeftMenuLink extends React.Component { // eslint-disable-line react/prefer-stateless-function
render() {
let url;
if (!isEmpty(this.props.environments)) {
url = includes(config.environmentsRequired, this.props.link.slug) ?
`${this.props.link.slug}/${this.props.environments[0].name}`
: `${this.props.link.slug}`;
}
return (
<li className={styles.pluginLeftMenuLink}>
<Link className={styles.link} to={`/plugins/settings-manager/${this.props.link.slug}`} activeClassName={styles.linkActive}>
<Link className={styles.link} to={`/plugins/settings-manager/${url}`} activeClassName={styles.linkActive}>
<i className={`fa fa-${this.props.link.icon}`} />
<span><FormattedMessage {...{id: this.props.link.name}} /></span>
</Link>
@ -23,6 +32,7 @@ class PluginLeftMenuLink extends React.Component { // eslint-disable-line react/
}
PluginLeftMenuLink.propTypes = {
environments: React.PropTypes.array,
link: React.PropTypes.object.isRequired,
};

View File

@ -17,6 +17,7 @@ class PluginLeftMenuSection extends React.Component { // eslint-disable-line rea
<PluginLeftMenuLink
key={index}
link={item}
environments={this.props.environments}
/>
));
@ -34,6 +35,7 @@ class PluginLeftMenuSection extends React.Component { // eslint-disable-line rea
}
PluginLeftMenuSection.propTypes = {
environments: React.PropTypes.array,
section: React.PropTypes.object.isRequired,
};

View File

@ -6,7 +6,9 @@
import {
MENU_FETCH,
ENVIRONMENTS_FETCH,
MENU_FETCH_SUCCEEDED,
ENVIRONMENTS_FETCH_SUCCEEDED,
} from './constants';
@ -22,3 +24,16 @@ export function fetchMenuSucceeded(menu) {
menu,
};
}
export function environmentsFetch() {
return {
type: ENVIRONMENTS_FETCH,
};
}
export function environmentsFetchSucceeded(environments) {
return {
type: ENVIRONMENTS_FETCH_SUCCEEDED,
environments,
};
}

View File

@ -5,4 +5,6 @@
*/
export const MENU_FETCH = 'SettingsManager/App/MENU_FETCH';
export const ENVIRONMENTS_FETCH = 'SettingsManager/App/ENVIRONMENTS_FETCH';
export const MENU_FETCH_SUCCEEDED = 'SettingsManager/App/MENU_FETCH_SUCCEEDED';
export const ENVIRONMENTS_FETCH_SUCCEEDED = 'SettingsManager/App/ENVIRONMENTS_FETCH_SUCCEEDED';

View File

@ -15,8 +15,8 @@ import PluginLeftMenu from 'components/PluginLeftMenu';
import { define } from 'i18n';
import messages from '../../translations/en.json';
import { menuFetch } from './actions';
import { makeSelectSections } from './selectors';
import { menuFetch, environmentsFetch } from './actions';
import { makeSelectSections, makeSelectEnvironments } from './selectors';
import styles from './styles.scss';
define(map(messages, (message, id) => ({
id,
@ -27,12 +27,13 @@ define(map(messages, (message, id) => ({
class App extends React.Component {
componentDidMount() {
this.props.menuFetch();
this.props.environmentsFetch();
}
componentWillReceiveProps(nextProps) {
// redirect the user to the first general section
if (!this.props.params.slug && !isEmpty(nextProps.sections)) {
this.props.history.push(`${this.props.location.pathname}/${nextProps.sections[0].items[0].slug}`)
this.props.history.push(`${this.props.location.pathname}/${nextProps.sections[0].items[0].slug}`);
}
}
@ -51,7 +52,7 @@ class App extends React.Component {
*/}
<div className={`container-fluid ${styles.noPadding}`}>
<div className="row">
<PluginLeftMenu sections={this.props.sections} />
<PluginLeftMenu sections={this.props.sections} environments={this.props.environments} />
{React.Children.toArray(content)}
</div>
</div>
@ -66,6 +67,8 @@ App.contextTypes = {
App.propTypes = {
children: React.PropTypes.node.isRequired,
environments: React.PropTypes.array,
environmentsFetch: React.PropTypes.func,
exposedComponents: React.PropTypes.object.isRequired,
history: React.PropTypes.object,
location: React.PropTypes.object,
@ -78,6 +81,7 @@ export function mapDispatchToProps(dispatch) {
return bindActionCreators(
{
menuFetch,
environmentsFetch,
},
dispatch
);
@ -85,6 +89,7 @@ export function mapDispatchToProps(dispatch) {
const mapStateToProps = createStructuredSelector({
sections: makeSelectSections(),
environments: makeSelectEnvironments(),
});
// Wrap the component to inject dispatch and state into it

View File

@ -7,16 +7,22 @@
import { fromJS, List } from 'immutable';
import {
MENU_FETCH_SUCCEEDED,
ENVIRONMENTS_FETCH_SUCCEEDED,
} from './constants';
/* eslint-disable new-cap */
const initialState = fromJS({
sections: List(), // eslint-disable-line new-cap
environments: List(),
});
function appReducer(state = initialState, action) {
switch (action.type) {
case MENU_FETCH_SUCCEEDED:
return state.set('sections', List(action.menu.sections)); // eslint-disable-line new-cap
return state.set('sections', List(action.menu.sections));
case ENVIRONMENTS_FETCH_SUCCEEDED:
return state
.set('environments', List(action.environments.environments));
default:
return state;
}

View File

@ -1,8 +1,8 @@
import { takeLatest } from 'redux-saga';
import { put, fork } from 'redux-saga/effects';
import { put, fork, take, cancel } from 'redux-saga/effects';
import { fetchMenuSucceeded } from './actions';
import { MENU_FETCH } from './constants';
import { fetchMenuSucceeded, environmentsFetchSucceeded } from './actions';
import { MENU_FETCH, MENU_FETCH_SUCCEEDED, ENVIRONMENTS_FETCH, ENVIRONMENTS_FETCH_SUCCEEDED } from './constants';
export function* fetchMenu() {
try {
@ -21,9 +21,31 @@ export function* fetchMenu() {
}
}
export function* fetchEnvironments() {
try {
const opts = {
method: 'GET',
};
const response = yield fetch('/settings-manager/environments', opts);
const data = yield response.json();
yield put(environmentsFetchSucceeded(data));
} catch(error) {
console.log(error);
}
}
function* defaultSaga() {
yield fork(takeLatest, MENU_FETCH, fetchMenu);
const loadMenu = yield fork(takeLatest, MENU_FETCH, fetchMenu);
const loadEnvironments = yield fork(takeLatest, ENVIRONMENTS_FETCH, fetchEnvironments);
yield take(MENU_FETCH_SUCCEEDED);
yield cancel(loadMenu);
yield take(ENVIRONMENTS_FETCH_SUCCEEDED);
yield cancel(loadEnvironments)
}
export default [defaultSaga];

View File

@ -27,5 +27,10 @@ const makeSelectSections = () => createSelector(
(globalSate) => globalSate.get('sections').toJS(),
);
export { selectLocationState, makeSelectSections };
const makeSelectEnvironments = () => createSelector(
selectGlobalDomain(),
(globalSate) => globalSate.get('environments').toJS(),
);
export { selectLocationState, makeSelectSections, makeSelectEnvironments };
export default selectGlobalDomain;

View File

@ -1,14 +1,13 @@
/*
*
* Home actions
*
*/
import { forEach } from 'lodash';
*
* Home actions
*
*/
import { forEach } from 'lodash';
import {
CONFIG_FETCH,
ENVIRONMENTS_FETCH,
CONFIG_FETCH_SUCCEEDED,
ENVIRONMENTS_FETCH_SUCCEEDED,
DEFAULT_ACTION,
} from './constants';
@ -25,19 +24,6 @@ export function configFetch(endPoint) {
};
}
export function environmentsFetch() {
return {
type: ENVIRONMENTS_FETCH,
};
}
export function environmentsFetchSucceeded(environments) {
return {
type: ENVIRONMENTS_FETCH_SUCCEEDED,
environments,
};
}
export function configFetchSucceded(configs) {
const data = {};
forEach(configs.sections, (section) => {

View File

@ -5,7 +5,5 @@
*/
export const CONFIG_FETCH = 'src/Home/CONFIG_FETCH';
export const ENVIRONMENTS_FETCH = 'src/Home/ENVIRONMENTS_FETCH';
export const CONFIG_FETCH_SUCCEEDED = 'src/Home/CONFIG_FETCH_SUCCEEDED';
export const ENVIRONMENTS_FETCH_SUCCEEDED = 'src/Home/ENVIRONMENTS_FETCH_SUCCEEDED';
export const DEFAULT_ACTION = 'src/Home/DEFAULT_ACTION';

View File

@ -7,49 +7,31 @@
import React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { includes } from 'lodash';
import Helmet from 'react-helmet';
import selectHome from './selectors';
import { configFetch, environmentsFetch } from './actions'
import { configFetch } from './actions'
import styles from './styles.scss';
import config from './config.json';
export class Home extends React.Component { // eslint-disable-line react/prefer-stateless-function
componentDidMount() {
// always fetch environments
this.props.environmentsFetch();
if (this.props.params.slug) {
const isEnvironmentsRequired = includes(config.environmentsRequired, this.props.params.slug);
if (!isEnvironmentsRequired) {
this.props.configFetch(this.props.params.slug);
} else if (this.props.params.env){
this.props.configFetch(`${this.props.params.slug}/${this.props.params.env}`);
}
const apiUrl = this.props.params.env ? `${this.props.params.slug}/${this.props.params.env}` : this.props.params.slug;
this.props.configFetch(apiUrl);
}
}
componentWillReceiveProps(nextProps) {
const isEnvironmentsRequired = nextProps.params.slug ? includes(config.environmentsRequired, nextProps.params.slug) : false;
// check if params slug updated
if (this.props.params.slug !== nextProps.params.slug && nextProps.params.slug) {
// redirect user if environnemnt is required and params environment not provided
if (isEnvironmentsRequired && !nextProps.params.env) {
this.props.history.push(`${nextProps.location.pathname}/${nextProps.environments[0].name}`)
}
// get data from api if params slug updated
const apiUrl = isEnvironmentsRequired ? `${nextProps.params.slug}/${nextProps.environments[0].name}` : nextProps.params.slug;
const apiUrl = nextProps.params.env ? `${nextProps.params.slug}/${nextProps.params.env}` : nextProps.params.slug;
this.props.configFetch(apiUrl);
} else if (this.props.params.env !== nextProps.params.env) {
console.log('-------');
// get data if params env updated
this.props.configFetch(`${this.props.params.slug}/${nextProps.params.env}`);
}
@ -75,7 +57,6 @@ function mapDispatchToProps(dispatch) {
return bindActionCreators(
{
configFetch,
environmentsFetch,
},
dispatch
)
@ -83,8 +64,6 @@ function mapDispatchToProps(dispatch) {
Home.propTypes = {
configFetch: React.PropTypes.func.isRequired,
environmentsFetch: React.PropTypes.func.isRequired,
history: React.PropTypes.object.isRequired,
params: React.PropTypes.object.isRequired,
};

View File

@ -4,12 +4,10 @@
*
*/
import { fromJS, List, Map, OrderedMap } from 'immutable';
import { fromJS, Map, OrderedMap } from 'immutable';
import {
CONFIG_FETCH,
ENVIRONMENTS_FETCH,
CONFIG_FETCH_SUCCEEDED,
ENVIRONMENTS_FETCH_SUCCEEDED,
} from './constants';
/* eslint-disable new-cap */
@ -18,7 +16,6 @@ const initialState = fromJS({
configsDisplay: OrderedMap(),
initialData: Map(),
modifiedData: Map(),
environments: List(),
});
function homeReducer(state = initialState, action) {
@ -31,12 +28,6 @@ function homeReducer(state = initialState, action) {
.set('configsDisplay', OrderedMap(action.configs))
.set('initialData', Map(action.data))
.set('modifiedData', Map(action.data));
case ENVIRONMENTS_FETCH:
return state.set('loading', true);
case ENVIRONMENTS_FETCH_SUCCEEDED:
return state
.set('loading', false)
.set('environments', List(action.environments.environments));
default:
return state;
}

View File

@ -1,8 +1,8 @@
import { takeLatest } from 'redux-saga';
import { take, put, fork, cancel } from 'redux-saga/effects';
// import { FormattedMessage } from 'react-intl';
import { CONFIG_FETCH, ENVIRONMENTS_FETCH, CONFIG_FETCH_SUCCEEDED, ENVIRONMENTS_FETCH_SUCCEEDED } from './constants';
import { configFetchSucceded, environmentsFetchSucceeded } from './actions';
import { CONFIG_FETCH, CONFIG_FETCH_SUCCEEDED } from './constants';
import { configFetchSucceded } from './actions';
export function* fetchConfig(action) {
try {
@ -22,31 +22,11 @@ export function* fetchConfig(action) {
}
}
export function* fetchEnvironments() {
try {
const opts = {
method: 'GET',
};
const response = yield fetch('/settings-manager/environments', opts);
const data = yield response.json();
yield put(environmentsFetchSucceeded(data));
} catch(error) {
console.log(error);
}
}
// Individual exports for testing
export function* defaultSaga() {
const loadConfig = yield fork(takeLatest, CONFIG_FETCH, fetchConfig);
const loadEnvironments = yield fork(takeLatest, ENVIRONMENTS_FETCH, fetchEnvironments);
yield take(CONFIG_FETCH_SUCCEEDED);
yield cancel(loadConfig);
yield take(ENVIRONMENTS_FETCH_SUCCEEDED);
yield cancel(loadEnvironments);
}
// All sagas to be loaded