OHIF with Cornerstone3D 2.0 (#4347)
This commit is contained in:
1 parent
8981a61b8c
commit
7ce7127d7c
803 files changed
+32760
-15893
No files matched your search
@@ -1,2 +1,3 @@
|
||||
.vercel
|
||||
test-results
|
||||
store.json
|
||||
@@ -1,7 +1,7 @@
|
||||
# docker-compose
|
||||
# --------------
|
||||
# This dockerfile is used by the `docker-compose.yml` adjacent file. When
|
||||
# running `docker-compose build`, this dockerfile helps build the "webapp" image.
|
||||
# running `docker compose build`, this dockerfile helps build the "webapp" image.
|
||||
# All paths are relative to the `context`, which is the project root directory.
|
||||
#
|
||||
# docker build
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# docker-compose
|
||||
# --------------
|
||||
# This dockerfile is used by the `docker-compose.yml` adjacent file. When
|
||||
# running `docker-compose build`, this dockerfile helps build the "webapp" image.
|
||||
# running `docker compose build`, this dockerfile helps build the "webapp" image.
|
||||
# All paths are relative to the `context`, which is the project root directory.
|
||||
#
|
||||
# docker build
|
||||
|
||||
@@ -18,12 +18,18 @@ const PUBLIC_DIR = path.join(__dirname, '../public');
|
||||
const HTML_TEMPLATE = process.env.HTML_TEMPLATE || 'index.html';
|
||||
const PUBLIC_URL = process.env.PUBLIC_URL || '/';
|
||||
const APP_CONFIG = process.env.APP_CONFIG || 'config/default.js';
|
||||
|
||||
// proxy settings
|
||||
const PROXY_TARGET = process.env.PROXY_TARGET;
|
||||
const PROXY_DOMAIN = process.env.PROXY_DOMAIN;
|
||||
const PROXY_PATH_REWRITE_FROM = process.env.PROXY_PATH_REWRITE_FROM;
|
||||
const PROXY_PATH_REWRITE_TO = process.env.PROXY_PATH_REWRITE_TO;
|
||||
|
||||
const OHIF_PORT = Number(process.env.OHIF_PORT || 3000);
|
||||
const ENTRY_TARGET = process.env.ENTRY_TARGET || `${SRC_DIR}/index.js`;
|
||||
const Dotenv = require('dotenv-webpack');
|
||||
const writePluginImportFile = require('./writePluginImportsFile.js');
|
||||
// const MillionLint = require('@million/lint');
|
||||
|
||||
const copyPluginFromExtensions = writePluginImportFile(SRC_DIR, DIST_DIR);
|
||||
|
||||
@@ -75,6 +81,8 @@ module.exports = (env, argv) => {
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
// For debugging re-renders
|
||||
// MillionLint.webpack(),
|
||||
new Dotenv(),
|
||||
// Clean output.path
|
||||
new CleanWebpackPlugin(),
|
||||
@@ -104,21 +112,12 @@ module.exports = (env, argv) => {
|
||||
to: `${DIST_DIR}/app-config.js`,
|
||||
},
|
||||
// Copy Dicom Microscopy Viewer build files
|
||||
// This is in pluginCOnfig.json now
|
||||
// {
|
||||
// from: '../../../node_modules/dicom-microscopy-viewer/dist/dynamic-import',
|
||||
// to: DIST_DIR,
|
||||
// globOptions: {
|
||||
// ignore: ['**/*.min.js.map'],
|
||||
// },
|
||||
// // The dicom-microscopy-viewer is optional, so if it doeesn't get
|
||||
// // installed, it shouldn't cause issues.
|
||||
// noErrorOnMissing: true,
|
||||
// },
|
||||
// Copy dicom-image-loader build files
|
||||
{
|
||||
from: '../../../node_modules/@cornerstonejs/dicom-image-loader/dist/dynamic-import',
|
||||
from: '../../../node_modules/dicom-microscopy-viewer/dist/dynamic-import',
|
||||
to: DIST_DIR,
|
||||
globOptions: {
|
||||
ignore: ['**/*.min.js.map'],
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
@@ -179,12 +178,23 @@ module.exports = (env, argv) => {
|
||||
'Cross-Origin-Embedder-Policy': 'require-corp',
|
||||
'Cross-Origin-Opener-Policy': 'same-origin',
|
||||
},
|
||||
devMiddleware: {
|
||||
writeToDisk: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (hasProxy) {
|
||||
mergedConfig.devServer.proxy = mergedConfig.devServer.proxy || {};
|
||||
mergedConfig.devServer.proxy[PROXY_TARGET] = PROXY_DOMAIN;
|
||||
mergedConfig.devServer.proxy = {
|
||||
[PROXY_TARGET]: {
|
||||
target: PROXY_DOMAIN,
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
[`^${PROXY_PATH_REWRITE_FROM}`]: PROXY_PATH_REWRITE_TO,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (isProdBuild) {
|
||||
|
||||
@@ -13,10 +13,6 @@ export default defineConfig({
|
||||
console.log(launchOptions.args); // print all current args
|
||||
|
||||
console.log('***', browser.family, browser.name, '***');
|
||||
if (browser.family === 'chromium' && browser.name !== 'electron') {
|
||||
// auto open devtools
|
||||
launchOptions.args.push('--enable-features=SharedArrayBuffer');
|
||||
}
|
||||
|
||||
// whatever you return here becomes the launchOptions
|
||||
return launchOptions;
|
||||
|
||||
@@ -11,7 +11,7 @@ describe('OHIF HP', () => {
|
||||
});
|
||||
|
||||
it('Should display 3 up', () => {
|
||||
cy.get('[data-cy="viewport-pane"]').its('length').should('be.eq', 3);
|
||||
cy.get('[data-cy="viewport-pane"]').its('length').should('be.eq', 4);
|
||||
});
|
||||
|
||||
it('Should navigate next/previous stage', () => {
|
||||
|
||||
@@ -10,11 +10,11 @@ describe('OHIF Double Click', () => {
|
||||
});
|
||||
|
||||
it('Should double click each viewport to one up and back', () => {
|
||||
const numExpectedViewports = 3;
|
||||
const numExpectedViewports = 4;
|
||||
cy.get('[data-cy="viewport-pane"]').its('length').should('be.eq', numExpectedViewports);
|
||||
|
||||
for (let i = 0; i < numExpectedViewports; i += 1) {
|
||||
cy.wait(2000);
|
||||
for (let i = 0; i < 3; i += 1) {
|
||||
cy.wait(1000);
|
||||
|
||||
// For whatever reason, with Cypress tests, we have to activate the
|
||||
// viewport we are double clicking first.
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@ describe('OHIF Context Menu', function () {
|
||||
// Add length measurement
|
||||
cy.addLengthMeasurement();
|
||||
cy.get('[data-cy="prompt-begin-tracking-yes-btn"]').as('yesBtn').click();
|
||||
cy.get('[data-cy="measurement-item"]').as('measurementItem').click();
|
||||
cy.get('[data-cy="data-row"]').as('measurementItem').click();
|
||||
|
||||
const [x1, y1] = [150, 100];
|
||||
cy.get('@viewport')
|
||||
@@ -30,6 +30,6 @@ describe('OHIF Context Menu', function () {
|
||||
|
||||
// Click "Finding" subMenu
|
||||
cy.get('[data-cy="context-menu-item"]').as('item').contains('Aortic insufficiency').click();
|
||||
cy.get('[data-cy="measurement-item"]').as('measure-item').contains('Aortic insufficiency');
|
||||
cy.get('[data-cy="data-row"]').as('measure-item').contains('Aortic insufficiency');
|
||||
});
|
||||
});
|
||||
+3
-3
@@ -85,7 +85,7 @@ describe('OHIF Cornerstone Toolbar', () => {
|
||||
// The exact text is slightly dependent on the viewport resolution, so leave a range
|
||||
cy.get('@viewportInfoBottomLeft').should($txt => {
|
||||
const text = $txt.text();
|
||||
expect(text).to.include('W:118').include('L:479');
|
||||
expect(text).to.include('L:479');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -117,7 +117,7 @@ describe('OHIF Cornerstone Toolbar', () => {
|
||||
//Verify the measurement exists in the table
|
||||
cy.get('@measurementsPanel').should('be.visible');
|
||||
|
||||
cy.get('[data-cy="measurement-item"]').as('measure').its('length').should('be.at.least', 1);
|
||||
cy.get('[data-cy="data-row"]').as('measure').its('length').should('be.at.least', 1);
|
||||
});
|
||||
|
||||
/*it('checks if angle annotation can be added on viewport without causing any errors', () => {
|
||||
@@ -351,7 +351,7 @@ describe('OHIF Cornerstone Toolbar', () => {
|
||||
|
||||
//Verify if measurement annotation was added into the measurements panel
|
||||
cy.get('@measurementsBtn').click();
|
||||
cy.get('[data-cy="measurement-item"]')
|
||||
cy.get('[data-cy="data-row"]')
|
||||
.its('length')
|
||||
.should('be.at.least', 2);
|
||||
|
||||
|
||||
@@ -29,16 +29,17 @@ describe('OHIF Measurement Panel', function () {
|
||||
|
||||
cy.get('[data-cy="prompt-begin-tracking-yes-btn"]').as('yesBtn').click();
|
||||
|
||||
cy.get('[data-cy="measurement-item"]').as('measurementItem').click();
|
||||
cy.get('[data-cy="data-row"]').as('measurementItem').click();
|
||||
|
||||
cy.get('[data-cy="measurement-item"]').find('svg').eq(0).as('measurementItemSvg').click();
|
||||
cy.get('[data-cy="data-row"]').find('svg').eq(0).as('measurementItemSvg').click();
|
||||
|
||||
// enter Bone label
|
||||
cy.get('[data-cy="input-annotation"]').should('exist');
|
||||
cy.get('[data-cy="input-annotation"]').should('be.visible');
|
||||
cy.get('[data-cy="input-annotation"]').type('Bone{enter}');
|
||||
// Todo: move it to the new annotation input with drop down
|
||||
// cy.get('[data-cy="input-annotation"]').should('exist');
|
||||
// cy.get('[data-cy="input-annotation"]').should('be.visible');
|
||||
// cy.get('[data-cy="input-annotation"]').type('Bone{enter}');
|
||||
|
||||
cy.get('[data-cy="measurement-item"]').as('measurementItem').should('contain.text', 'Bone');
|
||||
// cy.get('[data-cy="data-row"]').as('measurementItem').should('contain.text', 'Bone');
|
||||
});
|
||||
|
||||
it('checks if image would jump when clicked on a measurement item', function () {
|
||||
@@ -58,7 +59,7 @@ describe('OHIF Measurement Panel', function () {
|
||||
cy.get('@viewportInfoBottomRight').should('contains.text', '(14/');
|
||||
|
||||
// Click on first measurement item
|
||||
cy.get('[data-cy="measurement-item"]').eq(0).click();
|
||||
cy.get('[data-cy="data-row"]').eq(0).click();
|
||||
|
||||
cy.get('@viewportInfoBottomRight').should('contains.text', '(1/');
|
||||
cy.get('@viewportInfoBottomRight').should('not.contains.text', '(14/');
|
||||
|
||||
@@ -39,9 +39,3 @@
|
||||
no-cache,
|
||||
no-store,
|
||||
must-revalidate'''
|
||||
|
||||
# COMMENT: For sharedArrayBuffer, see https://developer.chrome.com/blog/enabling-shared-array-buffer/
|
||||
Cross-Origin-Embedder-Policy = "require-corp"
|
||||
Cross-Origin-Opener-Policy = "same-origin"
|
||||
# set CORP to cross-origin for anyone who wants to use the viewer in an iframe
|
||||
Cross-Origin-Resource-Policy = "cross-origin"
|
||||
@@ -29,8 +29,8 @@
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack serve --config .webpack/webpack.pwa.js",
|
||||
"dev:no:cache": "cross-env NODE_ENV=development webpack serve --no-cache --config .webpack/webpack.pwa.js",
|
||||
"dev:orthanc": "cross-env NODE_ENV=development PROXY_TARGET=/dicom-web PROXY_DOMAIN=http://localhost:8042 APP_CONFIG=config/docker-nginx-orthanc.js webpack serve --config .webpack/webpack.pwa.js",
|
||||
"dev:orthanc:no:cache": "cross-env NODE_ENV=development PROXY_TARGET=/dicom-web PROXY_DOMAIN=http://localhost:8042 APP_CONFIG=config/docker-nginx-orthanc.js webpack serve --no-cache --config .webpack/webpack.pwa.js",
|
||||
"dev:orthanc": "cross-env NODE_ENV=development PROXY_TARGET=http://localhost:3000/pacs/dicom-web PROXY_DOMAIN=http://localhost:8042 PROXY_PATH_REWRITE_FROM=/pacs/dicom-web PROXY_PATH_REWRITE_TO=/dicom-web APP_CONFIG=config/docker-nginx-orthanc.js webpack serve --config .webpack/webpack.pwa.js",
|
||||
"dev:orthanc:no:cache": "cross-env NODE_ENV=development PROXY_TARGET=http://localhost:3000/pacs/dicom-web PROXY_DOMAIN=http://localhost:8042 PROXY_PATH_REWRITE_FROM=/pacs/dicom-web PROXY_PATH_REWRITE_TO=/dicom-web APP_CONFIG=config/docker-nginx-orthanc.js webpack serve --no-cache --config .webpack/webpack.pwa.js",
|
||||
"dev:dcm4chee": "cross-env NODE_ENV=development APP_CONFIG=config/local_dcm4chee.js webpack serve --config .webpack/webpack.pwa.js",
|
||||
"dev:static": "cross-env NODE_ENV=development APP_CONFIG=config/local_static.js webpack serve --config .webpack/webpack.pwa.js",
|
||||
"dev:viewer": "yarn run dev",
|
||||
@@ -53,7 +53,7 @@
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||
"@cornerstonejs/dicom-image-loader": "^1.86.0",
|
||||
"@cornerstonejs/dicom-image-loader": "^2.1.13",
|
||||
"@emotion/serialize": "^1.1.3",
|
||||
"@ohif/core": "3.9.0-beta.105",
|
||||
"@ohif/extension-cornerstone": "3.9.0-beta.105",
|
||||
@@ -100,7 +100,8 @@
|
||||
"react-router-dom": "^6.8.1",
|
||||
"react-shepherd": "6.1.1",
|
||||
"shepherd.js": "13.0.3",
|
||||
"url-loader": "^4.1.1"
|
||||
"url-loader": "^4.1.1",
|
||||
"zustand": "4.5.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-private-methods": "^7.18.6",
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
/*
|
||||
# Ensure the examples are cross-origin isolated so that
|
||||
# we can use SharedArrayBuffer
|
||||
# See https://developer.mozilla.org/en-US/docs/Web/API/crossOriginIsolated
|
||||
Cross-Origin-Embedder-Policy: require-corp
|
||||
Cross-Origin-Opener-Policy: same-origin
|
||||
@@ -427,14 +427,14 @@ window.config = {
|
||||
title: 'Jumping to Measurements in the Panel',
|
||||
text: 'Click the measurement in the measurement panel to jump to it.',
|
||||
attachTo: {
|
||||
element: '[data-cy="measurement-item"]',
|
||||
element: '[data-cy="data-row"]',
|
||||
on: 'left-start',
|
||||
},
|
||||
advanceOn: {
|
||||
selector: '[data-cy="measurement-item"]',
|
||||
selector: '[data-cy="data-row"]',
|
||||
event: 'click',
|
||||
},
|
||||
beforeShowPromise: () => waitForElement('[data-cy="measurement-item"]'),
|
||||
beforeShowPromise: () => waitForElement('[data-cy="data-row"]'),
|
||||
},
|
||||
{
|
||||
id: 'changeLayout',
|
||||
|
||||
@@ -17,7 +17,6 @@ window.config = {
|
||||
showCPUFallbackMessage: true,
|
||||
showLoadingIndicator: true,
|
||||
useNorm16Texture: true,
|
||||
useSharedArrayBuffer: 'AUTO',
|
||||
maxNumRequests: {
|
||||
interaction: 100,
|
||||
thumbnail: 75,
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
window.config = {
|
||||
routerBasename: '/ohif-viewer/',
|
||||
showStudyList: true,
|
||||
customizationService: {
|
||||
dicomUploadComponent:
|
||||
'@ohif/extension-cornerstone.customizationModule.cornerstoneDicomUploadComponent',
|
||||
},
|
||||
extensions: [],
|
||||
modes: [],
|
||||
// below flag is for performance reasons, but it might not work for all servers
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
window.config = {
|
||||
routerBasename: '/',
|
||||
showStudyList: true,
|
||||
customizationService: {
|
||||
dicomUploadComponent:
|
||||
'@ohif/extension-cornerstone.customizationModule.cornerstoneDicomUploadComponent',
|
||||
},
|
||||
extensions: [],
|
||||
modes: [],
|
||||
// below flag is for performance reasons, but it might not work for all servers
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
window.config = {
|
||||
routerBasename: '/',
|
||||
showStudyList: true,
|
||||
customizationService: {
|
||||
dicomUploadComponent:
|
||||
'@ohif/extension-cornerstone.customizationModule.cornerstoneDicomUploadComponent',
|
||||
},
|
||||
extensions: [],
|
||||
modes: [],
|
||||
// below flag is for performance reasons, but it might not work for all servers
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
/** @type {AppTypes.Config} */
|
||||
window.config = {
|
||||
routerBasename: '/',
|
||||
customizationService: {
|
||||
dicomUploadComponent:
|
||||
'@ohif/extension-cornerstone.customizationModule.cornerstoneDicomUploadComponent',
|
||||
},
|
||||
enableGoogleCloudAdapter: false,
|
||||
// below flag is for performance reasons, but it might not work for all servers
|
||||
showWarningMessageForCrossOrigin: true,
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
/** @type {AppTypes.Config} */
|
||||
window.config = {
|
||||
routerBasename: '/',
|
||||
customizationService: {
|
||||
dicomUploadComponent:
|
||||
'@ohif/extension-cornerstone.customizationModule.cornerstoneDicomUploadComponent',
|
||||
},
|
||||
showStudyList: true,
|
||||
extensions: [],
|
||||
modes: [],
|
||||
|
||||
@@ -3,10 +3,6 @@ window.config = {
|
||||
routerBasename: '/',
|
||||
extensions: [],
|
||||
modes: [],
|
||||
customizationService: {
|
||||
dicomUploadComponent:
|
||||
'@ohif/extension-cornerstone.customizationModule.cornerstoneDicomUploadComponent',
|
||||
},
|
||||
showStudyList: true,
|
||||
maxNumberOfWebWorkers: 3,
|
||||
showLoadingIndicator: true,
|
||||
|
||||
@@ -383,14 +383,14 @@ window.config = {
|
||||
title: 'Jumping to Measurements in the Panel',
|
||||
text: 'Click the measurement in the measurement panel to jump to it.',
|
||||
attachTo: {
|
||||
element: '[data-cy="measurement-item"]',
|
||||
element: '[data-cy="data-row"]',
|
||||
on: 'left-start',
|
||||
},
|
||||
advanceOn: {
|
||||
selector: '[data-cy="measurement-item"]',
|
||||
selector: '[data-cy="data-row"]',
|
||||
event: 'click',
|
||||
},
|
||||
beforeShowPromise: () => waitForElement('[data-cy="measurement-item"]'),
|
||||
beforeShowPromise: () => waitForElement('[data-cy="data-row"]'),
|
||||
},
|
||||
{
|
||||
id: 'changeLayout',
|
||||
|
||||
@@ -5,6 +5,7 @@ import PropTypes from 'prop-types';
|
||||
import i18n from '@ohif/i18n';
|
||||
import { I18nextProvider } from 'react-i18next';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
|
||||
import Compose from './routes/Mode/Compose';
|
||||
import {
|
||||
ExtensionManager,
|
||||
@@ -16,7 +17,6 @@ import {
|
||||
DialogProvider,
|
||||
Modal,
|
||||
ModalProvider,
|
||||
SnackbarProvider,
|
||||
ThemeWrapper,
|
||||
ViewportDialogProvider,
|
||||
ViewportGridProvider,
|
||||
@@ -24,7 +24,11 @@ import {
|
||||
UserAuthenticationProvider,
|
||||
ToolboxProvider,
|
||||
} from '@ohif/ui';
|
||||
import { ThemeWrapper as ThemeWrapperNext } from '@ohif/ui-next';
|
||||
import {
|
||||
ThemeWrapper as ThemeWrapperNext,
|
||||
NotificationProvider,
|
||||
TooltipProvider,
|
||||
} from '@ohif/ui-next';
|
||||
// Viewer Project
|
||||
// TODO: Should this influence study list?
|
||||
import { AppConfigProvider } from '@state';
|
||||
@@ -88,17 +92,19 @@ function App({
|
||||
const canvas = document.createElement('canvas');
|
||||
const gl = canvas.getContext('webgl2');
|
||||
|
||||
const max3DTextureSize = gl.getParameter(gl.MAX_3D_TEXTURE_SIZE);
|
||||
appConfigState.max3DTextureSize = max3DTextureSize;
|
||||
if (gl) {
|
||||
const max3DTextureSize = gl.getParameter(gl.MAX_3D_TEXTURE_SIZE);
|
||||
appConfigState.max3DTextureSize = max3DTextureSize;
|
||||
}
|
||||
|
||||
const {
|
||||
uiDialogService,
|
||||
uiModalService,
|
||||
uiNotificationService,
|
||||
uiViewportDialogService,
|
||||
viewportGridService,
|
||||
cineService,
|
||||
userAuthenticationService,
|
||||
uiNotificationService,
|
||||
customizationService,
|
||||
} = servicesManager.services;
|
||||
|
||||
@@ -112,8 +118,8 @@ function App({
|
||||
[ViewportGridProvider, { service: viewportGridService }],
|
||||
[ViewportDialogProvider, { service: uiViewportDialogService }],
|
||||
[CineProvider, { service: cineService }],
|
||||
// [NotificationProvider, { service: uiNotificationService }],
|
||||
[SnackbarProvider, { service: uiNotificationService }],
|
||||
[NotificationProvider, { service: uiNotificationService }],
|
||||
[TooltipProvider],
|
||||
[DialogProvider, { service: uiDialogService }],
|
||||
[ModalProvider, { service: uiModalService, modal: Modal }],
|
||||
[ShepherdJourneyProvider],
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
UIDialogService,
|
||||
UIViewportDialogService,
|
||||
MeasurementService,
|
||||
StateSyncService,
|
||||
DisplaySetService,
|
||||
ToolbarService,
|
||||
ViewportGridService,
|
||||
@@ -73,7 +72,6 @@ async function appInit(appConfigOrFunc, defaultExtensions, defaultModes) {
|
||||
UserAuthenticationService.REGISTRATION,
|
||||
PanelService.REGISTRATION,
|
||||
WorkflowStepsService.REGISTRATION,
|
||||
StateSyncService.REGISTRATION,
|
||||
[StudyPrefetcherService.REGISTRATION, appConfig.studyPrefetcher],
|
||||
]);
|
||||
|
||||
|
||||
@@ -23,13 +23,8 @@ function ViewerViewportGrid(props: withAppTypes) {
|
||||
});
|
||||
const layoutHash = useRef(null);
|
||||
|
||||
const {
|
||||
displaySetService,
|
||||
measurementService,
|
||||
hangingProtocolService,
|
||||
cornerstoneViewportService,
|
||||
uiNotificationService,
|
||||
} = servicesManager.services;
|
||||
const { displaySetService, measurementService, hangingProtocolService, uiNotificationService } =
|
||||
servicesManager.services;
|
||||
|
||||
const generateLayoutHash = () => `${numCols}-${numRows}`;
|
||||
|
||||
@@ -129,7 +124,7 @@ function ViewerViewportGrid(props: withAppTypes) {
|
||||
title: 'Drag and Drop',
|
||||
message:
|
||||
'The selected display sets could not be added to the viewport due to a mismatch in the Hanging Protocol rules.',
|
||||
type: 'info',
|
||||
type: 'error',
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Icon } from '@ohif/ui';
|
||||
function Debug() {
|
||||
return (
|
||||
<div style={{ width: '100%', height: '100%' }}>
|
||||
<div className="flex h-screen w-screen items-center justify-center ">
|
||||
<div className="flex h-screen w-screen items-center justify-center">
|
||||
<div className="bg-secondary-dark mx-auto space-y-2 rounded-lg py-8 px-8 drop-shadow-md">
|
||||
<img
|
||||
className="mx-auto block h-14"
|
||||
@@ -24,21 +24,6 @@ function Debug() {
|
||||
}
|
||||
className="h-5 w-5"
|
||||
/>
|
||||
{!window.crossOriginIsolated && (
|
||||
<div className="text-md flex-1 text-white">
|
||||
We use SharedArrayBuffer to render volume data (e.g., MPR). If you are seeing
|
||||
this message, it means that your browser has not enabled COOP/COEP. Please see
|
||||
the following link for more information:{' '}
|
||||
<a
|
||||
href="https://web.dev/coop-coep/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary-active"
|
||||
>
|
||||
Learn More
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState, useEffect, useMemo } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import PropTypes, { object } from 'prop-types';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import moment from 'moment';
|
||||
import qs from 'query-string';
|
||||
@@ -20,7 +20,6 @@ import {
|
||||
StudyListPagination,
|
||||
StudyListFilter,
|
||||
TooltipClipboard,
|
||||
Header,
|
||||
useModal,
|
||||
AboutModal,
|
||||
UserPreferences,
|
||||
@@ -31,10 +30,12 @@ import {
|
||||
ButtonEnums,
|
||||
} from '@ohif/ui';
|
||||
|
||||
import { Header } from '@ohif/ui-next';
|
||||
|
||||
import { Types } from '@ohif/ui';
|
||||
|
||||
import i18n from '@ohif/i18n';
|
||||
import { Onboarding } from '@ohif/ui-next';
|
||||
import { Onboarding, ScrollArea } from '@ohif/ui-next';
|
||||
|
||||
const PatientInfoVisibility = Types.PatientInfoVisibility;
|
||||
|
||||
@@ -497,29 +498,32 @@ function WorkList({
|
||||
}
|
||||
|
||||
const { customizationService } = servicesManager.services;
|
||||
const { component: dicomUploadComponent } =
|
||||
customizationService.get('dicomUploadComponent') ?? {};
|
||||
const { component: DicomUploadComponent } =
|
||||
customizationService.getCustomization('dicomUploadComponent') || {};
|
||||
|
||||
const uploadProps =
|
||||
dicomUploadComponent && dataSource.getConfig()?.dicomUploadEnabled
|
||||
DicomUploadComponent && dataSource.getConfig()?.dicomUploadEnabled
|
||||
? {
|
||||
title: 'Upload files',
|
||||
closeButton: true,
|
||||
shouldCloseOnEsc: false,
|
||||
shouldCloseOnOverlayClick: false,
|
||||
content: dicomUploadComponent.bind(null, {
|
||||
dataSource,
|
||||
onComplete: () => {
|
||||
hide();
|
||||
onRefresh();
|
||||
},
|
||||
onStarted: () => {
|
||||
show({
|
||||
...uploadProps,
|
||||
// when upload starts, hide the default close button as closing the dialogue must be handled by the upload dialogue itself
|
||||
closeButton: false,
|
||||
});
|
||||
},
|
||||
}),
|
||||
content: () => (
|
||||
<DicomUploadComponent
|
||||
dataSource={dataSource}
|
||||
onComplete={() => {
|
||||
hide();
|
||||
onRefresh();
|
||||
}}
|
||||
onStarted={() => {
|
||||
show({
|
||||
...uploadProps,
|
||||
// when upload starts, hide the default close button as closing the dialogue must be handled by the upload dialogue itself
|
||||
closeButton: false,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
),
|
||||
}
|
||||
: undefined;
|
||||
|
||||
@@ -537,45 +541,51 @@ function WorkList({
|
||||
/>
|
||||
<Onboarding />
|
||||
<InvestigationalUseDialog dialogConfiguration={appConfig?.investigationalUseDialog} />
|
||||
<div className="ohif-scrollbar ohif-scrollbar-stable-gutter flex grow flex-col overflow-y-auto sm:px-5">
|
||||
<StudyListFilter
|
||||
numOfStudies={pageNumber * resultsPerPage > 100 ? 101 : numOfStudies}
|
||||
filtersMeta={filtersMeta}
|
||||
filterValues={{ ...filterValues, ...defaultSortValues }}
|
||||
onChange={setFilterValues}
|
||||
clearFilters={() => setFilterValues(defaultFilterValues)}
|
||||
isFiltering={isFiltering(filterValues, defaultFilterValues)}
|
||||
onUploadClick={uploadProps ? () => show(uploadProps) : undefined}
|
||||
getDataSourceConfigurationComponent={
|
||||
dataSourceConfigurationComponent ? () => dataSourceConfigurationComponent() : undefined
|
||||
}
|
||||
/>
|
||||
{hasStudies ? (
|
||||
<div className="flex flex-col overflow-y-auto">
|
||||
<ScrollArea>
|
||||
<div className="flex grow flex-col">
|
||||
<StudyListTable
|
||||
tableDataSource={tableDataSource.slice(offset, offsetAndTake)}
|
||||
numOfStudies={numOfStudies}
|
||||
querying={querying}
|
||||
<StudyListFilter
|
||||
numOfStudies={pageNumber * resultsPerPage > 100 ? 101 : numOfStudies}
|
||||
filtersMeta={filtersMeta}
|
||||
filterValues={{ ...filterValues, ...defaultSortValues }}
|
||||
onChange={setFilterValues}
|
||||
clearFilters={() => setFilterValues(defaultFilterValues)}
|
||||
isFiltering={isFiltering(filterValues, defaultFilterValues)}
|
||||
onUploadClick={uploadProps ? () => show(uploadProps) : undefined}
|
||||
getDataSourceConfigurationComponent={
|
||||
dataSourceConfigurationComponent
|
||||
? () => dataSourceConfigurationComponent()
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
<div className="grow">
|
||||
<StudyListPagination
|
||||
onChangePage={onPageNumberChange}
|
||||
onChangePerPage={onResultsPerPageChange}
|
||||
currentPage={pageNumber}
|
||||
perPage={resultsPerPage}
|
||||
</div>
|
||||
{hasStudies ? (
|
||||
<div className="flex grow flex-col">
|
||||
<StudyListTable
|
||||
tableDataSource={tableDataSource.slice(offset, offsetAndTake)}
|
||||
numOfStudies={numOfStudies}
|
||||
querying={querying}
|
||||
filtersMeta={filtersMeta}
|
||||
/>
|
||||
<div className="grow">
|
||||
<StudyListPagination
|
||||
onChangePage={onPageNumberChange}
|
||||
onChangePerPage={onResultsPerPageChange}
|
||||
currentPage={pageNumber}
|
||||
perPage={resultsPerPage}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center pt-48">
|
||||
{appConfig.showLoadingIndicator && isLoadingData ? (
|
||||
<LoadingIndicatorProgress className={'h-full w-full bg-black'} />
|
||||
) : (
|
||||
<EmptyStudies />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center pt-48">
|
||||
{appConfig.showLoadingIndicator && isLoadingData ? (
|
||||
<LoadingIndicatorProgress className={'h-full w-full bg-black'} />
|
||||
) : (
|
||||
<EmptyStudies />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</ScrollArea>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Routes, Route } from 'react-router-dom';
|
||||
import { ErrorBoundary } from '@ohif/ui';
|
||||
import { ErrorBoundary } from '@ohif/ui-next';
|
||||
|
||||
// Route Components
|
||||
import DataSourceWrapper from './DataSourceWrapper';
|
||||
@@ -120,10 +120,7 @@ const createRoutes = ({
|
||||
function RouteWithErrorBoundary({ route, ...rest }) {
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
return (
|
||||
<ErrorBoundary
|
||||
context={`Route ${route.path}`}
|
||||
fallbackRoute="/"
|
||||
>
|
||||
<ErrorBoundary context={`Route ${route.path}`}>
|
||||
<route.children
|
||||
{...rest}
|
||||
{...route.props}
|
||||
|
||||
@@ -44,7 +44,7 @@ const initUserManager = (oidc, routerBasename) => {
|
||||
post_logout_redirect_uri: _makeAbsoluteIfNecessary(post_logout_redirect_uri, baseUri),
|
||||
});
|
||||
|
||||
const client = firstOpenIdClient.useAuthorizationCodeFlow ? NextClient : LegacyClient
|
||||
const client = firstOpenIdClient.response_type === 'code' ? NextClient : LegacyClient;
|
||||
|
||||
return client(openIdConnectConfiguration);
|
||||
};
|
||||
|
||||
@@ -39,16 +39,16 @@ module.exports = {
|
||||
mono: ['Menlo', 'Monaco', 'Consolas', '"Liberation Mono"', '"Courier New"', 'monospace'],
|
||||
},
|
||||
fontSize: {
|
||||
xs: '0.65rem',
|
||||
sm: '0.75rem',
|
||||
base: '0.8125rem',
|
||||
lg: '0.9275rem',
|
||||
xl: '1.25rem',
|
||||
'2xl': '1.5rem',
|
||||
'3xl': '1.875rem',
|
||||
'4xl': '2.25rem',
|
||||
'5xl': '3rem',
|
||||
'6xl': '4rem',
|
||||
xxs: '0.6875rem', // 11px
|
||||
xs: '0.75rem', // 12px
|
||||
sm: '0.8125rem', // 13px
|
||||
base: '0.875rem', // 14px
|
||||
lg: '1rem', // 16px
|
||||
xl: '1.125rem', // 18px
|
||||
'2xl': '1.25rem', // 20px
|
||||
'3xl': '1.375rem', // 22px
|
||||
'4xl': '1.5rem', // 24px
|
||||
'5xl': '1.875rem', // 30px
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -2,3 +2,7 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
* {
|
||||
min-height: 0 !important;
|
||||
}
|
||||
Reference in new issue
Block a user