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

Updated to Requests API v1

- Moved pages to ui/pages/admin
parent 333fc252
......@@ -235,6 +235,10 @@
"type": {
"in": "Individual",
"or": "Organizational"
},
"purposeType": {
"0": "Other (please elaborate in Notes field)",
"1": "Research for food and agriculture"
}
}
}
......@@ -9,10 +9,7 @@ import FaoInstituteFilter from 'model/FaoInstituteFilter';
* Action list
*
* @param filter filter
* @param d d
* @param l l
* @param p p
* @param s s
* @param page pagination and sort options
*/
export const list = (filter: string | FaoInstituteFilter, page: IPageRequest) => (dispatch, getState): Promise<FilteredPage<FaoInstitute>> => {
const authorization = getState().login.access_token;
......@@ -29,5 +26,3 @@ export const get = (code: string) => (dispatch, getState): Promise<FaoInstitute>
const authorization = getState().login.access_token;
return InstituteService.get(authorization, code);
};
......@@ -2,18 +2,21 @@
import RequestService from 'service/genesys/RequestService';
import Page from 'model/Page';
import FilteredPage, { IPageRequest } from 'model/FilteredPage';
import MaterialRequest from 'model/MaterialRequest';
import MaterialRequestFilter from 'model/MaterialRequestFilter';
import MaterialSubRequest from 'model/MaterialSubRequest';
import MaterialSubRequestFilter from 'model/MaterialSubRequestFilter';
/**
* Action listRequests
* Action list
*
* @param page page
* @param filter filter
* @param page pagination and sort options
*/
export const listRequests = (page?: number) => (dispatch, getState): Promise<Page<MaterialRequest>> => {
export const listRequests = (filter: string | MaterialRequestFilter, page: IPageRequest) => (dispatch, getState): Promise<FilteredPage<MaterialRequest>> => {
const authorization = getState().login.access_token;
return RequestService.listRequests(authorization, page);
return RequestService.list(authorization, filter, page);
};
/**
......@@ -27,23 +30,23 @@ export const getRequest = (uuid: string) => (dispatch, getState): Promise<Materi
};
/**
* Action reconfirmRequest
* Action sendValidationEmail
*
* @param uuid uuid
*/
export const reconfirmRequest = (uuid: string) => (dispatch, getState): Promise<MaterialRequest> => {
export const sendValidationEmail = (uuid: string) => (dispatch, getState): Promise<MaterialRequest> => {
const authorization = getState().login.access_token;
return RequestService.reconfirmRequest(authorization, uuid);
return RequestService.sendValidationEmail(authorization, uuid);
};
/**
* Action updatePid
* Action recheckPid
*
* @param uuid uuid
*/
export const updatePid = (uuid: string) => (dispatch, getState): Promise<MaterialRequest> => {
export const recheckPid = (uuid: string) => (dispatch, getState): Promise<MaterialRequest> => {
const authorization = getState().login.access_token;
return RequestService.updatePid(authorization, uuid);
return RequestService.recheckPid(authorization, uuid);
};
/**
......@@ -60,11 +63,12 @@ export const validateRequest = (uuid: string) => (dispatch, getState): Promise<M
* Action listInstituteRequests
*
* @param instCode instCode
* @param page page
* @param filter filter
* @param page pagination and sort options
*/
export const listInstituteRequests = (instCode: string, page?: number) => (dispatch, getState): Promise<any> => {
export const listInstituteRequests = (instCode: string, filter: string | MaterialSubRequestFilter, page: IPageRequest) => (dispatch, getState): Promise<FilteredPage<MaterialSubRequest>> => {
const authorization = getState().login.access_token;
return RequestService.listInstituteRequests(authorization, instCode, page);
return RequestService.listInstituteRequests(authorization, instCode, filter, page);
};
/**
......@@ -73,7 +77,7 @@ export const listInstituteRequests = (instCode: string, page?: number) => (dispa
* @param instCode instCode
* @param uuid uuid
*/
export const getInstituteRequest = (instCode: string, uuid: string) => (dispatch, getState): Promise<any> => {
export const getInstituteRequest = (instCode: string, uuid: string) => (dispatch, getState): Promise<MaterialSubRequest> => {
const authorization = getState().login.access_token;
return RequestService.getInstituteRequest(authorization, instCode, uuid);
};
import * as _ from 'lodash';
import {getRequest, listRequests, reconfirmRequest, updatePid, validateRequest} from 'actions/genesys/requestService';
import {getRequest, listRequests, sendValidationEmail, recheckPid, validateRequest} from 'actions/genesys/requestService';
// constants
import {RECEIVE_MATERIAL_REQUEST, RECEIVE_MATERIAL_REQUESTS} from 'constants/requests';
// models
import MaterialRequest from 'model/MaterialRequest';
import Page from 'model/Page';
import FilteredPage, {IPageRequest} from 'model/FilteredPage';
const receiveRequests = (paged: Page<MaterialRequest>, error = null) => ({
const receiveRequests = (paged: FilteredPage<MaterialRequest>, error = null) => ({
type: RECEIVE_MATERIAL_REQUESTS,
payload: { paged, error },
});
......@@ -46,8 +46,10 @@ const refreshRequest = (request: MaterialRequest) => (dispatch, getState) => {
}
};
export const listMaterialRequests = (page: number) => (dispatch) => {
return dispatch(listRequests(page))
export { listRequests as listMaterialRequestsPromise };
export const listMaterialRequests = (page: IPageRequest) => (dispatch) => {
return dispatch(listRequests(null, page))
.then((page) => {
dispatch(receiveRequests(page));
})
......@@ -66,8 +68,8 @@ export const loadMaterialRequest = (uuid: string) => (dispatch) => {
});
};
export const updatePidAction = (uuid: string) => (dispatch) => {
return dispatch(updatePid(uuid))
export const recheckPidAction = (uuid: string) => (dispatch) => {
return dispatch(recheckPid(uuid))
.then((request) => {
dispatch(receiveRequest(request));
dispatch(refreshRequestPID(request));
......@@ -89,8 +91,8 @@ export const validateRequestAction = (uuid: string) => (dispatch) => {
});
};
export const reconfirmRequestAction = (uuid: string) => (dispatch) => {
return dispatch(reconfirmRequest(uuid))
export const sendValidationEmailAction = (uuid: string) => (dispatch) => {
return dispatch(sendValidationEmail(uuid))
.then((request) => {
dispatch(receiveRequest(request));
dispatch(refreshRequest(request));
......
......@@ -15,10 +15,14 @@ class MaterialRequest {
public lastReminderDate: Date;
public pid: string;
public state: number;
public subRequests: MaterialSubRequest[];
public subrequests: MaterialSubRequest[];
public uuid: string;
public version: number;
public static DEFAULT_SORT = {
property: 'lastModifiedDate',
direction: 'DESC',
};
}
......
import DateFilter from 'model/DateFilter';
import StringFilter from 'model/StringFilter';
/*
* Defined in Swagger as '#/definitions/MaterialRequestFilter'
*/
class MaterialRequestFilter {
public active: boolean;
public createdBy: number[];
public createdDate: DateFilter;
public email: StringFilter;
public id: number[];
public lastModifiedBy: number[];
public lastModifiedDate: DateFilter;
public pid: string[];
public state: number[];
public uuid: string[];
public version: number[];
}
export default MaterialRequestFilter;
......@@ -5,7 +5,7 @@ import MaterialRequest from 'model/MaterialRequest';
*/
class MaterialSubRequest {
public active: boolean;
public body: string;
public body: any;
public createdBy: number;
public createdDate: Date;
public id: number;
......@@ -19,6 +19,10 @@ class MaterialSubRequest {
public uuid: string;
public version: number;
public static DEFAULT_SORT = {
property: 'lastModifiedDate',
direction: 'DESC',
};
}
......
import DateFilter from 'model/DateFilter';
import StringFilter from 'model/StringFilter';
/*
* Defined in Swagger as '#/definitions/MaterialSubRequestFilter'
*/
class MaterialSubRequestFilter {
public active: boolean;
public createdBy: number[];
public createdDate: DateFilter;
public email: StringFilter;
public id: number[];
public lastModifiedBy: number[];
public lastModifiedDate: DateFilter;
public pid: string[];
public state: number[];
public uuid: string[];
public version: number[];
}
export default MaterialSubRequestFilter;
......@@ -2,14 +2,14 @@ import update from 'immutability-helper';
import { IReducerAction } from 'model/common.model';
import MaterialRequest from 'model/MaterialRequest';
import Page from 'model/Page';
import FilteredPage from 'model/FilteredPage';
import {RECEIVE_MATERIAL_REQUEST, RECEIVE_MATERIAL_REQUESTS} from 'constants/requests';
const INITIAL_STATE: {
request: Request;
requestError: any;
paged: Page<MaterialRequest>;
paged: FilteredPage<MaterialRequest>;
pagedError: any;
} = {
request: null,
......
......@@ -4,16 +4,19 @@ import * as QueryString from 'query-string';
import authenticatedRequest from 'utilities/requestUtils';
import { API_ROOT } from 'constants/apiURLS';
import Page from 'model/Page';
import FilteredPage, { IPageRequest } from 'model/FilteredPage';
import MaterialRequest from 'model/MaterialRequest';
const URL_LIST_REQUESTS = `${API_ROOT}/api/v0/requests`;
const URL_GET_REQUEST = UrlTemplate.parse(`${API_ROOT}/api/v0/requests/r/{uuid}`);
const URL_RECONFIRM_REQUEST = UrlTemplate.parse(`${API_ROOT}/api/v0/requests/r/{uuid}/reconfirm`);
const URL_UPDATE_PID = UrlTemplate.parse(`${API_ROOT}/api/v0/requests/r/{uuid}/update-pid`);
const URL_VALIDATE_REQUEST = UrlTemplate.parse(`${API_ROOT}/api/v0/requests/r/{uuid}/validate`);
const URL_LIST_INSTITUTE_REQUESTS = UrlTemplate.parse(`${API_ROOT}/api/v0/requests/{instCode}`);
const URL_GET_INSTITUTE_REQUEST = UrlTemplate.parse(`${API_ROOT}/api/v0/requests/{instCode}/r/{uuid}`);
import MaterialRequestFilter from 'model/MaterialRequestFilter';
import MaterialSubRequest from 'model/MaterialSubRequest';
import MaterialSubRequestFilter from 'model/MaterialSubRequestFilter';
const URL_GET_REQUEST = UrlTemplate.parse(`${API_ROOT}/api/v1/requests/r/{uuid}`);
const URL_SEND_VALIDATION_EMAIL = UrlTemplate.parse(`${API_ROOT}/api/v1/requests/r/{uuid}/reconfirm`);
const URL_RECHECK_PID = UrlTemplate.parse(`${API_ROOT}/api/v1/requests/r/{uuid}/update-pid`);
const URL_VALIDATE_REQUEST = UrlTemplate.parse(`${API_ROOT}/api/v1/requests/r/{uuid}/validate`);
const URL_LIST_INSTITUTE_REQUESTS = UrlTemplate.parse(`${API_ROOT}/api/v1/requests/{instCode}`);
const URL_GET_INSTITUTE_REQUEST = UrlTemplate.parse(`${API_ROOT}/api/v1/requests/{instCode}/r/{uuid}`);
const URL_LIST = `${API_ROOT}/api/v1/requests/list`;
/*
* Defined in Swagger as 'request'
......@@ -21,29 +24,7 @@ const URL_GET_INSTITUTE_REQUEST = UrlTemplate.parse(`${API_ROOT}/api/v0/requests
class RequestService {
/**
* listRequests at /api/v0/requests
*
* @param authToken Authorization token
* @param page page
*/
public static listRequests(authToken: string, page?: number): Promise<Page<MaterialRequest>> {
const qs = QueryString.stringify({
page: page || undefined,
}, {});
const apiUrl = URL_LIST_REQUESTS + (qs ? `?${qs}` : '');
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return authenticatedRequest(authToken, {
url: apiUrl,
method: 'GET',
...content,
}).then(({ data }) => data as any);
}
/**
* getRequest at /api/v0/requests/r/{uuid}
* getRequest at /api/v1/requests/r/{uuid}
*
* @param authToken Authorization token
* @param uuid uuid
......@@ -62,14 +43,14 @@ class RequestService {
}
/**
* reconfirmRequest at /api/v0/requests/r/{uuid}/reconfirm
* sendValidationEmail at /api/v1/requests/r/{uuid}/reconfirm
*
* @param authToken Authorization token
* @param uuid uuid
*/
public static reconfirmRequest(authToken: string, uuid: string): Promise<MaterialRequest> {
public static sendValidationEmail(authToken: string, uuid: string): Promise<MaterialRequest> {
const apiUrl = URL_RECONFIRM_REQUEST.expand({uuid});
const apiUrl = URL_SEND_VALIDATION_EMAIL.expand({uuid});
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
......@@ -81,14 +62,14 @@ class RequestService {
}
/**
* updatePid at /api/v0/requests/r/{uuid}/update-pid
* recheckPid at /api/v1/requests/r/{uuid}/update-pid
*
* @param authToken Authorization token
* @param uuid uuid
*/
public static updatePid(authToken: string, uuid: string): Promise<MaterialRequest> {
public static recheckPid(authToken: string, uuid: string): Promise<MaterialRequest> {
const apiUrl = URL_UPDATE_PID.expand({uuid});
const apiUrl = URL_RECHECK_PID.expand({uuid});
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
......@@ -100,7 +81,7 @@ class RequestService {
}
/**
* validateRequest at /api/v0/requests/r/{uuid}/validate
* validateRequest at /api/v1/requests/r/{uuid}/validate
*
* @param authToken Authorization token
* @param uuid uuid
......@@ -119,36 +100,42 @@ class RequestService {
}
/**
* listInstituteRequests at /api/v0/requests/{instCode}
* listInstituteRequests at /api/v1/requests/{instCode}
*
* @param authToken Authorization token
* @param instCode instCode
* @param page page
* @param filter filter
* @param page pagination and sort options
*/
public static listInstituteRequests(authToken: string, instCode: string, page?: number): Promise<any> {
public static listInstituteRequests(authToken: string, instCode: string, filter: string | MaterialSubRequestFilter, page: IPageRequest): Promise<FilteredPage<MaterialSubRequest>> {
const qs = QueryString.stringify({
page: page || undefined,
f: typeof filter === 'string' ? filter : undefined,
p: page.page || undefined,
l: page.size || 100,
d: page.direction && page.direction.length && page.direction || MaterialSubRequest.DEFAULT_SORT.direction,
s: page.properties || MaterialSubRequest.DEFAULT_SORT.property,
}, {});
const apiUrl = URL_LIST_INSTITUTE_REQUESTS.expand({instCode}) + (qs ? `?${qs}` : '');
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
const content = { data: typeof filter === 'string' ? null : { ...filter } };
return authenticatedRequest(authToken, {
url: apiUrl,
method: 'GET',
method: 'POST',
headers: {'Content-Type': 'application/json'},
...content,
}).then(({ data }) => data as any);
}).then(({ data }) => data as FilteredPage<MaterialSubRequest>);
}
/**
* getInstituteRequest at /api/v0/requests/{instCode}/r/{uuid}
* getInstituteRequest at /api/v1/requests/{instCode}/r/{uuid}
*
* @param authToken Authorization token
* @param instCode instCode
* @param uuid uuid
*/
public static getInstituteRequest(authToken: string, instCode: string, uuid: string): Promise<any> {
public static getInstituteRequest(authToken: string, instCode: string, uuid: string): Promise<MaterialSubRequest> {
const apiUrl = URL_GET_INSTITUTE_REQUEST.expand({instCode, uuid});
// console.log(`Fetching from ${apiUrl}`);
......@@ -158,7 +145,35 @@ class RequestService {
url: apiUrl,
method: 'GET',
...content,
}).then(({ data }) => data as any);
}).then(({ data }) => data as MaterialSubRequest);
}
/**
* list at /api/v1/requests/list
*
* @param authToken Authorization token
* @param filter filter
* @param page pagination and sort options
*/
public static list(authToken: string, filter: string | MaterialRequestFilter, page: IPageRequest): Promise<FilteredPage<MaterialRequest>> {
const qs = QueryString.stringify({
f: typeof filter === 'string' ? filter : undefined,
p: page.page || undefined,
l: page.size || 100,
d: page.direction && page.direction.length && page.direction || MaterialRequest.DEFAULT_SORT.direction,
s: page.properties || MaterialRequest.DEFAULT_SORT.property,
}, {});
const apiUrl = URL_LIST + (qs ? `?${qs}` : '');
// console.log(`Fetching from ${apiUrl}`);
const content = { data: typeof filter === 'string' ? null : { ...filter } };
return authenticatedRequest(authToken, {
url: apiUrl,
method: 'POST',
headers: {'Content-Type': 'application/json'},
...content,
}).then(({ data }) => data as FilteredPage<MaterialRequest>);
}
......
......@@ -4,6 +4,7 @@ import {withStyles} from '@material-ui/core/styles';
import MaterialRequest from 'model/MaterialRequest';
import {RequestLink} from 'ui/genesys/Links';
import Card, {CardContent} from 'ui/common/Card';
import PrettyDate from 'ui/common/time/PrettyDate';
const styles = () => ({
firstRow: {
......@@ -13,7 +14,11 @@ const styles = () => ({
const RequestCard = ({request, classes, index, ...other}: { request: MaterialRequest, classes: any, index?: number } & React.ClassAttributes<any>) => {
const requestStates = [{label: 'NOT VALIDATED', color: 'orange'}, {label: 'VALIDATED', color: 'green'}, {label: 'DISPATCHED', color: '#06aced'}];
if (! request) {
console.log('Null request for RequestCard');
return null;
}
const requestStates = [{label: 'NOT VALIDATED', color: 'orange'}, {label: 'VALIDATED', color: '#06aced'}, {label: 'DISPATCHED', color: 'green'}];
return (
<Card>
......@@ -22,20 +27,20 @@ const RequestCard = ({request, classes, index, ...other}: { request: MaterialReq
<b>
{ index !== undefined && `${index + 1}. ` }
<RequestLink to={ request }>
{ `Request from ${ request.email }` }
{ request.email }
</RequestLink>
</b>
{ request.state !== undefined &&
<span>
<b></b>
<b style={ {color: requestStates[request.state].color} }> { ` ${requestStates[request.state].label}` } </b>
</span>
}
<b></b>
<PrettyDate value={ request.createdDate }/>
</div>
<div>
<em>
{ `Notes: ${request.body.requestInfo.notes}` }
</em>
{ request.state !== undefined &&
<span>
<b style={ {color: requestStates[request.state].color} }> { ` ${requestStates[request.state].label}` } </b>
<b></b>
</span>
}
{ request.body.accessionIds.length } accessions
</div>
</CardContent>
</Card>
......
......@@ -15,6 +15,7 @@ import { PageContents } from 'ui/layout/PageLayout';
import Loading from 'ui/common/Loading';
import PagedLoader from 'ui/common/PagedLoader';
import RequestCard from 'ui/genesys/materialRequest/RequestCard';
import ContentHeaderWithButton from 'ui/common/heading/ContentHeaderWithButton';
class BrowsePage extends BrowsePageTemplate<any> {
......@@ -34,15 +35,18 @@ class BrowsePage extends BrowsePageTemplate<any> {
};
return (
<div>
<ContentHeaderWithButton title={ `${paged ? paged.totalElements : '-'} requests for PGR material` } />
<PageContents>
{ ! paged ? <Loading /> :
<PagedLoader
paged={ paged }
loadPage={ this.loadNextPage }
roughItemHeight={ 45 }
roughItemHeight={ 80 }
itemRenderer={ renderRequest } />
}
</PageContents>
</div>
);
}
}
......
......@@ -4,7 +4,7 @@ import {bindActionCreators} from 'redux';
import {translate} from 'react-i18next';
// Actions
import {loadMaterialRequest, reconfirmRequestAction, updatePidAction, validateRequestAction} from 'actions/requests';
import {loadMaterialRequest, sendValidationEmailAction, recheckPidAction, validateRequestAction} from 'actions/requests';
// Models
import MaterialRequest from 'model/MaterialRequest';
......@@ -17,6 +17,7 @@ import Loading from 'ui/common/Loading';
import PrettyDate from 'ui/common/time/PrettyDate';
import ActionButton from 'ui/common/buttons/ActionButton';
import BackButton from 'ui/common/buttons/BackButton';
import Markdown from 'ui/catalog/markdown';
interface IDisplayPageProps extends React.ClassAttributes<any> {
t: any;
......@@ -24,9 +25,9 @@ interface IDisplayPageProps extends React.ClassAttributes<any> {
request: MaterialRequest;
error: any;
loadMaterialRequest: any;
updatePid: any;
recheckPid: any;
validateRequest: any;
reconfirmRequest: any;
sendValidationEmail: any;
}
class DisplayPage extends React.Component<IDisplayPageProps, any> {
......@@ -44,7 +45,7 @@ class DisplayPage extends React.Component<IDisplayPageProps, any> {
public render() {
const {request, t, updatePid, reconfirmRequest, validateRequest} = this.props;
const {request, t, recheckPid, sendValidationEmail, validateRequest} = this.props;
return request === null ? (<Loading/>) : (
......@@ -53,32 +54,33 @@ class DisplayPage extends React.Component<IDisplayPageProps, any> {
title={ `Request from ${request.email}` }
buttons={
<div>
<ActionButton title="Update PID" action={ () => updatePid(request.uuid) }/>
<ActionButton title="Reconfirm Request" action={ () => reconfirmRequest(request.uuid) }/>
<ActionButton title="Send validation email" action={ () => sendValidationEmail(request.uuid) }/>
<ActionButton title="Validate Request" action={ () => validateRequest(request.uuid) }/>
<ActionButton title="Recheck PID" action={ () => recheckPid(request.uuid) }/>
<BackButton defaultTarget="/admin/requests"/>
</div>
}
/>
{ request.body &&
<PageContents>
<MainSection title="Main information">
<MainSection title="Request information">
<Properties>
<PropertiesItem title="Requested accession ids">{ request.body.accessionIds.reduce((id, acc) => `${acc}, ${id}`) }</PropertiesItem>
<PropertiesItem title="Email">{ request.email }</PropertiesItem>
<PropertiesItem title="State">{ t(`request.state.${request.state}`) }</PropertiesItem></