fix(StackSync): Miscellaneous fixes for stack image sync (#3663)

This commit is contained in:
Bill Wallace authored and GitHub committed 2023-10-03 10:59:09 -04:00
1 parent b3429729f1
commit 8a335bd03d
26 files changed
+432 -293

No files matched your search

+2
View File
@@ -131,6 +131,8 @@ module.exports = (env, argv) => {
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
// Need to exclude the theme as it is updated independently
exclude: [/theme/],
// Cache large files for the manifests to avoid warning messages
maximumFileSizeToCacheInBytes: 1024 * 1024 * 50,
}),
],
// https://webpack.js.org/configuration/dev-server/
@@ -74,7 +74,7 @@ function getRuntimeLoadModesExtensions(modules) {
);
});
dynamicLoad.push(
' return (await import(module)).default;',
' return (await import(/* webpackIgnore: true */ module)).default;',
'}\n',
'// Import a list of items (modules or string names)',
'// @return a Promise evaluating to a list of modules',
@@ -409,20 +409,42 @@ describe('OHIF Cornerstone Toolbar', () => {
cy.get('@moreBtn').click();
cy.get('.tooltip-toolbar-overlay').should('not.exist');
});
it('check if Flip V tool will flip the image vertically in the viewport', () => {
//Click on More button
cy.get('@moreBtn').click();
//Verify if overlay is displayed
cy.get('.tooltip-toolbar-overlay').should('be.visible');
//Click on Flip V button
cy.get('[data-cy="flip v"]').click();
*/
it('check if Flip tool will flip the image in the viewport', () => {
cy.get('@viewportInfoMidLeft').should('contains.text', 'R');
cy.get('@viewportInfoMidTop').should('contains.text', 'F');
cy.get('@viewportInfoMidTop').should('contains.text', 'A');
//Click on More button to close it
cy.get('@moreBtn').click();
cy.get('.tooltip-toolbar-overlay').should('not.exist');
});*/
//Click on More button
cy.get('@moreBtnSecondary').click();
//Click on Flip button
cy.get('[data-cy="flip-horizontal"]').click();
cy.waitDicomImage();
cy.get('@viewportInfoMidLeft').should('contains.text', 'L');
cy.get('@viewportInfoMidTop').should('contains.text', 'A');
});
it('checks if stack sync is preserved on new display set and uses FOR', () => {
// Active stack image sync and reference lines
cy.get('[data-cy="MoreTools-split-button-secondary"]').click();
cy.get('[data-cy="StackImageSync"]').click();
// Add reference lines as that sometimes throws an exception
cy.get('[data-cy="MoreTools-split-button-secondary"]').click();
cy.get('[data-cy="ReferenceLines"]').click();
cy.get('[data-cy="study-browser-thumbnail"]:nth-child(2)').dblclick();
cy.get('body').type('{downarrow}{downarrow}');
// Change the layout and double load the first
cy.setLayout(2, 1);
cy.get('body').type('{rightarrow}');
cy.get('[data-cy="study-browser-thumbnail"]:nth-child(2)').dblclick();
cy.waitDicomImage();
// Now navigate down once and check that the left hand pane navigated
cy.get('body').type('{downarrow}');
cy.get('body').type('{leftarrow}');
cy.setLayout(1, 1);
cy.get('@viewportInfoTopRight').should('contains.text', 'I:2 (2/20)');
});
});
@@ -36,6 +36,8 @@ describe('OHIF Download Snapshot File', () => {
// Check buttons
cy.get('[data-cy="cancel-btn"]').scrollIntoView().should('be.visible');
cy.get('[data-cy="download-btn"]').scrollIntoView().should('be.visible');
cy.get('[data-cy="cancel-btn"]').click();
});
/*it('cancel changes on download modal', function() {
@@ -1,11 +1,9 @@
describe('OHIF Study Viewer Page', function () {
beforeEach(function () {
cy.checkStudyRouteInViewer('1.2.840.113619.2.5.1762583153.215519.978957063.78');
cy.expectMinimumThumbnails(3);
cy.initCommonElementsAliases();
cy.initCornerstoneToolsAliases();
});
describe('OHIF General Viewer', function () {
beforeEach(() =>
cy.initViewer('1.2.840.113619.2.5.1762583153.215519.978957063.78', {
minimumThumbnails: 3,
})
);
it('scrolls series stack using scrollbar', function () {
cy.scrollToIndex(13);
@@ -1,4 +1,4 @@
describe('OHIF Study Viewer Page', function () {
describe('OHIF Study Browser', function () {
beforeEach(function () {
cy.checkStudyRouteInViewer('1.2.840.113619.2.5.1762583153.215519.978957063.78');
+14 -7
View File
@@ -69,6 +69,18 @@ Cypress.Commands.add(
}
);
Cypress.Commands.add('initViewer', (StudyInstanceUID, other = {}) => {
const { mode = '/basic-test', minimumThumbnails = 1, params = '' } = other;
cy.openStudyInViewer(StudyInstanceUID, params, mode);
cy.waitDicomImage();
// Very short wait to ensure pending updates are handled
cy.wait(25);
cy.expectMinimumThumbnails(minimumThumbnails);
cy.initCommonElementsAliases();
cy.initCornerstoneToolsAliases();
});
Cypress.Commands.add(
'openStudyInViewer',
(StudyInstanceUID, otherParams = '', mode = '/basic-test') => {
@@ -347,14 +359,9 @@ Cypress.Commands.add('percyCanvasSnapshot', (name, options = {}) => {
});
Cypress.Commands.add('setLayout', (columns = 1, rows = 1) => {
cy.get('[data-cy="layout"]').click();
cy.get('[data-cy="Layout"]').click();
cy.get('.layoutChooser')
.find('tr')
.eq(rows - 1)
.find('td')
.eq(columns - 1)
.click();
cy.get(`[data-cy="Layout-${columns - 1}-${rows - 1}"]`).click();
cy.wait(10);
cy.waitDicomImage();
+22 -2
View File
@@ -38,8 +38,28 @@ window.config = {
configuration: {
friendlyName: 'Static WADO Local Data',
name: 'DCM4CHEE',
qidoRoot: '/dicomweb',
wadoRoot: '/dicomweb',
qidoRoot: 'http://localhost:5000/dicomweb',
wadoRoot: 'http://localhost:5000/dicomweb',
qidoSupportsIncludeField: false,
supportsReject: true,
supportsStow: true,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
enableStudyLazyLoad: true,
supportsFuzzyMatching: false,
supportsWildcard: true,
staticWado: true,
singlepart: 'bulkdata,video,pdf',
},
},
{
namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
sourceName: 'docker',
configuration: {
friendlyName: 'Static WADO Docker Data',
name: 'DCM4CHEE',
qidoRoot: 'http://localhost:25080/dicomweb',
wadoRoot: 'http://localhost:25080/dicomweb',
qidoSupportsIncludeField: false,
supportsReject: true,
supportsStow: true,
+1 -1
View File
@@ -443,7 +443,7 @@ export default function ModeRoute({
<ImageViewerProvider
// initialState={{ StudyInstanceUIDs: StudyInstanceUIDs }}
StudyInstanceUIDs={studyInstanceUIDs}
// reducer={reducer}
// reducer={reducer}
>
<CombinedContextProvider>
<DragAndDropProvider>
@@ -2,12 +2,37 @@ import merge from 'lodash.merge';
import { CommandsManager } from '../../classes';
import { ExtensionManager } from '../../extensions';
import { PubSubService } from '../_shared/pubSubServiceInterface';
import type { RunCommand, Commands } from '../../types/Command';
const EVENTS = {
TOOL_BAR_MODIFIED: 'event::toolBarService:toolBarModified',
TOOL_BAR_STATE_MODIFIED: 'event::toolBarService:toolBarStateModified',
};
export type ButtonListeners = Record<string, RunCommand>;
export interface ButtonProps {
primary?: Button;
secondary?: Button;
items?: Button[];
}
export interface Button extends Commands {
id: string;
icon?: string;
label?: string;
type?: string;
tooltip?: string;
isActive?: boolean;
listeners?: ButtonListeners;
props?: ButtonProps;
}
export interface ExtraButtonOptions {
listeners?: ButtonListeners;
isActive?: boolean;
}
export default class ToolbarService extends PubSubService {
public static REGISTRATION = {
name: 'toolbarService',
@@ -18,7 +43,27 @@ export default class ToolbarService extends PubSubService {
},
};
buttons: Record<string, unknown> = {};
public static _createButton(
type: string,
id: string,
icon: string,
label: string,
commands: Command | Commands,
tooltip?: string,
extraOptions?: ExtraButtonOptions
): Button {
return {
id,
icon,
label,
type,
commands,
tooltip,
...extraOptions,
};
}
buttons: Record<string, Button> = {};
state: {
primaryToolId: string;
toggles: Record<string, boolean>;
@@ -54,7 +99,7 @@ export default class ToolbarService extends PubSubService {
this.buttons = {};
}
onModeEnter() {
public onModeEnter(): void {
this.reset();
}
@@ -65,7 +110,7 @@ export default class ToolbarService extends PubSubService {
* used for calling the specified interaction. That is, the command is
* called with {...commandOptions,...options}
*/
recordInteraction(interaction, options?: Record<string, unknown>) {
public recordInteraction(interaction, options?: Record<string, unknown>) {
if (!interaction) {
return;
}
@@ -174,12 +219,18 @@ export default class ToolbarService extends PubSubService {
}
getActiveTools() {
return [this.state.primaryToolId, ...Object.keys(this.state.toggles)];
const activeTools = [this.state.primaryToolId];
Object.keys(this.state.toggles).forEach(key => {
if (this.state.toggles[key]) {
activeTools.push(key);
}
});
return activeTools;
}
/** Sets the toggle state of a button to the isActive state */
public setActive(id: string, isActive: boolean): void {
if (isActive) {
/** Sets the toggle state of a button to the isToggled state */
public setToggled(id: string, isToggled: boolean): void {
if (isToggled) {
this.state.toggles[id] = true;
} else {
delete this.state.toggles[id];
@@ -197,10 +248,25 @@ export default class ToolbarService extends PubSubService {
}
}
getButton(id) {
public getButton(id: string): Button {
return this.buttons[id];
}
/** Gets a nested button, found in the items/props for the children */
public getNestedButton(id: string): Button {
if (this.buttons[id]) {
return this.buttons[id];
}
for (const buttonId of Object.keys(this.buttons)) {
const { primary, items } = this.buttons[buttonId].props || {};
if (primary?.id === id) { return primary; }
const found = items?.find(childButton => childButton.id === id);
if (found) {
return found;
}
}
}
setButtons(buttons) {
this.buttons = buttons;
this._broadcastEvent(this.EVENTS.TOOL_BAR_MODIFIED, {
@@ -267,23 +333,22 @@ export default class ToolbarService extends PubSubService {
if (!this.buttons[button.id]) {
this.buttons[button.id] = button;
}
this._setTogglesForButtonItems(button.props?.items);
});
this._setTogglesForButtonItems(buttons);
this._broadcastEvent(this.EVENTS.TOOL_BAR_MODIFIED, {});
}
_setTogglesForButtonItems(buttonItems) {
if (!buttonItems) {
_setTogglesForButtonItems(buttons) {
if (!buttons) {
return;
}
buttonItems.forEach(buttonItem => {
buttons.forEach(buttonItem => {
if (buttonItem.type === 'toggle') {
this.state.toggles[buttonItem.id] = buttonItem.isActive;
} else {
this._setTogglesForButtonItems(buttonItem.props?.items);
this.setToggled(buttonItem.id, buttonItem.isActive);
}
this._setTogglesForButtonItems(buttonItem.props?.items);
});
}
+3 -1
View File
@@ -4,7 +4,9 @@ export interface Command {
context?: string;
}
export type RunCommand = Command | Command[];
/** A set of commands, typically contained in a tool item or other configuration */
export interface Commands {
commands: Command[];
commands: RunCommand;
}
@@ -34,6 +34,7 @@ function LayoutSelector({ onSelection, rows, columns }) {
border: '1px solid white',
backgroundColor: isHovered(index) ? '#5acce6' : '#0b1a42',
}}
data-cy={`Layout-${index % columns}-${Math.floor(index / columns)}`}
className="cursor-pointer"
onClick={() => {
const x = index % columns;