fix: Issues on StudyList Filter (#1513)

* Fix instances font size

* Fixing sorting style and icons

* Fix clear filters flicking filter parent height

* Make filter size matching with study list table columns

* Addin width for grid24

* Use grid24 instead of 12

* Adding missing borders

* Fix gridCol division
This commit is contained in:
Gustavo André Lelis 2020-03-13 12:02:04 -03:00 committed by James A. Petts
parent 88846e5c70
commit 11bd7105d6
6 changed files with 210 additions and 96 deletions

View File

@ -1,3 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="9" height="16" viewBox="0 0 9 16"> <svg xmlns="http://www.w3.org/2000/svg" width="9" height="16" viewBox="0 0 9 16">
<path fill="currentColor" fill-rule="evenodd" d="M8.69 7.516L7.51 6.274 4.5 9.442 1.49 6.274 0.31 7.516 4.5 11.926z"/> <g fill="currentColor" fill-rule="evenodd">
<path d="M8.69 11.516L7.51 10.274 4.5 13.442 1.49 10.274 0.31 11.516 4.5 15.926z"/>
<path fill="transparent" d="M8.69 1.516L7.51 0.274 4.499 3.442 1.49 0.274 0.31 1.516 4.5 5.926z" transform="matrix(1 0 0 -1 0 6.2)"/>
</g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 212 B

After

Width:  |  Height:  |  Size: 380 B

View File

@ -1,5 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="9" height="16" viewBox="0 0 9 16"> <svg xmlns="http://www.w3.org/2000/svg" width="9" height="16" viewBox="0 0 9 16">
<g fill="currentColor" fill-rule="evenodd"> <g fill="currentColor" fill-rule="evenodd">
<path fill="currentColor" d="M8.69 1.516L7.51 0.274 4.499 3.442 1.49 0.274 0.31 1.516 4.5 5.926z" transform="translate(0 5) matrix(1 0 0 -1 0 6.2)"/> <path fill="transparent" d="M8.69 11.516L7.51 10.274 4.5 13.442 1.49 10.274 0.31 11.516 4.5 15.926z"/>
<path d="M8.69 1.516L7.51 0.274 4.499 3.442 1.49 0.274 0.31 1.516 4.5 5.926z" transform="matrix(1 0 0 -1 0 6.2)"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 380 B

View File

@ -7,6 +7,58 @@ import StudyListFilter from './components/StudyListFilter';
import StudyListTable from './components/StudyListTable'; import StudyListTable from './components/StudyListTable';
import StudyListPagination from './components/StudyListPagination'; import StudyListPagination from './components/StudyListPagination';
const filtersMeta = [
{
name: 'patientName',
displayName: 'Patient Name',
inputType: 'text',
isSortable: true,
gridCol: 4,
},
{
name: 'mrn',
displayName: 'MRN',
inputType: 'text',
isSortable: true,
gridCol: 2,
},
{
name: 'studyDate',
displayName: 'Study date',
inputType: 'text',
isSortable: true,
gridCol: 3,
},
{
name: 'description',
displayName: 'Description',
inputType: 'text',
isSortable: true,
gridCol: 5,
},
{
name: 'modality',
displayName: 'Modality',
inputType: 'text',
isSortable: true,
gridCol: 3,
},
{
name: 'accession',
displayName: 'Accession',
inputType: 'text',
isSortable: true,
gridCol: 4,
},
{
name: 'instances',
displayName: 'Instances',
inputType: 'none',
isSortable: false,
gridCol: 3,
},
];
const StudyList = ({ studies, perPage }) => { const StudyList = ({ studies, perPage }) => {
const studiesData = studies.slice(0, perPage); const studiesData = studies.slice(0, perPage);
const numOfStudies = studies.length; const numOfStudies = studies.length;
@ -18,8 +70,12 @@ const StudyList = ({ studies, perPage }) => {
})} })}
> >
<Header /> <Header />
<StudyListFilter numOfStudies={numOfStudies} /> <StudyListFilter numOfStudies={numOfStudies} filtersMeta={filtersMeta} />
<StudyListTable studies={studiesData} numOfStudies={numOfStudies} /> <StudyListTable
studies={studiesData}
numOfStudies={numOfStudies}
filtersMeta={filtersMeta}
/>
{!isEmptyStudies && <StudyListPagination />} {!isEmptyStudies && <StudyListPagination />}
</div> </div>
); );

