fix(bugs): Update dependencies and enhance UI components (#4478)
This commit is contained in:
parent
61e3a9cb52
commit
05d41c5206
@ -46,8 +46,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/adapters": "^2.1.17",
|
"@cornerstonejs/adapters": "^2.2.1",
|
||||||
"@cornerstonejs/core": "^2.1.17",
|
"@cornerstonejs/core": "^2.2.1",
|
||||||
"@kitware/vtk.js": "32.1.0",
|
"@kitware/vtk.js": "32.1.0",
|
||||||
"react-color": "^2.19.3"
|
"react-color": "^2.19.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,8 +46,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/adapters": "^2.1.17",
|
"@cornerstonejs/adapters": "^2.2.1",
|
||||||
"@cornerstonejs/core": "^2.1.17",
|
"@cornerstonejs/core": "^2.2.1",
|
||||||
"@kitware/vtk.js": "32.1.0",
|
"@kitware/vtk.js": "32.1.0",
|
||||||
"react-color": "^2.19.3"
|
"react-color": "^2.19.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import { LoadingIndicatorTotalPercent, useViewportGrid, ViewportActionArrows } f
|
|||||||
import createSEGToolGroupAndAddTools from '../utils/initSEGToolGroup';
|
import createSEGToolGroupAndAddTools from '../utils/initSEGToolGroup';
|
||||||
import promptHydrateSEG from '../utils/promptHydrateSEG';
|
import promptHydrateSEG from '../utils/promptHydrateSEG';
|
||||||
import _getStatusComponent from './_getStatusComponent';
|
import _getStatusComponent from './_getStatusComponent';
|
||||||
import { useSegmentationPresentationStore } from '@ohif/extension-cornerstone';
|
|
||||||
import { SegmentationRepresentations } from '@cornerstonejs/tools/enums';
|
import { SegmentationRepresentations } from '@cornerstonejs/tools/enums';
|
||||||
|
|
||||||
const SEG_TOOLGROUP_BASE_NAME = 'SEGToolGroup';
|
const SEG_TOOLGROUP_BASE_NAME = 'SEGToolGroup';
|
||||||
@ -251,6 +250,14 @@ function OHIFCornerstoneSEGViewport(props: withAppTypes) {
|
|||||||
if (toolGroup) {
|
if (toolGroup) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// keep the already stored segmentationPresentation for this viewport in memory
|
||||||
|
// so that we can restore it after hydrating the SEG
|
||||||
|
commandsManager.runCommand('updateStoredSegmentationPresentation', {
|
||||||
|
displaySet: segDisplaySet,
|
||||||
|
type: SegmentationRepresentations.Labelmap,
|
||||||
|
});
|
||||||
|
|
||||||
// always start fresh for this viewport since it is special type of viewport
|
// always start fresh for this viewport since it is special type of viewport
|
||||||
// that should only show one segmentation at a time.
|
// that should only show one segmentation at a time.
|
||||||
segmentationService.clearSegmentationRepresentations(viewportId);
|
segmentationService.clearSegmentationRepresentations(viewportId);
|
||||||
|
|||||||
@ -46,9 +46,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/adapters": "^2.1.17",
|
"@cornerstonejs/adapters": "^2.2.1",
|
||||||
"@cornerstonejs/core": "^2.1.17",
|
"@cornerstonejs/core": "^2.2.1",
|
||||||
"@cornerstonejs/tools": "^2.1.17",
|
"@cornerstonejs/tools": "^2.2.1",
|
||||||
"classnames": "^2.3.2"
|
"classnames": "^2.3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,8 +42,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/core": "^2.1.17",
|
"@cornerstonejs/core": "^2.2.1",
|
||||||
"@cornerstonejs/tools": "^2.1.17",
|
"@cornerstonejs/tools": "^2.2.1",
|
||||||
"classnames": "^2.3.2"
|
"classnames": "^2.3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,7 +38,7 @@
|
|||||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||||
"@cornerstonejs/dicom-image-loader": "^2.1.17",
|
"@cornerstonejs/dicom-image-loader": "^2.2.1",
|
||||||
"@icr/polyseg-wasm": "^0.4.0",
|
"@icr/polyseg-wasm": "^0.4.0",
|
||||||
"@ohif/core": "3.9.0-beta.109",
|
"@ohif/core": "3.9.0-beta.109",
|
||||||
"@ohif/ui": "3.9.0-beta.109",
|
"@ohif/ui": "3.9.0-beta.109",
|
||||||
@ -55,9 +55,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/adapters": "^2.1.17",
|
"@cornerstonejs/adapters": "^2.2.1",
|
||||||
"@cornerstonejs/core": "^2.1.17",
|
"@cornerstonejs/core": "^2.2.1",
|
||||||
"@cornerstonejs/tools": "^2.1.17",
|
"@cornerstonejs/tools": "^2.2.1",
|
||||||
"@icr/polyseg-wasm": "^0.4.0",
|
"@icr/polyseg-wasm": "^0.4.0",
|
||||||
"@kitware/vtk.js": "32.1.0",
|
"@kitware/vtk.js": "32.1.0",
|
||||||
"html2canvas": "^1.4.1",
|
"html2canvas": "^1.4.1",
|
||||||
|
|||||||
@ -111,16 +111,14 @@ function commandsModule({
|
|||||||
commandsManager.run(options, optionsToUse);
|
commandsManager.run(options, optionsToUse);
|
||||||
},
|
},
|
||||||
updateStoredSegmentationPresentation: ({ displaySet, type }) => {
|
updateStoredSegmentationPresentation: ({ displaySet, type }) => {
|
||||||
const { setSegmentationPresentation } = useSegmentationPresentationStore.getState();
|
const { addSegmentationPresentationItem } = useSegmentationPresentationStore.getState();
|
||||||
|
|
||||||
const referencedDisplaySetInstanceUID = displaySet.referencedDisplaySetInstanceUID;
|
const referencedDisplaySetInstanceUID = displaySet.referencedDisplaySetInstanceUID;
|
||||||
setSegmentationPresentation(referencedDisplaySetInstanceUID, [
|
addSegmentationPresentationItem(referencedDisplaySetInstanceUID, {
|
||||||
{
|
segmentationId: displaySet.displaySetInstanceUID,
|
||||||
segmentationId: displaySet.displaySetInstanceUID,
|
hydrated: true,
|
||||||
hydrated: true,
|
type,
|
||||||
type,
|
});
|
||||||
},
|
|
||||||
]);
|
|
||||||
},
|
},
|
||||||
updateStoredPositionPresentation: ({ viewportId, displaySetInstanceUID }) => {
|
updateStoredPositionPresentation: ({ viewportId, displaySetInstanceUID }) => {
|
||||||
const presentations = cornerstoneViewportService.getPresentations(viewportId);
|
const presentations = cornerstoneViewportService.getPresentations(viewportId);
|
||||||
@ -1043,7 +1041,7 @@ function commandsModule({
|
|||||||
* @param props.key - The style key to set
|
* @param props.key - The style key to set
|
||||||
* @param props.value - The style value
|
* @param props.value - The style value
|
||||||
*/
|
*/
|
||||||
setSegmentationStyleCommand: ({ segmentationId, type, key, value }) => {
|
setSegmentationStyleCommand: ({ type, key, value }) => {
|
||||||
const { segmentationService } = servicesManager.services;
|
const { segmentationService } = servicesManager.services;
|
||||||
segmentationService.setStyle({ type }, { [key]: value });
|
segmentationService.setStyle({ type }, { [key]: value });
|
||||||
},
|
},
|
||||||
@ -1150,12 +1148,17 @@ function commandsModule({
|
|||||||
const segment = segmentation.segments[segmentIndex];
|
const segment = segmentation.segments[segmentIndex];
|
||||||
const { label } = segment;
|
const { label } = segment;
|
||||||
|
|
||||||
callInputDialog(uiDialogService, label, (label, actionId) => {
|
const callback = (label, actionId) => {
|
||||||
if (label === '') {
|
if (label === '') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
segmentationService.setSegmentLabel(segmentationId, segmentIndex, label);
|
segmentationService.setSegmentLabel(segmentationId, segmentIndex, label);
|
||||||
|
};
|
||||||
|
|
||||||
|
callInputDialog(uiDialogService, label, callback, false, {
|
||||||
|
dialogTitle: 'Edit Segment Label',
|
||||||
|
inputLabel: 'Enter new label',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1169,12 +1172,17 @@ function commandsModule({
|
|||||||
|
|
||||||
const { label } = segmentation;
|
const { label } = segmentation;
|
||||||
|
|
||||||
callInputDialog(uiDialogService, label, (label, actionId) => {
|
const callback = (label, actionId) => {
|
||||||
if (label === '') {
|
if (label === '') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
segmentationService.addOrUpdateSegmentation({ segmentationId, label });
|
segmentationService.addOrUpdateSegmentation({ segmentationId, label });
|
||||||
|
};
|
||||||
|
|
||||||
|
callInputDialog(uiDialogService, label, callback, false, {
|
||||||
|
dialogTitle: 'Edit Segmentation Label',
|
||||||
|
inputLabel: 'Enter new label',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -6,8 +6,6 @@ import { metaData } from '@cornerstonejs/core';
|
|||||||
export default function PanelSegmentation({
|
export default function PanelSegmentation({
|
||||||
servicesManager,
|
servicesManager,
|
||||||
commandsManager,
|
commandsManager,
|
||||||
extensionManager,
|
|
||||||
configuration,
|
|
||||||
children,
|
children,
|
||||||
}: withAppTypes) {
|
}: withAppTypes) {
|
||||||
const { customizationService, viewportGridService, displaySetService } = servicesManager.services;
|
const { customizationService, viewportGridService, displaySetService } = servicesManager.services;
|
||||||
@ -91,23 +89,23 @@ export default function PanelSegmentation({
|
|||||||
commandsManager.run('deleteSegmentation', { segmentationId });
|
commandsManager.run('deleteSegmentation', { segmentationId });
|
||||||
},
|
},
|
||||||
|
|
||||||
setFillAlpha: (type, value) => {
|
setFillAlpha: ({ type }, value) => {
|
||||||
commandsManager.run('setFillAlpha', { type, value });
|
commandsManager.run('setFillAlpha', { type, value });
|
||||||
},
|
},
|
||||||
|
|
||||||
setOutlineWidth: (type, value) => {
|
setOutlineWidth: ({ type }, value) => {
|
||||||
commandsManager.run('setOutlineWidth', { type, value });
|
commandsManager.run('setOutlineWidth', { type, value });
|
||||||
},
|
},
|
||||||
|
|
||||||
setRenderFill: (type, value) => {
|
setRenderFill: ({ type }, value) => {
|
||||||
commandsManager.run('setRenderFill', { type, value });
|
commandsManager.run('setRenderFill', { type, value });
|
||||||
},
|
},
|
||||||
|
|
||||||
setRenderOutline: (type, value) => {
|
setRenderOutline: ({ type }, value) => {
|
||||||
commandsManager.run('setRenderOutline', { type, value });
|
commandsManager.run('setRenderOutline', { type, value });
|
||||||
},
|
},
|
||||||
|
|
||||||
setFillAlphaInactive: (type, value) => {
|
setFillAlphaInactive: ({ type }, value) => {
|
||||||
commandsManager.run('setFillAlphaInactive', { type, value });
|
commandsManager.run('setFillAlphaInactive', { type, value });
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -152,6 +150,14 @@ export default function PanelSegmentation({
|
|||||||
const exportOptions = segmentationsWithRepresentations.map(({ segmentation }) => {
|
const exportOptions = segmentationsWithRepresentations.map(({ segmentation }) => {
|
||||||
const { representationData, segmentationId } = segmentation;
|
const { representationData, segmentationId } = segmentation;
|
||||||
const { Labelmap } = representationData;
|
const { Labelmap } = representationData;
|
||||||
|
|
||||||
|
if (!Labelmap) {
|
||||||
|
return {
|
||||||
|
segmentationId,
|
||||||
|
isExportable: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const referencedImageIds = Labelmap.referencedImageIds;
|
const referencedImageIds = Labelmap.referencedImageIds;
|
||||||
const firstImageId = referencedImageIds[0];
|
const firstImageId = referencedImageIds[0];
|
||||||
|
|
||||||
|
|||||||
@ -100,10 +100,16 @@ class SegmentationService extends PubSubService {
|
|||||||
this._segmentationIdToColorLUTIndexMap = new Map();
|
this._segmentationIdToColorLUTIndexMap = new Map();
|
||||||
|
|
||||||
this.servicesManager = servicesManager;
|
this.servicesManager = servicesManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public onModeEnter(): void {
|
||||||
this._initSegmentationService();
|
this._initSegmentationService();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onModeExit(): void {
|
||||||
|
this.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a segmentation by its ID.
|
* Retrieves a segmentation by its ID.
|
||||||
*
|
*
|
||||||
@ -1386,7 +1392,11 @@ class SegmentationService extends PubSubService {
|
|||||||
const frameOfReferenceUID = viewport.getFrameOfReferenceUID();
|
const frameOfReferenceUID = viewport.getFrameOfReferenceUID();
|
||||||
const segImage = cache.getImage(imageIds[0]);
|
const segImage = cache.getImage(imageIds[0]);
|
||||||
|
|
||||||
if (segImage?.FrameOfReferenceUID === frameOfReferenceUID) {
|
if (
|
||||||
|
segImage?.FrameOfReferenceUID &&
|
||||||
|
frameOfReferenceUID &&
|
||||||
|
segImage.FrameOfReferenceUID === frameOfReferenceUID
|
||||||
|
) {
|
||||||
const isConverted = await this.convertStackToVolumeViewport(viewport);
|
const isConverted = await this.convertStackToVolumeViewport(viewport);
|
||||||
triggerSegmentationRepresentationModified(
|
triggerSegmentationRepresentationModified(
|
||||||
viewportId,
|
viewportId,
|
||||||
|
|||||||
@ -763,6 +763,10 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!volumesNotLoaded.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// This returns the async continuation only
|
// This returns the async continuation only
|
||||||
return this.setVolumesForViewport(viewport, volumeInputArray, presentations);
|
return this.setVolumesForViewport(viewport, volumeInputArray, presentations);
|
||||||
}
|
}
|
||||||
@ -1114,8 +1118,8 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
|||||||
|
|
||||||
const { segmentationService } = this.servicesManager.services;
|
const { segmentationService } = this.servicesManager.services;
|
||||||
|
|
||||||
segmentationPresentation.forEach((presentation: SegmentationPresentationItem) => {
|
segmentationPresentation.forEach((presentationItem: SegmentationPresentationItem) => {
|
||||||
const { segmentationId, type, hydrated } = presentation;
|
const { segmentationId, type, hydrated } = presentationItem;
|
||||||
|
|
||||||
if (hydrated) {
|
if (hydrated) {
|
||||||
segmentationService.addSegmentationRepresentation(viewport.id, {
|
segmentationService.addSegmentationRepresentation(viewport.id, {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { devtools } from 'zustand/middleware';
|
import { devtools } from 'zustand/middleware';
|
||||||
import { SegmentationPresentation } from '../types/Presentation';
|
import { SegmentationPresentation, SegmentationPresentationItem } from '../types/Presentation';
|
||||||
import { JOIN_STR } from './presentationUtils';
|
import { JOIN_STR } from './presentationUtils';
|
||||||
import { getViewportOrientationFromImageOrientationPatient } from '../utils/getViewportOrientationFromImageOrientationPatient';
|
import { getViewportOrientationFromImageOrientationPatient } from '../utils/getViewportOrientationFromImageOrientationPatient';
|
||||||
|
|
||||||
@ -62,10 +62,9 @@ type SegmentationPresentationStore = {
|
|||||||
* @param segmentationPresentation - The `SegmentationPresentation` to add.
|
* @param segmentationPresentation - The `SegmentationPresentation` to add.
|
||||||
* @param servicesManager - The services manager instance.
|
* @param servicesManager - The services manager instance.
|
||||||
*/
|
*/
|
||||||
addSegmentationPresentation: (
|
addSegmentationPresentationItem: (
|
||||||
presentationId: string,
|
presentationId: string,
|
||||||
segmentationPresentation: SegmentationPresentation,
|
segmentationPresentationItem: SegmentationPresentationItem
|
||||||
{ servicesManager }: { servicesManager: AppTypes.ServicesManager }
|
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -183,33 +182,52 @@ const createSegmentationPresentationStore = set => ({
|
|||||||
set({ segmentationPresentationStore: {} }, false, 'clearSegmentationPresentationStore'),
|
set({ segmentationPresentationStore: {} }, false, 'clearSegmentationPresentationStore'),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new segmentation presentation to the store.
|
* Adds a new segmentation presentation item to the store.
|
||||||
|
*
|
||||||
|
* segmentationPresentationItem: {
|
||||||
|
* segmentationId: string;
|
||||||
|
* type: SegmentationRepresentations;
|
||||||
|
* hydrated: boolean | null;
|
||||||
|
* config?: unknown;
|
||||||
|
* }
|
||||||
*/
|
*/
|
||||||
addSegmentationPresentation: (
|
addSegmentationPresentationItem: (
|
||||||
presentationId: string,
|
presentationId: string,
|
||||||
segmentationPresentation: SegmentationPresentation,
|
segmentationPresentationItem: SegmentationPresentationItem
|
||||||
{ servicesManager }: { servicesManager: AppTypes.ServicesManager }
|
|
||||||
) =>
|
) =>
|
||||||
set(
|
set(
|
||||||
state => ({
|
state => ({
|
||||||
segmentationPresentationStore: {
|
segmentationPresentationStore: {
|
||||||
...state.segmentationPresentationStore,
|
...state.segmentationPresentationStore,
|
||||||
[presentationId]: segmentationPresentation,
|
[presentationId]: [
|
||||||
|
...(state.segmentationPresentationStore[presentationId] || []),
|
||||||
|
segmentationPresentationItem,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
false,
|
false,
|
||||||
'addSegmentationPresentation'
|
'addSegmentationPresentationItem'
|
||||||
),
|
),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the segmentation presentation for a given presentation ID.
|
* Sets the segmentation presentation for a given presentation ID. A segmentation
|
||||||
|
* presentation is an array of SegmentationPresentationItem.
|
||||||
|
*
|
||||||
|
* segmentationPresentationItem: {
|
||||||
|
* segmentationId: string;
|
||||||
|
* type: SegmentationRepresentations;
|
||||||
|
* hydrated: boolean | null;
|
||||||
|
* config?: unknown;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* segmentationPresentation: SegmentationPresentationItem[]
|
||||||
*/
|
*/
|
||||||
setSegmentationPresentation: (presentationId: string, value: SegmentationPresentation) =>
|
setSegmentationPresentation: (presentationId: string, values: SegmentationPresentation) =>
|
||||||
set(
|
set(
|
||||||
state => ({
|
state => ({
|
||||||
segmentationPresentationStore: {
|
segmentationPresentationStore: {
|
||||||
...state.segmentationPresentationStore,
|
...state.segmentationPresentationStore,
|
||||||
[presentationId]: value,
|
[presentationId]: values,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
false,
|
false,
|
||||||
|
|||||||
@ -4,9 +4,9 @@ import getDisplayUnit from './getDisplayUnit';
|
|||||||
export const getStatisticDisplayString = (numbers, unit, key) => {
|
export const getStatisticDisplayString = (numbers, unit, key) => {
|
||||||
if (Array.isArray(numbers) && numbers.length > 0) {
|
if (Array.isArray(numbers) && numbers.length > 0) {
|
||||||
const results = numbers.map(number => utils.roundNumber(number, 2));
|
const results = numbers.map(number => utils.roundNumber(number, 2));
|
||||||
return `${key.charAt(0).toUpperCase() + key.slice(1)}: ${results.join(', ')} <small>${getDisplayUnit(unit)}</small>`;
|
return `${key.charAt(0).toUpperCase() + key.slice(1)}: ${results.join(', ')} ${getDisplayUnit(unit)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = utils.roundNumber(numbers, 2);
|
const result = utils.roundNumber(numbers, 2);
|
||||||
return `${key.charAt(0).toUpperCase() + key.slice(1)}: ${result} <small>${getDisplayUnit(unit)}</small>`;
|
return `${key.charAt(0).toUpperCase() + key.slice(1)}: ${result} ${getDisplayUnit(unit)}`;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -23,16 +23,26 @@ const SidePanelWithServices = ({
|
|||||||
|
|
||||||
// Tracks whether this SidePanel has been opened at least once since this SidePanel was inserted into the DOM.
|
// Tracks whether this SidePanel has been opened at least once since this SidePanel was inserted into the DOM.
|
||||||
// Thus going to the Study List page and back to the viewer resets this flag for a SidePanel.
|
// Thus going to the Study List page and back to the viewer resets this flag for a SidePanel.
|
||||||
const [hasBeenOpened, setHasBeenOpened] = useState(false);
|
const [sidePanelOpen, setSidePanelOpen] = useState(activeTabIndexProp !== null);
|
||||||
const [activeTabIndex, setActiveTabIndex] = useState(activeTabIndexProp);
|
const [activeTabIndex, setActiveTabIndex] = useState(activeTabIndexProp);
|
||||||
const [tabs, setTabs] = useState(tabsProp ?? panelService.getPanels(side));
|
const [tabs, setTabs] = useState(tabsProp ?? panelService.getPanels(side));
|
||||||
|
|
||||||
const handleSidePanelOpen = useCallback(() => {
|
|
||||||
setHasBeenOpened(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleActiveTabIndexChange = useCallback(({ activeTabIndex }) => {
|
const handleActiveTabIndexChange = useCallback(({ activeTabIndex }) => {
|
||||||
setActiveTabIndex(activeTabIndex);
|
setActiveTabIndex(activeTabIndex);
|
||||||
|
setSidePanelOpen(activeTabIndex !== null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleOpen = useCallback(() => {
|
||||||
|
setSidePanelOpen(true);
|
||||||
|
// If panel is being opened but no tab is active, set first tab as active
|
||||||
|
if (activeTabIndex === null && tabs.length > 0) {
|
||||||
|
setActiveTabIndex(0);
|
||||||
|
}
|
||||||
|
}, [activeTabIndex, tabs]);
|
||||||
|
|
||||||
|
const handleClose = useCallback(() => {
|
||||||
|
setSidePanelOpen(false);
|
||||||
|
setActiveTabIndex(null);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
/** update the active tab index from outside */
|
/** update the active tab index from outside */
|
||||||
@ -61,7 +71,7 @@ const SidePanelWithServices = ({
|
|||||||
const activatePanelSubscription = panelService.subscribe(
|
const activatePanelSubscription = panelService.subscribe(
|
||||||
panelService.EVENTS.ACTIVATE_PANEL,
|
panelService.EVENTS.ACTIVATE_PANEL,
|
||||||
(activatePanelEvent: Types.ActivatePanelEvent) => {
|
(activatePanelEvent: Types.ActivatePanelEvent) => {
|
||||||
if (!hasBeenOpened || activatePanelEvent.forceActive) {
|
if (sidePanelOpen || activatePanelEvent.forceActive) {
|
||||||
const tabIndex = tabs.findIndex(tab => tab.id === activatePanelEvent.panelId);
|
const tabIndex = tabs.findIndex(tab => tab.id === activatePanelEvent.panelId);
|
||||||
if (tabIndex !== -1) {
|
if (tabIndex !== -1) {
|
||||||
setActiveTabIndex(tabIndex);
|
setActiveTabIndex(tabIndex);
|
||||||
@ -73,7 +83,7 @@ const SidePanelWithServices = ({
|
|||||||
return () => {
|
return () => {
|
||||||
activatePanelSubscription.unsubscribe();
|
activatePanelSubscription.unsubscribe();
|
||||||
};
|
};
|
||||||
}, [tabs, hasBeenOpened, panelService]);
|
}, [tabs, sidePanelOpen, panelService]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SidePanel
|
<SidePanel
|
||||||
@ -81,10 +91,11 @@ const SidePanelWithServices = ({
|
|||||||
side={side}
|
side={side}
|
||||||
tabs={tabs}
|
tabs={tabs}
|
||||||
activeTabIndex={activeTabIndex}
|
activeTabIndex={activeTabIndex}
|
||||||
onOpen={handleSidePanelOpen}
|
onOpen={handleOpen}
|
||||||
|
onClose={handleClose}
|
||||||
onActiveTabIndexChange={handleActiveTabIndexChange}
|
onActiveTabIndexChange={handleActiveTabIndexChange}
|
||||||
expandedWidth={expandedWidth}
|
expandedWidth={expandedWidth}
|
||||||
></SidePanel>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -32,8 +32,8 @@
|
|||||||
"start": "yarn run dev"
|
"start": "yarn run dev"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@cornerstonejs/core": "^2.1.17",
|
"@cornerstonejs/core": "^2.2.1",
|
||||||
"@cornerstonejs/tools": "^2.1.17",
|
"@cornerstonejs/tools": "^2.2.1",
|
||||||
"@ohif/core": "3.9.0-beta.109",
|
"@ohif/core": "3.9.0-beta.109",
|
||||||
"@ohif/extension-cornerstone-dicom-sr": "3.9.0-beta.109",
|
"@ohif/extension-cornerstone-dicom-sr": "3.9.0-beta.109",
|
||||||
"@ohif/extension-default": "3.9.0-beta.109",
|
"@ohif/extension-default": "3.9.0-beta.109",
|
||||||
|
|||||||
@ -98,6 +98,9 @@ function TrackedCornerstoneViewport(
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isTracked) {
|
if (isTracked) {
|
||||||
annotation.config.style.setViewportToolStyles(viewportId, {
|
annotation.config.style.setViewportToolStyles(viewportId, {
|
||||||
|
ReferenceLines: {
|
||||||
|
lineDash: '4,4',
|
||||||
|
},
|
||||||
global: {
|
global: {
|
||||||
lineDash: '',
|
lineDash: '',
|
||||||
},
|
},
|
||||||
|
|||||||
@ -140,7 +140,13 @@ const toolbarButtons: Button[] = [
|
|||||||
context: 'CORNERSTONE',
|
context: 'CORNERSTONE',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
evaluate: 'evaluate.action',
|
evaluate: [
|
||||||
|
'evaluate.action',
|
||||||
|
{
|
||||||
|
name: 'evaluate.viewport.supported',
|
||||||
|
unsupportedViewportTypes: ['video', 'wholeSlide'],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -213,7 +213,13 @@ const toolbarButtons: Button[] = [
|
|||||||
icon: 'tool-capture',
|
icon: 'tool-capture',
|
||||||
label: 'Capture',
|
label: 'Capture',
|
||||||
commands: 'showDownloadViewportModal',
|
commands: 'showDownloadViewportModal',
|
||||||
evaluate: 'evaluate.action',
|
evaluate: [
|
||||||
|
'evaluate.action',
|
||||||
|
{
|
||||||
|
name: 'evaluate.viewport.supported',
|
||||||
|
unsupportedViewportTypes: ['video', 'wholeSlide'],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -85,8 +85,14 @@ function modeFactory({ modeConfiguration }) {
|
|||||||
* Lifecycle hooks
|
* Lifecycle hooks
|
||||||
*/
|
*/
|
||||||
onModeEnter: function ({ servicesManager, extensionManager, commandsManager }: withAppTypes) {
|
onModeEnter: function ({ servicesManager, extensionManager, commandsManager }: withAppTypes) {
|
||||||
const { measurementService, toolbarService, toolGroupService, customizationService } =
|
const {
|
||||||
servicesManager.services;
|
measurementService,
|
||||||
|
toolbarService,
|
||||||
|
toolGroupService,
|
||||||
|
customizationService,
|
||||||
|
panelService,
|
||||||
|
segmentationService,
|
||||||
|
} = servicesManager.services;
|
||||||
|
|
||||||
measurementService.clearMeasurements();
|
measurementService.clearMeasurements();
|
||||||
|
|
||||||
@ -110,25 +116,23 @@ function modeFactory({ modeConfiguration }) {
|
|||||||
|
|
||||||
// // ActivatePanel event trigger for when a segmentation or measurement is added.
|
// // ActivatePanel event trigger for when a segmentation or measurement is added.
|
||||||
// // Do not force activation so as to respect the state the user may have left the UI in.
|
// // Do not force activation so as to respect the state the user may have left the UI in.
|
||||||
// _activatePanelTriggersSubscriptions = [
|
_activatePanelTriggersSubscriptions = [
|
||||||
// ...panelService.addActivatePanelTriggers(dicomSeg.panel, [
|
...panelService.addActivatePanelTriggers(cornerstone.segmentation, [
|
||||||
// {
|
{
|
||||||
// sourcePubSubService: segmentationService,
|
sourcePubSubService: segmentationService,
|
||||||
// sourceEvents: [
|
sourceEvents: [segmentationService.EVENTS.SEGMENTATION_ADDED],
|
||||||
// segmentationService.EVENTS.SEGMENTATION_PIXEL_DATA_CREATED,
|
},
|
||||||
// ],
|
]),
|
||||||
// },
|
...panelService.addActivatePanelTriggers(tracked.measurements, [
|
||||||
// ]),
|
{
|
||||||
// ...panelService.addActivatePanelTriggers(tracked.measurements, [
|
sourcePubSubService: measurementService,
|
||||||
// {
|
sourceEvents: [
|
||||||
// sourcePubSubService: measurementService,
|
measurementService.EVENTS.MEASUREMENT_ADDED,
|
||||||
// sourceEvents: [
|
measurementService.EVENTS.RAW_MEASUREMENT_ADDED,
|
||||||
// measurementService.EVENTS.MEASUREMENT_ADDED,
|
],
|
||||||
// measurementService.EVENTS.RAW_MEASUREMENT_ADDED,
|
},
|
||||||
// ],
|
]),
|
||||||
// },
|
];
|
||||||
// ]),
|
|
||||||
// ];
|
|
||||||
},
|
},
|
||||||
onModeExit: ({ servicesManager }: withAppTypes) => {
|
onModeExit: ({ servicesManager }: withAppTypes) => {
|
||||||
const {
|
const {
|
||||||
|
|||||||
@ -172,7 +172,7 @@ const toolbarButtons: Button[] = [
|
|||||||
'evaluate.action',
|
'evaluate.action',
|
||||||
{
|
{
|
||||||
name: 'evaluate.viewport.supported',
|
name: 'evaluate.viewport.supported',
|
||||||
unsupportedViewportTypes: ['video'],
|
unsupportedViewportTypes: ['video', 'wholeSlide'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -114,8 +114,7 @@ function modeFactory({ modeConfiguration }) {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
extensions: extensionDependencies,
|
extensions: extensionDependencies,
|
||||||
hangingProtocol: ['default'],
|
hangingProtocol: 'default',
|
||||||
|
|
||||||
sopClassHandlers: [
|
sopClassHandlers: [
|
||||||
'@ohif/extension-cornerstone.sopClassHandlerModule.DicomMicroscopySopClassHandler',
|
'@ohif/extension-cornerstone.sopClassHandlerModule.DicomMicroscopySopClassHandler',
|
||||||
'@ohif/extension-dicom-microscopy.sopClassHandlerModule.DicomMicroscopySRSopClassHandler',
|
'@ohif/extension-dicom-microscopy.sopClassHandlerModule.DicomMicroscopySRSopClassHandler',
|
||||||
|
|||||||
@ -114,7 +114,13 @@ const toolbarButtons = [
|
|||||||
icon: 'tool-capture',
|
icon: 'tool-capture',
|
||||||
label: 'Capture',
|
label: 'Capture',
|
||||||
commands: 'showDownloadViewportModal',
|
commands: 'showDownloadViewportModal',
|
||||||
evaluate: 'evaluate.action',
|
evaluate: [
|
||||||
|
'evaluate.action',
|
||||||
|
{
|
||||||
|
name: 'evaluate.viewport.supported',
|
||||||
|
unsupportedViewportTypes: ['video', 'wholeSlide'],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -133,7 +133,7 @@ function modeFactory({ modeConfiguration }) {
|
|||||||
props: {
|
props: {
|
||||||
leftPanels: [ohif.leftPanel],
|
leftPanels: [ohif.leftPanel],
|
||||||
rightPanels: [cornerstone.panelTool],
|
rightPanels: [cornerstone.panelTool],
|
||||||
leftPanelClosed: true,
|
// leftPanelClosed: true,
|
||||||
viewports: [
|
viewports: [
|
||||||
{
|
{
|
||||||
namespace: cornerstone.viewport,
|
namespace: cornerstone.viewport,
|
||||||
|
|||||||
@ -69,7 +69,13 @@ const toolbarButtons: Button[] = [
|
|||||||
icon: 'tool-capture',
|
icon: 'tool-capture',
|
||||||
label: 'Capture',
|
label: 'Capture',
|
||||||
commands: 'showDownloadViewportModal',
|
commands: 'showDownloadViewportModal',
|
||||||
evaluate: 'evaluate.action',
|
evaluate: [
|
||||||
|
'evaluate.action',
|
||||||
|
{
|
||||||
|
name: 'evaluate.viewport.supported',
|
||||||
|
unsupportedViewportTypes: ['video', 'wholeSlide'],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -53,7 +53,7 @@
|
|||||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||||
"@cornerstonejs/dicom-image-loader": "^2.1.17",
|
"@cornerstonejs/dicom-image-loader": "^2.2.1",
|
||||||
"@emotion/serialize": "^1.1.3",
|
"@emotion/serialize": "^1.1.3",
|
||||||
"@ohif/core": "3.9.0-beta.109",
|
"@ohif/core": "3.9.0-beta.109",
|
||||||
"@ohif/extension-cornerstone": "3.9.0-beta.109",
|
"@ohif/extension-cornerstone": "3.9.0-beta.109",
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||||
"@cornerstonejs/dicom-image-loader": "^2.1.17",
|
"@cornerstonejs/dicom-image-loader": "^2.2.1",
|
||||||
"@ohif/ui": "3.9.0-beta.109",
|
"@ohif/ui": "3.9.0-beta.109",
|
||||||
"cornerstone-math": "0.1.9",
|
"cornerstone-math": "0.1.9",
|
||||||
"dicom-parser": "^1.8.21"
|
"dicom-parser": "^1.8.21"
|
||||||
|
|||||||
@ -165,6 +165,10 @@ export default class CustomizationService extends PubSubService {
|
|||||||
this.modeCustomizations.clear();
|
this.modeCustomizations.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onModeExit(): void {
|
||||||
|
this.onModeEnter();
|
||||||
|
}
|
||||||
|
|
||||||
public getModeCustomizations(): Map<string, Customization> {
|
public getModeCustomizations(): Map<string, Customization> {
|
||||||
return this.modeCustomizations;
|
return this.modeCustomizations;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,15 +9,20 @@ const generateAcceptHeader = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
let acceptHeader = ['multipart/related'];
|
let acceptHeader = ['multipart/related'];
|
||||||
|
let hasTransferSyntax = false;
|
||||||
if (requestTransferSyntaxUID && typeForTS[requestTransferSyntaxUID]) {
|
if (requestTransferSyntaxUID && typeForTS[requestTransferSyntaxUID]) {
|
||||||
const type = typeForTS[requestTransferSyntaxUID];
|
const type = typeForTS[requestTransferSyntaxUID];
|
||||||
acceptHeader.push('type=' + type);
|
acceptHeader.push('type=' + type);
|
||||||
acceptHeader.push('transfer-syntax=' + requestTransferSyntaxUID);
|
acceptHeader.push('transfer-syntax=' + requestTransferSyntaxUID);
|
||||||
|
hasTransferSyntax = true;
|
||||||
} else {
|
} else {
|
||||||
acceptHeader.push('type=application/octet-stream');
|
acceptHeader.push('type=application/octet-stream');
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptHeader.push('transfer-syntax=*');
|
if (!hasTransferSyntax) {
|
||||||
|
acceptHeader.push('transfer-syntax=*');
|
||||||
|
}
|
||||||
|
|
||||||
if (!omitQuotationForMultipartRequest) {
|
if (!omitQuotationForMultipartRequest) {
|
||||||
//need to add quotation for each mime type of each accept entry
|
//need to add quotation for each mime type of each accept entry
|
||||||
acceptHeader = acceptHeader.map(mime => {
|
acceptHeader = acceptHeader.map(mime => {
|
||||||
|
|||||||
@ -178,6 +178,31 @@ Now:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## SidePanel auto switch if open
|
||||||
|
|
||||||
|
In `basic viewer` mode, if the side panel is open and the segmentation panel is active, adding a measurement will automatically switch to the measurement panel. This switch won't occur if the side panel is closed. To enable or disable this feature, adjust your mode configuration accordingly.
|
||||||
|
|
||||||
|
```js
|
||||||
|
panelService.addActivatePanelTriggers('your.panel.id', [
|
||||||
|
{
|
||||||
|
sourcePubSubService: segmentationService,
|
||||||
|
sourceEvents: [segmentationService.EVENTS.SEGMENTATION_ADDED],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
panelService.addActivatePanelTriggers('your.panel.id', [
|
||||||
|
{
|
||||||
|
sourcePubSubService: measurementService,
|
||||||
|
sourceEvents: [
|
||||||
|
measurementService.EVENTS.MEASUREMENT_ADDED,
|
||||||
|
measurementService.EVENTS.RAW_MEASUREMENT_ADDED,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## DicomUpload
|
## DicomUpload
|
||||||
|
|
||||||
The DICOM upload functionality in OHIF has been refactored to use the standard customization service pattern. Now you don't need to put
|
The DICOM upload functionality in OHIF has been refactored to use the standard customization service pattern. Now you don't need to put
|
||||||
|
|||||||
@ -53,7 +53,6 @@
|
|||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-day-picker": "^8.10.1",
|
"react-day-picker": "^8.10.1",
|
||||||
"react-shepherd": "6.1.1",
|
"react-shepherd": "6.1.1",
|
||||||
"sanitize-html": "^2.13.1",
|
|
||||||
"shepherd.js": "13.0.3",
|
"shepherd.js": "13.0.3",
|
||||||
"sonner": "^1.5.0",
|
"sonner": "^1.5.0",
|
||||||
"tailwind-merge": "^2.3.0",
|
"tailwind-merge": "^2.3.0",
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import {
|
|||||||
} from '../../components/DropdownMenu';
|
} from '../../components/DropdownMenu';
|
||||||
import { Icons } from '../../components/Icons/Icons';
|
import { Icons } from '../../components/Icons/Icons';
|
||||||
import { Tooltip, TooltipTrigger, TooltipContent } from '../../components/Tooltip/Tooltip';
|
import { Tooltip, TooltipTrigger, TooltipContent } from '../../components/Tooltip/Tooltip';
|
||||||
import sanitizeHtml from 'sanitize-html';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DataRow is a complex UI component that displays a selectable, interactive row with hierarchical data.
|
* DataRow is a complex UI component that displays a selectable, interactive row with hierarchical data.
|
||||||
@ -131,7 +130,7 @@ const DataRow: React.FC<DataRowProps> = ({
|
|||||||
key={`empty-${indent}`}
|
key={`empty-${indent}`}
|
||||||
className="h-2"
|
className="h-2"
|
||||||
></div>
|
></div>
|
||||||
); // Empty row
|
);
|
||||||
}
|
}
|
||||||
const cleanText = decodeHTML(text);
|
const cleanText = decodeHTML(text);
|
||||||
return (
|
return (
|
||||||
@ -142,11 +141,11 @@ const DataRow: React.FC<DataRowProps> = ({
|
|||||||
{indentation}
|
{indentation}
|
||||||
{cleanText.includes(':') ? (
|
{cleanText.includes(':') ? (
|
||||||
<>
|
<>
|
||||||
<span className="font-medium">{sanitizeHtml(cleanText.split(':')[0])}:</span>
|
<span className="font-medium">{cleanText.split(':')[0]}:</span>
|
||||||
{sanitizeHtml(cleanText.split(':')[1])}
|
{cleanText.split(':')[1]}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<span className="font-medium">{sanitizeHtml(cleanText)}</span>
|
<span className="font-medium">{cleanText}</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -51,17 +51,19 @@ export const AddSegmentRow: React.FC<AddSegmentRowProps> = ({ children = null, s
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-primary-dark my-px flex h-7 w-full items-center justify-between rounded pl-0.5 pr-7">
|
<div className="bg-primary-dark my-px flex h-7 w-full items-center justify-between rounded pl-0.5 pr-7">
|
||||||
{allowAddSegment ? (
|
<div className="flex-1">
|
||||||
<Button
|
{allowAddSegment ? (
|
||||||
size="sm"
|
<Button
|
||||||
variant="ghost"
|
size="sm"
|
||||||
className="pr pl-0.5"
|
variant="ghost"
|
||||||
onClick={() => onSegmentAdd(segmentationIdToUse)}
|
className="pr pl-0.5"
|
||||||
>
|
onClick={() => onSegmentAdd(segmentationIdToUse)}
|
||||||
<Icons.Add />
|
>
|
||||||
Add Segment
|
<Icons.Add />
|
||||||
</Button>
|
Add Segment
|
||||||
) : null}
|
</Button>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
<Button
|
<Button
|
||||||
size="icon"
|
size="icon"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
|
|||||||
@ -61,7 +61,7 @@ export const SegmentationSelectorHeader: React.FC<{ children?: React.ReactNode }
|
|||||||
info: seg.segmentation.cachedStats?.info,
|
info: seg.segmentation.cachedStats?.info,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const allowExport = exportOptions.find(
|
const allowExport = exportOptions?.find(
|
||||||
({ segmentationId }) => segmentationId === activeSegmentation.id
|
({ segmentationId }) => segmentationId === activeSegmentation.id
|
||||||
)?.isExportable;
|
)?.isExportable;
|
||||||
|
|
||||||
|
|||||||
@ -149,6 +149,7 @@ const SidePanel = ({
|
|||||||
activeTabIndex: activeTabIndexProp = null,
|
activeTabIndex: activeTabIndexProp = null,
|
||||||
tabs,
|
tabs,
|
||||||
onOpen,
|
onOpen,
|
||||||
|
onClose,
|
||||||
expandedWidth = 280,
|
expandedWidth = 280,
|
||||||
onActiveTabIndexChange,
|
onActiveTabIndexChange,
|
||||||
}) => {
|
}) => {
|
||||||
@ -167,9 +168,11 @@ const SidePanel = ({
|
|||||||
setPanelOpen(panelOpen);
|
setPanelOpen(panelOpen);
|
||||||
if (panelOpen && onOpen) {
|
if (panelOpen && onOpen) {
|
||||||
onOpen();
|
onOpen();
|
||||||
|
} else if (onClose && !panelOpen) {
|
||||||
|
onClose();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[onOpen]
|
[onOpen, onClose]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateActiveTabIndex = useCallback(
|
const updateActiveTabIndex = useCallback(
|
||||||
@ -407,6 +410,7 @@ SidePanel.propTypes = {
|
|||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
onOpen: PropTypes.func,
|
onOpen: PropTypes.func,
|
||||||
|
onClose: PropTypes.func,
|
||||||
onActiveTabIndexChange: PropTypes.func,
|
onActiveTabIndexChange: PropTypes.func,
|
||||||
expandedWidth: PropTypes.number,
|
expandedWidth: PropTypes.number,
|
||||||
};
|
};
|
||||||
|
|||||||
66
yarn.lock
66
yarn.lock
@ -2580,10 +2580,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
|
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
|
||||||
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
|
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
|
||||||
|
|
||||||
"@cornerstonejs/adapters@^2.1.17":
|
"@cornerstonejs/adapters@^2.2.1":
|
||||||
version "2.1.17"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-2.1.17.tgz#509e62d500c733ab8babde7a3918548d59d6fa08"
|
resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-2.2.1.tgz#9bed051a7fd9ca5ad5af3ccb97fbb79862feadc1"
|
||||||
integrity sha512-+eptnnP+C+qKfRh0t0ZoZqQvxtDtwXZzMWk5IzNs/APRPh4XTt/VGh4hWt9UPUwxldG67k/bndjxilQkFUVNkA==
|
integrity sha512-7eIZTN3PO4s95vaLrAAD018bNKsD1w7l0FL+bLv+eqebNHrhBMQQbAfEWuQCueE+tYd1mVDCpNWVDMKMMabHmQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime-corejs2" "^7.17.8"
|
"@babel/runtime-corejs2" "^7.17.8"
|
||||||
buffer "^6.0.3"
|
buffer "^6.0.3"
|
||||||
@ -2616,32 +2616,33 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.5.tgz#8690b61a86fa53ef38a70eee9d665a79229517c0"
|
resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.5.tgz#8690b61a86fa53ef38a70eee9d665a79229517c0"
|
||||||
integrity sha512-MZCUy8VG0VG5Nl1l58+g+kH3LujAzLYTfJqkwpWI2gjSrGXnP6lgwyy4GmPRZWVoS40/B1LDNALK905cNWm+sg==
|
integrity sha512-MZCUy8VG0VG5Nl1l58+g+kH3LujAzLYTfJqkwpWI2gjSrGXnP6lgwyy4GmPRZWVoS40/B1LDNALK905cNWm+sg==
|
||||||
|
|
||||||
"@cornerstonejs/core@^2.1.17":
|
"@cornerstonejs/core@^2.2.1":
|
||||||
version "2.1.17"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-2.1.17.tgz#3cf4e7b586fccc0cd430947933f69bb08aaa6839"
|
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-2.2.1.tgz#37cc052d40fffcc093f0f773051787c610d07386"
|
||||||
integrity sha512-rtjRzRlEWk95Q4xlWkUaLitcX9g6bPsGXLASDm2nds8Dd5aEXCnPyEdBo6ow/rhvanohd7I1eC2fK2Wz7WWbJw==
|
integrity sha512-5ZZcpa7hU+E45jM4MvEJrIFA+WHFaLWIVh9FO1HksJXtkIeBurdYr6R95aOfk7ujkkft2rsgQA29a5Jl8E6aGg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@kitware/vtk.js" "32.1.0"
|
"@kitware/vtk.js" "32.1.0"
|
||||||
comlink "^4.4.1"
|
comlink "^4.4.1"
|
||||||
gl-matrix "^3.4.3"
|
gl-matrix "^3.4.3"
|
||||||
|
|
||||||
"@cornerstonejs/dicom-image-loader@^2.1.17":
|
"@cornerstonejs/dicom-image-loader@^2.2.1":
|
||||||
version "2.1.17"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-2.1.17.tgz#5429a10b921ed5586f093f51a363524e45cf6ecb"
|
resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-2.2.1.tgz#01f38061cd128c56b00fb5a3c47488880fb0f6bf"
|
||||||
integrity sha512-UIH4th4+F+a2s/myACpEmMjkPWFljAFbXeoj2Qo0JpL02FYYYGQuO7Ov+gjK/gv90twAh7q8Qg2+yNbHkC9pzA==
|
integrity sha512-yFO6K4vFZqG1dkUBpVSsQhOxS6nkb7uKEETwobhroAs8lIIfQ8141R8u2DfxBTIY7o9uJuYpabYzlhbyUYr4eA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@cornerstonejs/codec-charls" "^1.2.3"
|
"@cornerstonejs/codec-charls" "^1.2.3"
|
||||||
"@cornerstonejs/codec-libjpeg-turbo-8bit" "^1.2.2"
|
"@cornerstonejs/codec-libjpeg-turbo-8bit" "^1.2.2"
|
||||||
"@cornerstonejs/codec-openjpeg" "^1.2.2"
|
"@cornerstonejs/codec-openjpeg" "^1.2.2"
|
||||||
"@cornerstonejs/codec-openjph" "^2.4.5"
|
"@cornerstonejs/codec-openjph" "^2.4.5"
|
||||||
comlink "^4.4.1"
|
comlink "^4.4.1"
|
||||||
|
jpeg-lossless-decoder-js "^2.1.0"
|
||||||
pako "^2.0.4"
|
pako "^2.0.4"
|
||||||
uuid "^9.0.0"
|
uuid "^9.0.0"
|
||||||
|
|
||||||
"@cornerstonejs/tools@^2.1.17":
|
"@cornerstonejs/tools@^2.2.1":
|
||||||
version "2.1.17"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-2.1.17.tgz#74e7a18845da779f5bc513902de6dbfe1880add0"
|
resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-2.2.1.tgz#a6d34c39c330927c485e4af8b4c99026226249e4"
|
||||||
integrity sha512-vHdCVKV0kxYgvbS2ff9lDjd6AOKy6hP2Ohp96ac0enbZBNakUwDhqxWp94SezKqK7vn19fxRdSnPRLIchrqvJA==
|
integrity sha512-cxTZAr+zA1atAJjspA4u4yD+mMZsV+H/fqf2Oa8yn3EZU5ONmFF37QbwLiXd3Zo47GYfEgTPDKQwFWG7wIAsxg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/offscreencanvas" "2019.7.3"
|
"@types/offscreencanvas" "2019.7.3"
|
||||||
comlink "^4.4.1"
|
comlink "^4.4.1"
|
||||||
@ -5490,6 +5491,11 @@
|
|||||||
estree-walker "^2.0.2"
|
estree-walker "^2.0.2"
|
||||||
picomatch "^2.3.1"
|
picomatch "^2.3.1"
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-x64-gnu@4.13.0":
|
||||||
|
version "4.13.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz#f672f6508f090fc73f08ba40ff76c20b57424778"
|
||||||
|
integrity sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==
|
||||||
|
|
||||||
"@rspack/binding-darwin-arm64@1.0.14":
|
"@rspack/binding-darwin-arm64@1.0.14":
|
||||||
version "1.0.14"
|
version "1.0.14"
|
||||||
resolved "https://registry.yarnpkg.com/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.0.14.tgz#b9d99fb71e047f5300a851614f89cb9d7168db3e"
|
resolved "https://registry.yarnpkg.com/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.0.14.tgz#b9d99fb71e047f5300a851614f89cb9d7168db3e"
|
||||||
@ -13955,7 +13961,7 @@ htmlparser2@^6.1.0:
|
|||||||
domutils "^2.5.2"
|
domutils "^2.5.2"
|
||||||
entities "^2.0.0"
|
entities "^2.0.0"
|
||||||
|
|
||||||
htmlparser2@^8.0.0, htmlparser2@^8.0.1:
|
htmlparser2@^8.0.1:
|
||||||
version "8.0.2"
|
version "8.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.2.tgz#f002151705b383e62433b5cf466f5b716edaec21"
|
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.2.tgz#f002151705b383e62433b5cf466f5b716edaec21"
|
||||||
integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==
|
integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==
|
||||||
@ -15488,6 +15494,13 @@ joi@^17.9.2:
|
|||||||
"@sideway/formula" "^3.0.1"
|
"@sideway/formula" "^3.0.1"
|
||||||
"@sideway/pinpoint" "^2.0.0"
|
"@sideway/pinpoint" "^2.0.0"
|
||||||
|
|
||||||
|
jpeg-lossless-decoder-js@^2.1.0:
|
||||||
|
version "2.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/jpeg-lossless-decoder-js/-/jpeg-lossless-decoder-js-2.1.2.tgz#9ff0ecfcafa6acaee6097c532720bd526278aa3d"
|
||||||
|
integrity sha512-fYf/plymnuKwVw+s8gJ8O/BPw8y8OLaN11MBvEcT05kuy3m45o7BEC4J0JbxMNUYyO+MdK/I/jq0q1gkVYZm2Q==
|
||||||
|
optionalDependencies:
|
||||||
|
"@rollup/rollup-linux-x64-gnu" "4.13.0"
|
||||||
|
|
||||||
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
|
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||||
@ -18990,11 +19003,6 @@ parse-path@^7.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
protocols "^2.0.0"
|
protocols "^2.0.0"
|
||||||
|
|
||||||
parse-srcset@^1.0.2:
|
|
||||||
version "1.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1"
|
|
||||||
integrity sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==
|
|
||||||
|
|
||||||
parse-url@^8.1.0:
|
parse-url@^8.1.0:
|
||||||
version "8.1.0"
|
version "8.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-8.1.0.tgz#972e0827ed4b57fc85f0ea6b0d839f0d8a57a57d"
|
resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-8.1.0.tgz#972e0827ed4b57fc85f0ea6b0d839f0d8a57a57d"
|
||||||
@ -20145,7 +20153,7 @@ postcss@^8.2.1, postcss@^8.3.5, postcss@^8.4.18, postcss@^8.4.23, postcss@^8.4.3
|
|||||||
picocolors "^1.0.0"
|
picocolors "^1.0.0"
|
||||||
source-map-js "^1.2.0"
|
source-map-js "^1.2.0"
|
||||||
|
|
||||||
postcss@^8.3.11, postcss@^8.4.21, postcss@^8.4.24, postcss@^8.4.26, postcss@^8.4.38, postcss@^8.4.47:
|
postcss@^8.4.21, postcss@^8.4.24, postcss@^8.4.26, postcss@^8.4.38, postcss@^8.4.47:
|
||||||
version "8.4.47"
|
version "8.4.47"
|
||||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365"
|
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365"
|
||||||
integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==
|
integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==
|
||||||
@ -21860,18 +21868,6 @@ safe-regex-test@^1.0.3:
|
|||||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||||
|
|
||||||
sanitize-html@^2.13.1:
|
|
||||||
version "2.13.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.13.1.tgz#b4639b0a09574ab62b1b353cb99b1b87af742834"
|
|
||||||
integrity sha512-ZXtKq89oue4RP7abL9wp/9URJcqQNABB5GGJ2acW1sdO8JTVl92f4ygD7Yc9Ze09VAZhnt2zegeU0tbNsdcLYg==
|
|
||||||
dependencies:
|
|
||||||
deepmerge "^4.2.2"
|
|
||||||
escape-string-regexp "^4.0.0"
|
|
||||||
htmlparser2 "^8.0.0"
|
|
||||||
is-plain-object "^5.0.0"
|
|
||||||
parse-srcset "^1.0.2"
|
|
||||||
postcss "^8.3.11"
|
|
||||||
|
|
||||||
sax@^1.2.4:
|
sax@^1.2.4:
|
||||||
version "1.4.1"
|
version "1.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f"
|
resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user