web: refactor info and tenant reducers action

This change adds info fetch state action type and simplifies the main App
by using the new info attributes.

Change-Id: I2cfd3f6ae605051e11f58272e62925d8f97e4ac9
This commit is contained in:
Tristan Cacqueray 2018-12-02 01:46:43 +00:00
parent 76867ca14a
commit 17144c2a46
7 changed files with 85 additions and 31 deletions

View File

@ -86,8 +86,12 @@ class App extends React.Component {
}
renderContent = () => {
const { tenant } = this.props
const { info, tenant } = this.props
const allRoutes = []
if (info.isFetching) {
return (<h2>Fetching info...</h2>)
}
this.menu
// Do not include '/tenants' route in white-label setup
.filter(item =>
@ -102,10 +106,13 @@ class App extends React.Component {
/>
)
})
if (tenant.defaultRoute)
allRoutes.push(
<Redirect from='*' to={tenant.defaultRoute} key='default-route' />
)
return (
<Switch>
{allRoutes}
<Redirect from='*' to={tenant.defaultRoute} key='default-route' />
</Switch>
)
}
@ -113,7 +120,7 @@ class App extends React.Component {
componentDidUpdate() {
// This method is called when info property is updated
const { tenant, info } = this.props
if (info.capabilities) {
if (info.ready) {
let tenantName, whiteLabel
if (info.tenant) {
@ -129,12 +136,10 @@ class App extends React.Component {
if (match) {
tenantName = match.params.tenant
} else {
tenantName = ''
}
}
// Set tenant only if it changed to prevent DidUpdate loop
if (typeof tenant.name === 'undefined' || tenant.name !== tenantName) {
if (tenant.name !== tenantName) {
const tenantAction = setTenantAction(tenantName, whiteLabel)
this.props.dispatch(tenantAction)
if (tenantName) {
@ -204,10 +209,6 @@ class App extends React.Component {
const { menuCollapsed, showErrors } = this.state
const { tenant, configErrors } = this.props
if (typeof tenant.name === 'undefined') {
return (<h2>Loading...</h2>)
}
return (
<React.Fragment>
<Masthead

View File

@ -19,7 +19,7 @@ import ReactDOM from 'react-dom'
import { Link, BrowserRouter as Router } from 'react-router-dom'
import { Provider } from 'react-redux'
import { fetchInfoAction } from './actions/info'
import { fetchInfoIfNeeded } from './actions/info'
import createZuulStore from './store'
import App from './App'
import TenantsPage from './pages/Tenants'
@ -54,7 +54,7 @@ it('renders multi tenant', () => {
const application = ReactTestUtils.renderIntoDocument(
<Provider store={store}><Router><App /></Router></Provider>
)
store.dispatch(fetchInfoAction()).then(() => {
store.dispatch(fetchInfoIfNeeded()).then(() => {
// Link should be tenant scoped
const topMenuLinks = ReactTestUtils.scryRenderedComponentsWithType(
application, Link)
@ -86,7 +86,7 @@ it('renders single tenant', () => {
<Provider store={store}><Router><App /></Router></Provider>
)
store.dispatch(fetchInfoAction()).then(() => {
store.dispatch(fetchInfoIfNeeded()).then(() => {
// Link should be white-label scoped
const topMenuLinks = ReactTestUtils.scryRenderedComponentsWithType(
application, Link)

View File

@ -12,16 +12,46 @@
// License for the specific language governing permissions and limitations
// under the License.
import { fetchInfo } from '../api'
import * as API from '../api'
export function fetchInfoAction () {
return (dispatch) => {
return fetchInfo()
.then(response => {
dispatch({type: 'FETCH_INFO_SUCCESS', info: response.data.info})
})
.catch(error => {
throw (error)
})
export const INFO_FETCH_REQUEST = 'INFO_FETCH_REQUEST'
export const INFO_FETCH_SUCCESS = 'INFO_FETCH_SUCCESS'
export const INFO_FETCH_FAIL = 'INFO_FETCH_FAIL'
export const fetchInfoRequest = () => ({
type: INFO_FETCH_REQUEST
})
export const fetchInfoSuccess = json => ({
type: INFO_FETCH_SUCCESS,
tenant: json.info.tenant,
})
const fetchInfoFail = error => ({
type: INFO_FETCH_FAIL,
error
})
const fetchInfo = () => dispatch => {
dispatch(fetchInfoRequest())
return API.fetchInfo()
.then(response => dispatch(fetchInfoSuccess(response.data)))
.catch(error => dispatch(fetchInfoFail(error)))
}
const shouldFetchInfo = state => {
const info = state.info
if (!info) {
return true
}
if (info.isFetching) {
return false
}
return true
}
export const fetchInfoIfNeeded = () => (dispatch, getState) => {
if (shouldFetchInfo(getState())) {
return dispatch(fetchInfo())
}
}

View File

@ -12,6 +12,8 @@
// License for the specific language governing permissions and limitations
// under the License.
export const TENANT_SET = 'TENANT_SET'
export function setTenantAction (name, whiteLabel) {
let apiPrefix = ''
let linkPrefix = ''
@ -24,7 +26,7 @@ export function setTenantAction (name, whiteLabel) {
defaultRoute = '/tenants'
}
return {
type: 'SET_TENANT',
type: TENANT_SET,
tenant: {
name: name,
whiteLabel: whiteLabel,

View File

@ -25,14 +25,14 @@ import './index.css'
import { getHomepageUrl } from './api'
import registerServiceWorker from './registerServiceWorker'
import { fetchInfoAction } from './actions/info'
import { fetchInfoIfNeeded } from './actions/info'
import createZuulStore from './store'
import App from './App'
const store = createZuulStore()
// Load info endpoint
store.dispatch(fetchInfoAction())
store.dispatch(fetchInfoIfNeeded())
ReactDOM.render(
<Provider store={store}>

View File

@ -12,10 +12,29 @@
// License for the specific language governing permissions and limitations
// under the License.
export default (state = {}, action) => {
import {
INFO_FETCH_REQUEST,
INFO_FETCH_SUCCESS,
INFO_FETCH_FAIL,
} from '../actions/info'
export default (state = {
isFetching: false,
tenant: null,
}, action) => {
switch (action.type) {
case 'FETCH_INFO_SUCCESS':
return action.info
case INFO_FETCH_REQUEST:
case INFO_FETCH_FAIL:
return {
isFetching: true,
tenant: null,
}
case INFO_FETCH_SUCCESS:
return {
isFetching: false,
tenant: action.tenant,
ready: true
}
default:
return state
}

View File

@ -12,9 +12,11 @@
// License for the specific language governing permissions and limitations
// under the License.
export default (state = {}, action) => {
import { TENANT_SET } from '../actions/tenant'
export default (state = {name: null}, action) => {
switch (action.type) {
case 'SET_TENANT':
case TENANT_SET:
return action.tenant
default:
return state