Commit 4f6af264 authored by Viacheslav Pavlov's avatar Viacheslav Pavlov
Browse files

Accession display: Display audit log data

AccessionAuditLog moved to separate model, audit log now loads on click
parent 566dece5
......@@ -89,6 +89,8 @@
"name": "Name",
"newVersionAvailable": "New version available",
"no": "No",
"noChanges": "No changes yet",
"noValue": "No value",
"prettyNumber": "{{value, number}}",
"registered": "Registered",
"sortBy": "Sort By",
......
......@@ -369,6 +369,7 @@
"historic": "Historic accession",
"isHistoric": "This is a historic record of an accession",
"DOI": "DOI",
"loadChanges": "Show changes",
"acquisitionDate": "Acquisition Date",
"availability": "Availability for distribution",
"ITPGRFAMLS": "ITPGRFA MLS",
......
/**
* This is a top-level group for actions in /accessions/* routes.
*/
import * as _ from 'lodash';
import navigateTo from 'actions/navigation';
import FilteredPage, { IPageRequest } from 'model/FilteredPage';
import Accession from 'model/accession/Accession';
import AccessionFilter from 'model/accession/AccessionFilter';
import AccessionDetails from 'model/accession/AccessionDetails';
import AccessionMapInfo from 'model/accession/AccessionMapInfo';
import AccessionAuditLog from 'model/accession/AccessionAuditLog';
import { RECEIVE_ACCESSIONS, RECEIVE_ACCESSION, RECEIVE_ACCESSION_OVERVIEW, APPEND_ACCESSIONS, RECEIVE_ACCESSION_MAPINFO } from 'accessions/constants';
import { RECEIVE_ACCESSIONS, RECEIVE_ACCESSION, RECEIVE_ACCESSION_OVERVIEW, APPEND_ACCESSIONS, RECEIVE_ACCESSION_MAPINFO, RECEIVE_ACCESSION_AUDIT_LOG } from 'accessions/constants';
import AccessionService from 'service/genesys/AccessionService';
import { showSnackbar } from 'actions/snackbar';
import Page from 'model/Page';
......@@ -38,6 +40,12 @@ const receiveAccession = (accession: AccessionDetails, error = null) => ({
payload: { accession, error },
});
const receiveAccessionAuditLog = (auditLog: AccessionAuditLog, error = null) => ({
type: RECEIVE_ACCESSION_AUDIT_LOG,
payload: { auditLog, error },
});
export const updateRoute = (paged: FilteredPage<Accession>, path: string = '/a') => (dispatch) => {
const qs = {
s: paged.sort[0].property === Accession.DEFAULT_SORT.property ? undefined : paged.sort[0].property,
......@@ -164,6 +172,24 @@ export const loadAccession = ({ uuid, doi }: { uuid?: string, doi?: string }) =>
});
};
export const loadAccessionAuditLog = ({uuid, doi}: {uuid?: string, doi?: string}) => (dispatch) => {
const loader = doi ? AccessionService.getAccessionAuditLogByDoi : AccessionService.getAccessionAuditLogByUUID;
const lookup = doi ? doi : uuid;
return loader(lookup)
.then((auditLog) => {
if (_.isEmpty(auditLog.auditAccession) && _.isEmpty(auditLog.auditAccessionCollect) && _.isEmpty(auditLog.auditAccessionGeo) && _.isEmpty(auditLog.auditAccessionId)) {
return dispatch(showSnackbar('common:label.noChanges'));
}
dispatch(receiveAccessionAuditLog(auditLog));
}).catch((error) => {
console.log(`API error`, error);
dispatch(receiveAccession(null, error));
});
};
export const overviewAccessions = (filterCode: string) => (dispatch) => {
return AccessionService.listOverview(filterCode)
.then((overview) => {
......
export const RECEIVE_ACCESSIONS = 'accessions/RECEIVE_ACCESSIONS';
export const APPEND_ACCESSIONS = 'accessions/APPEND_ACCESSIONS';
export const RECEIVE_ACCESSION_OVERVIEW = 'accessions/RECEIVE_ACCESSION_OVERVIEW';
export const RECEIVE_ACCESSION_AUDIT_LOG = 'accessions/RECEIVE_ACCESSION_AUDIT_LOG';
export const RECEIVE_ACCESSION = 'accessions/RECEIVE_ACCESSION';
export const RECEIVE_ACCESSION_MAPINFO = 'accessions/RECEIVE_ACCESSION_MAPINFO';
export const ACCESSION_FILTERFORM = 'Form/Accession/ACCESSION_FILTERFORM';
......
import update from 'immutability-helper';
import { IReducerAction } from 'model/common.model';
import {RECEIVE_ACCESSIONS, RECEIVE_ACCESSION, RECEIVE_ACCESSION_OVERVIEW, APPEND_ACCESSIONS, RECEIVE_ACCESSION_MAPINFO} from 'accessions/constants';
import { RECEIVE_ACCESSIONS, RECEIVE_ACCESSION, RECEIVE_ACCESSION_OVERVIEW, APPEND_ACCESSIONS, RECEIVE_ACCESSION_MAPINFO, RECEIVE_ACCESSION_AUDIT_LOG } from 'accessions/constants';
import FilteredPage from 'model/FilteredPage';
import Accession from 'model/accession/Accession';
import AccessionMapInfo from 'model/accession/AccessionMapInfo';
import AccessionOverview from 'model/accession/AccessionOverview';
import AccessionAuditLog from 'model/accession/AccessionAuditLog';
const INITIAL_STATE: {
accession: Accession;
auditLog: AccessionAuditLog,
accessionError: any;
paged: FilteredPage<Accession>;
pagedError: any;
......@@ -17,6 +19,7 @@ const INITIAL_STATE: {
mapInfo: AccessionMapInfo;
} = {
accession: null,
auditLog: null,
accessionError: null,
paged: null,
pagedError: null,
......@@ -35,6 +38,7 @@ function publicAccessions(state = INITIAL_STATE, action: IReducerAction) {
if (receivedIndex !== -1) {
return update(state, {
accession: { $set: accession },
auditLog: {$set: null},
paged: {
content: {
[receivedIndex]: {$set: accession},
......@@ -45,12 +49,20 @@ function publicAccessions(state = INITIAL_STATE, action: IReducerAction) {
} else {
return update(state, {
accession: { $set: accession},
auditLog: {$set: null},
paged: {$set: null},
accessionError: {$set: error},
});
}
}
case RECEIVE_ACCESSION_AUDIT_LOG: {
const {auditLog} = action.payload;
return update(state, {
auditLog: {$set: auditLog},
});
}
case RECEIVE_ACCESSIONS: {
const { paged, error } = action.payload;
return update(state, {
......
......@@ -34,6 +34,7 @@
"historic": "Historic accession",
"isHistoric": "This is a historic record of an accession",
"DOI": "DOI",
"loadChanges": "Show changes",
"acquisitionDate": "Acquisition Date",
"availability": "Availability for distribution",
"ITPGRFAMLS": "ITPGRFA MLS",
......
......@@ -5,12 +5,16 @@ import { translate } from 'react-i18next';
import { withStyles } from '@material-ui/core/styles';
// Actions
import { loadAccession, applyFilters } from 'accessions/actions/public';
import { loadAccession, applyFilters, loadAccessionAuditLog } from 'accessions/actions/public';
import {addAccessionToMyList, removeAccessionFromMyList} from 'list/actions/public';
// Constants
import { ROLE_USER } from 'constants/userRoles';
// Models
import AccessionDetails from 'model/accession/AccessionDetails';
import RepositoryFile from 'model/repository/RepositoryFile';
import AccessionAuditLog from 'model/accession/AccessionAuditLog';
// UI
import PrettyDate from 'ui/common/time/PrettyDate';
......@@ -32,6 +36,8 @@ import McpdDate from 'ui/common/time/McpdDate';
import PdciTable from './c/PdciTable';
import ImageGalleryView from 'repository/ui/c/ImageGalleryView';
import Button from '@material-ui/core/Button/Button';
import AuditedInfo from 'ui/common/AuditedInfo';
import Authorize from 'ui/common/authorized/Authorize';
const styles = (theme) => ({
pageSection: {
......@@ -53,8 +59,10 @@ interface IBrowsePageProps {
uuid: string;
doi: string; // DOI comes from the route without the '10.'
accession: AccessionDetails;
auditLog: AccessionAuditLog;
error: any;
loadAccession: any;
loadAccessionAuditLog: any;
accessions: any;
addAccessionToMyList: any;
removeAccessionFromMyList: any;
......@@ -86,6 +94,17 @@ class BrowsePage extends React.Component<IBrowsePageProps, any> {
}
}
private loadAuditLog = () => {
const { doi, uuid, loadAccessionAuditLog } = this.props;
const theDoi = `10.${doi}`;
if (doi) {
loadAccessionAuditLog({ doi: theDoi });
} else {
loadAccessionAuditLog({uuid});
}
}
private onCheckboxChange = (event, checked) => {
const {accession: {details: accession}, addAccessionToMyList, removeAccessionFromMyList} = this.props;
if (checked) {
......@@ -104,7 +123,10 @@ class BrowsePage extends React.Component<IBrowsePageProps, any> {
public render() {
const { t, error, uuid, doi, accessions, classes } = this.props;
const { t, error, uuid, doi, accessions, auditLog, classes } = this.props;
const { auditAccession, auditAccessionId, auditAccessionCollect, auditAccessionGeo } = auditLog || { auditAccession: {}, auditAccessionId: {}, auditAccessionCollect: {}, auditAccessionGeo: {} };
const { details: accession, pdci, datasets, subsets, files, imageGallery } = this.props.accession ?
this.props.accession
:
......@@ -133,6 +155,9 @@ class BrowsePage extends React.Component<IBrowsePageProps, any> {
<div>
{ t('accessions.common.modelName') }: { accession.accessionNumber }
<div className="float-right">
<Authorize role={ ROLE_USER }>
<Button className="mr-20" variant="contained" onClick={ this.loadAuditLog }>{ t('accessions.public.p.display.loadChanges') }</Button>
</Authorize>
<ReduxCheckbox
label={
<b>
......@@ -150,28 +175,60 @@ class BrowsePage extends React.Component<IBrowsePageProps, any> {
>
<Properties>
{ accession.doi && <PropertiesItem title={ t('accessions.public.p.display.DOI') }><DOI noPrefix value={ accession.doi } /></PropertiesItem> }
<PropertiesItem title={ t('accessions.common.acceNumb') } >{ accession.accessionNumber }</PropertiesItem>
<PropertiesItem title={ t('accessions.common.acceNumb') } >
{ accession.accessionNumber }
<AuditedInfo info={ auditAccession.accessionNumber }/>
</PropertiesItem>
<PropertiesItem title={ t('accessions.public.p.display.holdingInstitute') }>
<InstituteLink to={ accession.institute }>
{ accession.institute.fullName }
</InstituteLink>
<span> &mdash; </span>
<CountryLink noflag country={ accession.institute.country }/>
<AuditedInfo info={ auditAccession.institute }/>
</PropertiesItem>
{ accession.historic &&
<PropertiesItem className={ accession.historic ? classes.historic : '' } title={ t('accessions.public.p.display.historic') }>
{ t('accessions.public.p.display.isHistoric') }
<AuditedInfo info={ auditAccession.historic }/>
</PropertiesItem>
}
<PropertiesItem title={ t('accessions.common.instituteCode') }>
{ accession.institute.code }
<AuditedInfo info={ auditAccession.instituteCode }/>
</PropertiesItem>
<PropertiesItem title={ t('accessions.public.p.display.acquisitionDate') }>
<McpdDate value={ accession.acquisitionDate } />
<AuditedInfo info={ auditAccession.acquisitionDate }/>
</PropertiesItem>
{ accession.historic && <PropertiesItem className={ accession.historic ? classes.historic : '' } title={ t('accessions.public.p.display.historic') }>{ t('accessions.public.p.display.isHistoric') }</PropertiesItem> }
<PropertiesItem title={ t('accessions.common.instituteCode') }>{ accession.institute.code }</PropertiesItem>
<PropertiesItem title={ t('accessions.public.p.display.acquisitionDate') }><McpdDate value={ accession.acquisitionDate } /></PropertiesItem>
{ accession.countryOfOrigin && <PropertiesItem title={ t('accessions.common.countryOfOrigin') }>{ <CountryLink country={ accession.countryOfOrigin }/> }</PropertiesItem> }
{ accession.sampStat && <PropertiesItem title={ t('accessions.common.sampStat') }>{ t(`accessions.common.sampleStatus.${accession.sampStat}`) }</PropertiesItem> }
{ accession.countryOfOrigin && <PropertiesItem title={ t('accessions.common.countryOfOrigin') }>{ <CountryLink country={ accession.countryOfOrigin }/> }<AuditedInfo info={ auditAccession.countryOfOrigin }/></PropertiesItem> }
{ accession.sampStat &&
<PropertiesItem title={ t('accessions.common.sampStat') }>
{ t(`accessions.common.sampleStatus.${accession.sampStat}`) }
<AuditedInfo info={ auditAccession.sampStat }/>
</PropertiesItem>
}
{ accession.storage && accession.storage.length > 0 && <PropertiesItem title={ t('accessions.common.storageType') }>
{ accession.storage.map((storage, i) => (
<div key={ storage } style={ {width: '100%', paddingTop: '.25rem'} }>{ t(`accessions.common.storage.${storage}`) }</div>
)) }
</PropertiesItem> }
<PropertiesItem title={ t('accessions.public.p.display.availability') } keepEmpty>{ t(`accessions.common.available.${accession.available}`) }</PropertiesItem>
<PropertiesItem title={ t('accessions.public.p.display.ITPGRFAMLS') } keepEmpty>{ t(`accessions.common.mlsStatus.${accession.mlsStatus}`) }</PropertiesItem>
<PropertiesItem title={ t('accessions.public.p.display.donorInstitute') }>{ accession.donorCode }</PropertiesItem>
<PropertiesItem title={ t('accessions.public.p.display.donorAccessionNumber') }>{ accession.donorNumb }</PropertiesItem>
<PropertiesItem title={ t('accessions.public.p.display.availability') } keepEmpty>
{ t(`accessions.common.available.${accession.available}`) }
<AuditedInfo info={ auditAccession.available }/>
</PropertiesItem>
<PropertiesItem title={ t('accessions.public.p.display.ITPGRFAMLS') } keepEmpty>
{ t(`accessions.common.mlsStatus.${accession.mlsStatus}`) }
<AuditedInfo info={ auditAccession.mlsStatus }/>
</PropertiesItem>
<PropertiesItem title={ t('accessions.public.p.display.donorInstitute') }>
{ accession.donorCode }
<AuditedInfo info={ auditAccession.donorCode }/>
</PropertiesItem>
<PropertiesItem title={ t('accessions.public.p.display.donorAccessionNumber') }>
{ accession.donorNumb }
<AuditedInfo info={ auditAccession.donorNumb }/>
</PropertiesItem>
{ accession.duplSite && accession.duplSite.length > 0 && <PropertiesItem title={ t('accessions.public.p.display.safetyDuplicationInstitute') }>
{ accession.duplSite.map((duplSite, i) => (
......@@ -189,7 +246,10 @@ class BrowsePage extends React.Component<IBrowsePageProps, any> {
<PageSection title={ t('accessions.common.taxonomy') }>
<Properties>
<PropertiesItem title={ t('accessions.common.genus') }>{ accession.taxonomy.genus }</PropertiesItem>
<PropertiesItem title={ t('accessions.common.genus') }>
{ accession.taxonomy.genus }
<AuditedInfo info={ auditAccession.genus }/>
</PropertiesItem>
<PropertiesItem title={ t('accessions.common.species') }>
{ accession.taxonomy.species }
{ '' }
......@@ -215,24 +275,43 @@ class BrowsePage extends React.Component<IBrowsePageProps, any> {
{ accession.coll &&
<PageSection title={ t('accessions.public.p.display.collectingInformation') }>
<Properties>
{ accession.countryOfOrigin && <PropertiesItem title={ t('accessions.common.countryOfOrigin') }>{ <CountryLink country={ accession.countryOfOrigin }/> }</PropertiesItem> }
{ accession.coll.collDate && <PropertiesItem key="collDate" title={ t(`accessions.common.coll.collDate`) }><McpdDate value={ accession.coll.collDate } /></PropertiesItem> }
{ accession.countryOfOrigin &&
<PropertiesItem title={ t('accessions.common.countryOfOrigin') }>
<CountryLink country={ accession.countryOfOrigin }/>
<AuditedInfo info={ auditAccessionCollect.countryOfOrigin }/>
</PropertiesItem>
}
{ accession.coll.collDate &&
<PropertiesItem key="collDate" title={ t(`accessions.common.coll.collDate`) }>
<McpdDate value={ accession.coll.collDate } />
<AuditedInfo info={ auditAccessionCollect.collDate }/>
</PropertiesItem>
}
{ accession.coll &&
[ 'collMissId', 'collNumb', 'collSite', 'collSrc' ]
.filter((prop) => accession.coll[prop] !== null).map((prop) => (
<PropertiesItem key={ prop } title={ t(`accessions.common.coll.${prop}`) }>{ accession.coll[prop] }</PropertiesItem>
<PropertiesItem key={ prop } title={ t(`accessions.common.coll.${prop}`) }>
{ accession.coll[prop] }
<AuditedInfo info={ auditAccessionCollect[prop] }/>
</PropertiesItem>
))
}
{ accession.coll &&
[ 'collCode', 'collName' ]
.filter((prop) => accession.coll[prop].length).map((prop) => (
<PropertiesItem key={ prop } title={ t(`accessions.common.coll.${prop}`) }>{ accession.coll[prop] }</PropertiesItem>
<PropertiesItem key={ prop } title={ t(`accessions.common.coll.${prop}`) }>
{ accession.coll[prop] }
<AuditedInfo info={ auditAccessionCollect[prop] }/>
</PropertiesItem>
))
}
{ accession.geo &&
[ 'latitude', 'longitude', 'datum', 'method', 'uncertainty', 'elevation' ]
.filter((prop) => accession.geo[prop] !== null).map((prop) => (
<PropertiesItem key={ prop } title={ t(`accessions.common.geo.${prop}`) }>{ accession.geo[prop] }</PropertiesItem>
<PropertiesItem key={ prop } title={ t(`accessions.common.geo.${prop}`) }>
{ accession.geo[prop] }
<AuditedInfo info={ auditAccessionGeo[prop] }/>
</PropertiesItem>
))
}
</Properties>
......@@ -273,7 +352,10 @@ class BrowsePage extends React.Component<IBrowsePageProps, any> {
<PageSection title={ t('accessions.public.p.display.metadata') }>
<Properties>
<PropertiesItem title={ t('common:label.UUID') }>{ `urn:uuid:${accession.uuid}` }</PropertiesItem>
<PropertiesItem title={ t('common:label.UUID') }>
{ `urn:uuid:${accession.uuid}` }
<AuditedInfo info={ auditAccessionId.uuid }/>
</PropertiesItem>
<PropertiesItem title={ t('accessions.public.p.display.permanentURL') }><ExternalLink link={ `https://purl.org/germplasm/id/${accession.uuid}` } /></PropertiesItem>
<PropertiesItem title={ t('common:label.lastUpdated') }><PrettyDate value={ accession.lastModifiedDate } /></PropertiesItem>
<PropertiesItem title={ t('common:label.created') }><PrettyDate value={ accession.createdDate } /></PropertiesItem>
......@@ -309,6 +391,7 @@ class BrowsePage extends React.Component<IBrowsePageProps, any> {
const mapStateToProps = (state, ownProps) => ({
accession: state.accessions.public.accession,
auditLog: state.accessions.public.auditLog,
error: state.accessions.public.accessionError,
uuid: ownProps.match.params.uuid,
doi: ownProps.match.params.doi,
......@@ -319,6 +402,7 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({
addAccessionToMyList,
removeAccessionFromMyList,
loadAccession,
loadAccessionAuditLog,
applyFilters,
}, dispatch);
......
class AuditLog {
public action: string;
public classPk: any;
public entityId: number;
public id: number;
public logDate: Date;
public newState: string;
public previousState: string;
public propertyName: string;
public referencedEntity: any;
}
export default AuditLog;
/*
* Defined in Swagger as '#/definitions/AccessionAuditLog'
*/
class AccessionAuditLog {
public auditAccession: any;
public auditAccessionCollect: any;
public auditAccessionGeo: any;
public auditAccessionId: any;
}
export default AccessionAuditLog;
......@@ -11,6 +11,10 @@ class AccessionDetails {
public pdci: PDCI;
public files: RepositoryFile[];
public imageGallery: ImageGallery;
public auditAccession: any;
public auditAccessionCollect: any;
public auditAccessionGeo: any;
public auditAccessionId: any;
}
export default AccessionDetails;
......@@ -9,11 +9,14 @@ import AccessionFilter from 'model/accession/AccessionFilter';
import AccessionMapInfo from 'model/accession/AccessionMapInfo';
import FilteredPage, { IPageRequest } from 'model/FilteredPage';
import {AccessionRef} from 'model/accession/AccessionRef';
import AccessionAuditLog from 'model/accession/AccessionAuditLog';
const URL_GET_BY_DOI = `/api/v1/acn/{doi}`; // UrlTemplate doesn't like the / in DOI
const URL_GET_BY_UUID = UrlTemplate.parse(`/api/v1/acn/{uuid}`);
const URL_GEO_JSON = `/api/v1/acn/geoJson`;
const URL_LIST_BY_UUID = `/api/v1/acn/for-uuid`;
const URL_GET_ACCESSION_AUDIT_LOG_BY_DOI = `/api/v1/acn/auditlog/{doi}`; // UrlTemplate doesn't like the / in DOI
const URL_GET_ACCESSION_AUDIT_LOG_BY_UUID = UrlTemplate.parse(`/api/v1/acn/auditlog/{uuid}`);
const URL_GET_DETAILS_BY_DOI = `/api/v1/acn/details/{doi}`; // UrlTemplate doesn't like the / in DOI
const URL_GET_DETAILS_BY_UUID = UrlTemplate.parse(`/api/v1/acn/details/{uuid}`);
const URL_TO_UUID = `/api/v1/acn/toUUID`;
......@@ -86,6 +89,43 @@ class AccessionService {
}).then(({ data }) => data as any);
}
/**
* getAccessionAuditLogByDoi at /api/v1/acn/auditlog/{doi}
*
* @param doi doi
*/
public static getAccessionAuditLogByDoi(doi: string): Promise<AccessionAuditLog> {
const apiUrl = URL_GET_ACCESSION_AUDIT_LOG_BY_DOI.replace(/{doi}/, doi);
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return axiosBackend.request({
url: apiUrl,
method: 'GET',
...content,
}).then(({ data }) => data as AccessionAuditLog);
}
/**
* getAccessionAuditLogByUUID at /api/v1/acn/auditlog/{uuid}
*
* @param uuid uuid
*/
public static getAccessionAuditLogByUUID(uuid: string): Promise<AccessionAuditLog> {
const apiUrl = URL_GET_ACCESSION_AUDIT_LOG_BY_UUID.expand({uuid});
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return axiosBackend({
url: apiUrl,
method: 'GET',
...content,
}).then(({ data }) => data as AccessionAuditLog);
}
/**
* getByDoi at /api/v1/acn/10.{dummy}/**}
*
......
import * as React from 'react';
import { translate } from 'react-i18next';
// model
import AuditLog from 'model/AuditLog';
// ui
import PrettyDate from 'ui/common/time/PrettyDate';
import withStyles from '@material-ui/core/styles/withStyles';
const styles = (theme) => ({
root: {
display: 'flex' as 'flex',
justifyContent: 'space-between' as 'space-between',
width: '100%',
marginTop: '.5em',
fontSize: '12px',
color: '#7d7d7d',
},
arrow: {
fontSize: '16px',
margin: '0 8px',
},
noValue: {
color: '#c7254e8c',
padding: '2px 4px',
backgroundColor: '#f9f2f4',
},
});
interface IAuditedInfo extends React.ClassAttributes<any> {
info: AuditLog[];
t?: any;
classes?: any;
}
class AuditedInfo extends React.Component<IAuditedInfo> {
public render() {
const { info, t, classes } = this.props;
return info ? (
<div>
{ info.map((auditLog) => (
<div className={ classes.root } key={ auditLog.id }>
<code>
<span>{ auditLog.previousState || <span className={ classes.noValue }>{ t('common:label.noValue') }</span> }</span>
<span className={ classes.arrow }>&#10230;</span>
<span>{ auditLog.newState || <span className={ classes.noValue }>{ t('common:label.noValue') }</span> }</span>
</code>
<PrettyDate value={ auditLog.logDate } t={ t }/>
</div>
)) }
</div>
) : null;
}
}
export default translate()(withStyles(styles)(AuditedInfo));
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