Skip to content
This repository has been archived by the owner on Feb 19, 2024. It is now read-only.

Commit

Permalink
Merge pull request #402 from onaio/bug/tests-on-staging
Browse files Browse the repository at this point in the history
Establish v1.3.1
  • Loading branch information
Conor Kelly authored Jan 28, 2020
2 parents 8c4cf03 + 83e2f6c commit 4819929
Show file tree
Hide file tree
Showing 8 changed files with 341 additions and 154 deletions.
152 changes: 151 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,157 @@ An example layer file in the path `/layers/ken-health-sites.json`
}
```

Ensure that the data file for the layer is located in the specified source path `data/ken_health_sites.geojson`.
## Data Sources

Gisida supports various data sources. These include: <br>
**csv -** A [csv](https://en.wikipedia.org/wiki/Comma-separated_values) file can be used solely as a source without joining it with any other source as long as it has geolocations columns i.e longitude and latitude. If the fields are named differently one will need to include geo-columns property on the layer spec as shown below.

```
"geo-columns": ["longitude", "latitude"]
```

An example of such a layer

```json
{
"label": "Kenya Health Sites",
"source": {
"type": "geojson",
"featureType": "Point",
"data": "data/ken_health_sites.csv"
},
"geo-columns": ["longs", "lats"],
"type": "symbol",
"minZoom": 0,
"paint": {
"text-color": "#000",
"text-halo-color": "#fff",
"text-halo-width": 1.3,
"text-halo-blur": 1
},
"layout": {
"text-field": "{name} ({type})",
"text-offset": [0, 2],
"icon-image": "hospital-11",
"icon-allow-overlap": true,
"text-transform": "uppercase"
},
"visible": false,
"credit": "Global Healthsites Mapping Project<br>Aug 15, 2017"
}
```

We can also join the csv with a vector layer being served from mapbox. To achieve this we need to add a columns with simmillar data on both datasets for the join to work.

```
"join":["vectorProp","csvProp"]
```

An example of such a layer

```json
{
"label": "Kenya Health Sites",
"source": {
"type": "vector",
"layer": "province",
"url": "mapbox://ona.cxeuuuuu",
"data": "data/ken_health_sites.csv",
"join": ["ADM2_EN", "province1"]
},
"type": "fill",
"minZoom": 0,
"categories": {
"breaks": "yes",
"color": "Greens",
"clusters": 3
},
"visible": false,
"credit": "Kenya Health Mapping Project"
}
```

The url points to the tileset which is joined with the csv file on basis of the two files i.e ADM2_EN and province1
<br>
**geojson -** We use [geojon](https://geojson.org/) format mostly to build to render geometric centres (centroids) of regions on a map but they still can be used simmilarly as csv's. An example of geojson data source in action

```json
{
"label": "District Labels",
"source": {
"type": "geojson",
"data": "data/centroids-2.geojson"
},
"type": "symbol",
"minzoom": 0,
"paint": {
"text-color": "#000",
"text-halo-color": "#fff",
"text-halo-width": 1.3,
"text-halo-blur": 1
},
"layout": {
"text-size": 12,
"text-field": "{NAME}",
"text-transform": "uppercase",
"text-offset": [0, 0]
},
"visible": false,
"category": "Boundaries & Labels"
}
```

To test whether the geojson file is working and is of right format you can paste it's content [here](http://geojson.io) and check whether it renders.
<br>
**onadata -** Gisida supports data coming from [Ona](https://ona.io/) forms. When building layers that pull data from Ona you will have to provide the form id on the layer spec.

```
"source": {
"type": "geojson",
"data": 899
}
```

We can also pull data from different forms and join the various form data. Here is an example.

```
"source": {
"type": "geojson",
"data": [
55,
56,
],
"join": [
"pd_number",
"pd_number",
],
}
```

<br>

**superset slice -** Gisida supports [superset/canopy](https://canopyinsights.com/) slices. The slice are api's that hold unique id's. The splice id property should be provided on the layer spec. Here is an example of a superset layer in action:

```
"source": {
"type": "vector",
"data": {
"type": "superset",
"slice-id": 2238},
"layer": "homes",
"url": "mapbox://cncncncnc",
"join": [
"homes",
"homes"
]
},
```

<br>

**Pulling Directly from Mapbox**

Ensure that the data file for the layer is located in the specified source path `data/ken_health_sites.geojson or a remote url that points to the file`.

### 3. Actions

Expand Down
14 changes: 3 additions & 11 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
/* eslint-disable no-underscore-dangle */
/* eslint-disable global-require */
import app from './store/reducers/app';
import filter from './store/reducers/filter';
import layersReducer from './store/reducers/layers';
Expand All @@ -9,6 +7,7 @@ import regions from './store/reducers/regions';
import styles from './store/reducers/styles';
import supersetConfig from './store/reducers/superset-config';

// eslint-disable-next-line no-underscore-dangle, global-require
if (!global._babelPolyfill) require('babel-polyfill');

const gisida = {};
Expand All @@ -17,17 +16,10 @@ gisida.version = require('../package.json').version;
gisida.initStore = require('./store/initStore').default;
gisida.loadLayers = require('./store/initStore').loadLayers;
gisida.reducerRegistry = require('./store/reducerRegistry').default;
gisida.createMapReducer = require('./store/reducers/createMapReducer/createMapReducer').createMapReducer;
gisida.createMapReducer = require('./store/reducers/app').createMapReducer;

gisida.reducers = {
...app,
filter,
layersReducer,
loc,
locationsReducer,
regions,
styles,
supersetConfig,
...app, filter, layersReducer, loc, locationsReducer, regions, styles, supersetConfig,
};
gisida.Actions = require('./store/actions/actions').default;
gisida.prepareLayer = require('./map/prepareLayer').default;
Expand Down
4 changes: 2 additions & 2 deletions src/store/reducers/layers.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default function LAYERS(state = defaultState.LAYERS, action) {
}
case ADD_LAYER_GROUP: {
// parse action.group for urls
const groupMapper = layer => {
const groupMapper = (layer) => {
if (typeof layer === 'string') {
if (layer.indexOf('http') === -1) {
return layer;
Expand All @@ -20,7 +20,7 @@ export default function LAYERS(state = defaultState.LAYERS, action) {
return pathSplit[pathSplit.length - 1];
}
const subGroup = {};
Object.keys(layer).forEach(key => {
Object.keys(layer).forEach((key) => {
subGroup[key] = layer[key].map(groupMapper);
});
return subGroup;
Expand Down
18 changes: 7 additions & 11 deletions src/store/reducers/loc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ export default function LOC(state = defaultState.LOC, action) {
...state,
locations: { ...action.config },
location: {
...Object.keys(action.config)
.map(d => action.config[d])
.find(d => d.default === true),
...Object.keys(action.config).map(d => action.config[d]).find(d => d.default === true),
doUpdateLOC: false,
},
doUpdateMap: state.doUpdateMap,
Expand All @@ -24,21 +22,19 @@ export default function LOC(state = defaultState.LOC, action) {
...state,
doUpdateMap: mapId,
active: typeof locations[loc] !== 'undefined' ? loc : active,
location:
typeof locations[loc] !== 'undefined'
? { ...locations[loc], doUpdateLOC: !state.location.doUpdateLOC }
: { ...state.location, doUpdateLOC: false },
location: typeof locations[loc] !== 'undefined'
? { ...locations[loc], doUpdateLOC: !state.location.doUpdateLOC }
: { ...state.location, doUpdateLOC: false },
};
}
case TOGGLE_MAP_LOCATION: {
const { loc } = action;
const { locations } = state;
return {
...state,
location:
typeof locations[loc] !== 'undefined'
? { ...locations[loc], doUpdateLOC: !state.location.doUpdateLOC }
: { ...state.location, doUpdateLOC: false },
location: typeof locations[loc] !== 'undefined' ?
{ ...locations[loc], doUpdateLOC: !state.location.doUpdateLOC } :
{ ...state.location, doUpdateLOC: false },
};
}
default:
Expand Down
4 changes: 2 additions & 2 deletions src/store/reducers/regions.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default function REGIONS(state = defaultState.REGIONS, action) {
switch (action.type) {
case INIT_REGIONS: {
const regions = action.regions
? action.regions.map(r => {
? action.regions.map((r) => {
const region = r;
// check if mapconfig center matches region center to set current region
if (
Expand All @@ -20,7 +20,7 @@ export default function REGIONS(state = defaultState.REGIONS, action) {
return regions;
}
case CHANGE_REGION: {
const updatedRegions = state.map(r => {
const updatedRegions = state.map((r) => {
const region = r;
if (action.region === region.name) {
region.current = true;
Expand Down
4 changes: 2 additions & 2 deletions src/store/reducers/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import { INIT_STYLES, CHANGE_STYLE } from '../constants/actionTypes';
export default function STYLES(state = defaultState.STYLES, action) {
switch (action.type) {
case INIT_STYLES: {
const styles = action.styles.map(s => {
const styles = action.styles.map((s) => {
const style = s;
if (style.url === action.mapConfig.style) style.current = true;
return style;
});
return styles;
}
case CHANGE_STYLE: {
const updatedStyles = state.map(s => {
const updatedStyles = state.map((s) => {
const style = s;
if (action.style === style.url) {
if (action.mapId) {
Expand Down
52 changes: 52 additions & 0 deletions test/store/reducers/reducers.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { APP } from '../../../src/store/reducers';
import defaultState from '../../../src/store/defaultState';
import { INIT_APP } from '../../../src/store/constants/actionTypes';

describe('APP', () => {
it('should return the initial state', () => {
expect(APP(undefined, {})).toEqual(defaultState.APP);
});

it('should handle INIT_APP', () => {
const action = {
type: INIT_APP,
config: {
accessToken: false,
appName: 'React Gisida',
loaded: false,
mapConfig: {
center: [0, 0],
container: 'map',
style: '',
zoom: 10,
},
},
};
// Case 1: The state obj is empty
const stateEmpty = {};
expect(APP(stateEmpty, action)).toEqual({
...stateEmpty,
...action.config,
loaded: true,
});

// Case 2: The state obj is not empty
const stateOld = {
accessToken: false,
appName: 'Old App Name',
loaded: true,
mapConfig: {
center: [0, 0],
container: 'map',
style: '',
zoom: 10,
},
};

expect(APP(stateOld, action)).toEqual({
...stateOld,
...action.config,
loaded: true,
});
});
});
Loading

0 comments on commit 4819929

Please sign in to comment.