Change toolbarModule scheme and extensionManager

This commit is contained in:
dannyrb 2020-06-14 21:18:29 -04:00
parent ae107f4d3b
commit f70392a52a
5 changed files with 132 additions and 258 deletions

View File

@ -0,0 +1,7 @@
import React from 'react';
export default function ToolbarDivider() {
return (
<span className="self-center w-1 h-8 mx-2 border-l border-common-dark" />
);
}

View File

@ -1,10 +1,9 @@
import React, { useState } from 'react';
import React from 'react';
import PropTypes from 'prop-types';
//
import { NavBar, Svg, Icon, IconButton, Toolbar } from '@ohif/ui';
import { NavBar, Svg, Icon, IconButton } from '@ohif/ui';
function Header({ tools, moreTools }) {
const [activeTool, setActiveTool] = useState('Zoom');
function Header({ children }) {
// const dropdownContent = [
// {
// name: 'Soft tissue',
@ -14,80 +13,16 @@ function Header({ tools, moreTools }) {
// { name: 'Liver', value: '150 / 90' },
// { name: 'Bone', value: '2500 / 480' },
// { name: 'Brain', value: '80 / 40' },
// ];
// ]
// TODO -> In ToolBarManager => Consume commandName and commandOptions and create onClick?
/*
const tools = [
{
id: 'Zoom',
label: 'Zoom',
icon: 'tool-zoom',
commandName: 'setToolActive',
commandOptions: { toolName: 'Zoom' },
onClick: () => setActiveTool('Zoom'),
},
{
id: 'Wwwc',
label: 'Levels',
icon: 'tool-window-level',
commandName: 'setToolActive',
commandOptions: { toolName: 'Wwwc' },
onClick: () => setActiveTool('Wwwc'),
dropdownContent: (
<div>
{dropdownContent.map((row, i) => (
<div
key={i}
className="flex justify-between py-2 px-3 hover:bg-secondary-dark cursor-pointer"
>
<div>
<span className="text-base text-white">{row.name}</span>
<span className="text-base text-primary-light ml-3">
{row.value}
</span>
</div>
<span className="text-base text-primary-active ml-4">{i}</span>
</div>
))}
</div>
),
},
{
id: 'Pan',
label: 'Pan',
icon: 'tool-move',
commandName: 'setToolActive',
commandOptions: { toolName: 'Pan' },
onClick: () => setActiveTool('Pan'),
},
{
id: 'Capture',
label: 'Capture',
icon: 'tool-capture',
commandName: 'setToolActive',
commandOptions: { toolName: 'Capture' },
onClick: () => setActiveTool('Capture'),
},
{
id: 'Layout',
label: 'Layout',
icon: 'tool-layout',
commandName: 'setToolActive',
commandOptions: { toolName: 'Layout' },
onClick: () => setActiveTool('Layout'),
},
];
*/
return (
<NavBar className="justify-between border-b-4 border-black">
<div className="flex flex-1 justify-between">
<div className="flex justify-between flex-1">
<div className="flex items-center">
<div className="mr-3 inline-flex items-center">
<div className="inline-flex items-center mr-3">
<Icon
name="chevron-left"
className="text-primary-active w-8 cursor-pointer"
className="w-8 cursor-pointer text-primary-active"
onClick={() => alert('Navigate to previous page')}
/>
<a href="#" className="ml-4">
@ -95,15 +30,9 @@ function Header({ tools, moreTools }) {
</a>
</div>
</div>
<div className="flex items-center">{children}</div>
<div className="flex items-center">
<Toolbar
tools={tools}
activeTool={activeTool}
moreTools={moreTools}
/>
</div>
<div className="flex items-center">
<span className="mr-3 text-common-light text-lg">
<span className="mr-3 text-lg text-common-light">
FOR INVESTIGATIONAL USE ONLY
</span>
<IconButton
@ -123,8 +52,7 @@ function Header({ tools, moreTools }) {
}
Header.propTypes = {
tools: PropTypes.array.isRequired,
moreTools: PropTypes.array.isRequired,
children: PropTypes.any.isRequired,
};
export default Header;

View File

@ -1,7 +1,7 @@
import React, { useEffect, useState, useCallback } from 'react';
import React, { useEffect, useState } from 'react';
import classnames from 'classnames';
import PropTypes from 'prop-types';
import { SidePanel, Toolbar } from '@ohif/ui';
//
import { SidePanel, ToolbarButton } from '@ohif/ui';
import Header from './Header.jsx';
function ViewerLayout({
@ -54,71 +54,23 @@ function ViewerLayout({
};
};
const handleToolBarSubscription = newToolBarLayout => {
// Get buttons to pass to toolbars.
console.log(commandsManager);
const firstTool = newToolBarLayout[0].tools[0];
const toolBarLayout = [];
newToolBarLayout.forEach(newToolBar => {
const toolBar = { tools: [], moreTools: [] };
Object.keys(newToolBar).forEach(key => {
if (newToolBar[key].length) {
newToolBar[key].forEach(tool => {
const commandOptions = tool.commandOptions || {};
toolBar[key].push({
context: tool.context,
icon: tool.icon,
id: tool.id,
label: tool.label,
type: 'setToolActive',
onClick: () => {
commandsManager.runCommand(tool.commandName, commandOptions);
},
});
});
}
});
toolBarLayout.push(toolBar);
// if (newToolBar.moreTools && newToolBar.moreTools.length) {
// newToolBar.moreTools.forEach(tool => {
// const commandOptions = tool.commandOptions || {};
// toolBar.push({
// context: tool.context,
// icon: tool.icon,
// id: tool.id,
// label: tool.label,
// type: 'setToolActive',
// command: () =>
// commandsManager.runCommand(tool.commandName, commandOptions),
// });
// });
// }
});
setToolBarLayout(toolBarLayout);
};
const [toolBarLayout, setToolBarLayout] = useState([
{ tools: [], moreTools: [] },
{ tools: [] },
]);
const [toolbars, setToolbars] = useState({ primary: [], secondary: [] });
useEffect(() => {
const { unsubscribe } = ToolBarService.subscribe(
ToolBarService.EVENTS.TOOL_BAR_MODIFIED,
handleToolBarSubscription
() => {
console.warn('~~~ TOOL BAR MODIFIED EVENT CAUGHT');
const updatedToolbars = {
primary: ToolBarService.getButtonSection('primary'),
secondary: ToolBarService.getButtonSection('secondary'),
};
setToolbars(updatedToolbars);
}
);
return unsubscribe;
}, []);
}, [ToolBarService]);
const leftPanelComponents = leftPanels.map(getPanelData);
const rightPanelComponents = rightPanels.map(getPanelData);
@ -126,10 +78,16 @@ function ViewerLayout({
return (
<div>
<Header
tools={toolBarLayout[0].tools}
moreTools={toolBarLayout[0].moreTools}
/>
<Header>
{/* relative, flex, justify-center */}
<div className="flex">
{toolbars.primary.map(toolDef => {
const { id, Component, componentProps } = toolDef;
return <Component key={id} id={id} {...componentProps} />;
})}
</div>
</Header>
<div
className="flex flex-row flex-no-wrap items-stretch w-full overflow-hidden"
style={{ height: 'calc(100vh - 57px' }}
@ -145,67 +103,17 @@ function ViewerLayout({
{/* TOOLBAR + GRID */}
<div className="flex flex-col flex-1 h-full">
<div className="flex h-12 border-b border-transparent flex-2 w-100">
<Toolbar type="secondary" tools={toolBarLayout[1].tools} />
{toolbars.secondary.map(toolDef => {
const { id, Component, componentProps } = toolDef;
return <Component key={id} id={id} {...componentProps} />;
})}
</div>
<div className="flex items-center justify-center flex-1 h-full pt-1 pb-2 overflow-hidden bg-black">
<ViewportGridComp
servicesManager={servicesManager}
viewportComponents={viewportComponents}
/>
{/*
viewportContents={[
<Viewport
viewportIndex={0}
onSeriesChange={direction => alert(`Series ${direction}`)}
studyData={{
label: 'A',
isTracked: true,
isLocked: false,
studyDate: '07-Sep-2011',
currentSeries: 1,
seriesDescription:
'Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit ',
modality: 'CT',
patientInformation: {
patientName: 'Smith, Jane',
patientSex: 'F',
patientAge: '59',
MRN: '10000001',
thickness: '5.0mm',
spacing: '1.25mm',
scanner: 'Aquilion',
},
}}
>
</Viewport>,
<Viewport
viewportIndex={1}
onSeriesChange={direction => alert(`Series ${direction}`)}
studyData={{
label: 'A',
isTracked: false,
isLocked: true,
studyDate: '07-Sep-2010',
currentSeries: 2,
seriesDescription:
'Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit ',
modality: 'SR',
patientInformation: {
patientName: 'Smith, Jane',
patientSex: 'F',
patientAge: '59',
MRN: '10000001',
thickness: '2.0mm',
spacing: '1.25mm',
scanner: 'Aquilion',
},
}}
>
</Viewport>,
]}
setActiveViewportIndex={setActiveViewportIndex}
activeViewportIndex={activeViewportIndex}
/>*/}
</div>
</div>
{rightPanelComponents.length && (
@ -227,14 +135,6 @@ ViewerLayout.propTypes = {
}).isRequired,
commandsManager: PropTypes.object,
// From modes
// TODO: Not in love with this shape,
toolBarLayout: PropTypes.arrayOf(
PropTypes.shape({
tools: PropTypes.array,
moreTools: PropTypes.array,
})
).isRequired,
//displaySetInstanceUids: PropTypes.any.isRequired,
leftPanels: PropTypes.array,
rightPanels: PropTypes.array,
/** Responsible for rendering our grid of viewports; provided by consuming application */

View File

@ -1,19 +1,86 @@
const TOOLBAR_BUTTON_TYPES = {
COMMAND: 'command',
SET_TOOL_ACTIVE: 'setToolActive',
BUILT_IN: 'builtIn',
};
import { ToolbarButton } from '@ohif/ui';
import ToolbarDivider from './Toolbar/ToolbarDivider.jsx';
const definitions = [
{
id: 'Layout',
label: 'Layout',
icon: 'tool-layout',
commandName: 'toggleLayoutSelectionDialog',
commandOptions: { },
},
];
export default function getToolbarModule({ commandsManager, servicesManager }) {
const toolbarService = servicesManager.services.ToolBarService;
export default function getToolbarModule() {
return { definitions, defaultContext: 'ACTIVE_VIEWPORT::CORNERSTONE' };
return [
{
name: 'ohif.divider',
defaultComponent: ToolbarDivider,
clickHandler: () => {},
},
{
name: 'ohif.action',
defaultComponent: ToolbarButton,
requiredConfig: [],
optionalConfig: [],
requiredProps: [],
optionalProps: [],
clickHandler: (evt, btn, btnSectionName) => {
const { props } = btn;
commandsManager.runCommand(props.commandName, props.commandOptions);
},
},
{
name: 'ohif.radioGroup',
defaultComponent: ToolbarButton,
requiredConfig: ['groupName'],
optionalConfig: [],
requiredProps: [],
optionalProps: [],
clickHandler: (evt, clickedBtn, btnSectionName) => {
const { props } = clickedBtn;
const allButtons = toolbarService.getButtons();
// Set all buttons in same group to inactive
Object.keys(allButtons).forEach(btnName => {
const btn = allButtons[btnName];
const isRadioGroupBtn =
btn.config &&
btn.config.groupName &&
btn.type === 'ohif.radioGroup';
if (
isRadioGroupBtn &&
clickedBtn.config.groupName === btn.config.groupName
) {
btn.props.isActive = false;
}
});
// Set our clicked button to active
allButtons[clickedBtn.id].props.isActive = true;
// Run button logic/command
commandsManager.runCommand(props.commandName, props.commandOptions);
// Set buttons & trigger notification
toolbarService.setButtons(allButtons);
},
},
{
name: 'ohif.toggle',
defaultComponent: ToolbarButton,
requiredConfig: [],
optionalConfig: [],
requiredProps: [],
optionalProps: [],
clickHandler: (evt, clickedBtn, btnSectionName) => {
const { props } = clickedBtn;
const allButtons = toolbarService.getButtons();
const thisButton = allButtons[clickedBtn.id];
// Set our clicked button to active
thisButton.props.isActive = !thisButton.props.isActive;
// Run button logic/command
// MAKE SURE THIS SUPPORTS TOGGLE!
commandsManager.runCommand(props.commandName, props.commandOptions);
// Set buttons & trigger notification
toolbarService.setButtons(allButtons);
},
},
];
}

View File

@ -17,9 +17,6 @@ export default class ExtensionManager {
this.modules[moduleType] = [];
});
this.dataSourceMap = {};
console.log('modules map');
console.log(this.modulesMap);
}
/**
@ -102,9 +99,6 @@ export default class ExtensionManager {
);
break;
case MODULE_TYPES.TOOLBAR:
this._initToolBarModule(extensionModule, extensionId);
break;
case MODULE_TYPES.VIEWPORT:
case MODULE_TYPES.PANEL:
case MODULE_TYPES.SOP_CLASS_HANDLER:
@ -112,7 +106,6 @@ export default class ExtensionManager {
case MODULE_TYPES.LAYOUT_TEMPLATE:
// Default for most extension points,
// Just adds each entry ready for consumption by mode.
extensionModule.forEach(element => {
this.modulesMap[
`${extensionId}.${moduleType}.${element.name}`
@ -141,27 +134,6 @@ export default class ExtensionManager {
return this.dataSourceMap[dataSourceName];
};
_initToolBarModule = (extensionModule, extensionId) => {
let { definitions, defaultContext } = extensionModule;
if (!definitions || Object.keys(definitions).length === 0) {
log.warn('Commands Module contains no command definitions');
return;
}
defaultContext = defaultContext || 'VIEWER';
definitions.forEach(definition => {
console.log(`${extensionId}.${MODULE_TYPES.TOOLBAR}.${definition.id}`);
// TODO -> Deep copy instead of mutation? We only do this once, but would be better.
definition.context = definition.context || defaultContext;
this.modulesMap[
`${extensionId}.${MODULE_TYPES.TOOLBAR}.${definition.id}`
] = definition;
});
};
/**
* @private
* @param {string} moduleType
@ -178,13 +150,13 @@ export default class ExtensionManager {
try {
const extensionModule = getModuleFn({
getDataSources: this.getDataSources, // Why pass this in if we're passing in `extensionManager`?
servicesManager: this._servicesManager,
commandsManager: this._commandsManager,
appConfig: this._appConfig,
getDataSources: this.getDataSources, // Why pass this in if we're passing in `extensionManager`?
commandsManager: this._commandsManager,
extensionManager: this,
servicesManager: this._servicesManager,
configuration,
api: this._api,
extensionManager: this,
});
if (!extensionModule) {