Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 17 additions & 34 deletions src/components/AnnotationGroupItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
Col,
Divider,
InputNumber,
Menu,
Popover,
Row,
Select,
Expand Down Expand Up @@ -564,41 +563,25 @@ class AnnotationGroupItem extends React.Component<
const color = this.getCurrentColor()
const isBadgeVisible =
this.state.isVisible && this.state.currentStyle.measurement === null
const {
annotationGroup,
defaultStyle,
isVisible,
metadata,
onVisibilityChange,
onStyleChange,
onAnnotationGroupClick,
...otherProps
} = this.props
return (
<Menu.Item
style={{ height: '100%', paddingLeft: '3px' }}
key={this.props.annotationGroup.uid}
{...otherProps}
>
<Space align="start">
<div style={{ paddingLeft: '14px' }}>
<AnnotationGroupControls
isVisible={this.props.isVisible}
onVisibilityChange={this.handleVisibilityChange}
settings={settings}
color={this.state.currentStyle.color ?? [255, 255, 255]}
/>
</div>
<AnnotationGroupBadgeDescription
onClick={this.handleAnnotationGroupClick}
annotationGroup={this.props.annotationGroup}
isBadgeVisible={isBadgeVisible}
color={color}
label={this.props.annotationGroup.label}
attributes={attributes}
<Space align="start">
<div style={{ paddingLeft: '14px' }}>
<AnnotationGroupControls
isVisible={this.props.isVisible}
onVisibilityChange={this.handleVisibilityChange}
settings={settings}
color={this.state.currentStyle.color ?? [255, 255, 255]}
/>
</Space>
</Menu.Item>
</div>
<AnnotationGroupBadgeDescription
onClick={this.handleAnnotationGroupClick}
annotationGroup={this.props.annotationGroup}
isBadgeVisible={isBadgeVisible}
color={color}
label={this.props.annotationGroup.label}
attributes={attributes}
/>
</Space>
)
}
}
Expand Down
38 changes: 22 additions & 16 deletions src/components/AnnotationGroupList.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { MenuProps } from 'antd'
import { Menu, Switch } from 'antd'
// skipcq: JS-C1003
import type * as dcmjs from 'dcmjs'
Expand Down Expand Up @@ -67,21 +68,26 @@ class AnnotationGroupList extends React.Component<
}

render(): React.ReactNode {
const items = this.props.annotationGroups.map((annotationGroup, _index) => {
const uid = annotationGroup.uid
return (
<AnnotationGroupItem
key={annotationGroup.uid}
annotationGroup={annotationGroup}
onAnnotationGroupClick={this.props.onAnnotationGroupClick}
metadata={this.props.metadata[uid]}
isVisible={this.props.visibleAnnotationGroupUIDs.has(uid)}
defaultStyle={this.props.defaultAnnotationGroupStyles[uid]}
onVisibilityChange={this.props.onAnnotationGroupVisibilityChange}
onStyleChange={this.props.onAnnotationGroupStyleChange}
/>
)
})
const items: MenuProps['items'] = this.props.annotationGroups.map(
(annotationGroup) => {
const uid = annotationGroup.uid
return {
key: uid,
style: { height: '100%', paddingLeft: '3px' },
label: (
<AnnotationGroupItem
annotationGroup={annotationGroup}
onAnnotationGroupClick={this.props.onAnnotationGroupClick}
metadata={this.props.metadata[uid]}
isVisible={this.props.visibleAnnotationGroupUIDs.has(uid)}
defaultStyle={this.props.defaultAnnotationGroupStyles[uid]}
onVisibilityChange={this.props.onAnnotationGroupVisibilityChange}
onStyleChange={this.props.onAnnotationGroupStyleChange}
/>
),
}
},
)

return (
<>
Expand All @@ -100,7 +106,7 @@ class AnnotationGroupList extends React.Component<
unCheckedChildren={<FaEyeSlash />}
/>
</div>
<Menu selectable={false}>{items}</Menu>
<Menu selectable={false} items={items} />
</>
)
}
Expand Down
131 changes: 115 additions & 16 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
UserOutlined,
} from '@ant-design/icons'
import {
Badge,
Col,
Collapse,
Dropdown,
Expand Down Expand Up @@ -86,6 +85,59 @@
},
}

/**
* Static count pill that avoids antd Badge → rc-motion `findDOMNode`
* (deprecated under React Strict Mode).
*/
function HeaderCountBadge({
count,
color = '#ff4d4f',
zIndex,
children,
}: {
count: number
color?: string
zIndex?: number
children?: React.ReactNode
}): JSX.Element {

Check warning on line 102 in src/components/Header.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Mark the props of the component as read-only.

See more on https://sonarcloud.io/project/issues?id=ImagingDataCommons_slim&issues=AZ9dv8CgM2Z0o2L3l0on&open=AZ9dv8CgM2Z0o2L3l0on&pullRequest=398
const pill =
count > 0 ? (
<sup
style={{
position: children != null ? 'absolute' : 'relative',
top: children != null ? -4 : undefined,
right: children != null ? -8 : undefined,
zIndex,
display: 'inline-block',
minWidth: 16,
height: 16,
padding: '0 5px',
borderRadius: 8,
background: color,
color: '#fff',
fontSize: 10,
lineHeight: '16px',
textAlign: 'center',
boxShadow: '0 0 0 1px #fff',
verticalAlign: children != null ? undefined : 'middle',
}}
>
{count > 99 ? '99+' : count}
</sup>
) : null

if (children == null) {
return <>{pill}</>
}

return (
<span style={{ position: 'relative', display: 'inline-block' }}>
{children}
{pill}
</span>
)
}

