Commit dd51a22d authored by Matija Obreza's avatar Matija Obreza

Accession maps with CDN and lat/lng bounds

parent aefacb9e
......@@ -6,9 +6,10 @@ import FilteredPage, { IPageRequest } from 'model/FilteredPage';
import Accession from 'model/Accession';
import AccessionFilter from 'model/AccessionFilter';
import AccessionDetails from 'model/AccessionDetails';
import AccessionMapInfo from 'model/AccessionMapInfo';
import {list as listAccessions, getDetailsByUuid, getDetailsByDoi, listOverview as listAccessionOverview, toUUID} from 'actions/genesys/accessionService';
import {RECEIVE_ACCESSIONS, RECEIVE_ACCESSION, RECEIVE_ACCESSION_OVERVIEW, APPEND_ACCESSIONS} from 'constants/accessions';
import {list as listAccessions, getDetailsByUuid, getDetailsByDoi, listOverview as listAccessionOverview, toUUID, mapInfo} from 'actions/genesys/accessionService';
import {RECEIVE_ACCESSIONS, RECEIVE_ACCESSION, RECEIVE_ACCESSION_OVERVIEW, APPEND_ACCESSIONS, RECEIVE_ACCESSION_MAPINFO} from 'constants/accessions';
const receiveAccessions = (paged: FilteredPage<Accession>, error = null) => ({
type: RECEIVE_ACCESSIONS,
......@@ -25,6 +26,11 @@ const receiveAccessionOverview = (overview: any, error = null) => ({
payload: { overview, error },
});
const receiveAccessionMapInfo = (mapInfo: AccessionMapInfo, error = null) => ({
type: RECEIVE_ACCESSION_MAPINFO,
payload: { mapInfo, error },
});
const receiveAccession = (accession: AccessionDetails, error = null) => ({
type: RECEIVE_ACCESSION,
payload: { accession, error },
......@@ -37,7 +43,12 @@ export const updateRoute = (paged: FilteredPage<Accession>, path: string = '/a')
s: paged.sort[0].property === Accession.DEFAULT_SORT.property ? undefined : paged.sort[0].property,
d: paged.sort[0].direction === Accession.DEFAULT_SORT.direction ? undefined : paged.sort[0].direction,
};
dispatch(navigateTo(paged.filterCode ? `${path}/${paged.filterCode}` : path, qs));
dispatch(updateRoute2(paged.filterCode, path, qs));
};
export const updateRoute2 = (filterCode: string, path: string = '/a', qs?: any) => (dispatch) => {
console.log(`Update route2 ${filterCode} ${path}`, qs);
dispatch(navigateTo(filterCode ? `${path}/${filterCode}` : path, qs));
};
export const applyFilters = (filters: string | AccessionFilter, page: IPageRequest = { page: 0 }) => (dispatch) => {
......@@ -76,6 +87,17 @@ export const loadAccessionsOverviewPage = (filterCode: string) => (dispatch) =>
});
};
export const loadAccessionsMapInfo = (filters: string | AccessionFilter) => (dispatch) => {
return dispatch(mapInfo(filters))
.then((mapInfo: AccessionMapInfo) => {
dispatch(receiveAccessionMapInfo(mapInfo));
dispatch(updateRoute2(mapInfo.filterCode, '/a/map'));
}).catch((error) => {
console.log(`API error`, error);
dispatch(receiveAccessionMapInfo(null, error.response));
});
};
export const loadAccessionsPage = (page: IPageRequest) => (dispatch, getState) => {
const filterCode = getState().accessions.paged.filterCode;
return dispatch(listAccessions(filterCode, page))
......
......@@ -7,7 +7,7 @@ import AccessionFilter from 'model/AccessionFilter';
import FilteredPage, { IPageRequest } from 'model/FilteredPage';
import {AccessionIdentifier} from 'model/dataset.model';
import AccessionDetails from 'model/AccessionDetails';
import AccessionMapInfo from 'model/AccessionMapInfo';
/**
......@@ -73,3 +73,8 @@ export const listOverview = (filter: string | AccessionFilter) => (dispatch, g
const authorization = getState().login.access_token;
return AccessionService.listOverview(authorization, filter);
};
export const mapInfo = (filter: string | AccessionFilter) => (dispatch, getState): Promise<AccessionMapInfo> => {
const authorization = getState().login.access_token;
return AccessionService.mapInfo(authorization, filter);
};
......@@ -2,6 +2,6 @@ export const RECEIVE_ACCESSIONS = 'accessions/RECEIVE_ACCESSIONS';
export const APPEND_ACCESSIONS = 'accessions/APPEND_ACCESSIONS';
export const RECEIVE_ACCESSION_OVERVIEW = 'accessions/RECEIVE_ACCESSION_OVERVIEW';
export const RECEIVE_ACCESSION = 'accessions/RECEIVE_ACCESSION';
export const RECEIVE_ACCESSION_MAPINFO = 'accessions/RECEIVE_ACCESSION_MAPINFO';
export const ACCESSION_FILTERFORM = 'Form/Accession/ACCESSION_FILTERFORM';
export const ACCESSION_FORM = 'Form/Accession/ACCESSION_FORM';
import AccessionFilter from 'model/AccessionFilter';
/*
* Defined in Swagger as '#/definitions/AccessionMapInfo'
*/
class AccessionMapInfo {
public filterCode: string;
public filter: AccessionFilter;
public bounds: number[][];
public accessionCount: number;
public tileServers: string[];
}
export default AccessionMapInfo;
import update from 'immutability-helper';
import { IReducerAction } from 'model/common.model';
import {RECEIVE_ACCESSIONS, RECEIVE_ACCESSION, RECEIVE_ACCESSION_OVERVIEW, APPEND_ACCESSIONS} from 'constants/accessions';
import {RECEIVE_ACCESSIONS, RECEIVE_ACCESSION, RECEIVE_ACCESSION_OVERVIEW, APPEND_ACCESSIONS, RECEIVE_ACCESSION_MAPINFO} from 'constants/accessions';
import FilteredPage from 'model/FilteredPage';
import Accession from 'model/Accession';
import AccessionMapInfo from 'model/AccessionMapInfo';
const INITIAL_STATE: {
accession: Accession;
......@@ -12,12 +13,14 @@ const INITIAL_STATE: {
paged: FilteredPage<Accession>;
pagedError: any;
overview: any;
mapInfo: AccessionMapInfo;
} = {
accession: null,
accessionError: null,
paged: null,
pagedError: null,
overview: null,
mapInfo: null,
};
function accessions(state = INITIAL_STATE, action: IReducerAction) {
......@@ -52,6 +55,8 @@ function accessions(state = INITIAL_STATE, action: IReducerAction) {
return update(state, {
paged: { $set: paged },
pagedError: { $set: error },
overview: {$set: null},
mapInfo: { $set: null },
});
}
......@@ -60,6 +65,7 @@ function accessions(state = INITIAL_STATE, action: IReducerAction) {
return update(state, {
overview: { $set: overview },
pagedError: { $set: error },
mapInfo: { $set: null },
});
}
......@@ -80,6 +86,16 @@ function accessions(state = INITIAL_STATE, action: IReducerAction) {
});
}
case RECEIVE_ACCESSION_MAPINFO: {
const { mapInfo, error } = action.payload;
return update(state, {
mapInfo: { $set: mapInfo },
pagedError: { $set: error },
paged: {$set: null},
overview: {$set: null},
});
}
default:
return state;
}
......
......@@ -7,6 +7,7 @@ import { API_ROOT } from 'constants/apiURLS';
import Accession from 'model/Accession';
import AccessionDetails from 'model/AccessionDetails';
import AccessionFilter from 'model/AccessionFilter';
import AccessionMapInfo from 'model/AccessionMapInfo';
import FilteredPage, { IPageRequest } from 'model/FilteredPage';
import {AccessionIdentifier} from 'model/dataset.model';
......@@ -17,6 +18,7 @@ const URL_GET_DETAILS_BY_UUID = UrlTemplate.parse(`${API_ROOT}/api/v1/acn/detail
const URL_TO_UUID = `${API_ROOT}/api/v1/acn/toUUID`;
const URL_LIST = `${API_ROOT}/api/v1/acn/list`;
const URL_LIST_OVERVIEW = `${API_ROOT}/api/v1/acn/overview`;
const URL_MAPINFO = `${API_ROOT}/api/v1/acn/mapinfo`;
/*
* Defined in Swagger as 'accession'
......@@ -155,6 +157,27 @@ class AccessionService {
...content,
}).then(({ data }) => data);
}
/**
* get map information
*
* @param authToken Authorization token
* @param filter filter or AccessionFilter
*/
public static mapInfo(authToken: string, filter: string | AccessionFilter): Promise<AccessionMapInfo> {
const qs = QueryString.stringify({
f: typeof filter === 'string' ? filter : undefined,
}, {});
const apiUrl = URL_MAPINFO + (qs ? `?${qs}` : '');
const content = { data: typeof filter === 'string' ? null : { ...filter } };
return authenticatedRequest(authToken, {
url: apiUrl,
method: 'POST',
headers: {'Content-Type': 'application/json'},
...content,
}).then(({ data }) => data);
}
}
export default AccessionService;
......@@ -40,7 +40,7 @@ class BrowsePage extends BrowsePageTemplate<Accession> {
}
public render() {
const { paged, currentTab } = this.props;
const { paged, filterCode, currentTab } = this.props;
const renderAccession = (s: Accession, index: number) => {
return <AccessionCard key={ s.uuid } index={ index } accession={ s } />;
......@@ -68,9 +68,9 @@ class BrowsePage extends BrowsePageTemplate<Accession> {
</span>
}
>
<Tab name="data" to={ `/a/` }>Accessions</Tab>
<Tab name="overview" to={ `/a/overview/` }>Overview</Tab>
<Tab name="map" to={ `/a/map/` }>Map</Tab>
<Tab name="data" to={ `/a/${filterCode || ''}` }>Accessions</Tab>
<Tab name="overview" to={ `/a/overview/${filterCode || ''}` }>Overview</Tab>
<Tab name="map" to={ `/a/map/${filterCode || '' }` }>Map</Tab>
</Tabs>
......
......@@ -2,15 +2,15 @@ import * as React from 'react';
import {connect} from 'react-redux';
import {withStyles} from '@material-ui/core/styles';
import {bindActionCreators} from 'redux';
import { parse } from 'query-string';
import { applyFilters, updateRoute } from 'actions/accessions';
import { loadAccessionsMapInfo } from 'actions/accessions';
import AccessionFilter from 'model/AccessionFilter';
import Loading from 'ui/common/Loading';
import AccessionMapInfo from 'model/AccessionMapInfo';
import PageLayout from 'ui/layout/PageLayout';
import ContentHeader from '../../common/heading/ContentHeader';
import FilteredPage from '../../../model/FilteredPage';
import Accession from '../../../model/Accession';
import ContentHeader from 'ui/common/heading/ContentHeader';
import Button from '@material-ui/core/Button';
import Tabs, {Tab} from 'ui/common/Tabs';
import PrettyFilters from '../../common/filter/PrettyFilters';
import PrettyFilters from 'ui/common/filter/PrettyFilters';
let Map;
......@@ -18,12 +18,11 @@ let TileLayer;
interface IMapPageProps extends React.ClassAttributes<any> {
apiUrl: string;
paged: FilteredPage<Accession>;
mapInfo: AccessionMapInfo;
currentTab: string;
classes: any;
filterCode: string;
applyFilters: any;
updateRoute: any;
loadAccessionsMapInfo: any;
}
const styles = (theme) => ({
......@@ -36,13 +35,8 @@ const styles = (theme) => ({
class BrowsePage extends React.Component<IMapPageProps, any> {
protected static needs = [
({ search, params: { filterCode } }) => {
const qs = parse(search || '');
const page = { direction: qs.d, properties: null };
if (qs.s) {
page.properties = [ ...qs.s ];
}
return applyFilters(filterCode || '', page);
({ params: { filterCode } }) => {
return loadAccessionsMapInfo(filterCode || '');
},
];
......@@ -56,33 +50,34 @@ class BrowsePage extends React.Component<IMapPageProps, any> {
public componentWillMount() {
const { paged, filterCode, updateRoute, applyFilters } = this.props;
// console.log(`Filter code for map ${filterCode} ?== ${paged && paged.filterCode}`, filterCode, paged ? paged.filterCode : 'No paged');
if (paged && paged.filterCode !== filterCode) {
// console.log(`paged.filterCode !== filterCode. updatingRoute`);
updateRoute(paged, '/a/map');
} else if (!paged) {
applyFilters(filterCode || '');
const { mapInfo, filterCode, loadAccessionsMapInfo } = this.props;
// console.log(`Filter code for map ${filterCode} ?== ${mapInfo && mapInfo.filterCode}`, filterCode, mapInfo ? mapInfo.filterCode : 'No mapInfo');
if (mapInfo && mapInfo.filterCode !== filterCode) {
// console.log(`mapInfo.filterCode !== filterCode. updatingRoute`);
loadAccessionsMapInfo(filterCode || '');
} else if (!mapInfo) {
loadAccessionsMapInfo(filterCode || '');
}
}
/// Wrap applyFilters dispatch and fills the current sort selection
protected myApplyFilters = (filters: any) => {
const { paged, applyFilters } = this.props;
if (paged) {
applyFilters(filters, { page: 0, direction: paged.sort[0].direction, properties: [ paged.sort[0].property ] });
} else {
applyFilters(filters, { page: 0 });
}
/// Wrap loadAccessionsMapInfo dispatch and fills the current sort selection
protected myApplyFilters = (filters: AccessionFilter) => {
const { loadAccessionsMapInfo } = this.props;
loadAccessionsMapInfo(filters);
}
public render() {
const position = [30, 0];
const { paged, currentTab, classes, filterCode, apiUrl } = this.props;
const { mapInfo, currentTab, classes, filterCode } = this.props;
if (! mapInfo) {
return <Loading />;
}
// const color = 'f00ba0';
const layerUrl = `${apiUrl}/acn/tile/{z}/{x}/{y}?f=${filterCode ? filterCode : ''}`; // `&color=${color}`;
const layerUrl = `{s}/acn/tile/{z}/{x}/{y}?f=${filterCode ? filterCode : ''}`; // `&color=${color}`;
return (
<PageLayout>
......@@ -98,20 +93,21 @@ class BrowsePage extends React.Component<IMapPageProps, any> {
</span>
}
>
<Tab name="data" to={ `/a/` }>Accessions</Tab>
<Tab name="overview" to={ `/a/overview/` }>Overview</Tab>
<Tab name="map" to={ `/a/map/` }>Map</Tab>
<Tab name="data" to={ `/a/${filterCode || ''}` }>Accessions</Tab>
<Tab name="overview" to={ `/a/overview/${filterCode || ''}` }>Overview</Tab>
<Tab name="map" to={ `/a/map/${filterCode || '' }` }>Map</Tab>
</Tabs>
<PrettyFilters
prefix="accessions"
filterObj={ paged && paged.filter || {} }
filterObj={ mapInfo && mapInfo.filter || {} }
onSubmit={ this.myApplyFilters }
/>
<div className={ classes.leafletContainer }>
{ typeof window !== 'undefined' &&
{ mapInfo && typeof window !== 'undefined' &&
<Map
center={ position }
zoom={ 3 } minZoom={ 2 } maxZoom={ 14 }>
zoom={ 3 } minZoom={ 2 } maxZoom={ 14 }
bounds={ mapInfo.bounds }>
<TileLayer
opacity={ 0.50 }
attribution={ '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' }
......@@ -122,6 +118,7 @@ class BrowsePage extends React.Component<IMapPageProps, any> {
updateWhenZooming={ false }
attribution="&amp;copy Accession localities from <a href=&quot;/&quot;>Genesys PGR</a>"
url={ layerUrl }
subdomains={ mapInfo.tileServers }
/>
</Map>
}
......@@ -132,15 +129,13 @@ class BrowsePage extends React.Component<IMapPageProps, any> {
}
const mapStateToProps = (state, ownProps) => ({
apiUrl: state.applicationConfig.apiUrl,
paged: state.accessions.paged || undefined,
mapInfo: state.accessions.mapInfo || undefined,
filterCode: ownProps.match.params.filterCode || '',
currentTab: ownProps.match.params.tab || 'map', // current tab, or ownProps.location.pathname
});
const mapDispatchToProps = (dispatch) => bindActionCreators({
applyFilters,
updateRoute,
loadAccessionsMapInfo,
}, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(BrowsePage));
......@@ -62,7 +62,7 @@ class BrowsePage extends React.Component<IOverviewPageProps, any> {
}
public render() {
const { paged, currentTab, applyOverviewFilters, overview, t } = this.props;
const { paged, filterCode, currentTab, applyOverviewFilters, overview, t } = this.props;
const overviewKeys = ['institute.code', 'institute.country.code3', 'cropName', 'crop.shortName', 'sampStat', 'taxonomy.genus', 'taxonomy.genusSpecies',
'countryOfOrigin.code3', 'donorCode', 'mlsStatus', 'available', 'duplSite', 'sgsv', 'storage', 'breederCode'];
......@@ -87,15 +87,13 @@ class BrowsePage extends React.Component<IOverviewPageProps, any> {
tab={ currentTab }
actions={
<span>
<Button> Select all </Button>
<Button> Delete selected </Button>
<Button> Share selected </Button>
<Button> Something </Button>
</span>
}
>
<Tab name="data" to={ `/a/` }>Accessions</Tab>
<Tab name="overview" to={ `/a/overview/` }>Overview</Tab>
<Tab name="map" to={ `/a/map/` }>Map</Tab>
<Tab name="data" to={ `/a/${filterCode || ''}` }>Accessions</Tab>
<Tab name="overview" to={ `/a/overview/${filterCode || ''}` }>Overview</Tab>
<Tab name="map" to={ `/a/map/${filterCode || '' }` }>Map</Tab>
</Tabs>
<PrettyFilters
prefix="accessions"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment