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

Added Subset and Dataset support

- add dataset list and details page
- add subset list and details page
- use filter from config
- add translations
parent 2f96278a
......@@ -31,6 +31,12 @@
<li class="nav-item">
<a class="nav-link" href="#/cart">Cart</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#/subsets">Subsets</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#/datasets">Datasets</a>
</li>
<li class="nav-item">
<a class="nav-link" href=".">EN</a>
</li>
......
......@@ -38,6 +38,12 @@
<li class="nav-item">
<a class="nav-link" href="#/map">Map</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#/subsets">Subsets</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#/datasets">Datasets</a>
</li>
<li class="nav-item">
<a class="nav-link" href="index.html">EN</a>
</li>
......
import React from 'react';
import { connect } from 'react-redux';
import {Link} from "react-router-dom";
import { AccessionService } from '@genesys-pgr/client/service';
import { Property } from 'ui/common/Property';
......@@ -281,7 +282,7 @@ class AccessionDetailsPage extends React.Component<AccessionDetailsPageProps & W
<h2 className="mt-4">{ t('accession.subsets') }</h2>
{ accession.subsets.map((subset, idx) => (
<div key={ idx }>
<a target="_blank" href= { `${publicWebsiteUrl}/subsets/${subset.uuid}` }>{ subset.title }</a>
<Link to={`/subsets/${subset.uuid}` }>{ subset.title }</Link>
<p>{ subset.description }</p>
</div>
)) }
......
import React from 'react';
import {useTranslation} from 'react-i18next';
import {useSelector} from "react-redux";
import {Link} from "react-router-dom";
// model
import Dataset from "@genesys-pgr/client/model/catalog/Dataset";
import Accession from "@genesys-pgr/client/model/accession/Accession";
// service
import {AccessionService, DatasetService} from '@genesys-pgr/client/service';
// ui
import {Property} from 'ui/common/Property';
import Loading from 'ui/common/Loading';
import PageTitle from 'ui/common/PageTitle';
interface DatasetDetailsPageProps {
match: any;
}
const DatasetDetailsPage = ({match}: DatasetDetailsPageProps) => {
// util
const {t} = useTranslation();
// state
const [dataset, setDataset] = React.useState<Dataset>();
const [accessions, setAccessions] = React.useState<Accession[]>();
const loadData = React.useCallback((uuid: string): Promise<void> => {
return DatasetService
.getDataset(uuid)
.then((data) => {
console.log('dataset: ', data);
setDataset(data);
AccessionService
.list({datasets: [data.uuid]}, {page: 0})
.then((accessions) => setAccessions(accessions.content));
})
.catch((e) => {
console.log('Api call failed: ', e);
});
}, []);
// redux
const publicWebsiteUrl = useSelector((state: any) => state?.apiInfo?.apiInfo?.publicWebsiteUrl);
React.useEffect(() => {
loadData(match.params.uuid);
}, [loadData, match.params])
if (!dataset) {
return (
<>
<PageTitle title={t('loading')}/>
<Loading/>
</>
);
}
let propertyIndex = 0;
return (
<>
<PageTitle title={t('pagetitle.dataset', {datasetTitle: dataset.title})}/>
<div className="d-flex justify-content-between align-items-center">
<h1>{dataset.title}</h1>
</div>
{dataset.title &&
<Property
title={t('dataset.title')} value={<p>{dataset.title}</p>}
index={propertyIndex++}
/>
}
{dataset.description &&
<Property
title={t('dataset.description')} value={<p>{dataset.description}</p>}
index={propertyIndex++}
/>
}
{dataset.owner &&
<Property
title={t('dataset.dataProvider.title')}
value={<a href={`${publicWebsiteUrl}/p/${dataset.owner.uuid}`}>{dataset.owner.name}</a>}
index={propertyIndex++}
/>
}
{dataset.crops && dataset.crops.length > 0 &&
<Property
title={t('dataset.cropName')} value={<p>{dataset.crops.join(', ')}</p>}
index={propertyIndex++}
/>
}
{!!dataset.accessionCount &&
<Property
title={t('dataset.accessionCount')} value={<p>{dataset.accessionCount}</p>}
index={propertyIndex++}
/>
}
{!!dataset.descriptorCount &&
<Property
title={t('dataset.traitCount')} value={<p>{dataset.descriptorCount}</p>}
index={propertyIndex++}
/>
}
{!!dataset.startDate &&
<Property
title={t('dataset.startDate')} value={<p>{dataset.startDate}</p>}
index={propertyIndex++}
/>
}
{!!dataset.endDate &&
<Property
title={t('dataset.endDate')} value={<p>{dataset.endDate}</p>}
index={propertyIndex++}
/>
}
{dataset.language &&
<Property
title={t('dataset.language')} value={<p>{dataset.language}</p>}
index={propertyIndex++}
/>
}
{dataset.format &&
<Property
title={t('dataset.format')} value={<p>{dataset.format}</p>}
index={propertyIndex++}
/>
}
{dataset.source &&
<Property
title={t('dataset.source')} value={<a href={dataset.source}>{dataset.source}</a>}
index={propertyIndex++}
/>
}
{dataset.creators && dataset.creators.length > 0 && (
<>
<Property
title={t('dataset.details.creators')}
value={
<ul>
{dataset.creators.map((creat) => (
<li key={creat.id}><b>{creat.role}</b>{` ${creat.fullName} - ${creat.instituteAddress} `}</li>
))}
</ul>
}
index={propertyIndex++}
/>
</>
)}
{dataset.locations && dataset.locations.length > 0 && (
<>
<h2 className="mt-4">{t('dataset.details.locations')}</h2>
<Property
title={t('dataset.locations')}
value={
<ul>
{dataset.locations.map((location) => (
<li key={location.id}>
<b>{`${location.mapCountry || location.userCountry} `}</b>
({location.decimalLatitude.toFixed(2)};{location.decimalLongitude.toFixed(2)})
</li>
))}
</ul>
}
index={propertyIndex++}
/>
</>
)}
{dataset.owner && (
<>
<h2 className="mt-4">{t('dataset.details.dataProvider')}</h2>
{dataset.owner.name &&
<Property
title={t('dataset.dataProvider.name')}
value={dataset.owner.name}
index={propertyIndex++}
/>
}
{dataset.owner.email &&
<Property
title={t('dataset.dataProvider.email')}
value={dataset.owner.email}
index={propertyIndex++}
/>
}
{dataset.owner.address &&
<Property
title={t('dataset.dataProvider.address')}
value={dataset.owner.address}
index={propertyIndex++}
/>
}
</>
)}
<h2 className="mt-4">{t('dataset.details.metadata')}</h2>
<Property title={t('dataset.uuid')} value={`urn:uuid:${dataset.uuid}`} index={propertyIndex++}/>
<Property
title={t('dataset.createDate')}
value={dataset.createdDate}
index={propertyIndex++}
/>
<Property
title={t('dataset.lastModified')}
value={dataset.lastModifiedDate}
index={propertyIndex++}
/>
{dataset.descriptors && dataset.descriptors.length > 0 &&
<Property
title={t('dataset.descriptors')}
value={
<ul>
{dataset.descriptors.map((descr) => (
<li key={descr.id}><a href={`${publicWebsiteUrl}/descriptors/${descr.uuid}`}>{`${descr.title}`}</a></li>
))}
</ul>
}
index={propertyIndex++}
/>}
{accessions && accessions.length > 0 && (
<>
<h2 className="mt-4">{t('dataset.details.accessions')}</h2>
<Property
title={t('dataset.accessions')}
value={(
<ul>{accessions.map((acc) => (
<li key={acc.id}><Link to={`/a/${acc.uuid}`}>{acc.accessionNumber}</Link></li>
))}
</ul>
)}
index={propertyIndex++}
/>
</>
)}
</>
);
};
export default DatasetDetailsPage;
\ No newline at end of file
import React, {useState} from 'react';
import {useTranslation} from 'react-i18next';
// model
import DatasetFilter from "@genesys-pgr/client/model/catalog/DatasetFilter";
interface DatasetFiltersProps {
filter: DatasetFilter;
applyFilter: (filter: Partial<DatasetFilter>) => void;
}
export function DatasetFilters({filter, applyFilter}: DatasetFiltersProps) {
const {t} = useTranslation();
const [text, setText] = useState(filter._text || '');
const handleSubmit = (e) => {
e.preventDefault();
console.log('------------')
applyFilter({
_text: text,
});
};
const onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setText(e.target.value);
};
return (
<form className="form-inline mb-4" onSubmit={handleSubmit}>
<div className="form-group mx-sm-2">
<label className="mr-2">{t('accession.filters.fullText')}</label>
<input name="full-text-search" type="text" className="form-control" value={text}
onChange={onInputChange}/>
</div>
<button className="btn btn-primary" type="submit">{t('action.submit')}</button>
</form>
);
}
import * as React from "react";
import {Link} from "react-router-dom";
import {useTranslation} from "react-i18next";
// model
import {IPageRequest} from "@genesys-pgr/client/model/Page";
import FilteredPage from "@genesys-pgr/client/model/FilteredPage";
import DatasetFilter from "@genesys-pgr/client/model/catalog/DatasetFilter";
import Dataset from "@genesys-pgr/client/model/catalog/Dataset";
import {Config} from "config/config";
// service
import {DatasetService} from "@genesys-pgr/client/service";
// ui
import PageTitle from "ui/common/PageTitle";
import Pagination from "ui/common/Pagination";
import {DatasetFilters} from "dataset/DatasetFilters";
// util
import {parseLocationSearch} from "utilities/filterUtil";
import {useSelector} from "react-redux";
interface IDatasetListPageProps {
location: any;
}
const DatasetListPage = ({location}: IDatasetListPageProps) => {
// util
const {t} = useTranslation();
// redux
const appConfig: Config = useSelector((state: any) => state?.appConfig?.config);
// state
const [datasets, setDatasets] = React.useState<FilteredPage<Dataset, DatasetFilter>>();
const [filter, setFilter] = React.useState<DatasetFilter>(appConfig.filter);
const loadData = React.useCallback((filter: string | DatasetFilter, pageR: IPageRequest): Promise<FilteredPage<Dataset, DatasetFilter>> => {
return DatasetService
.datasetList(filter, pageR)
.then((data) => {
setDatasets(data);
setFilter(data.filter);
return data;
})
.catch((e) => {
console.log('Api call failed: ', e);
return null;
});
}, []);
const applyFilter = React.useCallback((newFilter: DatasetFilter) => {
loadData({...filter, ...newFilter}, {});
}, [filter, loadData]);
// effect
React.useEffect(() => {
const {current, filterCode} = parseLocationSearch(location);
if (!datasets || datasets?.filterCode !== filterCode) {
loadData(filterCode || filter || datasets?.filter, current ? {page: current} : {});
}
}, [datasets, filter, loadData, location])
return datasets ? (
<>
<PageTitle title={t('pagetitle.datasetList')}/>
<h1 className="d-flex justify-content-between align-items-center">
{t('estimatedNumberOfItems', {
count: datasets.totalElements,
what: t('dataset.model', {count: datasets.totalElements})
})}
</h1>
<DatasetFilters
filter={filter}
applyFilter={applyFilter}
key={`filters-${datasets.filterCode}`}
/>
<Pagination loadData={loadData} paged={datasets} prefix="/datasets">
<table className="table table-striped">
<thead className="thead-dark">
<tr>
<th>{t('dataset.title')}</th>
<th>{t('dataset.crops')}</th>
<th>{t('dataset.traitCount')}</th>
<th>{t('dataset.accessionCount')}</th>
</tr>
</thead>
<tbody>
{datasets.content.map((d) => (
<tr key={d.id}>
<td><Link to={`/datasets/${d.uuid}`}>{d.title}</Link></td>
<td>{d.crops && d.crops.length > 0 && <p>{d.crops.join(', ')}</p>}</td>
<td>{d.descriptorCount}</td>
<td>{d.accessionCount}</td>
</tr>
))}
</tbody>
</table>
</Pagination>
</>
) : null;
};
export default DatasetListPage;
......@@ -17,7 +17,11 @@
"accession": "Accession {{accessionNumber}}",
"cart": "Cart",
"overview": "Collection overview",
"apiInfo": "API information"
"apiInfo": "API information",
"datasetList": "Dataset list",
"dataset": "Dataset {{datasetTitle}}",
"subsetList": "Subset list",
"subset": "Subset {{subsetTitle}}"
},
"error": {
"notFound": "Not Found",
......@@ -218,6 +222,61 @@
"isEmpty": "Shopping cart is empty",
"request": "Request material"
},
"dataset": {
"model": "Dataset",
"model_plural": "Datasets",
"title": "Title",
"dataProvider": {
"title": "Data provider",
"name": "Data provider name",
"email": "Email",
"address": "Address"
},
"description": "Description",
"uuid": "Record UUID",
"crops": "Crops",
"cropName": "Crop name",
"traitCount": "Trait count",
"accessionCount": "Accession count",
"startDate": "Start of evaluation",
"endDate": "End of evaluation",
"language": "Language",
"locations": "Locations",
"format": "Format",
"descriptors": "Traits",
"source": "More information",
"createDate": "Metadata create date",
"lastModified": "Metadata updated date",
"accessions": "Accessions",
"details": {
"creators": "Dataset creators",
"dataProvider": "Data provider contact information",
"metadata": "Other metadata",
"accessions": "Accessions",
"traits": "Traits Observed",
"locations": "Location information"
}
},
"subset": {
"model": "Subset",
"model_plural": "Subset",
"title": "Title",
"description": "Description",
"accessionCount": "Accession count",
"source": "More information",
"uuid": "Record UUID",
"crops": "Crops",
"createDate": "Metadata create date",
"creators": "Subset creators",
"lastModified": "Metadata updated date",
"institute": "Institute",
"accessions": "Accessions",
"details": {
"dataProvider": "Data provider contact information",
"metadata": "Other metadata",
"accessions": "Accessions"
}
},
"request": {
"title": "Personal information",
"submit": "Submit request",
......
import React from 'react';
import {Link} from 'react-router-dom';
import {useTranslation} from 'react-i18next';
import {useSelector} from "react-redux";
// model
import Subset from "@genesys-pgr/client/model/subset/Subset";
import Accession from "@genesys-pgr/client/model/accession/Accession";
// service
import {AccessionService, SubsetService} from '@genesys-pgr/client/service';
// ui
import {Property} from 'ui/common/Property';
import Loading from 'ui/common/Loading';
import PageTitle from 'ui/common/PageTitle';
interface SubsetDetailsPageProps {
match: any;
publicWebsiteUrl: string;
}
const SubsetDetailsPage = ({match}: SubsetDetailsPageProps) => {
// util
const {t} = useTranslation();
// state
const [subset, setSubset] = React.useState<Subset>();
const [accessions, setAccessions] = React.useState<Accession[]>();
// redux
const publicWebsiteUrl = useSelector((state: any) => state?.apiInfo?.apiInfo?.publicWebsiteUrl);
const loadData = React.useCallback((uuid: string): Promise<void> => {
return SubsetService
.get(uuid)
.then((data) => {
console.log('subset: ', data);
setSubset(data);
AccessionService
.list({subsets: [data.uuid]}, {page: 0})
.then((accessions) => setAccessions(accessions.content));
})
.catch((e) => {
console.log('Api call failed: ', e);
});
}, []);
React.useEffect(() => {
loadData(match.params.uuid);
}, [loadData, match.params])
if (!subset) {
return (
<>
<PageTitle title={t('loading')}/>
<Loading/>
</>
);
}
let propertyIndex = 0;
return (
<>
<PageTitle title={t('pagetitle.subset', {subsetTitle: subset.title})}/>
<div className="d-flex justify-content-between align-items-center">
<h1>{subset.title}</h1>