feat(App): Loads mode extensions on demand (#3312)
* feat: Dynamic plugin imports * Remove unused file * Fix basic dev mode * Fix the modes issue that Joe requested * Merge fixes * Add the ability to publish directory contents * PR review changes ---------
This commit is contained in:
parent
2f355fa158
commit
a688f03fdb
@ -10,7 +10,6 @@ const configs = {
|
|||||||
const ohif = {
|
const ohif = {
|
||||||
layout: '@ohif/extension-default.layoutTemplateModule.viewerLayout',
|
layout: '@ohif/extension-default.layoutTemplateModule.viewerLayout',
|
||||||
sopClassHandler: '@ohif/extension-default.sopClassHandlerModule.stack',
|
sopClassHandler: '@ohif/extension-default.sopClassHandlerModule.stack',
|
||||||
hangingProtocol: '@ohif/extension-default.hangingProtocolModule.default',
|
|
||||||
measurements: '@ohif/extension-default.panelModule.measure',
|
measurements: '@ohif/extension-default.panelModule.measure',
|
||||||
thumbnailList: '@ohif/extension-default.panelModule.seriesList',
|
thumbnailList: '@ohif/extension-default.panelModule.seriesList',
|
||||||
};
|
};
|
||||||
@ -47,8 +46,8 @@ const extensionDependencies = {
|
|||||||
function modeFactory({ modeConfiguration }) {
|
function modeFactory({ modeConfiguration }) {
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
routeName: 'viewer',
|
routeName: 'dev',
|
||||||
displayName: 'Basic Viewer CS3D',
|
displayName: 'Basic Dev Viewer',
|
||||||
/**
|
/**
|
||||||
* Lifecycle hooks
|
* Lifecycle hooks
|
||||||
*/
|
*/
|
||||||
@ -134,6 +133,15 @@ function modeFactory({ modeConfiguration }) {
|
|||||||
'MoreTools',
|
'MoreTools',
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
onModeExit: ({ servicesManager }) => {
|
||||||
|
const {
|
||||||
|
toolGroupService,
|
||||||
|
measurementService,
|
||||||
|
toolbarService,
|
||||||
|
} = servicesManager.services;
|
||||||
|
|
||||||
|
toolGroupService.destroy();
|
||||||
|
},
|
||||||
validationTags: {
|
validationTags: {
|
||||||
study: [],
|
study: [],
|
||||||
series: [],
|
series: [],
|
||||||
@ -177,7 +185,7 @@ function modeFactory({ modeConfiguration }) {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
extensions: extensionDependencies,
|
extensions: extensionDependencies,
|
||||||
hangingProtocol: [ohif.hangingProtocol],
|
hangingProtocol: 'default',
|
||||||
sopClassHandlers: [
|
sopClassHandlers: [
|
||||||
dicomvideo.sopClassHandler,
|
dicomvideo.sopClassHandler,
|
||||||
ohif.sopClassHandler,
|
ohif.sopClassHandler,
|
||||||
|
|||||||
9
platform/public/demo.html
Normal file
9
platform/public/demo.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<h1>Demo Page</h1>
|
||||||
|
<p>This demo page shows how to include directories of content in the pluginConfig.json file.
|
||||||
|
The idea is that it is possible to serve up non-compiled content such as the microscopy mode
|
||||||
|
which will not be included in the compile of OHIF but can be included later on dynamically.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -1,11 +1,14 @@
|
|||||||
const pluginConfig = require('../pluginConfig.json');
|
const pluginConfig = require('../pluginConfig.json');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const os = require('os');
|
||||||
const glob = require('glob');
|
const glob = require('glob');
|
||||||
|
|
||||||
const autogenerationDisclaimer = `
|
const autogenerationDisclaimer = `
|
||||||
// THIS FILE IS AUTOGENERATED AS PART OF THE EXTENSION AND MODE PLUGIN PROCESS.
|
// THIS FILE IS AUTOGENERATED AS PART OF THE EXTENSION AND MODE PLUGIN PROCESS.
|
||||||
// IT SHOULD NOT BE MODIFIED MANUALLY \n`;
|
// IT SHOULD NOT BE MODIFIED MANUALLY \n`;
|
||||||
|
|
||||||
|
const extractName = (val) => (typeof val === 'string') ? val : val.packageName;
|
||||||
|
|
||||||
function constructLines(input, categoryName) {
|
function constructLines(input, categoryName) {
|
||||||
let pluginCount = 0;
|
let pluginCount = 0;
|
||||||
|
|
||||||
@ -19,14 +22,10 @@ function constructLines(input, categoryName) {
|
|||||||
input.forEach(entry => {
|
input.forEach(entry => {
|
||||||
if (entry.default === false) return;
|
if (entry.default === false) return;
|
||||||
|
|
||||||
const packageName = entry.packageName;
|
const packageName = extractName(entry);
|
||||||
const defaultImportName = `${categoryName}${pluginCount}`;
|
|
||||||
|
|
||||||
lines.importLines.push(
|
|
||||||
`import ${defaultImportName} from '${packageName}';\n`
|
|
||||||
);
|
|
||||||
lines.addToWindowLines.push(
|
lines.addToWindowLines.push(
|
||||||
`${categoryName}.push(${defaultImportName});\n`
|
`${categoryName}.push("${packageName}");\n`
|
||||||
);
|
);
|
||||||
|
|
||||||
pluginCount++;
|
pluginCount++;
|
||||||
@ -49,7 +48,7 @@ function getFormattedWindowBlock(addToWindowLines) {
|
|||||||
let content =
|
let content =
|
||||||
'const extensions = [];\n' +
|
'const extensions = [];\n' +
|
||||||
'const modes = [];\n' +
|
'const modes = [];\n' +
|
||||||
'const modesFactory = [];\n' +
|
'\n// Not required any longer\n' +
|
||||||
'window.extensions = extensions;\n' +
|
'window.extensions = extensions;\n' +
|
||||||
'window.modes = modes;\n\n';
|
'window.modes = modes;\n\n';
|
||||||
|
|
||||||
@ -60,47 +59,55 @@ function getFormattedWindowBlock(addToWindowLines) {
|
|||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRuntimeLoadModesExtensions() {
|
function getRuntimeLoadModesExtensions(modules) {
|
||||||
return (
|
const dynamicLoad = [];
|
||||||
'\n\n// Add a dynamic runtime loader\n' +
|
dynamicLoad.push(
|
||||||
'export default async () => {\n' +
|
'\n\n// Add a dynamic runtime loader',
|
||||||
' for(const modeFactory of modesFactory) {\n' +
|
'async function loadModule(module) {',
|
||||||
' const newModes = await modeFactory(modes,extensions);\n' +
|
' if (typeof module !== \'string\') return module;');
|
||||||
' newModes.forEach(newMode => modes.push(newMode));\n' +
|
modules.forEach(module => {
|
||||||
'}\n}\n\n\n' +
|
const packageName = extractName(module);
|
||||||
'async function loadRuntimeImports(config) {\n' +
|
dynamicLoad.push(
|
||||||
' if (config && config.modes && config.modes.length) {\n' +
|
` if( module==="${packageName}") {`,
|
||||||
' for (const modeName of config.modes) {\n' +
|
` const imported = await import("${packageName}");`,
|
||||||
' const existingMode = modes.find(mode => mode.id === modeName);\n' +
|
' return imported.default;',
|
||||||
' if (!existingMode) {\n' +
|
' }'
|
||||||
' if (modeName === `@ohif/mode-test`) {\n' +
|
|
||||||
' const mode = await import(`@ohif/mode-test`);\n' +
|
|
||||||
' window.modes.push(mode.default);\n' +
|
|
||||||
' const extension = await import(`@ohif/extension-test`);\n' +
|
|
||||||
' window.extensions.push(extension.default);\n' +
|
|
||||||
' }\n' +
|
|
||||||
' }\n' +
|
|
||||||
' };\n' +
|
|
||||||
' }\n' +
|
|
||||||
'}\n' +
|
|
||||||
'export { loadRuntimeImports };\n\n'
|
|
||||||
);
|
);
|
||||||
|
})
|
||||||
|
dynamicLoad.push(
|
||||||
|
' return (await import(module)).default;',
|
||||||
|
'}\n',
|
||||||
|
'// Import a list of items (modules or string names)',
|
||||||
|
'// @return a Promise evaluating to a list of modules',
|
||||||
|
'export default function importItems(modules) {',
|
||||||
|
' return Promise.all(modules.map(loadModule));',
|
||||||
|
'}\n',
|
||||||
|
'export { loadModule, modes, extensions, importItems };\n\n');
|
||||||
|
return dynamicLoad.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
const fromDirectory = (srcDir, path) => {
|
||||||
|
if (!path) return;
|
||||||
|
if (path[0] === '.') return srcDir + '/../../..' + path.substring(1);
|
||||||
|
if (path[0] === '~') return os.homedir() + path.substring(1);
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
const createCopyPluginToDistForLink = (
|
const createCopyPluginToDistForLink = (
|
||||||
SRC_DIR,
|
srcDir,
|
||||||
DIST_DIR,
|
distDir,
|
||||||
plugins,
|
plugins,
|
||||||
folderName
|
folderName
|
||||||
) => {
|
) => {
|
||||||
return plugins
|
return plugins
|
||||||
.map(plugin => {
|
.map(plugin => {
|
||||||
const from = `${SRC_DIR}/../node_modules/${plugin.packageName}/${folderName}/`;
|
const fromDir = fromDirectory(srcDir, plugin.directory);
|
||||||
|
const from = fromDir || `${srcDir}/../node_modules/${plugin.packageName}/${folderName}/`;
|
||||||
const exists = fs.existsSync(from);
|
const exists = fs.existsSync(from);
|
||||||
return exists
|
return exists
|
||||||
? {
|
? {
|
||||||
from,
|
from,
|
||||||
to: DIST_DIR,
|
to: distDir,
|
||||||
toType: 'dir',
|
toType: 'dir',
|
||||||
}
|
}
|
||||||
: undefined;
|
: undefined;
|
||||||
@ -134,23 +141,20 @@ function writePluginImportsFile(SRC_DIR, DIST_DIR) {
|
|||||||
|
|
||||||
const extensionLines = constructLines(pluginConfig.extensions, 'extensions');
|
const extensionLines = constructLines(pluginConfig.extensions, 'extensions');
|
||||||
const modeLines = constructLines(pluginConfig.modes, 'modes');
|
const modeLines = constructLines(pluginConfig.modes, 'modes');
|
||||||
const modesFactoryLines = constructLines(
|
|
||||||
pluginConfig.modesFactory,
|
|
||||||
'modesFactory'
|
|
||||||
);
|
|
||||||
|
|
||||||
pluginImportsJsContent += getFormattedImportBlock([
|
pluginImportsJsContent += getFormattedImportBlock([
|
||||||
...extensionLines.importLines,
|
...extensionLines.importLines,
|
||||||
...modeLines.importLines,
|
...modeLines.importLines,
|
||||||
...modesFactoryLines.importLines,
|
|
||||||
]);
|
]);
|
||||||
pluginImportsJsContent += getFormattedWindowBlock([
|
pluginImportsJsContent += getFormattedWindowBlock([
|
||||||
...extensionLines.addToWindowLines,
|
...extensionLines.addToWindowLines,
|
||||||
...modeLines.addToWindowLines,
|
...modeLines.addToWindowLines,
|
||||||
...modesFactoryLines.addToWindowLines,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
pluginImportsJsContent += getRuntimeLoadModesExtensions();
|
pluginImportsJsContent += getRuntimeLoadModesExtensions([
|
||||||
|
...pluginConfig.extensions,
|
||||||
|
...pluginConfig.modes,
|
||||||
|
]);
|
||||||
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
`${SRC_DIR}/pluginImports.js`,
|
`${SRC_DIR}/pluginImports.js`,
|
||||||
@ -172,10 +176,8 @@ function writePluginImportsFile(SRC_DIR, DIST_DIR) {
|
|||||||
SRC_DIR,
|
SRC_DIR,
|
||||||
DIST_DIR,
|
DIST_DIR,
|
||||||
[
|
[
|
||||||
...pluginConfig.modesFactory,
|
|
||||||
...pluginConfig.modes,
|
...pluginConfig.modes,
|
||||||
...pluginConfig.extensions,
|
...pluginConfig.extensions,
|
||||||
...pluginConfig.umd,
|
|
||||||
],
|
],
|
||||||
'public'
|
'public'
|
||||||
);
|
);
|
||||||
@ -184,10 +186,9 @@ function writePluginImportsFile(SRC_DIR, DIST_DIR) {
|
|||||||
SRC_DIR,
|
SRC_DIR,
|
||||||
DIST_DIR,
|
DIST_DIR,
|
||||||
[
|
[
|
||||||
...pluginConfig.modesFactory,
|
|
||||||
...pluginConfig.modes,
|
...pluginConfig.modes,
|
||||||
...pluginConfig.extensions,
|
...pluginConfig.extensions,
|
||||||
...pluginConfig.umd,
|
...pluginConfig.public,
|
||||||
],
|
],
|
||||||
'public'
|
'public'
|
||||||
);
|
);
|
||||||
@ -198,10 +199,8 @@ function writePluginImportsFile(SRC_DIR, DIST_DIR) {
|
|||||||
SRC_DIR,
|
SRC_DIR,
|
||||||
DIST_DIR,
|
DIST_DIR,
|
||||||
[
|
[
|
||||||
...pluginConfig.modesFactory,
|
|
||||||
...pluginConfig.modes,
|
...pluginConfig.modes,
|
||||||
...pluginConfig.extensions,
|
...pluginConfig.extensions,
|
||||||
...pluginConfig.umd,
|
|
||||||
],
|
],
|
||||||
'dist'
|
'dist'
|
||||||
);
|
);
|
||||||
@ -210,15 +209,13 @@ function writePluginImportsFile(SRC_DIR, DIST_DIR) {
|
|||||||
SRC_DIR,
|
SRC_DIR,
|
||||||
DIST_DIR,
|
DIST_DIR,
|
||||||
[
|
[
|
||||||
...pluginConfig.modesFactory,
|
|
||||||
...pluginConfig.modes,
|
...pluginConfig.modes,
|
||||||
...pluginConfig.extensions,
|
...pluginConfig.extensions,
|
||||||
...pluginConfig.umd,
|
|
||||||
],
|
],
|
||||||
'dist'
|
'dist'
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('copy plugins', [
|
console.warn('copy plugins', [
|
||||||
...copyPluginPublicToDistBuild,
|
...copyPluginPublicToDistBuild,
|
||||||
...copyPluginPublicToDistLink,
|
...copyPluginPublicToDistLink,
|
||||||
...copyPluginDistToDistBuild,
|
...copyPluginDistToDistBuild,
|
||||||
|
|||||||
@ -1,60 +1,83 @@
|
|||||||
{
|
{
|
||||||
"extensions": [
|
"extensions": [
|
||||||
|
{
|
||||||
|
"packageName": "@ohif/extension-default"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"packageName": "@ohif/extension-cornerstone",
|
"packageName": "@ohif/extension-cornerstone",
|
||||||
|
"default": false,
|
||||||
"version": "3.0.0"
|
"version": "3.0.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"packageName": "@ohif/extension-measurement-tracking",
|
"packageName": "@ohif/extension-measurement-tracking",
|
||||||
|
"default": false,
|
||||||
"version": "3.0.0"
|
"version": "3.0.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"packageName": "@ohif/extension-cornerstone-dicom-sr",
|
"packageName": "@ohif/extension-cornerstone-dicom-sr",
|
||||||
"version": "3.0.0"
|
"default": false,
|
||||||
},
|
|
||||||
{
|
|
||||||
"packageName": "@ohif/extension-default",
|
|
||||||
"version": "3.0.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"packageName": "@ohif/extension-dicom-microscopy",
|
|
||||||
"version": "3.0.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"packageName": "@ohif/extension-dicom-pdf",
|
|
||||||
"version": "3.0.1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"packageName": "@ohif/extension-dicom-video",
|
|
||||||
"version": "3.0.1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"packageName": "@ohif/extension-tmtv",
|
|
||||||
"version": "3.0.0"
|
"version": "3.0.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"packageName": "@ohif/extension-cornerstone-dicom-seg",
|
"packageName": "@ohif/extension-cornerstone-dicom-seg",
|
||||||
|
"default": false,
|
||||||
|
"version": "3.0.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"packageName": "@ohif/extension-dicom-microscopy",
|
||||||
|
"default": false,
|
||||||
|
"version": "3.0.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"packageName": "@ohif/extension-dicom-pdf",
|
||||||
|
"default": false,
|
||||||
|
"version": "3.0.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"packageName": "@ohif/extension-dicom-video",
|
||||||
|
"default": false,
|
||||||
|
"version": "3.0.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"packageName": "@ohif/extension-tmtv",
|
||||||
|
"default": false,
|
||||||
|
"version": "3.0.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"packageName": "@ohif/extension-test",
|
||||||
|
"default": false,
|
||||||
"version": "3.0.0"
|
"version": "3.0.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"packageName": "@ohif/extension-cornerstone-dicom-rt",
|
"packageName": "@ohif/extension-cornerstone-dicom-rt",
|
||||||
|
"default": false,
|
||||||
"version": "3.0.0"
|
"version": "3.0.0"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modes": [
|
"modes": [
|
||||||
{
|
{
|
||||||
"packageName": "@ohif/mode-longitudinal",
|
"packageName": "@ohif/mode-longitudinal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"packageName": "@ohif/mode-tmtv"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"packageName": "@ohif/mode-microscopy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"packageName": "@ohif/mode-test",
|
||||||
|
"default": false,
|
||||||
"version": "3.0.0"
|
"version": "3.0.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"packageName": "@ohif/mode-microscopy",
|
"packageName": "@ohif/mode-basic-dev-mode",
|
||||||
"version": "3.0.0"
|
"default": false,
|
||||||
},
|
|
||||||
{
|
|
||||||
"packageName": "@ohif/mode-tmtv",
|
|
||||||
"version": "3.0.0"
|
"version": "3.0.0"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modesFactory": [],
|
"public": [
|
||||||
"umd": []
|
{
|
||||||
|
"directory": "./platform/public"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ window.config = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
extensions: [],
|
extensions: [],
|
||||||
modes: ['@ohif/mode-test'],
|
modes: ['@ohif/mode-test', '@ohif/mode-basic-dev-mode'],
|
||||||
showStudyList: true,
|
showStudyList: true,
|
||||||
maxNumberOfWebWorkers: 4,
|
maxNumberOfWebWorkers: 4,
|
||||||
// below flag is for performance reasons, but it might not work for all servers
|
// below flag is for performance reasons, but it might not work for all servers
|
||||||
|
|||||||
@ -21,6 +21,8 @@ import {
|
|||||||
// utils,
|
// utils,
|
||||||
} from '@ohif/core';
|
} from '@ohif/core';
|
||||||
|
|
||||||
|
import loadModules from './pluginImports';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {object|func} appConfigOrFunc - application configuration, or a function that returns application configuration
|
* @param {object|func} appConfigOrFunc - application configuration, or a function that returns application configuration
|
||||||
* @param {object[]} defaultExtensions - array of extension objects
|
* @param {object[]} defaultExtensions - array of extension objects
|
||||||
@ -74,8 +76,12 @@ async function appInit(appConfigOrFunc, defaultExtensions, defaultModes) {
|
|||||||
* Example: [ext1, ext2, ext3]
|
* Example: [ext1, ext2, ext3]
|
||||||
* Example2: [[ext1, config], ext2, [ext3, config]]
|
* Example2: [[ext1, config], ext2, [ext3, config]]
|
||||||
*/
|
*/
|
||||||
|
const loadedExtensions = await loadModules([
|
||||||
|
...defaultExtensions,
|
||||||
|
...appConfig.extensions,
|
||||||
|
]);
|
||||||
await extensionManager.registerExtensions(
|
await extensionManager.registerExtensions(
|
||||||
[...defaultExtensions, ...appConfig.extensions],
|
loadedExtensions,
|
||||||
appConfig.dataSources
|
appConfig.dataSources
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -87,24 +93,38 @@ async function appInit(appConfigOrFunc, defaultExtensions, defaultModes) {
|
|||||||
throw new Error('No modes are defined! Check your app-config.js');
|
throw new Error('No modes are defined! Check your app-config.js');
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < defaultModes.length; i++) {
|
const loadedModes = await loadModules([
|
||||||
const { modeFactory, id } = defaultModes[i];
|
...(appConfig.modes || []),
|
||||||
|
...defaultModes,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// This is the name for the loaded istance object
|
||||||
|
appConfig.loadedModes = [];
|
||||||
|
const modesById = new Set();
|
||||||
|
for (let i = 0; i < loadedModes.length; i++) {
|
||||||
|
let mode = loadedModes[i];
|
||||||
|
if (!mode) continue;
|
||||||
|
const { id } = mode;
|
||||||
|
|
||||||
|
if (mode.modeFactory) {
|
||||||
// If the appConfig contains configuration for this mode, use it.
|
// If the appConfig contains configuration for this mode, use it.
|
||||||
const modeConfig =
|
const modeConfig =
|
||||||
appConfig.modeConfig && appConfig.modeConfig[i]
|
appConfig.modeConfig && appConfig.modeConfig[i]
|
||||||
? appConfig.modeConfig[id]
|
? appConfig.modeConfig[id]
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
const mode = modeFactory(modeConfig);
|
mode = mode.modeFactory(modeConfig);
|
||||||
|
|
||||||
appConfig.modes.push(mode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove modes that are not objects, or have no id
|
if (modesById.has(id)) continue;
|
||||||
appConfig.modes = appConfig.modes.filter(
|
// Prevent duplication
|
||||||
mode => typeof mode === 'object' && mode.id
|
modesById.add(id);
|
||||||
);
|
if (!mode || typeof mode !== 'object') continue;
|
||||||
|
appConfig.loadedModes.push(mode);
|
||||||
|
}
|
||||||
|
// Hack alert - don't touch the original modes definition,
|
||||||
|
// but there are still dependencies on having the appConfig modes defined
|
||||||
|
appConfig.modes = appConfig.loadedModes;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
appConfig,
|
appConfig,
|
||||||
|
|||||||
@ -16,25 +16,24 @@ import { history } from './utils/history';
|
|||||||
* pluginImports.js imports all of the modes and extensions and adds them
|
* pluginImports.js imports all of the modes and extensions and adds them
|
||||||
* to the window for processing.
|
* to the window for processing.
|
||||||
*/
|
*/
|
||||||
import loadDynamicImports, { loadRuntimeImports } from './pluginImports.js';
|
import {
|
||||||
|
modes as defaultModes,
|
||||||
|
extensions as defaultExtensions,
|
||||||
|
} from './pluginImports';
|
||||||
|
|
||||||
loadDynamicImports().then(() => {
|
|
||||||
loadRuntimeImports(window.config).then(() => {
|
|
||||||
/**
|
/**
|
||||||
* Combine our appConfiguration with installed extensions and modes.
|
* Combine our appConfiguration with installed extensions and modes.
|
||||||
* In the future appConfiguration may contain modes added at runtime.
|
* In the future appConfiguration may contain modes added at runtime.
|
||||||
* */
|
* */
|
||||||
const appProps = {
|
const appProps = {
|
||||||
config: window ? window.config : {},
|
config: window ? window.config : {},
|
||||||
defaultExtensions: window.extensions,
|
defaultExtensions,
|
||||||
defaultModes: window.modes,
|
defaultModes,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Create App */
|
/** Create App */
|
||||||
const app = React.createElement(App, appProps, null);
|
const app = React.createElement(App, appProps, null);
|
||||||
/** Render */
|
/** Render */
|
||||||
ReactDOM.render(app, document.getElementById('root'));
|
ReactDOM.render(app, document.getElementById('root'));
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
export { history };
|
export { history };
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import ViewportGrid from '@components/ViewportGrid';
|
|||||||
import Compose from './Compose';
|
import Compose from './Compose';
|
||||||
import getStudies from './studiesList';
|
import getStudies from './studiesList';
|
||||||
import { history } from '../../utils/history';
|
import { history } from '../../utils/history';
|
||||||
|
import loadModules from '../../pluginImports';
|
||||||
|
|
||||||
const { getSplitParam } = utils;
|
const { getSplitParam } = utils;
|
||||||
|
|
||||||
@ -102,6 +103,8 @@ export default function ModeRoute({
|
|||||||
const [studyInstanceUIDs, setStudyInstanceUIDs] = useState();
|
const [studyInstanceUIDs, setStudyInstanceUIDs] = useState();
|
||||||
|
|
||||||
const [refresh, setRefresh] = useState(false);
|
const [refresh, setRefresh] = useState(false);
|
||||||
|
const [allExtensionsLoaded, setAllExtensionsLoaded] = useState(false);
|
||||||
|
|
||||||
const layoutTemplateData = useRef(false);
|
const layoutTemplateData = useRef(false);
|
||||||
const locationRef = useRef(null);
|
const locationRef = useRef(null);
|
||||||
const isMounted = useRef(false);
|
const isMounted = useRef(false);
|
||||||
@ -235,6 +238,18 @@ export default function ModeRoute({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setupRouteInit = async () => {
|
||||||
|
const loadedExtensions = await loadModules(Object.keys(extensions));
|
||||||
|
for (const extension of loadedExtensions) {
|
||||||
|
const { id: extensionId } = extension;
|
||||||
|
if (
|
||||||
|
extensionManager.registeredExtensionIds.indexOf(extensionId) === -1
|
||||||
|
) {
|
||||||
|
await extensionManager.registerExtension(extension);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setAllExtensionsLoaded(true);
|
||||||
|
|
||||||
// TODO: For some reason this is running before the Providers
|
// TODO: For some reason this is running before the Providers
|
||||||
// are calling setServiceImplementation
|
// are calling setServiceImplementation
|
||||||
// TODO -> iterate through services.
|
// TODO -> iterate through services.
|
||||||
@ -269,7 +284,6 @@ export default function ModeRoute({
|
|||||||
commandsManager,
|
commandsManager,
|
||||||
});
|
});
|
||||||
|
|
||||||
const setupRouteInit = async () => {
|
|
||||||
/**
|
/**
|
||||||
* The next line should get all the query parameters provided by the URL
|
* The next line should get all the query parameters provided by the URL
|
||||||
* - except the StudyInstanceUIDs - and create an object called filters
|
* - except the StudyInstanceUIDs - and create an object called filters
|
||||||
@ -382,8 +396,8 @@ export default function ModeRoute({
|
|||||||
<CombinedContextProvider>
|
<CombinedContextProvider>
|
||||||
<DragAndDropProvider>
|
<DragAndDropProvider>
|
||||||
{layoutTemplateData.current &&
|
{layoutTemplateData.current &&
|
||||||
studyInstanceUIDs?.length &&
|
studyInstanceUIDs?.[0] !== undefined &&
|
||||||
studyInstanceUIDs[0] !== undefined &&
|
allExtensionsLoaded &&
|
||||||
renderLayoutData({
|
renderLayoutData({
|
||||||
...layoutTemplateData.current.props,
|
...layoutTemplateData.current.props,
|
||||||
ViewportGridComp: ViewportGridWithDataSource,
|
ViewportGridComp: ViewportGridWithDataSource,
|
||||||
|
|||||||
@ -336,7 +336,7 @@ function WorkList({
|
|||||||
: []
|
: []
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{appConfig.modes.map((mode, i) => {
|
{appConfig.loadedModes.map((mode, i) => {
|
||||||
const isFirst = i === 0;
|
const isFirst = i === 0;
|
||||||
|
|
||||||
const isValidMode = mode.isValidMode({ modalities });
|
const isValidMode = mode.isValidMode({ modalities });
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ModeRoute from '@routes/Mode';
|
import ModeRoute from '@routes/Mode';
|
||||||
import checkExtensionDependencies from './checkExtensionDependencies';
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Routes uniquely define an entry point to:
|
Routes uniquely define an entry point to:
|
||||||
@ -41,8 +40,6 @@ export default function buildModeRoutes({
|
|||||||
});
|
});
|
||||||
|
|
||||||
modes.forEach(mode => {
|
modes.forEach(mode => {
|
||||||
checkExtensionDependencies(mode, extensionManager);
|
|
||||||
|
|
||||||
// todo: for each route. add route to path.
|
// todo: for each route. add route to path.
|
||||||
dataSourceNames.forEach(dataSourceName => {
|
dataSourceNames.forEach(dataSourceName => {
|
||||||
const path = `/${mode.routeName}/${dataSourceName}`;
|
const path = `/${mode.routeName}/${dataSourceName}`;
|
||||||
|
|||||||
@ -1,39 +0,0 @@
|
|||||||
export default function checkExtensionDependencies(mode, extensionManager) {
|
|
||||||
const extensionDependencies = mode.extensions;
|
|
||||||
|
|
||||||
const dependencyString = `Unmet extension dependency in mode: ${mode.id}`;
|
|
||||||
|
|
||||||
Object.keys(extensionDependencies).forEach(extensionId => {
|
|
||||||
const extensionInstalled = extensionManager.registeredExtensionIds.includes(
|
|
||||||
extensionId
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!extensionInstalled) {
|
|
||||||
throw new Error(
|
|
||||||
`${dependencyString}: extension ${extensionId} not found`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function areVersionsCompatible(semanticVersion, installedVersion) {
|
|
||||||
if (semanticVersion.includes('^')) {
|
|
||||||
// Major must match
|
|
||||||
const versionLessCaret = semanticVersion.split('^')[1];
|
|
||||||
|
|
||||||
// Index 0 is the major version.
|
|
||||||
return versionLessCaret[0] === installedVersion[0];
|
|
||||||
} else if (semanticVersion.includes('~')) {
|
|
||||||
// Major and minor must match
|
|
||||||
const versionLessTilde = semanticVersion.split('~')[1];
|
|
||||||
|
|
||||||
// Index 0 is the major version.
|
|
||||||
// Index 2 is the minor version.
|
|
||||||
return (
|
|
||||||
versionLessTilde[0] === installedVersion[0] &&
|
|
||||||
versionLessTilde[2] === installedVersion[2]
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return semanticVersion === installedVersion;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user