Commit 0dd9797d authored by Loic Huder's avatar Loic Huder
Browse files

Merge branch 'investigation-date-filter' into 'master'

Adds a date filter to the InvestigationTable (single day pick)

See merge request !424
parents db08287a 4f94d870
Pipeline #32081 passed with stages
in 7 minutes and 32 seconds
import React from 'react';
import { Glyphicon, Button } from 'react-bootstrap';
import DayPickerInput from 'react-day-picker/DayPickerInput';
import { formatDate, parseDate } from 'react-day-picker/moment';
import { INVESTIGATION_DATE_FORMAT } from '../../constants';
import styles from './InvestigationDateFilter.module.css';
function InvestigationDateFilter(props) {
const { rootClassName, value, onDayChange, onClear } = props;
return (
<div className={rootClassName}>
<DayPickerInput
inputProps={{ className: styles.dateFilterInput }}
value={value}
placeholder="Filter by start date"
format={INVESTIGATION_DATE_FORMAT}
formatDate={formatDate}
parseDate={parseDate}
onDayChange={onDayChange}
/>
<Button
disabled={!value}
onClick={onClear}
bsStyle="link"
className={styles.clearButton}
>
<Glyphicon glyph="remove" />
</Button>
</div>
);
}
export default InvestigationDateFilter;
.clearButton {
color: inherit;
padding-left: 6px;
}
.clearButton:hover {
color: darkslategray;
}
.dateFilterInput {
padding: 7px 0;
}
import React from 'react'; import React, { useState } from 'react';
import { Col, Glyphicon, Grid, Row } from 'react-bootstrap'; import { Col, Glyphicon, Grid, Row } from 'react-bootstrap';
import { Link } from 'react-router-dom'; import moment from 'moment';
import { import {
DATASET_COUNT, DATASET_COUNT,
FILE_COUNT, FILE_COUNT,
SAMPLE_COUNT,
VOLUME, VOLUME,
} from '../../constants/parameterTypes'; } from '../../constants/parameterTypes';
import DOIBadge from '../doi/DOIBadge'; import DOIBadge from '../doi/DOIBadge';
...@@ -12,290 +11,279 @@ import ResponsiveTable from '../Table/ResponsiveTable'; ...@@ -12,290 +11,279 @@ import ResponsiveTable from '../Table/ResponsiveTable';
import InvestigationWidget from './InvestigationWidget'; import InvestigationWidget from './InvestigationWidget';
import { beamlineFormatter, dateFormatter, nameFormatter } from './utils'; import { beamlineFormatter, dateFormatter, nameFormatter } from './utils';
import { stringifyBytesSize } from '../../helpers'; import { stringifyBytesSize } from '../../helpers';
import InvestigationDateFilter from './InvestigationDateFilter';
import styles from './InvestigationTable.module.css';
class InvestigationTable extends React.Component { function volumeFormatter(cell, investigation) {
logbookFormatter(cell, investigation) { const volume = investigation.parameters.find((o) => o.name === VOLUME);
return ( if (volume && volume.value && volume.value !== 0) {
<Link to={`/investigation/${investigation.id}/events`}> return stringifyBytesSize(volume.value);
<Glyphicon glyph="list-alt" />
</Link>
);
} }
}
volumeFormatter(cell, investigation) { function experimentFormatter(cell, investigation, rowIndex, extraData) {
const volume = investigation.parameters.find((o) => o.name === VOLUME); return (
if (volume && volume.value && volume.value !== 0) { <Grid style={{ textAlign: 'center' }}>
return stringifyBytesSize(volume.value); <Row className="show-grid">
} <Col xs={12} md={12}>
} {nameFormatter(
investigation,
extraData.props.withProposalLinks,
extraData.props.user.isAdministrator
)}
</Col>
</Row>
<Row className="show-grid">
<Col xs={12} md={12}>
<span style={{ fontWeight: 'bold' }}>
{beamlineFormatter(investigation, investigation.visitId)}
</span>
</Col>
</Row>
<Row className="show-grid">
<Col xs={12}>
<div style={{ color: 'gray', fontStyle: 'italic' }}>
{investigation.summary}
</div>
</Col>
</Row>
<Row className="show-grid" style={{ fontSize: 10 }}>
<Col xs={12}>
<DOIBadge doi={investigation.doi} />
</Col>
</Row>
</Grid>
);
}
experimentFormatter(cell, investigation, rowIndex, extraData) { /**
return ( * This looks into the parameters of the investigation
<Grid style={{ textAlign: 'center' }}> */
<Row className="show-grid"> function getParameter(investigation, parameterName) {
<Col xs={12} md={12}> const parameter = investigation.parameters.find(
{nameFormatter( (o) => o.name === parameterName
investigation, );
extraData.props.withProposalLinks, if (parameter && parameter.value) {
extraData.props.user.isAdministrator return parameter.value;
)}
</Col>
</Row>
<Row className="show-grid">
<Col xs={12} md={12}>
<span style={{ fontWeight: 'bold' }}>
{beamlineFormatter(investigation, investigation.visitId)}
</span>
</Col>
</Row>
<Row className="show-grid">
<Col xs={12}>
<div style={{ color: 'gray', fontStyle: 'italic' }}>
{investigation.summary}
</div>
</Col>
</Row>
<Row className="show-grid" style={{ fontSize: 10 }}>
<Col xs={12}>
<DOIBadge doi={investigation.doi} />
</Col>
</Row>
</Grid>
);
} }
}
/** function fileCountFormatter(cell, investigation) {
* This looks into the parameters of the investigation const fileCount = getParameter(investigation, FILE_COUNT);
*/
getParameter(investigation, parameterName) {
const parameter = investigation.parameters.find(
(o) => o.name === parameterName
);
if (parameter && parameter.value) {
return parameter.value;
}
}
sampleCountFormatter(cell, investigation, extraData) { if (!fileCount) {
const sampleCount = extraData.getParameter(investigation, SAMPLE_COUNT); return undefined;
if (sampleCount) {
if (sampleCount !== 0) {
return sampleCount;
}
}
} }
fileCountFormatter(cell, investigation, rowIndex, extraData) { return (
const fileCount = extraData.getParameter(investigation, FILE_COUNT); <span style={{ width: 50, textAlign: 'right', float: 'left' }}>
if (fileCount) { {fileCount}
if (fileCount !== 0) { </span>
return ( );
<span style={{ width: 50, textAlign: 'right', float: 'left' }}> }
{fileCount}
</span>
);
}
}
}
datasetCountFormatter(cell, investigation, rowIndex, extraData) { function datasetCountFormatter(cell, investigation) {
const datasetCount = investigation.parameters.find( const datasetCount = investigation.parameters.find(
(o) => o.name === DATASET_COUNT (o) => o.name === DATASET_COUNT
);
if (datasetCount && datasetCount.value) {
return (
<>
<span style={{ width: 40, textAlign: 'right', float: 'left' }}>
{datasetCount.value}
</span>
<span
style={{
width: 70,
marginLeft: 5,
float: 'left',
fontStyle: 'italic',
color: '#999',
fontSize: 12,
}}
>
({volumeFormatter(cell, investigation)})
</span>
</>
); );
if (datasetCount && datasetCount.value && datasetCount.value !== 0) {
return (
<>
<span style={{ width: 40, textAlign: 'right', float: 'left' }}>
{datasetCount.value}
</span>
<span
style={{
width: 70,
marginLeft: 5,
float: 'left',
fontStyle: 'italic',
color: '#999',
fontSize: 12,
}}
>
({extraData.volumeFormatter(cell, investigation, extraData)})
</span>
</>
);
}
} }
}
/** function getLgHeaderStyle(width, hidden) {
* It return true if releaseDate < now return {
*/ xs: { hidden: true },
isReleased(investigation) { sm: { hidden: true },
return !!investigation && !!investigation.releaseDate; md: { hidden: true },
} lg: { hidden, width, textAlign: 'center' },
};
}
getColumns() { function getColumns(props) {
function getLgHeaderStyle(width, hidden) { return [
return { {
xs: { hidden: true }, text: 'id',
sm: { hidden: true }, dataField: 'id',
hidden: true,
},
{
text: 'Experiment',
dataField: 'name',
formatter: experimentFormatter,
formatExtraData: props,
sort: true,
hidden: false,
headerStyle: () => ({ width: '50%', textAlign: 'center' }),
responsiveHeaderStyle: {
xs: { width: '100%' },
sm: { width: '100%' },
md: { hidden: true }, md: { hidden: true },
lg: { hidden, width, textAlign: 'center' }, lg: { hidden: true },
};
}
return [
{
text: 'id',
dataField: 'id',
hidden: true,
},
{
text: 'Experiment',
dataField: 'name',
formatter: this.experimentFormatter,
formatExtraData: this,
sort: true,
hidden: false,
headerStyle: () => ({ width: '50%', textAlign: 'center' }),
responsiveHeaderStyle: {
xs: { width: '100%' },
sm: { width: '100%' },
md: { hidden: true },
lg: { hidden: true },
},
},
{
text: 'Proposal',
dataField: 'name',
formatter: (_, investigation, __, props) =>
nameFormatter(
investigation,
props.withProposalLinks,
props.user.isAdministrator
),
formatExtraData: this.props,
sort: true,
hidden: false,
headerStyle: () => ({ width: '50%', textAlign: 'center' }),
responsiveHeaderStyle: {
xs: { hidden: true },
sm: { hidden: true },
md: { width: 140, textAlign: 'center' },
lg: { width: 140, textAlign: 'center' },
},
}, },
{ },
text: 'Beamline', {
dataField: 'visitId', text: 'Proposal',
formatter: (visitId, investigation) => ( dataField: 'name',
<span style={{ fontWeight: 'bold' }}> formatter: (_, investigation, __, props) =>
{beamlineFormatter(investigation, visitId)} nameFormatter(
</span> investigation,
), props.withProposalLinks,
sort: true, props.user.isAdministrator
responsiveHeaderStyle: {
xs: { hidden: true },
sm: { hidden: true },
md: { width: 110, textAlign: 'center' },
lg: { width: 110, textAlign: 'center' },
},
},
{
text: 'Start Date',
dataField: 'startDate',
formatter: dateFormatter,
sort: true,
responsiveHeaderStyle: getLgHeaderStyle(110, false),
},
{
text: 'Title',
dataField: 'summary',
sort: true,
responsiveHeaderStyle: {
xs: { hidden: true },
sm: { hidden: true },
},
},
{
text: 'Datasets',
dataField: 'datasets',
formatter: this.datasetCountFormatter,
formatExtraData: this,
responsiveHeaderStyle: getLgHeaderStyle(
130,
!this.props.showInvestigationStats
),
},
{
text: 'Files',
hidden: !this.props.user.isAdministrator,
dataField: 'dummy-1',
isDummyField: true,
formatter: this.fileCountFormatter,
formatExtraData: this,
responsiveHeaderStyle: getLgHeaderStyle(
80,
!this.props.showInvestigationStats
), ),
formatExtraData: props,
sort: true,
hidden: false,
headerStyle: () => ({ width: '50%', textAlign: 'center' }),
responsiveHeaderStyle: {
xs: { hidden: true },
sm: { hidden: true },
md: { width: 140, textAlign: 'center' },
lg: { width: 140, textAlign: 'center' },
}, },
{ },
text: 'Release', {
dataField: 'releaseDate', text: 'Beamline',
formatter: dateFormatter, dataField: 'visitId',
sort: true, formatter: (visitId, investigation) => (
responsiveHeaderStyle: getLgHeaderStyle(110, false), <span style={{ fontWeight: 'bold' }}>
{beamlineFormatter(investigation, visitId)}
</span>
),
sort: true,
responsiveHeaderStyle: {
xs: { hidden: true },
sm: { hidden: true },
md: { width: 110, textAlign: 'center' },
lg: { width: 110, textAlign: 'center' },
}, },
{ },
text: 'DOI', {
dataField: 'doi', text: 'Start Date',
formatter: (doi) => <DOIBadge doi={doi} />, dataField: 'startDate',
sort: true, formatter: dateFormatter,
responsiveHeaderStyle: getLgHeaderStyle(260, false), sort: true,
responsiveHeaderStyle: getLgHeaderStyle(110, false),
},
{
text: 'Title',
dataField: 'summary',
sort: true,
responsiveHeaderStyle: {
xs: { hidden: true },
sm: { hidden: true },
}, },
]; },
} {
text: 'Datasets',
dataField: 'datasets',
formatter: datasetCountFormatter,
responsiveHeaderStyle: getLgHeaderStyle(
130,
!props.showInvestigationStats
),
},
{
text: 'Files',
hidden: !props.user.isAdministrator,
dataField: 'dummy-1',
isDummyField: true,
formatter: fileCountFormatter,
responsiveHeaderStyle: getLgHeaderStyle(
80,
!props.showInvestigationStats
),
},
{
text: 'Release',
dataField: 'releaseDate',
formatter: dateFormatter,
sort: true,
responsiveHeaderStyle: getLgHeaderStyle(110, false),
},
{
text: 'DOI',
dataField: 'doi',
formatter: (doi) => <DOIBadge doi={doi} />,
sort: true,
responsiveHeaderStyle: getLgHeaderStyle(260, false),
},
];
}
render() { function InvestigationTable(props) {
const expandRow = { const { expanded, user, investigations } = props;
showExpandColumn: true, const [dateFilter, setDateFilter] = useState();
//expandByColumnOnly: true,
expanded: this.props.expanded, const expandRow = {
expandColumnPosition: 'right', showExpandColumn: true,
expandHeaderColumnRenderer: ({ isAnyExpands }) => { expanded,
if (isAnyExpands) { expandColumnPosition: 'right',
return ( expandHeaderColumnRenderer: ({ isAnyExpands }) => {
<span style={{ fontSize: 18 }}> if (isAnyExpands) {
<Glyphicon glyph="zoom-out" />
</span>
);
}
return ( return (
<span style={{ fontSize: 18 }}> <span style={{ fontSize: 18 }}>
<Glyphicon glyph="zoom-in" /> <Glyphicon glyph="zoom-out" />
</span> </span>
); );
}, }
expandColumnRenderer: ({ expanded }) => { return (
if (expanded) { <span style={{ fontSize: 18 }}>
return <Glyphicon glyph="zoom-out" />; <Glyphicon glyph="zoom-in" />
} </span>
return <Glyphicon glyph="zoom-in" />; );
}, },
renderer: (investigation) => ( expandColumnRenderer: ({ expanded }) => {
<InvestigationWidget if (expanded) {
investigation={investigation} return <Glyphicon glyph="zoom-out" />;
sessionId={this.props.user.sessionId} }
/> return <Glyphicon glyph="zoom-in" />;
), },
}; renderer: (investigation) => (
<InvestigationWidget
investigation={investigation}
sessionId={user.sessionId}
/>
),
};
return ( return (
<>
<div className={styles.wrapper}>
<InvestigationDateFilter
rootClassName={styles.filter}
value={dateFilter && dateFilter.toDate()}
onDayChange={(date) => setDateFilter(moment(date))}
onClear={() => setDateFilter(undefined)}