chore: Data Mocking for Study List (#1515)

* feat: Data mocking for studies

* feat: Data Mocking for Study List

* fix empty study position

* rename variables for numOfStudies

* fix studies query

* remove alert :|

* minor refactor

* split utils and refactoring

* refactoring -- format, clean up icons, mdx mock
This commit is contained in:
Rodrigo Antinarelli 2020-03-12 23:27:48 -03:00 committed by James A. Petts
parent 2138565990
commit 2bf5486112
19 changed files with 249 additions and 333 deletions

View File

@ -1,3 +1,5 @@
import * as utils from './src/utils/';
export {
Button,
ButtonGroup,
@ -9,4 +11,6 @@ export {
Typography,
} from './src/components';
export { utils };
export { StudyList } from './src/views';

View File

@ -26,6 +26,7 @@
},
"dependencies": {
"classnames": "^2.2.6",
"date-fns": "^2.10.0",
"docz": "^2.2.0",
"theme-ui": "^0.2.38",
"gatsby": "2.19.24",

View File

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="20" viewBox="0 0 21 20">
<g fill="#348CFD">
<path d="M14.75.917c.693 0 1.263.528 1.327 1.205l.006.128v4.167c0 .276-.224.5-.5.5-.245 0-.45-.177-.492-.41l-.008-.09V2.25c0-.161-.114-.295-.266-.327l-.067-.006H2.25c-.161 0-.295.114-.327.266l-.006.067v12.5c0 .161.114.295.266.327l.067.006h4.167c.276 0 .5.224.5.5 0 .246-.177.45-.41.492l-.09.008H2.25c-.693 0-1.263-.528-1.327-1.205l-.006-.128V2.25c0-.693.528-1.263 1.205-1.327L2.25.917h12.5z" transform="translate(-.5 -1)"/>
<path d="M19.583 5.917H7.417c-.829 0-1.5.671-1.5 1.5v12.166c0 .829.671 1.5 1.5 1.5h12.166c.829 0 1.5-.671 1.5-1.5V7.417c0-.829-.671-1.5-1.5-1.5zm-12.166 1h12.166c.276 0 .5.224.5.5v12.166c0 .276-.224.5-.5.5H7.417c-.276 0-.5-.224-.5-.5V7.417c0-.276.224-.5.5-.5z" transform="translate(-.5 -1)"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 856 B

View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="111" height="111" viewBox="0 0 111 111">
<g fill="none" fill-rule="evenodd" stroke="#3A3F99" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" transform="translate(2 2)">
<circle cx="53.419" cy="53.419" r="53.419" fill="#06081D"/>
<circle cx="49.411" cy="49.411" r="23.862"/>
<path d="M66.282 66.282L81.29 81.29"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 420 B

View File

Before

Width:  |  Height:  |  Size: 861 B

After

Width:  |  Height:  |  Size: 861 B

View File

Before

Width:  |  Height:  |  Size: 849 B

After

Width:  |  Height:  |  Size: 849 B

View File

@ -1,6 +1,7 @@
import React from 'react';
// Icons
import active from './../../assets/icons/active.svg';
import seriesActive from './../../assets/icons/series-active.svg';
import seriesInactive from './../../assets/icons/series-inactive.svg';
import cancel from './../../assets/icons/cancel.svg';
import chevronDown from './../../assets/icons/chevron-down.svg';
import chevronRight from './../../assets/icons/chevron-right.svg';
@ -8,6 +9,7 @@ import infoLink from './../../assets/icons/info-link.svg';
import launchArrow from './../../assets/icons/launch-arrow.svg';
import launchInfo from './../../assets/icons/launch-info.svg';
import logoOhifSmall from './../../assets/icons/logo-ohif-small.svg';
import magnifier from './../../assets/icons/magnifier.svg';
import notificationwarningDiamond from './../../assets/icons/notificationwarning-diamond.svg';
import settings from './../../assets/icons/settings.svg';
import sorting from './../../assets/icons/sorting.svg';
@ -15,7 +17,8 @@ import sortingActiveDown from './../../assets/icons/sorting-active-down.svg';
import sortingActiveUp from './../../assets/icons/sorting-active-up.svg';
const ICONS = {
active: active,
'series-active': seriesActive,
'series-inactive': seriesInactive,
cancel: cancel,
'chevron-down': chevronDown,
'chevron-right': chevronRight,
@ -23,6 +26,7 @@ const ICONS = {
'launch-arrow': launchArrow,
'launch-info': launchInfo,
'logo-ohif-small': logoOhifSmall,
magnifier: magnifier,
'notificationwarning-diamond': notificationwarningDiamond,
settings: settings,
'sorting-active-down': sortingActiveDown,

View File

@ -14,7 +14,7 @@ import { ICONS } from './getIcon';
<Playground>
<div className="p-4">
<Icon name="active" className="text-custom-aquaBright m-4" />
<Icon name="series-active" className="text-custom-aquaBright m-4" />
</div>
</Playground>

View File

@ -3,10 +3,13 @@
{
"StudyInstanceUID": "1.2.840.113619.2.5.1762583153.215519.978957063.78",
"StudyDescription": "BRAIN SELLA",
"AccessionNumber": "11788761116031",
"StudyDate": "20010108",
"StudyTime": "120022",
"PatientName": "MISTER^MR",
"PatientId": "832040",
"Instances": 33,
"Modalities": "MR",
"series": [
{
"SeriesDescription": "SAG T-1",

View File

@ -1,270 +0,0 @@
/* eslint-disable no-use-before-define */
/**
* Returns a number whose value is limited to the given range.
*
* @param {number} value The value to be clamped
* @param {number} min The lower boundary of the output range
* @param {number} max The upper boundary of the output range
* @returns {number} A number in the range [min, max]
*/
function clamp(value, min = 0, max = 1) {
if (process.env.NODE_ENV !== 'production') {
if (value < min || value > max) {
console.error(
`@ohif/ui: the value provided ${value} is out of range [${min}, ${max}].`
);
}
}
return Math.min(Math.max(min, value), max);
}
/**
* Converts a color from CSS hex format to CSS rgb format.
*
* @param {string} color - Hex color, i.e. #nnn or #nnnnnn
* @returns {string} A CSS rgb color string
*/
export function hexToRgb(color) {
color = color.substr(1);
const re = new RegExp(`.{1,${color.length / 3}}`, 'g');
let colors = color.match(re);
if (colors && colors[0].length === 1) {
colors = colors.map(n => n + n);
}
return colors ? `rgb(${colors.map(n => parseInt(n, 16)).join(', ')})` : '';
}
function intToHex(int) {
const hex = int.toString(16);
return hex.length === 1 ? `0${hex}` : hex;
}
/**
* Converts a color from CSS rgb format to CSS hex format.
*
* @param {string} color - RGB color, i.e. rgb(n, n, n)
* @returns {string} A CSS rgb color string, i.e. #nnnnnn
*/
export function rgbToHex(color) {
// Idempotent
if (color.indexOf('#') === 0) {
return color;
}
const { values } = decomposeColor(color);
return `#${values.map(n => intToHex(n)).join('')}`;
}
/**
* Converts a color from hsl format to rgb format.
*
* @param {string} color - HSL color values
* @returns {string} rgb color values
*/
export function hslToRgb(color) {
color = decomposeColor(color);
const { values } = color;
const h = values[0];
const s = values[1] / 100;
const l = values[2] / 100;
const a = s * Math.min(l, 1 - l);
const f = (n, k = (n + h / 30) % 12) =>
l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
let type = 'rgb';
const rgb = [
Math.round(f(0) * 255),
Math.round(f(8) * 255),
Math.round(f(4) * 255),
];
if (color.type === 'hsla') {
type += 'a';
rgb.push(values[3]);
}
return recomposeColor({ type, values: rgb });
}
/**
* Returns an object with the type and values of a color.
*
* Note: Does not support rgb % values.
*
* @param {string} color - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()
* @returns {object} - A MUI color object: {type: string, values: number[]}
*/
export function decomposeColor(color) {
// Idempotent
if (color.type) {
return color;
}
if (color.charAt(0) === '#') {
return decomposeColor(hexToRgb(color));
}
const marker = color.indexOf('(');
const type = color.substring(0, marker);
if (['rgb', 'rgba', 'hsl', 'hsla'].indexOf(type) === -1) {
throw new Error(
[
`@ohif/ui: unsupported \`${color}\` color.`,
'We support the following formats: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla().',
].join('\n')
);
}
let values = color.substring(marker + 1, color.length - 1).split(',');
values = values.map(value => parseFloat(value));
return { type, values };
}
/**
* Converts a color object with type and values to a string.
*
* @param {object} color - Decomposed color
* @param {string} color.type - One of: 'rgb', 'rgba', 'hsl', 'hsla'
* @param {array} color.values - [n,n,n] or [n,n,n,n]
* @returns {string} A CSS color string
*/
export function recomposeColor(color) {
const { type } = color;
let { values } = color;
if (type.indexOf('rgb') !== -1) {
// Only convert the first 3 values to int (i.e. not alpha)
values = values.map((n, i) => (i < 3 ? parseInt(n, 10) : n));
} else if (type.indexOf('hsl') !== -1) {
values[1] = `${values[1]}%`;
values[2] = `${values[2]}%`;
}
return `${type}(${values.join(', ')})`;
}
/**
* Calculates the contrast ratio between two colors.
*
* Formula: https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests
*
* @param {string} foreground - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()
* @param {string} background - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()
* @returns {number} A contrast ratio value in the range 0 - 21.
*/
export function getContrastRatio(foreground, background) {
const lumA = getLuminance(foreground);
const lumB = getLuminance(background);
return (Math.max(lumA, lumB) + 0.05) / (Math.min(lumA, lumB) + 0.05);
}
/**
* The relative brightness of any point in a color space,
* normalized to 0 for darkest black and 1 for lightest white.
*
* Formula: https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests
*
* @param {string} color - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()
* @returns {number} The relative brightness of the color in the range 0 - 1
*/
export function getLuminance(color) {
color = decomposeColor(color);
let rgb =
color.type === 'hsl'
? decomposeColor(hslToRgb(color)).values
: color.values;
rgb = rgb.map(val => {
val /= 255; // normalized
return val <= 0.03928 ? val / 12.92 : ((val + 0.055) / 1.055) ** 2.4;
});
// Truncate at 3 digits
return Number(
(0.2126 * rgb[0] + 0.7152 * rgb[1] + 0.0722 * rgb[2]).toFixed(3)
);
}
/**
* Darken or lighten a color, depending on its luminance.
* Light colors are darkened, dark colors are lightened.
*
* @param {string} color - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()
* @param {number} coefficient=0.15 - multiplier in the range 0 - 1
* @returns {string} A CSS color string. Hex input values are returned as rgb
*/
export function emphasize(color, coefficient = 0.15) {
return getLuminance(color) > 0.5
? darken(color, coefficient)
: lighten(color, coefficient);
}
/**
* Set the absolute transparency of a color.
* Any existing alpha values are overwritten.
*
* @param {string} color - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()
* @param {number} value - value to set the alpha channel to in the range 0 -1
* @returns {string} A CSS color string. Hex input values are returned as rgb
*/
export function fade(color, value) {
color = decomposeColor(color);
value = clamp(value);
if (color.type === 'rgb' || color.type === 'hsl') {
color.type += 'a';
}
color.values[3] = value;
return recomposeColor(color);
}
/**
* Darkens a color.
*
* @param {string} color - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()
* @param {number} coefficient - multiplier in the range 0 - 1
* @returns {string} A CSS color string. Hex input values are returned as rgb
*/
export function darken(color, coefficient) {
color = decomposeColor(color);
coefficient = clamp(coefficient);
if (color.type.indexOf('hsl') !== -1) {
color.values[2] *= 1 - coefficient;
} else if (color.type.indexOf('rgb') !== -1) {
for (let i = 0; i < 3; i += 1) {
color.values[i] *= 1 - coefficient;
}
}
return recomposeColor(color);
}
/**
* Lightens a color.
*
* @param {string} color - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()
* @param {number} coefficient - multiplier in the range 0 - 1
* @returns {string} A CSS color string. Hex input values are returned as rgb
*/
export function lighten(color, coefficient) {
color = decomposeColor(color);
coefficient = clamp(coefficient);
if (color.type.indexOf('hsl') !== -1) {
color.values[2] += (100 - color.values[2]) * coefficient;
} else if (color.type.indexOf('rgb') !== -1) {
for (let i = 0; i < 3; i += 1) {
color.values[i] += (255 - color.values[i]) * coefficient;
}
}
return recomposeColor(color);
}

View File

@ -0,0 +1,15 @@
/**
* 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

@ -0,0 +1,17 @@
import studyListMock from '../mocks/studyList.json';
/** Values can be env vars */
const DEFAULT_MOCKED_STUDIES_LIMIT = 1000;
/**
* Method to get a mocked study list
* @param {number} items Number of studies to be loaded
* @returns {array} Study list
*/
const getMockedStudies = (items = 50) => {
const num =
items > DEFAULT_MOCKED_STUDIES_LIMIT ? DEFAULT_MOCKED_STUDIES_LIMIT : items;
return new Array(num).fill(studyListMock.studies[0]);
};
export default getMockedStudies;

View File

@ -0,0 +1,20 @@
/**
* 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

@ -0,0 +1,6 @@
import capitalize from './capitalize';
import getMockedStudies from './getMockedStudies';
import getModalities from './getModalities';
import getInstances from './getInstances';
export { capitalize, getMockedStudies, getModalities, getInstances };

View File

@ -1,18 +1,38 @@
import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import Header from './components/Header';
import StudyListFilter from './components/StudyListFilter';
import StudyListTable from './components/StudyListTable';
import StudyListPagination from './components/StudyListPagination';
const StudyList = () => {
const StudyList = ({ studies, perPage }) => {
const studiesData = studies.slice(0, perPage);
const numOfStudies = studies.length;
const isEmptyStudies = numOfStudies === 0;
return (
<div>
<div
className={classnames('bg-black h-full', {
'h-screen': isEmptyStudies,
})}
>
<Header />
<StudyListFilter />
<StudyListTable />
<StudyListPagination />
<StudyListFilter numOfStudies={numOfStudies} />
<StudyListTable studies={studiesData} numOfStudies={numOfStudies} />
{!isEmptyStudies && <StudyListPagination />}
</div>
);
};
StudyList.defaultProps = {
studies: [],
perPage: 25,
};
StudyList.propTypes = {
studies: PropTypes.array,
perPage: PropTypes.number,
};
export default StudyList;

View File

@ -4,8 +4,11 @@ menu: Views
route: views/studyList
---
import { useState } from 'react'
import { Playground, Props } from 'docz';
import StudyList from './';
import Button from '../../components/Button';
import { getMockedStudies } from '../../utils/'
# StudyList
@ -20,9 +23,24 @@ import { StudyList } from '@ohfi/ui';
## StudyList
<Playground>
<>
<StudyList />
</>
{() => {
const [studies, setStudies] = useState([])
const handleStudyList = (number) => {
const studies = getMockedStudies(number)
setStudies(studies)
}
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>
</div>
<StudyList studies={studies} />
</div>
);
}}
</Playground>
## Properties

View File

@ -1,19 +1,24 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { Button } from '@ohif/ui';
import { format } from 'date-fns';
import { Button, Icon, Typography } from '@ohif/ui';
/** TODO: Icon component should be used instead of importing the icons directly */
import ChevronRight from '../../../assets/icons/chevron-right.svg';
import ChevronDown from '../../../assets/icons/chevron-down.svg';
import InstancesActive from '../../../assets/icons/instances-active.svg';
import InstancesInactive from '../../../assets/icons/instances-inactive.svg';
import LaunchInfo from '../../../assets/icons/launch-info.svg';
const TableRow = props => {
const {
AccessionNumber,
Modalities,
Instances,
StudyDescription,
PatientId,
PatientName,
StudyDate,
series,
} = props;
const TableRow = () => {
const [isOpened, setIsOpened] = useState(false);
const toggleRow = () => setIsOpened(!isOpened);
const ChevronIcon = isOpened ? ChevronDown : ChevronRight;
const InstancesIcon = isOpened ? InstancesActive : InstancesInactive;
const ChevronIconName = isOpened ? 'chevron-down' : 'chevron-right';
const tdClasses = [
'px-4 py-2',
{ 'border-b border-custom-violetPale': !isOpened },
@ -23,7 +28,6 @@ const TableRow = () => {
small: 'px-2 flex-0.3',
};
const seriesBodyClasses = 'border-r border-custom-violetPale';
return (
<>
<tr>
@ -50,31 +54,39 @@ const TableRow = () => {
onClick={toggleRow}
>
<td className={classnames(...tdClasses)}>
<ChevronIcon />
<Icon name={ChevronIconName} />
</td>
<td className={classnames(...tdClasses)}>Patient name</td>
<td className={classnames(...tdClasses)}>11000002</td>
<td className={classnames(...tdClasses)}>{PatientName}</td>
<td className={classnames(...tdClasses)}>{PatientId}</td>
<td className={classnames(...tdClasses)}>
Mar-29-2013 11:26 AM
{format(StudyDate, 'MMM-DD-YYYY')}
</td>
<td className={classnames(...tdClasses)}>
PET^1_PETCT_WB_AC (Adult)
{StudyDescription}
</td>
<td className={classnames(...tdClasses)}>CT/OT/PT</td>
<td className={classnames(...tdClasses)}>00000001</td>
<td className={classnames(...tdClasses)}>{Modalities}</td>
<td className={classnames(...tdClasses)}>
<InstancesIcon className="inline-flex mr-2" />
902
{AccessionNumber}
</td>
<td className={classnames(...tdClasses)}>
<Icon
name="series-active"
className={classnames('inline-flex mr-2', {
'text-custom-blueBright': isOpened,
'text-custom-violetPale': !isOpened,
})}
/>
{Instances}
</td>
</tr>
{isOpened && (
<tr className={classnames('bg-black')}>
<td colSpan="8" className="py-4 pl-20 pr-2">
<div>
<div className="flex">
<Button
rounded="full"
variant="outlined"
endIcon={<LaunchInfo />}
endIcon={<Icon name="launch-info" />}
className="mr-4"
>
Basic Viewer
@ -82,7 +94,7 @@ const TableRow = () => {
<Button
rounded="full"
variant="outlined"
endIcon={<LaunchInfo />}
endIcon={<Icon name="launch-info" />}
className="mr-4"
>
Segmentation
@ -90,14 +102,17 @@ const TableRow = () => {
<Button
rounded="full"
variant="outlined"
endIcon={<LaunchInfo />}
endIcon={<Icon name="launch-info" />}
>
Module 3
</Button>
<span className="ml-4 text-lg text-custom-grayBright">
{/* ADD ICON HERE */}
<div className="ml-5 text-lg text-custom-grayBright flex items-center">
<Icon
name="notificationwarning-diamond"
className="mr-2 w-5 h-5"
/>
Feedback text lorem ipsum dolor sit amet
</span>
</div>
</div>
<div className="mt-4">
<div className="w-full text-lg">
@ -124,7 +139,7 @@ const TableRow = () => {
</div>
</div>
<div className="mt-2 h-48 overflow-y-scroll ohif-scrollbar">
{new Array(30).fill('').map((el, i) => (
{series.map((seriesItem, i) => (
<div className="w-full flex" key={i}>
<div
className={classnames(
@ -140,7 +155,7 @@ const TableRow = () => {
seriesBodyClasses
)}
>
#
{seriesItem.SeriesNumber}
</div>
<div
className={classnames(
@ -148,10 +163,10 @@ const TableRow = () => {
seriesBodyClasses
)}
>
CT
{seriesItem.Modality}
</div>
<div className={classnames('pl-3 flex-1')}>
149
{seriesItem.instances.length}
</div>
</div>
))}
@ -170,27 +185,85 @@ const TableRow = () => {
);
};
const StudyListTable = () => {
TableRow.propTypes = {
AccessionNumber: PropTypes.string.isRequired,
Modalities: PropTypes.string.isRequired,
Instances: PropTypes.number.isRequired,
PatientId: PropTypes.string.isRequired,
PatientName: PropTypes.string.isRequired,
StudyDescription: PropTypes.string.isRequired,
StudyDate: PropTypes.string.isRequired,
series: PropTypes.array.isRequired,
};
const StudyListTable = ({ studies, numOfStudies }) => {
const renderTable = () => {
return (
<table className="w-full text-white">
<tbody>
{studies.map((study, i) => (
<TableRow
key={i}
AccessionNumber={study.AccessionNumber || ''}
Modalities={study.Modalities || ''}
Instances={study.Instances || ''}
StudyDescription={study.StudyDescription || ''}
PatientId={study.PatientId || ''}
PatientName={study.PatientName || ''}
StudyDate={study.StudyDate || ''}
series={study.series || []}
/>
))}
</tbody>
</table>
);
};
const renderEmpty = () => {
return (
<div className="flex flex-col items-center justify-center pt-48">
<Icon name="magnifier" className="mb-4" />
<Typography className="text-custom-aquaBright" variant="h5">
No studies available
</Typography>
</div>
);
};
return (
<>
<div className="bg-black">
<div className="container m-auto relative">
<div className="bg-custom-blue text-center text-base py-1 rounded-b sticky top-0">
<p className="text-white">
Filter list to 100 studies or less to enable sorting
</p>
</div>
<table className="w-full text-white">
<tbody>
{new Array(30).fill('').map((empty, i) => (
<TableRow key={i} />
))}
</tbody>
</table>
{numOfStudies > 100 && (
<div className="bg-custom-blue text-center text-base py-1 rounded-b sticky top-0">
<p className="text-white">
Filter list to 100 studies or less to enable sorting
</p>
</div>
)}
{numOfStudies > 0 && renderTable()}
{numOfStudies === 0 && renderEmpty()}
</div>
</div>
</>
);
};
StudyListTable.propTypes = {
studies: PropTypes.arrayOf(
PropTypes.shape({
AccessionNumber: PropTypes.string.isRequired,
Modalities: PropTypes.string.isRequired,
Instances: PropTypes.number.isRequired,
PatientId: PropTypes.string.isRequired,
PatientName: PropTypes.string.isRequired,
StudyDescription: PropTypes.string.isRequired,
StudyDate: PropTypes.string.isRequired,
series: PropTypes.array.isRequired,
})
).isRequired,
numOfStudies: PropTypes.number.isRequired,
};
export default StudyListTable;

View File

@ -1,8 +1,12 @@
import React from 'react';
import { StudyList } from '@ohif/ui';
// TEMPORARY MOCKING DATA FOR VISUALIZATION PURPOSES
import { utils } from '@ohif/ui';
const ConnectedStudyList = () => {
return <StudyList />;
const studies = utils.getMockedStudies();
return <StudyList studies={studies} />;
};
export default ConnectedStudyList;

View File

@ -6280,7 +6280,7 @@ date-fns@^1.27.2:
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==
date-fns@^2.2.1:
date-fns@^2.10.0, date-fns@^2.2.1:
version "2.10.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.10.0.tgz#abd10604d8bafb0bcbd2ba2e9b0563b922ae4b6b"
integrity sha512-EhfEKevYGWhWlZbNeplfhIU/+N+x0iCIx7VzKlXma2EdQyznVlZhCptXUY+BegNpPW2kjdx15Rvq503YcXXrcA==