Commit e2534b45 authored by Viacheslav Pavlov's avatar Viacheslav Pavlov Committed by Matija Obreza
Browse files

Accession details: More details


Signed-off-by: Matija Obreza's avatarMatija Obreza <matija.obreza@croptrust.org>
parent a718ba14
......@@ -5,8 +5,9 @@ import navigateTo from 'actions/navigation';
import FilteredPage, { IPageRequest } from 'model/FilteredPage';
import Accession from 'model/Accession';
import AccessionFilter from 'model/AccessionFilter';
import AccessionDetails from 'model/AccessionDetails';
import {list as listAccessions, getByUuid, getByDoi, listOverview as listAccessionOverview, toUUID} from 'actions/genesys/accessionService';
import {list as listAccessions, getDetailsByUuid, getDetailsByDoi, listOverview as listAccessionOverview, toUUID} from 'actions/genesys/accessionService';
import {RECEIVE_ACCESSIONS, RECEIVE_ACCESSION, RECEIVE_ACCESSION_OVERVIEW, APPEND_ACCESSIONS} from 'constants/accessions';
const receiveAccessions = (paged: FilteredPage<Accession>, error = null) => ({
......@@ -24,7 +25,7 @@ const receiveAccessionOverview = (overview: any, error = null) => ({
payload: { overview, error },
});
const receiveAccession = (accession: Accession, error = null) => ({
const receiveAccession = (accession: AccessionDetails, error = null) => ({
type: RECEIVE_ACCESSION,
payload: { accession, error },
});
......@@ -92,7 +93,7 @@ export const loadAccessionsPage = (page: IPageRequest) => (dispatch, getState) =
};
export const loadAccession = ({ uuid, doi }: { uuid?: string, doi?: string }) => (dispatch) => {
const loader = doi ? getByDoi : getByUuid;
const loader = doi ? getDetailsByDoi : getDetailsByUuid;
const lookup = doi ? doi : uuid;
return dispatch(loader(lookup))
......
......@@ -6,6 +6,7 @@ import Accession from 'model/Accession';
import AccessionFilter from 'model/AccessionFilter';
import FilteredPage, { IPageRequest } from 'model/FilteredPage';
import {AccessionIdentifier} from 'model/dataset.model';
import AccessionDetails from 'model/AccessionDetails';
......@@ -28,6 +29,25 @@ export const getByUuid = (UUID: string) => (dispatch, getState): Promise<Accessi
return AccessionService.getByUuid(authorization, UUID);
};
/**
* Action getDetailsByDoi
*
*/
export const getDetailsByDoi = (doi: string) => (dispatch, getState): Promise<AccessionDetails> => {
const authorization = getState().login.access_token;
return AccessionService.getDetailsByDoi(authorization, doi);
};
/**
* Action getDetailsByUuid
*
* @param UUID UUID
*/
export const getDetailsByUuid = (UUID: string) => (dispatch, getState): Promise<AccessionDetails> => {
const authorization = getState().login.access_token;
return AccessionService.getDetailsByUuid(authorization, UUID);
};
export const toUUID = (identifiers: AccessionIdentifier[]) => (dispatch, getState): Promise<Map<string, AccessionIdentifier>> => {
const authorization = getState().login.access_token;
......
import Accession from 'model/Accession';
import Subset from 'model/Subset';
import PDCI from 'model/PDCI';
class AccessionDetails {
public details: Accession;
public datasets: any[];
public subsets: Subset[];
public pdci: PDCI;
}
export default AccessionDetails;
\ No newline at end of file
......@@ -5,12 +5,15 @@ import authenticatedRequest from 'utilities/requestUtils';
import { API_ROOT } from 'constants/apiURLS';
import Accession from 'model/Accession';
import AccessionDetails from 'model/AccessionDetails';
import AccessionFilter from 'model/AccessionFilter';
import FilteredPage, { IPageRequest } from 'model/FilteredPage';
import {AccessionIdentifier} from 'model/dataset.model';
const URL_GET_BY_DOI = `${API_ROOT}/api/v1/acn/{doi}`; // UrlTemplate doesn't like the / in DOI
const URL_GET_BY_UUID = UrlTemplate.parse(`${API_ROOT}/api/v1/acn/{UUID}`);
const URL_GET_DETAILS_BY_DOI = `${API_ROOT}/api/v1/acn/details/{doi}`; // UrlTemplate doesn't like the / in DOI
const URL_GET_DETAILS_BY_UUID = UrlTemplate.parse(`${API_ROOT}/api/v1/acn/details/{UUID}`);
const URL_TO_UUID = `${API_ROOT}/api/v1/acn/toUUID`;
const URL_LIST = `${API_ROOT}/api/v1/acn/list`;
const URL_LIST_OVERVIEW = `${API_ROOT}/api/v1/acn/overview`;
......@@ -58,6 +61,43 @@ class AccessionService {
}).then(({ data }) => data as Accession);
}
/**
* getByDoi at /api/v1/acn/10.{dummy}/**}
*
* @param authToken Authorization token
*/
public static getDetailsByDoi(authToken: string, doi: string): Promise<AccessionDetails> {
const apiUrl = URL_GET_DETAILS_BY_DOI.replace(/{doi}/, doi);
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return authenticatedRequest(authToken, {
url: apiUrl,
method: 'GET',
...content,
}).then(({ data }) => data as AccessionDetails);
}
/**
* getByUuid at /api/v1/acn/{UUID}
*
* @param authToken Authorization token
* @param UUID UUID
*/
public static getDetailsByUuid(authToken: string, UUID: string): Promise<AccessionDetails> {
const apiUrl = URL_GET_DETAILS_BY_UUID.expand({ UUID });
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return authenticatedRequest(authToken, {
url: apiUrl,
method: 'GET',
...content,
}).then(({ data }) => data as AccessionDetails);
}
public static toUUID(authToken: string, identifiers: AccessionIdentifier[]) {
const apiUrl = URL_TO_UUID;
const content = { data: identifiers };
......
......@@ -10,6 +10,8 @@ interface IBundledProps extends React.ClassAttributes<any> {
title: string;
small?: boolean;
t: any;
topSection?: any;
propertyItemProps: any;
}
......@@ -17,17 +19,20 @@ class PropertiesCard extends React.Component<IBundledProps, any> {
public render() {
const {children = null, propertiesList, title, small = false, t} = this.props;
const {children = null, propertiesList, title, small = false, topSection, t, propertyItemProps} = this.props;
return (
<Grid item lg={ small ? 6 : 12 } md={ 12 } xs={ 12 }>
<PageSection title={ title }>
<Grid>
{ topSection }
</Grid>
<Grid container justify={ 'center' } spacing={ 16 }>
<Grid item md={ children ? 7 : 12 } sm={ 12 } style={ {width: '100%'} }>
<Properties>
{
propertiesList.map((property, i) => (
<PropertiesItem key={ `${i}-${property.title}` } numeric title={ property.title }>
<PropertiesItem key={ `${i}-${property.title}` } numeric title={ property.title } { ...propertyItemProps } >
{ property.value && typeof property.value === 'number' ? t(`common:label.prettyNumber`, {value: property.value}) : property.value }
</PropertiesItem>
))
......
......@@ -86,4 +86,17 @@ const CountryLink = ({ country, noflag, children }: { country: Country, noflag?:
);
};
export { SubsetLink, AccessionLink, InstituteLink, RequestLink, CountryLink};
const DatasetLink = ({ to: dataset, edit = false, children = null }
: { to: any, edit?: boolean, children?: any }) => {
if (dataset) {
return (
<Link to={ `/datasets/${dataset.uuid}` }>
{ children || <Markdown basic source={ dataset.title } /> }
</Link>
);
} else {
return null;
}
};
export { SubsetLink, AccessionLink, InstituteLink, RequestLink, CountryLink, DatasetLink};
......@@ -8,7 +8,7 @@ import { loadAccession } from 'actions/accessions';
import {addAccessionToMyList, removeAccessionFromMyList} from 'actions/user';
// Models
import Accession from 'model/Accession';
import AccessionDetails from 'model/AccessionDetails';
// UI
import { Link } from 'react-router-dom';
......@@ -24,15 +24,18 @@ import { ScrollToTopOnMount } from 'ui/common/page/scrollers';
import ReduxCheckbox from 'ui/common/checkbox';
import CropChips from 'ui/genesys/crop/CropChips';
import LocationMap from 'ui/common/LocationMap';
import {CountryLink, InstituteLink} from 'ui/genesys/Links';
import {CountryLink, DatasetLink, InstituteLink, SubsetLink} from 'ui/genesys/Links';
import PropertiesCard from 'ui/common/PropertiesCard';
import GridLayout from 'ui/layout/GridLayout';
import McpdDate from 'ui/common/time/McpdDate';
import PdciTable from './c/PdciTable';
interface IBrowsePageProps extends React.ClassAttributes<any> {
t: any;
uuid: string;
doi: string; // DOI comes from the route without the '10.'
accession: Accession;
accession: AccessionDetails;
error: any;
loadAccession: any;
accessions: any;
......@@ -53,7 +56,9 @@ class BrowsePage extends React.Component<IBrowsePageProps, any> {
}
public componentWillMount() {
const { accession, doi, uuid, loadAccession } = this.props;
const { doi, uuid, loadAccession } = this.props;
const accession = this.props.accession ? this.props.accession.details : null;
const theDoi = `10.${doi}`;
if (doi && (! accession || theDoi !== accession.doi)) {
loadAccession({ doi: theDoi });
......@@ -64,7 +69,7 @@ class BrowsePage extends React.Component<IBrowsePageProps, any> {
}
private onCheckboxChange = (event, checked) => {
const {accession, addAccessionToMyList, removeAccessionFromMyList} = this.props;
const {accession: {details: accession}, addAccessionToMyList, removeAccessionFromMyList} = this.props;
if (checked) {
addAccessionToMyList(accession.uuid);
} else {
......@@ -73,7 +78,12 @@ class BrowsePage extends React.Component<IBrowsePageProps, any> {
}
public render() {
const { t, error, accession, uuid, doi, accessions } = this.props;
const { t, error, uuid, doi, accessions } = this.props;
const {details: accession, pdci, datasets, subsets} = this.props.accession ?
this.props.accession
:
{details: null, pdci: null, datasets: null, subsets: null};
const isChecked = accession && accessions && accessions.includes(accession.uuid);
const theDoi = `10.${doi}`;
const stillLoading: boolean = ! error && (! accession
......@@ -159,15 +169,16 @@ class BrowsePage extends React.Component<IBrowsePageProps, any> {
<PropertiesItem title="Provided crop name">{ accession.cropName }</PropertiesItem>
</Properties>
</PageSection>
<PageSection title="Accession names">
<Properties>
{ accession.donorCode && <PropertiesItem title={ t('accession.alias.DONORNUMB') }>{ accession.donorNumb } { accession.donorCode }</PropertiesItem> }
{ accession.aliases && accession.aliases.map((alias) => (
<PropertiesItem key={ alias.id } title={ t(`accession.alias.${alias.aliasType}`) }>{ alias.name } { alias.usedBy }</PropertiesItem>
)) }
</Properties>
</PageSection>
{ accession.donorCode || (accession.aliases && accession.aliases.length > 0) &&
<PageSection title="Accession names">
<Properties>
{ accession.donorCode && <PropertiesItem title={ t('accession.alias.DONORNUMB') }>{ accession.donorNumb } { accession.donorCode }</PropertiesItem> }
{ accession.aliases && accession.aliases.map((alias) => (
<PropertiesItem key={ alias.id } title={ t(`accession.alias.${alias.aliasType}`) }>{ alias.name } { alias.usedBy }</PropertiesItem>
)) }
</Properties>
</PageSection>
}
{ accession.coll &&
<PageSection title="Collecting information">
......@@ -216,24 +227,7 @@ class BrowsePage extends React.Component<IBrowsePageProps, any> {
</Properties>
</PageSection> }
{ accession.pdci && <PageSection title="Passport Data Completeness Index">
<div style={ { marginBottom: '2em', padding: '2em', backgroundColor: '#b6c1b4', borderRadius: '6px' } }>
<span style={ { fontSize: '1.5em' } }>
{ t('accession.pdciScore', { score: accession.pdci.score }) }
{ /*<p>{ t(`accession.pdciInstitute`, { score: accession.pdci.score }) }</p>*/ }
</span>
{ ' ' }
<a href="#">Read about Passport Data Completeness Index</a>
</div>
<Properties>
{ accession.pdci.independentItems.map((item) => (
<PropertiesItem small key={ item } title={ item.toUpperCase() }>{ accession.pdci[item] }</PropertiesItem>
)) }
{ accession.pdci.dependentItems.map((item) => (
<PropertiesItem small key={ item } title={ item.toUpperCase() }>{ accession.pdci[item] }</PropertiesItem>
)) }
</Properties>
</PageSection> }
{ pdci && <PdciTable pdci={ pdci } title="Passport Data Completeness Index"/> }
<PageSection title="Metadata">
<Properties>
......@@ -243,6 +237,25 @@ class BrowsePage extends React.Component<IBrowsePageProps, any> {
<PropertiesItem title="Created"><PrettyDate value={ accession.createdDate } /></PropertiesItem>
</Properties>
</PageSection>
<GridLayout>
{ datasets && datasets.length > 0 &&
<PropertiesCard
small
title="Associated datasets"
propertyItemProps={ {keepEmpty: true} }
propertiesList={ datasets.map((dataset) => ({title: <DatasetLink to={ dataset } />, value: ''})) }
/>
}
{ subsets && subsets.length > 0 &&
<PropertiesCard
small
title="Associated Subsets"
propertyItemProps={ {keepEmpty: true} }
propertiesList={ subsets.map((subset) => ({title: <SubsetLink to={ subset } />, value: ''})) }
/>
}
</GridLayout>
</PageContents>
}
</div>
......
import * as React from 'react';
import {translate} from 'react-i18next';
// model
import PDCI from 'model/PDCI';
// UI
import Grid from '@material-ui/core/Grid';
import withWidth from '@material-ui/core/withWidth';
import {Breakpoint} from '@material-ui/core/styles/createBreakpoints';
import {Properties, PropertiesItem} from 'ui/common/Properties';
import {PageSection} from 'ui/layout/PageLayout';
interface IPdciTableProps extends React.ClassAttributes<any> {
children?: any;
width: Breakpoint;
pdci: PDCI;
title: string;
small?: boolean;
t: any;
}
const mobile = ['sm', 'xs'] as Breakpoint[];
class PdciTable extends React.Component<IPdciTableProps, any> {
private getColumnStyle = (columnIndex) => {
const columnsAmount = 3;
const firstColumnMargin = '0 8px 0 0';
const middleColumnMargin = '0 8px';
const lastColumnMargin = '0 0 0 8px';
let margin;
switch (columnIndex % columnsAmount) {
case 0:
margin = firstColumnMargin;
break;
case columnsAmount - 1:
margin = lastColumnMargin;
break;
default:
margin = middleColumnMargin;
break;
}
const width = `calc(${(100 / columnsAmount)}% - 12px)`;
return {margin, width};
}
public render() {
const {pdci, title, small = false, t, width} = this.props;
const isMobile = mobile.indexOf(width) !== -1;
return (
<Grid item lg={ small ? 6 : 12 } md={ 12 } xs={ 12 }>
<PageSection title={ title }>
<Grid>
<div style={ {marginBottom: '2em', padding: '2em', backgroundColor: '#e7e7e7', borderRadius: '6px'} }>
<span style={ {fontSize: '1.5em'} }>
{ t('accession.pdciScore', {score: pdci.score}) }
</span>
{ ' ' }
<a href="#">Read about Passport Data Completeness Index</a>
</div>
</Grid>
<Grid container justify={ 'center' } spacing={ 16 }>
<Grid item sm={ 12 } style={ {width: '100%'} }>
<Properties>
{
[...pdci.independentItems, ...pdci.dependentItems].map((property, i) => (
<Grid item style={ !isMobile ? this.getColumnStyle(i) : {width: '100%'} } key={ `${i}-${property}` }>
<PropertiesItem numeric keepEmpty title={ property.toUpperCase() }>
{ pdci[property] && t(`common:label.prettyNumber`, {value: pdci[property]}) }
</PropertiesItem>
</Grid>
))
}
</Properties>
</Grid>
</Grid>
</PageSection>
</Grid>
);
}
}
export default translate()(withWidth()(PdciTable));
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment