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:
parent
056f56f5b4
commit
f4b078912a
@ -27,6 +27,9 @@ export {
|
|||||||
Label,
|
Label,
|
||||||
NavBar,
|
NavBar,
|
||||||
Select,
|
Select,
|
||||||
|
StudyListExpandedRow,
|
||||||
|
StudyListPagination,
|
||||||
|
StudyListTable,
|
||||||
Svg,
|
Svg,
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
|
|||||||
@ -26,7 +26,6 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"date-fns": "^2.10.0",
|
|
||||||
"docz": "^2.2.0",
|
"docz": "^2.2.0",
|
||||||
"gatsby": "2.19.24",
|
"gatsby": "2.19.24",
|
||||||
"gatsby-plugin-postcss": "^2.1.20",
|
"gatsby-plugin-postcss": "^2.1.20",
|
||||||
|
|||||||
@ -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;
|
||||||
2
platform/ui/src/components/StudyListExpandedRow/index.js
Normal file
2
platform/ui/src/components/StudyListExpandedRow/index.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import StudyListExpandedRow from './StudyListExpandedRow';
|
||||||
|
export default StudyListExpandedRow;
|
||||||
@ -1,18 +1,22 @@
|
|||||||
import React, { useState } from 'react';
|
import React from 'react';
|
||||||
import {
|
import PropTypes from 'prop-types';
|
||||||
Typography,
|
import { Button, ButtonGroup, Icon, IconButton, Typography } from '@ohif/ui';
|
||||||
ButtonGroup,
|
|
||||||
Button,
|
|
||||||
IconButton,
|
|
||||||
Icon,
|
|
||||||
} from '../../../components/';
|
|
||||||
|
|
||||||
|
<<<<<<< HEAD:platform/ui/src/views/StudyList/components/StudyListPagination.js
|
||||||
const StudyListPagination = (props) => {
|
const StudyListPagination = (props) => {
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
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 navigateToPage = (page) => {
|
||||||
const toPage = page < 1 ? 1 : page;
|
const toPage = page < 1 ? 1 : page;
|
||||||
setCurrentPage(toPage);
|
onChangePage(toPage);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -22,9 +26,15 @@ const StudyListPagination = (props) => {
|
|||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="relative mr-3">
|
<div className="relative mr-3">
|
||||||
<select
|
<select
|
||||||
|
<<<<<<< HEAD:platform/ui/src/views/StudyList/components/StudyListPagination.js
|
||||||
defaultValue="25"
|
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"
|
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 }}
|
style={{ height: 28 }}
|
||||||
|
onChange={(e) => onChangePerPage(e.target.value)}
|
||||||
>
|
>
|
||||||
<option value="25">25</option>
|
<option value="25">25</option>
|
||||||
<option value="50">50</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;
|
export default StudyListPagination;
|
||||||
@ -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} />
|
||||||
3
platform/ui/src/components/StudyListPagination/index.js
Normal file
3
platform/ui/src/components/StudyListPagination/index.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import StudyListPagination from './StudyListPagination';
|
||||||
|
|
||||||
|
export default StudyListPagination;
|
||||||
35
platform/ui/src/components/StudyListTable/StudyListTable.js
Normal file
35
platform/ui/src/components/StudyListTable/StudyListTable.js
Normal 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;
|
||||||
62
platform/ui/src/components/StudyListTable/StudyListTable.mdx
Normal file
62
platform/ui/src/components/StudyListTable/StudyListTable.mdx
Normal 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} />
|
||||||
@ -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;
|
||||||
3
platform/ui/src/components/StudyListTable/index.js
Normal file
3
platform/ui/src/components/StudyListTable/index.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import StudyListTable from './StudyListTable';
|
||||||
|
|
||||||
|
export default StudyListTable;
|
||||||
@ -14,6 +14,9 @@ import Label from './Label';
|
|||||||
import NavBar from './NavBar';
|
import NavBar from './NavBar';
|
||||||
import Select from './Select';
|
import Select from './Select';
|
||||||
import Svg from './Svg';
|
import Svg from './Svg';
|
||||||
|
import StudyListExpandedRow from './StudyListExpandedRow';
|
||||||
|
import StudyListPagination from './StudyListPagination';
|
||||||
|
import StudyListTable from './StudyListTable';
|
||||||
import Table from './Table';
|
import Table from './Table';
|
||||||
import TableBody from './TableBody';
|
import TableBody from './TableBody';
|
||||||
import TableCell from './TableCell';
|
import TableCell from './TableCell';
|
||||||
@ -39,6 +42,9 @@ export {
|
|||||||
NavBar,
|
NavBar,
|
||||||
Select,
|
Select,
|
||||||
Svg,
|
Svg,
|
||||||
|
StudyListExpandedRow,
|
||||||
|
StudyListPagination,
|
||||||
|
StudyListTable,
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
TableCell,
|
TableCell,
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"StudyInstanceUID": "1.2.840.113619.2.5.1762583153.215519.978957063.78",
|
"StudyInstanceUID": "1.2.840.113619.2.5.1762583153.215519.978957063.78",
|
||||||
"StudyDescription": "BRAIN SELLA",
|
"StudyDescription": "BRAIN SELLA",
|
||||||
"AccessionNumber": "11788761116031",
|
"AccessionNumber": "11788761116031",
|
||||||
"StudyDate": "20010108",
|
"StudyDate": "2020-03-26T23:33:59.073Z",
|
||||||
"StudyTime": "120022",
|
"StudyTime": "120022",
|
||||||
"PatientName": "MISTER^MR",
|
"PatientName": "MISTER^MR",
|
||||||
"PatientId": "832040",
|
"PatientId": "832040",
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
export default string => {
|
|
||||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
||||||
};
|
|
||||||
@ -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;
|
|
||||||
@ -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;
|
|
||||||
@ -1,10 +1,7 @@
|
|||||||
import capitalize from './capitalize';
|
|
||||||
import getMockedStudies from './getMockedStudies';
|
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;
|
export default utils;
|
||||||
|
|||||||
@ -1,11 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* THIS IS A TEMPORARY FILE -- SHOULD BE REMOVED
|
||||||
|
*/
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import classnames from 'classnames';
|
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 Header from './components/Header';
|
||||||
import StudyListFilter from './components/StudyListFilter';
|
import StudyListFilter from './components/StudyListFilter';
|
||||||
import StudyListTable from './components/StudyListTable';
|
|
||||||
import StudyListPagination from './components/StudyListPagination';
|
|
||||||
|
|
||||||
const filtersMeta = [
|
const filtersMeta = [
|
||||||
{
|
{
|
||||||
@ -84,21 +96,175 @@ const defaultFilterValues = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const isFiltering = (filterValues, defaultFilterValues) => {
|
const isFiltering = (filterValues, defaultFilterValues) => {
|
||||||
return Object.keys(defaultFilterValues).some(name => {
|
return Object.keys(defaultFilterValues).some((name) => {
|
||||||
return filterValues[name] !== defaultFilterValues[name];
|
return filterValues[name] !== defaultFilterValues[name];
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const StudyList = ({ studies, perPage }) => {
|
const StudyList = () => {
|
||||||
const [filterValues, setFilterValues] = useState(defaultFilterValues);
|
const [filterValues, setFilterValues] = useState(defaultFilterValues);
|
||||||
const studiesData = studies.slice(0, perPage);
|
const studies = utils.getMockedStudies();
|
||||||
const numOfStudies = studies.length;
|
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 (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classnames('bg-black h-full', {
|
className={classnames('bg-black h-full', {
|
||||||
'h-screen': isEmptyStudies,
|
'h-screen': !hasStudies,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Header />
|
<Header />
|
||||||
@ -110,24 +276,28 @@ const StudyList = ({ studies, perPage }) => {
|
|||||||
clearFilters={() => setFilterValues(defaultFilterValues)}
|
clearFilters={() => setFilterValues(defaultFilterValues)}
|
||||||
isFiltering={isFiltering(filterValues, defaultFilterValues)}
|
isFiltering={isFiltering(filterValues, defaultFilterValues)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{hasStudies ? (
|
||||||
|
<>
|
||||||
<StudyListTable
|
<StudyListTable
|
||||||
studies={studiesData}
|
tableDataSource={tableDataSource}
|
||||||
numOfStudies={numOfStudies}
|
numOfStudies={numOfStudies}
|
||||||
filtersMeta={filtersMeta}
|
filtersMeta={filtersMeta}
|
||||||
/>
|
/>
|
||||||
{!isEmptyStudies && <StudyListPagination />}
|
<StudyListPagination
|
||||||
|
onChangePage={onChangePage}
|
||||||
|
onChangePerPage={onChangePerPage}
|
||||||
|
currentPage={currentPage}
|
||||||
|
perPage={perPage}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="flex flex-col items-center justify-center pt-48">
|
||||||
|
<EmptyStudies />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
StudyList.defaultProps = {
|
|
||||||
studies: [],
|
|
||||||
perPage: 25,
|
|
||||||
};
|
|
||||||
|
|
||||||
StudyList.propTypes = {
|
|
||||||
studies: PropTypes.array,
|
|
||||||
perPage: PropTypes.number,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default StudyList;
|
export default StudyList;
|
||||||
|
|||||||
@ -4,10 +4,28 @@ menu: Views
|
|||||||
route: views/studyList
|
route: views/studyList
|
||||||
---
|
---
|
||||||
|
|
||||||
import { useState } from 'react'
|
import { useState } from 'react';
|
||||||
import { Playground, Props } from 'docz';
|
import { Playground, Props } from 'docz';
|
||||||
import { StudyList, Button } from '@ohif/ui';
|
import {
|
||||||
import { getMockedStudies } from '../../utils/'
|
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
|
# StudyList
|
||||||
|
|
||||||
@ -23,25 +41,325 @@ import { StudyList } from '@ohif/ui';
|
|||||||
|
|
||||||
<Playground>
|
<Playground>
|
||||||
{() => {
|
{() => {
|
||||||
const [studies, setStudies] = useState([])
|
const defaultFilterValues = {
|
||||||
const handleStudyList = (number) => {
|
patientName: '',
|
||||||
const studies = getMockedStudies(number)
|
mrn: '',
|
||||||
setStudies(studies)
|
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);
|
||||||
|
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 (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="bg-white p-4">
|
<div className="bg-white p-4">
|
||||||
<Button className="mr-2" onClick={() => handleStudyList(0)}>0 Studies</Button>
|
<Button className="mr-2" onClick={() => handleStudyList(0)}>
|
||||||
<Button className="mr-2" onClick={() => handleStudyList(50)}>50 Studies</Button>
|
0 Studies
|
||||||
<Button className="mr-2" onClick={() => handleStudyList(100)}>100 Studies</Button>
|
</Button>
|
||||||
<Button className="mr-2" onClick={() => handleStudyList(1000)}>1000 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>
|
</div>
|
||||||
<StudyList studies={studies} />
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</Playground>
|
</Playground>
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
<Props of={StudyList} />
|
|
||||||
|
|||||||
@ -3,125 +3,6 @@ import PropTypes from 'prop-types';
|
|||||||
|
|
||||||
import { Button, Icon, Typography, InputGroup } from '@ohif/ui';
|
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 = ({
|
const StudyListFilter = ({
|
||||||
filtersMeta,
|
filtersMeta,
|
||||||
filterValues,
|
filterValues,
|
||||||
@ -137,7 +18,6 @@ const StudyListFilter = ({
|
|||||||
...filterValues,
|
...filterValues,
|
||||||
...sortingValues,
|
...sortingValues,
|
||||||
});
|
});
|
||||||
>>>>>>> 26d8c8ae5... refactor: StudyListFilter refactor (#1580)
|
|
||||||
};
|
};
|
||||||
const isSortingEnable = numOfStudies > 0 && numOfStudies <= 100;
|
const isSortingEnable = numOfStudies > 0 && numOfStudies <= 100;
|
||||||
|
|
||||||
@ -194,26 +74,6 @@ const StudyListFilter = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="sticky z-10 border-b-4 border-black" style={{ top: 58 }}>
|
<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 ">
|
<div className="bg-custom-navyDark pt-3 pb-3 ">
|
||||||
<InputGroup
|
<InputGroup
|
||||||
inputMeta={filtersMeta}
|
inputMeta={filtersMeta}
|
||||||
@ -223,7 +83,6 @@ const StudyListFilter = ({
|
|||||||
onSortingChange={setFilterSorting}
|
onSortingChange={setFilterSorting}
|
||||||
isSortingEnable={isSortingEnable}
|
isSortingEnable={isSortingEnable}
|
||||||
/>
|
/>
|
||||||
>>>>>>> 26d8c8ae5... refactor: StudyListFilter refactor (#1580)
|
|
||||||
</div>
|
</div>
|
||||||
{numOfStudies > 100 && (
|
{numOfStudies > 100 && (
|
||||||
<div className="container m-auto">
|
<div className="container m-auto">
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { StudyList } from '@ohif/ui';
|
import { StudyList } from '@ohif/ui';
|
||||||
|
|
||||||
// TEMPORARY MOCKING DATA FOR VISUALIZATION PURPOSES
|
|
||||||
import { utils } from '@ohif/ui';
|
|
||||||
|
|
||||||
const ConnectedStudyList = () => {
|
const ConnectedStudyList = () => {
|
||||||
const studies = utils.getMockedStudies();
|
return (
|
||||||
return <StudyList studies={studies} />;
|
/** 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;
|
export default ConnectedStudyList;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user