Commit 12c58d14 authored by Matija Obreza's avatar Matija Obreza

Merge branch '725-diversity-trees-public-pages' into 'master'

Diversity trees: Public pages

Closes #725

See merge request genesys-pgr/genesys-ui!714
parents 0ffacb5b d41cf94e
......@@ -20,6 +20,7 @@ enum CreatorRole {
COLLECTOR = 'COLLECTOR',
DIGITIZER = 'DIGITIZER',
CURATOR = 'CURATOR',
CONTRIBUTOR = 'CONTRIBUTOR',
}
export { DiversityTreeCreator as default, CreatorRole };
......@@ -46,6 +46,7 @@ class AccessionFilter {
public subsets?: string[];
public datasets?: string[];
public networks?: string[];
public nodeKey?: string;
public NOT?: AccessionFilter;
public NULL?: string[];
......
......@@ -5,6 +5,7 @@ import RepositoryFile from '@genesys/client/model/repository/RepositoryFile';
import Dataset from '@genesys/client/model/catalog/Dataset';
import Subset from '@genesys/client/model/subset/Subset';
import DescriptorList from '@genesys/client/model/catalog/DescriptorList';
import DiversityTree from '@genesys/client/model/DiversityTree';
/*
* Defined in Swagger as '#/definitions/CropDetails'
......@@ -18,6 +19,7 @@ class CropDetails extends Crop {
public recentDatasets: Dataset[];
public recentSubsets: Subset[];
public recentDescriptorLists: DescriptorList[];
public diversityTrees: DiversityTree[];
}
......
......@@ -72,7 +72,7 @@ class CSV {
// }
public static detectSeparator(lines: string[]): string {
const symbols = CSV.getAllNonLetterAndDigitSymbols(lines);
const symbols = CSV.getAllNonLetterAndDigitSymbols(lines, /[\t,]/g); // tabs or commas?
const separators: Char[] = [];
symbols.forEach((symbol) => separators.push(new Char(symbol)));
......@@ -101,7 +101,7 @@ class CSV {
public static detectQuoteChar(lines: string[], separator: string): string {
const columnValues: string[] = CSV.getColumnValues(lines, separator);
const symbols = CSV.getAllNonLetterAndDigitSymbols(lines);
const symbols = CSV.getAllNonLetterAndDigitSymbols(lines, /["']/g);
const quoteChars: Char[] = [];
columnValues.forEach((value) => {
......@@ -208,9 +208,8 @@ class CSV {
}
// scans
private static getAllNonLetterAndDigitSymbols(lines: string[]): string[] {
private static getAllNonLetterAndDigitSymbols(lines: string[], regexp = /[^A-Za-z0-9]/g): string[] {
const symbols: string[] = [];
const regexp = /[^A-Za-z0-9]/g;
lines.forEach((row) => {
if (row !== '') {
let result = regexp.exec(row);
......
......@@ -1120,7 +1120,8 @@
"holdingInstitutes": "Holding institutes",
"countryOfInstitutes": "Country of holding institute",
"representedGenera": "Most represented Genera",
"representedSpecies": "Most represented Species"
"representedSpecies": "Most represented Species",
"diversityTrees": "Diversity trees"
},
"browse": {
"title": "Crop list",
......@@ -1775,7 +1776,7 @@
"currentVersion": "Current version"
},
"diversityTreeDisplay": {
"divTreeCreators": "Diversity tree creators",
"divTreeContributors": "Diversity tree contributors",
"rematch": "Rematch accessions",
"diversityTreeMetadata": "Diversity tree metadata",
"dataAndResources": "Data and resources",
......@@ -1788,7 +1789,14 @@
"map": "Accession map",
"mapDescription": "Explore diversity tree accessions on the map",
"browse": "Filter accessions",
"browseDescription": "Apply custom filters to accessions in this diversity tree"
"browseDescription": "Apply custom filters to accessions in this diversity tree",
"view": "View",
"info": "Info"
},
"treeExplorer": {
"nodeKey": "Node key: {{what}}",
"accessionList": "Accession list",
"noAccessions": "No accessions"
}
},
"f": {
......@@ -1853,7 +1861,6 @@
},
"creators": {
"stepName": "Diversity tree creators",
"Role": "Role: ",
"fullName": "Full name",
"fullNamePlaceholder": "Jane A. Doe",
"institutionalAffiliation": "Institutional affiliation",
......@@ -1888,10 +1895,7 @@
"stats_plural": "Diversity trees",
"creators": {
"role": {
"MANAGER": "Data manager",
"DIGITIZER": "Data digitizer",
"COLLECTOR": "Data collector",
"CURATOR": "Data curator",
"CONTRIBUTOR": "Contributor",
"null": "Not specified"
},
"roledesc": {
......
......@@ -24,7 +24,8 @@
"holdingInstitutes": "Holding institutes",
"countryOfInstitutes": "Country of holding institute",
"representedGenera": "Most represented Genera",
"representedSpecies": "Most represented Species"
"representedSpecies": "Most represented Species",
"diversityTrees": "Diversity trees"
},
"browse": {
"title": "Crop list",
......
......@@ -16,6 +16,7 @@ import { showSnackbar } from 'actions/snackbar';
// Models
import Crop from '@genesys/client/model/genesys/Crop';
import CropDetails from '@genesys/client/model/genesys/CropDetails';
import RepositoryFile from '@genesys/client/model/repository/RepositoryFile';
// UI
import PageLayout, { PageContents, MainSection } from 'ui/layout/PageLayout';
......@@ -38,9 +39,8 @@ import { IPageRequest } from '@genesys/client/model/Page';
import ErrorMessage from 'ui/common/error/ErrorMessage';
import ImageGalleryView from 'repository/ui/c/ImageGalleryView';
import TreePreviewer from 'crop/ui/c/TreePreviewer';
import RepositoryFile from '@genesys/client/model/repository/RepositoryFile';
import { ScrollToTopOnMount } from 'ui/common/page/scrollers';
import { DatasetLink, SubsetLink } from 'ui/genesys/Links';
import { DatasetLink, DiversityTreeLink, SubsetLink } from 'ui/genesys/Links';
import { DescriptorListLink } from 'ui/catalog/Links';
import { Grid } from '@material-ui/core';
......@@ -68,7 +68,6 @@ interface IDisplayPageProps extends React.ClassAttributes<any>, WithTranslation
applyOverviewFilters: (filters: string | AccessionFilter, page?: IPageRequest) => void;
showSnackbar: (snack: string) => void;
repositoryDownloadUrl: (file: RepositoryFile) => string;
treeData: object;
}
class DisplayPage extends React.Component<IDisplayPageProps, any> {
......@@ -92,6 +91,7 @@ class DisplayPage extends React.Component<IDisplayPageProps, any> {
this.setState({ treesData: null });
}
// todo: remove when migration to cropDetails.diversityTrees will be finished
if (typeof window !== 'undefined') {
if (cropDetails && cropDetails.files && cropDetails.shortName === shortName) {
console.log(`Crop files`, cropDetails.files);
......@@ -108,7 +108,6 @@ class DisplayPage extends React.Component<IDisplayPageProps, any> {
}
}
}
}
public componentDidUpdate(prevProps: IDisplayPageProps) {
......@@ -173,6 +172,7 @@ class DisplayPage extends React.Component<IDisplayPageProps, any> {
public render() {
const { cropDetails, error, shortName, classes, t } = this.props;
const { treesData } = this.state;
const crop = cropDetails;
return (
......@@ -257,7 +257,12 @@ class DisplayPage extends React.Component<IDisplayPageProps, any> {
/>
}
{ treesData && treesData.map((tree) => (tree && tree.treeData.children && tree.treeData.children.length > 0 &&
<TreePreviewer key={ tree.treeFile.uuid } source={ tree.treeFile } treeData={ tree.treeData } name={ tree.treeFile.subject || tree.treeFile.title || crop.name } />
<TreePreviewer
key={ tree.treeFile.uuid }
treeFile={ tree.treeFile }
treeData={ tree.treeData }
name={ tree.treeFile.subject || tree.treeFile.title || crop.name }
/>
))}
</GridContainer >
}
......@@ -314,6 +319,21 @@ class DisplayPage extends React.Component<IDisplayPageProps, any> {
/>
</Grid>
}
{ cropDetails.diversityTrees && cropDetails.diversityTrees.length > 0 &&
<Grid item lg={ 4 } xs={ 12 } style={ { minHeight: '100%' } }>
<PropertiesCard
style={ {height: '100%'} }
title={ t('crop.public.p.display.diversityTrees') }
propertyItemProps={ { keepEmpty: true } }
propertiesList={
cropDetails.diversityTrees
.map((diversityTree) => (
{ value: <DiversityTreeLink to={ diversityTree }/> }
))
}
/>
</Grid>
}
</GridContainer>
</PageContents>
}
......
......@@ -6,6 +6,7 @@ interface IConfiguredTreeProps extends React.ClassAttributes<any> {
treeData: any[];
initialZoom: number;
zoomable?: boolean;
nodeLabelComponent?: { render: React.ReactNode, foreignObjectWrapper: Record<string, number | string> };
}
class ConfiguredTree extends React.Component<IConfiguredTreeProps, any> {
......@@ -16,11 +17,12 @@ class ConfiguredTree extends React.Component<IConfiguredTreeProps, any> {
if (typeof window !== 'undefined') {
Tree = require('react-d3-tree').Tree;
}
this.state = {
translate: null,
};
}
public state = {
translate: null,
};
public componentDidMount() {
if (this.treeContainer) {
const dimensions = this.treeContainer.getBoundingClientRect();
......@@ -34,7 +36,7 @@ class ConfiguredTree extends React.Component<IConfiguredTreeProps, any> {
}
public render() {
const {treeData, initialZoom, zoomable = false} = this.props;
const { treeData, initialZoom, zoomable = false, nodeLabelComponent } = this.props;
return (
<div style={ { height: '100%' } } ref={ (ref) => this.treeContainer = ref }>
......@@ -85,6 +87,8 @@ class ConfiguredTree extends React.Component<IConfiguredTreeProps, any> {
textAnchor: 'start',
y: 0,
} }
allowForeignObjects={ !!nodeLabelComponent }
nodeLabelComponent={ nodeLabelComponent }
/>
}
</div>
......
......@@ -18,7 +18,7 @@ import {
// Model
import DiversityTree from '@genesys/client/model/DiversityTree';
import DiversityTreeAccessionRef from '@genesys/client/model/DiversityTreeAccessionRef';
import DiversityTreeCreator from '@genesys/client/model/DiversityTreeCreator';
import DiversityTreeCreator, { CreatorRole } from '@genesys/client/model/DiversityTreeCreator';
// Service
import AccessionService from '@genesys/client/service/genesys/AccessionService';
......@@ -26,6 +26,7 @@ import DiversityTreeService from '@genesys/client/service/genesys/DiversityTreeS
// UI
import steps from 'divtree/ui/dashboard/diversity-tree-stepper/steps';
import { clearDiversityTree } from 'divtree/actions/public';
// Wrapped API Calls
const apiAddAccessions = createApiCaller(DiversityTreeService.addAccessions, DASHBOARD_RECEIVE_DIVERSITY_TREE);
......@@ -105,6 +106,7 @@ export const unpublishDiversityTree = (divtree: DiversityTree) => (dispatch) =>
};
export const approveDiversityTree = (divtree: DiversityTree) => (dispatch) => {
dispatch(clearDiversityTree());
return dispatch(apiApproveDiversityTrees([divtree]));
};
......@@ -117,6 +119,7 @@ export const createDiversityTreeCreator = () => (dispatch, getState) => {
const currentDiversityTree = getState().divtree.dashboard.divtree && getState().divtree.dashboard.divtree.data;
const creator = new DiversityTreeCreator();
creator.fullName = '';
creator.role = CreatorRole.CONTRIBUTOR;
return dispatch(apiCreateDiversityTreeCreator(currentDiversityTree.uuid, creator));
};
......
......@@ -4,9 +4,10 @@
// Actions
import navigateTo from 'actions/navigation';
import {filterCodeToUrl} from 'actions/filterCode';
import { filterCodeToUrl } from 'actions/filterCode';
// import { showSnackbar } from 'actions/snackbar';
import {createApiCaller} from 'actions/ApiCall';
import { createApiCaller , createPureApiCaller } from 'actions/ApiCall';
import { apiDeleteDiversityTrees, apiRejectDiversityTrees } from 'divtree/actions/editor';
// Constants
import {
......@@ -15,15 +16,18 @@ import {
CLEAR_DIVERSITY_TREE,
} from 'divtree/constants';
// Service
import AccessionService from '@genesys/client/service/genesys/AccessionService';
import DiversityTreeService from '@genesys/client/service/genesys/DiversityTreeService';
// Model
import FilteredPage from '@genesys/client/model/FilteredPage';
import DiversityTreeService from '@genesys/client/service/genesys/DiversityTreeService';
import Page from '@genesys/client/model/Page';
import {AccessionRef} from '@genesys/client/model/accession/AccessionRef';
import OpResponse from '@genesys/client/model/OpResponse';
import { apiDeleteDiversityTrees, apiRejectDiversityTrees } from 'divtree/actions/editor';
import DiversityTree from '@genesys/client/model/DiversityTree';
import Accession from '@genesys/client/model/accession/Accession';
// Wrapped API Calls
const apiListDiversityTreeAccessions = createApiCaller(DiversityTreeService.listAccessions, APPEND_DIVERSITY_TREE_ACCESSIONS);
const apiLoadDiversityTree = createApiCaller(DiversityTreeService.get, RECEIVE_DIVERSITY_TREE);
......@@ -32,6 +36,8 @@ const apiRematchAccessions = createApiCaller(DiversityTreeService.rematchAccessi
const apiRejectDiversityTree = createApiCaller(DiversityTreeService.reject, RECEIVE_DIVERSITY_TREE);
const apiApproveDiversityTree = createApiCaller(DiversityTreeService.approve, RECEIVE_DIVERSITY_TREE);
const apiLoadNodeAccesisons = createPureApiCaller(AccessionService.list);
export const loadMoreAccessions = (uuid: string, paged?: Page<AccessionRef>) => (dispatch, getState) => {
return dispatch(apiListDiversityTreeAccessions(uuid, Page.nextPage(paged)));
};
......@@ -90,4 +96,12 @@ export const deleteDiversityTree = (divtree: DiversityTree) => (dispatch) => {
});
};
export const loadNodeAccessions = (uuid: string, nodeKey: string) => (dispatch) => {
const filter = { diversityTrees: [uuid], nodeKey };
return dispatch(apiLoadNodeAccesisons(filter, { page: 0 }));
};
export const loadMoreNodeAccessions = (paged: FilteredPage<Accession>) => (dispatch) => {
return dispatch(apiLoadNodeAccesisons(paged.filterCode, Page.nextPage(paged)));
};
......@@ -17,7 +17,7 @@ const publicRoutes = [
// },
// },
{
path: '/divtree/:uuid([a-z\\-0-9]+)',
path: '/divtree/:uuid([a-z\\-0-9]+)/:tab?',
component: Loadable({
loader: () => import(/* webpackMode:"lazy", webpackChunkName: "divtree" */'divtree/ui/DisplayPage'),
}),
......
......@@ -11,7 +11,7 @@
"currentVersion": "Current version"
},
"diversityTreeDisplay": {
"divTreeCreators": "Diversity tree creators",
"divTreeContributors": "Diversity tree contributors",
"rematch": "Rematch accessions",
"diversityTreeMetadata": "Diversity tree metadata",
"dataAndResources": "Data and resources",
......@@ -24,7 +24,14 @@
"map": "Accession map",
"mapDescription": "Explore diversity tree accessions on the map",
"browse": "Filter accessions",
"browseDescription": "Apply custom filters to accessions in this diversity tree"
"browseDescription": "Apply custom filters to accessions in this diversity tree",
"view": "View",
"info": "Info"
},
"treeExplorer": {
"nodeKey": "Node key: {{what}}",
"accessionList": "Accession list",
"noAccessions": "No accessions"
}
},
"f": {
......@@ -89,7 +96,6 @@
},
"creators": {
"stepName": "Diversity tree creators",
"Role": "Role: ",
"fullName": "Full name",
"fullNamePlaceholder": "Jane A. Doe",
"institutionalAffiliation": "Institutional affiliation",
......@@ -124,10 +130,7 @@
"stats_plural": "Diversity trees",
"creators": {
"role": {
"MANAGER": "Data manager",
"DIGITIZER": "Data digitizer",
"COLLECTOR": "Data collector",
"CURATOR": "Data curator",
"CONTRIBUTOR": "Contributor",
"null": "Not specified"
},
"roledesc": {
......
......@@ -12,17 +12,14 @@ import { applyFiltersAsync as applyFilters, loadAccessionsMapInfo as applyMapFil
// models
import DiversityTree from '@genesys/client/model/DiversityTree';
import DiversityTreeAccessionRef from '@genesys/client/model/DiversityTreeAccessionRef';
// import Accession from 'model/accession/Accession';
import AccessionFilter from '@genesys/client/model/accession/AccessionFilter';
import { IPageRequest } from '@genesys/client/model/FilteredPage';
import Page from '@genesys/client/model/Page';
// import {AccessionRef} from 'model/accession/AccessionRef';
import { PublishState } from '@genesys/client/model/common.model';
// ui
import Grid from '@material-ui/core/Grid';
import Loading from 'ui/common/Loading';
import PagedLoader from 'ui/common/PagedLoader';
// import DownloadDialog, { DOWNLOAD_AUTH_SLUG } from 'ui/common/download-dialog';
import ButtonBar from 'ui/common/buttons/ButtonBar';
import { Button } from '@material-ui/core';
import Authorize from 'ui/common/authorized/Authorize';
......@@ -33,26 +30,20 @@ import Divider from '@material-ui/core/Divider/Divider';
import DiversityTreeCard from './DiversityTreeCard';
import Permissions from 'ui/common/permission/Permissions';
import DiversityTreeAccessionRefCard from './DiversityTreeAccessionRefCard';
// import ActionButton from 'ui/common/buttons/ActionButton';
const styles = (theme) => ({
section: {
marginTop: '16px',
},
accessionCard: {
// marginBottom: '8px',
},
buttonGreen: theme.buttons.green,
});
interface IDetailInfoProps extends React.ClassAttributes<any>, WithTranslation {
// listAccessions: (filter: string | AccessionFilter, page: IPageRequest) => Promise<Page<Accession>>;
unpublishDiversityTree: (divtree: DiversityTree) => void;
editDiversityTree: (divtree: DiversityTree) => void;
approveDiversityTree: (divtree: DiversityTree) => void;
deleteDiversityTree: (divtree: DiversityTree) => void;
// addAllToMyList: (divtree: DiversityTree) => Promise<any>;
classes: any;
divtree: DiversityTree;
......@@ -222,74 +213,71 @@ class DetailInfo extends React.Component<IDetailInfoProps, any> {
</ButtonBar>
) }
/>
<Grid container spacing={ 0 } className={ classes.section }>
<Grid item xs={ 12 }>
<Section title={ t('divtree.public.c.diversityTreeDisplay.diversityTreeMetadata') }>
{ divtree.creators && divtree.creators.length > 0 &&
<div>
<div className="pt-15 pb-15 pl-20 pr-20">
<h4 className="font-bold m-0">{ t('divtree.public.c.diversityTreeDisplay.divTreeCreators') }</h4>
</div>
<Divider/>
<Grid container spacing={ 0 } className="p-20">
<Grid item xs={ 12 }>
<Properties>
{ divtree.creators && divtree.creators.map((creator) => creator && (
<PropertiesItem title={ t(`divtree.common.creators.role.${creator.role}`) } key={ creator.id }>
<span>
<b>{ creator.fullName }</b>
{ creator.institutionalAffiliation && <span> { creator.institutionalAffiliation }</span> }
</span>
</PropertiesItem>
)) }
</Properties>
</Grid>
</Grid>
<Divider/>
</div>
}
<div>
<div className="pt-15 pb-15 pl-20 pr-20">
<h4 className="font-bold m-0">
{ t('divtree.public.c.diversityTreeDisplay.dataAndResources') }
</h4>
</div>
<Divider/>
<Grid container spacing={ 0 } className="p-20">
<Grid item xs={ 12 }>
<Properties>
{ /* <PropertiesItem key={ divtree.uuid } title={
<Authorize role="ROLE_USER" withTooltip>
<DownloadDialog
downloadUrl={ `${apiUrl}/api/v1/subset/${subset.uuid}/download` }
slug={ DOWNLOAD_AUTH_SLUG }
postParams={ {mcpd: 'mcpd'} }
buttonTitle={ `${t('common:action.download')} ${t('subsets.public.p.display.MCPD')}` }
variant="contained"
btnClasses={ classes.buttonGreen }
/>
</Authorize>
}>
<p>{ t(`subsets.public.c.subsetDisplay.mcpdPasportData`) }</p>
<p>{ `MCPD - ${subset.uuid}.xlsx` }</p>
</PropertiesItem> */ }
<PropertiesItem title={
<Button onClick={ this.onBrowseAccessions } variant="contained">{ t('divtree.public.c.diversityTreeDisplay.browse') }</Button>
}>
<p>{ t(`divtree.public.c.diversityTreeDisplay.browseDescription`) }</p>
</PropertiesItem>
<PropertiesItem title={
<Button onClick={ this.onShowMap } variant="contained">{ t('divtree.public.c.diversityTreeDisplay.map') }</Button>
}>
<p>{ t(`divtree.public.c.diversityTreeDisplay.mapDescription`) }</p>
</PropertiesItem>
</Properties>
</Grid>
</Grid>
</div>
</Section>
{ ((accessions && accessions.content && accessions.content.length !== 0) || (divtree.creators && divtree.creators.length > 0)) &&
<Grid container spacing={ 0 } className={ classes.section }>
<Grid item xs={ 12 }>
<Section title={ t('divtree.public.c.diversityTreeDisplay.diversityTreeMetadata') }>
{ divtree.creators && divtree.creators.length > 0 &&
<div>
<div className="pt-15 pb-15 pl-20 pr-20">
<h4 className="font-bold m-0">{t('divtree.public.c.diversityTreeDisplay.divTreeContributors')}</h4>
</div>
<Divider/>
<Grid container spacing={0} className="p-20">
<Grid item xs={12}>
<Properties>
{ divtree.creators && divtree.creators.map((creator) => creator && (
<PropertiesItem key={ creator.id }>
<span>
<b>{ creator.fullName }</b>
{ creator.institutionalAffiliation && <span> { creator.institutionalAffiliation }</span> }
</span>
</PropertiesItem>
)) }
</Properties>
</Grid>
</Grid>
<Divider/>
</div>
}
{ accessions && accessions.content && accessions.content.length !== 0 &&
<div>
<div className="pt-15 pb-15 pl-20 pr-20">
<h4 className="font-bold m-0">
{ t('divtree.public.c.diversityTreeDisplay.dataAndResources') }
</h4>
</div>
<Divider/>
<Grid container spacing={ 0 } className="p-20">
<Grid item xs={ 12 }>
<Properties>
<PropertiesItem
title={
<Button onClick={ this.onBrowseAccessions } variant="contained">
{ t('divtree.public.c.diversityTreeDisplay.browse') }
</Button>
}
>
<p>{ t(`divtree.public.c.diversityTreeDisplay.browseDescription`) }</p>
</PropertiesItem>
<PropertiesItem
title={
<Button onClick={ this.onShowMap } variant="contained">
{ t('divtree.public.c.diversityTreeDisplay.map') }
</Button>
}
>
<p>{ t(`divtree.public.c.diversityTreeDisplay.mapDescription`) }</p>
</PropertiesItem>
</Properties>
</Grid>
</Grid>
</div>
}
</Section>
</Grid>
</Grid>
</Grid>
}
<Grid container spacing={ 2 } className="mt-5" justify={ 'space-between' }>
{ ! accessions ? <Loading /> :
<Grid item xs={ 12 } className="p-10">
......@@ -297,9 +285,6 @@ class DetailInfo extends React.Component<IDetailInfoProps, any> {
<SectionHeader
title={ t('divtree.public.c.diversityTreeDisplay.accessions') }
subTitle={ t('divtree.public.c.diversityTreeDisplay.listOfAccessions') }
// actions={
// <ActionButton variant="contained" sync action={ this.addAllToMyListHandler } title={ t('accessions.public.c.accessionCard.addToMyList') } />
// }
/>
}
<PagedLoader
......
import * as React from 'react';
import { withStyles, WithStyles, createStyles } from '@material-ui/core/styles';
import { WithTranslation, withTranslation } from 'react-i18next';
// Model
import Accession from '@genesys/client/model/accession/Accession';
import FilteredPage from '@genesys/client/model/FilteredPage';
import Page from '@genesys/client/model/Page';
import ConfiguredTree from 'crop/ui/c/ConfiguredTree';
import Button from '@material-ui/core/Button';
import { throttle } from 'lodash';
import Card, { CardContent, CardHeader } from 'ui/common/Card';
import IconButton from '@material-ui/core/IconButton';
import CloseIcon from '@material-ui/icons/Close';
import PagedLoader from 'ui/common/PagedLoader';
import Loading from 'ui/common/Loading';
import AccessionCard from 'accessions/ui/c/AccessionCard';