@ohif/app 3.13.0-beta.116 → 3.13.0-beta.117

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/{1206.bundle.47f070e2254d128c.js → 1206.bundle.e04ca1efe6f987ba.js} +1 -1
  2. package/dist/1483.bundle.ab1e3a882b58eb79.js +470 -0
  3. package/dist/{1602.bundle.097ec19e8e61516f.js → 1602.bundle.ea4c1b43123dd2b3.js} +2 -2
  4. package/dist/{7701.bundle.945445d6681ddd20.js → 2343.bundle.48839e1b3fa4505e.js} +990 -7
  5. package/dist/{3500.bundle.1e063b7b4910d6cf.js → 3500.bundle.da69a02594beccc8.js} +1 -1
  6. package/dist/{3760.bundle.6c7eeb4b7f1583ca.js → 3760.bundle.e406b1c3fadf2a3b.js} +2 -2
  7. package/dist/{5448.bundle.1e50777e4c4e122a.js → 5448.bundle.5686ebb99c379f64.js} +1 -1
  8. package/dist/{5696.bundle.9f0366ad867385bc.js → 5696.bundle.4e44ce1f590134eb.js} +7 -4
  9. package/dist/{5910.bundle.5561806884c95754.js → 5910.bundle.0f19608f3e76859b.js} +2 -2
  10. package/dist/{419.bundle.9d0e6a72e1e3a17b.js → 6749.bundle.8c3dd9258f09df24.js} +288 -62
  11. package/dist/{7248.bundle.f761b21f343d4b9f.js → 7248.bundle.11ec7ee7e10b0a34.js} +2 -2
  12. package/dist/{7295.bundle.4d4b6de4d2bb8856.js → 7499.bundle.0f065214db09a60b.js} +502 -5
  13. package/dist/{781.bundle.efb0a6981676cebb.js → 781.bundle.3c1a02ca26d4565a.js} +2 -2
  14. package/dist/{8423.bundle.5d1b3092bc9562c9.js → 8423.bundle.f8e7d0f1eba7e178.js} +2 -2
  15. package/dist/8492.bundle.de58afbc98ce7972.js +504 -0
  16. package/dist/8595.css +2 -0
  17. package/dist/{899.bundle.e786f8dfb66d74ca.js → 899.bundle.50c16f860acbc848.js} +2 -2
  18. package/dist/{9068.bundle.cd36fcb4e15a153e.js → 9068.bundle.95f1e638ef694ea9.js} +2 -2
  19. package/dist/{9402.bundle.6549cc304496cd5c.js → 9402.bundle.6a8a324e963b4099.js} +2 -2
  20. package/dist/{9415.bundle.2a970c71de4014bf.js → 9415.bundle.20fee612b3b3dbfd.js} +2 -2
  21. package/dist/{9437.bundle.0fff227a859992ea.js → 9437.bundle.f3f5aff637471ac4.js} +107 -123
  22. package/dist/app-config.js +1 -1
  23. package/dist/{app.bundle.55057e411d635dc3.js → app.bundle.a73ad7e598640adf.js} +203 -36
  24. package/dist/customizations/index.html +400 -0
  25. package/dist/customizations/segmentation/segmentationAnnotationTools.jsonc +48 -0
  26. package/dist/customizations/segmentation/segmentationEditing.jsonc +59 -0
  27. package/dist/customizations/{ctPresets.jsonc → tools/ctPresets.jsonc} +1 -1
  28. package/dist/customizations/{measurementLabels.jsonc → tools/measurementLabels.jsonc} +1 -1
  29. package/dist/customizations/{smoothRotate.jsonc → tools/smoothRotate.jsonc} +1 -1
  30. package/dist/customizations/veterinary/veterinary.jsonc +5 -0
  31. package/dist/customizations/{veterinaryOverlay.jsonc → veterinary/veterinaryOverlay.jsonc} +3 -3
  32. package/dist/customizations/{patientBirthDate.jsonc → worklist/patientBirthDate.jsonc} +2 -2
  33. package/dist/index.html +1 -1
  34. package/dist/sw.js +1 -1
  35. package/package.json +5 -5
  36. package/dist/4834.bundle.a91450199d0f45e4.js +0 -900
  37. package/dist/6001.bundle.0789789db5410764.js +0 -1529
  38. package/dist/customizations/veterinary.jsonc +0 -5
  39. /package/dist/{100.bundle.ac04a425c0851574.js → 100.bundle.ec5ee3b5f479a217.js} +0 -0
  40. /package/dist/{1180.bundle.c19c443fe8d26719.js → 1180.bundle.9bed26c1a1e75389.js} +0 -0
  41. /package/dist/{2779.bundle.dca036a18399be96.js → 2779.bundle.2a225a69fb65c30d.js} +0 -0
  42. /package/dist/{4556.bundle.b705ab15473128c7.js → 4556.bundle.735ccc9efdad0052.js} +0 -0
  43. /package/dist/{4683.bundle.5d12928efa9f70f4.js → 4683.bundle.e5d3182f0f4347af.js} +0 -0
  44. /package/dist/{7295.css → 8492.css} +0 -0
  45. /package/dist/{8832.bundle.ede981706cac8e15.js → 8832.bundle.1cb57aab32daeab8.js} +0 -0
  46. /package/dist/{9116.bundle.225e003c28c550c1.js → 9116.bundle.fffb2ff349a3c452.js} +0 -0
  47. /package/dist/{9290.bundle.a18c40b82772a3c6.js → 9290.bundle.82cf4e74ab3fa20a.js} +0 -0
