feat(multimonitor): Add simple multi-monitor support to open another study(#4178)
This commit is contained in:
1 parent
a4a6de07f4
commit
07c628e689
49 files changed
+1476
-367
No files matched your search
@@ -25,6 +25,67 @@ window.config = {
|
||||
prefetch: 25,
|
||||
},
|
||||
// filterQueryParam: false,
|
||||
// Defines multi-monitor layouts
|
||||
multimonitor: [
|
||||
{
|
||||
id: 'split',
|
||||
test: ({ multimonitor }) => multimonitor === 'split',
|
||||
screens: [
|
||||
{
|
||||
id: 'ohif0',
|
||||
screen: null,
|
||||
location: {
|
||||
screen: 0,
|
||||
width: 0.5,
|
||||
height: 1,
|
||||
left: 0,
|
||||
top: 0,
|
||||
},
|
||||
options: 'location=no,menubar=no,scrollbars=no,status=no,titlebar=no',
|
||||
},
|
||||
{
|
||||
id: 'ohif1',
|
||||
screen: null,
|
||||
location: {
|
||||
width: 0.5,
|
||||
height: 1,
|
||||
left: 0.5,
|
||||
top: 0,
|
||||
},
|
||||
options: 'location=no,menubar=no,scrollbars=no,status=no,titlebar=no',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
id: '2',
|
||||
test: ({ multimonitor }) => multimonitor === '2',
|
||||
screens: [
|
||||
{
|
||||
id: 'ohif0',
|
||||
screen: 0,
|
||||
location: {
|
||||
width: 1,
|
||||
height: 1,
|
||||
left: 0,
|
||||
top: 0,
|
||||
},
|
||||
options: 'fullscreen=yes,location=no,menubar=no,scrollbars=no,status=no,titlebar=no',
|
||||
},
|
||||
{
|
||||
id: 'ohif1',
|
||||
screen: 1,
|
||||
location: {
|
||||
width: 1,
|
||||
height: 1,
|
||||
left: 0,
|
||||
top: 0,
|
||||
},
|
||||
options: 'fullscreen=yes,location=no,menubar=no,scrollbars=no,status=no,titlebar=no',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
defaultDataSourceName: 'dicomweb',
|
||||
/* Dynamic config allows user to pass "configUrl" query string this allows to load config without recompiling application. The regex will ensure valid configuration source */
|
||||
// dangerouslyUseDynamicConfig: {
|
||||
|
||||
@@ -21,6 +21,67 @@ window.config = {
|
||||
investigationalUseDialog: {
|
||||
option: 'never',
|
||||
},
|
||||
// Defines multi-monitor layouts
|
||||
multimonitor: [
|
||||
{
|
||||
id: 'split',
|
||||
test: ({ multimonitor }) => multimonitor === 'split',
|
||||
screens: [
|
||||
{
|
||||
id: 'ohif0',
|
||||
screen: null,
|
||||
location: {
|
||||
screen: 0,
|
||||
width: 0.5,
|
||||
height: 1,
|
||||
left: 0,
|
||||
top: 0,
|
||||
},
|
||||
options: 'location=no,menubar=no,scrollbars=no,status=no,titlebar=no',
|
||||
},
|
||||
{
|
||||
id: 'ohif1',
|
||||
screen: null,
|
||||
location: {
|
||||
width: 0.5,
|
||||
height: 1,
|
||||
left: 0.5,
|
||||
top: 0,
|
||||
},
|
||||
options: 'location=no,menubar=no,scrollbars=no,status=no,titlebar=no',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
id: '2',
|
||||
test: ({ multimonitor }) => multimonitor === '2',
|
||||
screens: [
|
||||
{
|
||||
id: 'ohif0',
|
||||
screen: 0,
|
||||
location: {
|
||||
width: 1,
|
||||
height: 1,
|
||||
left: 0,
|
||||
top: 0,
|
||||
},
|
||||
options: 'fullscreen=yes,location=no,menubar=no,scrollbars=no,status=no,titlebar=no',
|
||||
},
|
||||
{
|
||||
id: 'ohif1',
|
||||
screen: 1,
|
||||
location: {
|
||||
width: 1,
|
||||
height: 1,
|
||||
left: 0,
|
||||
top: 0,
|
||||
},
|
||||
options: 'fullscreen=yes,location=no,menubar=no,scrollbars=no,status=no,titlebar=no',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
dataSources: [
|
||||
{
|
||||
namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
PanelService,
|
||||
WorkflowStepsService,
|
||||
StudyPrefetcherService,
|
||||
MultiMonitorService,
|
||||
// utils,
|
||||
} from '@ohif/core';
|
||||
|
||||
@@ -58,6 +59,7 @@ async function appInit(appConfigOrFunc, defaultExtensions, defaultModes) {
|
||||
servicesManager.setExtensionManager(extensionManager);
|
||||
|
||||
servicesManager.registerServices([
|
||||
[MultiMonitorService.REGISTRATION, appConfig.multimonitor],
|
||||
UINotificationService.REGISTRATION,
|
||||
UIModalService.REGISTRATION,
|
||||
UIDialogService.REGISTRATION,
|
||||
|
||||
@@ -3,13 +3,19 @@ import { useLocation } from 'react-router';
|
||||
/**
|
||||
* It returns a URLSearchParams of the query parameters in the URL, where the keys are
|
||||
* either lowercase or maintain their case based on the lowerCaseKeys parameter.
|
||||
* This will automatically include the hash parameters as preferred parameters
|
||||
* @param {lowerCaseKeys:boolean} true to return lower case keys; false (default) to maintain casing;
|
||||
* @returns {URLSearchParams}
|
||||
*/
|
||||
export default function useSearchParams(options = { lowerCaseKeys: false }) {
|
||||
const { lowerCaseKeys } = options;
|
||||
const searchParams = new URLSearchParams(useLocation().search);
|
||||
const location = useLocation();
|
||||
const searchParams = new URLSearchParams(location.search);
|
||||
const hashParams = new URLSearchParams(location.hash?.substring(1) || '');
|
||||
|
||||
for (const [key, value] of hashParams) {
|
||||
searchParams.set(key, value);
|
||||
}
|
||||
if (!lowerCaseKeys) {
|
||||
return searchParams;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ import 'regenerator-runtime/runtime';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import App from './App';
|
||||
import React from 'react';
|
||||
import { history } from './utils/history';
|
||||
export { publicUrl } from './utils/publicUrl';
|
||||
|
||||
/**
|
||||
* EXTENSIONS AND MODES
|
||||
@@ -19,6 +17,9 @@ export { publicUrl } from './utils/publicUrl';
|
||||
*/
|
||||
import { modes as defaultModes, extensions as defaultExtensions } from './pluginImports';
|
||||
import loadDynamicConfig from './loadDynamicConfig';
|
||||
export { history } from './utils/history';
|
||||
export { preserveQueryParameters, preserveQueryStrings } from './utils/preserveQueryParameters';
|
||||
export { publicUrl } from './utils/publicUrl';
|
||||
|
||||
loadDynamicConfig(window.config).then(config_json => {
|
||||
// Reset Dynamic config if defined
|
||||
@@ -41,5 +42,3 @@ loadDynamicConfig(window.config).then(config_json => {
|
||||
const root = createRoot(container);
|
||||
root.render(React.createElement(App, appProps));
|
||||
});
|
||||
|
||||
export { history };
|
||||
@@ -43,6 +43,7 @@ import {
|
||||
import { Types } from '@ohif/ui';
|
||||
|
||||
import i18n from '@ohif/i18n';
|
||||
import { preserveQueryParameters, preserveQueryStrings } from '../../utils/preserveQueryParameters';
|
||||
|
||||
const PatientInfoVisibility = Types.PatientInfoVisibility;
|
||||
|
||||
@@ -206,11 +207,12 @@ function WorkList({
|
||||
}
|
||||
});
|
||||
|
||||
preserveQueryStrings(queryString);
|
||||
|
||||
const search = qs.stringify(queryString, {
|
||||
skipNull: true,
|
||||
skipEmptyString: true,
|
||||
});
|
||||
|
||||
navigate({
|
||||
pathname: publicUrl,
|
||||
search: search ? `?${search}` : undefined,
|
||||
@@ -413,6 +415,7 @@ function WorkList({
|
||||
query.append('configUrl', filterValues.configUrl);
|
||||
}
|
||||
query.append('StudyInstanceUIDs', studyInstanceUid);
|
||||
preserveQueryParameters(query);
|
||||
|
||||
return (
|
||||
mode.displayName && (
|
||||
@@ -640,7 +643,6 @@ const defaultFilterValues = {
|
||||
pageNumber: 1,
|
||||
resultsPerPage: 25,
|
||||
datasources: '',
|
||||
configUrl: null,
|
||||
};
|
||||
|
||||
function _tryParseInt(str, defaultValue) {
|
||||
|
||||
@@ -112,8 +112,7 @@ const createRoutes = ({
|
||||
const allRoutes = [
|
||||
...routes,
|
||||
...(showStudyList ? [WorkListRoute] : []),
|
||||
// This next line adds a route on / to allow loading from the route and redirecting to the public url
|
||||
...(publicUrl !== '/' && showStudyList ? [{ ...WorkListRoute, path: '/' }] : []),
|
||||
...(publicUrl !== '/' && showStudyList ? [{ ...WorkListRoute, path: publicUrl }] : []),
|
||||
...(customRoutes?.routes || []),
|
||||
...bakedInRoutes,
|
||||
customRoutes?.notFoundRoute || notFoundRoute,
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
function preserve(query, current, key) {
|
||||
const value = current.get(key);
|
||||
if (value) {
|
||||
query.append(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
export const preserveKeys = ['configUrl', 'multimonitor', 'screenNumber'];
|
||||
|
||||
export function preserveQueryParameters(
|
||||
query,
|
||||
current = new URLSearchParams(window.location.search)
|
||||
) {
|
||||
for (const key of preserveKeys) {
|
||||
preserve(query, current, key);
|
||||
}
|
||||
}
|
||||
|
||||
export function preserveQueryStrings(query, current = new URLSearchParams(window.location.search)) {
|
||||
for (const key of preserveKeys) {
|
||||
const value = current.get(key);
|
||||
if (value) {
|
||||
query[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user