Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Julien Jerphanion
Rex Dri
Commits
d569450d
Commit
d569450d
authored
Sep 01, 2018
by
Florent Chehab
Browse files
API generation for frontend and more standardized js processes
parent
34db017b
Changes
9
Hide whitespace changes
Inline
Side-by-side
Makefile
View file @
d569450d
...
@@ -7,6 +7,9 @@ install_backend:
...
@@ -7,6 +7,9 @@ install_backend:
generate_backend
:
generate_backend
:
python ./backend/generate/generate_all.py
python ./backend/generate/generate_all.py
generate_frontend
:
python ./frontend/generate/generate_frontend_files.py
test_backend
:
generate_backend
test_backend
:
generate_backend
pytest
pytest
...
...
frontend/generate/generate_frontend_files.py
View file @
d569450d
#####
#####
# This python file is used to generate js files for redux
# This python file is used to generate js files for redux
import
os
import
os
from
os.path
import
join
from
django
import
template
from
django
import
template
import
re
import
re
import
yaml
############
############
# Need to do this first so that Django template engine is working
# Need to do this first so that Django template engine is working
...
@@ -35,21 +37,19 @@ templates = [
...
@@ -35,21 +37,19 @@ templates = [
'combinedReducers'
'combinedReducers'
]
]
API_BASE
=
"http://127.0.0.1:8000/api/"
API_BASE
=
"/api/"
with
open
(
join
(
current_dir
,
'../../backend/generate/api_config.yml'
),
'r'
)
as
f
:
contexts
=
[
data
=
f
.
read
()
{
api_config
=
yaml
.
load
(
data
)
'name'
:
'universities'
,
'api_url'
:
API_BASE
+
"university/"
,
contexts
=
[]
},
{
for
api
in
api_config
:
'name'
:
'countries'
,
name
=
api
[
'viewset'
].
split
(
'ViewSet'
)[
0
]
'api_url'
:
API_BASE
+
"country/"
name
=
name
[
0
].
lower
()
+
name
[
1
:]
},
{
contexts
.
append
({
'name'
:
'mainCampus'
,
"name"
:
name
,
'api_url'
:
API_BASE
+
"main_campus/"
,
"api_end_point"
:
API_BASE
+
api
[
"api_end_point"
]
+
'/'
'read_only'
:
True
})
}
]
def
read_file
(
file
):
def
read_file
(
file
):
...
...
frontend/generate/templates/actions.tpl
View file @
d569450d
...
@@ -29,25 +29,25 @@ import {
...
@@ -29,25 +29,25 @@ import {
//////////////////////////////////
//////////////////////////////////
// generic function definitions
// generic function definitions
function _FetchData(pk, api_
url
, _IsLoading, _FetchDataSuccess, _Invalidated, _HasError, pk_required=false) {
function _FetchData(pk, api_
end_point
, _IsLoading, _FetchDataSuccess, _Invalidated, _HasError, pk_required=false) {
if (pk_required
&&
pk == ""){
if (pk_required
&&
pk == ""){
throw "pk shouldn't be empty when requesting a specific element";
throw "pk shouldn't be empty when requesting a specific element";
}
}
return (dispatch) => {
return (dispatch) => {
dispatch(_IsLoading(true));
dispatch(_IsLoading(true));
let token = Cookies.get('csrftoken');
fetch(api_
url
)
fetch(api_
end_point,
{
credentials
:
'same-origin'
,
headers
:
{
'X-CSRFToken'
:
token
}}
)
.then((response) => {
.then((response) => {
if (!response.ok) {
if (!response.ok) {
throw Error(response.statusText);
throw Error(response.statusText);
}
}
dispatch(_IsLoading(false));
return response;
return response;
})
})
.then((response) => response.json())
.then((response) => response.json())
.then((obj) => {
.then((obj) => {
dispatch(_Invalidated(false));
dispatch(_Invalidated(false));
dispatch(_FetchDataSuccess(obj));
dispatch(_FetchDataSuccess(obj));
dispatch(_IsLoading(false));
})
})
.catch(() => dispatch(_HasError(true)));
.catch(() => dispatch(_HasError(true)));
};
};
...
@@ -55,7 +55,7 @@ function _FetchData(pk, api_url, _IsLoading, _FetchDataSuccess, _Invalidated, _H
...
@@ -55,7 +55,7 @@ function _FetchData(pk, api_url, _IsLoading, _FetchDataSuccess, _Invalidated, _H
function _ElSaveData(data, api_
url
, _IsLoading, _FetchDataSuccess, _Invalidated, _HasError) {
function _ElSaveData(data, api_
end_point
, _IsLoading, _FetchDataSuccess, _Invalidated, _HasError) {
return (dispatch) => {
return (dispatch) => {
let method = "POST";
let method = "POST";
let pk = "";
let pk = "";
...
@@ -66,7 +66,7 @@ function _ElSaveData(data, api_url, _IsLoading, _FetchDataSuccess, _Invalidated,
...
@@ -66,7 +66,7 @@ function _ElSaveData(data, api_url, _IsLoading, _FetchDataSuccess, _Invalidated,
dispatch(_ElIsSaving(true));
dispatch(_ElIsSaving(true));
let token = Cookies.get('csrftoken');
let token = Cookies.get('csrftoken');
fetch(api_
url
+pk, {
fetch(api_
end_point
+pk, {
method: method,
method: method,
credentials: 'same-origin',
credentials: 'same-origin',
headers: {
headers: {
...
@@ -81,13 +81,13 @@ function _ElSaveData(data, api_url, _IsLoading, _FetchDataSuccess, _Invalidated,
...
@@ -81,13 +81,13 @@ function _ElSaveData(data, api_url, _IsLoading, _FetchDataSuccess, _Invalidated,
throw Error(response.statusText);
throw Error(response.statusText);
}
}
dispatch(_ElIsSaving(false));
return response;
return response;
})
})
.then((response) => response.json())
.then((response) => response.json())
.then((_El) => {
.then((_El) => {
dispatch(_ElInvalidated(false));
dispatch(_ElInvalidated(false));
dispatch(_ElSaveDataSuccess(_El));
dispatch(_ElSaveDataSuccess(_El));
dispatch(_ElIsSaving(false));
})
})
.catch(() => dispatch(_ElHasError(true)));
.catch(() => dispatch(_ElHasError(true)));
};
};
...
@@ -131,7 +131,7 @@ export function {{obj.name}}FetchDataSuccess({{obj.name}}) {
...
@@ -131,7 +131,7 @@ export function {{obj.name}}FetchDataSuccess({{obj.name}}) {
export function {
{
obj
.
name
}
}FetchData() {
export function {
{
obj
.
name
}
}FetchData() {
return _FetchData(
return _FetchData(
"",
"",
"{
{
obj
.
api_
url
}
}",
"{
{
obj
.
api_
end_point
}
}",
{
{
obj
.
name
}
}IsLoading,
{
{
obj
.
name
}
}IsLoading,
{
{
obj
.
name
}
}FetchDataSuccess,
{
{
obj
.
name
}
}FetchDataSuccess,
{
{
obj
.
name
}
}Invalidated,
{
{
obj
.
name
}
}Invalidated,
...
@@ -176,7 +176,7 @@ export function {{obj.name}}ElFetchDataSuccess({{obj.name}}El) {
...
@@ -176,7 +176,7 @@ export function {{obj.name}}ElFetchDataSuccess({{obj.name}}El) {
export function {
{
obj
.
name
}
}ElFetchData(pk) {
export function {
{
obj
.
name
}
}ElFetchData(pk) {
return _FetchData(
return _FetchData(
pk,
pk,
"{
{
obj
.
api_
url
}
}",
"{
{
obj
.
api_
end_point
}
}",
{
{
obj
.
name
}
}ElIsLoading,
{
{
obj
.
name
}
}ElIsLoading,
{
{
obj
.
name
}
}ElFetchDataSuccess,
{
{
obj
.
name
}
}ElFetchDataSuccess,
{
{
obj
.
name
}
}ElInvalidated,
{
{
obj
.
name
}
}ElInvalidated,
...
@@ -207,7 +207,7 @@ export function {{obj.name}}ElSaveDataSuccess({{obj.name}}El) {
...
@@ -207,7 +207,7 @@ export function {{obj.name}}ElSaveDataSuccess({{obj.name}}El) {
}
}
export function {
{
obj
.
name
}
}ElSaveData(data) {
export function {
{
obj
.
name
}
}ElSaveData(data) {
return _ElSaveData(data, "{
{
obj
.
api_
url
}
}", {
{
obj
.
name
}
}ElIsLoading, {
{
obj
.
name
}
}ElFetchDataSuccess, {
{
obj
.
name
}
}ElInvalidated, {
{
obj
.
name
}
}ElHasError)
return _ElSaveData(data, "{
{
obj
.
api_
end_point
}
}", {
{
obj
.
name
}
}ElIsLoading, {
{
obj
.
name
}
}ElFetchDataSuccess, {
{
obj
.
name
}
}ElInvalidated, {
{
obj
.
name
}
}ElHasError)
}
}
{% endif %}
{% endif %}
...
...
frontend/generate/templates/reducers.tpl
View file @
d569450d
...
@@ -65,11 +65,11 @@ export function {{obj.name}}ElIsLoading(state = false, action) {
...
@@ -65,11 +65,11 @@ export function {{obj.name}}ElIsLoading(state = false, action) {
}
}
}
}
export function {
{
obj
.
name
}
}Fetched(state = {
{
{
obj
.
name
}
}: [], {
{
obj
.
name
}
}F
etchedAt: null }, action) {
export function {
{
obj
.
name
}
}Fetched(state = {
data: Object(), f
etchedAt: null }, action) {
switch (action.type) {
switch (action.type) {
case {
{
obj
.
NAME
}
}_FETCH_DATA_SUCCESS:
case {
{
obj
.
NAME
}
}_FETCH_DATA_SUCCESS:
return {
return {
{
{
obj
.
name
}
}
: action.{
{
obj
.
name
}
},
data
: action.{
{
obj
.
name
}
},
fetchedAt: action.{
{
obj
.
name
}
}FetchedAt
fetchedAt: action.{
{
obj
.
name
}
}FetchedAt
}
}
...
@@ -100,11 +100,11 @@ export function {{obj.name}}ElInvalidated(state = false, action) {
...
@@ -100,11 +100,11 @@ export function {{obj.name}}ElInvalidated(state = false, action) {
}
}
}
}
export function {
{
obj
.
name
}
}ElFetched(state = {
{
{
obj
.
name
}
}El: [], {
{
obj
.
name
}
}ElF
etchedAt: null }, action) {
export function {
{
obj
.
name
}
}ElFetched(state = {
data: Object(), f
etchedAt: null }, action) {
switch (action.type) {
switch (action.type) {
case {
{
obj
.
NAME
}
}_EL_FETCH_DATA_SUCCESS:
case {
{
obj
.
NAME
}
}_EL_FETCH_DATA_SUCCESS:
return {
return {
{
{
obj
.
name
}
}El
: action.{
{
obj
.
name
}
}El,
data
: action.{
{
obj
.
name
}
}El,
fetchedAt: action.{
{
obj
.
name
}
}ElFetchedAt
fetchedAt: action.{
{
obj
.
name
}
}ElFetchedAt
}
}
...
@@ -128,11 +128,11 @@ export function {{obj.name}}ElIsSaving(state = false, action) {
...
@@ -128,11 +128,11 @@ export function {{obj.name}}ElIsSaving(state = false, action) {
}
}
}
}
export function {
{
obj
.
name
}
}ElSaved(state = {
{
{
obj
.
name
}
}El: [], {
{
obj
.
name
}
}ElS
avedAt: null }, action) {
export function {
{
obj
.
name
}
}ElSaved(state = {
data: Object(), s
avedAt: null }, action) {
switch (action.type) {
switch (action.type) {
case {
{
obj
.
NAME
}
}_EL_SAVING_DATA_SUCCESS:
case {
{
obj
.
NAME
}
}_EL_SAVING_DATA_SUCCESS:
return {
return {
{
{
obj
.
name
}
}El
: action.{
{
obj
.
name
}
}El,
data
: action.{
{
obj
.
name
}
}El,
fetchedAt: action.{
{
obj
.
name
}
}ElSavedAt
fetchedAt: action.{
{
obj
.
name
}
}ElSavedAt
}
}
...
...
frontend/src/components/App.js
View file @
d569450d
...
@@ -17,7 +17,7 @@ import SchoolIcon from '@material-ui/icons/School';
...
@@ -17,7 +17,7 @@ import SchoolIcon from '@material-ui/icons/School';
import
{
mainListItems
,
secondaryListItems
}
from
'
./template/listItems
'
;
import
{
mainListItems
,
secondaryListItems
}
from
'
./template/listItems
'
;
import
{
connect
}
from
"
react-redux
"
;
import
{
connect
}
from
"
react-redux
"
;
import
Loading
from
'
./other/Loading
'
;
import
MyComponent
from
'
./MyComponent
'
// import route Components here
// import route Components here
...
@@ -27,7 +27,7 @@ import {
...
@@ -27,7 +27,7 @@ import {
}
from
'
react-router-dom
'
;
}
from
'
react-router-dom
'
;
import
{
import
{
countr
ies
FetchData
,
countr
y
FetchData
,
}
from
'
../generated/actions
'
;
}
from
'
../generated/actions
'
;
...
@@ -97,10 +97,10 @@ const styles = theme => ({
...
@@ -97,10 +97,10 @@ const styles = theme => ({
myPaper
:
{
myPaper
:
{
padding
:
16
padding
:
16
},
},
null
:{}
null
:
{}
});
});
class
App
extends
React
.
Component
{
class
App
extends
My
Component
{
state
=
{
state
=
{
open
:
true
,
open
:
true
,
};
};
...
@@ -113,32 +113,8 @@ class App extends React.Component {
...
@@ -113,32 +113,8 @@ class App extends React.Component {
this
.
setState
({
open
:
false
});
this
.
setState
({
open
:
false
});
};
};
componentDidMount
()
{
myRender
()
{
if
(
this
.
props
.
countries
.
fetched
.
countries
.
length
==
0
||
this
.
props
.
invalidated
)
{
this
.
props
.
fetchData
();
}
}
componentDidUpdate
()
{
// TODO ajouter expire date
if
(
this
.
props
.
countries
.
invalidated
)
{
this
.
props
.
countries
.
fetchData
();
}
}
componentWillUnmount
()
{
}
render
()
{
if
(
this
.
props
.
countries
.
hasError
)
{
return
<
p
>
Sorry
!
There
was
an
error
loading
the
items
<
/p>
;
}
if
(
this
.
props
.
countries
.
isLoading
||
this
.
props
.
countries
.
invalidated
)
{
return
<
Loading
/>
;
}
const
{
classes
}
=
this
.
props
;
const
{
classes
}
=
this
.
props
;
return
(
return
(
...
@@ -204,7 +180,9 @@ const mapStateToProps = (state) => {
...
@@ -204,7 +180,9 @@ const mapStateToProps = (state) => {
const
mapDispatchToProps
=
(
dispatch
)
=>
{
const
mapDispatchToProps
=
(
dispatch
)
=>
{
return
{
return
{
fetchData
:
()
=>
dispatch
(
countriesFetchData
()),
fetchData
:
{
countries
:
()
=>
dispatch
(
countryFetchData
())
}
};
};
};
};
...
...
frontend/src/components/MyComponent.js
View file @
d569450d
import
React
,
{
Component
}
from
'
react
'
;
import
React
,
{
Component
}
from
'
react
'
;
import
Loading
from
'
./other/Loading
'
;
class
MyComponent
extends
Component
{
class
MyComponent
extends
Component
{
checkProps
(
val
)
{
checkProps
(
val
)
{
for
(
let
el
in
this
.
props
)
{
for
(
let
el
in
this
.
props
)
{
let
prop
=
this
.
props
[
el
];
let
prop
=
this
.
props
[
el
];
if
(
val
in
prop
&&
prop
[
val
])
{
if
(
prop
&&
val
in
prop
&&
prop
[
val
])
{
return
true
;
return
true
;
}
}
}
}
return
false
;
return
false
;
}
}
checkPropsHasError
()
{
checkPropsHasError
()
{
return
this
.
checkProps
(
'
hasError
'
);
return
this
.
checkProps
(
'
hasError
'
);
}
}
...
@@ -18,6 +20,48 @@ class MyComponent extends Component {
...
@@ -18,6 +20,48 @@ class MyComponent extends Component {
checkPropsIsLoading
()
{
checkPropsIsLoading
()
{
return
this
.
checkProps
(
'
isLoading
'
);
return
this
.
checkProps
(
'
isLoading
'
);
}
}
checkPropsInvalidated
()
{
return
this
.
checkProps
(
'
invalidated
'
);
}
loadPropsIfNeeded
(){
for
(
let
prop_key
in
this
.
props
)
{
let
prop
=
this
.
props
[
prop_key
];
if
(
prop
&&
'
fetched
'
in
prop
){
if
(
(
!
prop
.
fetched
.
fetchedAt
)
||
prop
.
invalidated
){
if
(
!
prop
.
isLoading
){
this
.
props
.
fetchData
[
prop_key
]();
}
}
}
}
}
componentDidMount
()
{
this
.
loadPropsIfNeeded
();
this
.
myComponentDidMount
();
}
myComponentDidMount
(){};
componentDidUpdate
()
{
// TODO ajouter expire date
this
.
loadPropsIfNeeded
();
this
.
myComponentDidMount
();
}
myComponentDidMount
(){};
render
()
{
if
(
this
.
checkPropsHasError
())
{
return
<
p
>
Sorry
!
There
was
an
error
loading
the
items
<
/p>
;
}
if
(
this
.
checkPropsIsLoading
()
||
this
.
checkPropsInvalidated
())
{
return
<
Loading
/>
;
}
return
this
.
myRender
();
}
}
}
...
...
frontend/src/components/map/UnivMakers.js
View file @
d569450d
...
@@ -17,8 +17,8 @@ class UnivMarkers extends Component {
...
@@ -17,8 +17,8 @@ class UnivMarkers extends Component {
render
()
{
render
()
{
let
universities
=
this
.
props
.
universities
;
let
universities
=
this
.
props
.
universities
.
fetched
.
data
;
let
mainCampus
=
this
.
props
.
mainCampus
;
let
mainCampus
=
this
.
props
.
mainCampus
.
fetched
.
data
;
let
selected_main_campus
=
[];
let
selected_main_campus
=
[];
for
(
let
main_campus_pk
in
mainCampus
)
{
for
(
let
main_campus_pk
in
mainCampus
)
{
...
@@ -50,17 +50,8 @@ class UnivMarkers extends Component {
...
@@ -50,17 +50,8 @@ class UnivMarkers extends Component {
const
mapStateToProps
=
(
state
)
=>
{
const
mapStateToProps
=
(
state
)
=>
{
return
{
return
{
universities
:
state
.
universities
.
fetched
.
universities
,
universities
:
state
.
universities
,
universitiesFetchedAt
:
state
.
universities
.
fetched
.
fetchedAt
,
mainCampus
:
state
.
mainCampus
universitiesHasError
:
state
.
universities
.
hasError
,
universitiesIsLoading
:
state
.
universities
.
isLoading
,
universitiesInvalidated
:
state
.
universities
.
invalidated
,
mainCampus
:
state
.
mainCampus
.
fetched
.
mainCampus
,
mainCampusFetchedAt
:
state
.
mainCampus
.
fetched
.
fetchedAt
,
mainCampusHasError
:
state
.
mainCampus
.
hasError
,
mainCampusIsLoading
:
state
.
mainCampus
.
isLoading
,
mainCampusInvalidated
:
state
.
mainCampus
.
invalidated
,
};
};
};
};
...
...
frontend/src/components/map/UnivMap.js
View file @
d569450d
...
@@ -5,7 +5,7 @@ import Loading from '../other/Loading';
...
@@ -5,7 +5,7 @@ import Loading from '../other/Loading';
import
{
Map
,
TileLayer
,
Marker
,
Popup
,
LayersControl
,
FeatureGroup
,
Circle
,
LayerGroup
}
from
'
react-leaflet
'
;
import
{
Map
,
TileLayer
,
Marker
,
Popup
,
LayersControl
,
FeatureGroup
,
Circle
,
LayerGroup
}
from
'
react-leaflet
'
;
// import MarkerClusterGroup from 'react-leaflet-markercluster';
// import MarkerClusterGroup from 'react-leaflet-markercluster';
import
{
import
{
universit
ies
FetchData
,
universit
y
FetchData
,
mainCampusFetchData
,
mainCampusFetchData
,
}
from
'
../../generated/actions
'
;
}
from
'
../../generated/actions
'
;
import
UnivMarkers
from
'
./UnivMakers
'
;
import
UnivMarkers
from
'
./UnivMakers
'
;
...
@@ -20,30 +20,6 @@ class UnivMap extends MyComponent {
...
@@ -20,30 +20,6 @@ class UnivMap extends MyComponent {
};
};
}
}
componentDidMount
()
{
let
univ_data
=
this
.
props
.
universities
.
fetched
.
universities
;
if
(
univ_data
.
length
==
0
||
this
.
props
.
universities
.
invalidated
)
{
this
.
props
.
fetchUniversities
();
}
let
main_campus_data
=
this
.
props
.
mainCampus
.
fetched
.
mainCampus
;
if
(
main_campus_data
.
length
==
0
||
this
.
props
.
mainCampus
.
invalidated
)
{
this
.
props
.
fetchMainCampus
();
}
}
componentDidUpdate
()
{
// TODO ajouter expire date
if
(
this
.
props
.
universities
.
invalidated
)
{
this
.
props
.
fetchUniversities
();
}
if
(
this
.
props
.
mainCampus
.
invalidated
)
{
this
.
props
.
fetchMainCampus
();
}
}
componentWillUnmount
()
{
componentWillUnmount
()
{
let
l
=
this
.
state
.
leaflet_instance
;
let
l
=
this
.
state
.
leaflet_instance
;
...
@@ -76,18 +52,11 @@ class UnivMap extends MyComponent {
...
@@ -76,18 +52,11 @@ class UnivMap extends MyComponent {
}))
}))
}
}
render
()
{
myRender
()
{
if
(
this
.
checkPropsHasError
())
{
return
<
p
>
Sorry
!
There
was
an
error
loading
the
items
<
/p>
;
}
if
(
this
.
checkPropsIsLoading
())
{
return
<
Loading
/>
;
}
let
stamen_name
=
"
Stamen Watercolor
"
;
let
stamen_name
=
"
Stamen Watercolor
"
;
let
osm_fr_name
=
"
OpenStreetMap France
"
;
let
osm_fr_name
=
"
OpenStreetMap France
"
;
let
esri_name
=
"
Esri WorldImagery
"
;
let
esri_name
=
"
Esri WorldImagery
"
;
return
(
return
(
<
Map
center
=
{
this
.
props
.
map
.
center
}
zoom
=
{
this
.
props
.
map
.
zoom
}
style
=
{{
height
:
"
800px
"
}}
whenReady
=
{(
e
)
=>
this
.
saveLeafletInstance
(
e
.
target
)}
onBaselayerchange
=
{(
e
)
=>
this
.
saveSelectedLayer
(
e
)}
>
<
Map
center
=
{
this
.
props
.
map
.
center
}
zoom
=
{
this
.
props
.
map
.
zoom
}
style
=
{{
height
:
"
800px
"
}}
whenReady
=
{(
e
)
=>
this
.
saveLeafletInstance
(
e
.
target
)}
onBaselayerchange
=
{(
e
)
=>
this
.
saveSelectedLayer
(
e
)}
>
<
LayersControl
position
=
"
topright
"
>
<
LayersControl
position
=
"
topright
"
>
...
@@ -145,8 +114,10 @@ const mapStateToProps = (state) => {
...
@@ -145,8 +114,10 @@ const mapStateToProps = (state) => {
const
mapDispatchToProps
=
(
dispatch
)
=>
{
const
mapDispatchToProps
=
(
dispatch
)
=>
{
return
{
return
{
fetchUniversities
:
()
=>
dispatch
(
universitiesFetchData
()),
fetchData
:
{
fetchMainCampus
:
()
=>
dispatch
(
mainCampusFetchData
()),
universities
:
()
=>
dispatch
(
universityFetchData
()),
mainCampus
:
()
=>
dispatch
(
mainCampusFetchData
())
},
saveMainMap
:
(
pos
)
=>
dispatch
(
saveMainMapPosition
(
pos
)),
saveMainMap
:
(
pos
)
=>
dispatch
(
saveMainMapPosition
(
pos
)),
};
};
};
};
...
...
frontend/src/reducers/index.js
View file @
d569450d
import
{
combineReducers
}
from
'
redux
'
;
import
{
combineReducers
}
from
'
redux
'
;
import
{
import
{
universit
ies
Reducers
,
universit
y
Reducers
,
mainCampusReducers
,
mainCampusReducers
,
countr
ies
Reducers
,
countr
y
Reducers
,
countr
ies
ElReducers
,
countr
y
ElReducers
,
universit
ies
ElReducers
universit
y
ElReducers
}
from
'
../generated/combinedReducers
'
;
}
from
'
../generated/combinedReducers
'
;
import
{
import
{
...
@@ -17,10 +17,10 @@ const appReducers = combineReducers({
...
@@ -17,10 +17,10 @@ const appReducers = combineReducers({
})
})