fix(bugs): fixing lots of bugs regarding release candidate (#3700)

This commit is contained in:
Alireza 2023-10-05 23:39:56 -04:00 committed by GitHub
parent 29aeb070e0
commit 8bc12a37d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 119 additions and 76 deletions

View File

@ -35,6 +35,7 @@ dotenv.config();
const defineValues = {
/* Application */
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.NODE_DEBUG': JSON.stringify(process.env.NODE_DEBUG),
'process.env.DEBUG': JSON.stringify(process.env.DEBUG),
'process.env.PUBLIC_URL': JSON.stringify(process.env.PUBLIC_URL || '/'),
'process.env.BUILD_NUM': JSON.stringify(BUILD_NUM),

View File

@ -28,7 +28,6 @@ function commandsModule({
toolGroupService,
cineService,
toolbarService,
stateSyncService,
uiDialogService,
cornerstoneViewportService,
uiNotificationService,
@ -155,7 +154,7 @@ function commandsModule({
* @param props - containing the updates to apply
* @param props.measurementKey - chooses the measurement key to apply the
* code to. This will typically be finding or site to apply a
* finind code or a findingSites code.
* finding code or a findingSites code.
* @param props.code - A coding scheme value from DICOM, including:
* * CodeValue - the language independent code, for example '1234'
* * CodingSchemeDesignator - the issue of the code value
@ -225,6 +224,25 @@ function commandsModule({
arrowTextCallback: ({ callback, data }) => {
callInputDialog(uiDialogService, data, callback);
},
cleanUpCrosshairs: () => {
// if the crosshairs tool is active, deactivate it and set window level active
// since we are going back to main non-mpr HP
const activeViewportToolGroup = toolGroupService.getToolGroup(null);
if (activeViewportToolGroup._toolInstances?.Crosshairs?.mode === Enums.ToolModes.Active) {
actions.toolbarServiceRecordInteraction({
interactionType: 'tool',
commands: [
{
commandOptions: {
toolName: 'WindowLevel',
},
context: 'CORNERSTONE',
},
],
});
}
},
toggleCine: () => {
const { viewports } = viewportGridService.getState();
const { isCineEnabled } = cineService.getState();
@ -294,18 +312,8 @@ function commandsModule({
}
const toolGroup = toolGroupService.getToolGroup(toolGroupId);
const toolGroupViewportIds = toolGroup?.getViewportIds?.();
// if toolGroup has been destroyed, or its viewports have been removed
if (!toolGroupViewportIds || !toolGroupViewportIds.length) {
return;
}
const filteredViewports = Array.from(viewports.values()).filter(viewport => {
return toolGroupViewportIds.includes(viewport.viewportId);
});
if (!filteredViewports.length) {
if (!toolGroup) {
return;
}
@ -708,6 +716,9 @@ function commandsModule({
setToolbarToggled: {
commandFn: actions.setToolbarToggled,
},
cleanUpCrosshairs: {
commandFn: actions.cleanUpCrosshairs,
},
};
return {

View File

@ -24,18 +24,7 @@ const mpr: Types.HangingProtocol.Protocol = {
// Turns off crosshairs when switching out of MPR mode
onProtocolExit: [
{
commandName: 'toolbarServiceRecordInteraction',
commandOptions: {
interactionType: 'tool',
commands: [
{
commandOptions: {
toolName: 'WindowLevel',
},
context: 'CORNERSTONE',
},
],
},
commandName: 'cleanUpCrosshairs',
},
],
},

View File

@ -224,9 +224,11 @@ class CornerstoneCacheService {
const segDisplaySetInstanceUID = segmentation.displaySetInstanceUID;
const segDisplaySet = displaySetService.getDisplaySetByUID(segDisplaySetInstanceUID);
const instance = segDisplaySet.instances?.[0] || segDisplaySet.instance;
const shouldDisplaySeg = segmentationService.shouldRenderSegmentation(
viewportDisplaySetInstanceUIDs,
segDisplaySet.instances[0].FrameOfReferenceUID
instance.FrameOfReferenceUID
);
if (shouldDisplaySeg) {

View File

@ -160,7 +160,7 @@ export default class StaticWadoClient extends api.DICOMwebClient {
if (!valueElem) {
return false;
}
if (valueElem.vr == 'DA') {
if (valueElem.vr === 'DA' && valueElem.Value?.[0]) {
return this.compareDateRange(testValue, valueElem.Value[0]);
}
const value = valueElem.Value;

View File

@ -33,7 +33,6 @@ function PanelStudyBrowser({
const [studyDisplayList, setStudyDisplayList] = useState([]);
const [displaySets, setDisplaySets] = useState([]);
const [thumbnailImageSrcMap, setThumbnailImageSrcMap] = useState({});
const isMounted = useRef(true);
const onDoubleClickThumbnailHandler = displaySetInstanceUID => {
let updatedViewports = [];
@ -120,17 +119,11 @@ function PanelStudyBrowser({
}
// When the image arrives, render it and store the result in the thumbnailImgSrcMap
newImageSrcEntry[dSet.displaySetInstanceUID] = await getImageSrc(imageId);
if (!isMounted.current) {
return;
}
setThumbnailImageSrcMap(prevState => {
return { ...prevState, ...newImageSrcEntry };
});
});
return () => {
isMounted.current = false;
};
}, [StudyInstanceUIDs, dataSource, displaySetService, getImageSrc]);
// ~~ displaySets

View File

@ -170,6 +170,7 @@ const commandsModule = ({
stageIndex,
reset = false,
}: HangingProtocolParams): boolean => {
const primaryToolBeforeHPChange = toolbarService.getActivePrimaryTool();
try {
// Stores in the state the display set selector id to displaySetUID mapping
// Pass in viewportId for the active viewport. This item will get set as
@ -241,7 +242,29 @@ const commandsModule = ({
stateSyncService.store(stateSyncReduce);
// This is a default action applied
const { protocol } = hangingProtocolService.getActiveProtocol();
actions.toggleHpTools(protocol);
actions.toggleHpTools();
// try to use the same tool in the new hanging protocol stage
const primaryButton = toolbarService.getButton(primaryToolBeforeHPChange);
if (primaryButton) {
// is there any type of interaction on this button, if not it might be in the
// items. This is a bit of a hack, but it works for now.
let interactionType = primaryButton.props?.interactionType;
if (!interactionType && primaryButton.props?.items) {
const firstItem = primaryButton.props.items[0];
interactionType = firstItem.props?.interactionType || firstItem.props?.type;
}
if (interactionType) {
toolbarService.recordInteraction({
interactionType,
...primaryButton.props,
});
}
}
// Send the notification about updating the state
if (protocolId !== hpInfo.protocolId) {
// The old protocol callbacks are used for turning off things
@ -253,7 +276,8 @@ const commandsModule = ({
commandsManager.run(protocol.callbacks?.onProtocolEnter);
return true;
} catch (e) {
actions.toggleHpTools(hangingProtocolService.getActiveProtocol());
console.error(e);
actions.toggleHpTools();
uiNotificationService.show({
title: 'Apply Hanging Protocol',
message: 'The hanging protocol could not be applied.',

View File

@ -188,7 +188,8 @@ function DataSourceWrapper(props) {
!isSamePage || (!isLoading && (newOffset !== previousOffset || isLocationUpdated));
if (isDataInvalid) {
getData().catch(() => {
getData().catch(e => {
console.error(e);
// If there is a data source configuration API, then the Worklist will popup the dialog to attempt to configure it
// and attempt to resolve this issue.
if (dataSource.getConfig().configurationAPI) {

View File

@ -74,7 +74,7 @@ function _getInstance(StudyInstanceUID, SeriesInstanceUID, SOPInstanceUID) {
return;
}
return series.instances.find(instance => instance.SOPInstanceUID === SOPInstanceUID);
return series.getInstance(SOPInstanceUID);
}
function _getInstanceByImageId(imageId) {

View File

@ -1,9 +1,26 @@
function createSeriesMetadata(instances) {
const { SeriesInstanceUID } = instances[0];
function createSeriesMetadata(SeriesInstanceUID) {
const instances = [];
const instancesMap = new Map();
return {
SeriesInstanceUID,
instances,
addInstance: function (newInstance) {
this.addInstances([newInstance]);
},
addInstances: function (newInstances) {
for (let i = 0, len = newInstances.length; i < len; i++) {
const instance = newInstances[i];
if (!instancesMap.has(instance.SOPInstanceUID)) {
instancesMap.set(instance.SOPInstanceUID, instance);
instances.push(instance);
}
}
},
getInstance: function (SOPInstanceUID) {
return instancesMap.get(SOPInstanceUID);
},
};
}

View File

@ -8,54 +8,29 @@ function createStudyMetadata(StudyInstanceUID) {
isLoaded: false,
series: [],
/**
*
* @param {object} instance
* @returns {bool} true if series were added; false if series already exist
*/
addInstanceToSeries: function (instance) {
const { SeriesInstanceUID } = instance;
if (!this.StudyDescription) {
this.StudyDescription = instance.StudyDescription;
}
const existingSeries = this.series.find(s => s.SeriesInstanceUID === SeriesInstanceUID);
if (existingSeries) {
existingSeries.instances.push(instance);
} else {
const series = createSeriesMetadata([instance]);
this.series.push(series);
const { Modality } = series;
if (this.ModalitiesInStudy.indexOf(Modality) === -1) {
this.ModalitiesInStudy.push(Modality);
}
}
this.addInstancesToSeries([instance]);
},
/**
*
* @param {object[]} instances
* @param {string} instances[].SeriesInstanceUID
* @param {string} instances[].StudyDescription
* @returns {bool} true if series were added; false if series already exist
*/
addInstancesToSeries: function (instances) {
const { SeriesInstanceUID } = instances[0];
if (!this.StudyDescription) {
this.StudyDescription = instances[0].StudyDescription;
}
const existingSeries = this.series.find(s => s.SeriesInstanceUID === SeriesInstanceUID);
let series = this.series.find(s => s.SeriesInstanceUID === SeriesInstanceUID);
if (existingSeries) {
// Only add instances not already present, so generate a map
// of existing instances and filter the to add by things
// already present.
const sopMap = {};
existingSeries.instances.forEach(it => (sopMap[it.SOPInstanceUID] = it));
const newInstances = instances.filter(it => !sopMap[it.SOPInstanceUID]);
existingSeries.instances.push(...newInstances);
} else {
const series = createSeriesMetadata(instances);
if (!series) {
const series = createSeriesMetadata(SeriesInstanceUID);
this.series.push(series);
}
series.addInstances(instances);
},
setSeriesMetadata: function (SeriesInstanceUID, seriesMetadata) {
@ -64,7 +39,8 @@ function createStudyMetadata(StudyInstanceUID) {
if (existingSeries) {
existingSeries = Object.assign(existingSeries, seriesMetadata);
} else {
this.series.push(Object.assign({ instances: [] }, seriesMetadata));
const series = createSeriesMetadata(SeriesInstanceUID);
this.series.push(Object.assign(series, seriesMetadata));
}
},
};

View File

@ -115,7 +115,13 @@ export default class ToolbarService extends PubSubService {
return;
}
const commandsManager = this._commandsManager;
const { groupId, itemId, interactionType, commands } = interaction;
const { groupId, itemId, commands, type } = interaction;
let { interactionType } = interaction;
// if not interaction type, assume the type can be used
if (!interactionType) {
interactionType = type;
}
switch (interactionType) {
case 'action': {
@ -228,6 +234,10 @@ export default class ToolbarService extends PubSubService {
return activeTools;
}
getActivePrimaryTool() {
return this.state.primaryToolId;
}
/** Sets the toggle state of a button to the isToggled state */
public setToggled(id: string, isToggled: boolean): void {
if (isToggled) {
@ -259,7 +269,9 @@ export default class ToolbarService extends PubSubService {
}
for (const buttonId of Object.keys(this.buttons)) {
const { primary, items } = this.buttons[buttonId].props || {};
if (primary?.id === id) { return primary; }
if (primary?.id === id) {
return primary;
}
const found = items?.find(childButton => childButton.id === id);
if (found) {
return found;

View File

@ -153,3 +153,14 @@ directly from
Your public folder should look like this:
![](../../assets/img/dicom-json-public.png)
:::note
When hosting the DICOM JSON files, it is important to be aware that certain providers
do not automatically handle the 404 error and fallback to index.html. For example, Netlify
handles this, but Azure does not. Consequently, when you attempt to access a link with a
specific URL, a 404 error will be displayed.
This issue also occurs locally, where the http-server does not handle it. However,
if you utilize the `serve` package (npx serve ./dist -l 8080 -s), it effectively addresses this problem.
:::

View File

@ -18,13 +18,15 @@ It can be compiled with Java and Gradle, and then run against a set of dicom, in
the example located in /dicom/study1 outputting to /dicomweb, and then a server
run against that data, like this:
```
```bash
git clone https://github.com/OHIF/static-wado
cd static-wado
./gradlew installDist
StaticWado/build/install/StaticWado/bin/StaticWado -d /dicomweb /dicom/study1
cd /dicomweb
npx http-server -p 5000 --cors -g
# you can use npx serve ./dist -l 8080 -s as an alternative to http-server
```
There is then a dev environment in the platform/app directory which can be

View File

@ -106,6 +106,8 @@ yarn global add http-server
# Serve the files in our current directory
# Accessible at: `http://localhost:8080`
npx http-server ./dist
# you can use npx serve ./dist -l 8080 -s as an alternative to http-server
```
:::caution

View File

@ -44,8 +44,10 @@ Download the index.html and the build (against the /ohif/ path) from [here](http
Then run the
```
```bash
npx http-server unzipped-folder
# you can use npx serve ./dist -l 8080 -s as an alternative to http-server
```
You should be able to see