refactor: Remove LabelingFlow/ContextMenu services and reimplement on top of the Dialog service #1264 (#1292)

* Remove ContextMenu and Labelling services and provider to use DialogService directly

* Refactor init to display labelling

* Cleanup labelling flow in measurements init

* Cleanup viewer imports

* Add classname to toolcontextmenu

* Add error message
This commit is contained in:
Igor Octaviano 2019-12-16 11:19:40 -03:00 committed by Danny Brown
parent f78abe2afa
commit b58aa4575a
20 changed files with 210 additions and 693 deletions

View File

@ -23,8 +23,6 @@ import {
UINotificationService,
UIModalService,
UIDialogService,
UIContextMenuService,
UILabellingFlowService,
} from './services';
const OHIF = {
@ -55,8 +53,6 @@ const OHIF = {
UINotificationService,
UIModalService,
UIDialogService,
UIContextMenuService,
UILabellingFlowService,
};
export {
@ -86,8 +82,6 @@ export {
UINotificationService,
UIModalService,
UIDialogService,
UIContextMenuService,
UILabellingFlowService,
};
export { OHIF };

View File

@ -13,8 +13,6 @@ describe('Top level exports', () => {
'UINotificationService',
'UIModalService',
'UIDialogService',
'UIContextMenuService',
'UILabellingFlowService',
//
'utils',
'studies',

View File

@ -1,66 +0,0 @@
/**
* UI Context Menu
*
* @typedef {Object} ContextMenuProps
* @property {Event} event The event with tool information.
*/
const name = 'UIContextMenuService';
const publicAPI = {
name,
hide: _hide,
show: _show,
setServiceImplementation,
};
const serviceImplementation = {
_show: () => console.warn('show() NOT IMPLEMENTED'),
_hide: () => console.warn('hide() NOT IMPLEMENTED'),
};
/**
* Show a new UI ContextMenu dialog;
*
* @param {ContextMenuProps} props { event }
*/
function _show({ event }) {
return serviceImplementation._show({
event,
});
}
/**
* Hide a UI ContextMenu dialog;
*
*/
function _hide() {
return serviceImplementation._hide();
}
/**
*
*
* @param {*} {
* show: showImplementation,
* hide: hideImplementation,
* }
*/
function setServiceImplementation({
show: showImplementation,
hide: hideImplementation,
}) {
if (showImplementation) {
serviceImplementation._show = showImplementation;
}
if (hideImplementation) {
serviceImplementation._hide = hideImplementation;
}
}
export default {
name,
create: ({ configuration = {} }) => {
return publicAPI;
},
};

View File

@ -1,71 +0,0 @@
/**
* UI Labelling Flow
*
* @typedef {Object} LabellingFlowProps
* @property {Object} defaultPosition The position of the labelling dialog.
* @property {boolean} centralize conditional to center the labelling dialog.
* @property {Object} props The labelling props.
*
*/
const name = 'UILabellingFlowService';
const publicAPI = {
name,
show: _show,
hide: _hide,
setServiceImplementation,
};
const serviceImplementation = {
_show: () => console.warn('show() NOT IMPLEMENTED'),
_hide: () => console.warn('hide() NOT IMPLEMENTED'),
};
/**
* Hide a UI LabellingFlow dialog;
*
*/
function _hide() {
return serviceImplementation._hide();
}
/**
* Show a new UI LabellingFlow dialog;
*
* @param {LabellingFlowProps} props { defaultPosition, centralize, props }
*/
function _show({ defaultPosition, centralize, props }) {
return serviceImplementation._show({
defaultPosition,
centralize,
props,
});
}
/**
*
*
* @param {*} {
* show: showImplementation,
* hide: hideImplementation,
* }
*/
function setServiceImplementation({
show: showImplementation,
hide: hideImplementation,
}) {
if (showImplementation) {
serviceImplementation._show = showImplementation;
}
if (hideImplementation) {
serviceImplementation._hide = hideImplementation;
}
}
export default {
name,
create: ({ configuration = {} }) => {
return publicAPI;
},
};

View File

@ -2,14 +2,10 @@ import ServicesManager from './ServicesManager.js';
import UINotificationService from './UINotificationService';
import UIModalService from './UIModalService';
import UIDialogService from './UIDialogService';
import UIContextMenuService from './UIContextMenuService';
import UILabellingFlowService from './UILabellingFlowService';
export {
UINotificationService,
UIModalService,
UIDialogService,
UIContextMenuService,
UILabellingFlowService,
ServicesManager,
};

View File

@ -1,20 +1,19 @@
.ToolContextMenu {
.ContextMenu {
position: relative;
background-color: white;
border: 1px solid white;
border-radius: 5px;
z-index: 1000;
display: block;
width: 170px;
}
.ToolContextMenu > ul {
.ContextMenu>ul {
list-style-type: none;
padding-left: 0;
margin: 0;
}
.ToolContextMenu > ul > li > button {
.ContextMenu>ul>li>button {
padding: 10px;
font-size: 14px;
border: none;
@ -25,10 +24,10 @@
background: none;
}
.ToolContextMenu > ul > li > button:hover {
.ContextMenu>ul>li>button:hover {
color: #16202b;
}
.ToolContextMenu > ul > li > button:active {
.ContextMenu>ul>li>button:active {
color: #79f9fe;
}

View File

@ -0,0 +1,27 @@
import React from 'react';
import PropTypes from 'prop-types';
import './ContextMenu.css';
const ContextMenu = ({ items, onClick }) => {
return (
<div className="ContextMenu">
<ul>
{items.map((item, index) => (
<li key={index}>
<button className="form-action" onClick={() => onClick(item)}>
<span key={index}>{item.label}</span>
</button>
</li>
))}
</ul>
</div>
);
};
ContextMenu.propTypes = {
items: PropTypes.array.isRequired,
onClick: PropTypes.func.isRequired,
};
export default ContextMenu;

View File

@ -0,0 +1 @@
export { default as ContextMenu } from './ContextMenu.js';

View File

@ -17,6 +17,7 @@ import { RoundedButtonGroup } from './roundedButtonGroup';
import { SelectTree } from './selectTree';
import { SimpleDialog } from './simpleDialog';
import { OHIFModal } from './ohifModal';
import { ContextMenu } from './contextMenu';
import {
PageToolbar,
StudyList,
@ -27,6 +28,7 @@ import { ToolbarSection } from './toolbarSection';
import { Tooltip } from './tooltip';
export {
ContextMenu,
Checkbox,
CineDialog,
ViewportDownloadForm,

View File

@ -1,147 +0,0 @@
import React, {
createContext,
useContext,
useEffect,
useCallback,
} from 'react';
import PropTypes from 'prop-types';
import { useDialog } from '@ohif/ui';
import { useLabellingFlow } from '@ohif/ui';
const ContextMenuContext = createContext(null);
const { Provider } = ContextMenuContext;
export const useContextMenu = () => useContext(ContextMenuContext);
const ContextMenuProvider = ({
children,
service,
contextMenuComponent: ContextMenuComponent,
onDelete,
}) => {
const { create, dismiss } = useDialog();
const { show: showLabellingFlow } = useLabellingFlow();
/**
* Sets the implementation of a context menu service that can be used by extensions.
*
* @returns void
*/
useEffect(() => {
if (service) {
service.setServiceImplementation({
show,
hide,
});
}
}, [hide, service, show]);
const hide = useCallback(() => dismiss({ id: 'context-menu' }), [dismiss]);
/**
* Show the context menu and override its configuration props.
*
* @param {ContextMenuProps} props { eventData, isTouchEvent, onClose, visible }
* @returns void
*/
const show = useCallback(
({ event }) => {
hide();
create({
id: 'context-menu',
isDraggable: false,
preservePosition: false,
content: ContextMenuComponent,
contentProps: {
eventData: event,
onDelete: (nearbyToolData, eventData) =>
onDelete(nearbyToolData, eventData),
onClose: () => dismiss({ id: 'context-menu' }),
onSetLabel: (eventData, measurementData) =>
showLabellingFlow({
event: eventData,
centralize: true,
props: {
measurementData,
skipAddLabelButton: true,
editLocation: true,
},
}),
onSetDescription: (eventData, measurementData) =>
showLabellingFlow({
event: eventData,
centralize: false,
defaultPosition: _getDefaultPosition(eventData),
props: {
measurementData,
editDescriptionOnDialog: true,
},
}),
},
defaultPosition: _getDefaultPosition(event),
});
},
[ContextMenuComponent, create, dismiss, hide, onDelete, showLabellingFlow]
);
const _getDefaultPosition = event => ({
x: (event && event.currentPoints.client.x) || 0,
y: (event && event.currentPoints.client.y) || 0,
});
return (
<Provider
value={{
show,
hide,
}}
>
{children}
</Provider>
);
};
/**
* Higher Order Component to use the context menu methods through a Class Component.
*
* @returns
*/
export const withContextMenu = Component => {
return function WrappedComponent(props) {
const { show, hide } = useContextMenu();
return (
<Component
{...props}
modal={{
show,
hide,
}}
/>
);
};
};
ContextMenuProvider.defaultProps = {
service: null,
};
ContextMenuProvider.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]).isRequired,
service: PropTypes.shape({
setServiceImplementation: PropTypes.func,
}),
contextMenuComponent: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
PropTypes.func,
]).isRequired,
onDelete: PropTypes.func.isRequired,
};
export default ContextMenuProvider;
export const ContextMenuConsumer = ContextMenuContext.Consumer;

View File

@ -1,136 +0,0 @@
import React, {
createContext,
useContext,
useEffect,
useCallback,
} from 'react';
import PropTypes from 'prop-types';
import { useDialog } from './DialogProvider';
const LabellingFlowContext = createContext(null);
const { Provider } = LabellingFlowContext;
export const useLabellingFlow = () => useContext(LabellingFlowContext);
const LabellingFlowProvider = ({
children,
service,
labellingComponent: LabellingComponent,
onUpdateLabelling,
}) => {
const { create, dismiss } = useDialog();
/**
* Sets the implementation of a labelling flow service that can be used by extensions.
*
* @returns void
*/
useEffect(() => {
if (service) {
service.setServiceImplementation({
show,
hide,
});
}
}, [hide, service, show]);
const hide = useCallback(() => dismiss({ id: 'labelling' }), [dismiss]);
const show = useCallback(
({ centralize, defaultPosition, props }) => {
hide();
create({
id: 'labelling',
centralize,
isDraggable: false,
showOverlay: true,
content: LabellingComponent,
defaultPosition,
contentProps: {
visible: true,
measurementData: props.measurementData,
labellingDoneCallback: () => dismiss({ id: 'labelling' }),
updateLabelling: labellingData =>
_updateLabellingHandler(labellingData, props.measurementData),
...props,
},
});
},
[LabellingComponent, _updateLabellingHandler, create, dismiss, hide]
);
const _updateLabellingHandler = useCallback(
(labellingData, measurementData) => {
const { location, description, response } = labellingData;
if (location) {
measurementData.location = location;
}
measurementData.description = description || '';
if (response) {
measurementData.response = response;
}
onUpdateLabelling(labellingData, measurementData);
},
[onUpdateLabelling]
);
return (
<Provider
value={{
show,
hide,
}}
>
{children}
</Provider>
);
};
/**
* Higher Order Component to use the labelling flow methods through a Class Component.
*
* @returns
*/
export const withLabellingFlow = Component => {
return function WrappedComponent(props) {
const { show, hide } = useLabellingFlow();
return (
<Component
{...props}
modal={{
show,
hide,
}}
/>
);
};
};
LabellingFlowProvider.defaultProps = {
service: null,
};
LabellingFlowProvider.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]).isRequired,
service: PropTypes.shape({
setServiceImplementation: PropTypes.func,
}),
labellingComponent: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
PropTypes.func,
]).isRequired,
onUpdateLabelling: PropTypes.func.isRequired,
};
export default LabellingFlowProvider;
export const LabellingFlowConsumer = LabellingFlowContext.Consumer;

View File

@ -18,15 +18,3 @@ export {
withDialog,
useDialog,
} from './DialogProvider.js';
export {
default as ContextMenuProvider,
withContextMenu,
useContextMenu,
ContextMenuConsumer,
} from './ContextMenuProvider.js';
export {
default as LabellingFlowProvider,
withLabellingFlow,
useLabellingFlow,
LabellingFlowConsumer,
} from './LabellingFlowProvider.js';

View File

@ -1,4 +1,5 @@
import {
ContextMenu,
Checkbox,
CineDialog,
ViewportDownloadForm,
@ -60,14 +61,6 @@ import {
ModalConsumer,
useModal,
withModal,
ContextMenuProvider,
ContextMenuConsumer,
useContextMenu,
withContextMenu,
LabellingFlowProvider,
LabellingFlowConsumer,
useLabellingFlow,
withLabellingFlow,
} from './contextProviders';
export {
@ -80,6 +73,7 @@ export {
TextArea,
TextInput,
CineDialog,
ContextMenu,
ViewportDownloadForm,
ExpandableToolMenu,
Icon,
@ -125,14 +119,6 @@ export {
DialogProvider,
withDialog,
useDialog,
ContextMenuProvider,
ContextMenuConsumer,
useContextMenu,
withContextMenu,
LabellingFlowProvider,
LabellingFlowConsumer,
useLabellingFlow,
withLabellingFlow,
// Hooks
useDebounce,
useMedia,

View File

@ -8,9 +8,6 @@ import { hot } from 'react-hot-loader/root';
import OHIFCornerstoneExtension from '@ohif/extension-cornerstone';
import ToolContextMenu from './connectedComponents/ToolContextMenu';
import LabellingFlow from './components/Labelling/LabellingFlow';
import {
SnackbarProvider,
ModalProvider,
@ -18,11 +15,6 @@ import {
OHIFModal,
} from '@ohif/ui';
import {
LabellingFlowProvider,
ContextMenuProvider,
} from './appCustomProviders';
import {
CommandsManager,
ExtensionManager,
@ -31,8 +23,6 @@ import {
UINotificationService,
UIModalService,
UIDialogService,
UIContextMenuService,
UILabellingFlowService,
utils,
redux as reduxOHIF,
} from '@ohif/core';
@ -135,13 +125,7 @@ class App extends Component {
} = this._appConfig;
this.initUserManager(oidc);
_initServices([
UINotificationService,
UIModalService,
UIDialogService,
UIContextMenuService,
UILabellingFlowService,
]);
_initServices([UINotificationService, UIModalService, UIDialogService]);
_initExtensions(
[...defaultExtensions, ...extensions],
cornerstoneExtensionConfig
@ -161,9 +145,7 @@ class App extends Component {
const {
UINotificationService,
UIDialogService,
UILabellingFlowService,
UIModalService,
UIContextMenuService,
} = servicesManager.services;
if (this._userManager) {
@ -181,21 +163,9 @@ class App extends Component {
modal={OHIFModal}
service={UIModalService}
>
<LabellingFlowProvider
service={UILabellingFlowService}
labellingComponent={LabellingFlow}
commandsManager={commandsManager}
>
<ContextMenuProvider
service={UIContextMenuService}
contextMenuComponent={ToolContextMenu}
commandsManager={commandsManager}
>
<OHIFStandaloneViewer
userManager={this._userManager}
/>
</ContextMenuProvider>
</LabellingFlowProvider>
<OHIFStandaloneViewer
userManager={this._userManager}
/>
</ModalProvider>
</DialogProvider>
</SnackbarProvider>
@ -218,19 +188,7 @@ class App extends Component {
<SnackbarProvider service={UINotificationService}>
<DialogProvider service={UIDialogService}>
<ModalProvider modal={OHIFModal} service={UIModalService}>
<LabellingFlowProvider
service={UILabellingFlowService}
labellingComponent={LabellingFlow}
commandsManager={commandsManager}
>
<ContextMenuProvider
service={UIContextMenuService}
contextMenuComponent={ToolContextMenu}
commandsManager={commandsManager}
>
<OHIFStandaloneViewer />
</ContextMenuProvider>
</LabellingFlowProvider>
<OHIFStandaloneViewer />
</ModalProvider>
</DialogProvider>
</SnackbarProvider>

View File

@ -1,51 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { ContextMenuProvider } from '@ohif/ui';
const CustomContextMenuProvider = ({
children,
service,
contextMenuComponent,
commandsManager,
}) => {
const onDeleteHandler = (nearbyToolData, eventData) => {
const element = eventData.element;
commandsManager.runCommand('removeToolState', {
element,
toolType: nearbyToolData.toolType,
tool: nearbyToolData.tool,
});
};
return (
<ContextMenuProvider
service={service}
contextMenuComponent={contextMenuComponent}
onDelete={onDeleteHandler}
>
{children}
</ContextMenuProvider>
);
};
CustomContextMenuProvider.defaultProps = {
service: null,
};
CustomContextMenuProvider.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]).isRequired,
service: PropTypes.shape({
setServiceImplementation: PropTypes.func,
}),
contextMenuComponent: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
PropTypes.func,
]).isRequired,
commandsManager: PropTypes.object.isRequired,
};
export default CustomContextMenuProvider;

View File

@ -1,49 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { LabellingFlowProvider } from '@ohif/ui';
const CustomLabellingFlowProvider = ({
children,
service,
labellingComponent,
commandsManager,
}) => {
const onUpdateLabellingHandler = (labellingData, measurementData) => {
commandsManager.runCommand(
'updateTableWithNewMeasurementData',
measurementData
);
};
return (
<LabellingFlowProvider
service={service}
labellingComponent={labellingComponent}
onUpdateLabelling={onUpdateLabellingHandler}
>
{children}
</LabellingFlowProvider>
);
};
CustomLabellingFlowProvider.defaultProps = {
service: null,
};
CustomLabellingFlowProvider.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]).isRequired,
service: PropTypes.shape({
setServiceImplementation: PropTypes.func,
}),
labellingComponent: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
PropTypes.func,
]).isRequired,
commandsManager: PropTypes.object.isRequired,
};
export default CustomLabellingFlowProvider;

View File

@ -1,6 +0,0 @@
export {
default as LabellingFlowProvider,
} from './LabellingFlowProvider/LabellingFlowProvider.js';
export {
default as ContextMenuProvider,
} from './ContextMenuProvider/ContextMenuProvider.js';

View File

@ -2,6 +2,8 @@ import React from 'react';
import ConnectedMeasurementTable from './ConnectedMeasurementTable.js';
import init from './init.js';
import LabellingFlow from '../../components/Labelling/LabellingFlow';
export default {
/**
* Only required property. Should be a unique value across all extensions.
@ -13,32 +15,51 @@ export default {
},
getPanelModule({ servicesManager, commandsManager }) {
const { UILabellingFlowService, UINotificationService } = servicesManager.services;
const { UINotificationService, UIDialogService } = servicesManager.services;
const showLabellingDialog = (props, measurementData) => {
if (!UIDialogService) {
console.warn('Unable to show dialog; no UI Dialog Service available.');
return;
}
UIDialogService.dismiss({ id: 'labelling' });
UIDialogService.create({
id: 'labelling',
centralize: true,
isDraggable: false,
showOverlay: true,
content: LabellingFlow,
contentProps: {
measurementData,
labellingDoneCallback: () =>
UIDialogService.dismiss({ id: 'labelling' }),
updateLabelling: ({ location, description, response }) => {
measurementData.location = location || measurementData.location;
measurementData.description = description || '';
measurementData.response = response || measurementData.response;
commandsManager.runCommand(
'updateTableWithNewMeasurementData',
measurementData
);
},
...props,
},
});
};
const ExtendedConnectedMeasurementTable = () => (
<ConnectedMeasurementTable
onRelabel={tool => {
if (UILabellingFlowService) {
UILabellingFlowService.show({
centralize: true,
props: {
skipAddLabelButton: true,
editLocation: true,
measurementData: tool,
},
});
}
}}
onEditDescription={tool => {
if (UILabellingFlowService) {
UILabellingFlowService.show({
centralize: true,
props: {
editDescriptionOnDialog: true,
measurementData: tool,
},
});
}
}}
onRelabel={tool =>
showLabellingDialog(
{ editLocation: true, skipAddLabelButton: true },
tool
)
}
onEditDescription={tool =>
showLabellingDialog({ editDescriptionOnDialog: true }, tool)
}
onSaveComplete={message => {
if (UINotificationService) {
UINotificationService.show(message);

View File

@ -3,6 +3,9 @@ import cornerstone from 'cornerstone-core';
import csTools from 'cornerstone-tools';
import throttle from 'lodash.throttle';
import LabellingFlow from '../../components/Labelling/LabellingFlow';
import ToolContextMenu from '../../connectedComponents/ToolContextMenu';
const {
onAdded,
onRemoved,
@ -29,10 +32,7 @@ export default function init({
commandsManager,
configuration,
}) {
const {
UIContextMenuService,
UILabellingFlowService,
} = servicesManager.services;
const { UIDialogService } = servicesManager.services;
// TODO: MEASUREMENT_COMPLETED (not present in initial implementation)
const onMeasurementsChanged = (action, event) => {
@ -46,21 +46,108 @@ export default function init({
'labelmapModified'
);
const onRightClick = event => {
if (UIContextMenuService) {
UIContextMenuService.show({ event: event.detail });
const _getDefaultPosition = event => ({
x: (event && event.currentPoints.client.x) || 0,
y: (event && event.currentPoints.client.y) || 0,
});
const _updateLabellingHandler = (labellingData, measurementData) => {
const { location, description, response } = labellingData;
if (location) {
measurementData.location = location;
}
measurementData.description = description || '';
if (response) {
measurementData.response = response;
}
commandsManager.runCommand(
'updateTableWithNewMeasurementData',
measurementData
);
};
const showLabellingDialog = (props, contentProps, measurementData) => {
if (!UIDialogService) {
console.warn('Unable to show dialog; no UI Dialog Service available.');
return;
}
UIDialogService.create({
id: 'labelling',
isDraggable: false,
showOverlay: true,
content: LabellingFlow,
contentProps: {
measurementData,
labellingDoneCallback: () =>
UIDialogService.dismiss({ id: 'labelling' }),
updateLabelling: labellingData =>
_updateLabellingHandler(labellingData, measurementData),
...contentProps,
},
...props,
});
};
const onRightClick = event => {
if (!UIDialogService) {
console.warn('Unable to show dialog; no UI Dialog Service available.');
return;
}
UIDialogService.dismiss({ id: 'context-menu' });
UIDialogService.create({
id: 'context-menu',
isDraggable: false,
preservePosition: false,
defaultPosition: _getDefaultPosition(event.detail),
content: ToolContextMenu,
contentProps: {
eventData: event.detail,
onDelete: (nearbyToolData, eventData) => {
const element = eventData.element;
commandsManager.runCommand('removeToolState', {
element,
toolType: nearbyToolData.toolType,
tool: nearbyToolData.tool,
});
},
onClose: () => UIDialogService.dismiss({ id: 'context-menu' }),
onSetLabel: (eventData, measurementData) => {
showLabellingDialog(
{ centralize: true, isDraggable: false },
{ skipAddLabelButton: true, editLocation: true },
measurementData
);
},
onSetDescription: (eventData, measurementData) => {
showLabellingDialog(
{ defaultPosition: _getDefaultPosition(eventData) },
{ editDescriptionOnDialog: true },
measurementData
);
},
},
});
};
const onTouchPress = event => {
if (UIContextMenuService) {
UIContextMenuService.show({
event: event.detail,
props: {
isTouchEvent: true,
},
});
if (!UIDialogService) {
console.warn('Unable to show dialog; no UI Dialog Service available.');
return;
}
UIDialogService.create({
eventData: event.detail,
content: ToolContextMenu,
contentProps: {
isTouchEvent: true,
},
});
};
const onTouchStart = () => resetLabelligAndContextMenu();
@ -68,10 +155,13 @@ export default function init({
const onMouseClick = () => resetLabelligAndContextMenu();
const resetLabelligAndContextMenu = () => {
if (UILabellingFlowService && UIContextMenuService) {
UILabellingFlowService.hide();
UIContextMenuService.hide();
if (!UIDialogService) {
console.warn('Unable to show dialog; no UI Dialog Service available.');
return;
}
UIDialogService.dismiss({ id: 'context-menu' });
UIDialogService.dismiss({ id: 'labelling' });
};
// TODO: This makes scrolling painfully slow

View File

@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { commandsManager } from './../App.js';
import './ToolContextMenu.css';
import { ContextMenu } from '@ohif/ui';
const toolTypes = [
'Angle',
@ -24,11 +24,13 @@ const ToolContextMenu = ({
}) => {
const defaultDropdownItems = [
{
label: 'Delete measurement',
actionType: 'Delete',
action: ({ nearbyToolData, eventData }) =>
onDelete(nearbyToolData, eventData),
},
{
label: 'Relabel',
actionType: 'setLabel',
action: ({ nearbyToolData, eventData }) => {
const { tool: measurementData } = nearbyToolData;
@ -51,7 +53,10 @@ const ToolContextMenu = ({
availableToolTypes: toolTypes,
});
// Annotate tools for touch events already have a press handle to edit it, has a better UX for deleting it
/*
* Annotate tools for touch events already have a press handle to edit it,
* has a better UX for deleting it.
*/
if (
isTouchEvent &&
nearbyToolData &&
@ -63,21 +68,10 @@ const ToolContextMenu = ({
let dropdownItems = [];
if (nearbyToolData) {
defaultDropdownItems.forEach(item => {
item.params = {
eventData,
nearbyToolData,
};
if (item.actionType === 'Delete') {
item.text = 'Delete measurement';
}
if (item.actionType === 'setLabel') {
item.text = 'Relabel';
}
item.params = { eventData, nearbyToolData };
if (item.actionType === 'setDescription') {
item.text = `${
item.label = `${
nearbyToolData.tool.description ? 'Edit' : 'Add'
} Description`;
}
@ -89,7 +83,7 @@ const ToolContextMenu = ({
return dropdownItems;
};
const itemOnClickHandler = (action, params, onClose) => {
const onClickHandler = ({ action, params }) => {
action(params);
if (onClose) {
onClose();
@ -99,23 +93,9 @@ const ToolContextMenu = ({
const dropdownItems = getDropdownItems(eventData, isTouchEvent);
return (
dropdownItems.length &&
eventData && (
<div className="ToolContextMenu">
<ul className="bounded">
{dropdownItems.map(({ params, action, text, actionType }) => (
<li key={actionType}>
<button
className="form-action"
onClick={() => itemOnClickHandler(action, params, onClose)}
>
<span key={actionType}>{text}</span>
</button>
</li>
))}
</ul>
</div>
)
<div className="ToolContextMenu">
<ContextMenu items={dropdownItems} onClick={onClickHandler} />;
</div>
);
};
@ -123,6 +103,9 @@ ToolContextMenu.propTypes = {
isTouchEvent: PropTypes.bool.isRequired,
eventData: PropTypes.object,
onClose: PropTypes.func,
onSetDescription: PropTypes.func,
onSetLabel: PropTypes.func,
onDelete: PropTypes.func,
};
ToolContextMenu.defaultProps = {