interface HeaderProps extends RouteComponentProps {
app: {
name: string
Expand Down Expand Up @@ -421,11 +473,14 @@
const { Panel } = Collapse

const showErrorCount = (errcount: number): JSX.Element => (
<Badge count={errcount} />
<HeaderCountBadge count={errcount} />
)

const showWarningCount = (warncount: number): JSX.Element => (
<Badge color={warncount > 0 ? 'green' : undefined} count={warncount} />
<HeaderCountBadge
count={warncount}
color={warncount > 0 ? '#52c41a' : '#ff4d4f'}
/>
)

Modal.info({
Expand Down Expand Up @@ -567,7 +622,7 @@
})
}

render(): React.ReactNode {

Check failure on line 625 in src/components/Header.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 18 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=ImagingDataCommons_slim&issues=AZ9dv8CgM2Z0o2L3l0oo&open=AZ9dv8CgM2Z0o2L3l0oo&pullRequest=398
let user = null
if (this.props.user !== undefined) {
const userMenuItems = []
Expand Down Expand Up @@ -612,19 +667,63 @@
)

const debugButton = (
<Badge count={this.state.errorObj.length} style={{ zIndex: 1000 }}>
<Badge
color={this.state.warnings.length > 0 ? 'green' : undefined}
count={this.state.warnings.length}
style={{ zIndex: 1001 }}
>
<Button
icon={BugOutlined}
tooltip="Debug info"
onClick={this.handleDebugButtonClick}
/>
</Badge>
</Badge>
<span style={{ position: 'relative', display: 'inline-block' }}>
<Button
icon={BugOutlined}
tooltip="Debug info"
onClick={this.handleDebugButtonClick}
/>
{this.state.warnings.length > 0 ? (
<sup
style={{
position: 'absolute',
top: -4,
right: this.state.errorObj.length > 0 ? 10 : -8,
zIndex: 1001,
display: 'inline-block',
minWidth: 16,
height: 16,
padding: '0 5px',
borderRadius: 8,
background: '#52c41a',
color: '#fff',
fontSize: 10,
lineHeight: '16px',
textAlign: 'center',
boxShadow: '0 0 0 1px #fff',
}}
>
{this.state.warnings.length > 99
? '99+'
: this.state.warnings.length}
</sup>
) : null}
{this.state.errorObj.length > 0 ? (
<sup
style={{
position: 'absolute',
top: -4,
right: -8,
zIndex: 1000,
display: 'inline-block',
minWidth: 16,
height: 16,
padding: '0 5px',
borderRadius: 8,
background: '#ff4d4f',
color: '#fff',
fontSize: 10,
lineHeight: '16px',
textAlign: 'center',
boxShadow: '0 0 0 1px #fff',
}}
>
{this.state.errorObj.length > 99
? '99+'
: this.state.errorObj.length}
</sup>
) : null}
</span>
)

const showDicomTagBrowser = DICOM_TAG_BROWSER_PATHS.some((path) =>
Expand Down
91 changes: 41 additions & 50 deletions src/components/SlideItem.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Menu, Typography } from 'antd'
import { Typography } from 'antd'
// skipcq: JS-C1003
import * as dmv from 'dicom-microscopy-viewer'
import React from 'react'
Expand Down Expand Up @@ -106,60 +106,51 @@ class SlideItem extends React.Component<SlideItemProps, SlideItemState> {
return <FaSpinner />
}

/* Properties need to be propagated down to Menu.Item:
* https://github.com/react-component/menu/issues/142
*/
return (
<Menu.Item
style={{ height: '100%' }}
key={this.props.slide.seriesInstanceUIDs[0]}
{...this.props}
<Description
header={this.props.slide.containerIdentifier}
attributes={attributes}
selectable
>
<Description
header={this.props.slide.containerIdentifier}
attributes={attributes}
selectable
>
<div style={{ position: 'relative', height: '100px' }}>
{this.props.slide.overviewImages.length > 0 ||
this.props.slide.thumbnailImages.length > 0 ? (
<div ref={this.overviewViewportRef} style={{ height: '100%' }} />
) : (
<div
style={{
height: '100%',
textAlign: 'center',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: '1.5rem',
fontWeight: 300,
color: '#8F9BA8',
letterSpacing: '0.1em',
}}
>
SM
</div>
)}
<ValidationWarning slide={this.props.slide} />
</div>
{this.props.slide.seriesDescription !== undefined &&
this.props.slide.seriesDescription !== null &&
this.props.slide.seriesDescription !== '' ? (
<Typography.Text
type="secondary"
<div style={{ position: 'relative', height: '100px' }}>
{this.props.slide.overviewImages.length > 0 ||
this.props.slide.thumbnailImages.length > 0 ? (
<div ref={this.overviewViewportRef} style={{ height: '100%' }} />
) : (
<div
style={{
display: 'block',
marginTop: 4,
fontSize: '0.75rem',
lineHeight: 1.2,
height: '100%',
textAlign: 'center',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: '1.5rem',
fontWeight: 300,
color: '#8F9BA8',
letterSpacing: '0.1em',
}}
>
{this.props.slide.seriesDescription}
</Typography.Text>
) : null}
</Description>
</Menu.Item>
SM
</div>
)}
<ValidationWarning slide={this.props.slide} />
</div>
{this.props.slide.seriesDescription !== undefined &&
this.props.slide.seriesDescription !== null &&
this.props.slide.seriesDescription !== '' ? (
<Typography.Text
type="secondary"
style={{
display: 'block',
marginTop: 4,
fontSize: '0.75rem',
lineHeight: 1.2,
}}
>
{this.props.slide.seriesDescription}
</Typography.Text>
) : null}
</Description>
)
}
}
Expand Down
Loading
Loading