feat: StudyListTable, ExpandedRow, API definitions (#1579)

* feat: StudyListTable Refactor

* feat: StudyListTable + Props Refactor

* fix expanded rows handler

* update and fix study list doc page

* fix date format

* use moment to format date

* expose new components

* fix study list expanded row

* Export and Create doc page for Pagination

* API Definition, Export and Doc page for StudyListTable

* StudyListTableRow

* use real example to mount study list

* move files

* temporary change study list (viewer) structure

* fix studyList

* remove unused files

* remove file

* remove unused package

* PR fixes

* Remove console.dir

Co-authored-by: Gustavo Lelis <galelis@gmail.com>
This commit is contained in:
Rodrigo Antinarelli 2020-04-02 16:58:18 -03:00 committed by James A. Petts
parent 056f56f5b4
commit f4b078912a
21 changed files with 858 additions and 240 deletions

View File

@ -27,6 +27,9 @@ export {
Label,
NavBar,
Select,
StudyListExpandedRow,
StudyListPagination,
StudyListTable,
Svg,
Table,
TableBody,

View File

@ -26,7 +26,6 @@
},
"dependencies": {
"classnames": "^2.2.6",
"date-fns": "^2.10.0",
"docz": "^2.2.0",
"gatsby": "2.19.24",
"gatsby-plugin-postcss": "^2.1.20",

View File

@ -0,0 +1,50 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Table, TableHead, TableBody, TableRow, TableCell } from '@ohif/ui';
const StudyListExpandedRow = ({
seriesTableColumns,
seriesTableDataSource,
children,
}) => {
return (
<div className="w-full bg-black py-4 pl-12 pr-2">
<div className="block">{children}</div>
<div className="mt-4">
<Table>
<TableHead>
<TableRow>
{Object.keys(seriesTableColumns).map((columnKey) => {
return (
<TableCell key={columnKey}>
{seriesTableColumns[columnKey]}
</TableCell>
);
})}
</TableRow>
</TableHead>
<TableBody>
{seriesTableDataSource.map((row, i) => (
<TableRow key={i}>
{Object.keys(row).map((cellKey) => {
const content = row[cellKey];
return <TableCell key={cellKey}>{content}</TableCell>;
})}
</TableRow>
))}
</TableBody>
</Table>
</div>
</div>
);
};
StudyListExpandedRow.propTypes = {
seriesTableDataSource: PropTypes.arrayOf(PropTypes.object).isRequired,
seriesTableColumns: PropTypes.object.isRequired,
children: PropTypes.node.isRequired,
};
export default StudyListExpandedRow;

View File

@ -0,0 +1,2 @@
import StudyListExpandedRow from './StudyListExpandedRow';
export default StudyListExpandedRow;

View File

@ -1,18 +1,22 @@
import React, { useState } from 'react';
import {
Typography,
ButtonGroup,
Button,
IconButton,
Icon,
} from '../../../components/';
import React from 'react';
import PropTypes from 'prop-types';
import { Button, ButtonGroup, Icon, IconButton, Typography } from '@ohif/ui';
<<<<<<< HEAD:platform/ui/src/views/StudyList/components/StudyListPagination.js
const StudyListPagination = (props) => {
const [currentPage, setCurrentPage] = useState(1);
=======
const StudyListPagination = ({
onChangePage,
currentPage,
perPage,
onChangePerPage,
}) => {
>>>>>>> d5a288db1... feat: StudyListTable, ExpandedRow, API definitions (#1579):platform/ui/src/components/StudyListPagination/StudyListPagination.js
const navigateToPage = (page) => {
const toPage = page < 1 ? 1 : page;
setCurrentPage(toPage);
onChangePage(toPage);
};
return (
@ -22,9 +26,15 @@ const StudyListPagination = (props) => {
<div className="flex items-center">
<div className="relative mr-3">
<select
<<<<<<< HEAD:platform/ui/src/views/StudyList/components/StudyListPagination.js
defaultValue="25"
className="block appearance-none w-full bg-transparent border border-common-active text-white text-base px-2 pr-4 rounded leading-tight focus:outline-none"
=======
defaultValue={perPage}
className="block appearance-none w-full bg-transparent border border-custom-darkSlateBlue text-white text-base px-2 pr-4 rounded leading-tight focus:outline-none"
>>>>>>> d5a288db1... feat: StudyListTable, ExpandedRow, API definitions (#1579):platform/ui/src/components/StudyListPagination/StudyListPagination.js
style={{ height: 28 }}
onChange={(e) => onChangePerPage(e.target.value)}
>
<option value="25">25</option>
<option value="50">50</option>
@ -82,4 +92,11 @@ const StudyListPagination = (props) => {
);
};
StudyListPagination.propTypes = {
onChangePage: PropTypes.func.isRequired,
currentPage: PropTypes.number.isRequired,
perPage: PropTypes.number.isRequired,
onChangePerPage: PropTypes.func.isRequired,
};
export default StudyListPagination;

View File

@ -0,0 +1,45 @@
---
name: Study List Pagination
menu: Components
route: components/studyListPagination
---
import { useState } from 'react';
import { Playground, Props } from 'docz';
import { StudyListPagination } from '@ohif/ui';
# StudyListPagination
## Import
```javascript
import { StudyListPagination } from '@ohif/ui';
```
## Basic usage
<Playground>
{() => {
const [currentPage, setCurrentPage] = useState(1);
const [perPage, setPerPage] = useState(25);
const onChangePage = (page) => {
setCurrentPage(page);
};
const onChangePerPage = (perPage) => {
setPerPage(perPage);
setCurrentPage(1);
};
return (
<StudyListPagination
onChangePage={onChangePage}
onChangePerPage={onChangePerPage}
currentPage={currentPage}
perPage={perPage}
/>
);
}}
</Playground>
## Properties
<Props of={StudyListPagination} />

View File

@ -0,0 +1,3 @@
import StudyListPagination from './StudyListPagination';
export default StudyListPagination;

View File

@ -0,0 +1,35 @@
import React from 'react';
import PropTypes from 'prop-types';
import StudyListTableRow from './StudyListTableRow';
const StudyListTable = ({ tableDataSource }) => {
return (
<>
<div className="bg-black">
<div className="container m-auto relative">
<table className="w-full text-white">
<tbody>
{tableDataSource.map((tableData, i) => {
return <StudyListTableRow tableData={tableData} key={i} />;
})}
</tbody>
</table>
</div>
</div>
</>
);
};
StudyListTable.propTypes = {
tableDataSource: PropTypes.arrayOf(
PropTypes.shape({
row: PropTypes.array.isRequired,
expandedContent: PropTypes.node.isRequired,
onClickRow: PropTypes.func.isRequired,
isExpanded: PropTypes.bool.isRequired,
})
),
};
export default StudyListTable;

View File

@ -0,0 +1,62 @@
---
name: Study List Table
menu: Components
route: components/studyListTable
---
import { useState } from 'react';
import { Playground, Props } from 'docz';
import { StudyListTable } from '@ohif/ui';
# StudyListTable
This component is used to display a studies list.
## Import
```javascript
import { StudyListTable } from '@ohif/ui';
```
## Basic usage
<Playground>
{() => {
const studies = new Array(10).fill('');
const [expandedRows, setExpandedRows] = useState([]);
const tableDataSource = studies.map((study, key) => {
const rowKey = key + 1;
const isExpanded = expandedRows.some((k) => k === rowKey);
return {
row: [
{ key: 'Cell 01', content: 'Cell 01', gridCol: 2 },
{ key: 'Cell 02', content: 'Cell 02', gridCol: 4 },
{ key: 'Cell 03', content: 'Cell 03', gridCol: 4 },
{ key: 'Cell 04', content: 'Cell 04', gridCol: 4 },
],
expandedContent: (
<td className="w-full p-8">
Custom expanded content for row {rowKey}
</td>
),
onClickRow: () =>
setExpandedRows((rows) =>
isExpanded ? rows.filter((n) => rowKey !== n) : [...rows, rowKey]
),
isExpanded,
};
});
return (
<div className="py-4">
<StudyListTable
tableDataSource={tableDataSource}
numOfStudies={studies.length}
/>
</div>
);
}}
</Playground>
## Properties
<Props of={StudyListTable} />

View File

@ -0,0 +1,85 @@
import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
const StudyListTableRow = (props) => {
const { tableData } = props;
const { row, expandedContent, onClickRow, isExpanded } = tableData;
return (
<>
<tr>
<td
className={classnames('border-0 p-0', {
'border-b border-custom-violetPale bg-custom-navyDark': isExpanded,
})}
>
<div
className={classnames('w-full transition duration-300', {
'border border-custom-aquaBright rounded overflow-hidden mb-2 hover:border-custom-violetPale': isExpanded,
})}
>
<table className={classnames('w-full p-4')}>
<tbody>
<tr
className={classnames(
'cursor-pointer hover:bg-custom-violetDark transition duration-300 bg-black',
{
'bg-custom-navyDark': !isExpanded,
},
{ 'bg-custom-navy': isExpanded }
)}
onClick={onClickRow}
>
{row.map((cell) => {
const { content, gridCol, name } = cell;
return (
<td
key={name}
className={classnames(
'px-4 py-2 text-base',
{ 'border-b border-custom-violetPale': !isExpanded },
`w-${gridCol}/24` || ''
)}
>
<div className="flex flex-row items-center pl-1">
{content}
</div>
</td>
);
})}
</tr>
{isExpanded && (
<tr
className={classnames(
'w-full bg-black max-h-0 overflow-hidden'
)}
>
<td colSpan={row.length}>{expandedContent}</td>
</tr>
)}
</tbody>
</table>
</div>
</td>
</tr>
</>
);
};
StudyListTableRow.propTypes = {
tableData: PropTypes.shape({
row: PropTypes.arrayOf(
PropTypes.shape({
key: PropTypes.string.isRequired,
content: PropTypes.node.isRequired,
gridCol: PropTypes.number.isRequired,
})
).isRequired,
expandedContent: PropTypes.node.isRequired,
onClickRow: PropTypes.func.isRequired,
isExpanded: PropTypes.bool.isRequired,
}),
};
export default StudyListTableRow;

View File

@ -0,0 +1,3 @@
import StudyListTable from './StudyListTable';
export default StudyListTable;

View File

@ -14,6 +14,9 @@ import Label from './Label';
import NavBar from './NavBar';
import Select from './Select';
import Svg from './Svg';
import StudyListExpandedRow from './StudyListExpandedRow';
import StudyListPagination from './StudyListPagination';
import StudyListTable from './StudyListTable';
import Table from './Table';
import TableBody from './TableBody';
import TableCell from './TableCell';
@ -39,6 +42,9 @@ export {
NavBar,
Select,
Svg,
StudyListExpandedRow,
StudyListPagination,
StudyListTable,
Table,
TableBody,
TableCell,

View File

@ -4,7 +4,7 @@
"StudyInstanceUID": "1.2.840.113619.2.5.1762583153.215519.978957063.78",
"StudyDescription": "BRAIN SELLA",
"AccessionNumber": "11788761116031",
"StudyDate": "20010108",
"StudyDate": "2020-03-26T23:33:59.073Z",
"StudyTime": "120022",
"PatientName": "MISTER^MR",
"PatientId": "832040",

View File

@ -1,3 +0,0 @@
export default string => {
return string.charAt(0).toUpperCase() + string.slice(1);
};

View File

@ -1,15 +0,0 @@
/**
* Calculates the number of instances in series
* @param {array} series
* @returns {number} Number of instances in series
*/
const getInstances = series => {
const instances = series.reduce((acc, item) => {
return acc + item.instances.length;
}, 0);
return instances;
};
export default getInstances;

View File

@ -1,20 +0,0 @@
/**
* Get formatted Modalities
* @param {array} series
* @returns {string} Formatted modalities
*/
const getModalities = series => {
const modalities = series.reduce((acc, item) => {
const { Modality } = item;
if (acc.includes(Modality)) {
return acc;
}
acc.push(Modality);
return acc;
}, []);
return modalities.join('/');
};
export default getModalities;

View File

@ -1,10 +1,7 @@
import capitalize from './capitalize';
import getMockedStudies from './getMockedStudies';
import getModalities from './getModalities';
import getInstances from './getInstances';
const utils = { capitalize, getMockedStudies, getModalities, getInstances };
const utils = { getMockedStudies };
export { capitalize, getMockedStudies, getModalities, getInstances };
export { getMockedStudies };
export default utils;

View File

@ -1,11 +1,23 @@
/**
* THIS IS A TEMPORARY FILE -- SHOULD BE REMOVED
*/
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import moment from 'moment';
import {
EmptyStudies,
utils,
Icon,
StudyListExpandedRow,
Button,
StudyListPagination,
StudyListTable,
} from '@ohif/ui';
// fix imports after refactor
import Header from './components/Header';
import StudyListFilter from './components/StudyListFilter';
import StudyListTable from './components/StudyListTable';
import StudyListPagination from './components/StudyListPagination';
const filtersMeta = [
{
@ -84,21 +96,175 @@ const defaultFilterValues = {
};
const isFiltering = (filterValues, defaultFilterValues) => {
return Object.keys(defaultFilterValues).some(name => {
return Object.keys(defaultFilterValues).some((name) => {
return filterValues[name] !== defaultFilterValues[name];
});
};
const StudyList = ({ studies, perPage }) => {
const StudyList = () => {
const [filterValues, setFilterValues] = useState(defaultFilterValues);
const studiesData = studies.slice(0, perPage);
const studies = utils.getMockedStudies();
const numOfStudies = studies.length;
const isEmptyStudies = numOfStudies === 0;
const [expandedRows, setExpandedRows] = useState([]);
const tableDataSource = studies.map((study, key) => {
const rowKey = key + 1;
const isExpanded = expandedRows.some((k) => k === rowKey);
const {
AccessionNumber,
Modalities,
Instances,
StudyDescription,
PatientId,
PatientName,
StudyDate,
series,
} = study;
const seriesTableColumns = {
description: 'Description',
seriesNumber: 'Series',
modality: 'Modality',
Instances: 'Instances',
};
const seriesTableDataSource = series.map((seriesItem) => {
const { SeriesNumber, Modality, instances } = seriesItem;
return {
description: 'Patient Protocol',
seriesNumber: SeriesNumber,
modality: Modality,
Instances: instances.length,
};
});
return {
row: [
{
key: 'patientName',
content: (
<>
<Icon
name={isExpanded ? 'chevron-down' : 'chevron-right'}
className="mr-4"
/>
{PatientName}
</>
),
gridCol: 4,
},
{
key: 'mrn',
content: PatientId,
gridCol: 2,
},
{
key: 'studyDate',
content: (
<div>
<span className="mr-4">
{moment(StudyDate).format('MMM-DD-YYYY')}
</span>
<span>{moment(StudyDate).format('hh:mm A')}</span>
</div>
),
gridCol: 5,
},
{
key: 'description',
content: StudyDescription,
gridCol: 4,
},
{
key: 'modality',
content: Modalities,
gridCol: 3,
},
{
key: 'accession',
content: AccessionNumber,
gridCol: 4,
},
{
key: 'instances',
content: (
<>
<Icon
name="series-active"
className={classnames('inline-flex mr-2', {
'text-custom-blueBright': isExpanded,
'text-custom-violetPale': !isExpanded,
})}
/>
{Instances}
</>
),
gridCol: 4,
},
],
expandedContent: (
<StudyListExpandedRow
seriesTableColumns={seriesTableColumns}
seriesTableDataSource={seriesTableDataSource}
>
<Button
rounded="full"
variant="contained"
className="mr-4 font-bold"
endIcon={<Icon name="launch-arrow" style={{ color: '#21a7c6' }} />}
>
Basic Viewer
</Button>
<Button
rounded="full"
variant="contained"
className="mr-4 font-bold"
endIcon={<Icon name="launch-arrow" style={{ color: '#21a7c6' }} />}
>
Segmentation
</Button>
<Button
rounded="full"
variant="outlined"
endIcon={<Icon name="launch-info" />}
className="font-bold"
>
Module 3
</Button>
<div className="ml-5 text-lg text-custom-grayBright inline-flex items-center">
<Icon name="notificationwarning-diamond" className="mr-2 w-5 h-5" />
Feedback text lorem ipsum dolor sit amet
</div>
</StudyListExpandedRow>
),
onClickRow: () =>
setExpandedRows((s) =>
isExpanded ? s.filter((n) => rowKey !== n) : [...s, rowKey]
),
isExpanded,
};
});
const [currentPage, setCurrentPage] = useState(1);
const [perPage, setPerPage] = useState(25);
const totalPages = Math.floor(numOfStudies / perPage);
const onChangePage = (page) => {
if (page > totalPages) {
return;
}
setCurrentPage(page);
};
const onChangePerPage = (perPage) => {
setPerPage(perPage);
setCurrentPage(1);
};
const hasStudies = numOfStudies > 0;
return (
<div
className={classnames('bg-black h-full', {
'h-screen': isEmptyStudies,
'h-screen': !hasStudies,
})}
>
<Header />
@ -110,24 +276,28 @@ const StudyList = ({ studies, perPage }) => {
clearFilters={() => setFilterValues(defaultFilterValues)}
isFiltering={isFiltering(filterValues, defaultFilterValues)}
/>
<StudyListTable
studies={studiesData}
numOfStudies={numOfStudies}
filtersMeta={filtersMeta}
/>
{!isEmptyStudies && <StudyListPagination />}
{hasStudies ? (
<>
<StudyListTable
tableDataSource={tableDataSource}
numOfStudies={numOfStudies}
filtersMeta={filtersMeta}
/>
<StudyListPagination
onChangePage={onChangePage}
onChangePerPage={onChangePerPage}
currentPage={currentPage}
perPage={perPage}
/>
</>
) : (
<div className="flex flex-col items-center justify-center pt-48">
<EmptyStudies />
</div>
)}
</div>
);
};
StudyList.defaultProps = {
studies: [],
perPage: 25,
};
StudyList.propTypes = {
studies: PropTypes.array,
perPage: PropTypes.number,
};
export default StudyList;

View File

@ -4,10 +4,28 @@ menu: Views
route: views/studyList
---
import { useState } from 'react'
import { useState } from 'react';
import { Playground, Props } from 'docz';
import { StudyList, Button } from '@ohif/ui';
import { getMockedStudies } from '../../utils/'
import {
StudyList,
utils,
Icon,
StudyListExpandedRow,
Button,
NavBar,
Svg,
IconButton,
EmptyStudies,
StudyListTable,
StudyListPagination,
} from '@ohif/ui';
<!-- TEMPORARY IMPORTING -- SHOULD USE InputGroup after PR #1580 gets merged -->
import StudyListFilter from './components/StudyListFilter';
import { getMockedStudies } from '../../utils/';
import classnames from 'classnames';
import moment from 'moment';
# StudyList
@ -23,25 +41,325 @@ import { StudyList } from '@ohif/ui';
<Playground>
{() => {
const [studies, setStudies] = useState([])
const defaultFilterValues = {
patientName: '',
mrn: '',
studyDate: {
startDate: null,
endDate: null,
},
description: '',
modality: undefined,
accession: '',
sortBy: '',
sortDirection: 'none',
page: 0,
resultsPerPage: 25,
};
const [filterValues, setFilterValues] = useState(defaultFilterValues);
const [studies, setStudies] = useState([]);
const numOfStudies = studies.length;
const [expandedRows, setExpandedRows] = useState([]);
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: 'DateRange',
isSortable: true,
gridCol: 5,
},
{
name: 'description',
displayName: 'Description',
inputType: 'Text',
isSortable: true,
gridCol: 4,
},
{
name: 'modality',
displayName: 'Modality',
inputType: 'MultiSelect',
inputProps: {
options: [
{ value: 'SEG', label: 'SEG' },
{ value: 'CT', label: 'CT' },
{ value: 'MR', label: 'MR' },
{ value: 'SR', label: 'SR' },
],
},
isSortable: true,
gridCol: 3,
},
{
name: 'accession',
displayName: 'Accession',
inputType: 'Text',
isSortable: true,
gridCol: 4,
},
{
name: 'instances',
displayName: 'Instances',
inputType: 'None',
isSortable: true,
gridCol: 2,
},
];
const isFiltering = (filterValues, defaultFilterValues) => {
return Object.keys(defaultFilterValues).some(name => {
return filterValues[name] !== defaultFilterValues[name];
});
};
const tableDataSource = studies.map((study, key) => {
const rowKey = key + 1;
const isExpanded = expandedRows.some((k) => k === rowKey);
const {
AccessionNumber,
Modalities,
Instances,
StudyDescription,
PatientId,
PatientName,
StudyDate,
series,
} = study;
const seriesTableColumns = {
description: 'Description',
seriesNumber: 'Series',
modality: 'Modality',
Instances: 'Instances',
};
const seriesTableDataSource = series.map((seriesItem) => {
const { SeriesNumber, Modality, instances } = seriesItem;
return {
description: 'Patient Protocol',
seriesNumber: SeriesNumber,
modality: Modality,
Instances: instances.length,
};
});
return {
row: [
{
key: 'patientName',
content: (
<>
<Icon
name={isExpanded ? 'chevron-down' : 'chevron-right'}
className="mr-4"
/>
{PatientName}
</>
),
gridCol: 4,
},
{
key: 'mrn',
content: PatientId,
gridCol: 2,
},
{
key: 'studyDate',
content: (
<div>
<span className="mr-4">
{moment(StudyDate).format('MMM-DD-YYYY')}
</span>
<span>{moment(StudyDate).format('hh:mm A')}</span>
</div>
),
gridCol: 5,
},
{
key: 'description',
content: StudyDescription,
gridCol: 4,
},
{
key: 'modality',
content: Modalities,
gridCol: 3,
},
{
key: 'accession',
content: AccessionNumber,
gridCol: 4,
},
{
key: 'instances',
content: (
<>
<Icon
name="series-active"
className={classnames('inline-flex mr-2', {
'text-custom-blueBright': isExpanded,
'text-custom-violetPale': !isExpanded,
})}
/>
{Instances}
</>
),
gridCol: 4,
},
],
expandedContent: (
<StudyListExpandedRow
seriesTableColumns={seriesTableColumns}
seriesTableDataSource={seriesTableDataSource}
>
<Button
rounded="full"
variant="contained"
className="mr-4 font-bold"
endIcon={
<Icon name="launch-arrow" style={{ color: '#21a7c6' }} />
}
>
Basic Viewer
</Button>
<Button
rounded="full"
variant="contained"
className="mr-4 font-bold"
endIcon={
<Icon name="launch-arrow" style={{ color: '#21a7c6' }} />
}
>
Segmentation
</Button>
<Button
rounded="full"
variant="outlined"
endIcon={<Icon name="launch-info" />}
className="font-bold"
>
Module 3
</Button>
<div className="ml-5 text-lg text-custom-grayBright inline-flex items-center">
<Icon
name="notificationwarning-diamond"
className="mr-2 w-5 h-5"
/>
Feedback text lorem ipsum dolor sit amet
</div>
</StudyListExpandedRow>
),
onClickRow: () =>
setExpandedRows((s) =>
isExpanded ? s.filter((n) => rowKey !== n) : [...s, rowKey]
),
isExpanded,
};
});
const handleStudyList = (number) => {
const studies = getMockedStudies(number)
setStudies(studies)
}
const studies = getMockedStudies(number);
setStudies(studies);
setCurrentPage(1);
};
const [currentPage, setCurrentPage] = useState(1);
const [perPage, setPerPage] = useState(25);
const totalPages = Math.floor(numOfStudies / perPage);
const onChangePage = (page) => {
if (page > totalPages) {
return;
}
setCurrentPage(page);
};
const onChangePerPage = (perPage) => {
setPerPage(perPage);
setCurrentPage(1);
};
const hasStudies = numOfStudies > 0;
return (
<div>
<div className="bg-white p-4">
<Button className="mr-2" onClick={() => handleStudyList(0)}>0 Studies</Button>
<Button className="mr-2" onClick={() => handleStudyList(50)}>50 Studies</Button>
<Button className="mr-2" onClick={() => handleStudyList(100)}>100 Studies</Button>
<Button className="mr-2" onClick={() => handleStudyList(1000)}>1000 Studies</Button>
<Button className="mr-2" onClick={() => handleStudyList(0)}>
0 Studies
</Button>
<Button className="mr-2" onClick={() => handleStudyList(50)}>
50 Studies
</Button>
<Button className="mr-2" onClick={() => handleStudyList(100)}>
100 Studies
</Button>
<Button className="mr-2" onClick={() => handleStudyList(1000)}>
1000 Studies
</Button>
</div>
<div
className={classnames('bg-black h-full', {
'h-screen': !hasStudies,
})}
>
<NavBar className="justify-between border-b-4 border-black">
<div className="flex items-center">
<div className="mx-3">
<Svg name="logo-ohif" />
</div>
</div>
<div className="flex items-center">
<span className="mr-3 text-custom-grayLight text-lg">
FOR INVESTIGATIONAL USE ONLY
</span>
<IconButton
variant="text"
color="inherit"
className="text-custom-blueBright"
onClick={() => {}}
>
<React.Fragment>
<Icon name="settings" />
<Icon name="chevron-down" />
</React.Fragment>
</IconButton>
</div>
</NavBar>
<StudyListFilter
numOfStudies={numOfStudies}
filtersMeta={filtersMeta}
filterValues={filterValues}
setFilterValues={setFilterValues}
clearFilters={() => setFilterValues(defaultFilterValues)}
isFiltering={isFiltering(filterValues, defaultFilterValues)}
/>
{hasStudies ? (
<>
<StudyListTable
tableDataSource={tableDataSource.slice(
(currentPage - 1) * perPage,
(currentPage - 1) * perPage + perPage
)}
numOfStudies={numOfStudies}
filtersMeta={filtersMeta}
/>
<StudyListPagination
onChangePage={onChangePage}
onChangePerPage={onChangePerPage}
currentPage={currentPage}
perPage={perPage}
/>
</>
) : (
<div className="flex flex-col items-center justify-center pt-48">
<EmptyStudies />
</div>
)}
</div>
<StudyList studies={studies} />
</div>
);
}}
</Playground>
## Properties
<Props of={StudyList} />

View File

@ -3,125 +3,6 @@ import PropTypes from 'prop-types';
import { Button, Icon, Typography, InputGroup } from '@ohif/ui';
<<<<<<< HEAD
const isFiltering = (currentFiltersValues, filtersValues) => {
return Object.keys(currentFiltersValues).some((name) => {
const filterValue = currentFiltersValues[name];
return filterValue !== filtersValues[name];
});
};
const StudyListFilter = ({ filtersMeta, filtersValues, numOfStudies }) => {
const [currentFiltersValues, setcurrentFiltersValues] = useState(
filtersValues
);
const { sortBy, sortDirection } = currentFiltersValues;
const handleFilterLabelClick = (name) => {
let _sortDirection = 'ascending';
if (sortBy === name) {
if (sortDirection === 'ascending') {
_sortDirection = 'descending';
} else if (sortDirection === 'descending') {
_sortDirection = 'none';
}
}
if (numOfStudies <= 100) {
setcurrentFiltersValues((prevState) => ({
...prevState,
sortBy: _sortDirection !== 0 ? name : '',
sortDirection: _sortDirection,
}));
}
};
const clearFilters = () => {
setcurrentFiltersValues(filtersValues);
};
const renderFieldInputComponent = ({
name,
displayName,
inputProps,
isSortable,
inputType,
}) => {
const _isSortable = isSortable && numOfStudies <= 100 && numOfStudies > 0;
const _sortDirection = sortBy !== name ? 'none' : sortDirection;
const onLabelClick = () => {
if (_isSortable) {
handleFilterLabelClick(name);
}
};
switch (inputType) {
case 'Text':
return (
<InputText
key={name}
label={displayName}
isSortable={_isSortable}
sortDirection={_sortDirection}
onLabelClick={onLabelClick}
value={currentFiltersValues[name]}
onChange={(newValue) => {
setcurrentFiltersValues((prevState) => ({
...prevState,
[name]: newValue,
}));
}}
/>
);
break;
case 'MultiSelect':
return (
<InputMultiSelect
key={name}
label={displayName}
isSortable={_isSortable}
sortDirection={_sortDirection}
onLabelClick={onLabelClick}
options={inputProps.options}
value={currentFiltersValues[name]}
onChange={(newValue) => {
setcurrentFiltersValues((prevState) => ({
...prevState,
[name]: newValue,
}));
}}
/>
);
case 'DateRange':
return (
<InputDateRange
key={name}
label={displayName}
isSortable={_isSortable}
sortDirection={_sortDirection}
onLabelClick={onLabelClick}
value={currentFiltersValues[name]}
onChange={(newValue) => {
setcurrentFiltersValues((prevState) => ({
...prevState,
[name]: newValue,
}));
}}
/>
);
case 'None':
return (
<InputLabelWrapper
key={name}
label={displayName}
isSortable={_isSortable}
sortDirection={_sortDirection}
onLabelClick={onLabelClick}
/>
);
default:
break;
}
=======
const StudyListFilter = ({
filtersMeta,
filterValues,
@ -137,7 +18,6 @@ const StudyListFilter = ({
...filterValues,
...sortingValues,
});
>>>>>>> 26d8c8ae5... refactor: StudyListFilter refactor (#1580)
};
const isSortingEnable = numOfStudies > 0 && numOfStudies <= 100;
@ -194,26 +74,6 @@ const StudyListFilter = ({
</div>
</div>
<div className="sticky z-10 border-b-4 border-black" style={{ top: 58 }}>
<<<<<<< HEAD
<div className="bg-primary-dark pt-3 pb-3 ">
<div className="container m-auto relative flex flex-col">
<div className="flex flex-row w-full">
{filtersMeta.map((filterMeta) => {
return (
<div
key={filterMeta.name}
className={classnames(
'pl-4 first:pl-12',
`w-${filterMeta.gridCol}/24`
)}
>
{renderFieldInputComponent(filterMeta)}
</div>
);
})}
</div>
</div>
=======
<div className="bg-custom-navyDark pt-3 pb-3 ">
<InputGroup
inputMeta={filtersMeta}
@ -223,7 +83,6 @@ const StudyListFilter = ({
onSortingChange={setFilterSorting}
isSortingEnable={isSortingEnable}
/>
>>>>>>> 26d8c8ae5... refactor: StudyListFilter refactor (#1580)
</div>
{numOfStudies > 100 && (
<div className="container m-auto">

View File

@ -1,12 +1,14 @@
import React from 'react';
import { StudyList } from '@ohif/ui';
// TEMPORARY MOCKING DATA FOR VISUALIZATION PURPOSES
import { utils } from '@ohif/ui';
const ConnectedStudyList = () => {
const studies = utils.getMockedStudies();
return <StudyList studies={studies} />;
return (
/** Temporary using StudyList -- We should mount it by using the created
* components such as NavBar, InputGroup, StudyListTable, etc...
* Check "Views > StudyList" in @ohif/ui for reference
*/
<StudyList />
);
};
export default ConnectedStudyList;