Skip to content

Commit db95c7d

Browse files
Merge pull request #147 from ImagingDataCommons/feat/update-to-slim-lts-dmv-0.48.14-2
Update to slim lts dmv 0.48.14 2
2 parents 6968b8b + b88a216 commit db95c7d

File tree

7 files changed

+323
-75
lines changed

7 files changed

+323
-75
lines changed

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
[![DOI](https://zenodo.org/badge/335130719.svg)](https://zenodo.org/badge/latestdoi/335130719)
22
[![Build Status](https://github.com/imagingdatacommons/slim/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/imagingdatacommons/slim/actions)
33

4-
# Slim: Interoperable slide microscopy viewer and annotation tool for imaging data science and computational pathology
4+
# Slim IDC fork
5+
6+
## Upgrade process
7+
8+
- Merge into master
9+
- It will get deployed into IDC dev tier automatically
10+
- Test in dev tier
11+
- If all good, update main
12+
13+
## Slim: Interoperable slide microscopy viewer and annotation tool for imaging data science and computational pathology
514

615
_Slim_ is a single-page application for interactive visualization and annotation of digital whole slide microscopy images and derived image analysis results in standard DICOM format.
716
The application is based on the [dicom-microscopy-viewer](https://github.com/MGHComputationalPathology/dicom-microscopy-viewer) JavaScript library and runs fully client side without any custom server components.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"@testing-library/react": "^11.2.2",
4545
"@testing-library/user-event": "^7.1.2",
4646
"@types/jest": "^28.1.3",
47+
"@types/lodash": "^4.17.20",
4748
"@types/node": "^14.14.9",
4849
"@types/react": "^18.0.14",
4950
"@types/react-dom": "^18.0.5",
@@ -56,7 +57,7 @@
5657
"craco-less": "^2.0.0",
5758
"dcmjs": "^0.35.0",
5859
"detect-browser": "^5.2.1",
59-
"dicom-microscopy-viewer": "^0.48.13",
60+
"dicom-microscopy-viewer": "^0.48.14",
6061
"dicomweb-client": "^0.10.3",
6162
"gh-pages": "^5.0.0",
6263
"oidc-client": "^1.11.5",

src/components/Header.tsx

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import React from 'react'
22
import { NavLink } from 'react-router-dom'
33
import {
44
Col,
5-
Descriptions,
65
Dropdown,
76
Input,
87
Layout,
@@ -26,6 +25,7 @@ import {
2625
CloudDownloadOutlined
2726
} from '@ant-design/icons'
2827
import { detect } from 'detect-browser'
28+
import appPackageJson from '../../package.json'
2929

3030
import Button from './Button'
3131
import { RouteComponentProps, withRouter } from '../utils/router'
@@ -172,36 +172,57 @@ class Header extends React.Component<HeaderProps, HeaderState> {
172172
}
173173
}
174174

175+
const slimCommit = process.env.REACT_APP_GIT_SHA !== undefined && process.env.REACT_APP_GIT_SHA !== '' ? process.env.REACT_APP_GIT_SHA : null
176+
const viewerCommit = process.env.REACT_APP_DMV_GIT_SHA !== undefined && process.env.REACT_APP_DMV_GIT_SHA !== '' ? process.env.REACT_APP_DMV_GIT_SHA : null
177+
const devDeps = appPackageJson.devDependencies as Record<string, string> | undefined
178+
const deps = appPackageJson.dependencies as Record<string, string> | undefined
179+
const viewerVersionRaw =
180+
devDeps?.['dicom-microscopy-viewer'] ??
181+
deps?.['dicom-microscopy-viewer'] ??
182+
'unknown'
183+
const viewerVersion = viewerVersionRaw.replace(/^[^0-9]*/, '')
184+
175185
Modal.info({
176-
title: 'About',
177-
width: 600,
186+
width: 480,
187+
title: null,
188+
centered: true,
178189
content: (
179-
<>
180-
<Descriptions title='Application' column={1}>
181-
<Descriptions.Item label='Name'>
182-
{this.props.app.name}
183-
</Descriptions.Item>
184-
<Descriptions.Item label='Version'>
185-
{this.props.app.version}
186-
</Descriptions.Item>
187-
<Descriptions.Item label='Homepage'>
190+
<div style={{ textAlign: 'center', lineHeight: 1.6, paddingRight: 25 }}>
191+
<div style={{ fontSize: '2.2rem', fontWeight: 700, marginBottom: 4 }}>{this.props.app.name}</div>
192+
<div style={{ fontSize: '2rem', fontWeight: 600 }}>{this.props.app.version}</div>
193+
<div style={{ fontSize: '1rem', marginBottom: 16 }}>
194+
<a href={this.props.app.homepage} target='_blank' rel='noreferrer'>
188195
{this.props.app.homepage}
189-
</Descriptions.Item>
190-
</Descriptions>
191-
<Descriptions title='Browser' column={1}>
192-
<Descriptions.Item label='Name'>
193-
{environment.browser.name}
194-
</Descriptions.Item>
195-
<Descriptions.Item label='Version'>
196-
{environment.browser.version}
197-
</Descriptions.Item>
198-
</Descriptions>
199-
<Descriptions title='Operating System' column={1}>
200-
<Descriptions.Item label='Name'>
201-
{environment.os.name}
202-
</Descriptions.Item>
203-
</Descriptions>
204-
</>
196+
</a>
197+
</div>
198+
199+
<div style={{ marginBottom: 12 }}>
200+
<div style={{ fontWeight: 600 }}>Commit Hash</div>
201+
<code>{slimCommit ?? 'unknown'}</code>
202+
</div>
203+
204+
<div style={{ marginBottom: 12 }}>
205+
<div style={{ fontWeight: 600 }}>
206+
<a
207+
href='https://github.com/MGHComputationalPathology/dicom-microscopy-viewer'
208+
target='_blank'
209+
rel='noreferrer'
210+
>
211+
DICOM Microscopy Viewer
212+
</a>
213+
</div>
214+
<div>Version {viewerVersion}</div>
215+
<code>{viewerCommit ?? 'unknown'}</code>
216+
</div>
217+
218+
<div style={{ marginBottom: 12 }}>
219+
<div style={{ fontWeight: 600 }}>Current Browser &amp; OS</div>
220+
<div>
221+
{environment.browser.name ?? 'Unknown'} {environment.browser.version ?? ''}
222+
</div>
223+
<div>{environment.os.name ?? 'Unknown OS'}</div>
224+
</div>
225+
</div>
205226
),
206227
onOk (): void {}
207228
})

src/components/HoveredRoiTooltip.tsx

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,38 +5,78 @@ const HoveredRoiTooltip = ({
55
}: {
66
xPosition: number
77
yPosition: number
8-
rois: Array<{ index: number, roiUid: string, attributes: Array<{ name: string, value: string }>}>
8+
rois: Array<{ index: number, roiUid: string, attributes: Array<{ name: string, value: string }>, seriesDescription?: string }>
99
}): JSX.Element => {
10+
// Always group ROIs by series description
11+
const groupedRois = rois.reduce<{ [key: string]: typeof rois }>((acc, roi) => {
12+
const seriesDesc = (roi.seriesDescription !== null && roi.seriesDescription !== undefined && roi.seriesDescription !== '') ? roi.seriesDescription : 'Unknown Series'
13+
if (acc[seriesDesc] === undefined) {
14+
acc[seriesDesc] = []
15+
}
16+
acc[seriesDesc].push(roi)
17+
return acc
18+
}, {})
19+
20+
const baseStyle: React.CSSProperties = {
21+
position: 'fixed',
22+
top: `${yPosition}px`,
23+
left: `${xPosition}px`,
24+
backgroundColor: 'rgba(230, 230, 230, 0.95)',
25+
padding: '10px',
26+
fontWeight: 'bold',
27+
pointerEvents: 'none',
28+
borderRadius: '4px',
29+
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)',
30+
zIndex: 10000
31+
}
32+
1033
return (
1134
<div
1235
style={{
13-
position: 'fixed',
14-
top: `${yPosition}px`,
15-
left: `${xPosition}px`,
16-
backgroundColor: 'rgba(230, 230, 230, 0.65)',
17-
minWidth: '150px',
18-
minHeight: '60px',
19-
padding: '20px',
20-
fontWeight: 'bold',
21-
pointerEvents: 'none'
36+
...baseStyle,
37+
minWidth: '200px',
38+
maxWidth: '400px'
2239
}}
2340
>
24-
{rois.map((roi, i) => {
25-
const attributes = roi.attributes
26-
return (
27-
<div key={roi.roiUid}>
28-
<span>ROI {roi.index}</span>
29-
{attributes.map((attr) => {
41+
{Object.entries(groupedRois).map(([seriesDesc, seriesRois], seriesIndex) => (
42+
<div key={seriesDesc} style={{ marginBottom: seriesIndex > 0 ? '12px' : '0' }}>
43+
{seriesIndex > 0 && (
44+
<hr style={{ margin: '10px 0', border: 'none', borderTop: '1px solid rgba(0, 0, 0, 0.2)' }} />
45+
)}
46+
<div style={{ fontSize: '13px', fontWeight: 'bold', color: 'rgba(0, 0, 0, 0.8)', marginBottom: '8px', paddingBottom: '4px', borderBottom: '1px solid rgba(0, 0, 0, 0.15)' }}>
47+
{seriesDesc}
48+
</div>
49+
<div style={{ marginLeft: '4px' }}>
50+
{seriesRois.map((roi: { index: number, roiUid: string, attributes: Array<{ name: string, value: string }>, seriesDescription?: string }, roiIndex: number) => {
51+
const annotationGroupLabelAttr = roi.attributes.find((attr: { name: string, value: string }) => attr.name === 'Annotation Group Label')
52+
const otherAttributes = roi.attributes.filter(
53+
(attr: { name: string, value: string }) => attr.name !== 'Series Description' && attr.name !== 'Annotation Group Label'
54+
)
3055
return (
31-
<div key={attr.name + roi.roiUid}>
32-
{attr.name}: <span style={{ fontWeight: 500 }}>{attr.value}</span>
56+
<div key={roi.roiUid} style={{ marginBottom: roiIndex < seriesRois.length - 1 ? '6px' : '0', fontSize: '12px' }}>
57+
<div style={{ fontWeight: 'bold' }}>
58+
ROI {roi.index}
59+
{(annotationGroupLabelAttr != null) && (
60+
<span style={{ fontWeight: 500, marginLeft: '6px', color: 'rgba(0, 0, 0, 0.7)' }}>
61+
- {annotationGroupLabelAttr.value}
62+
</span>
63+
)}
64+
</div>
65+
{otherAttributes.length > 0 && (
66+
<div style={{ marginLeft: '12px', fontSize: '11px', color: 'rgba(0, 0, 0, 0.8)', marginTop: '2px' }}>
67+
{otherAttributes.map((attr: { name: string, value: string }) => (
68+
<div key={String(attr.name) + '-' + String(roi.roiUid)}>
69+
{attr.name}: <span style={{ fontWeight: 500 }}>{attr.value}</span>
70+
</div>
71+
))}
72+
</div>
73+
)}
3374
</div>
3475
)
3576
})}
3677
</div>
37-
38-
)
39-
})}
78+
</div>
79+
))}
4080
</div>
4181
)
4282
}

0 commit comments

Comments
 (0)