feat: Add customization URL parameter (#5992)
* Add customization URL parameter * fix: Preserve should be customizeable * Update customizations docs * fix: Overlay items on patient name * Add customization test * Fix resolve to absolute path * fix: Warn on no data in load * Remove unused customization stuff * fix: PR comments * Update stored parameters to only use an array for mulitples * Remove requires ohif.* special call out * Remove strict mode * PR comments * Document segmentation examples * Add three examples as requested * PR comments * lock * Remove old customizatoin export * fix: Ordering issues on customization loads * fix: Use correct default for dev builds app config * Fixes for conflicts * chore: restore pnpm-lock.yaml to match master The lockfile diff was incidental peer-descriptor churn and carried no functional dependency change. It tripped the CircleCI security-audit gate (which only runs when pnpm-lock.yaml is in the PR diff), surfacing a pre-existing critical `decompress` transitive vuln that also exists on master. Restoring master's lockfile removes the audit trigger. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ci): restore json5 lockfile entry; ignore unfixable decompress GHSA The previous commit restored pnpm-lock.yaml from master, which dropped the json5@2.2.3 entry that platform/core legitimately depends on (JSONC parsing for the customization feature). That broke `--frozen-lockfile` install (ERR_PNPM_OUTDATED_LOCKFILE). This restores the correct lockfile. Because the lockfile must change (json5), the CircleCI security-audit gate runs and previously failed on a critical `decompress` <=4.2.1 zip-slip advisory. This is a pre-existing transitive vuln (present on master too) with no published patch — decompress's latest release is 4.2.1, so no version bump/override can resolve it. It reaches the tree only via @itk-wasm/dam, a build/data-asset extraction tool under @cornerstonejs/labelmap-interpolation. Add GHSA-mp2f-45pm-3cg9 to the existing pnpm-workspace.yaml auditConfig ignoreGhsas accepted-risk list, matching how the repo already exempts other build-tooling advisories. `pnpm audit --audit-level high` now passes locally (1 critical ignored, 0 high). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(e2e): fix visitStudy URL encoding that broke mpr2 study load The visitStudy rewrite (added for the ?customization= option) built the URL with new URLSearchParams({ StudyInstanceUIDs: studyInstanceUID }), which percent-encodes the value. mpr2.spec.ts embeds an extra param in the UID string ('<uid>&hangingprotocolid=mpr'), so the & and = were encoded and the whole thing collapsed into one invalid StudyInstanceUIDs value -> the study could not be found ('studies are not available'), the viewer never rendered, and the side-panel-header-right click timed out. Restore master's raw concatenation for StudyInstanceUIDs (so embedded params survive as separate query params) while still appending the customization option separately. Only mpr2 embeds & in the UID, matching the single failure. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * PR comments --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
3d9a17bc0c
commit
3dd5c70cb2
58 files changed
+3411
-586
No files matched your search
+22
-76
@@ -1,11 +1,9 @@
|
||||
import update from 'immutability-helper';
|
||||
import { ToolbarService, utils } from '@ohif/core';
|
||||
import { utils } from '@ohif/core';
|
||||
|
||||
import initToolGroups from './initToolGroups';
|
||||
import toolbarButtons from './toolbarButtons';
|
||||
import { id } from './id';
|
||||
|
||||
const { TOOLBAR_SECTIONS } = ToolbarService;
|
||||
const { structuredCloneWithFunctions } = utils;
|
||||
|
||||
/**
|
||||
@@ -145,9 +143,22 @@ export function onModeEnter({
|
||||
// Init Default and SR ToolGroups
|
||||
initToolGroups(extensionManager, toolGroupService, commandsManager);
|
||||
|
||||
toolbarService.register(this.toolbarButtons);
|
||||
// Toolbar buttons and layout may be supplied either as a customization name
|
||||
// (a string, resolved through the customization service so `?customization=`
|
||||
// modules can extend the cornerstone-registered defaults) or as a literal
|
||||
// value (the button array / sections object) for modes that define them inline.
|
||||
const resolveToolbarCustomization = (value: unknown) =>
|
||||
typeof value === 'string' ? customizationService.getCustomization(value) : value;
|
||||
|
||||
for (const [key, section] of Object.entries(this.toolbarSections)) {
|
||||
const toolbarButtons = resolveToolbarCustomization(this.toolbarButtons) as any;
|
||||
const toolbarSections = (resolveToolbarCustomization(this.toolbarSections) ?? {}) as Record<
|
||||
string,
|
||||
string[]
|
||||
>;
|
||||
|
||||
toolbarService.register(toolbarButtons);
|
||||
|
||||
for (const [key, section] of Object.entries(toolbarSections)) {
|
||||
toolbarService.updateSection(key, section);
|
||||
}
|
||||
|
||||
@@ -212,74 +223,6 @@ export function onModeExit({ servicesManager }: withAppTypes) {
|
||||
cornerstoneViewportService.destroy();
|
||||
}
|
||||
|
||||
export const toolbarSections = {
|
||||
[TOOLBAR_SECTIONS.primary]: [
|
||||
'MeasurementTools',
|
||||
'Zoom',
|
||||
'Pan',
|
||||
'TrackballRotate',
|
||||
'WindowLevel',
|
||||
'Capture',
|
||||
'Layout',
|
||||
'Crosshairs',
|
||||
'MoreTools',
|
||||
],
|
||||
|
||||
[TOOLBAR_SECTIONS.viewportActionMenu.topLeft]: ['orientationMenu', 'dataOverlayMenu'],
|
||||
|
||||
[TOOLBAR_SECTIONS.viewportActionMenu.bottomMiddle]: ['AdvancedRenderingControls'],
|
||||
|
||||
AdvancedRenderingControls: [
|
||||
'windowLevelMenuEmbedded',
|
||||
'voiManualControlMenu',
|
||||
'Colorbar',
|
||||
'opacityMenu',
|
||||
'thresholdMenu',
|
||||
],
|
||||
|
||||
[TOOLBAR_SECTIONS.viewportActionMenu.topRight]: [
|
||||
'modalityLoadBadge',
|
||||
'trackingStatus',
|
||||
'navigationComponent',
|
||||
],
|
||||
|
||||
[TOOLBAR_SECTIONS.viewportActionMenu.bottomLeft]: ['windowLevelMenu'],
|
||||
|
||||
MeasurementTools: [
|
||||
'Length',
|
||||
'Bidirectional',
|
||||
'ArrowAnnotate',
|
||||
'EllipticalROI',
|
||||
'RectangleROI',
|
||||
'CircleROI',
|
||||
'PlanarFreehandROI',
|
||||
'SplineROI',
|
||||
'LivewireContour',
|
||||
],
|
||||
|
||||
MoreTools: [
|
||||
'Reset',
|
||||
'rotate-right',
|
||||
'flipHorizontal',
|
||||
'ImageSliceSync',
|
||||
'ReferenceLines',
|
||||
'ImageOverlayViewer',
|
||||
'StackScroll',
|
||||
'invert',
|
||||
'Probe',
|
||||
'Cine',
|
||||
'Angle',
|
||||
'CobbAngle',
|
||||
'Magnify',
|
||||
'CalibrationLine',
|
||||
'TagBrowser',
|
||||
'AdvancedMagnify',
|
||||
'UltrasoundDirectionalTool',
|
||||
'WindowLevelRegion',
|
||||
'SegmentLabelTool',
|
||||
],
|
||||
};
|
||||
|
||||
export const basicLayout = {
|
||||
id: ohif.layout,
|
||||
props: {
|
||||
@@ -342,7 +285,10 @@ export const modeInstance = {
|
||||
hide: false,
|
||||
displayName: 'Non-Longitudinal Basic',
|
||||
_activatePanelTriggersSubscriptions: [],
|
||||
toolbarSections,
|
||||
// Toolbar buttons and layout are referenced by customization name; the
|
||||
// cornerstone extension registers the defaults and `?customization=` modules
|
||||
// can extend them. onModeEnter resolves these names via the customization service.
|
||||
toolbarSections: 'cornerstone.toolbarSections',
|
||||
|
||||
/**
|
||||
* Lifecycle hooks
|
||||
@@ -364,7 +310,7 @@ export const modeInstance = {
|
||||
// general handler needs to come last. For this case, the dicomvideo must
|
||||
// come first to remove video transfer syntax before ohif uses images
|
||||
sopClassHandlers,
|
||||
toolbarButtons,
|
||||
toolbarButtons: 'cornerstone.toolbarButtons',
|
||||
enableSegmentationEdit: false,
|
||||
nonModeModalities: NON_IMAGE_MODALITIES,
|
||||
};
|
||||
@@ -389,4 +335,4 @@ export const mode = {
|
||||
};
|
||||
|
||||
export default mode;
|
||||
export { initToolGroups, toolbarButtons };
|
||||
export { initToolGroups };
|
||||
@@ -69,6 +69,7 @@ function initDefaultToolGroup(extensionManager, toolGroupService, commandsManage
|
||||
{ toolName: toolNames.Angle },
|
||||
{ toolName: toolNames.CobbAngle },
|
||||
{ toolName: toolNames.Magnify },
|
||||
{ toolName: toolNames.PlanarRotate },
|
||||
{ toolName: toolNames.CalibrationLine },
|
||||
{
|
||||
toolName: toolNames.PlanarFreehandContourSegmentation,
|
||||
|
||||
@@ -1,711 +0,0 @@
|
||||
import type { Button } from '@ohif/core/types';
|
||||
|
||||
import { EVENTS } from '@cornerstonejs/core';
|
||||
import { ViewportGridService } from '@ohif/core';
|
||||
import i18n from 'i18next';
|
||||
|
||||
const callbacks = (toolName: string) => [
|
||||
{
|
||||
commandName: 'setViewportForToolConfiguration',
|
||||
commandOptions: {
|
||||
toolName,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const setToolActiveToolbar = {
|
||||
commandName: 'setToolActiveToolbar',
|
||||
commandOptions: {
|
||||
toolGroupIds: ['default', 'mpr', 'SRToolGroup', 'volume3d'],
|
||||
},
|
||||
};
|
||||
|
||||
const toolbarButtons: Button[] = [
|
||||
// sections
|
||||
{
|
||||
id: 'MeasurementTools',
|
||||
uiType: 'ohif.toolButtonList',
|
||||
props: {
|
||||
buttonSection: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'MoreTools',
|
||||
uiType: 'ohif.toolButtonList',
|
||||
props: {
|
||||
buttonSection: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'AdvancedRenderingControls',
|
||||
uiType: 'ohif.advancedRenderingControls',
|
||||
props: {
|
||||
buttonSection: true,
|
||||
},
|
||||
},
|
||||
// tool defs
|
||||
{
|
||||
id: 'modalityLoadBadge',
|
||||
uiType: 'ohif.modalityLoadBadge',
|
||||
props: {
|
||||
icon: 'Status',
|
||||
label: i18n.t('Buttons:Status'),
|
||||
tooltip: i18n.t('Buttons:Status'),
|
||||
evaluate: {
|
||||
name: 'evaluate.modalityLoadBadge',
|
||||
hideWhenDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'navigationComponent',
|
||||
uiType: 'ohif.navigationComponent',
|
||||
props: {
|
||||
icon: 'Navigation',
|
||||
label: i18n.t('Buttons:Navigation'),
|
||||
tooltip: i18n.t('Buttons:Navigate between segments/measurements and manage their visibility'),
|
||||
evaluate: {
|
||||
name: 'evaluate.navigationComponent',
|
||||
hideWhenDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'trackingStatus',
|
||||
uiType: 'ohif.trackingStatus',
|
||||
props: {
|
||||
icon: 'TrackingStatus',
|
||||
label: i18n.t('Buttons:Tracking Status'),
|
||||
tooltip: i18n.t('Buttons:View and manage tracking status of measurements and annotations'),
|
||||
evaluate: {
|
||||
name: 'evaluate.trackingStatus',
|
||||
hideWhenDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'dataOverlayMenu',
|
||||
uiType: 'ohif.dataOverlayMenu',
|
||||
props: {
|
||||
icon: 'ViewportViews',
|
||||
label: i18n.t('Buttons:Data Overlay'),
|
||||
tooltip: i18n.t(
|
||||
'Buttons:Configure data overlay options and manage foreground/background display sets'
|
||||
),
|
||||
evaluate: 'evaluate.dataOverlayMenu',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'orientationMenu',
|
||||
uiType: 'ohif.orientationMenu',
|
||||
props: {
|
||||
icon: 'OrientationSwitch',
|
||||
label: i18n.t('Buttons:Orientation'),
|
||||
tooltip: i18n.t(
|
||||
'Buttons:Change viewport orientation between axial, sagittal, coronal and reformat planes'
|
||||
),
|
||||
evaluate: {
|
||||
name: 'evaluate.orientationMenu',
|
||||
// hideWhenDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'windowLevelMenuEmbedded',
|
||||
uiType: 'ohif.windowLevelMenuEmbedded',
|
||||
props: {
|
||||
icon: 'WindowLevel',
|
||||
label: i18n.t('Buttons:Window Level'),
|
||||
tooltip: i18n.t('Buttons:Adjust window/level presets and customize image contrast settings'),
|
||||
evaluate: {
|
||||
name: 'evaluate.windowLevelMenuEmbedded',
|
||||
hideWhenDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'windowLevelMenu',
|
||||
uiType: 'ohif.windowLevelMenu',
|
||||
props: {
|
||||
icon: 'WindowLevel',
|
||||
label: i18n.t('Buttons:Window Level'),
|
||||
tooltip: i18n.t('Buttons:Adjust window/level presets and customize image contrast settings'),
|
||||
evaluate: {
|
||||
name: 'evaluate.windowLevelMenu',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'voiManualControlMenu',
|
||||
uiType: 'ohif.voiManualControlMenu',
|
||||
props: {
|
||||
icon: 'WindowLevelAdvanced',
|
||||
label: i18n.t('Buttons:Advanced Window Level'),
|
||||
tooltip: i18n.t('Buttons:Advanced window/level settings with manual controls and presets'),
|
||||
evaluate: 'evaluate.voiManualControlMenu',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'thresholdMenu',
|
||||
uiType: 'ohif.thresholdMenu',
|
||||
props: {
|
||||
icon: 'Threshold',
|
||||
label: i18n.t('Buttons:Threshold'),
|
||||
tooltip: i18n.t('Buttons:Image threshold settings'),
|
||||
evaluate: {
|
||||
name: 'evaluate.thresholdMenu',
|
||||
hideWhenDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'opacityMenu',
|
||||
uiType: 'ohif.opacityMenu',
|
||||
props: {
|
||||
icon: 'Opacity',
|
||||
label: i18n.t('Buttons:Opacity'),
|
||||
tooltip: i18n.t('Buttons:Image opacity settings'),
|
||||
evaluate: {
|
||||
name: 'evaluate.opacityMenu',
|
||||
hideWhenDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'Colorbar',
|
||||
uiType: 'ohif.colorbar',
|
||||
props: {
|
||||
type: 'tool',
|
||||
label: i18n.t('Buttons:Colorbar'),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'Reset',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-reset',
|
||||
label: i18n.t('Buttons:Reset View'),
|
||||
tooltip: i18n.t('Buttons:Reset View'),
|
||||
commands: 'resetViewport',
|
||||
evaluate: 'evaluate.action',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'rotate-right',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-rotate-right',
|
||||
label: i18n.t('Buttons:Rotate Right'),
|
||||
tooltip: i18n.t('Buttons:Rotate +90'),
|
||||
commands: 'rotateViewportCW',
|
||||
evaluate: [
|
||||
'evaluate.action',
|
||||
{
|
||||
name: 'evaluate.viewport.supported',
|
||||
unsupportedViewportTypes: ['video'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'flipHorizontal',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-flip-horizontal',
|
||||
label: i18n.t('Buttons:Flip Horizontal'),
|
||||
tooltip: i18n.t('Buttons:Flip Horizontally'),
|
||||
commands: 'flipViewportHorizontal',
|
||||
evaluate: [
|
||||
'evaluate.viewportProperties.toggle',
|
||||
{
|
||||
name: 'evaluate.viewport.supported',
|
||||
unsupportedViewportTypes: ['video', 'volume3d'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'ImageSliceSync',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'link',
|
||||
label: i18n.t('Buttons:Image Slice Sync'),
|
||||
tooltip: i18n.t('Buttons:Enable position synchronization on stack viewports'),
|
||||
commands: {
|
||||
commandName: 'toggleSynchronizer',
|
||||
commandOptions: {
|
||||
type: 'imageSlice',
|
||||
},
|
||||
},
|
||||
listeners: {
|
||||
[EVENTS.VIEWPORT_NEW_IMAGE_SET]: {
|
||||
commandName: 'toggleImageSliceSync',
|
||||
commandOptions: { toggledState: true },
|
||||
},
|
||||
},
|
||||
evaluate: [
|
||||
'evaluate.cornerstone.synchronizer',
|
||||
{
|
||||
name: 'evaluate.viewport.supported',
|
||||
unsupportedViewportTypes: ['video', 'volume3d'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'ReferenceLines',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-referenceLines',
|
||||
label: i18n.t('Buttons:Reference Lines'),
|
||||
tooltip: i18n.t('Buttons:Show Reference Lines'),
|
||||
commands: 'toggleEnabledDisabledToolbar',
|
||||
listeners: {
|
||||
[ViewportGridService.EVENTS.ACTIVE_VIEWPORT_ID_CHANGED]: callbacks('ReferenceLines'),
|
||||
[ViewportGridService.EVENTS.VIEWPORTS_READY]: callbacks('ReferenceLines'),
|
||||
},
|
||||
evaluate: [
|
||||
'evaluate.cornerstoneTool.toggle',
|
||||
{
|
||||
name: 'evaluate.viewport.supported',
|
||||
unsupportedViewportTypes: ['video'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'ImageOverlayViewer',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'toggle-dicom-overlay',
|
||||
label: i18n.t('Buttons:Image Overlay'),
|
||||
tooltip: i18n.t('Buttons:Toggle Image Overlay'),
|
||||
commands: 'toggleEnabledDisabledToolbar',
|
||||
evaluate: [
|
||||
'evaluate.cornerstoneTool.toggle',
|
||||
{
|
||||
name: 'evaluate.viewport.supported',
|
||||
unsupportedViewportTypes: ['video'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'StackScroll',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-stack-scroll',
|
||||
label: i18n.t('Buttons:Stack Scroll'),
|
||||
tooltip: i18n.t('Buttons:Stack Scroll'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: 'evaluate.cornerstoneTool',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'invert',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-invert',
|
||||
label: i18n.t('Buttons:Invert'),
|
||||
tooltip: i18n.t('Buttons:Invert Colors'),
|
||||
commands: 'invertViewport',
|
||||
evaluate: [
|
||||
'evaluate.viewportProperties.toggle',
|
||||
{
|
||||
name: 'evaluate.viewport.supported',
|
||||
unsupportedViewportTypes: ['video'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'Probe',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-probe',
|
||||
label: i18n.t('Buttons:Probe'),
|
||||
tooltip: i18n.t('Buttons:Probe'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: 'evaluate.cornerstoneTool',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'Cine',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-cine',
|
||||
label: i18n.t('Buttons:Cine'),
|
||||
tooltip: i18n.t('Buttons:Cine'),
|
||||
commands: 'toggleCine',
|
||||
evaluate: [
|
||||
'evaluate.cine',
|
||||
{
|
||||
name: 'evaluate.viewport.supported',
|
||||
unsupportedViewportTypes: ['volume3d'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'Angle',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-angle',
|
||||
label: i18n.t('Buttons:Angle'),
|
||||
tooltip: i18n.t('Buttons:Angle'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: 'evaluate.cornerstoneTool',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'CobbAngle',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'icon-tool-cobb-angle',
|
||||
label: i18n.t('Buttons:Cobb Angle'),
|
||||
tooltip: i18n.t('Buttons:Cobb Angle'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: 'evaluate.cornerstoneTool',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'Magnify',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-magnify',
|
||||
label: i18n.t('Buttons:Zoom-in'),
|
||||
tooltip: i18n.t('Buttons:Zoom-in'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: [
|
||||
'evaluate.cornerstoneTool',
|
||||
{
|
||||
name: 'evaluate.viewport.supported',
|
||||
unsupportedViewportTypes: ['video'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'CalibrationLine',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-calibration',
|
||||
label: i18n.t('Buttons:Calibration'),
|
||||
tooltip: i18n.t('Buttons:Calibration Line'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: [
|
||||
'evaluate.cornerstoneTool',
|
||||
{
|
||||
name: 'evaluate.viewport.supported',
|
||||
unsupportedViewportTypes: ['video'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'TagBrowser',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'dicom-tag-browser',
|
||||
label: i18n.t('Buttons:Dicom Tag Browser'),
|
||||
tooltip: i18n.t('Buttons:Dicom Tag Browser'),
|
||||
commands: 'openDICOMTagViewer',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'AdvancedMagnify',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'icon-tool-loupe',
|
||||
label: i18n.t('Buttons:Magnify Probe'),
|
||||
tooltip: i18n.t('Buttons:Magnify Probe'),
|
||||
commands: 'toggleActiveDisabledToolbar',
|
||||
evaluate: [
|
||||
'evaluate.cornerstoneTool.toggle.ifStrictlyDisabled',
|
||||
{
|
||||
name: 'evaluate.viewport.supported',
|
||||
unsupportedViewportTypes: ['video'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'UltrasoundDirectionalTool',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'icon-tool-ultrasound-bidirectional',
|
||||
label: i18n.t('Buttons:Ultrasound Directional'),
|
||||
tooltip: i18n.t('Buttons:Ultrasound Directional'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: [
|
||||
'evaluate.cornerstoneTool',
|
||||
{
|
||||
name: 'evaluate.modality.supported',
|
||||
supportedModalities: ['US'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'WindowLevelRegion',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'icon-tool-window-region',
|
||||
label: i18n.t('Buttons:Window Level Region'),
|
||||
tooltip: i18n.t('Buttons:Window Level Region'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: [
|
||||
'evaluate.cornerstoneTool',
|
||||
{
|
||||
name: 'evaluate.viewport.supported',
|
||||
unsupportedViewportTypes: ['video'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'Length',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-length',
|
||||
label: i18n.t('Buttons:Length'),
|
||||
tooltip: i18n.t('Buttons:Length Tool'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: 'evaluate.cornerstoneTool',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'Bidirectional',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-bidirectional',
|
||||
label: i18n.t('Buttons:Bidirectional'),
|
||||
tooltip: i18n.t('Buttons:Bidirectional Tool'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: 'evaluate.cornerstoneTool',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'ArrowAnnotate',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-annotate',
|
||||
label: i18n.t('Buttons:Annotation'),
|
||||
tooltip: i18n.t('Buttons:Arrow Annotate'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: 'evaluate.cornerstoneTool',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'EllipticalROI',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-ellipse',
|
||||
label: i18n.t('Buttons:Ellipse'),
|
||||
tooltip: i18n.t('Buttons:Ellipse ROI'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: 'evaluate.cornerstoneTool',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'RectangleROI',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-rectangle',
|
||||
label: i18n.t('Buttons:Rectangle'),
|
||||
tooltip: i18n.t('Buttons:Rectangle ROI'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: 'evaluate.cornerstoneTool',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'CircleROI',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-circle',
|
||||
label: i18n.t('Buttons:Circle'),
|
||||
tooltip: i18n.t('Buttons:Circle Tool'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: 'evaluate.cornerstoneTool',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'PlanarFreehandROI',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'icon-tool-freehand-roi',
|
||||
label: i18n.t('Buttons:Freehand ROI'),
|
||||
tooltip: i18n.t('Buttons:Freehand ROI'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: 'evaluate.cornerstoneTool',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'SplineROI',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'icon-tool-spline-roi',
|
||||
label: i18n.t('Buttons:Spline ROI'),
|
||||
tooltip: i18n.t('Buttons:Spline ROI'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: 'evaluate.cornerstoneTool',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'LivewireContour',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'icon-tool-livewire',
|
||||
label: i18n.t('Buttons:Livewire tool'),
|
||||
tooltip: i18n.t('Buttons:Livewire tool'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: 'evaluate.cornerstoneTool',
|
||||
},
|
||||
},
|
||||
// Window Level
|
||||
{
|
||||
id: 'WindowLevel',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-window-level',
|
||||
label: i18n.t('Buttons:Window Level'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: [
|
||||
'evaluate.cornerstoneTool',
|
||||
{
|
||||
name: 'evaluate.viewport.supported',
|
||||
unsupportedViewportTypes: ['wholeSlide'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'Pan',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
type: 'tool',
|
||||
icon: 'tool-move',
|
||||
label: i18n.t('Buttons:Pan'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: 'evaluate.cornerstoneTool',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'Zoom',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
type: 'tool',
|
||||
icon: 'tool-zoom',
|
||||
label: i18n.t('Buttons:Zoom'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: 'evaluate.cornerstoneTool',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'TrackballRotate',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
type: 'tool',
|
||||
icon: 'tool-3d-rotate',
|
||||
label: i18n.t('Buttons:3D Rotate'),
|
||||
commands: setToolActiveToolbar,
|
||||
evaluate: {
|
||||
name: 'evaluate.cornerstoneTool',
|
||||
disabledText: i18n.t('Buttons:Select a 3D viewport to enable this tool'),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'Capture',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
icon: 'tool-capture',
|
||||
label: i18n.t('Buttons:Capture'),
|
||||
commands: 'showDownloadViewportModal',
|
||||
evaluate: [
|
||||
'evaluate.action',
|
||||
{
|
||||
name: 'evaluate.viewport.supported',
|
||||
unsupportedViewportTypes: ['video', 'wholeSlide'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'Layout',
|
||||
uiType: 'ohif.layoutSelector',
|
||||
props: {
|
||||
rows: 3,
|
||||
columns: 4,
|
||||
evaluate: 'evaluate.action',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'Crosshairs',
|
||||
uiType: 'ohif.toolButton',
|
||||
props: {
|
||||
type: 'tool',
|
||||
icon: 'tool-crosshair',
|
||||
label: i18n.t('Buttons:Crosshairs'),
|
||||
tooltip: i18n.t('Buttons:Click to toggle on or off'),
|
||||
commands: {
|
||||
commandName: 'toggleActiveDisabledToolbar',
|
||||
commandOptions: {
|
||||
toolGroupIds: ['mpr'],
|
||||
},
|
||||
},
|
||||
evaluate: {
|
||||
name: 'evaluate.cornerstoneTool.toggleWithModifier',
|
||||
disabledText: i18n.t('Buttons:Select an MPR viewport to enable this tool'),
|
||||
toggledOnIcon: 'tool-crosshair-checked',
|
||||
defaultIcon: 'tool-crosshair',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'SegmentLabelTool',
|
||||
uiType: 'ohif.toolBoxButton',
|
||||
props: {
|
||||
icon: 'tool-segment-label',
|
||||
label: i18n.t('Buttons:Segment Label Display'),
|
||||
tooltip: i18n.t(
|
||||
'Buttons:Click to show or hide segment labels when hovering with your mouse.'
|
||||
),
|
||||
commands: { commandName: 'toggleSegmentLabel' },
|
||||
evaluate: [
|
||||
'evaluate.cornerstoneTool.toggle',
|
||||
{
|
||||
name: 'evaluate.cornerstone.hasSegmentation',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
// {
|
||||
// id: 'Undo',
|
||||
// uiType: 'ohif.toolButton',
|
||||
// props: {
|
||||
// type: 'tool',
|
||||
// icon: 'prev-arrow',
|
||||
// label: 'Undo',
|
||||
// commands: {
|
||||
// commandName: 'undo',
|
||||
// },
|
||||
// evaluate: 'evaluate.action',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// id: 'Redo',
|
||||
// uiType: 'ohif.toolButton',
|
||||
// props: {
|
||||
// type: 'tool',
|
||||
// icon: 'next-arrow',
|
||||
// label: 'Redo',
|
||||
// commands: {
|
||||
// commandName: 'redo',
|
||||
// },
|
||||
// evaluate: 'evaluate.action',
|
||||
// },
|
||||
// },
|
||||
];
|
||||
|
||||
export default toolbarButtons;
|
||||
@@ -1,6 +1,6 @@
|
||||
import i18n from 'i18next';
|
||||
import { id } from './id';
|
||||
import { initToolGroups, toolbarButtons, cornerstone,
|
||||
import { initToolGroups, cornerstone,
|
||||
ohif,
|
||||
dicomsr,
|
||||
dicomvideo,
|
||||
@@ -73,4 +73,4 @@ const mode = {
|
||||
};
|
||||
|
||||
export default mode;
|
||||
export { initToolGroups, toolbarButtons };
|
||||
export { initToolGroups };
|
||||
Reference in new issue
Block a user