@@ -641,7 +641,7 @@ function _extends() { return _extends = Object.assign ? Object.assign.bind() : f
641
641
 
642
642
 
643
643
  const Component = /*#__PURE__*/react.lazy(() => {
644
- return Promise.all(/* import() */ [__webpack_require__.e(8432), __webpack_require__.e(5642), __webpack_require__.e(9402), __webpack_require__.e(7701), __webpack_require__.e(5910)]).then(__webpack_require__.bind(__webpack_require__, 67329));
644
+ return Promise.all(/* import() */ [__webpack_require__.e(8432), __webpack_require__.e(5642), __webpack_require__.e(9402), __webpack_require__.e(2343), __webpack_require__.e(5910)]).then(__webpack_require__.bind(__webpack_require__, 67329));
645
645
  });
646
646
  const OHIFCornerstoneRTViewport = props => {
647
647
  return /*#__PURE__*/react.createElement(react.Suspense, {
@@ -1329,8 +1329,8 @@ function _createGetImageSrcFromImageIdFn(extensionManager) {
1329
1329
  }
1330
1330
  }
1331
1331
  /* export default */ const panels_PanelStudyBrowserTracking = (WrappedPanelStudyBrowserTracking);
1332
- // EXTERNAL MODULE: ../../../extensions/cornerstone/src/index.tsx + 198 modules
1333
- var cornerstone_src = __webpack_require__(28772);
1332
+ // EXTERNAL MODULE: ../../../extensions/cornerstone/src/index.tsx + 200 modules
1333
+ var cornerstone_src = __webpack_require__(86714);
1334
1334
  ;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/panels/PanelMeasurementTableTracking.tsx
1335
1335
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
1336
1336
 
@@ -9,7 +9,7 @@ __webpack_require__.d(__webpack_exports__, {
9
9
  /* import */ var prop_types__rspack_import_0_default = /*#__PURE__*/__webpack_require__.n(prop_types__rspack_import_0);
10
10
  /* import */ var react__rspack_import_1 = __webpack_require__(86326);
11
11
  /* import */ var _ohif_ui_next__rspack_import_2 = __webpack_require__(39987);
12
- /* import */ var _ohif_extension_cornerstone__rspack_import_3 = __webpack_require__(28772);
12
+ /* import */ var _ohif_extension_cornerstone__rspack_import_3 = __webpack_require__(86714);
13
13
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
14
14
 
15
15
 
@@ -17,8 +17,8 @@ var package_namespaceObject = JSON.parse('{"UU":"@ohif/mode-longitudinal"}')
17
17
 
18
18
  const id = package_namespaceObject.UU;
19
19
 
20
- // EXTERNAL MODULE: ../../../modes/basic/src/index.tsx + 3 modules
21
- var src = __webpack_require__(86750);
20
+ // EXTERNAL MODULE: ../../../modes/basic/src/index.tsx + 4 modules
21
+ var src = __webpack_require__(69932);
22
22
  ;// CONCATENATED MODULE: ../../../modes/longitudinal/src/index.ts
23
23
 
24
24
 
@@ -38,6 +38,9 @@ const longitudinalInstance = {
38
38
  id: src/* .ohif.layout */.Dt.layout,
39
39
  props: {
40
40
  ...src/* .basicLayout.props */.xT.props,
41
+ // Literal panel lists; the mode route seeds them into the standard
42
+ // `leftPanels` / `rightPanels` customizations so `mode` phase
43
+ // blocks and global customizations can modify them.
41
44
  leftPanels: [tracked.thumbnailList],
42
45
  rightPanels: [src/* .cornerstone.segmentation */.Nu.segmentation, tracked.measurements],
43
46
  viewports: [{
@@ -51,8 +54,8 @@ const longitudinalRoute = {
51
54
  ...src/* .basicRoute */.o2,
52
55
  path: 'longitudinal',
53
56
  /*init: ({ servicesManager, extensionManager }) => {
54
- //defaultViewerRouteInit
55
- },*/
57
+ //defaultViewerRouteInit
58
+ },*/
56
59
  layoutInstance: longitudinalInstance
57
60
  };
58
61
  const modeInstance = {
@@ -16,8 +16,8 @@ var prop_types = __webpack_require__(97598);
16
16
  var prop_types_default = /*#__PURE__*/__webpack_require__.n(prop_types);
17
17
  // EXTERNAL MODULE: ../../ui-next/src/index.ts + 3682 modules
18
18
  var src = __webpack_require__(39987);
19
- // EXTERNAL MODULE: ../../../extensions/cornerstone/src/index.tsx + 198 modules
20
- var cornerstone_src = __webpack_require__(28772);
19
+ // EXTERNAL MODULE: ../../../extensions/cornerstone/src/index.tsx + 200 modules
20
+ var cornerstone_src = __webpack_require__(86714);
21
21
  ;// CONCATENATED MODULE: ../../../extensions/cornerstone-dicom-rt/src/utils/promptHydrateRT.ts
22
22
 
23
23
  function promptHydrateRT({
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
- (globalThis["rspackChunk"] = globalThis["rspackChunk"] || []).push([[419], {
3
- 86750(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
2
+ (globalThis["rspackChunk"] = globalThis["rspackChunk"] || []).push([[6749], {
3
+ 69932(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
4
4
 
5
5
  // EXPORTS
6
6
  __webpack_require__.d(__webpack_exports__, {
@@ -10,13 +10,18 @@ __webpack_require__.d(__webpack_exports__, {
10
10
  "default": () => (/* binding */ basic_src),
11
11
  V6: () => (/* binding */ dicomRT),
12
12
  tR: () => (/* binding */ extensionDependencies),
13
+ ur: () => (/* binding */ isValidMode),
14
+ ZM: () => (/* binding */ layoutTemplate),
13
15
  Mq: () => (/* binding */ mode),
16
+ U1: () => (/* binding */ modeFactory),
14
17
  dw: () => (/* binding */ src_modeInstance),
15
18
  Dt: () => (/* binding */ ohif),
19
+ jQ: () => (/* binding */ onModeEnter),
20
+ $2: () => (/* binding */ onModeExit),
16
21
  b2: () => (/* binding */ segmentation)
17
22
  });
18
23
 
19
- // UNUSED EXPORTS: NON_IMAGE_MODALITIES, dicomPmap, dicomSeg, dicomecg, dicompdf, dicomsr, dicomvideo, initToolGroups, isValidMode, layoutTemplate, modeFactory, onModeEnter, onModeExit, sopClassHandlers
24
+ // UNUSED EXPORTS: NON_IMAGE_MODALITIES, addActivatePanelTriggers, applyToolGroupAdditions, customizations, defaultActivatePanelTriggers, dicomPmap, dicomSeg, dicomecg, dicompdf, dicomsr, dicomvideo, initToolGroups, registerModeToolbar, sopClassHandlers
20
25
 
21
26
  // EXTERNAL MODULE: ../../../node_modules/immutability-helper/index.js
22
27
  var immutability_helper = __webpack_require__(1752);
@@ -358,13 +363,131 @@ function initVolume3DToolGroup(extensionManager, toolGroupService) {
358
363
  };
359
364
  toolGroupService.createToolGroupAndAddTools('volume3d', tools);
360
365
  }
361
- function initToolGroups(extensionManager, toolGroupService, commandsManager) {
366
+
367
+ /**
368
+ * Mode tool group setup. All modes share this options-object signature so a
369
+ * mode (or a `modeConfiguration`) can substitute any other mode's
370
+ * implementation via the `initToolGroups` instance property.
371
+ */
372
+ function initToolGroups({
373
+ extensionManager,
374
+ toolGroupService,
375
+ commandsManager
376
+ }) {
362
377
  initDefaultToolGroup(extensionManager, toolGroupService, commandsManager, 'default');
363
378
  initSRToolGroup(extensionManager, toolGroupService);
364
379
  initMPRToolGroup(extensionManager, toolGroupService, commandsManager);
365
380
  initVolume3DToolGroup(extensionManager, toolGroupService);
366
381
  }
367
382
  /* export default */ const src_initToolGroups = (initToolGroups);
383
+ ;// CONCATENATED MODULE: ../../../modes/basic/src/modeCustomization.ts
384
+ /**
385
+ * Helpers for applying a mode's toolbar / tool-group composition.
386
+ *
387
+ * The composition values (`toolbarButtons`, `toolbarSections`,
388
+ * `toolGroupAdditions`) are ordinary customizations resolved through the
389
+ * customization service. A mode lists the capability packs it uses with
390
+ * `{ $reference: '<name>' }` markers; the service expands those at read time
391
+ * (packs that are arrays are flattened into the surrounding list), and a site
392
+ * `?customization=` module extends or replaces them with immutability-helper
393
+ * commands (`$push` another `{ $reference }`, `$set` a hard-coded value, ...).
394
+ * By the time these helpers run, the values passed in are already fully
395
+ * resolved — so they only need to shape/register them.
396
+ */
397
+
398
+ /** Normalizes a value to an array (wrapping a single object, dropping nullish). */
399
+ function toArray(value) {
400
+ if (value === undefined || value === null) {
401
+ return [];
402
+ }
403
+ return Array.isArray(value) ? value : [value];
404
+ }
405
+
406
+ /**
407
+ * Registers a mode's toolbar from its resolved composition.
408
+ *
409
+ * `toolbarButtons` is a flat list of button definitions registered with the
410
+ * toolbar service. `toolbarSections` is one or more
411
+ * `{ sectionKey: buttonIds[] }` objects shallow-merged in order (later values
412
+ * win per section) and applied with `updateSection`.
413
+ */
414
+ function registerModeToolbar({
415
+ toolbarService
416
+ }, {
417
+ toolbarButtons,
418
+ toolbarSections
419
+ }) {
420
+ toolbarService.register(toArray(toolbarButtons));
421
+ const sections = Object.assign({}, ...toArray(toolbarSections));
422
+ for (const [key, section] of Object.entries(sections)) {
423
+ toolbarService.updateSection(key, section);
424
+ }
425
+ }
426
+
427
+ /**
428
+ * Adds extra tools to the tool groups a mode has already created.
429
+ *
430
+ * `toolGroupAdditions` is a resolved object mapping a tool group id to a list
431
+ * of tool blocks (each a `{ active/passive/enabled/disabled }` object). Tool
432
+ * groups the mode did not create are skipped, so a single additions object can
433
+ * be shared between modes with different tool group sets.
434
+ */
435
+ function applyToolGroupAdditions({
436
+ toolGroupService
437
+ }, toolGroupAdditions) {
438
+ if (!toolGroupAdditions) {
439
+ return;
440
+ }
441
+ for (const additions of toArray(toolGroupAdditions)) {
442
+ for (const [toolGroupId, toolBlocks] of Object.entries(additions)) {
443
+ if (!toolGroupService.getToolGroup(toolGroupId)) {
444
+ continue;
445
+ }
446
+ for (const tools of toArray(toolBlocks)) {
447
+ toolGroupService.addToolsToToolGroup(toolGroupId, tools);
448
+ }
449
+ }
450
+ }
451
+ }
452
+
453
+ /**
454
+ * Wires up a mode's ActivatePanel event triggers from data.
455
+ *
456
+ * `activatePanelTriggers` is a list of
457
+ * `{ panelId, sourceServiceName, sourceEvents, forceActive? }` entries;
458
+ * `sourceEvents` names are looked up in the source service's `EVENTS` map
459
+ * (falling back to the raw value) so the whole entry is JSON-serializable and
460
+ * can be supplied by a `?customization=` module or an extending mode.
461
+ *
462
+ * Returns the unsubscribe functions for the subscriptions created.
463
+ */
464
+ function addActivatePanelTriggers({
465
+ servicesManager
466
+ }, activatePanelTriggers) {
467
+ const {
468
+ panelService
469
+ } = servicesManager.services;
470
+ const unsubscriptions = [];
471
+ for (const trigger of activatePanelTriggers ?? []) {
472
+ const {
473
+ panelId,
474
+ sourceServiceName,
475
+ sourceEvents,
476
+ forceActive = true
477
+ } = trigger;
478
+ const sourcePubSubService = servicesManager.services[sourceServiceName];
479
+ if (!sourcePubSubService) {
480
+ console.warn(`addActivatePanelTriggers: no service registered for "${sourceServiceName}"`);
481
+ continue;
482
+ }
483
+ const subscriptions = panelService.addActivatePanelTriggers(panelId, [{
484
+ sourcePubSubService,
485
+ sourceEvents: sourceEvents.map(name => sourcePubSubService.EVENTS?.[name] ?? name)
486
+ }], forceActive);
487
+ unsubscriptions.push(...subscriptions.map(subscription => () => subscription.unsubscribe()));
488
+ }
489
+ return unsubscriptions;
490
+ }
368
491
  ;// CONCATENATED MODULE: ../../../modes/basic/package.json
369
492
  var package_namespaceObject = JSON.parse('{"UU":"@ohif/mode-basic"}')
370
493
  ;// CONCATENATED MODULE: ../../../modes/basic/src/id.js
@@ -376,6 +499,7 @@ const id = package_namespaceObject.UU;
376
499
 
377
500
 
378
501
 
502
+
379
503
  const {
380
504
  structuredCloneWithFunctions
381
505
  } = src/* .utils */.Wp;
@@ -447,24 +571,49 @@ const extensionDependencies = {
447
571
  const sopClassHandlers = [dicomvideo.sopClassHandler, dicomecg.sopClassHandler, dicomSeg.sopClassHandler, dicomPmap.sopClassHandler, ohif.sopClassHandler, ohif.wsiSopClassHandler, dicompdf.sopClassHandler, dicomsr.sopClassHandler3D, dicomsr.sopClassHandler, dicomRT.sopClassHandler];
448
572
 
449
573
  /**
450
- * Indicate this is a valid mode if:
451
- * - it contains at least one of the modeModalities
452
- * - it contains all of the array value in modeModalities
453
- * Otherwise, if modeModalities is not defined:
454
- * - it contains at least one modality other than the nonModeMOdalities.
574
+ * Data-driven mode validity check, using these mode instance properties:
575
+ * - `excludedStudies`: a list of `{ attribute: value }` objects; a study
576
+ * matching every attribute of any entry is invalid.
577
+ * - `excludedModalities`: the study is invalid when it contains ANY of these.
578
+ * - `modeModalities`: the study is valid when it contains at least one entry;
579
+ * an array entry requires all of its modalities to be present (e.g.
580
+ * `[['PT', 'CT']]` requires both PT and CT).
581
+ * - otherwise `nonModeModalities`: the study is valid when it contains at
582
+ * least one modality NOT in this list.
455
583
  */
456
584
  function isValidMode({
457
- modalities
585
+ modalities,
586
+ study
458
587
  }) {
459
588
  const modalities_list = modalities.split('\\');
589
+ if (study && this.excludedStudies?.length) {
590
+ const excluded = this.excludedStudies.find(exclusion => Object.entries(exclusion).every(([key, value]) => study[key] === value));
591
+ if (excluded) {
592
+ return {
593
+ valid: false,
594
+ description: `The mode excludes studies matching: ${JSON.stringify(excluded)}`
595
+ };
596
+ }
597
+ }
598
+ if (this.excludedModalities?.length) {
599
+ const excluded = this.excludedModalities.find(modality => modalities_list.includes(modality));
600
+ if (excluded) {
601
+ return {
602
+ valid: false,
603
+ description: `The mode does not support studies containing the ${excluded} modality`
604
+ };
605
+ }
606
+ }
460
607
  if (this.modeModalities?.length) {
461
608
  for (const modeModality of this.modeModalities) {
462
- if (Array.isArray(modeModality) && modeModality.every(m => modalities.indexOf(m) !== -1)) {
463
- return {
464
- valid: true,
465
- description: `Matches ${modeModality.join(', ')}`
466
- };
467
- } else if (modalities.indexOf(modeModality)) {
609
+ if (Array.isArray(modeModality)) {
610
+ if (modeModality.every(m => modalities_list.includes(m))) {
611
+ return {
612
+ valid: true,
613
+ description: `Matches ${modeModality.join(', ')}`
614
+ };
615
+ }
616
+ } else if (modalities_list.includes(modeModality)) {
468
617
  return {
469
618
  valid: true,
470
619
  description: `Matches ${modeModality}`
@@ -476,17 +625,33 @@ function isValidMode({
476
625
  description: `None of the mode modalities match: ${JSON.stringify(this.modeModalities)}`
477
626
  };
478
627
  }
628
+ const nonModeModalities = this.nonModeModalities ?? [];
479
629
  return {
480
- valid: !!modalities_list.find(modality => this.nonModeModalities.indexOf(modality) === -1),
481
- description: `The mode does not support studies that ONLY include the following modalities: ${this.nonModeModalities.join(', ')}`
630
+ valid: !!modalities_list.find(modality => !nonModeModalities.includes(modality)),
631
+ description: `The mode does not support studies that ONLY include the following modalities: ${nonModeModalities.join(', ')}`
482
632
  };
483
633
  }
634
+
635
+ /**
636
+ * The panel activation triggers the basic family of modes historically shipped
637
+ * (commented out): activate the segmentation/measurement panel when a
638
+ * segmentation/measurement is added. Not enabled by default; a mode or
639
+ * customization can set them via the `activatePanelTriggers` instance
640
+ * property.
641
+ */
642
+ const defaultActivatePanelTriggers = [{
643
+ panelId: cornerstone.segmentation,
644
+ sourceServiceName: 'segmentationService',
645
+ sourceEvents: ['SEGMENTATION_ADDED']
646
+ }, {
647
+ panelId: cornerstone.measurements,
648
+ sourceServiceName: 'measurementService',
649
+ sourceEvents: ['MEASUREMENT_ADDED', 'RAW_MEASUREMENT_ADDED']
650
+ }];
484
651
  function onModeEnter({
485
652
  servicesManager,
486
653
  extensionManager,
487
- commandsManager,
488
- panelService,
489
- segmentationService
654
+ commandsManager
490
655
  }) {
491
656
  const {
492
657
  measurementService,
@@ -496,39 +661,51 @@ function onModeEnter({
496
661
  } = servicesManager.services;
497
662
  measurementService.clearMeasurements();
498
663
 
499
- // Init Default and SR ToolGroups
500
- src_initToolGroups(extensionManager, toolGroupService, commandsManager);
664
+ // Subscriptions the mode creates are tracked as unsubscribe functions on the
665
+ // instance; the shared onModeExit cleans them up. Extending modes push
666
+ // their own unsubscribe functions here after calling this function.
667
+ this._unsubscriptions = [];
501
668
 
502
- // Toolbar buttons and layout may be supplied either as a customization name
503
- // (a string, resolved through the customization service so `?customization=`
504
- // modules can extend the cornerstone-registered defaults) or as a literal
505
- // value (the button array / sections object) for modes that define them inline.
506
- const resolveToolbarCustomization = value => typeof value === 'string' ? customizationService.getCustomization(value) : value;
507
- const toolbarButtons = resolveToolbarCustomization(this.toolbarButtons);
508
- const toolbarSections = resolveToolbarCustomization(this.toolbarSections) ?? {};
509
- toolbarService.register(toolbarButtons);
510
- for (const [key, section] of Object.entries(toolbarSections)) {
511
- toolbarService.updateSection(key, section);
512
- }
513
- if (!this.enableSegmentationEdit) {
514
- customizationService.setCustomizations({
515
- 'panelSegmentation.disableEditing': {
516
- $set: true
517
- }
518
- });
519
- }
669
+ // Init the mode's tool groups. The function is a mode instance property so
670
+ // extending modes can substitute their own tool group setup.
671
+ this.initToolGroups?.({
672
+ extensionManager,
673
+ toolGroupService,
674
+ commandsManager,
675
+ servicesManager
676
+ });
520
677
 
521
- // // ActivatePanel event trigger for when a segmentation or measurement is added.
522
- // // Do not force activation so as to respect the state the user may have left the UI in.
523
- if (this.activatePanelTrigger) {
524
- this._activatePanelTriggersSubscriptions = [...panelService.addActivatePanelTriggers(cornerstone.segmentation, [{
525
- sourcePubSubService: segmentationService,
526
- sourceEvents: [segmentationService.EVENTS.SEGMENTATION_ADDED]
527
- }], true), ...panelService.addActivatePanelTriggers(cornerstone.measurements, [{
528
- sourcePubSubService: measurementService,
529
- sourceEvents: [measurementService.EVENTS.MEASUREMENT_ADDED, measurementService.EVENTS.RAW_MEASUREMENT_ADDED]
530
- }], true), true];
531
- }
678
+ // Toolbar buttons and layout come from the mode's composition, which the
679
+ // mode route seeded onto the Mode customization scope on enter (the plain
680
+ // `toolbarButtons` / `toolbarSections` keys) and the app config / URL `mode`
681
+ // phase then layered on top. Reading them here — after that layering — lets
682
+ // `?customization=` modules extend the toolbar without the mode restating it.
683
+ registerModeToolbar({
684
+ toolbarService
685
+ }, {
686
+ toolbarButtons: customizationService.getCustomization('toolbarButtons'),
687
+ toolbarSections: customizationService.getCustomization('toolbarSections')
688
+ });
689
+
690
+ // Extra tools (e.g. segmentation editing tools added by a customization) are
691
+ // layered onto the tool groups created above, from the resolved
692
+ // `toolGroupAdditions` composition (seeded on enter, refined by the `mode`
693
+ // phase).
694
+ applyToolGroupAdditions({
695
+ toolGroupService
696
+ }, customizationService.getCustomization('toolGroupAdditions'));
697
+
698
+ // Note: the mode's `modeCustomizations` are NOT applied here — the mode
699
+ // route applies them right after the mode scope is reset, before the app
700
+ // config / URL `mode` phase blocks, so the final value of every key is
701
+ // decided purely by customization scope precedence and application order.
702
+
703
+ // ActivatePanel event triggers (e.g. activating the segmentation panel when
704
+ // a segmentation is added). Off by default; supplied as data so extending
705
+ // modes and customizations can point at their own panels.
706
+ this._unsubscriptions.push(...addActivatePanelTriggers({
707
+ servicesManager
708
+ }, this.activatePanelTriggers));
532
709
  }
533
710
  function onModeExit({
534
711
  servicesManager
@@ -541,8 +718,8 @@ function onModeExit({
541
718
  uiDialogService,
542
719
  uiModalService
543
720
  } = servicesManager.services;
544
- this._activatePanelTriggersSubscriptions.forEach(sub => sub.unsubscribe());
545
- this._activatePanelTriggersSubscriptions.length = 0;
721
+ this._unsubscriptions?.forEach(unsubscribe => unsubscribe());
722
+ this._unsubscriptions = [];
546
723
  uiDialogService.hideAll();
547
724
  uiModalService.hide();
548
725
  toolGroupService.destroy();
@@ -553,6 +730,11 @@ function onModeExit({
553
730
  const basicLayout = {
554
731
  id: ohif.layout,
555
732
  props: {
733
+ // Literal panel lists. The mode route seeds these into the standard
734
+ // `leftPanels` / `rightPanels` customizations at the bottom of
735
+ // the mode scope, so `mode` phase blocks and global customizations can
736
+ // modify them (e.g. swap in the segmentation panels with editing tools)
737
+ // before the sidebars resolve.
556
738
  leftPanels: [ohif.thumbnailList],
557
739
  leftPanelResizable: true,
558
740
  rightPanels: [cornerstone.segmentation, cornerstone.measurements],
@@ -596,11 +778,35 @@ const src_modeInstance = {
596
778
  // instance by default.
597
779
  hide: false,
598
780
  displayName: 'Non-Longitudinal Basic',
599
- _activatePanelTriggersSubscriptions: [],
600
- // Toolbar buttons and layout are referenced by customization name; the
601
- // cornerstone extension registers the defaults and `?customization=` modules
602
- // can extend them. onModeEnter resolves these names via the customization service.
603
- toolbarSections: 'cornerstone.toolbarSections',
781
+ // Toolbar/tool-group composition: which capability packs this mode uses,
782
+ // named with `{ $reference }` markers the customization service expands at
783
+ // read time. The mode route seeds these onto the Mode customization scope on
784
+ // enter (as the plain `toolbarButtons` / `toolbarSections` /
785
+ // `toolGroupAdditions` keys), so `?customization=` modules extend them
786
+ // through the `mode` phase (e.g.
787
+ // `mode.basic.toolbarButtons: { $push: [{ $reference: '...' }] }`).
788
+ toolbarSections: [{
789
+ $reference: 'cornerstone.toolbarSections'
790
+ }],
791
+ toolGroupAdditions: {
792
+ default: [],
793
+ mpr: [],
794
+ SRToolGroup: [],
795
+ volume3d: []
796
+ },
797
+ // Tool group setup used by onModeEnter; extending modes can replace it.
798
+ initToolGroups: src_initToolGroups,
799
+ // The mode's own customizations, referenced by name: the block is registered
800
+ // at default scope when the mode loads (see `customizations` below), and the
801
+ // mode route applies it as the bottom layer of the mode scope on enter.
802
+ // Later layers — the app config / URL `mode` phase blocks and any global
803
+ // customization (e.g. `segmentationEditing`) — override it purely by
804
+ // application order and scope precedence.
805
+ modeCustomizations: 'basicModeCustomizations',
806
+ // ActivatePanel event triggers, applied on mode enter. Empty by default so
807
+ // the state the user left the UI in is respected; extending modes or
808
+ // customizations can push `defaultActivatePanelTriggers` entries.
809
+ activatePanelTriggers: [],
604
810
  /**
605
811
  * Lifecycle hooks
606
812
  */
@@ -620,8 +826,9 @@ const src_modeInstance = {
620
826
  // general handler needs to come last. For this case, the dicomvideo must
621
827
  // come first to remove video transfer syntax before ohif uses images
622
828
  sopClassHandlers,
623
- toolbarButtons: 'cornerstone.toolbarButtons',
624
- enableSegmentationEdit: false,
829
+ toolbarButtons: [{
830
+ $reference: 'cornerstone.toolbarButtons'
831
+ }],
625
832
  nonModeModalities: NON_IMAGE_MODALITIES
626
833
  };
627
834
 
@@ -638,6 +845,23 @@ function modeFactory({
638
845
  }
639
846
  return modeInstance;
640
847
  }
848
+
849
+ /**
850
+ * Customizations the mode registers with the customization service (Default
851
+ * scope) when it loads — before the bootstrap phase applies, so bootstrap and
852
+ * `?customization=` modules can modify them before anything reads them.
853
+ * Values are plain data (registered customization values never carry `$`
854
+ * commands — commands are how later customizations modify them).
855
+ */
856
+ const customizations = {
857
+ // The mode's own mode-scope block, applied by the mode route as the bottom
858
+ // layer of the mode scope on mode enter (see `modeCustomizations` above).
859
+ basicModeCustomizations: {
860
+ // Segmentation panel editing is off in the basic modes; e.g. the
861
+ // `segmentationEditing` customization overrides this at global scope.
862
+ 'panelSegmentation.disableEditing': true
863
+ }
864
+ };
641
865
  const mode = {
642
866
  id: id,
643
867
  modeFactory,
@@ -645,11 +869,13 @@ const mode = {
645
869
  ...src_modeInstance,
646
870
  hide: true
647
871
  },
648
- extensionDependencies
872
+ extensionDependencies,
873
+ customizations
649
874
  };
650
875
  /* export default */ const basic_src = (mode);
651
876
 
652
877
 
878
+
653
879
  },
654
880
 
655
881
  }]);
@@ -65,8 +65,8 @@ var react = __webpack_require__(86326);
65
65
  var src = __webpack_require__(50679);
66
66
  // EXTERNAL MODULE: ../../i18n/src/index.js + 300 modules
67
67
  var i18n_src = __webpack_require__(90119);
68
- // EXTERNAL MODULE: ../../../extensions/cornerstone/src/index.tsx + 198 modules
69
- var cornerstone_src = __webpack_require__(28772);
68
+ // EXTERNAL MODULE: ../../../extensions/cornerstone/src/index.tsx + 200 modules
69
+ var cornerstone_src = __webpack_require__(86714);
70
70
  // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/adapters/dist/esm/index.js + 83 modules
71
71
  var esm = __webpack_require__(86186);
72
72
  // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/tools/dist/esm/index.js