Commit 444024da authored by Matija Obreza's avatar Matija Obreza

Merge branch '122-list-crop-traits' into 'master'

List crop traits

Closes #122

See merge request !99
parents dc66605e d0f6610a
......@@ -88,6 +88,27 @@
"previousState": "Previous State",
"newState": "New State"
},
"CropTrait": {
"categoryCode": "Category",
"codedName": "Name",
"crop": "Crop",
"dataTypeCode": "Data Type Code",
"id": "ID",
"isArchived": "Is archived",
"isCoded": "Is coded",
"isPeerReviewed": "Is peer reviewed",
"maxLength": "Maximum length",
"numericFormat": "Numeric format",
"numericMaximum": "Numeric maximum",
"numericMinimum": "Numeric minimum",
"ontologyUrl": "Ontology URL",
"originalValueFormat": "Original value format",
"originalValueTypeCode": "Original value Type Code"
},
"TranslatedCropTraitCode": {
"code": "Code",
"cropTrait": "Crop trait"
},
"Geography": {
"geography": "Geography",
"currentGeography": "Current Valid Geography",
......
import Cooperator from '@gringlobal/client/model/gringlobal/Cooperator';
import Crop from '@gringlobal/client/model/gringlobal/Crop';
/**
* CropTrait
*
* GRIN-Global CE API
*/
class CropTrait {
public createdBy: number;
public createdDate: Date;
public modifiedBy: number;
public modifiedDate: Date;
public ownedBy: Cooperator;
public ownedDate: Date;
public categoryCode: string;
public codedName: string;
public crop: Crop;
public dataTypeCode: string;
public id: number;
public isArchived: string;
public isCoded: string;
public isPeerReviewed: string;
public maxLength: number;
public note: string;
public numericFormat: string;
public numericMaximum: number;
public numericMinimum: number;
public ontologyUrl: string;
public originalValueFormat: string;
public originalValueTypeCode: string;
public static CodeValues = {
dataTypeCode: 'CROP_TRAIT_DATA_TYPE',
categoryCode: 'DESCRIPTOR_CATEGORY',
originalValueTypeCode: 'CROP_TRAIT_DATA_TYPE',
}
}
export default CropTrait;
import Cooperator from '@gringlobal/client/model/gringlobal/Cooperator';
import CropTrait from '@gringlobal/client/model/gringlobal/CropTrait';
import RepositoryFile from '@gringlobal/client/model/repository/RepositoryFile';
/**
* CropTraitAttach
*
* GRIN-Global CE API
*/
class CropTraitAttach {
public createdBy: number;
public createdDate: Date;
public modifiedBy: number;
public modifiedDate: Date;
public ownedBy: Cooperator;
public ownedDate: Date;
public title: string;
public virtualPath: string;
public thumbnailVirtualPath: string;
public contentType: string;
public isWebVisible: string;
public sortOrder: number;
public note: string;
public repositoryFile: RepositoryFile;
public id: number;
public attachCooperator: Cooperator;
public attachDate: Date;
public attachDateCode: string;
public categoryCode: string;
public cropTrait: CropTrait;
public description: string;
}
export default CropTraitAttach;
import CropTraitAttach from '@gringlobal/client/model/gringlobal/CropTraitAttach';
import RepositoryFile from '@gringlobal/client/model/repository/RepositoryFile';
/**
* CropTraitAttachmentRequest
*
* GRIN-Global CE API
*/
class CropTraitAttachmentRequest {
public fileMetadata: RepositoryFile;
public attachMetadata: CropTraitAttach;
}
export default CropTraitAttachmentRequest;
import Cooperator from '@gringlobal/client/model/gringlobal/Cooperator';
import CropTrait from '@gringlobal/client/model/gringlobal/CropTrait';
/**
* CropTraitCode
*
* GRIN-Global CE API
*/
class CropTraitCode {
public createdBy: number;
public createdDate: Date;
public modifiedBy: number;
public modifiedDate: Date;
public ownedBy: Cooperator;
public ownedDate: Date;
public code: string;
public cropTrait: CropTrait;
public id: number;
}
export default CropTraitCode;
import Cooperator from '@gringlobal/client/model/gringlobal/Cooperator';
import CropTraitCode from '@gringlobal/client/model/gringlobal/CropTraitCode';
import RepositoryFile from '@gringlobal/client/model/repository/RepositoryFile';
/**
* CropTraitCodeAttach
*
* GRIN-Global CE API
*/
class CropTraitCodeAttach {
public createdBy: number;
public createdDate: Date;
public modifiedBy: number;
public modifiedDate: Date;
public ownedBy: Cooperator;
public ownedDate: Date;
public title: string;
public virtualPath: string;
public thumbnailVirtualPath: string;
public contentType: string;
public isWebVisible: string;
public sortOrder: number;
public note: string;
public repositoryFile: RepositoryFile;
public id: number;
public attachCooperator: Cooperator;
public attachDate: Date;
public attachDateCode: string;
public categoryCode: string;
public cropTraitCode: CropTraitCode;
public description: string;
}
export default CropTraitCodeAttach;
import CropTraitCodeAttach from '@gringlobal/client/model/gringlobal/CropTraitCodeAttach';
import RepositoryFile from '@gringlobal/client/model/repository/RepositoryFile';
/**
* CropTraitCodeAttachmentRequest
*
* GRIN-Global CE API
*/
class CropTraitCodeAttachmentRequest {
public fileMetadata: RepositoryFile;
public attachMetadata: CropTraitCodeAttach;
}
export default CropTraitCodeAttachmentRequest;
import Cooperator from '@gringlobal/client/model/gringlobal/Cooperator';
import CropTraitCode from '@gringlobal/client/model/gringlobal/CropTraitCode';
import SysLang from '@gringlobal/client/model/gringlobal/SysLang';
/**
* CropTraitCodeLang
*
* GRIN-Global CE API
*/
class CropTraitCodeLang {
public createdBy: number;
public createdDate: Date;
public modifiedBy: number;
public modifiedDate: Date;
public ownedBy: Cooperator;
public ownedDate: Date;
public entity: CropTraitCode;
public description: string;
public title: string;
public sysLang: SysLang;
public id: number;
}
export default CropTraitCodeLang;
import CooperatorFilter from '@gringlobal/client/model/gringlobal/CooperatorFilter';
import DateFilter from '@gringlobal/client/model/common/DateFilter';
import StringFilter from '@gringlobal/client/model/common/StringFilter';
/**
* CropTraitFilter
*
* GRIN-Global CE API
*/
class CropTraitFilter {
public NOT: CropTraitFilter;
public NULL: string[];
public NOTNULL: string[];
public id: number[];
public createdBy: number[];
public createdDate: DateFilter;
public modifiedBy: number[];
public modifiedDate: DateFilter;
public ownedBy: CooperatorFilter;
public ownedDate: DateFilter;
public crop: number[];
public codedName: string[];
public categoryCode: string[];
public description: StringFilter;
}
export default CropTraitFilter;
import Cooperator from '@gringlobal/client/model/gringlobal/Cooperator';
import CropTrait from '@gringlobal/client/model/gringlobal/CropTrait';
import SysLang from '@gringlobal/client/model/gringlobal/SysLang';
/**
* CropTraitLang
*
* GRIN-Global CE API
*/
class CropTraitLang {
public createdBy: number;
public createdDate: Date;
public modifiedBy: number;
public modifiedDate: Date;
public ownedBy: Cooperator;
public ownedDate: Date;
public entity: CropTrait;
public description: string;
public title: string;
public sysLang: SysLang;
public id: number;
}
export default CropTraitLang;
import Cooperator from '@gringlobal/client/model/gringlobal/Cooperator';
import Crop from '@gringlobal/client/model/gringlobal/Crop';
import TranslatedCropTraitCode from '@gringlobal/client/model/gringlobal/TranslatedCropTraitCode';
/**
* TranslatedCropTrait
*
* GRIN-Global CE API
*/
class TranslatedCropTrait {
public createdBy: number;
public createdDate: Date;
public modifiedBy: number;
public modifiedDate: Date;
public ownedBy: Cooperator;
public ownedDate: Date;
public categoryCode: string;
public codedName: string;
public crop: Crop;
public dataTypeCode: string;
public id: number;
public isArchived: string;
public isCoded: string;
public isPeerReviewed: string;
public maxLength: number;
public note: string;
public numericFormat: string;
public numericMaximum: number;
public numericMinimum: number;
public ontologyUrl: string;
public originalValueFormat: string;
public originalValueTypeCode: string;
public title: string;
public description: string;
public codes: TranslatedCropTraitCode[];
}
export default TranslatedCropTrait;
import Cooperator from '@gringlobal/client/model/gringlobal/Cooperator';
import CropTrait from '@gringlobal/client/model/gringlobal/CropTrait';
/**
* TranslatedCropTraitCode
*
* GRIN-Global CE API
*/
class TranslatedCropTraitCode {
public createdBy: number;
public createdDate: Date;
public modifiedBy: number;
public modifiedDate: Date;
public ownedBy: Cooperator;
public ownedDate: Date;
public code: string;
public cropTrait: CropTrait;
public id: number;
public title: string;
public description: string;
}
export default TranslatedCropTraitCode;
......@@ -77,6 +77,27 @@
"previousState": "Previous State",
"newState": "New State"
},
"CropTrait": {
"categoryCode": "Category",
"codedName": "Name",
"crop": "Crop",
"dataTypeCode": "Data Type Code",
"id": "ID",
"isArchived": "Is archived",
"isCoded": "Is coded",
"isPeerReviewed": "Is peer reviewed",
"maxLength": "Maximum length",
"numericFormat": "Numeric format",
"numericMaximum": "Numeric maximum",
"numericMinimum": "Numeric minimum",
"ontologyUrl": "Ontology URL",
"originalValueFormat": "Original value format",
"originalValueTypeCode": "Original value Type Code"
},
"TranslatedCropTraitCode": {
"code": "Code",
"cropTrait": "Crop trait"
},
"Geography": {
"geography": "Geography",
"currentGeography": "Current Valid Geography",
......
......@@ -10,6 +10,8 @@ import TaxonomySpeciesFilter from '@gringlobal/client/model/gringlobal/TaxonomyS
import CropDetails from '@gringlobal/client/model/gringlobal/CropDetails';
import CropAttachmentRequest from '@gringlobal/client/model/gringlobal/CropAttachmentRequest';
import CropAttach from '@gringlobal/client/model/gringlobal/CropAttach';
import { dereferenceReferences3 } from '@gringlobal/client/utilities';
import TaxonomySpecies from '@gringlobal/client/model/gringlobal/TaxonomySpecies';
const URL_REMOVE_FILE = UrlTemplate.parse('/api/v1/crop/attach/{cropId}/{attachmentId}');
const URL_UPLOAD_FILE = UrlTemplate.parse('/api/v1/crop/attach/{cropId}');
......@@ -21,6 +23,7 @@ const URL_UPDATE_CROP = '/api/v1/crop';
const URL_CREATE_CROP = '/api/v1/crop';
const URL_LIST_CROPS = '/api/v1/crop/list';
const URL_FILTER_CROPS = '/api/v1/crop/filter';
const URL_AUTOCOMPLETE_CROPS = '/api/v1/crop/autocomplete';
/**
......@@ -115,7 +118,7 @@ class CropService {
* @param cropId undefined
* @param xhrConfig additional xhr config
*/
public listCropSpecies = (data: TaxonomySpeciesFilter, cropId: number, xhrConfig?: AxiosRequestConfig): Promise<any> => {
public listCropSpecies = (data: TaxonomySpeciesFilter, cropId: number, xhrConfig?: AxiosRequestConfig): Promise<FilteredPage<TaxonomySpecies>> => {
const apiUrl = URL_LIST_CROP_SPECIES.expand({ cropId });
// console.log(`Fetching from ${apiUrl}`);
......@@ -126,7 +129,13 @@ class CropService {
url: apiUrl,
method: 'POST',
...content,
}).then(({ data }) => data as undefined);
}).then(({ data }) => {
dereferenceReferences3(data.content, {
gen: { id: [ 'taxonomyGenus' ] },
coo: { id: [ 'ownedBy', 'taxonomyGenus.ownedBy', 'verifierCooperator' ] },
});
return data as FilteredPage<TaxonomySpecies>;
});
}
/**
......@@ -263,6 +272,28 @@ class CropService {
method: 'POST',
...content,
}).then(({ data }) => data as FilteredPage<Crop>);
};
/**
* autocomplete at /api/v1/crop/autocomplete
*
* @param term undefined
* @param xhrConfig additional xhr config
*/
public autocomplete = (term: string, xhrConfig?: AxiosRequestConfig): Promise<Crop[]> => {
const qs = QueryString.stringify({
term: term || undefined,
}, {});
const apiUrl = URL_AUTOCOMPLETE_CROPS + (qs ? `?${qs}` : '');
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return this._axios.request({
...xhrConfig,
url: apiUrl,
method: 'GET',
...content,
}).then(({ data }) => data as Crop[]);
}
}
......
This diff is collapsed.
......@@ -58,7 +58,7 @@ class TaxonomyService {
}).then((response) => {
dereferenceReferences3(response.data.content, {
gen: { id: [ 'taxonomyGenus' ] },
coo: { id: [ 'ownedBy' ] }, // , 'modifiedBy', 'createdBy' ] },
coo: { id: [ 'ownedBy', 'verifierCooperator' ] }, // , 'modifiedBy', 'createdBy' ] },
});
return response.data;
});
......
......@@ -15,6 +15,8 @@ import RepositoryService from '@gringlobal/client/service/RepositoryService';
import GeographyService from '@gringlobal/client/service/GeographyService';
import OAuthManagementService from '@gringlobal/client/service/OAuthManagementService';
import CropService from '@gringlobal/client/service/CropService';
import CropTraitService from '@gringlobal/client/service/CropTraitService';
import axios from 'axios';
import { clearCookies } from '@gringlobal/client/utilities';
import { ApiError } from '@gringlobal/client/model/common';
......@@ -103,6 +105,7 @@ const ConfiguredMethodService = new MethodService(serviceAxios);
const ConfiguredGeographyService = new GeographyService(serviceAxios);
const ConfiguredOAuthManagementService = new OAuthManagementService(serviceAxios);
const ConfiguredCropService = new CropService(serviceAxios);
const ConfiguredCropTraitService = new CropTraitService(serviceAxios);
export {
ConfiguredCooperatorService as CooperatorService,
......@@ -122,4 +125,5 @@ export {
ConfiguredGeographyService as GeographyService,
ConfiguredOAuthManagementService as OAuthManagementService,
ConfiguredCropService as CropService,
ConfiguredCropTraitService as CropTraitService,
}
......@@ -44,7 +44,7 @@ const styles = (theme) => ({
});
interface ISlotLayout extends React.ClassAttributes<any>, WithStyles {
fixedContent: React.ReactNode;
fixedContent?: React.ReactNode;
children: React.ReactNode; // scrollable content
}
......@@ -53,9 +53,11 @@ function SlotLayout(props: ISlotLayout): JSX.Element {
return (
<div className={ classes.layout }>
<div className={ classes.topWrapper }>
{ fixedContent }
</div>
{ fixedContent &&
<div className={ classes.topWrapper }>
{ fixedContent }
</div>
}
<div className={ classes.containerWrapper }>
{ children }
</div>
......
......@@ -209,6 +209,17 @@
"traits": "Traits",
"species": "Species"
}
},
"traitsDetails": {
"title": "Crop trait details",
"codes": "Codes"
}
}
},
"admin": {
"p": {
"traitsEdit": {
"title": "New crop trait"
}
}
}
......
import * as React from 'react';
import Crop from '@gringlobal/client/model/gringlobal/Crop';
import { FieldRenderProps } from 'react-final-form';
import { ListItemText } from '@material-ui/core';
import { CropService } from '@gringlobal/client/service';
import Autocomplete from '@gringlobal/client/ui/common/form/Autocomplete';
interface ICropAutocomplete {
label: string;
}
class CropAutocomplete extends React.Component<ICropAutocomplete & FieldRenderProps<any>> {
public constructor(props) {
super(props);
}
private autocomplete = (text: string): Promise<Crop[]> => {
return CropService.autocomplete(text);
};
private renderOption = (crop: Crop, state: object): React.ReactNode => {
return (
<ListItemText
primary={ crop.name }
/>
);
};
private mapOptions = (crops: Crop[]): Crop[] => crops;
private getOptionLabel = (crop: Crop): string => crop.name;
public render() {
return (
<Autocomplete
{ ...this.props }
autocomplete={ this.autocomplete }
renderOption={ this.renderOption }
mapOptions={ this.mapOptions }
getOptionLabel={ this.getOptionLabel }
/>
);
}
}
export default CropAutocomplete;
import { put, takeEvery, call, take } from 'redux-saga/effects';
import { put, takeEvery, call, take, select } from 'redux-saga/effects';
// Constants
import {
ADMIN_RECEIVE_CROP,
ADMIN_RECEIVE_CROP_TRAIT,
REMOVE_CROP_TRAIT,
SAGA_ADMIN_CREATE_CROP,
SAGA_ADMIN_RECEIVE_CROP,
SAGA_ADMIN_EDIT_CROP,
SAGA_ADMIN_CREATE_CROP_TRAIT,
SAGA_ADMIN_EDIT_CROP_TRAIT,
SAGA_ADMIN_RECEIVE_CROP_TRAIT,
SAGA_ADMIN_REMOVE_CROP_TRAIT,
} from 'crop/constants';
// Model
import Crop from '@gringlobal/client/model/gringlobal/Crop';
import CropTrait from '@gringlobal/client/model/gringlobal/CropTrait';
// Service
import { CropService } from '@gringlobal/client/service';
import { CropService, CropTraitService } from '@gringlobal/client/service';
// Action
import { sagaNavigate } from '@gringlobal/client/action/navigation';
import { receiveCropDetailsSaga } from './public';
import { clearCropTrait, receiveCropDetailsSaga } from './public';
export const cropAdminSagas = [
takeEvery(SAGA_ADMIN_CREATE_CROP, createCropSaga),
takeEvery(SAGA_ADMIN_EDIT_CROP, editCropSaga),
takeEvery(SAGA_ADMIN_RECEIVE_CROP, getCropSaga),