Commit 04876416 authored by Matija Obreza's avatar Matija Obreza

Merge branch '746-embedded-genesys-ui' into 'master'

Embedded Genesys UI

Closes #752 and #746

See merge request genesys-pgr/genesys-ui!725
parents 7810f710 b1c67744
......@@ -10,15 +10,19 @@
"accession"
],
"license": "Apache-2.0",
"homepage": "https://gitlab.croptrust.org/genesys-pgr/genesys-ui.git",
"homepage": "https://gitlab.croptrust.org/genesys-pgr/genesys-ui",
"repository": {
"type": "git",
"url": "https://gitlab.croptrust.org/genesys-pgr/genesys-ui.git"
},
"author": {
"name": "Genesys Helpdesk",
"email": "helpdesk@genesys-pgr.org",
"url": "https://www.genesys-pgr.org"
},
"bugs": {
"url": "https://gitlab.croptrust.org/genesys-pgr/genesys-ui/issues"
},
"author": "Genesys Team <helpdesk@genesys-pgr.org>",
"contributors": [
"Matija Obreza <matija.obreza@croptrust.org>"
],
......
{
"name": "@genesys/client",
"version": "1.0.0",
"private": true,
"license": "Apache-2.0",
"scripts": {
"clean": "rimraf lib",
......
......@@ -25,6 +25,13 @@ class AccessionDetails {
taxa: { id: [ 'details.taxonomy' ] },
grin: { id: [ 'details.taxonomy.grinTaxonomySpecies', 'details.taxonomy.currentTaxonomySpecies' ] },
};
public static DEREFERENCESLIST = {
crop: { id: [ 'crop' ] },
ctry: { id: [ 'countryOfOrigin', 'institute.country' ] },
inst: { id: [ 'institute' ] },
taxa: { id: [ 'taxonomy' ] },
grin: { id: [ 'taxonomy.grinTaxonomySpecies', 'taxonomy.currentTaxonomySpecies' ] },
};
}
export default AccessionDetails;
import * as UrlTemplate from 'url-template';
import { axiosBackend, apiLanguage } from '@genesys/client/utilities/requestUtils';
import { apiLanguage } from '@genesys/client/utilities/requestUtils';
import Crop from '@genesys/client/model/genesys/Crop';
import CropDetails from '@genesys/client/model/genesys/CropDetails';
import Article from '@genesys/client/model/cms/Article';
import { AxiosInstance } from 'axios';
const URL_LIST_CROPS = UrlTemplate.parse(`/api/v1/crops`);
const URL_SAVE_CROP = `/api/v1/crops/save`;
......@@ -14,19 +15,24 @@ const URL_RELINK_ACCESSIONS = UrlTemplate.parse(`/api/v1/crops/{shortName}/relin
const URL_UPDATE_CROP_BLURB = UrlTemplate.parse(`/api/v1/crops/{shortName}/blurb`);
export class CropService {
private _axios: AxiosInstance;
public constructor(axios: AxiosInstance) {
this._axios = axios;
}
/**
* listCrops at /api/v1/crops
*
* @param authToken Authorization token
*/
public static listCrops(xhrConfig?): Promise<Crop[]> {
public listCrops = (xhrConfig?): Promise<Crop[]> => {
const apiUrl = URL_LIST_CROPS.expand();
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return axiosBackend.request({
return this._axios.request({
...xhrConfig,
url: apiUrl,
method: 'GET',
......@@ -40,13 +46,13 @@ export class CropService {
* @param authToken Authorization token
* @param cropJson cropJson
*/
public static saveCrop(cropJson: Crop, xhrConfig?): Promise<Crop> {
public saveCrop = (cropJson: Crop, xhrConfig?): Promise<Crop> => {
const apiUrl = URL_SAVE_CROP;
// console.log(`Fetching from ${apiUrl}`);
const content = { data: cropJson };
return axiosBackend.request({
return this._axios.request({
...xhrConfig,
url: apiUrl,
method: 'PUT',
......@@ -60,13 +66,13 @@ export class CropService {
*
* @param shortName shortName
*/
public static getCrop(shortName: string, xhrConfig?): Promise<Crop> {
public getCrop = (shortName: string, xhrConfig?): Promise<Crop> => {
const apiUrl = URL_GET_CROP.expand({shortName});
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return axiosBackend({
return this._axios({
...xhrConfig,
url: apiUrl,
method: 'GET',
......@@ -80,13 +86,13 @@ export class CropService {
* @param authToken Authorization token
* @param shortName shortName
*/
public static deleteCrop(shortName: string, xhrConfig?): Promise<Crop> {
public deleteCrop = (shortName: string, xhrConfig?): Promise<Crop> => {
const apiUrl = URL_DELETE_CROP.expand({shortName});
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return axiosBackend.request({
return this._axios.request({
...xhrConfig,
url: apiUrl,
method: 'DELETE',
......@@ -99,13 +105,13 @@ export class CropService {
*
* @param shortName shortName
*/
public static getCropDetails(shortName: string, lang: string, xhrConfig?): Promise<CropDetails> {
public getCropDetails = (shortName: string, lang: string, xhrConfig?): Promise<CropDetails> => {
const apiUrl = apiLanguage(lang) + URL_GET_CROP_DETAILS.expand({ shortName });
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return axiosBackend({
return this._axios({
...xhrConfig,
url: apiUrl,
method: 'GET',
......@@ -118,13 +124,13 @@ export class CropService {
*
* @param shortName shortName
*/
public static relinkAccessions(shortName: string, xhrConfig?): Promise<boolean> {
public relinkAccessions = (shortName: string, xhrConfig?): Promise<boolean> => {
const apiUrl = URL_RELINK_ACCESSIONS.expand({shortName});
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return axiosBackend.request({
return this._axios.request({
...xhrConfig,
url: apiUrl,
method: 'POST',
......@@ -137,13 +143,13 @@ export class CropService {
* @param article Article
* @param shortName shortName
*/
public static updateBlurb(article: Article, shortName: string, xhrConfig?): Promise<Article> {
public updateBlurb = (article: Article, shortName: string, xhrConfig?): Promise<Article> => {
const apiUrl = URL_UPDATE_CROP_BLURB.expand({shortName});
const content = { data: article };
return axiosBackend.request({
return this._axios.request({
...xhrConfig,
url: apiUrl,
method: 'POST',
......
import * as QueryString from 'query-string';
import { axiosBackend } from '@genesys/client/utilities/requestUtils';
import FaoInstitute from '@genesys/client/model/genesys/FaoInstitute';
import { dereferenceReferences2 } from '@genesys/client/utilities/';
const URL_AUTOCOMPLETE = `/api/v1/wiews/autocomplete`;
/*
* Defined in Swagger as 'institute'
*/
class InstituteService {
/**
* autocomplete at /api/v1/wiews/autocomplete
*
* @param text text
*/
public static autocomplete(text: string, xhrConfig?): Promise<FaoInstitute[]> {
const qs = QueryString.stringify({
text: text || undefined,
}, {});
const apiUrl = URL_AUTOCOMPLETE + (qs ? `?${qs}` : '');
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return axiosBackend.request({
...xhrConfig,
url: apiUrl,
method: 'GET',
...content,
}).then(({ data }) => data as FaoInstitute[])
.then((data) => {
dereferenceReferences2(data, FaoInstitute.DEREFERENCES);
return data;
});
}
}
export default InstituteService;
import { axiosBackend } from '@genesys/client/utilities/requestUtils';
import * as UrlTemplate from 'url-template';
// import FormData from 'form-data'; // it's in the browser
import { AxiosInstance } from 'axios';
import FormData from 'form-data';
const LOGIN_URL = `/oauth/token`;
const URL_LOGOUT = `/api/v1/me/logout`;
......@@ -13,24 +13,31 @@ const URL_UPDATE_PASSWORD = UrlTemplate.parse(`/api/v1/me/{tokenUuid}/pwdreset`)
export const VERIFY_GOOGLE_TOKEN_URL = `/api/google/verify-token`;
export class LoginService {
private _axios: AxiosInstance;
public static loginApp(clientId?: string, clientSecret?: string, baseURL?: string) {
return axiosBackend.post(LOGIN_URL, null, {
public constructor(axios: AxiosInstance) {
this._axios = axios;
}
public loginApp = (clientId?: string, clientSecret?: string, baseURL?: string) => {
const form = new FormData();
form.append('grant_type', 'client_credentials');
form.append('client_id', clientId || process.env.CLIENT_ID);
form.append('client_secret', clientSecret || process.env.CLIENT_SECRET || undefined);
const headers = form.getHeaders ? form.getHeaders() : {}; // In the browser FormData is window.FormData and getHeaders is undefined
return this._axios.post(LOGIN_URL, form, {
baseURL: baseURL || '/proxy',
params: {
grant_type: 'client_credentials',
client_id: clientId || process.env.CLIENT_ID,
client_secret: clientSecret || process.env.CLIENT_SECRET || undefined,
},
headers: { ...headers },
})
.then(({ data }) => data);
}
public static login(username: string, password: string, xhrConfig?) {
public login = (username: string, password: string, xhrConfig?) => {
const form = new FormData();
form.append('username', username);
form.append('password', password);
return axiosBackend.post(LOGIN_URL, form, {
return this._axios.post(LOGIN_URL, form, {
...xhrConfig,
baseURL: '/proxy',
// headers: {
......@@ -48,13 +55,13 @@ export class LoginService {
*
* @param authToken Authorization token
*/
public static logout(authToken: string, xhrConfig?): Promise<any> {
public logout = (authToken: string, xhrConfig?): Promise<any> => {
const apiUrl = URL_LOGOUT;
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return axiosBackend.request({
return this._axios.request({
...xhrConfig,
url: apiUrl,
method: 'POST',
......@@ -66,21 +73,21 @@ export class LoginService {
* @param clientId our OAuth Client ID
* @param tokenId Token returned by Google Auth
*/
public static verifyGoogleToken(clientId: string, tokenId, xhrConfig?) {
public verifyGoogleToken = (clientId: string, tokenId, xhrConfig?) => {
const form = new FormData();
form.append('clientId', clientId);
form.append('tokenId', tokenId);
return axiosBackend.post(VERIFY_GOOGLE_TOKEN_URL, form, xhrConfig)
return this._axios.post(VERIFY_GOOGLE_TOKEN_URL, form, xhrConfig)
.then(({ data }) => data);
}
/**
*
*/
public static refreshAccessToken(refreshToken, xhrConfig?) {
public refreshAccessToken = (refreshToken, xhrConfig?) => {
return axiosBackend.post(LOGIN_URL, null, {
return this._axios.post(LOGIN_URL, null, {
...xhrConfig,
baseURL: '/proxy',
params: {
......@@ -99,13 +106,13 @@ export class LoginService {
* @param email email
* @param gRecaptchaResponse g-recaptcha-response
*/
public static resetPassword(email: string, gRecaptchaResponse?: string, xhrConfig?): Promise<boolean> {
public resetPassword = (email: string, gRecaptchaResponse?: string, xhrConfig?): Promise<boolean> => {
const form = new FormData();
form.append('email', email || undefined);
form.append('g-recaptcha-response', gRecaptchaResponse || undefined);
return axiosBackend.post(URL_RESET_PASSWORD, form, xhrConfig)
return this._axios.post(URL_RESET_PASSWORD, form, xhrConfig)
.then(({ data }) => data as boolean);
}
......@@ -115,12 +122,12 @@ export class LoginService {
* @param tokenUuid tokenUuid
* @param gRecaptchaResponse g-recaptcha-response
*/
public static cancelValidation(tokenUuid: string, gRecaptchaResponse?: string, xhrConfig?): Promise<boolean> {
public cancelValidation = (tokenUuid: string, gRecaptchaResponse?: string, xhrConfig?): Promise<boolean> => {
const form = new FormData();
form.append('g-recaptcha-response', gRecaptchaResponse || undefined);
return axiosBackend.post(URL_CANCEL_VALIDATION.expand({ tokenUuid }), form, xhrConfig)
return this._axios.post(URL_CANCEL_VALIDATION.expand({ tokenUuid }), form, xhrConfig)
.then(({ data }) => data as boolean);
}
......@@ -130,12 +137,12 @@ export class LoginService {
* @param tokenUuid tokenUuid
* @param gRecaptchaResponse g-recaptcha-response
*/
public static cancelPasswordReset(tokenUuid: string, gRecaptchaResponse?: string, xhrConfig?): Promise<boolean> {
public cancelPasswordReset = (tokenUuid: string, gRecaptchaResponse?: string, xhrConfig?): Promise<boolean> => {
const form = new FormData();
form.append('g-recaptcha-response', gRecaptchaResponse || undefined);
return axiosBackend.post(URL_CANCEL_PASSWORD_RESET.expand({ tokenUuid }), form, xhrConfig)
return this._axios.post(URL_CANCEL_PASSWORD_RESET.expand({ tokenUuid }), form, xhrConfig)
.then(({ data }) => data as boolean);
}
......@@ -148,14 +155,14 @@ export class LoginService {
* @param password password
* @param gRecaptchaResponse g-recaptcha-response
*/
public static updatePassword(tokenUuid: string, key: string, password: string, gRecaptchaResponse?: string, xhrConfig?): Promise<boolean> {
public updatePassword = (tokenUuid: string, key: string, password: string, gRecaptchaResponse?: string, xhrConfig?): Promise<boolean> => {
const form = new FormData();
form.append('key', key || undefined);
form.append('password', password || undefined);
form.append('g-recaptcha-response', gRecaptchaResponse || undefined);
return axiosBackend.post(URL_UPDATE_PASSWORD.expand({ tokenUuid }), form, xhrConfig)
return this._axios.post(URL_UPDATE_PASSWORD.expand({ tokenUuid }), form, xhrConfig)
.then(({ data }) => data as boolean);
}
}
import { axiosBackend } from '@genesys/client/utilities/requestUtils';
import * as UrlTemplate from 'url-template';
import Taxonomy from '@genesys/client/model/genesys/Taxonomy2';
......@@ -11,6 +10,7 @@ import { dereferenceReferences3 } from '@genesys/client/utilities/';
import TaxonomyExtraFilter from '@genesys/client/model/genesys/TaxonomyExtraFilter';
import TaxonomySpeciesFilter from '@genesys/client/model/genesys/TaxonomySpeciesFilter';
import TaxonomySpecies from '@genesys/client/model/genesys/TaxonomySpecies';
import { AxiosInstance } from 'axios';
const URL_LIST_TAXONOMIES = `/api/v1/taxonomy/`;
const URL_LIST = `/api/v1/taxonomy/list`;
......@@ -22,6 +22,11 @@ const URL_SET_GRIN_SPECIES = UrlTemplate.parse(`/api/v1/taxonomy/set-grin-specie
* Defined in Swagger as 'taxonomy'
*/
class TaxonomyService {
private _axios: AxiosInstance;
public constructor(axios: AxiosInstance) {
this._axios = axios;
}
/**
* list at /api/v1/taxonomy/list
......@@ -30,7 +35,7 @@ class TaxonomyService {
* @param page undefined
* @param xhrConfig additional xhr config
*/
public static list(filter: TaxonomyExtraFilter, page?: IPageRequest, xhrConfig?: any): Promise<FilteredPage<Taxonomy2Info>> {
public list = (filter: TaxonomyExtraFilter, page?: IPageRequest, xhrConfig?: any): Promise<FilteredPage<Taxonomy2Info>> => {
const qs = QueryString.stringify({
p: page.page || undefined,
......@@ -42,7 +47,7 @@ class TaxonomyService {
// console.log(`Fetching from ${apiUrl}`);
const content = { data: typeof filter === 'string' ? {} : { ...filter } };
return axiosBackend.request({
return this._axios.request({
...xhrConfig,
url: apiUrl,
method: 'POST',
......@@ -59,13 +64,13 @@ class TaxonomyService {
* @param taxonomyFilter taxonomyFilter
* @param xhrConfig additional xhr config
*/
public static listTaxonomies(taxonomyFilter: TaxonomyFilter, xhrConfig?: any): Promise<Taxonomy[]> {
public listTaxonomies = (taxonomyFilter: TaxonomyFilter, xhrConfig?: any): Promise<Taxonomy[]> => {
const apiUrl = URL_LIST_TAXONOMIES;
// console.log(`Fetching from ${apiUrl}`);
const content = { data: taxonomyFilter };
return axiosBackend.request({
return this._axios.request({
...xhrConfig,
url: apiUrl,
method: 'POST',
......@@ -80,7 +85,7 @@ class TaxonomyService {
* @param page undefined
* @param xhrConfig additional xhr config
*/
public static listGrinTaxonomies(filter: TaxonomySpeciesFilter, page?: IPageRequest, xhrConfig?: any): Promise<FilteredPage<TaxonomySpecies>> {
public listGrinTaxonomies = (filter: TaxonomySpeciesFilter, page?: IPageRequest, xhrConfig?: any): Promise<FilteredPage<TaxonomySpecies>> => {
const qs = QueryString.stringify({
p: page.page || undefined,
......@@ -92,7 +97,7 @@ class TaxonomyService {
// console.log(`Fetching from ${apiUrl}`);
const content = { data: filter };
return axiosBackend.request({
return this._axios.request({
...xhrConfig,
url: apiUrl,
method: 'POST',
......@@ -110,7 +115,7 @@ class TaxonomyService {
* @param customGrinSpeciesId customGrinSpeciesId
* @param xhrConfig additional xhr config
*/
public static setGrinSpecies(id: number, customGrinSpeciesId?: number, xhrConfig?: any): Promise<Taxonomy> {
public setGrinSpecies = (id: number, customGrinSpeciesId?: number, xhrConfig?: any): Promise<Taxonomy> => {
const apiUrl = URL_SET_GRIN_SPECIES.expand({ id });
// console.log(`Fetching from ${apiUrl}`);
......@@ -119,7 +124,7 @@ class TaxonomyService {
data.append('customGrinSpeciesId', customGrinSpeciesId.toString());
}
return axiosBackend.request({
return this._axios.request({
...xhrConfig,
url: apiUrl,
method: 'POST',
......@@ -133,13 +138,13 @@ class TaxonomyService {
* @param id id
* @param xhrConfig additional xhr config
*/
public static get(id: number, xhrConfig?: any): Promise<Taxonomy> {
public get = (id: number, xhrConfig?: any): Promise<Taxonomy> => {
const apiUrl = URL_GET.expand({ id });
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return axiosBackend.request({
return this._axios.request({
...xhrConfig,
url: apiUrl,
method: 'GET',
......
import { log } from '@genesys/client/utilities/debug';
import { axiosBackend } from '@genesys/client/utilities/requestUtils';
import * as UrlTemplate from 'url-template';
import { User } from '@genesys/client/model/user/User';
import * as QueryString from 'query-string';
import UserFilter from '@genesys/client/model/UserFilter';
import FilteredPage, {IPageRequest} from '@genesys/client/model/FilteredPage';
import { AxiosInstance } from 'axios';
const REGISTER_URL = `/api/v1/user/register`;
const GET_USER_PROFILE_URL = `/api/v1/me/profile`;
......@@ -23,12 +23,17 @@ const URL_UPDATE_USER = `/api/v1/user/user`;
const URL_EXTEND_ACCOUNT = UrlTemplate.parse('/api/v1/user/u/{uuid}/extend');
export class UserService {
private _axios: AxiosInstance;
public constructor(axios: AxiosInstance) {
this._axios = axios;
}
// Get current user profile
public static getProfile(xhrConfig?): Promise<User> {
public getProfile = (xhrConfig?): Promise<User> => {
log('Loading current user profile.');
return axiosBackend.request({
return this._axios.request({
...xhrConfig,
url: `${GET_USER_PROFILE_URL}`,
method: 'GET',
......@@ -36,14 +41,14 @@ export class UserService {
}
// Change user password
public static changePassword(newPassword: string, oldPassword: string, xhrConfig?): Promise<any> {
public changePassword = (newPassword: string, oldPassword: string, xhrConfig?): Promise<any> => {
log('Changing user password');
const data = new FormData();
data.append('old', oldPassword);
data.append('new', newPassword);
return axiosBackend.request({
return this._axios.request({
...xhrConfig,
url: `${CHANGE_USER_PASSWORD_URL}`,
method: 'POST',
......@@ -51,13 +56,13 @@ export class UserService {
});
}
public static register(email: string, password: string, fullName: string, captcha: any, xhrConfig?) {
public register = (email: string, password: string, fullName: string, captcha: any, xhrConfig?) => {
const form = new FormData();
form.append('email', email);
form.append('pass', password);
form.append('fullName', fullName);
form.append('g-recaptcha-response', captcha);
return axiosBackend.post(REGISTER_URL, form, xhrConfig)
return this._axios.post(REGISTER_URL, form, xhrConfig)
.then(({data}) => data);
}
......@@ -68,7 +73,7 @@ export class UserService {
* @param key key
* @param xhrConfig additional xhr config
*/
public static validateEMail(tokenUuid: string, key: string, xhrConfig?: any): Promise<boolean> {
public validateEMail = (tokenUuid: string, key: string, xhrConfig?: any): Promise<boolean> => {
const qs = QueryString.stringify({
key: key || undefined,
......@@ -77,7 +82,7 @@ export class UserService {
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return axiosBackend.request({
return this._axios.request({
...xhrConfig,
url: apiUrl,
method: 'POST',
......@@ -93,7 +98,7 @@ export class UserService {
* @param filter the user filter