Commit 79f74e30 authored by Oleksii Savran's avatar Oleksii Savran

CropTrait: remove, add

parent 7fee466f
...@@ -33,6 +33,7 @@ class CropTrait { ...@@ -33,6 +33,7 @@ class CropTrait {
public static CodeValues = { public static CodeValues = {
dataTypeCode: 'CROP_TRAIT_DATA_TYPE', dataTypeCode: 'CROP_TRAIT_DATA_TYPE',
categoryCode: 'DESCRIPTOR_CATEGORY', categoryCode: 'DESCRIPTOR_CATEGORY',
originalValueTypeCode: 'CROP_TRAIT_DATA_TYPE',
} }
} }
......
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;
...@@ -21,6 +21,7 @@ const URL_UPDATE_CROP = '/api/v1/crop'; ...@@ -21,6 +21,7 @@ const URL_UPDATE_CROP = '/api/v1/crop';
const URL_CREATE_CROP = '/api/v1/crop'; const URL_CREATE_CROP = '/api/v1/crop';
const URL_LIST_CROPS = '/api/v1/crop/list'; const URL_LIST_CROPS = '/api/v1/crop/list';
const URL_FILTER_CROPS = '/api/v1/crop/filter'; const URL_FILTER_CROPS = '/api/v1/crop/filter';
const URL_AUTOCOMPLETE_CROPS = '/api/v1/crop/autocomplete';
/** /**
...@@ -263,6 +264,28 @@ class CropService { ...@@ -263,6 +264,28 @@ class CropService {
method: 'POST', method: 'POST',
...content, ...content,
}).then(({ data }) => data as FilteredPage<Crop>); }).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[]);
} }
} }
......
...@@ -6,6 +6,7 @@ import { AxiosInstance, AxiosRequestConfig } from 'axios'; ...@@ -6,6 +6,7 @@ import { AxiosInstance, AxiosRequestConfig } from 'axios';
import { IPageRequest } from '@gringlobal/client/model/page'; import { IPageRequest } from '@gringlobal/client/model/page';
import CropTrait from '@gringlobal/client/model/gringlobal/CropTrait'; import CropTrait from '@gringlobal/client/model/gringlobal/CropTrait';
import CropTraitFilter from '@gringlobal/client/model/gringlobal/CropTraitFilter'; import CropTraitFilter from '@gringlobal/client/model/gringlobal/CropTraitFilter';
import TranslatedCropTrait from '@gringlobal/client/model/gringlobal/TranslatedCropTrait';
const URL_UPLOAD_FILE = UrlTemplate.parse('/api/v1/crop-trait/attach/{cropTraitId}'); const URL_UPLOAD_FILE = UrlTemplate.parse('/api/v1/crop-trait/attach/{cropTraitId}');
const URL_GET_TRANSLATED = UrlTemplate.parse('/api/v1/crop-trait/{id}'); const URL_GET_TRANSLATED = UrlTemplate.parse('/api/v1/crop-trait/{id}');
...@@ -56,7 +57,7 @@ class CropTraitService { ...@@ -56,7 +57,7 @@ class CropTraitService {
* @param id undefined * @param id undefined
* @param xhrConfig additional xhr config * @param xhrConfig additional xhr config
*/ */
public getTranslated = (id: number, xhrConfig?: AxiosRequestConfig): Promise<any> => { public getTranslated = (id: number, xhrConfig?: AxiosRequestConfig): Promise<TranslatedCropTrait> => {
const apiUrl = URL_GET_TRANSLATED.expand({ id }); const apiUrl = URL_GET_TRANSLATED.expand({ id });
// console.log(`Fetching from ${apiUrl}`); // console.log(`Fetching from ${apiUrl}`);
...@@ -67,7 +68,7 @@ class CropTraitService { ...@@ -67,7 +68,7 @@ class CropTraitService {
url: apiUrl, url: apiUrl,
method: 'GET', method: 'GET',
...content, ...content,
}).then(({ data }) => data as undefined); }).then(({ data }) => data as TranslatedCropTrait);
}; };
/** /**
...@@ -76,7 +77,7 @@ class CropTraitService { ...@@ -76,7 +77,7 @@ class CropTraitService {
* @param id undefined * @param id undefined
* @param xhrConfig additional xhr config * @param xhrConfig additional xhr config
*/ */
public remove = (id: number, xhrConfig?: AxiosRequestConfig): Promise<any> => { public remove = (id: number, xhrConfig?: AxiosRequestConfig): Promise<CropTrait> => {
const apiUrl = URL_REMOVE.expand({ id }); const apiUrl = URL_REMOVE.expand({ id });
// console.log(`Fetching from ${apiUrl}`); // console.log(`Fetching from ${apiUrl}`);
...@@ -87,7 +88,7 @@ class CropTraitService { ...@@ -87,7 +88,7 @@ class CropTraitService {
url: apiUrl, url: apiUrl,
method: 'DELETE', method: 'DELETE',
...content, ...content,
}).then(({ data }) => data as undefined); }).then(({ data }) => data as CropTrait);
}; };
/** /**
...@@ -159,7 +160,7 @@ class CropTraitService { ...@@ -159,7 +160,7 @@ class CropTraitService {
* @param data Request body * @param data Request body
* @param xhrConfig additional xhr config * @param xhrConfig additional xhr config
*/ */
public update = (data: CropTrait, xhrConfig?: AxiosRequestConfig): Promise<any> => { public update = (data: CropTrait, xhrConfig?: AxiosRequestConfig): Promise<CropTrait> => {
const apiUrl = URL_UPDATE; const apiUrl = URL_UPDATE;
// console.log(`Fetching from ${apiUrl}`); // console.log(`Fetching from ${apiUrl}`);
...@@ -170,7 +171,7 @@ class CropTraitService { ...@@ -170,7 +171,7 @@ class CropTraitService {
url: apiUrl, url: apiUrl,
method: 'PUT', method: 'PUT',
...content, ...content,
}).then(({ data }) => data as undefined); }).then(({ data }) => data as CropTrait);
}; };
/** /**
...@@ -179,7 +180,7 @@ class CropTraitService { ...@@ -179,7 +180,7 @@ class CropTraitService {
* @param data Request body * @param data Request body
* @param xhrConfig additional xhr config * @param xhrConfig additional xhr config
*/ */
public create = (data: CropTrait, xhrConfig?: AxiosRequestConfig): Promise<any> => { public create = (data: CropTrait, xhrConfig?: AxiosRequestConfig): Promise<CropTrait> => {
const apiUrl = URL_CREATE; const apiUrl = URL_CREATE;
// console.log(`Fetching from ${apiUrl}`); // console.log(`Fetching from ${apiUrl}`);
...@@ -190,7 +191,7 @@ class CropTraitService { ...@@ -190,7 +191,7 @@ class CropTraitService {
url: apiUrl, url: apiUrl,
method: 'POST', method: 'POST',
...content, ...content,
}).then(({ data }) => data as undefined); }).then(({ data }) => data as CropTrait);
}; };
/** /**
...@@ -200,7 +201,7 @@ class CropTraitService { ...@@ -200,7 +201,7 @@ class CropTraitService {
* @param page undefined * @param page undefined
* @param xhrConfig additional xhr config * @param xhrConfig additional xhr config
*/ */
public list = (data: CropTraitFilter, page?: IPageRequest, xhrConfig?: AxiosRequestConfig): Promise<any> => { public list = (data: CropTraitFilter, page?: IPageRequest, xhrConfig?: AxiosRequestConfig): Promise<TranslatedCropTrait> => {
const qs = QueryString.stringify({ const qs = QueryString.stringify({
p: page.page || undefined, p: page.page || undefined,
...@@ -217,7 +218,7 @@ class CropTraitService { ...@@ -217,7 +218,7 @@ class CropTraitService {
url: apiUrl, url: apiUrl,
method: 'POST', method: 'POST',
...content, ...content,
}).then(({ data }) => data as undefined); }).then(({ data }) => data as TranslatedCropTrait);
} }
} }
......
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;
...@@ -4,12 +4,14 @@ import { put, takeEvery, call, take, select } from 'redux-saga/effects'; ...@@ -4,12 +4,14 @@ import { put, takeEvery, call, take, select } from 'redux-saga/effects';
import { import {
ADMIN_RECEIVE_CROP, ADMIN_RECEIVE_CROP,
ADMIN_RECEIVE_CROP_TRAIT, ADMIN_RECEIVE_CROP_TRAIT,
REMOVE_CROP_TRAIT,
SAGA_ADMIN_CREATE_CROP, SAGA_ADMIN_CREATE_CROP,
SAGA_ADMIN_RECEIVE_CROP, SAGA_ADMIN_RECEIVE_CROP,
SAGA_ADMIN_EDIT_CROP, SAGA_ADMIN_EDIT_CROP,
SAGA_ADMIN_CREATE_CROP_TRAIT, SAGA_ADMIN_CREATE_CROP_TRAIT,
SAGA_ADMIN_EDIT_CROP_TRAIT, SAGA_ADMIN_EDIT_CROP_TRAIT,
SAGA_ADMIN_RECEIVE_CROP_TRAIT, SAGA_ADMIN_RECEIVE_CROP_TRAIT,
SAGA_ADMIN_REMOVE_CROP_TRAIT,
} from 'crop/constants'; } from 'crop/constants';
// Model // Model
import Crop from '@gringlobal/client/model/gringlobal/Crop'; import Crop from '@gringlobal/client/model/gringlobal/Crop';
...@@ -18,7 +20,7 @@ import CropTrait from '@gringlobal/client/model/gringlobal/CropTrait'; ...@@ -18,7 +20,7 @@ import CropTrait from '@gringlobal/client/model/gringlobal/CropTrait';
import { CropService, CropTraitService } from '@gringlobal/client/service'; import { CropService, CropTraitService } from '@gringlobal/client/service';
// Action // Action
import { sagaNavigate } from '@gringlobal/client/action/navigation'; import { sagaNavigate } from '@gringlobal/client/action/navigation';
import { receiveCropDetailsSaga } from './public'; import { clearCropTrait, receiveCropDetailsSaga } from './public';
export const cropAdminSagas = [ export const cropAdminSagas = [
...@@ -28,6 +30,7 @@ export const cropAdminSagas = [ ...@@ -28,6 +30,7 @@ export const cropAdminSagas = [
takeEvery(SAGA_ADMIN_CREATE_CROP_TRAIT, createCropTraitSaga), takeEvery(SAGA_ADMIN_CREATE_CROP_TRAIT, createCropTraitSaga),
takeEvery(SAGA_ADMIN_EDIT_CROP_TRAIT, editCropTraitSaga), takeEvery(SAGA_ADMIN_EDIT_CROP_TRAIT, editCropTraitSaga),
takeEvery(SAGA_ADMIN_RECEIVE_CROP_TRAIT, getCropTraitSaga), takeEvery(SAGA_ADMIN_RECEIVE_CROP_TRAIT, getCropTraitSaga),
takeEvery(SAGA_ADMIN_REMOVE_CROP_TRAIT, removeCropTraitSaga),
]; ];
export const createCropAction = (crop: Crop) => ({ export const createCropAction = (crop: Crop) => ({
...@@ -60,6 +63,11 @@ export const getCropTraitAction = (id: string | number) => ({ ...@@ -60,6 +63,11 @@ export const getCropTraitAction = (id: string | number) => ({
payload: { id }, payload: { id },
}); });
export const removeCropTraitAction = (id: string | number) => ({
type: SAGA_ADMIN_REMOVE_CROP_TRAIT,
payload: { id },
});
function* createCropSaga(action) { function* createCropSaga(action) {
yield put({ yield put({
type: 'API', type: 'API',
...@@ -133,15 +141,11 @@ function* createCropTraitSaga(action) { ...@@ -133,15 +141,11 @@ function* createCropTraitSaga(action) {
return cropTrait; return cropTrait;
}, },
}); });
yield take(ADMIN_RECEIVE_CROP); yield take(ADMIN_RECEIVE_CROP_TRAIT);
const received = yield take(ADMIN_RECEIVE_CROP); const received = yield take(ADMIN_RECEIVE_CROP_TRAIT);
if (received.payload.apiCall.data) { if (received.payload.apiCall.data) {
console.log('navigate after creating'); yield call(sagaNavigate, `/crop/trait/${received.payload.apiCall.data.id}`);
// const id = received.payload.apiCall.data.id;
// yield call(receiveCropDetailsSaga, { payload: { id } });
// yield call(sagaNavigate, `/crop/${received.payload.apiCall.data.id}`);
// yield put({ type: ADMIN_RECEIVE_CROP, payload: received.payload })
} }
} }
...@@ -159,19 +163,9 @@ function* editCropTraitSaga(action) { ...@@ -159,19 +163,9 @@ function* editCropTraitSaga(action) {
yield take(ADMIN_RECEIVE_CROP_TRAIT); yield take(ADMIN_RECEIVE_CROP_TRAIT);
const received = yield take(ADMIN_RECEIVE_CROP_TRAIT); const received = yield take(ADMIN_RECEIVE_CROP_TRAIT);
// yield take(RECEIVE_CROP);
// const received = yield take(RECEIVE_CROP);
//
// if (received.payload.apiCall.data) {
// console.log('navigate after creating');
// yield call(sagaNavigate, `/crop/${received.payload.apiCall.data.id}`);
// yield put({ type: ADMIN_RECEIVE_CROP, payload: received.payload })
// }
if (received.payload.apiCall.data) { if (received.payload.apiCall.data) {
console.log('do something'); yield call(clearCropTrait);
// const id = received.payload.apiCall.data.id; yield call(sagaNavigate, `/crop/trait/${received.payload.apiCall.data.id}`);
// yield call(receiveCropDetailsSaga, { payload: { id } });
// yield call(sagaNavigate, `/crop/${received.payload.apiCall.data.id}`);
} }
} }
...@@ -180,13 +174,11 @@ function* getCropTraitSaga(action) { ...@@ -180,13 +174,11 @@ function* getCropTraitSaga(action) {
const publicCropTrait = yield select((state) => state.crop.public.trait); const publicCropTrait = yield select((state) => state.crop.public.trait);
if (publicCropTrait && publicCropTrait.data && +id === publicCropTrait.data.id) { if (publicCropTrait && publicCropTrait.data && +id === publicCropTrait.data.id) {
console.log('already in state, prevent api call', publicCropTrait);
yield put({ yield put({
type: ADMIN_RECEIVE_CROP_TRAIT, type: ADMIN_RECEIVE_CROP_TRAIT,
payload: { apiCall: publicCropTrait }, payload: { apiCall: publicCropTrait },
}) })
} else { } else {
console.log('get trait admin call');
yield put({ yield put({
type: 'API', type: 'API',
target: ADMIN_RECEIVE_CROP_TRAIT, target: ADMIN_RECEIVE_CROP_TRAIT,
...@@ -198,3 +190,18 @@ function* getCropTraitSaga(action) { ...@@ -198,3 +190,18 @@ function* getCropTraitSaga(action) {
}); });
} }
} }
function* removeCropTraitSaga(action) {
yield put({
type: 'API',
target: REMOVE_CROP_TRAIT,
method: CropTraitService.remove,
params: [action.payload.id],
onSuccess: (cropTrait: CropTrait) => {
return (function* () {
yield call(sagaNavigate, `/crop/${cropTrait.crop.id}`);
return cropTrait;
})();
},
});
}
...@@ -77,8 +77,6 @@ export const getCropTraitAction = (id: string | number) => ({ ...@@ -77,8 +77,6 @@ export const getCropTraitAction = (id: string | number) => ({
payload: { id }, payload: { id },
}); });
export const removeCropTraitAction = (id: string | number) => null;
function* listCropsSaga(action) { function* listCropsSaga(action) {
yield put({ yield put({
type: 'API', type: 'API',
...@@ -167,3 +165,10 @@ function* uploadCropAttachmentSaga(action) { ...@@ -167,3 +165,10 @@ function* uploadCropAttachmentSaga(action) {
}, },
}); });
} }
export function* clearCropTrait() {
yield put({
type: RECEIVE_CROP_TRAIT,
payload: { apiCall: null },
});
}
...@@ -27,3 +27,6 @@ export const ADMIN_RECEIVE_CROP_TRAIT = 'crop/admin/RECEIVE_CROP_TRAIT'; ...@@ -27,3 +27,6 @@ export const ADMIN_RECEIVE_CROP_TRAIT = 'crop/admin/RECEIVE_CROP_TRAIT';
export const SAGA_ADMIN_CREATE_CROP_TRAIT = 'saga/crop/public/CREATE_CROP_TRAIT'; export const SAGA_ADMIN_CREATE_CROP_TRAIT = 'saga/crop/public/CREATE_CROP_TRAIT';
export const SAGA_ADMIN_EDIT_CROP_TRAIT = 'saga/crop/public/EDIT_CROP_TRAIT'; export const SAGA_ADMIN_EDIT_CROP_TRAIT = 'saga/crop/public/EDIT_CROP_TRAIT';
export const SAGA_ADMIN_REMOVE_CROP_TRAIT = 'saga/crop/admin/REMOVE_CROP_TRAIT';
export const REMOVE_CROP_TRAIT = 'crop/public/REMOVE_CROP_TRAIT';
import update from 'immutability-helper'; import update from 'immutability-helper';
// Constants // Constants
import { RECEIVE_CROPS, RECEIVE_CROP_DETAILS, RECEIVE_CROP_SPECIES, RECEIVE_CROP_ATTACHMENT, RECEIVE_CROP_TRAITS, RECEIVE_CROP_TRAIT } from 'crop/constants'; import { RECEIVE_CROPS, RECEIVE_CROP_DETAILS, RECEIVE_CROP_SPECIES, RECEIVE_CROP_ATTACHMENT, RECEIVE_CROP_TRAITS, RECEIVE_CROP_TRAIT, REMOVE_CROP_TRAIT } from 'crop/constants';
// Model // Model
import { FilteredPage } from '@gringlobal/client/model/page'; import { FilteredPage } from '@gringlobal/client/model/page';
import { ApiCall } from '@gringlobal/client/model/common'; import { ApiCall } from '@gringlobal/client/model/common';
import Crop from '@gringlobal/client/model/gringlobal/Crop'; import Crop from '@gringlobal/client/model/gringlobal/Crop';
import CropDetails from '@gringlobal/client/model/gringlobal/CropDetails'; import CropDetails from '@gringlobal/client/model/gringlobal/CropDetails';
import TaxonomySpecies from '@gringlobal/client/model/gringlobal/TaxonomySpecies'; import TaxonomySpecies from '@gringlobal/client/model/gringlobal/TaxonomySpecies';
import CropTrait from '@gringlobal/client/model/gringlobal/CropTrait'; import TranslatedCropTrait from '@gringlobal/client/model/gringlobal/TranslatedCropTrait';
const initialState: { const initialState: {
crop: ApiCall<CropDetails>, crop: ApiCall<CropDetails>,
crops: ApiCall<FilteredPage<Crop>>, crops: ApiCall<FilteredPage<Crop>>,
species: ApiCall<FilteredPage<TaxonomySpecies>>, species: ApiCall<FilteredPage<TaxonomySpecies>>,
trait: ApiCall<CropTrait>, trait: ApiCall<TranslatedCropTrait>,
traits: ApiCall<FilteredPage<CropTrait>>, traits: ApiCall<FilteredPage<TranslatedCropTrait>>,
} = { } = {
crop: null, crop: null,
crops: null, crops: null,
...@@ -91,6 +91,31 @@ const cropPublicReducer = (state = initialState, action) => { ...@@ -91,6 +91,31 @@ const cropPublicReducer = (state = initialState, action) => {
} }
return state; return state;
} }
case REMOVE_CROP_TRAIT: {
const { apiCall: { data } } = action.payload;
if (data) {
if (state.traits && state.traits.data && state.traits.data.content) {
const updatedTraits = state.traits.data.content.filter((trait) => trait.id !== data.id);
return update(state, {
trait: { $set: null },
traits: {
data: {
content: {
$set: updatedTraits,
},
totalElements: {
$apply: (total) => total - 1,
},
},
},
});
}
return update(state, {
trait: { $set: null },
});
}
return state;
}
default: default:
return state; return state;
} }
......
<
...@@ -31,12 +31,13 @@ import CropTrait from '@gringlobal/client/model/gringlobal/CropTrait'; ...@@ -31,12 +31,13 @@ import CropTrait from '@gringlobal/client/model/gringlobal/CropTrait';
import AddNewButton from '@gringlobal/client/ui/common/button/AddNewButton'; import AddNewButton from '@gringlobal/client/ui/common/button/AddNewButton';
import { CodeValueDisplay } from 'common/CodeValue'; import { CodeValueDisplay } from 'common/CodeValue';
import SlotLayout from '@gringlobal/client/ui/common/layout/SlotLayout'; import SlotLayout from '@gringlobal/client/ui/common/layout/SlotLayout';
import TranslatedCropTrait from '@gringlobal/client/model/gringlobal/TranslatedCropTrait';
interface ICropDetailsPage extends React.ClassAttributes<any>, WithTranslation { interface ICropDetailsPage extends React.ClassAttributes<any>, WithTranslation {
cropCall: ApiCall<CropDetails>; cropCall: ApiCall<CropDetails>;
speciesCall: ApiCall<FilteredPage<TaxonomySpecies>>; speciesCall: ApiCall<FilteredPage<TaxonomySpecies>>;
traitsCall: ApiCall<FilteredPage<CropTrait>>; traitsCall: ApiCall<FilteredPage<TranslatedCropTrait>>;
getCropDetailsAction: (id) => void; getCropDetailsAction: (id) => void;
getCropSpeciesAction: (id) => void; getCropSpeciesAction: (id) => void;
getCropTraitsAction: (id) => void; getCropTraitsAction: (id) => void;
...@@ -49,6 +50,8 @@ export const CropTraitTablDefaultConfig = { ...@@ -49,6 +50,8 @@ export const CropTraitTablDefaultConfig = {
defaultColumns: [ defaultColumns: [
'id', 'id',