fix(bugs): fixing lots of bugs regarding release candidate (#3700)
This commit is contained in:
parent
29aeb070e0
commit
8bc12a37d0
@ -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),
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.',
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -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));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -153,3 +153,14 @@ directly from
|
||||
Your public folder should look like this:
|
||||
|
||||

|
||||
|
||||
|
||||
:::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.
|
||||
:::
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user