View File

@ -11,45 +11,6 @@ const sortIconMap = {
}; };
const defaultProps = { const defaultProps = {
numOfStudies: 0,
filterMeta: [
{
name: 'patientName',
displayName: 'Patient Name',
inputType: 'text',
isSortable: true,
},
{
name: 'mrn',
displayName: 'MRN',
inputType: 'text',
isSortable: true,
},
{
name: 'studyDate',
displayName: 'Study date',
inputType: 'text',
isSortable: true,
},
{
name: 'description',
displayName: 'Description',
inputType: 'text',
isSortable: true,
},
{
name: 'modality',
displayName: 'Modality',
inputType: 'text',
isSortable: true,
},
{
name: 'accession',
displayName: 'Accession',
inputType: 'text',
isSortable: true,
},
],
filtersValues: { filtersValues: {
patientName: '', patientName: '',
mrn: '', mrn: '',
@ -70,6 +31,7 @@ const FilterLabel = ({
isBeingSorted = false, isBeingSorted = false,
sortDirection = 0, sortDirection = 0,
onLabelClick, onLabelClick,
inputType,
className, className,
children, children,
}) => { }) => {
@ -87,11 +49,14 @@ const FilterLabel = ({
return ( return (
<label <label
className={classnames( className={classnames(
'flex flex-col flex-1 text-white text-lg pl-1', 'flex flex-col flex-1 text-white text-lg pl-1 select-none',
className className
)} )}
> >
<span className="flex flex-row" onClick={handleLabelClick}> <span
className="flex flex-row items-center cursor-pointer"
onClick={handleLabelClick}
>
{label} {label}
{isSortable && ( {isSortable && (
<Icon <Icon
@ -100,15 +65,15 @@ const FilterLabel = ({
/> />
)} )}
</span> </span>
{children} <span>{children}</span>
</label> </label>
); );
}; };
const StudyListFilter = ({ const StudyListFilter = ({
filtersMeta = defaultProps.filterMeta, filtersMeta = [],
filtersValues = defaultProps.filtersValues, filtersValues = defaultProps.filtersValues,
numOfStudies = 0, numOfStudies = 90,
}) => { }) => {
const [currentFiltersValues, setcurrentFiltersValues] = useState( const [currentFiltersValues, setcurrentFiltersValues] = useState(
filtersValues filtersValues
@ -116,11 +81,19 @@ const StudyListFilter = ({
const { sortBy, sortDirection } = currentFiltersValues; const { sortBy, sortDirection } = currentFiltersValues;
const handleFilterLabelClick = name => { const handleFilterLabelClick = name => {
let _sortDirection = 1;
if (sortBy === name) {
_sortDirection = sortDirection + 1;
if (_sortDirection > 1) {
_sortDirection = -1;
}
}
if (numOfStudies <= 100) { if (numOfStudies <= 100) {
setcurrentFiltersValues(prevState => ({ setcurrentFiltersValues(prevState => ({
...prevState, ...prevState,
sortBy: name, sortBy: _sortDirection !== 0 ? name : '',
sortDirection: sortDirection === 1 || sortBy === name ? -1 : 1, sortDirection: _sortDirection,
})); }));
} }
}; };
@ -151,9 +124,9 @@ const StudyListFilter = ({
}; };
return ( return (
<div className="bg-custom-navyDark"> <div className="bg-custom-navyDark border-t-4 border-black">
<div className="container m-auto relative flex flex-col pt-5 pb-3 px-4"> <div className="container m-auto relative flex flex-col pt-5 pb-3">
<div className="flex flex-row justify-between mb-5"> <div className="flex flex-row justify-between mb-5 px-12">
<div className="flex flex-row"> <div className="flex flex-row">
<Typography variant="h4" className="text-custom-aquaBright mr-6"> <Typography variant="h4" className="text-custom-aquaBright mr-6">
Study List Study List
@ -173,7 +146,7 @@ const StudyListFilter = ({
</Button> </Button>
</div> </div>
</div> </div>
<div className="flex flex-row items-baseline"> <div className="flex flex-row">
{isFiltering() && ( {isFiltering() && (
<Button <Button
rounded="full" rounded="full"
@ -186,41 +159,49 @@ const StudyListFilter = ({
Clear filters Clear filters
</Button> </Button>
)} )}
<Typography variant="h4" className="text-white mr-2"> <Typography variant="h4" className="mr-2">
{numOfStudies > 100 ? '>100' : numOfStudies} {numOfStudies > 100 ? '>100' : numOfStudies}
</Typography> </Typography>
<Typography variant="h6" className="text-custom-grayLight"> <Typography
variant="h6"
className="text-custom-grayLight self-end pb-1"
>
Studies Studies
</Typography> </Typography>
</div> </div>
</div> </div>
<div className="flex flex-row"> <div className="flex flex-row w-full">
{filtersMeta.map(({ name, displayName, inputType, isSortable }) => { {filtersMeta.map(
return ( ({ name, displayName, inputType, isSortable, gridCol }) => {
<FilterLabel return (
key={name} <div
label={displayName} className={classnames(`w-${gridCol}/24`, 'pl-4 first:pl-12')}
isSortable={ >
isSortable && numOfStudies <= 100 && numOfStudies > 0 <FilterLabel
} key={name}
isBeingSorted={sortBy === name} label={displayName}
sortDirection={sortDirection} isSortable={
onLabelClick={() => handleFilterLabelClick(name)} isSortable && numOfStudies <= 100 && numOfStudies > 0
inputType={inputType} }
> isBeingSorted={sortBy === name}
<Input sortDirection={sortDirection}
className="border-custom-blue mt-2 bg-black" onLabelClick={() => handleFilterLabelClick(name)}
type="text" inputType={inputType}
containerClassName="mr-2" >
value={currentFiltersValues[name] || ''} {inputType !== 'none' && (
onChange={event => handleFilterValueChange(event, name)} <Input
/> className="border-custom-blue mt-2 bg-black"
</FilterLabel> type="text"
); containerClassName="mr-2"
})} value={currentFiltersValues[name] || ''}
<label className="text-white text-sm pl-1 flex flex-1"> onChange={event => handleFilterValueChange(event, name)}
Instances />
</label> )}
</FilterLabel>
</div>
);
}
)}
</div> </div>
</div> </div>
</div> </div>
@ -233,6 +214,7 @@ StudyListFilter.propTypes = {
dsplayName: PropTypes.string, dsplayName: PropTypes.string,
inputType: PropTypes.oneOf(['text', 'select', 'date-range', 'none']), inputType: PropTypes.oneOf(['text', 'select', 'date-range', 'none']),
isSortable: PropTypes.bool, isSortable: PropTypes.bool,
gridCol: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
}), }),
filtersValues: PropTypes.object, filtersValues: PropTypes.object,
numOfStudies: PropTypes.number, numOfStudies: PropTypes.number,

View File

@ -1,9 +1,15 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
import { format } from 'date-fns'; import { format } from 'date-fns';
import { Button, Icon, Typography } from '@ohif/ui'; import { Button, Icon, Typography } from '@ohif/ui';
const getGridColClass = (filtersMeta, name) => {
const filter = filtersMeta.find(filter => filter.name === name);
return (filter && filter.gridCol && `w-${filter.gridCol}/24`) || '';
};
const TableRow = props => { const TableRow = props => {
const { const {
AccessionNumber, AccessionNumber,
@ -14,6 +20,7 @@ const TableRow = props => {
PatientName, PatientName,
StudyDate, StudyDate,
series, series,
filtersMeta,
} = props; } = props;
const [isOpened, setIsOpened] = useState(false); const [isOpened, setIsOpened] = useState(false);
@ -53,22 +60,63 @@ const TableRow = props => {
)} )}
onClick={toggleRow} onClick={toggleRow}
> >
<td className={classnames(...tdClasses)}> <td
<Icon name={ChevronIconName} /> className={classnames(
...tdClasses,
getGridColClass(filtersMeta, 'patientName')
)}
>
<div className="flex flex-row items-center pl-1">
<Icon name={ChevronIconName} className="mr-4" />
{PatientName}
</div>
</td> </td>
<td className={classnames(...tdClasses)}>{PatientName}</td> <td
<td className={classnames(...tdClasses)}>{PatientId}</td> className={classnames(
<td className={classnames(...tdClasses)}> ...tdClasses,
getGridColClass(filtersMeta, 'mrn')
)}
>
{PatientId}
</td>
<td
className={classnames(
...tdClasses,
getGridColClass(filtersMeta, 'studyDate')
)}
>
{format(StudyDate, 'MMM-DD-YYYY')} {format(StudyDate, 'MMM-DD-YYYY')}
</td> </td>
<td className={classnames(...tdClasses)}> <td
className={classnames(
...tdClasses,
getGridColClass(filtersMeta, 'description')
)}
>
{StudyDescription} {StudyDescription}
</td> </td>
<td className={classnames(...tdClasses)}>{Modalities}</td> <td
<td className={classnames(...tdClasses)}> className={classnames(
...tdClasses,
getGridColClass(filtersMeta, 'modality')
)}
>
{Modalities}
</td>
<td
className={classnames(
...tdClasses,
getGridColClass(filtersMeta, 'accession')
)}
>
{AccessionNumber} {AccessionNumber}
</td> </td>
<td className={classnames(...tdClasses)}> <td
className={classnames(
...tdClasses,
getGridColClass(filtersMeta, 'instances')
)}
>
<Icon <Icon
name="series-active" name="series-active"
className={classnames('inline-flex mr-2', { className={classnames('inline-flex mr-2', {
@ -81,7 +129,7 @@ const TableRow = props => {
</tr> </tr>
{isOpened && ( {isOpened && (
<tr className={classnames('bg-black')}> <tr className={classnames('bg-black')}>
<td colSpan="8" className="py-4 pl-20 pr-2"> <td colSpan="7" className="py-4 pl-12 pr-2">
<div className="flex"> <div className="flex">
<Button <Button
rounded="full" rounded="full"
@ -196,10 +244,10 @@ TableRow.propTypes = {
series: PropTypes.array.isRequired, series: PropTypes.array.isRequired,
}; };
const StudyListTable = ({ studies, numOfStudies }) => { const StudyListTable = ({ studies, numOfStudies, filtersMeta }) => {
const renderTable = () => { const renderTable = () => {
return ( return (
<table className="w-full text-white"> <table className="w-full text-white border-t-4 border-black">
<tbody> <tbody>
{studies.map((study, i) => ( {studies.map((study, i) => (
<TableRow <TableRow
@ -212,6 +260,7 @@ const StudyListTable = ({ studies, numOfStudies }) => {
PatientName={study.PatientName || ''} PatientName={study.PatientName || ''}
StudyDate={study.StudyDate || ''} StudyDate={study.StudyDate || ''}
series={study.series || []} series={study.series || []}
filtersMeta={filtersMeta}
/> />
))} ))}
</tbody> </tbody>

View File

@ -469,6 +469,29 @@ module.exports = {
'9/12': '75%', '9/12': '75%',
'10/12': '83.333333%', '10/12': '83.333333%',
'11/12': '91.666667%', '11/12': '91.666667%',
'1/24': '4.166666667%',
'2/24': '8.333333333%',
'3/24': '12.5%',
'4/24': '16.66666667%',
'5/24': '20.83333333%',
'6/24': '25%',
'7/24': '29.16666667%',
'8/24': '33.33333333%',
'9/24': '37.5%',
'10/24': '41.66666667%',
'11/24': '45.83333333%',
'12/24': '50%',
'13/24': '54.16666667%',
'14/24': '58.33333333%',
'15/24': '62.5%',
'16/24': '66.66666667%',
'17/24': '70.83333333%',
'18/24': '75%',
'19/24': '79.16666667%',
'20/24': '83.33333333%',
'21/24': '87.5%',
'22/24': '91.66666667%',
'23/24': '95.83333333%',
full: '100%', full: '100%',
screen: '100vw', screen: '100vw',
}), }),
@ -709,7 +732,7 @@ module.exports = {
order: ['responsive'], order: ['responsive'],
outline: ['responsive', 'focus'], outline: ['responsive', 'focus'],
overflow: ['responsive'], overflow: ['responsive'],
padding: ['responsive'], padding: ['responsive', 'first'],
placeholderColor: ['responsive', 'focus'], placeholderColor: ['responsive', 'focus'],
pointerEvents: ['responsive'], pointerEvents: ['responsive'],
position: ['responsive'], position: ['responsive'],