Commit e13d0e68 authored by Alejandro De Maria Antolinos's avatar Alejandro De Maria Antolinos
Browse files

Resolved conflicts

parents b67a7f29 16d94b25
Pipeline #51319 passed with stage
in 2 minutes and 50 seconds
......@@ -21,9 +21,14 @@ const getHrefByInstrument = (instrumentName) => {
function InvestigationDateFilter(props) {
const {
rootClassName,
value,
onDayChange,
onClear,
startValue,
onStartDayChange,
onStartClear,
startPlaceHolder,
endValue,
onEndDayChange,
onEndClear,
endPlaceHolder,
instrumentName,
showStatisticsMenu,
withJupyter,
......@@ -33,19 +38,40 @@ function InvestigationDateFilter(props) {
<div className={rootClassName}>
<DayPickerInput
inputProps={{ className: styles.dateFilterInput }}
value={value}
placeholder=" Filter by date"
value={startValue}
placeholder={startPlaceHolder ? startPlaceHolder : 'Filter by date'}
format={INVESTIGATION_DATE_FORMAT}
formatDate={formatDate}
parseDate={parseDate}
onDayChange={onDayChange}
onDayChange={onStartDayChange}
dayPickerProps={{
todayButton: 'Today',
}}
/>
<Button
disabled={!value}
onClick={onClear}
disabled={!startValue}
onClick={onStartClear}
bsStyle="link"
className={styles.clearButton}
>
<Glyphicon glyph="remove" />
</Button>
<DayPickerInput
inputProps={{ className: styles.dateFilterInput }}
value={endValue}
placeholder={endPlaceHolder ? endPlaceHolder : 'Filter by date'}
format={INVESTIGATION_DATE_FORMAT}
formatDate={formatDate}
parseDate={parseDate}
onDayChange={onEndDayChange}
dayPickerProps={{
todayButton: 'Today',
}}
/>
<Button
disabled={!endValue}
onClick={onEndClear}
bsStyle="link"
className={styles.clearButton}
>
......
......@@ -16,11 +16,11 @@ import {
} from './utils';
import InvestigationDateFilter from './InvestigationDateFilter';
import styles from './InvestigationTable.module.css';
import { useHistory, useLocation } from 'react-router';
import { useQuery } from '../../helpers/hooks';
import { useSelector } from 'react-redux';
import { INVESTIGATION_DATE_FORMAT } from '../../constants';
import UI from '../../config/ui';
import { useResource } from 'rest-hooks';
import InvestigationResource from '../../resources/investigation';
function getLgHeaderStyle(width, hidden) {
return {
......@@ -76,7 +76,7 @@ function getColumns({
{
text: 'Beamline',
dataField: 'visitId',
dataField: 'instrument',
formatter: (_, investigation) => (
<span style={{ fontWeight: 'bold' }}>
{beamlineFormatter(investigation)}
......@@ -165,42 +165,93 @@ function getColumns({
function InvestigationTable(props) {
const {
investigations,
withProposalLinks = false,
withInvestigationStats = false,
showStatisticsMenu = false,
instrumentName,
withUserPortalLink = false,
withJupyter = false,
filter,
} = props;
const [sizePerPage, setSizePerPage] = React.useState(25);
const [page, setPage] = React.useState(1);
const [search, setSearch] = React.useState('');
const [startDate, setStartDate] = React.useState(undefined);
const [endDate, setEndDate] = React.useState(undefined);
const [sortField, setSortField] = React.useState('startDate');
const [sortOrder, setSortOrder] = React.useState(-1);
let fetchingParams = {
limit: sizePerPage,
skip: sizePerPage * (page - 1),
sortBy: sortField ? sortField : 'startDate',
sortOrder: sortOrder ? sortOrder : -1,
};
if (filter) {
fetchingParams = { ...fetchingParams, filter };
}
if (startDate) {
fetchingParams = {
...fetchingParams,
startDate: moment(startDate).format('YYYY-MM-DD'),
};
}
if (endDate) {
fetchingParams = {
...fetchingParams,
endDate: moment(endDate).format('YYYY-MM-DD'),
};
}
if (instrumentName) {
fetchingParams = { ...fetchingParams, instrument: instrumentName };
}
if (search) {
fetchingParams = { ...fetchingParams, search };
}
const data = useResource(InvestigationResource.listShape(), fetchingParams);
const totalSize = data && data.length > 0 ? data[0].meta?.page?.total : 0;
const user = useSelector((state) => state.user);
const { sessionId, isAdministrator } = user;
const history = useHistory();
const query = useQuery();
const location = useLocation();
function handleStartDateChange(date) {
setStartDate(date);
setPage(1);
}
const dateForFiltering = query.has('date')
? moment(query.get('date'), moment.HTML5_FMT.DATE)
: undefined;
function handleEndDateChange(date) {
setEndDate(date);
setPage(1);
}
function handleDateChange(date) {
const newQuery = new URLSearchParams(query);
function handleStartDateClear() {
setStartDate(undefined);
setPage(1);
}
if (date) {
newQuery.set('date', moment(date).format(moment.HTML5_FMT.DATE));
} else {
newQuery.delete('date');
}
function handleEndDateClear() {
setEndDate(undefined);
setPage(1);
}
history.replace(`${location.pathname}?${newQuery.toString()}`);
function handleTableChange(page, sizePerPage, sortField, sortOrder) {
setPage(page);
setSizePerPage(sizePerPage);
setSortField(sortField);
const order = sortOrder ? (sortOrder === 'asc' ? 1 : -1) : undefined;
setSortOrder(order);
}
function handleDateClear() {
const newQuery = new URLSearchParams(query);
newQuery.delete('date');
history.replace(`${location.pathname}?${newQuery.toString()}`);
function onSearch(query) {
setSearch(query);
setPage(1);
}
const expandRow = {
......@@ -235,36 +286,27 @@ function InvestigationTable(props) {
),
};
function isInvestigationMatching(investigation) {
if (!dateForFiltering) {
return true;
}
return investigation.endDate
? dateForFiltering.isBetween(
investigation.startDate,
investigation.endDate,
'day',
'[]'
)
: dateForFiltering.isSame(investigation.startDate, 'day');
}
return (
<>
<div className={styles.wrapper}>
<InvestigationDateFilter
rootClassName={styles.filter}
value={dateForFiltering && dateForFiltering.toDate()}
onDayChange={handleDateChange}
onClear={handleDateClear}
startValue={startDate}
onStartDayChange={handleStartDateChange}
onStartClear={handleStartDateClear}
startPlaceHolder={'Filter between dates'}
endValue={endDate}
onEndDayChange={handleEndDateChange}
onEndClear={handleEndDateClear}
endPlaceHolder={'Filter between dates'}
showStatisticsMenu={showStatisticsMenu}
instrumentName={instrumentName}
withJupyter={withJupyter}
/>
</div>
<ResponsiveTable
data={investigations.filter(isInvestigationMatching)}
remote={true}
data={data}
pageOptions={{
showTotal: true,
sizePerPageList: [
......@@ -272,6 +314,8 @@ function InvestigationTable(props) {
{ text: '50', value: 50 },
{ text: '100', value: 100 },
],
sizePerPage,
totalSize,
}}
columns={getColumns({
showProposalLinks: withProposalLinks || isAdministrator,
......@@ -282,6 +326,9 @@ function InvestigationTable(props) {
(UI.userPortal.isLinkEnabled && isAdministrator),
})}
expandRow={expandRow}
handleTableChange={handleTableChange}
onSearch={onSearch}
delay={1250}
/>
</>
);
......
......@@ -7,105 +7,140 @@ import { LinkContainer } from 'react-router-bootstrap';
import styles from './ResponsiveTable.module.css';
import { getCurrentBreakpoint } from '../../helpers';
class ResponsiveTable extends React.Component {
/**
* This method will calculate the headerStyle based on the ResponsiveHeaderStyle and the size of the window
* @param {array} columns BootstrapTable2 columns
*/
configure(columns) {
const size = getCurrentBreakpoint();
/**
* This method will calculate the headerStyle based on the ResponsiveHeaderStyle and the size of the window
* @param {array} columns BootstrapTable2 columns
*/
function configure(columns) {
const size = getCurrentBreakpoint();
return columns.map((column) =>
column.responsiveHeaderStyle && column.responsiveHeaderStyle[size]
? {
...column,
headerStyle: column.responsiveHeaderStyle[size],
hidden: column.responsiveHeaderStyle[size].hidden,
}
: column
);
}
return columns.map((column) =>
column.responsiveHeaderStyle && column.responsiveHeaderStyle[size]
? {
...column,
headerStyle: column.responsiveHeaderStyle[size],
hidden: column.responsiveHeaderStyle[size].hidden,
}
: column
);
}
function renderActionButton(btnProps) {
const { label, icon, ...otherProps } = btnProps;
return (
<Button key={label} {...otherProps}>
{icon && <Glyphicon className={styles.actionIcon} glyph={icon} />}
{label}
</Button>
);
}
export default function ResponsiveTable(props) {
const { SearchBar } = Search;
const {
keyField,
data,
columns,
search,
expandRow,
actions,
onSearch,
defaultSorted,
selectRow,
pageOptions,
rowEvents,
rowClasses,
delay,
remote = false,
} = props;
function onColumnMatch({ searchText, value, column, row }) {
if (column.onMatch) {
return column.onMatch(searchText, value, row, column.formatExtraData);
}
renderActionButton(btnProps) {
const { label, icon, ...otherProps } = btnProps;
return (
<Button key={label} {...otherProps}>
{icon && <Glyphicon className={styles.actionIcon} glyph={icon} />}
{label}
</Button>
value !== null &&
value !== undefined &&
value.toString().toLowerCase().includes(searchText)
);
}
render() {
const { SearchBar } = Search;
function handleTableChange(
type,
{ page, sizePerPage, sortField, sortOrder }
) {
if (props.handleTableChange) {
props.handleTableChange(page, sizePerPage, sortField, sortOrder);
}
}
function onColumnMatch({ searchText, value, column, row }) {
if (column.onMatch) {
return column.onMatch(searchText, value, row, column.formatExtraData);
const remoteProps = remote
? {
remote: {
filter: true,
pagination: true,
sort: true,
cellEdit: false,
},
}
: {};
return (
value !== null &&
value !== undefined &&
value.toString().toLowerCase().includes(searchText)
);
}
return (
<ToolkitProvider
keyField={this.props.keyField || 'id'}
data={this.props.data}
columns={this.configure(this.props.columns)}
search={{ onColumnMatch, ...this.props.search }}
expandRow={this.props.expandRow}
>
{({ baseProps, searchProps }) => (
<>
<div className={styles.bar}>
<div className={styles.actions}>
{(this.props.actions || []).map((action) => {
const { href, ...btnProps } = action;
if (!href) {
return this.renderActionButton(btnProps);
return (
<ToolkitProvider
keyField={keyField || 'id'}
data={data}
columns={configure(columns)}
search={{ onColumnMatch, ...search }}
expandRow={expandRow}
>
{({ baseProps, searchProps }) => (
<>
<div className={styles.bar}>
<div className={styles.actions}>
{(actions || []).map((action) => {
const { href, ...btnProps } = action;
if (!href) {
return renderActionButton(btnProps);
}
return (
<LinkContainer key={btnProps.label} to={action.href}>
{renderActionButton(btnProps)}
</LinkContainer>
);
})}
</div>
<div className={styles.search}>
<SearchBar
searchText={searchProps.searchText}
delay={delay ? delay : 250}
onSearch={(query) => {
searchProps.onSearch(query);
if (onSearch) {
onSearch(query);
}
return (
<LinkContainer key={btnProps.label} to={action.href}>
{this.renderActionButton(btnProps)}
</LinkContainer>
);
})}
</div>
<div className={styles.search}>
<SearchBar
searchText={searchProps.searchText}
onSearch={(query) => {
if (this.props.onSearch) {
this.props.onSearch(query);
}
searchProps.onSearch(query);
}}
/>
</div>
}}
/>
</div>
<BootstrapTable2
striped
hover
condensed
showTotal
defaultSorted={this.props.defaultSorted}
selectRow={this.props.selectRow}
expandRow={this.props.expandRow}
pagination={paginationFactory(this.props.pageOptions)}
rowEvents={this.props.rowEvents}
rowClasses={this.props.rowClasses}
noDataIndication="No data to display"
{...baseProps}
/>
</>
)}
</ToolkitProvider>
);
}
</div>
<BootstrapTable2
{...remoteProps}
pagination={paginationFactory(pageOptions)}
onTableChange={handleTableChange}
striped
hover
condensed
defaultSorted={defaultSorted}
selectRow={selectRow}
expandRow={expandRow}
rowEvents={rowEvents}
rowClasses={rowClasses}
noDataIndication="No data to display"
{...baseProps}
/>
</>
)}
</ToolkitProvider>
);
}
export default ResponsiveTable;
import React from 'react';
import InvestigationTable from '../../components/Investigation/InvestigationTable';
import { useResource } from 'rest-hooks';
import InvestigationResource from '../../resources/investigation';
import { useParams } from 'react-router';
import UI from '../../config/ui';
function BeamlineDataTable(props) {
const { name } = useParams();
const { showStatisticsMenu = false } = props;
const investigations = useResource(InvestigationResource.listShape(), {
instrument: name,
});
return (
<InvestigationTable
investigations={investigations}
withInvestigationStats
withProposalLinks
showStatisticsMenu={showStatisticsMenu}
......
import React from 'react';
import { useResource } from 'rest-hooks';
import InvestigationTable from '../../components/Investigation/InvestigationTable';
import InvestigationResource from '../../resources/investigation';
function EmbargoedInvestigationsTable() {
const investigations = useResource(InvestigationResource.listShape(), {
filter: 'embargoed',
});
return <InvestigationTable investigations={investigations} />;
return <InvestigationTable filter="embargoed" />;
}
export default EmbargoedInvestigationsTable;
import React from 'react';
import { Panel, Glyphicon } from 'react-bootstrap';
import InvestigationTable from '../../components/Investigation/InvestigationTable';
import { useResource } from 'rest-hooks';
import InvestigationResource from '../../resources/investigation';
const INDUSTRY_PROPOSAL_REGEX = /^(IX|FX|IN|IM)/;
function MyIndustryProposalsPanel() {
const myInvestigations = useResource(InvestigationResource.listShape(), {
filter: 'participant',
});
// TODO replace `inv.visitId` with `inv.type !== "PROPOSAL"` when available
const industryProposals = myInvestigations.filter((inv) => {
return inv.visitId === 'PROPOSAL' && INDUSTRY_PROPOSAL_REGEX.test(inv.name);
});
if (industryProposals.length === 0) {
return null;
}
return (
<Panel bsStyle="info">
<Panel.Heading>
......@@ -34,7 +17,7 @@ function MyIndustryProposalsPanel() {
been scheduled for them.
</p>
<InvestigationTable
investigations={industryProposals}
filter="industry"
withInvestigationStats
withProposalLinks
/>
......
import React from 'react';
import { useResource } from 'rest-hooks';
import InvestigationResource from '../../resources/investigation';
import InvestigationTable from '../../components/Investigation/InvestigationTable';
import UI from '../../config/ui';
function MyInvestigationsTable() {
const myInvestigations = useResource(InvestigationResource.listShape(), {
filter: 'participant',
});
// TODO replace `inv.visitId` with `inv.type !== "PROPOSAL"` when available
const mySessions = myInvestigations.filter((inv) => {
return inv.visitId !== 'PROPOSAL';
});
return (
<InvestigationTable
investigations={mySessions}
filter="participant"
withInvestigationStats
withProposalLinks