Commit a7e8c158 authored by Matija Obreza's avatar Matija Obreza
Browse files

Merge branch '214-activity-indicator' into 'master'

Activity indicator

Closes #214

See merge request genesys-pgr/genesys-ui!224
parents 5e430f38 8942ff03
// actions
import {createApiCaller} from 'actions/ApiCall';
// Constants
import {DASHBOARD_APPEND_ACCESSIONS, DASHBOARD_RECEIVE_ACCESSIONS} from 'accessions/constants';
import {DASHBOARD_APPEND_ACCESSIONS} from 'accessions/constants';
// Model
import FilteredPage, {IPageRequest} from 'model/FilteredPage';
import Accession from 'model/accession/Accession';
import {IPageRequest} from 'model/FilteredPage';
import AccessionFilter from 'model/accession/AccessionFilter';
// Service
import AccessionService from 'service/genesys/AccessionService';
const receiveAccessions = (paged: FilteredPage<Accession>, error = null) => ({
type: DASHBOARD_RECEIVE_ACCESSIONS,
payload: { paged, error },
});
const appendAccessions = (paged: FilteredPage<Accession>, error = null) => ({
type: DASHBOARD_APPEND_ACCESSIONS,
payload: { paged, error },
});
const apiListAccessions = createApiCaller(AccessionService.list, DASHBOARD_APPEND_ACCESSIONS);
// Load accession page without redirect
export const loadAccessionsPageAction = (page: IPageRequest, filterCode: string | AccessionFilter) => (dispatch, getState) => {
return AccessionService.list(filterCode, page)
.then((paged) => {
if (paged.number === 0) {
dispatch(receiveAccessions(paged));
} else {
dispatch(appendAccessions(paged));
}
}).catch((error) => {
console.log(`API error`, error);
dispatch(receiveAccessions(null, error.response));
});
return dispatch(apiListAccessions(filterCode, page));
};
......@@ -6,46 +6,44 @@ import navigateTo from 'actions/navigation';
import FilteredPage, { IPageRequest } from 'model/FilteredPage';
import Accession from 'model/accession/Accession';
import AccessionFilter from 'model/accession/AccessionFilter';
import AccessionDetails from 'model/accession/AccessionDetails';
import AccessionMapInfo from 'model/accession/AccessionMapInfo';
import AccessionAuditLog from 'model/accession/AccessionAuditLog';
import MapLayer from 'model/genesys/MapTileLayer';
import { RECEIVE_ACCESSIONS, RECEIVE_ACCESSION, RECEIVE_ACCESSION_OVERVIEW, APPEND_ACCESSIONS, RECEIVE_ACCESSION_MAPINFO, RECEIVE_ACCESSION_AUDIT_LOG, RECEIVE_TILE_LAYER } from 'accessions/constants';
import {
RECEIVE_ACCESSION,
RECEIVE_ACCESSION_OVERVIEW,
RECEIVE_ACCESSION_MAPINFO,
RECEIVE_ACCESSION_AUDIT_LOG,
RECEIVE_TILE_LAYER,
APPEND_ACCESSIONS,
} from 'accessions/constants';
import AccessionService from 'service/genesys/AccessionService';
import ClimateService from 'service/genesys/ClimateService';
import { showSnackbar } from 'actions/snackbar';
import Page from 'model/Page';
import TileClimate from 'model/genesys/TileClimate';
import {createApiCaller, createPureApiCaller} from 'actions/ApiCall';
import ApiCall from 'model/ApiCall';
const receiveAccessions = (paged: FilteredPage<Accession>, error = null) => ({
type: RECEIVE_ACCESSIONS,
payload: { paged, error },
const receiveAccessionMapInfo = (apiCall: ApiCall<any>) => ({
type: RECEIVE_ACCESSION_MAPINFO,
payload: { apiCall },
});
const appendAccessions = (paged: FilteredPage<Accession>, error = null) => ({
type: APPEND_ACCESSIONS,
payload: { paged, error },
});
// Wrapped API calls
const apiListAccessions = createApiCaller(AccessionService.list, APPEND_ACCESSIONS);
const apiAccessionsOverview = createApiCaller(AccessionService.listOverview, RECEIVE_ACCESSION_OVERVIEW);
const apiAccessionsMapInfo = createApiCaller(AccessionService.mapInfo, RECEIVE_ACCESSION_MAPINFO);
const receiveAccessionOverview = (overview: any, error = null) => ({
type: RECEIVE_ACCESSION_OVERVIEW,
payload: { overview, error },
});
const apiGeoJson = createPureApiCaller(AccessionService.geoJson);
const apiClimateInfo = createPureApiCaller(ClimateService.getCurrentClimate);
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 },
});
const apiListAccessionByUuid = createPureApiCaller(AccessionService.listAllByUuid);
const apiAccessionByUuid = createApiCaller(AccessionService.getDetailsByUuid, RECEIVE_ACCESSION);
const apiAccessionByDoi = createApiCaller(AccessionService.getDetailsByDoi, RECEIVE_ACCESSION);
const receiveAccessionAuditLog = (auditLog: AccessionAuditLog, error = null) => ({
type: RECEIVE_ACCESSION_AUDIT_LOG,
payload: { auditLog, error },
});
const apiAccessionAuditByUuid = createApiCaller(AccessionService.getAccessionAuditLogByUUID, RECEIVE_ACCESSION_AUDIT_LOG);
const apiAccessionAuditByDoi = createApiCaller(AccessionService.getAccessionAuditLogByDoi, RECEIVE_ACCESSION_AUDIT_LOG);
export const updateRoute = (paged: FilteredPage<Accession>, path: string = '/a') => (dispatch) => {
......@@ -61,150 +59,85 @@ export const updateRouteWithFilterCode = (filterCode: string, path: string = '/a
dispatch(navigateTo(filterCode ? `${path}/${filterCode}${postfix}` : path, qs));
};
export const applyFilters = (filters: string | AccessionFilter, page: IPageRequest = { page: 0 }) => (dispatch) => {
export const applyFilters = (filters: string | AccessionFilter, page: IPageRequest = { page: 0 }) => (dispatch, getState) => {
console.log('Applying new filter', filters);
dispatch(showSnackbar('Applying filters...'));
return AccessionService.list(filters, page)
return dispatch(apiListAccessions(filters, page))
.then((paged) => {
dispatch(receiveAccessions(paged));
dispatch(updateRoute(paged));
dispatch(showSnackbar(`Filters applied.`));
}).catch((error) => {
console.log(`API error`, error);
dispatch(receiveAccessions(null, error));
dispatch(showSnackbar(`API error: ${error.statusText}`));
});
};
export const listAccessionsByUuid = (uuidList: string[]) => (dispatch) => {
return dispatch(apiListAccessionByUuid(uuidList));
};
export const loadMoreAccessions = (paged?: FilteredPage<Accession>) => (dispatch) => {
console.log('Load more accessions', paged);
return AccessionService.list(paged ? paged.filterCode : '', Page.nextPage(paged))
.then((paged) => {
if (paged.number === 0) {
dispatch(receiveAccessions(paged));
} else {
dispatch(appendAccessions(paged));
}
dispatch(updateRoute(paged));
}).catch((error) => {
console.log(`API error`, error);
dispatch(receiveAccessions(null, error));
});
return dispatch(apiListAccessions(paged ? paged.filterCode : '', Page.nextPage(paged)))
.then((paged) => dispatch(updateRoute(paged)));
};
export const applyOverviewFilters = (filters: string | AccessionFilter, page: IPageRequest = { page: 0 }) => (dispatch) => {
console.log('Applying new filter', filters);
return AccessionService.listOverview(filters)
return dispatch(apiAccessionsOverview(filters))
.then((overview) => {
dispatch(receiveAccessionOverview(overview));
dispatch(updateRouteWithFilterCode(overview.filterCode, '/a/overview'));
}).catch((error) => {
console.log(`API error`, error);
dispatch(receiveAccessionOverview(null, error));
});
};
export const loadAccessionsOverviewPage = (filterCode: string) => (dispatch) => {
return AccessionService.listOverview(filterCode)
.then((paged) => {
dispatch(receiveAccessionOverview(paged));
}).catch((error) => {
console.log(`API error`, error);
dispatch(receiveAccessionOverview(null, error));
});
return dispatch(apiAccessionsOverview(filterCode));
};
export const geoJsonRequest = (filter, limit) => (dispatch) => {
return dispatch(apiGeoJson(filter, limit));
};
export const currentClimateRequest = (lat, lng) => (dispatch) => {
return dispatch(apiClimateInfo(lat, lng));
};
export const loadAccessionsMapInfo = (filters: string | AccessionFilter, viewPort?: {center: number[], zoom: number}) => (dispatch) => {
return AccessionService.mapInfo(filters)
return dispatch(apiAccessionsMapInfo(filters))
.then((mapInfo: AccessionMapInfo) => {
if (!(mapInfo.bounds[0][0] && mapInfo.bounds[0][1] && mapInfo.bounds[1][0] && mapInfo.bounds[1][1])) {
mapInfo.bounds = [[-170, 80], [170, -80]];
console.log('One of map bounds is null, setting to default.');
dispatch(receiveAccessionMapInfo(ApiCall.success(mapInfo)));
}
dispatch(receiveAccessionMapInfo(mapInfo));
if (viewPort && viewPort.zoom && viewPort.center && viewPort.center.length === 2) {
console.log(`viewPort @..,z${viewPort.zoom}`, viewPort);
dispatch(updateRouteWithFilterCode(mapInfo.filterCode, '/a/map', null, viewPort && viewPort.center && `/@${viewPort.center[0]},${viewPort.center[1]},${viewPort.zoom}z`));
} else {
dispatch(updateRouteWithFilterCode(mapInfo.filterCode, '/a/map'));
}
}).catch((error) => {
console.log(`API error`, error);
dispatch(receiveAccessionMapInfo(null, error));
});
};
// export const loadAccessionsPage = (page: IPageRequest) => (dispatch, getState) => {
// const filterCode = getState().accessions.public.paged.filterCode;
// return AccessionService.list(filterCode, page)
// .then((paged) => {
// if (paged.number === 0) {
// dispatch(receiveAccessions(paged));
// } else {
// dispatch(appendAccessions(paged));
// }
// dispatch(updateRoute(paged));
// }).catch((error) => {
// console.log(`API error`, error);
// dispatch(receiveAccessions(null, error));
// });
// };
// // Load accession page without redirect
// export const loadAccessionsPageAction = (page: IPageRequest, filterCode: string | AccessionFilter) => (dispatch, getState) => {
// return AccessionService.list(filterCode, page)
// .then((paged) => {
// if (paged.number === 0) {
// dispatch(receiveAccessions(paged));
// } else {
// dispatch(appendAccessions(paged));
// }
// }).catch((error) => {
// console.log(`API error`, error);
// dispatch(receiveAccessions(null, error.response));
// });
// };
export const loadAccession = ({ uuid, doi }: { uuid?: string, doi?: string }) => (dispatch) => {
const loader = doi ? AccessionService.getDetailsByDoi : AccessionService.getDetailsByUuid;
const loader = doi ? apiAccessionByDoi : apiAccessionByUuid;
const lookup = doi ? doi : uuid;
return loader(lookup)
.then((accession) => {
dispatch(receiveAccession(accession));
}).catch((error) => {
console.log(`API error`, error);
dispatch(receiveAccession(null, error));
});
return dispatch(loader(lookup));
};
export const loadAccessionAuditLog = ({uuid, doi}: {uuid?: string, doi?: string}) => (dispatch) => {
const loader = doi ? AccessionService.getAccessionAuditLogByDoi : AccessionService.getAccessionAuditLogByUUID;
const loader = doi ? apiAccessionAuditByDoi : apiAccessionAuditByUuid;
const lookup = doi ? doi : uuid;
return loader(lookup)
return dispatch(loader(lookup))
.then((auditLog) => {
if (_.isEmpty(auditLog.auditAccession) && _.isEmpty(auditLog.auditAccessionCollect) && _.isEmpty(auditLog.auditAccessionGeo) && _.isEmpty(auditLog.auditAccessionId)) {
return dispatch(showSnackbar('common:label.noChanges'));
}
dispatch(receiveAccessionAuditLog(auditLog));
}).catch((error) => {
console.log(`API error`, error);
dispatch(receiveAccession(null, error));
});
};
export const overviewAccessions = (filterCode: string) => (dispatch) => {
return AccessionService.listOverview(filterCode)
.then((overview) => {
dispatch(receiveAccessionOverview(overview));
}).catch((error) => {
console.log(`API error`, error);
dispatch(receiveAccessionOverview(null, error));
});
return dispatch(apiAccessionsOverview(filterCode));
};
// TileLayers
......@@ -278,3 +211,4 @@ export const applyClimateFilters = (climate: TileClimate, extraFilters?: any) =>
dispatch(applyFilters(filter));
};
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_TILE_LAYER = 'accessions/RECEIVE_TILE_LAYER';
......@@ -10,6 +9,5 @@ export const ACCESSION_MAP_FILTERFORM = 'Form/Accession/ACCESSION_MAP_FILTERFORM
export const ACCESSION_FORM = 'Form/Accession/ACCESSION_FORM';
// Dashboard
export const DASHBOARD_RECEIVE_ACCESSIONS = 'accessions/dashboard/RECEIVE_ACCESSIONS';
export const DASHBOARD_APPEND_ACCESSIONS = 'accessions/dashboard/APPEND_ACCESSIONS';
export const DASHBOARD_RECEIVE_ACCESSION = 'accessions/dashboard/RECEIVE_ACCESSION';
import update from 'immutability-helper';
import { IReducerAction } from 'model/common.model';
import {DASHBOARD_RECEIVE_ACCESSIONS, DASHBOARD_RECEIVE_ACCESSION, DASHBOARD_APPEND_ACCESSIONS} from 'accessions/constants';
import {DASHBOARD_RECEIVE_ACCESSION, DASHBOARD_APPEND_ACCESSIONS} from 'accessions/constants';
import FilteredPage from 'model/FilteredPage';
import Accession from 'model/accession/Accession';
import ApiCall from 'model/ApiCall';
const INITIAL_STATE: {
accession: Accession;
accessionError: any;
paged: FilteredPage<Accession>;
pagedError: any;
accession: ApiCall<Accession>;
paged: ApiCall<FilteredPage<Accession>>;
} = {
accession: null,
accessionError: null,
paged: null,
pagedError: null,
};
function dashboardAccessions(state = INITIAL_STATE, action: IReducerAction) {
......@@ -23,52 +20,39 @@ function dashboardAccessions(state = INITIAL_STATE, action: IReducerAction) {
switch (action.type) {
case DASHBOARD_RECEIVE_ACCESSION: {
const {accession, error} = action.payload;
const receivedIndex = state.paged ? state.paged.content.findIndex((item) => item.uuid === accession.uuid) : -1;
const {apiCall} = action.payload;
const receivedIndex = state.paged ? state.paged.data.content.findIndex((item) => item.uuid === apiCall.data.uuid) : -1;
if (receivedIndex !== -1) {
return update(state, {
accession: { $set: accession },
accession: {$set: apiCall},
paged: {
data: {
content: {
[receivedIndex]: {$set: accession},
[receivedIndex]: {$set: apiCall.data},
},
},
},
accessionError: {$set: error},
});
} else {
return update(state, {
accession: { $set: accession},
accession: {$set: apiCall},
paged: {$set: null},
accessionError: {$set: error},
});
}
}
case DASHBOARD_RECEIVE_ACCESSIONS: {
const { paged, error } = action.payload;
return update(state, {
paged: { $set: paged },
pagedError: { $set: error },
overview: {$set: null},
mapInfo: { $set: null },
});
}
case DASHBOARD_APPEND_ACCESSIONS: {
const {paged, error} = action.payload;
return !state.paged ? update(state, {
paged: {$set: paged},
pagedError: {$set: error},
}) :
update(state, {
const {apiCall: {loading, error, timestamp, data}} = action.payload;
return update(state, {
paged: {
content: {$push: paged.content},
number: {$set: paged.number},
last: {$set: paged.last},
$set: {
loading,
error,
timestamp,
data: FilteredPage.merge(state.paged && state.paged.data, data),
},
},
pagedError: {$set: error},
});
}
......
......@@ -2,7 +2,6 @@ import update from 'immutability-helper';
import { IReducerAction } from 'model/common.model';
import {
RECEIVE_ACCESSIONS,
RECEIVE_ACCESSION,
RECEIVE_ACCESSION_OVERVIEW,
APPEND_ACCESSIONS,
......@@ -17,22 +16,19 @@ import AccessionMapInfo from 'model/accession/AccessionMapInfo';
import AccessionOverview from 'model/accession/AccessionOverview';
import AccessionAuditLog from 'model/accession/AccessionAuditLog';
import MapLayer, { AVAILABLE_LAYERS } from 'model/genesys/MapTileLayer';
import ApiCall from 'model/ApiCall';
const INITIAL_STATE: {
accession: Accession;
auditLog: AccessionAuditLog,
accessionError: any;
paged: FilteredPage<Accession>;
pagedError: any;
overview: AccessionOverview;
mapInfo: AccessionMapInfo;
accession: ApiCall<Accession>;
auditLog: ApiCall<AccessionAuditLog>,
paged: ApiCall<FilteredPage<Accession>>;
overview: ApiCall<AccessionOverview>;
mapInfo: ApiCall<AccessionMapInfo>;
mapLayers: MapLayer[]
} = {
accession: null,
auditLog: null,
accessionError: null,
paged: null,
pagedError: null,
overview: null,
mapInfo: null,
mapLayers: AVAILABLE_LAYERS,
......@@ -43,81 +39,72 @@ function publicAccessions(state = INITIAL_STATE, action: IReducerAction) {
switch (action.type) {
case RECEIVE_ACCESSION: {
const {accession, error} = action.payload;
const receivedIndex = state.paged ? state.paged.content.findIndex((item) => item.uuid === accession.uuid) : -1;
const {apiCall} = action.payload;
const receivedIndex = state.paged && apiCall.data ? state.paged.data.content.findIndex((item) => item.uuid === apiCall.data.uuid) : -1;
if (receivedIndex !== -1) {
return update(state, {
accession: { $set: accession },
accession: { $set: apiCall },
auditLog: {$set: null},
paged: {
data: {
content: {
[receivedIndex]: {$set: accession},
[receivedIndex]: {$set: apiCall.data},
},
},
},
accessionError: {$set: error},
});
} else {
return update(state, {
accession: { $set: accession},
accession: { $set: apiCall},
auditLog: {$set: null},
paged: {$set: null},
accessionError: {$set: error},
});
}
}
case RECEIVE_ACCESSION_AUDIT_LOG: {
const {auditLog} = action.payload;
return update(state, {
auditLog: {$set: auditLog},
});
}
case RECEIVE_ACCESSIONS: {
const { paged, error } = action.payload;
const {apiCall} = action.payload;
return update(state, {
paged: { $set: paged },
pagedError: { $set: error },
overview: {$set: null},
mapInfo: { $set: null },
auditLog: { $set: apiCall },
});
}
case RECEIVE_ACCESSION_OVERVIEW: {
const { overview, error } = action.payload;
const { apiCall: { loading, error, timestamp, data } } = action.payload;
return update(state, {
overview: { $set: overview },
pagedError: { $set: error },
paged: {$set: null},
mapInfo: { $set: null },
overview: { $set: {
loading,
error,
timestamp,
data: data !== undefined ? data : state.overview && state.overview.data,
} },
// paged: { $set: null },
// mapInfo: { $set: null },
});
}
case APPEND_ACCESSIONS: {
const {paged, error} = action.payload;
return !state.paged ? update(state, {
paged: {$set: paged},
pagedError: {$set: error},
}) :
update(state, {
paged: {
content: {$push: paged.content},
number: {$set: paged.number},
last: {$set: paged.last},
},
pagedError: {$set: error},
const { apiCall: { loading, error, timestamp, data } } = action.payload;
return update(state, {
paged: { $set: {
loading,
error,
timestamp,
data: FilteredPage.merge(state.paged && state.paged.data, data),
} },
// mapInfo: { $set: null },
// overview: { $set: null },
});
}
case RECEIVE_ACCESSION_MAPINFO: {
const { mapInfo, error } = action.payload;
const { apiCall } = action.payload;
apiCall.data = apiCall.loading && state.mapInfo ? state.mapInfo.data : apiCall.data;
return update(state, {
mapInfo: { $set: mapInfo },
pagedError: { $set: error },
paged: {$set: null},
overview: {$set: null},
mapInfo: { $set: apiCall },
// paged: {$set: null},
// overview: {$set: null},
});
}
case RECEIVE_TILE_LAYER: {
......
......@@ -13,7 +13,6 @@ import Accession from 'model/accession/Accession';
import BrowsePageTemplate, { IBrowsePageProps } from 'ui/pages/_base/BrowsePage';
import PageLayout, { PageContents } from 'ui/layout/PageLayout';
import ContentHeader from 'ui/common/heading/ContentHeader';
import Loading from 'ui/common/Loading';
import PagedLoader from 'ui/common/PagedLoader';
import PrettyFilters from 'ui/common/filter/PrettyFilters';
import AccessionCard from 'accessions/ui/c/AccessionCard';
......@@ -22,6 +21,7 @@ import AccessionFilters from './c/Filters';
import ButtonBar from 'ui/common/buttons/ButtonBar';
import DownloadDialog, { DOWNLOAD_LIMIT } from 'ui/common/download-dialog';
import PageTitle from 'ui/common/PageTitle';
import Loading from 'ui/common/Loading';
class BrowsePage extends BrowsePageTemplate<Accession> {
......@@ -42,7 +42,7 @@ class BrowsePage extends BrowsePageTemplate<Accession> {
}
public render() {
const { paged, loadMoreData, filterCode, currentTab, t} = this.props;
const { paged, loadMoreData, filterCode, currentTab, loading, t} = this.props;
const slug: string = this.state.authenticated ? 'download-authenticated' : 'download-anonymous';
const renderAccession = (s: Accession, index: number) => {
return <AccessionCard key={ s.uuid } index={ index } accession={ s } />;
......@@ -78,7 +78,6 @@ class BrowsePage extends BrowsePageTemplate<Accession> {
<Tab name="map" to={ `/a/map/${filterCode || '' }` }>{ t('accessions.tab.map') }</Tab>
</Tabs>
<PrettyFilters
prefix="accessions"
filterObj={ paged && paged.filter || {} }
......@@ -87,14 +86,13 @@ class BrowsePage extends BrowsePageTemplate<Accession> {
amount={ paged && paged.totalElements }
/>
<PageContents className="pt-1rem container-spacing-horizontal">
{ !